From 24759c71748c2d96c5f444baca13436ddf01108d Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Mon, 18 Nov 2019 19:14:06 +0100 Subject: [PATCH] WIP: first implementation. Testing needed. --- src/db/db/dbAsIfFlatEdges.h | 6 ++++ src/db/db/dbDeepEdges.cc | 34 ++++++++++++++++++----- src/db/db/dbDeepEdges.h | 5 +++- src/db/db/dbEdgeBoolean.h | 31 +++++++++++++++++++-- src/db/db/dbEdges.h | 10 +++++++ src/db/db/dbEdgesDelegate.h | 6 +--- src/db/db/dbEmptyEdges.h | 1 + src/db/db/dbLocalOperation.cc | 23 ++++++++++----- src/db/db/dbLocalOperation.h | 5 ++-- src/db/db/gsiDeclDbEdges.cc | 7 +++++ src/drc/drc/built-in-macros/_drc_layer.rb | 26 ++++++++++++++++- 11 files changed, 129 insertions(+), 25 deletions(-) diff --git a/src/db/db/dbAsIfFlatEdges.h b/src/db/db/dbAsIfFlatEdges.h index c47cf8409..6596036b4 100644 --- a/src/db/db/dbAsIfFlatEdges.h +++ b/src/db/db/dbAsIfFlatEdges.h @@ -27,6 +27,7 @@ #include "dbCommon.h" #include "dbBoxScanner.h" #include "dbEdgesDelegate.h" +#include "dbEdgeBoolean.h" #include "dbBoxScanner.h" #include "dbPolygonTools.h" @@ -138,6 +139,11 @@ public: return boolean (&other, EdgeOr); } + virtual EdgesDelegate *intersections (const Edges &other) const + { + return boolean (&other, EdgeIntersections); + } + virtual EdgesDelegate *add_in_place (const Edges &other) { return add (other); diff --git a/src/db/db/dbDeepEdges.cc b/src/db/db/dbDeepEdges.cc index 220b2c212..e0e11a055 100644 --- a/src/db/db/dbDeepEdges.cc +++ b/src/db/db/dbDeepEdges.cc @@ -751,11 +751,11 @@ EdgesDelegate *DeepEdges::merged () const } DeepLayer -DeepEdges::and_or_not_with (const DeepEdges *other, bool and_op) const +DeepEdges::and_or_not_with (const DeepEdges *other, EdgeBoolOp op) const { DeepLayer dl_out (m_deep_layer.derived ()); - db::EdgeBoolAndOrNotLocalOperation op (and_op); + db::EdgeBoolAndOrNotLocalOperation local_op (op); db::local_processor proc (const_cast (&m_deep_layer.layout ()), const_cast (&m_deep_layer.initial_cell ()), &other->deep_layer ().layout (), &other->deep_layer ().initial_cell ()); proc.set_base_verbosity (base_verbosity ()); @@ -763,7 +763,7 @@ DeepEdges::and_or_not_with (const DeepEdges *other, bool and_op) const proc.set_area_ratio (m_deep_layer.store ()->max_area_ratio ()); proc.set_max_vertex_count (m_deep_layer.store ()->max_vertex_count ()); - proc.run (&op, m_deep_layer.layer (), other->deep_layer ().layer (), dl_out.layer ()); + proc.run (&local_op, m_deep_layer.layer (), other->deep_layer ().layer (), dl_out.layer ()); return dl_out; } @@ -786,6 +786,26 @@ DeepEdges::edge_region_op (const DeepRegion *other, bool outside, bool include_b return dl_out; } +EdgesDelegate *DeepEdges::intersections (const Edges &other) const +{ + const DeepEdges *other_deep = dynamic_cast (other.delegate ()); + + if (empty () || other.empty ()) { + + // Nothing to do + return new EmptyEdges (); + + } else if (! other_deep) { + + return AsIfFlatEdges::intersections (other); + + } else { + + return new DeepEdges (and_or_not_with (other_deep, EdgeIntersections)); + + } +} + EdgesDelegate *DeepEdges::and_with (const Edges &other) const { const DeepEdges *other_deep = dynamic_cast (other.delegate ()); @@ -801,7 +821,7 @@ EdgesDelegate *DeepEdges::and_with (const Edges &other) const } else { - return new DeepEdges (and_or_not_with (other_deep, true)); + return new DeepEdges (and_or_not_with (other_deep, EdgeAnd)); } } @@ -851,7 +871,7 @@ EdgesDelegate *DeepEdges::not_with (const Edges &other) const } else { - return new DeepEdges (and_or_not_with (other_deep, false)); + return new DeepEdges (and_or_not_with (other_deep, EdgeNot)); } } @@ -903,8 +923,8 @@ EdgesDelegate *DeepEdges::xor_with (const Edges &other) const // Implement XOR as (A-B)+(B-A) - only this implementation // is compatible with the local processor scheme - DeepLayer n1 (and_or_not_with (other_deep, false)); - DeepLayer n2 (other_deep->and_or_not_with (this, false)); + DeepLayer n1 (and_or_not_with (other_deep, EdgeNot)); + DeepLayer n2 (other_deep->and_or_not_with (this, EdgeNot)); n1.add_from (n2); return new DeepEdges (n1); diff --git a/src/db/db/dbDeepEdges.h b/src/db/db/dbDeepEdges.h index e60bab2b1..af4f13e4f 100644 --- a/src/db/db/dbDeepEdges.h +++ b/src/db/db/dbDeepEdges.h @@ -28,6 +28,7 @@ #include "dbAsIfFlatEdges.h" #include "dbDeepShapeStore.h" +#include "dbEdgeBoolean.h" #include "dbEdgePairs.h" namespace db { @@ -132,6 +133,8 @@ public: virtual EdgesDelegate *add_in_place (const Edges &other); virtual EdgesDelegate *add (const Edges &other) const; + virtual EdgesDelegate *intersections (const Edges &other) const; + virtual EdgesDelegate *inside_part (const Region &other) const; virtual EdgesDelegate *outside_part (const Region &other) const; @@ -168,7 +171,7 @@ private: void init (); void ensure_merged_edges_valid () const; const DeepLayer &merged_deep_layer () const; - DeepLayer and_or_not_with(const DeepEdges *other, bool and_op) const; + DeepLayer and_or_not_with(const DeepEdges *other, EdgeBoolOp op) const; DeepLayer edge_region_op (const DeepRegion *other, bool outside, bool include_borders) const; EdgePairsDelegate *run_check (db::edge_relation_type rel, const Edges *other, db::Coord d, bool whole_edges, metrics_type metrics, double ignore_angle, distance_type min_projection, distance_type max_projection) const; virtual EdgesDelegate *pull_generic (const Edges &edges) const; diff --git a/src/db/db/dbEdgeBoolean.h b/src/db/db/dbEdgeBoolean.h index 126960546..db495a873 100644 --- a/src/db/db/dbEdgeBoolean.h +++ b/src/db/db/dbEdgeBoolean.h @@ -24,7 +24,6 @@ #define HDR_dbEdgeBoolean #include "dbEdge.h" -#include "dbEdgesDelegate.h" #include "dbBoxScanner.h" #include "tlIntervalMap.h" @@ -32,6 +31,11 @@ namespace db { +/** + * @brief A common definition for the boolean operations available on edges + */ +enum EdgeBoolOp { EdgeOr, EdgeNot, EdgeXor, EdgeAnd, EdgeIntersections }; + struct OrJoinOp { void operator() (int &v, int n) @@ -216,7 +220,15 @@ struct EdgeBooleanClusterCollector : public db::cluster_collector > { EdgeBooleanClusterCollector (OutputContainer *output, EdgeBoolOp op) - : db::cluster_collector > (EdgeBooleanCluster (output, op), op != EdgeAnd /*report single*/) + : db::cluster_collector > (EdgeBooleanCluster (output, op == EdgeIntersections ? EdgeAnd : op), op != EdgeAnd && op != EdgeIntersections /*report single*/), + mp_intersections (op == EdgeIntersections ? output : 0) + { + // .. nothing yet .. + } + + EdgeBooleanClusterCollector (OutputContainer *output, OutputContainer *intersections, EdgeBoolOp op) + : db::cluster_collector > (EdgeBooleanCluster (output, op), op != EdgeAnd /*report single*/), + mp_intersections (intersections) { // .. nothing yet .. } @@ -227,12 +239,27 @@ struct EdgeBooleanClusterCollector // 1.) not degenerate // 2.) parallel with some tolerance of roughly 1 dbu // 3.) connected + // In intersection-detection mode, identify intersection points otherwise + // and insert into the intersections container as degenerated edges. + if (! o1->is_degenerate () && ! o2->is_degenerate () && fabs ((double) db::vprod (*o1, *o2)) < db::coord_traits::prec_distance () * std::min (o1->double_length (), o2->double_length ()) && (o1->p1 () == o2->p1 () || o1->p1 () == o2->p2 () || o1->p2 () == o2->p1 () || o1->p2 () == o2->p2 () || o1->coincident (*o2))) { + db::cluster_collector >::add (o1, p1, o2, p2); + + } else if (mp_intersections && p1 != p2) { + + std::pair ip = o1->intersect_point (*o2); + if (ip.first) { + mp_intersections->insert (db::Edge (ip.second, ip.second)); + } + } } + +private: + OutputContainer *mp_intersections; }; } diff --git a/src/db/db/dbEdges.h b/src/db/db/dbEdges.h index a2c236d54..b4dfa2dc2 100644 --- a/src/db/db/dbEdges.h +++ b/src/db/db/dbEdges.h @@ -950,6 +950,16 @@ public: return *this; } + /** + * @brief Intersections with other edges + * Intersections are similar to "AND", but will also report + * non-parallel intersections between crossing edges. + */ + Edges intersections (const Edges &other) const + { + return Edges (mp_delegate->intersections (other)); + } + /** * @brief returns the extended edges * diff --git a/src/db/db/dbEdgesDelegate.h b/src/db/db/dbEdgesDelegate.h index 42564daca..6247faebe 100644 --- a/src/db/db/dbEdgesDelegate.h +++ b/src/db/db/dbEdgesDelegate.h @@ -155,11 +155,6 @@ class DB_PUBLIC EdgeToEdgePairProcessorBase // .. nothing yet .. }; -/** - * @brief A common definition for the boolean operations available on edges - */ -enum EdgeBoolOp { EdgeOr, EdgeNot, EdgeXor, EdgeAnd }; - class RecursiveShapeIterator; class EdgeFilterBase; class EdgePairsDelegate; @@ -267,6 +262,7 @@ public: virtual EdgesDelegate *or_with (const Edges &other) const = 0; virtual EdgesDelegate *add_in_place (const Edges &other) = 0; virtual EdgesDelegate *add (const Edges &other) const = 0; + virtual EdgesDelegate *intersections (const Edges &other) const = 0; virtual RegionDelegate *extended (coord_type ext_b, coord_type ext_e, coord_type ext_o, coord_type ext_i, bool join) const = 0; diff --git a/src/db/db/dbEmptyEdges.h b/src/db/db/dbEmptyEdges.h index 243bd56a3..368aabaff 100644 --- a/src/db/db/dbEmptyEdges.h +++ b/src/db/db/dbEmptyEdges.h @@ -81,6 +81,7 @@ public: virtual EdgesDelegate *or_with (const Edges &other) const; virtual EdgesDelegate *add_in_place (const Edges &other); virtual EdgesDelegate *add (const Edges &other) const; + virtual EdgesDelegate *intersections (const Edges &) const { return new EmptyEdges (); } virtual RegionDelegate *extended (coord_type, coord_type, coord_type, coord_type, bool) const; diff --git a/src/db/db/dbLocalOperation.cc b/src/db/db/dbLocalOperation.cc index 0789aa2d5..e4eacdc9b 100644 --- a/src/db/db/dbLocalOperation.cc +++ b/src/db/db/dbLocalOperation.cc @@ -177,8 +177,8 @@ std::string SelfOverlapMergeLocalOperation::description () const // --------------------------------------------------------------------------------------------- // EdgeBoolAndOrNotLocalOperation implementation -EdgeBoolAndOrNotLocalOperation::EdgeBoolAndOrNotLocalOperation (bool is_and) - : m_is_and (is_and) +EdgeBoolAndOrNotLocalOperation::EdgeBoolAndOrNotLocalOperation (EdgeBoolOp op) + : m_op (op) { // .. nothing yet .. } @@ -186,19 +186,27 @@ EdgeBoolAndOrNotLocalOperation::EdgeBoolAndOrNotLocalOperation (bool is_and) local_operation::on_empty_intruder_mode EdgeBoolAndOrNotLocalOperation::on_empty_intruder_hint () const { - return m_is_and ? Drop : Copy; + return (m_op == EdgeAnd || m_op == EdgeIntersections) ? Drop : Copy; } std::string EdgeBoolAndOrNotLocalOperation::description () const { - return m_is_and ? tl::to_string (tr ("Edge AND operation")) : tl::to_string (tr ("Edge NOT operation")); + if (m_op == EdgeIntersections) { + return tl::to_string (tr ("Edge INTERSECTION operation")); + } else if (m_op == EdgeAnd) { + return tl::to_string (tr ("Edge AND operation")); + } else if (m_op == EdgeNot) { + return tl::to_string (tr ("Edge NOT operation")); + } else { + return std::string (); + } } void EdgeBoolAndOrNotLocalOperation::compute_local (db::Layout * /*layout*/, const shape_interactions &interactions, std::unordered_set &result, size_t /*max_vertex_count*/, double /*area_ratio*/) const { - EdgeBooleanClusterCollector > cluster_collector (&result, m_is_and ? EdgeAnd : EdgeNot); + EdgeBooleanClusterCollector > cluster_collector (&result, m_op); db::box_scanner scanner; @@ -210,17 +218,18 @@ EdgeBoolAndOrNotLocalOperation::compute_local (db::Layout * /*layout*/, const sh } bool any_subject = false; + bool is_and = (m_op == EdgeAnd || m_op == EdgeIntersections); for (shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) { const db::Edge &subject = interactions.subject_shape (i->first); if (others.find (subject) != others.end ()) { - if (m_is_and) { + if (is_and) { result.insert (subject); } } else if (i->second.empty ()) { // shortcut (not: keep, and: drop) - if (! m_is_and) { + if (! is_and) { result.insert (subject); } } else { diff --git a/src/db/db/dbLocalOperation.h b/src/db/db/dbLocalOperation.h index 499704b29..fa388793a 100644 --- a/src/db/db/dbLocalOperation.h +++ b/src/db/db/dbLocalOperation.h @@ -28,6 +28,7 @@ #include "dbCommon.h" #include "dbLayout.h" +#include "dbEdgeBoolean.h" #include #include @@ -151,7 +152,7 @@ class DB_PUBLIC EdgeBoolAndOrNotLocalOperation : public local_operation { public: - EdgeBoolAndOrNotLocalOperation (bool is_and); + EdgeBoolAndOrNotLocalOperation (EdgeBoolOp op); virtual void compute_local (db::Layout *layout, const shape_interactions &interactions, std::unordered_set &result, size_t max_vertex_count, double area_ratio) const; virtual on_empty_intruder_mode on_empty_intruder_hint () const; @@ -161,7 +162,7 @@ public: virtual db::Coord dist () const { return 1; } private: - bool m_is_and; + EdgeBoolOp m_op; }; /** diff --git a/src/db/db/gsiDeclDbEdges.cc b/src/db/db/gsiDeclDbEdges.cc index 2f6d5c35c..d48b1f064 100644 --- a/src/db/db/gsiDeclDbEdges.cc +++ b/src/db/db/gsiDeclDbEdges.cc @@ -943,6 +943,13 @@ Class dec_Edges ("db", "Edges", "\n" "This method has been introduced in version 0.26.1\n" ) + + method ("intersections", &db::Edges::intersections, gsi::arg ("other"), + "@brief Computes the intersections between this edges and other edges\n" + "This computation is like an AND operation, but also including crossing points between non-coincident edges as " + "degenerated (point-like) edges.\n" + "\n" + "This method has been introduced in version 0.26.2\n" + ) + method ("inside_part", &db::Edges::inside_part, gsi::arg ("other"), "@brief Returns the parts of the edges of this edge collection which are inside the polygons of the region\n" "\n" diff --git a/src/drc/drc/built-in-macros/_drc_layer.rb b/src/drc/drc/built-in-macros/_drc_layer.rb index 8d4507afd..7b42e7a02 100644 --- a/src/drc/drc/built-in-macros/_drc_layer.rb +++ b/src/drc/drc/built-in-macros/_drc_layer.rb @@ -1601,6 +1601,16 @@ CODE # This method is available for polygon and edge layers. Edges can be selected # with respect to other edges or polygons. + # %DRC% + # @name intersections + # @brief Returns the intersection points of intersecting edge segments for two edge collections + # @synopsis layer.intersections(edges) + # This operation is similar to the "&" operator, but it does also report intersection points + # between non-colinear, but intersection edges. Such points are reported as point-like, + # degenerated edge objects. + # + # This method is available for edge layers. The argument must be an edge layer. + # %DRC% # @name inside_part # @brief Returns the parts of the edges inside the given region @@ -1731,7 +1741,6 @@ CODE end %w(inside_part outside_part).each do |f| - # In tiled mode, there are no modifying versions. Emulate using the non-modifying one. eval <<"CODE" def #{f}(other) other.requires_region("#{f}") @@ -1746,6 +1755,21 @@ CODE CODE end + %w(intersections).each do |f| + eval <<"CODE" + def #{f}(other) + other.requires_edges("#{f}") + requires_edges("#{f}") + if @engine.is_tiled? + @data = @engine._tcmd(@data, 0, @data.class, :#{f}, other.data) + DRCLayer::new(@engine, @data) + else + DRCLayer::new(@engine, @engine._tcmd(@data, 0, @data.class, :#{f}, other.data)) + end + end +CODE + end + # %DRC% # @name rectangles # @brief Selects all rectangle polygons from the input