diff --git a/src/db/db/dbCompoundOperation.cc b/src/db/db/dbCompoundOperation.cc index 1eae89c7e..573b8de29 100644 --- a/src/db/db/dbCompoundOperation.cc +++ b/src/db/db/dbCompoundOperation.cc @@ -22,25 +22,7 @@ #include "dbCompoundOperation.h" #include "dbRegion.h" - -/*@@@@ - -TODO: - -* Transform variants? -* "result is merged"? -* "requires raw input"? - -* edge pair to edge generation nodes (first, second) - -* Interactions with shapes over some distance for neighborhood analysis - -* Sized subject shapes as inputs for other operations? how to compute distance then? - -* how do the logical boolean ops work? -* what is the "multi_input" for case nodes? - -*/ +#include "dbRegionUtils.h" namespace db { @@ -584,16 +566,41 @@ run_poly_bool (CompoundRegionGeometricalBoolOperationNode::GeometricalOp op, db: // TODO: it's more efficient to feed the EP directly for polygon-to-polygon bools db::Region ra, rb; init_region (ra, a); - init_region (rb, b); - if (op == CompoundRegionGeometricalBoolOperationNode::And) { - write_result (layout, res, ra & rb); - } else if (op == CompoundRegionGeometricalBoolOperationNode::Or) { - write_result (layout, res, ra + rb); - } else if (op == CompoundRegionGeometricalBoolOperationNode::Xor) { - write_result (layout, res, ra ^ rb); - } else if (op == CompoundRegionGeometricalBoolOperationNode::Not) { - write_result (layout, res, ra - rb); + if (ra.empty ()) { + + if (op == CompoundRegionGeometricalBoolOperationNode::And || op == CompoundRegionGeometricalBoolOperationNode::Not) { + write_result (layout, res, ra); + } else if (op == CompoundRegionGeometricalBoolOperationNode::Or || op == CompoundRegionGeometricalBoolOperationNode::Xor) { + init_region (rb, b); + write_result (layout, res, rb); + } + + } else { + + init_region (rb, b); + if (rb.empty ()) { + + if (op == CompoundRegionGeometricalBoolOperationNode::And) { + write_result (layout, res, rb); + } else { + write_result (layout, res, ra); + } + + } else { + + if (op == CompoundRegionGeometricalBoolOperationNode::And) { + write_result (layout, res, ra & rb); + } else if (op == CompoundRegionGeometricalBoolOperationNode::Or) { + write_result (layout, res, ra + rb); + } else if (op == CompoundRegionGeometricalBoolOperationNode::Xor) { + write_result (layout, res, ra ^ rb); + } else if (op == CompoundRegionGeometricalBoolOperationNode::Not) { + write_result (layout, res, ra - rb); + } + + } + } } @@ -622,9 +629,22 @@ run_poly_vs_edge_bool (CompoundRegionGeometricalBoolOperationNode::GeometricalOp init_region (ra, a); db::Edges eb; - init_edges (eb, b); - write_result (layout, res, eb & ra); + if (ra.empty ()) { + + write_result (layout, res, eb); + + } else { + + init_edges (eb, b); + + if (eb.empty ()) { + write_result (layout, res, eb); + } else { + write_result (layout, res, eb & ra); + } + + } } static void @@ -647,17 +667,25 @@ run_edge_vs_poly_bool (CompoundRegionGeometricalBoolOperationNode::GeometricalOp return; } - // TODO: it's more efficient to feed the EP directly for polygon-to-polygon bools - db::Region rb; - init_region (rb, b); - db::Edges ea; init_edges (ea, a); - if (op == CompoundRegionGeometricalBoolOperationNode::And) { - write_result (layout, res, ea & rb); - } else if (op == CompoundRegionGeometricalBoolOperationNode::Not) { - write_result (layout, res, ea - rb); + if (ea.empty ()) { + + write_result (layout, res, ea); + + } else { + + // TODO: it's more efficient to feed the EP directly for polygon-to-polygon bools + db::Region rb; + init_region (rb, b); + + if (op == CompoundRegionGeometricalBoolOperationNode::And) { + write_result (layout, res, ea & rb); + } else if (op == CompoundRegionGeometricalBoolOperationNode::Not) { + write_result (layout, res, ea - rb); + } + } } @@ -678,16 +706,42 @@ run_bool (CompoundRegionGeometricalBoolOperationNode::GeometricalOp op, db::Layo { db::Edges ea, eb; init_edges (ea, a); - init_edges (eb, b); - if (op == CompoundRegionGeometricalBoolOperationNode::And) { - write_result (layout, res, ea & eb); - } else if (op == CompoundRegionGeometricalBoolOperationNode::Or) { - write_result (layout, res, ea + eb); - } else if (op == CompoundRegionGeometricalBoolOperationNode::Xor) { - write_result (layout, res, ea ^ eb); - } else if (op == CompoundRegionGeometricalBoolOperationNode::Not) { - write_result (layout, res, ea - eb); + if (ea.empty ()) { + + if (op == CompoundRegionGeometricalBoolOperationNode::And || op == CompoundRegionGeometricalBoolOperationNode::Not) { + write_result (layout, res, ea); + } else if (op == CompoundRegionGeometricalBoolOperationNode::Or || op == CompoundRegionGeometricalBoolOperationNode::Xor) { + init_edges (eb, b); + write_result (layout, res, eb); + } + + } else { + + init_edges (eb, b); + + if (eb.empty ()) { + + if (op == CompoundRegionGeometricalBoolOperationNode::And) { + write_result (layout, res, eb); + } else { + write_result (layout, res, ea); + } + + } else { + + if (op == CompoundRegionGeometricalBoolOperationNode::And) { + write_result (layout, res, ea & eb); + } else if (op == CompoundRegionGeometricalBoolOperationNode::Or) { + write_result (layout, res, ea + eb); + } else if (op == CompoundRegionGeometricalBoolOperationNode::Xor) { + write_result (layout, res, ea ^ eb); + } else if (op == CompoundRegionGeometricalBoolOperationNode::Not) { + write_result (layout, res, ea - eb); + } + + } + } } @@ -1154,6 +1208,39 @@ CompoundRegionToEdgeProcessingOperationNode::processed (db::Layout *, const db:: // --------------------------------------------------------------------------------------------- +CompoundRegionEdgeProcessingOperationNode::CompoundRegionEdgeProcessingOperationNode (EdgeProcessorBase *proc, CompoundRegionOperationNode *input, bool owns_proc) + : CompoundRegionMultiInputOperationNode (input), mp_proc (proc), m_owns_proc (owns_proc) +{ + set_description ("processor"); +} + +CompoundRegionEdgeProcessingOperationNode::~CompoundRegionEdgeProcessingOperationNode () +{ + if (m_owns_proc) { + delete mp_proc; + mp_proc = 0; + } +} + +void +CompoundRegionEdgeProcessingOperationNode::do_compute_local (db::Layout *layout, const shape_interactions &interactions, std::vector > &results, size_t max_vertex_count, double area_ratio) const +{ + implement_compute_local (layout, interactions, results, max_vertex_count, area_ratio); +} + +void +CompoundRegionEdgeProcessingOperationNode::do_compute_local (db::Layout *layout, const shape_interactions &interactions, std::vector > &results, size_t max_vertex_count, double area_ratio) const +{ + implement_compute_local (layout, interactions, results, max_vertex_count, area_ratio); +} + +void CompoundRegionEdgeProcessingOperationNode::processed (db::Layout *, const db::Edge &p, std::vector &res) const +{ + mp_proc->process (p, res); +} + +// --------------------------------------------------------------------------------------------- + CompoundRegionEdgeToPolygonProcessingOperationNode::CompoundRegionEdgeToPolygonProcessingOperationNode (EdgeToPolygonProcessorBase *proc, CompoundRegionOperationNode *input, bool owns_proc) : CompoundRegionMultiInputOperationNode (input), mp_proc (proc), m_owns_proc (owns_proc) { diff --git a/src/db/db/dbCompoundOperation.h b/src/db/db/dbCompoundOperation.h index 0c200af21..c9ee71d21 100644 --- a/src/db/db/dbCompoundOperation.h +++ b/src/db/db/dbCompoundOperation.h @@ -936,6 +936,46 @@ private: } }; +class DB_PUBLIC CompoundRegionEdgeProcessingOperationNode + : public CompoundRegionMultiInputOperationNode +{ +public: + CompoundRegionEdgeProcessingOperationNode (EdgeProcessorBase *proc, CompoundRegionOperationNode *input, bool owns_proc = false); + ~CompoundRegionEdgeProcessingOperationNode (); + + // specifies the result type + virtual ResultType result_type () const { return Edges; } + + virtual const TransformationReducer *vars () const { return mp_proc->vars (); } + virtual bool wants_variants () const { return mp_proc->wants_variants (); } + virtual bool wants_merged () const { return true; } + + virtual void do_compute_local (db::Layout *layout, const shape_interactions &interactions, std::vector > &results, size_t max_vertex_count, double area_ratio) const; + virtual void do_compute_local (db::Layout *layout, const shape_interactions &interactions, std::vector > &results, size_t max_vertex_count, double area_ratio) const; + +private: + EdgeProcessorBase *mp_proc; + bool m_owns_proc; + + void processed (db::Layout *, const db::Edge &p, std::vector &res) const; + + template + void implement_compute_local (db::Layout *layout, const shape_interactions &interactions, std::vector > &results, size_t max_vertex_count, double area_ratio) const + { + std::vector > one; + one.push_back (std::unordered_set ()); + + child (0)->compute_local (layout, interactions, one, max_vertex_count, area_ratio); + + std::vector res; + for (typename std::unordered_set::const_iterator p = one.front ().begin (); p != one.front ().end (); ++p) { + res.clear (); + processed (layout, *p, res); + results.front ().insert (res.begin (), res.end ()); + } + } +}; + class DB_PUBLIC CompoundRegionEdgePairToPolygonProcessingOperationNode : public CompoundRegionMultiInputOperationNode { diff --git a/src/db/db/dbEdges.cc b/src/db/db/dbEdges.cc index aebcbaf0e..25337e667 100644 --- a/src/db/db/dbEdges.cc +++ b/src/db/db/dbEdges.cc @@ -25,62 +25,12 @@ #include "dbOriginalLayerEdges.h" #include "dbEmptyEdges.h" #include "dbFlatEdges.h" +#include "dbEdgesUtils.h" #include "dbRegion.h" namespace db { -namespace -{ - -// ------------------------------------------------------------------------------------------------------------- -// Smoothing processor - -class EdgeSegmentSelector - : public EdgeProcessorBase -{ -public: - EdgeSegmentSelector (int mode, db::Edges::length_type length, double fraction) - : m_mode (mode), m_length (length), m_fraction (fraction) - { } - - virtual void process (const db::Edge &edge, std::vector &res) const - { - double l = std::max (edge.double_length () * m_fraction, double (m_length)); - - if (m_mode < 0) { - - res.push_back (db::Edge (edge.p1 (), db::Point (db::DPoint (edge.p1 ()) + db::DVector (edge.d ()) * (l / edge.double_length ())))); - - } else if (m_mode > 0) { - - res.push_back (db::Edge (db::Point (db::DPoint (edge.p2 ()) - db::DVector (edge.d ()) * (l / edge.double_length ())), edge.p2 ())); - - } else { - - db::DVector dl = db::DVector (edge.d ()) * (0.5 * l / edge.double_length ()); - db::DPoint center = db::DPoint (edge.p1 ()) + db::DVector (edge.p2 () - edge.p1 ()) * 0.5; - - res.push_back (db::Edge (db::Point (center - dl), db::Point (center + dl))); - - } - } - - virtual const TransformationReducer *vars () const { return &m_vars; } - virtual bool result_is_merged () const { return false; } - virtual bool requires_raw_input () const { return false; } - virtual bool result_must_not_be_merged () const { return m_length <= 0; } - virtual bool wants_variants () const { return true; } - -private: - int m_mode; - db::Edges::length_type m_length; - double m_fraction; - db::MagnificationReducer m_vars; -}; - -} - // ------------------------------------------------------------------------------------------------------------- // Edges implementation diff --git a/src/db/db/dbEdgesUtils.cc b/src/db/db/dbEdgesUtils.cc index 5b5c3e55a..79a48465a 100644 --- a/src/db/db/dbEdgesUtils.cc +++ b/src/db/db/dbEdgesUtils.cc @@ -174,4 +174,37 @@ extended_edge (const db::Edge &edge, db::Coord ext_b, db::Coord ext_e, db::Coord return poly; } +// ------------------------------------------------------------------------------------------------------------- +// EdgeSegmentSelector processor + +EdgeSegmentSelector::EdgeSegmentSelector (int mode, db::Edges::length_type length, double fraction) + : m_mode (mode), m_length (length), m_fraction (fraction) +{ } + +EdgeSegmentSelector::~EdgeSegmentSelector () +{ } + +void +EdgeSegmentSelector::process (const db::Edge &edge, std::vector &res) const +{ + double l = std::max (edge.double_length () * m_fraction, double (m_length)); + + if (m_mode < 0) { + + res.push_back (db::Edge (edge.p1 (), db::Point (db::DPoint (edge.p1 ()) + db::DVector (edge.d ()) * (l / edge.double_length ())))); + + } else if (m_mode > 0) { + + res.push_back (db::Edge (db::Point (db::DPoint (edge.p2 ()) - db::DVector (edge.d ()) * (l / edge.double_length ())), edge.p2 ())); + + } else { + + db::DVector dl = db::DVector (edge.d ()) * (0.5 * l / edge.double_length ()); + db::DPoint center = db::DPoint (edge.p1 ()) + db::DVector (edge.p2 () - edge.p1 ()) * 0.5; + + res.push_back (db::Edge (db::Point (center - dl), db::Point (center + dl))); + + } +} + } diff --git a/src/db/db/dbEdgesUtils.h b/src/db/db/dbEdgesUtils.h index 4848432ab..9fe9e4d67 100644 --- a/src/db/db/dbEdgesUtils.h +++ b/src/db/db/dbEdgesUtils.h @@ -336,6 +336,55 @@ private: */ db::Polygon extended_edge (const db::Edge &edge, db::Coord ext_b, db::Coord ext_e, db::Coord ext_o, db::Coord ext_i); +/** + * @brief Wraps the extension algorithm into a edge to polygon processor + */ +class DB_PUBLIC ExtendedEdgeProcessor + : public db::EdgeToPolygonProcessorBase +{ +public: + ExtendedEdgeProcessor (db::Coord e) + : m_ext_b (e), m_ext_e (e), m_ext_o (e), m_ext_i (e) + { } + + ExtendedEdgeProcessor (db::Coord ext_b, db::Coord ext_e, db::Coord ext_o, db::Coord ext_i) + : m_ext_b (ext_b), m_ext_e (ext_e), m_ext_o (ext_o), m_ext_i (ext_i) + { } + + virtual void process (const Edge &edge, std::vector &res) const + { + res.push_back (extended_edge (edge, m_ext_b, m_ext_e, m_ext_o, m_ext_i)); + } + +private: + db::Coord m_ext_b, m_ext_e, m_ext_o, m_ext_i; +}; + +/** + * @brief The EdgeSegmentSelector class + */ +class DB_PUBLIC EdgeSegmentSelector + : public EdgeProcessorBase +{ +public: + EdgeSegmentSelector (int mode, db::Edges::length_type length, double fraction); + ~EdgeSegmentSelector (); + + virtual void process (const db::Edge &edge, std::vector &res) const; + + virtual const TransformationReducer *vars () const { return &m_vars; } + virtual bool result_is_merged () const { return false; } + virtual bool requires_raw_input () const { return false; } + virtual bool result_must_not_be_merged () const { return m_length <= 0; } + virtual bool wants_variants () const { return true; } + +private: + int m_mode; + db::Edges::length_type m_length; + double m_fraction; + db::MagnificationReducer m_vars; +}; + } // namespace db #endif diff --git a/src/db/db/dbFlatTexts.cc b/src/db/db/dbFlatTexts.cc index bf98959bf..9f8e51477 100644 --- a/src/db/db/dbFlatTexts.cc +++ b/src/db/db/dbFlatTexts.cc @@ -32,7 +32,7 @@ namespace db // FlatTexts implementation FlatTexts::FlatTexts () - : AsIfFlatTexts (), m_texts (false) + : AsIfFlatTexts (), mp_texts (new db::Shapes (false)) { // .. nothing yet .. } @@ -43,13 +43,13 @@ FlatTexts::~FlatTexts () } FlatTexts::FlatTexts (const FlatTexts &other) - : AsIfFlatTexts (other), m_texts (false) + : AsIfFlatTexts (other), mp_texts (other.mp_texts) { - m_texts = other.m_texts; + // .. nothing yet .. } FlatTexts::FlatTexts (const db::Shapes &texts) - : AsIfFlatTexts (), m_texts (texts) + : AsIfFlatTexts (), mp_texts (new db::Shapes (texts)) { // .. nothing yet .. } @@ -61,56 +61,58 @@ void FlatTexts::invalidate_cache () void FlatTexts::reserve (size_t n) { - m_texts.reserve (db::Text::tag (), n); + mp_texts->reserve (db::Text::tag (), n); } TextsIteratorDelegate *FlatTexts::begin () const { - return new FlatTextsIterator (&m_texts); + return new FlatTextsIterator (mp_texts.get_non_const ()); } std::pair FlatTexts::begin_iter () const { - return std::make_pair (db::RecursiveShapeIterator (m_texts), db::ICplxTrans ()); + return std::make_pair (db::RecursiveShapeIterator (*mp_texts), db::ICplxTrans ()); } bool FlatTexts::empty () const { - return m_texts.empty (); + return mp_texts->empty (); } size_t FlatTexts::count () const { - return m_texts.size (); + return mp_texts->size (); } size_t FlatTexts::hier_count () const { - return m_texts.size (); + return mp_texts->size (); } Box FlatTexts::compute_bbox () const { - m_texts.update_bbox (); - return m_texts.bbox (); + mp_texts->update_bbox (); + return mp_texts->bbox (); } TextsDelegate * FlatTexts::filter_in_place (const TextFilterBase &filter) { - text_iterator_type pw = m_texts.get_layer ().begin (); + db::Shapes &texts = *mp_texts; + + text_iterator_type pw = texts.get_layer ().begin (); for (TextsIterator p (begin ()); ! p.at_end (); ++p) { if (filter.selected (*p)) { - if (pw == m_texts.get_layer ().end ()) { - m_texts.get_layer ().insert (*p); - pw = m_texts.get_layer ().end (); + if (pw == texts.get_layer ().end ()) { + texts.get_layer ().insert (*p); + pw = texts.get_layer ().end (); } else { - m_texts.get_layer ().replace (pw++, *p); + texts.get_layer ().replace (pw++, *p); } } } - m_texts.get_layer ().erase (pw, m_texts.get_layer ().end ()); + texts.get_layer ().erase (pw, texts.get_layer ().end ()); return this; } @@ -147,22 +149,24 @@ TextsDelegate *FlatTexts::add_in_place (const Texts &other) { invalidate_cache (); + db::Shapes &texts = *mp_texts; + FlatTexts *other_flat = dynamic_cast (other.delegate ()); if (other_flat) { - m_texts.insert (other_flat->raw_texts ().get_layer ().begin (), other_flat->raw_texts ().get_layer ().end ()); + texts.insert (other_flat->raw_texts ().get_layer ().begin (), other_flat->raw_texts ().get_layer ().end ()); } else { - size_t n = m_texts.size (); + size_t n = texts.size (); for (TextsIterator p (other.begin ()); ! p.at_end (); ++p) { ++n; } - m_texts.reserve (db::Text::tag (), n); + texts.reserve (db::Text::tag (), n); for (TextsIterator p (other.begin ()); ! p.at_end (); ++p) { - m_texts.insert (*p); + texts.insert (*p); } } @@ -172,7 +176,7 @@ TextsDelegate *FlatTexts::add_in_place (const Texts &other) const db::Text *FlatTexts::nth (size_t n) const { - return n < m_texts.size () ? &m_texts.get_layer ().begin () [n] : 0; + return n < mp_texts->size () ? &mp_texts->get_layer ().begin () [n] : 0; } bool FlatTexts::has_valid_texts () const @@ -199,13 +203,13 @@ FlatTexts::insert_into_as_polygons (Layout *layout, db::cell_index_type into_cel void FlatTexts::insert_into (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const { - layout->cell (into_cell).shapes (into_layer).insert (m_texts); + layout->cell (into_cell).shapes (into_layer).insert (*mp_texts); } void FlatTexts::insert (const db::Text &t) { - m_texts.insert (t); + mp_texts->insert (t); invalidate_cache (); } diff --git a/src/db/db/dbFlatTexts.h b/src/db/db/dbFlatTexts.h index 0aaa4fffc..5d3dfeb86 100644 --- a/src/db/db/dbFlatTexts.h +++ b/src/db/db/dbFlatTexts.h @@ -28,6 +28,7 @@ #include "dbAsIfFlatTexts.h" #include "dbShapes.h" +#include "tlCopyOnWrite.h" namespace db { @@ -110,14 +111,16 @@ public: void transform (const Trans &trans) { if (! trans.is_unity ()) { - for (text_iterator_type p = m_texts.template get_layer ().begin (); p != m_texts.template get_layer ().end (); ++p) { - m_texts.get_layer ().replace (p, p->transformed (trans)); + db::Shapes &texts = *mp_texts; + for (text_iterator_type p = texts.template get_layer ().begin (); p != texts.template get_layer ().end (); ++p) { + texts.get_layer ().replace (p, p->transformed (trans)); } invalidate_cache (); } } - db::Shapes &raw_texts () { return m_texts; } + db::Shapes &raw_texts () { return *mp_texts; } + const db::Shapes &raw_texts () const { return *mp_texts; } protected: virtual Box compute_bbox () const; @@ -128,7 +131,7 @@ private: FlatTexts &operator= (const FlatTexts &other); - mutable db::Shapes m_texts; + mutable tl::copy_on_write_ptr mp_texts; }; } diff --git a/src/db/db/dbRegion.cc b/src/db/db/dbRegion.cc index beb2efa01..c4c2b0d7f 100644 --- a/src/db/db/dbRegion.cc +++ b/src/db/db/dbRegion.cc @@ -22,6 +22,7 @@ #include "dbRegion.h" +#include "dbRegionUtils.h" #include "dbOriginalLayerRegion.h" #include "dbEmptyRegion.h" #include "dbFlatRegion.h" @@ -36,149 +37,6 @@ namespace db { -namespace -{ - -// ------------------------------------------------------------------------------------------------------------- -// Strange polygon processor - -/** - * @brief A helper class to implement the strange polygon detector - */ -struct StrangePolygonInsideFunc -{ - inline bool operator() (int wc) const - { - return wc < 0 || wc > 1; - } -}; - -class StrangePolygonCheckProcessor - : public PolygonProcessorBase -{ -public: - StrangePolygonCheckProcessor () { } - - virtual void process (const db::Polygon &poly, std::vector &res) const - { - EdgeProcessor ep; - ep.insert (poly); - - StrangePolygonInsideFunc inside; - db::GenericMerge op (inside); - db::PolygonContainer pc (res, false); - db::PolygonGenerator pg (pc, false, false); - ep.process (pg, op); - } - - virtual const TransformationReducer *vars () const { return 0; } - virtual bool result_is_merged () const { return false; } - virtual bool requires_raw_input () const { return true; } - virtual bool wants_variants () const { return true; } - virtual bool result_must_not_be_merged () const { return false; } -}; - -// ------------------------------------------------------------------------------------------------------------- -// Smoothing processor - -class SmoothingProcessor - : public PolygonProcessorBase -{ -public: - SmoothingProcessor (db::Coord d) : m_d (d) { } - - virtual void process (const db::Polygon &poly, std::vector &res) const - { - res.push_back (db::smooth (poly, m_d)); - } - - virtual const TransformationReducer *vars () const { return &m_vars; } - virtual bool result_is_merged () const { return false; } - virtual bool requires_raw_input () const { return false; } - virtual bool wants_variants () const { return true; } - virtual bool result_must_not_be_merged () const { return false; } - -private: - db::Coord m_d; - db::MagnificationReducer m_vars; -}; - -// ------------------------------------------------------------------------------------------------------------- -// Rounded corners processor - -class RoundedCornersProcessor - : public PolygonProcessorBase -{ -public: - RoundedCornersProcessor (double rinner, double router, unsigned int n) - : m_rinner (rinner), m_router (router), m_n (n) - { } - - virtual void process (const db::Polygon &poly, std::vector &res) const - { - res.push_back (db::compute_rounded (poly, m_rinner, m_router, m_n)); - } - - virtual const TransformationReducer *vars () const { return &m_vars; } - virtual bool result_is_merged () const { return true; } // we believe so ... - virtual bool requires_raw_input () const { return false; } - virtual bool wants_variants () const { return true; } - virtual bool result_must_not_be_merged () const { return false; } - -private: - double m_rinner, m_router; - unsigned int m_n; - db::MagnificationReducer m_vars; -}; - -// ------------------------------------------------------------------------------------------------------------- -// Holes decomposition processor - -class HolesExtractionProcessor - : public PolygonProcessorBase -{ -public: - HolesExtractionProcessor () { } - - virtual void process (const db::Polygon &poly, std::vector &res) const - { - for (size_t i = 0; i < poly.holes (); ++i) { - res.push_back (db::Polygon ()); - res.back ().assign_hull (poly.begin_hole ((unsigned int) i), poly.end_hole ((unsigned int) i)); - } - } - - virtual const TransformationReducer *vars () const { return 0; } - virtual bool result_is_merged () const { return true; } // we believe so ... - virtual bool requires_raw_input () const { return false; } - virtual bool wants_variants () const { return true; } - virtual bool result_must_not_be_merged () const { return false; } -}; - -// ------------------------------------------------------------------------------------------------------------- -// Hull extraction processor - -class HullExtractionProcessor - : public PolygonProcessorBase -{ -public: - HullExtractionProcessor () { } - - virtual void process (const db::Polygon &poly, std::vector &res) const - { - res.push_back (db::Polygon ()); - res.back ().assign_hull (poly.begin_hull (), poly.end_hull ()); - } - - virtual const TransformationReducer *vars () const { return 0; } - virtual bool result_is_merged () const { return true; } // we believe so ... - virtual bool requires_raw_input () const { return false; } - virtual bool wants_variants () const { return true; } - virtual bool result_must_not_be_merged () const { return false; } -}; - -} - // ------------------------------------------------------------------------------------------------------------- // Region implementation diff --git a/src/db/db/dbRegionUtils.cc b/src/db/db/dbRegionUtils.cc index e68f28139..8cfc5c176 100644 --- a/src/db/db/dbRegionUtils.cc +++ b/src/db/db/dbRegionUtils.cc @@ -22,6 +22,7 @@ #include "dbRegionUtils.h" +#include "dbPolygonTools.h" #include "dbEdgeBoolean.h" #include "tlSelect.h" @@ -379,6 +380,137 @@ poly2poly_check_base::enter (const PolygonType &o1, size_t p1, cons template class poly2poly_check_base; template class poly2poly_check_base; +// ------------------------------------------------------------------------------------- +// SinglePolygonCheck implementation + +SinglePolygonCheck::SinglePolygonCheck (db::edge_relation_type rel, db::Coord d, const RegionCheckOptions &options) + : m_relation (rel), m_d (d), m_options (options) +{ } + +void +SinglePolygonCheck::process (const db::Polygon &polygon, std::vector &res) const +{ + std::unordered_set result; + + EdgeRelationFilter check (m_relation, m_d, m_options.metrics); + check.set_include_zero (false); + check.set_whole_edges (m_options.whole_edges); + check.set_ignore_angle (m_options.ignore_angle); + check.set_min_projection (m_options.min_projection); + check.set_max_projection (m_options.max_projection); + + edge2edge_check > edge_check (check, result, false /*=same polygons*/, false /*=same layers*/, m_options.shielded); + poly2poly_check > poly_check (edge_check); + + do { + poly_check.enter (polygon, 0); + } while (edge_check.prepare_next_pass ()); + + res.insert (res.end (), result.begin (), result.end ()); +} + +// ------------------------------------------------------------------------------------------------------------- +// Strange polygon processor + +namespace { + +/** + * @brief A helper class to implement the strange polygon detector + */ +struct StrangePolygonInsideFunc +{ + inline bool operator() (int wc) const + { + return wc < 0 || wc > 1; + } +}; + +} + +StrangePolygonCheckProcessor::StrangePolygonCheckProcessor () { } + +StrangePolygonCheckProcessor::~StrangePolygonCheckProcessor () { } + +void +StrangePolygonCheckProcessor::process (const db::Polygon &poly, std::vector &res) const +{ + EdgeProcessor ep; + ep.insert (poly); + + StrangePolygonInsideFunc inside; + db::GenericMerge op (inside); + db::PolygonContainer pc (res, false); + db::PolygonGenerator pg (pc, false, false); + ep.process (pg, op); +} + +// ------------------------------------------------------------------------------------------------------------- +// Smoothing processor + +SmoothingProcessor::SmoothingProcessor (db::Coord d) : m_d (d) { } + +SmoothingProcessor::~SmoothingProcessor () { } + +void +SmoothingProcessor::process (const db::Polygon &poly, std::vector &res) const +{ + res.push_back (db::smooth (poly, m_d)); +} + +// ------------------------------------------------------------------------------------------------------------- +// Rounded corners processor + +RoundedCornersProcessor::RoundedCornersProcessor (double rinner, double router, unsigned int n) + : m_rinner (rinner), m_router (router), m_n (n) +{ } + +RoundedCornersProcessor::~RoundedCornersProcessor () +{ } + +void +RoundedCornersProcessor::process (const db::Polygon &poly, std::vector &res) const +{ + res.push_back (db::compute_rounded (poly, m_rinner, m_router, m_n)); +} + +// ------------------------------------------------------------------------------------------------------------- +// Holes decomposition processor + +HolesExtractionProcessor::HolesExtractionProcessor () +{ +} + +HolesExtractionProcessor::~HolesExtractionProcessor () +{ +} + +void +HolesExtractionProcessor::process (const db::Polygon &poly, std::vector &res) const +{ + for (size_t i = 0; i < poly.holes (); ++i) { + res.push_back (db::Polygon ()); + res.back ().assign_hull (poly.begin_hole ((unsigned int) i), poly.end_hole ((unsigned int) i)); + } +} + +// ------------------------------------------------------------------------------------------------------------- +// Hull decomposition processor + +HullExtractionProcessor::HullExtractionProcessor () +{ +} + +HullExtractionProcessor::~HullExtractionProcessor () +{ +} + +void +HullExtractionProcessor::process (const db::Polygon &poly, std::vector &res) const +{ + res.push_back (db::Polygon ()); + res.back ().assign_hull (poly.begin_hull (), poly.end_hull ()); +} + // ------------------------------------------------------------------------------------- // RegionToEdgeInteractionFilterBase implementation diff --git a/src/db/db/dbRegionUtils.h b/src/db/db/dbRegionUtils.h index abda1c309..8c1024d48 100644 --- a/src/db/db/dbRegionUtils.h +++ b/src/db/db/dbRegionUtils.h @@ -361,6 +361,113 @@ private: db::MagnificationAndOrientationReducer m_anisotropic_vars; }; +/** + * @brief A polygon processor filtering strange polygons + * + * "strange polygons" are those which do not have a specific orientation, e.g. + * "8" shape polygons. + */ +class DB_PUBLIC StrangePolygonCheckProcessor + : public PolygonProcessorBase +{ +public: + StrangePolygonCheckProcessor (); + ~StrangePolygonCheckProcessor (); + + virtual void process (const db::Polygon &poly, std::vector &res) const; + + virtual const TransformationReducer *vars () const { return 0; } + virtual bool result_is_merged () const { return false; } + virtual bool requires_raw_input () const { return true; } + virtual bool wants_variants () const { return true; } + virtual bool result_must_not_be_merged () const { return false; } +}; + +/** + * @brief A polygon processor applying smoothing + */ +class DB_PUBLIC SmoothingProcessor + : public PolygonProcessorBase +{ +public: + SmoothingProcessor (db::Coord d); + ~SmoothingProcessor (); + + virtual void process (const db::Polygon &poly, std::vector &res) const; + + virtual const TransformationReducer *vars () const { return &m_vars; } + virtual bool result_is_merged () const { return false; } + virtual bool requires_raw_input () const { return false; } + virtual bool wants_variants () const { return true; } + virtual bool result_must_not_be_merged () const { return false; } + +private: + db::Coord m_d; + db::MagnificationReducer m_vars; +}; + +/** + * @brief A polygon processor generating rounded corners + */ +class DB_PUBLIC RoundedCornersProcessor + : public PolygonProcessorBase +{ +public: + RoundedCornersProcessor (double rinner, double router, unsigned int n); + ~RoundedCornersProcessor (); + + virtual void process (const db::Polygon &poly, std::vector &res) const; + + virtual const TransformationReducer *vars () const { return &m_vars; } + virtual bool result_is_merged () const { return true; } // we believe so ... + virtual bool requires_raw_input () const { return false; } + virtual bool wants_variants () const { return true; } + virtual bool result_must_not_be_merged () const { return false; } + +private: + double m_rinner, m_router; + unsigned int m_n; + db::MagnificationReducer m_vars; +}; + +/** + * @brief A polygon processor extracting the holes + */ +class DB_PUBLIC HolesExtractionProcessor + : public PolygonProcessorBase +{ +public: + HolesExtractionProcessor (); + ~HolesExtractionProcessor (); + + virtual void process (const db::Polygon &poly, std::vector &res) const; + + virtual const TransformationReducer *vars () const { return 0; } + virtual bool result_is_merged () const { return true; } // we believe so ... + virtual bool requires_raw_input () const { return false; } + virtual bool wants_variants () const { return true; } + virtual bool result_must_not_be_merged () const { return false; } +}; + +/** + * @brief A polygon processor extracting the hull + */ +class DB_PUBLIC HullExtractionProcessor + : public PolygonProcessorBase +{ +public: + HullExtractionProcessor (); + ~HullExtractionProcessor (); + + virtual void process (const db::Polygon &poly, std::vector &res) const; + + virtual const TransformationReducer *vars () const { return 0; } + virtual bool result_is_merged () const { return true; } // we believe so ... + virtual bool requires_raw_input () const { return false; } + virtual bool wants_variants () const { return true; } + virtual bool result_must_not_be_merged () const { return false; } +}; + /** * @brief A helper class for the DRC functionality which acts as an edge pair receiver */ @@ -589,6 +696,23 @@ public: } }; +/** + * @brief A class wrapping the single-polygon checks into a polygon-to-edge pair processor + */ +class DB_PUBLIC SinglePolygonCheck + : public PolygonToEdgePairProcessorBase +{ +public: + SinglePolygonCheck (db::edge_relation_type rel, db::Coord d, const RegionCheckOptions &options); + + virtual void process (const db::Polygon &polygon, std::vector &res) const; + +private: + db::edge_relation_type m_relation; + db::Coord m_d; + db::RegionCheckOptions m_options; +}; + /** * @brief A helper class for the region to edge interaction functionality */ diff --git a/src/db/db/gsiDeclDbCompoundOperation.cc b/src/db/db/gsiDeclDbCompoundOperation.cc index e246577ae..018d5cca6 100644 --- a/src/db/db/gsiDeclDbCompoundOperation.cc +++ b/src/db/db/gsiDeclDbCompoundOperation.cc @@ -27,6 +27,7 @@ #include "dbRegionUtils.h" #include "dbEdgesUtils.h" #include "dbRegionLocalOperations.h" +#include "dbShapeCollectionUtils.h" namespace gsi { @@ -123,47 +124,86 @@ static db::CompoundRegionOperationNode *new_outside (db::CompoundRegionOperation } } +static db::CompoundRegionOperationNode *new_hulls (db::CompoundRegionOperationNode *input) +{ + return new db::CompoundRegionProcessingOperationNode (new db::HullExtractionProcessor (), input, true /*processor is owned*/); +} + +static db::CompoundRegionOperationNode *new_holes (db::CompoundRegionOperationNode *input) +{ + return new db::CompoundRegionProcessingOperationNode (new db::HolesExtractionProcessor (), input, true /*processor is owned*/); +} + +static db::CompoundRegionOperationNode *new_strange_polygons_filter (db::CompoundRegionOperationNode *input) +{ + return new db::CompoundRegionProcessingOperationNode (new db::StrangePolygonCheckProcessor (), input, true /*processor is owned*/); +} + +static db::CompoundRegionOperationNode *new_smoothed (db::CompoundRegionOperationNode *input, db::Coord d) +{ + return new db::CompoundRegionProcessingOperationNode (new db::SmoothingProcessor (d), input, true /*processor is owned*/); +} + +static db::CompoundRegionOperationNode *new_rounded_corners (db::CompoundRegionOperationNode *input, double rinner, double router, unsigned int n) +{ + return new db::CompoundRegionProcessingOperationNode (new db::RoundedCornersProcessor (rinner, router, n), input, true /*processor is owned*/); +} + static db::CompoundRegionOperationNode *new_case (const std::vector &inputs) { return new db::CompoundRegionLogicalCaseSelectOperationNode (inputs); } -static db::CompoundRegionOperationNode *new_corners_as_rectangles_node (db::CompoundRegionOperationNode *input, double angle_start, double angle_end, db::Coord dim = 1) +static db::CompoundRegionOperationNode *new_corners_as_rectangles (db::CompoundRegionOperationNode *input, double angle_start, double angle_end, db::Coord dim = 1) { return new db::CompoundRegionProcessingOperationNode (new db::CornersAsRectangles (angle_start, angle_end, dim), input, true /*processor is owned*/); } -static db::CompoundRegionOperationNode *new_corners_as_dots_node (db::CompoundRegionOperationNode *input, double angle_start, double angle_end) +static db::CompoundRegionOperationNode *new_corners_as_dots (db::CompoundRegionOperationNode *input, double angle_start, double angle_end) { return new db::CompoundRegionToEdgeProcessingOperationNode (new db::CornersAsDots (angle_start, angle_end), input, true /*processor is owned*/); } -static db::CompoundRegionOperationNode *new_relative_extents_node (db::CompoundRegionOperationNode *input, double fx1, double fy1, double fx2, double fy2, db::Coord dx, db::Coord dy) +static db::CompoundRegionOperationNode *new_extents (db::CompoundRegionOperationNode *input, db::Coord e) +{ + if (input->result_type () == db::CompoundRegionOperationNode::EdgePairs) { + return new db::CompoundRegionEdgePairToPolygonProcessingOperationNode (new db::extents_processor (e, e), input, true /*processor is owned*/); + } else if (input->result_type () == db::CompoundRegionOperationNode::EdgePairs) { + return new db::CompoundRegionEdgeToPolygonProcessingOperationNode (new db::extents_processor (e, e), input, true /*processor is owned*/); + } else if (input->result_type () == db::CompoundRegionOperationNode::Region) { + return new db::CompoundRegionProcessingOperationNode (new db::extents_processor (e, e), input, true /*processor is owned*/); + } else { + input->keep (); + return input; + } +} + +static db::CompoundRegionOperationNode *new_relative_extents (db::CompoundRegionOperationNode *input, double fx1, double fy1, double fx2, double fy2, db::Coord dx, db::Coord dy) { return new db::CompoundRegionProcessingOperationNode (new db::RelativeExtents (fx1, fy1, fx2, fy2, dx, dy), input, true /*processor is owned*/); } -static db::CompoundRegionOperationNode *new_relative_extents_as_edges_node (db::CompoundRegionOperationNode *input, double fx1, double fy1, double fx2, double fy2) +static db::CompoundRegionOperationNode *new_relative_extents_as_edges (db::CompoundRegionOperationNode *input, double fx1, double fy1, double fx2, double fy2) { return new db::CompoundRegionToEdgeProcessingOperationNode (new db::RelativeExtentsAsEdges (fx1, fy1, fx2, fy2), input, true /*processor is owned*/); } -static db::CompoundRegionOperationNode *new_convex_decomposition_node (db::CompoundRegionOperationNode *input, db::PreferredOrientation mode) +static db::CompoundRegionOperationNode *new_convex_decomposition (db::CompoundRegionOperationNode *input, db::PreferredOrientation mode) { return new db::CompoundRegionProcessingOperationNode (new db::ConvexDecomposition (mode), input, true /*processor is owned*/); } -static db::CompoundRegionOperationNode *new_trapezoid_decomposition_node (db::CompoundRegionOperationNode *input, db::TrapezoidDecompositionMode mode) +static db::CompoundRegionOperationNode *new_trapezoid_decomposition (db::CompoundRegionOperationNode *input, db::TrapezoidDecompositionMode mode) { return new db::CompoundRegionProcessingOperationNode (new db::TrapezoidDecomposition (mode), input, true /*processor is owned*/); } -static db::CompoundRegionOperationNode *new_polygon_breaker_node (db::CompoundRegionOperationNode *input, size_t max_vertex_count, double max_area_ratio) +static db::CompoundRegionOperationNode *new_polygon_breaker (db::CompoundRegionOperationNode *input, size_t max_vertex_count, double max_area_ratio) { return new db::CompoundRegionProcessingOperationNode (new db::PolygonBreaker (max_vertex_count, max_area_ratio), input, true /*processor is owned*/); } -static db::CompoundRegionOperationNode *new_size_node (db::CompoundRegionOperationNode *input, db::Coord dx, db::Coord dy, unsigned int mode) +static db::CompoundRegionOperationNode *new_sized (db::CompoundRegionOperationNode *input, db::Coord dx, db::Coord dy, unsigned int mode) { return new db::CompoundRegionProcessingOperationNode (new db::PolygonSizer (dx, dy, mode), input, true /*processor is owned*/); } @@ -188,37 +228,61 @@ static db::CompoundRegionOperationNode *new_minkowsky_sum_node4 (db::CompoundReg return new db::CompoundRegionProcessingOperationNode (new db::minkowsky_sum_computation > (p), input, true /*processor is owned*/); } -static db::CompoundRegionOperationNode *new_edges_node (db::CompoundRegionOperationNode *input) +static db::CompoundRegionOperationNode *new_edges (db::CompoundRegionOperationNode *input) { - return new db::CompoundRegionToEdgeProcessingOperationNode (new db::PolygonToEdgeProcessor (), input, true /*processor is owned*/); + if (input->result_type () == db::CompoundRegionOperationNode::EdgePairs) { + return new db::CompoundRegionEdgePairToEdgeProcessingOperationNode (new db::EdgePairToEdgesProcessor (), input, true /*processor is owned*/); + } else if (input->result_type () == db::CompoundRegionOperationNode::Region) { + return new db::CompoundRegionToEdgeProcessingOperationNode (new db::PolygonToEdgeProcessor (), input, true /*processor is owned*/); + } else { + input->keep (); + return input; + } } -static db::CompoundRegionOperationNode *new_edge_length_filter_node (db::CompoundRegionOperationNode *input, db::Edge::distance_type lmin, db::Edge::distance_type lmax, bool inverse) +static db::CompoundRegionOperationNode *new_edge_length_filter (db::CompoundRegionOperationNode *input, bool inverse, db::Edge::distance_type lmin, db::Edge::distance_type lmax) { return new db::CompoundRegionEdgeFilterOperationNode (new db::EdgeLengthFilter (lmin, lmax, inverse), input, true /*processor is owned*/); } -static db::CompoundRegionOperationNode *new_edge_orientation_filter_node (db::CompoundRegionOperationNode *input, double amin, double amax, bool inverse) +static db::CompoundRegionOperationNode *new_edge_orientation_filter (db::CompoundRegionOperationNode *input, bool inverse, double amin, double amax) { return new db::CompoundRegionEdgeFilterOperationNode (new db::EdgeOrientationFilter (amin, amax, inverse), input, true /*processor is owned*/); } -static db::CompoundRegionOperationNode *new_edge_pair_to_polygon_node (db::CompoundRegionOperationNode *input, db::Coord e) +static db::CompoundRegionOperationNode *new_polygons (db::CompoundRegionOperationNode *input, db::Coord e) { - return new db::CompoundRegionEdgePairToPolygonProcessingOperationNode (new db::EdgePairToPolygonProcessor (e), input, true /*processor is owned*/); + if (input->result_type () == db::CompoundRegionOperationNode::EdgePairs) { + return new db::CompoundRegionEdgePairToPolygonProcessingOperationNode (new db::EdgePairToPolygonProcessor (e), input, true /*processor is owned*/); + } else if (input->result_type () == db::CompoundRegionOperationNode::Edges) { + return new db::CompoundRegionEdgeToPolygonProcessingOperationNode (new db::ExtendedEdgeProcessor (e), input, true /*processor is owned*/); + } else { + input->keep (); + return input; + } } -static db::CompoundRegionOperationNode *new_edge_pair_to_edges_node (db::CompoundRegionOperationNode *input) +static db::CompoundRegionOperationNode *new_extended (db::CompoundRegionOperationNode *input, db::Coord ext_b, db::Coord ext_e, db::Coord ext_o, db::Coord ext_i) { - return new db::CompoundRegionEdgePairToEdgeProcessingOperationNode (new db::EdgePairToEdgesProcessor (), input, true /*processor is owned*/); + return new db::CompoundRegionEdgeToPolygonProcessingOperationNode (new db::ExtendedEdgeProcessor (ext_b, ext_e, ext_o, ext_i), input, true /*processor is owned*/); } -static db::CompoundRegionOperationNode *new_edge_pair_to_first_edges_node (db::CompoundRegionOperationNode *input) +static db::CompoundRegionOperationNode *new_extended_in (db::CompoundRegionOperationNode *input, db::Coord e) +{ + return new db::CompoundRegionEdgeToPolygonProcessingOperationNode (new db::ExtendedEdgeProcessor (0, 0, 0, e), input, true /*processor is owned*/); +} + +static db::CompoundRegionOperationNode *new_extended_out (db::CompoundRegionOperationNode *input, db::Coord e) +{ + return new db::CompoundRegionEdgeToPolygonProcessingOperationNode (new db::ExtendedEdgeProcessor (0, 0, e, 0), input, true /*processor is owned*/); +} + +static db::CompoundRegionOperationNode *new_edge_pair_to_first_edges (db::CompoundRegionOperationNode *input) { return new db::CompoundRegionEdgePairToEdgeProcessingOperationNode (new db::EdgePairToFirstEdgesProcessor (), input, true /*processor is owned*/); } -static db::CompoundRegionOperationNode *new_edge_pair_to_second_edges_node (db::CompoundRegionOperationNode *input) +static db::CompoundRegionOperationNode *new_edge_pair_to_second_edges (db::CompoundRegionOperationNode *input) { return new db::CompoundRegionEdgePairToEdgeProcessingOperationNode (new db::EdgePairToSecondEdgesProcessor (), input, true /*processor is owned*/); } @@ -251,42 +315,59 @@ static db::CompoundRegionOperationNode *new_check_node (db::CompoundRegionOperat ); } -static db::CompoundRegionOperationNode *new_width_check_node (db::Coord d, bool whole_edges, db::metrics_type metrics, const tl::Variant &ignore_angle, const tl::Variant &min_projection, const tl::Variant &max_projection, bool shielded) +static db::CompoundRegionOperationNode *new_width_check (db::Coord d, bool whole_edges, db::metrics_type metrics, const tl::Variant &ignore_angle, const tl::Variant &min_projection, const tl::Variant &max_projection, bool shielded) { - return new_check_node (db::WidthRelation, false, d, whole_edges, metrics, ignore_angle, min_projection, max_projection, shielded, db::NoOppositeFilter, db::NoSideAllowed); + db::RegionCheckOptions options (whole_edges, + metrics, + ignore_angle.is_nil () ? 90 : ignore_angle.to_double (), + min_projection.is_nil () ? db::Region::distance_type (0) : min_projection.to (), + max_projection.is_nil () ? std::numeric_limits::max () : max_projection.to (), + shielded); + return new db::CompoundRegionToEdgePairProcessingOperationNode (new db::SinglePolygonCheck (db::WidthRelation, d, options), new_primary (), true /*processor is owned*/); } -static db::CompoundRegionOperationNode *new_space_check_node (db::Coord d, bool whole_edges, db::metrics_type metrics, const tl::Variant &ignore_angle, const tl::Variant &min_projection, const tl::Variant &max_projection, bool shielded, db::OppositeFilter opposite_filter, db::RectFilter rect_filter) +static db::CompoundRegionOperationNode *new_space_check (db::Coord d, bool whole_edges, db::metrics_type metrics, const tl::Variant &ignore_angle, const tl::Variant &min_projection, const tl::Variant &max_projection, bool shielded, db::OppositeFilter opposite_filter, db::RectFilter rect_filter) +{ + return new_check_node (db::SpaceRelation, false, d, whole_edges, metrics, ignore_angle, min_projection, max_projection, shielded, opposite_filter, rect_filter); +} + +static db::CompoundRegionOperationNode *new_isolated_check (db::Coord d, bool whole_edges, db::metrics_type metrics, const tl::Variant &ignore_angle, const tl::Variant &min_projection, const tl::Variant &max_projection, bool shielded, db::OppositeFilter opposite_filter, db::RectFilter rect_filter) { return new_check_node (db::SpaceRelation, true, d, whole_edges, metrics, ignore_angle, min_projection, max_projection, shielded, opposite_filter, rect_filter); } -static db::CompoundRegionOperationNode *new_notch_check_node (db::Coord d, bool whole_edges, db::metrics_type metrics, const tl::Variant &ignore_angle, const tl::Variant &min_projection, const tl::Variant &max_projection, bool shielded) +static db::CompoundRegionOperationNode *new_notch_check (db::Coord d, bool whole_edges, db::metrics_type metrics, const tl::Variant &ignore_angle, const tl::Variant &min_projection, const tl::Variant &max_projection, bool shielded) { - return new_check_node (db::SpaceRelation, false, d, whole_edges, metrics, ignore_angle, min_projection, max_projection, shielded, db::NoOppositeFilter, db::NoSideAllowed); + db::RegionCheckOptions options (whole_edges, + metrics, + ignore_angle.is_nil () ? 90 : ignore_angle.to_double (), + min_projection.is_nil () ? db::Region::distance_type (0) : min_projection.to (), + max_projection.is_nil () ? std::numeric_limits::max () : max_projection.to (), + shielded); + return new db::CompoundRegionToEdgePairProcessingOperationNode (new db::SinglePolygonCheck (db::SpaceRelation, d, options), new_primary (), true /*processor is owned*/); } -static db::CompoundRegionOperationNode *new_separation_check_node (db::CompoundRegionOperationNode *input, db::Coord d, bool whole_edges, db::metrics_type metrics, const tl::Variant &ignore_angle, const tl::Variant &min_projection, const tl::Variant &max_projection, bool shielded, db::OppositeFilter opposite_filter, db::RectFilter rect_filter) +static db::CompoundRegionOperationNode *new_separation_check (db::CompoundRegionOperationNode *input, db::Coord d, bool whole_edges, db::metrics_type metrics, const tl::Variant &ignore_angle, const tl::Variant &min_projection, const tl::Variant &max_projection, bool shielded, db::OppositeFilter opposite_filter, db::RectFilter rect_filter) { return new_check_node (input, db::SpaceRelation, true, d, whole_edges, metrics, ignore_angle, min_projection, max_projection, shielded, opposite_filter, rect_filter); } -static db::CompoundRegionOperationNode *new_overlap_check_node (db::CompoundRegionOperationNode *input, db::Coord d, bool whole_edges, db::metrics_type metrics, const tl::Variant &ignore_angle, const tl::Variant &min_projection, const tl::Variant &max_projection, bool shielded, db::OppositeFilter opposite_filter, db::RectFilter rect_filter) +static db::CompoundRegionOperationNode *new_overlap_check (db::CompoundRegionOperationNode *input, db::Coord d, bool whole_edges, db::metrics_type metrics, const tl::Variant &ignore_angle, const tl::Variant &min_projection, const tl::Variant &max_projection, bool shielded, db::OppositeFilter opposite_filter, db::RectFilter rect_filter) { return new_check_node (input, db::OverlapRelation, true, d, whole_edges, metrics, ignore_angle, min_projection, max_projection, shielded, opposite_filter, rect_filter); } -static db::CompoundRegionOperationNode *new_inside_check_node (db::CompoundRegionOperationNode *input, db::Coord d, bool whole_edges, db::metrics_type metrics, const tl::Variant &ignore_angle, const tl::Variant &min_projection, const tl::Variant &max_projection, bool shielded, db::OppositeFilter opposite_filter, db::RectFilter rect_filter) +static db::CompoundRegionOperationNode *new_inside_check (db::CompoundRegionOperationNode *input, db::Coord d, bool whole_edges, db::metrics_type metrics, const tl::Variant &ignore_angle, const tl::Variant &min_projection, const tl::Variant &max_projection, bool shielded, db::OppositeFilter opposite_filter, db::RectFilter rect_filter) { return new_check_node (input, db::InsideRelation, true, d, whole_edges, metrics, ignore_angle, min_projection, max_projection, shielded, opposite_filter, rect_filter); } -static db::CompoundRegionOperationNode *new_perimeter_filter (db::CompoundRegionOperationNode *input, db::coord_traits::perimeter_type pmin, db::coord_traits::perimeter_type pmax, bool inverse) +static db::CompoundRegionOperationNode *new_perimeter_filter (db::CompoundRegionOperationNode *input, bool inverse, db::coord_traits::perimeter_type pmin, db::coord_traits::perimeter_type pmax) { return new db::CompoundRegionFilterOperationNode (new db::RegionPerimeterFilter (pmin, pmax, inverse), input, true); } -static db::CompoundRegionOperationNode *new_area_filter (db::CompoundRegionOperationNode *input, db::coord_traits::area_type amin, db::coord_traits::area_type amax, bool inverse) +static db::CompoundRegionOperationNode *new_area_filter (db::CompoundRegionOperationNode *input, bool inverse, db::coord_traits::area_type amin, db::coord_traits::area_type amax) { return new db::CompoundRegionFilterOperationNode (new db::RegionAreaFilter (amin, amax, inverse), input, true); } @@ -301,11 +382,26 @@ static db::CompoundRegionOperationNode *new_rectangle_filter (db::CompoundRegion return new db::CompoundRegionFilterOperationNode (new db::RectangleFilter (inverse), input, true); } -static db::CompoundRegionOperationNode *new_bbox_filter (db::CompoundRegionOperationNode *input, db::RegionBBoxFilter::parameter_type parameter, db::coord_traits::distance_type vmin, db::coord_traits::distance_type vmax, bool inverse) +static db::CompoundRegionOperationNode *new_bbox_filter (db::CompoundRegionOperationNode *input, db::RegionBBoxFilter::parameter_type parameter, bool inverse, db::coord_traits::distance_type vmin, db::coord_traits::distance_type vmax) { return new db::CompoundRegionFilterOperationNode (new db::RegionBBoxFilter (vmin, vmax, inverse, parameter), input, true); } +static db::CompoundRegionOperationNode *new_start_segments (db::CompoundRegionOperationNode *input, db::Edges::length_type length, double fraction) +{ + return new db::CompoundRegionEdgeProcessingOperationNode (new db::EdgeSegmentSelector (-1, length, fraction), input, true); +} + +static db::CompoundRegionOperationNode *new_end_segments (db::CompoundRegionOperationNode *input, db::Edges::length_type length, double fraction) +{ + return new db::CompoundRegionEdgeProcessingOperationNode (new db::EdgeSegmentSelector (1, length, fraction), input, true); +} + +static db::CompoundRegionOperationNode *new_centers (db::CompoundRegionOperationNode *input, db::Edges::length_type length, double fraction) +{ + return new db::CompoundRegionEdgeProcessingOperationNode (new db::EdgeSegmentSelector (0, length, fraction), input, true); +} + Class decl_CompoundRegionOperationNode ("db", "CompoundRegionOperationNode", gsi::constructor ("new_primary", &new_primary, "@brief Creates a node object representing the primary input" @@ -339,6 +435,26 @@ Class decl_CompoundRegionOperationNode ("db", " gsi::constructor ("new_outside", &new_outside, gsi::arg ("a"), gsi::arg ("b"), gsi::arg ("inverse", false), "@brief Creates a node representing an outside selection operation between the inputs.\n" ) + + gsi::constructor ("new_hulls", &new_hulls, gsi::arg ("input"), + "@brief Creates a node extracting the hulls from polygons.\n" + ) + + gsi::constructor ("new_holes", &new_holes, gsi::arg ("input"), + "@brief Creates a node extracting the holes from polygons.\n" + ) + + gsi::constructor ("new_strange_polygons_filter", &new_strange_polygons_filter, gsi::arg ("input"), + "@brief Creates a node extracting strange polygons.\n" + "'strange polygons' are ones which cannot be oriented - e.g. '8' shape polygons." + ) + + gsi::constructor ("new_smoothed", &new_smoothed, gsi::arg ("input"), gsi::arg ("d"), + "@brief Creates a node smoothing the polygons.\n" + "@param d The tolerance to be applied for the smoothing." + ) + + gsi::constructor ("new_rounded_corners", &new_rounded_corners, gsi::arg ("input"), gsi::arg ("rinner"), gsi::arg ("router"), gsi::arg ("n"), + "@brief Creates a node generating rounded corners.\n" + "@param rinner The inner corner radius." + "@param router The outer corner radius." + "@param n The number if points per full circle." + ) + gsi::constructor ("new_case", &new_case, gsi::arg ("inputs"), "@brief Creates a 'switch ladder' (case statement) compound operation node.\n" "\n" @@ -347,28 +463,32 @@ Class decl_CompoundRegionOperationNode ("db", " "rendered if c2 isn't empty etc. If none of the conditions renders a non-empty set and a default result is present, the default will be " "returned. Otherwise, the result is empty." ) + - gsi::constructor ("new_corners_as_rectangles", &new_corners_as_rectangles_node, gsi::arg ("input"), gsi::arg ("angle_start"), gsi::arg ("angle_end"), gsi::arg ("dim"), + gsi::constructor ("new_corners_as_rectangles", &new_corners_as_rectangles, gsi::arg ("input"), gsi::arg ("angle_start"), gsi::arg ("angle_end"), gsi::arg ("dim"), "@brief Creates a node turning corners into rectangles.\n" ) + - gsi::constructor ("new_corners_as_dots", &new_corners_as_dots_node, gsi::arg ("input"), gsi::arg ("angle_start"), gsi::arg ("angle_end"), + gsi::constructor ("new_corners_as_dots", &new_corners_as_dots, gsi::arg ("input"), gsi::arg ("angle_start"), gsi::arg ("angle_end"), "@brief Creates a node turning corners into dots (single-point edges).\n" ) + - gsi::constructor ("new_relative_extents", &new_relative_extents_node, gsi::arg ("input"), gsi::arg ("fx1"), gsi::arg ("fy1"), gsi::arg ("fx2"), gsi::arg ("fy2"), gsi::arg ("dx"), gsi::arg ("dy"), - "@brief Creates a node returning markers at specified locations of the extend (e.g. at the center).\n" + gsi::constructor ("new_extents", &new_extents, gsi::arg ("input"), gsi::arg ("e", 0), + "@brief Creates a node returning the extents of the objects.\n" + "The 'e' parameter provides a generic enlargement which is applied to the boxes. This is helpful to cover dot-like edges or edge pairs in the input." ) + - gsi::constructor ("new_relative_extents_as_edges", &new_relative_extents_as_edges_node, gsi::arg ("input"), gsi::arg ("fx1"), gsi::arg ("fy1"), gsi::arg ("fx2"), gsi::arg ("fy2"), - "@brief Creates a node returning edges at specified locations of the extend (e.g. at the center).\n" + gsi::constructor ("new_relative_extents", &new_relative_extents, gsi::arg ("input"), gsi::arg ("fx1"), gsi::arg ("fy1"), gsi::arg ("fx2"), gsi::arg ("fy2"), gsi::arg ("dx"), gsi::arg ("dy"), + "@brief Creates a node returning markers at specified locations of the extent (e.g. at the center).\n" ) + - gsi::constructor ("new_convex_decomposition", &new_convex_decomposition_node, gsi::arg ("input"), gsi::arg ("mode"), + gsi::constructor ("new_relative_extents_as_edges", &new_relative_extents_as_edges, gsi::arg ("input"), gsi::arg ("fx1"), gsi::arg ("fy1"), gsi::arg ("fx2"), gsi::arg ("fy2"), + "@brief Creates a node returning edges at specified locations of the extent (e.g. at the center).\n" + ) + + gsi::constructor ("new_convex_decomposition", &new_convex_decomposition, gsi::arg ("input"), gsi::arg ("mode"), "@brief Creates a node providing a composition into convex pieces.\n" ) + - gsi::constructor ("new_trapezoid_decomposition", &new_trapezoid_decomposition_node, gsi::arg ("input"), gsi::arg ("mode"), + gsi::constructor ("new_trapezoid_decomposition", &new_trapezoid_decomposition, gsi::arg ("input"), gsi::arg ("mode"), "@brief Creates a node providing a composition into trapezoids.\n" ) + - gsi::constructor ("new_polygon_breaker_node", &new_polygon_breaker_node, gsi::arg ("input"), gsi::arg ("max_vertex_count"), gsi::arg ("max_area_ratio"), + gsi::constructor ("new_polygon_breaker", &new_polygon_breaker, gsi::arg ("input"), gsi::arg ("max_vertex_count"), gsi::arg ("max_area_ratio"), "@brief Creates a node providing a composition into parts with less than the given number of points and a smaller area ratio.\n" ) + - gsi::constructor ("new_size_node", &new_size_node, gsi::arg ("input"), gsi::arg ("dx"), gsi::arg ("dy"), gsi::arg ("mode"), + gsi::constructor ("new_sized", &new_sized, gsi::arg ("input"), gsi::arg ("dx"), gsi::arg ("dy"), gsi::arg ("mode"), "@brief Creates a node providing sizing.\n" ) + gsi::constructor ("new_minkowsky_sum", &new_minkowsky_sum_node1, gsi::arg ("input"), gsi::arg ("e"), @@ -383,35 +503,38 @@ Class decl_CompoundRegionOperationNode ("db", " gsi::constructor ("new_minkowsky_sum", &new_minkowsky_sum_node4, gsi::arg ("input"), gsi::arg ("p"), "@brief Creates a node providing a Minkowsky sum with a point sequence forming a contour.\n" ) + - gsi::constructor ("new_width_check", &new_width_check_node, gsi::arg ("d"), gsi::arg ("whole_edges", false), gsi::arg ("metrics", db::Euclidian), gsi::arg ("ignore_angle", tl::Variant (), "default"), gsi::arg ("min_projection", tl::Variant (), "0"), gsi::arg ("max_projection", tl::Variant (), "max."), gsi::arg ("shielded", true), + gsi::constructor ("new_width_check", &new_width_check, gsi::arg ("d"), gsi::arg ("whole_edges", false), gsi::arg ("metrics", db::Euclidian), gsi::arg ("ignore_angle", tl::Variant (), "default"), gsi::arg ("min_projection", tl::Variant (), "0"), gsi::arg ("max_projection", tl::Variant (), "max."), gsi::arg ("shielded", true), "@brief Creates a node providing a width check.\n" ) + - gsi::constructor ("new_space_check", &new_space_check_node, gsi::arg ("d"), gsi::arg ("whole_edges", false), gsi::arg ("metrics", db::Euclidian), gsi::arg ("ignore_angle", tl::Variant (), "default"), gsi::arg ("min_projection", tl::Variant (), "0"), gsi::arg ("max_projection", tl::Variant (), "max."), gsi::arg ("shielded", true), gsi::arg ("opposite_filter", db::NoOppositeFilter), gsi::arg ("rect_filter", db::NoSideAllowed), + gsi::constructor ("new_space_check", &new_space_check, gsi::arg ("d"), gsi::arg ("whole_edges", false), gsi::arg ("metrics", db::Euclidian), gsi::arg ("ignore_angle", tl::Variant (), "default"), gsi::arg ("min_projection", tl::Variant (), "0"), gsi::arg ("max_projection", tl::Variant (), "max."), gsi::arg ("shielded", true), gsi::arg ("opposite_filter", db::NoOppositeFilter), gsi::arg ("rect_filter", db::NoSideAllowed), "@brief Creates a node providing a space check.\n" ) + - gsi::constructor ("new_notch_check", &new_notch_check_node, gsi::arg ("d"), gsi::arg ("whole_edges", false), gsi::arg ("metrics", db::Euclidian), gsi::arg ("ignore_angle", tl::Variant (), "default"), gsi::arg ("min_projection", tl::Variant (), "0"), gsi::arg ("max_projection", tl::Variant (), "max."), gsi::arg ("shielded", true), + gsi::constructor ("new_isolated_check", &new_isolated_check, gsi::arg ("d"), gsi::arg ("whole_edges", false), gsi::arg ("metrics", db::Euclidian), gsi::arg ("ignore_angle", tl::Variant (), "default"), gsi::arg ("min_projection", tl::Variant (), "0"), gsi::arg ("max_projection", tl::Variant (), "max."), gsi::arg ("shielded", true), gsi::arg ("opposite_filter", db::NoOppositeFilter), gsi::arg ("rect_filter", db::NoSideAllowed), + "@brief Creates a node providing a isolated polygons (space between different polygons) check.\n" + ) + + gsi::constructor ("new_notch_check", &new_notch_check, gsi::arg ("d"), gsi::arg ("whole_edges", false), gsi::arg ("metrics", db::Euclidian), gsi::arg ("ignore_angle", tl::Variant (), "default"), gsi::arg ("min_projection", tl::Variant (), "0"), gsi::arg ("max_projection", tl::Variant (), "max."), gsi::arg ("shielded", true), "@brief Creates a node providing a intra-polygon space check.\n" ) + - gsi::constructor ("new_separation_check", &new_separation_check_node, gsi::arg ("input"), gsi::arg ("d"), gsi::arg ("whole_edges", false), gsi::arg ("metrics", db::Euclidian), gsi::arg ("ignore_angle", tl::Variant (), "default"), gsi::arg ("min_projection", tl::Variant (), "0"), gsi::arg ("max_projection", tl::Variant (), "max."), gsi::arg ("shielded", true), gsi::arg ("opposite_filter", db::NoOppositeFilter), gsi::arg ("rect_filter", db::NoSideAllowed), + gsi::constructor ("new_separation_check", &new_separation_check, gsi::arg ("input"), gsi::arg ("d"), gsi::arg ("whole_edges", false), gsi::arg ("metrics", db::Euclidian), gsi::arg ("ignore_angle", tl::Variant (), "default"), gsi::arg ("min_projection", tl::Variant (), "0"), gsi::arg ("max_projection", tl::Variant (), "max."), gsi::arg ("shielded", true), gsi::arg ("opposite_filter", db::NoOppositeFilter), gsi::arg ("rect_filter", db::NoSideAllowed), "@brief Creates a node providing a separation check.\n" ) + - gsi::constructor ("new_overlap_check", &new_overlap_check_node, gsi::arg ("input"), gsi::arg ("d"), gsi::arg ("whole_edges", false), gsi::arg ("metrics", db::Euclidian), gsi::arg ("ignore_angle", tl::Variant (), "default"), gsi::arg ("min_projection", tl::Variant (), "0"), gsi::arg ("max_projection", tl::Variant (), "max."), gsi::arg ("shielded", true), gsi::arg ("opposite_filter", db::NoOppositeFilter), gsi::arg ("rect_filter", db::NoSideAllowed), + gsi::constructor ("new_overlap_check", &new_overlap_check, gsi::arg ("input"), gsi::arg ("d"), gsi::arg ("whole_edges", false), gsi::arg ("metrics", db::Euclidian), gsi::arg ("ignore_angle", tl::Variant (), "default"), gsi::arg ("min_projection", tl::Variant (), "0"), gsi::arg ("max_projection", tl::Variant (), "max."), gsi::arg ("shielded", true), gsi::arg ("opposite_filter", db::NoOppositeFilter), gsi::arg ("rect_filter", db::NoSideAllowed), "@brief Creates a node providing an overlap check.\n" ) + - gsi::constructor ("new_inside_check", &new_inside_check_node, gsi::arg ("input"), gsi::arg ("d"), gsi::arg ("whole_edges", false), gsi::arg ("metrics", db::Euclidian), gsi::arg ("ignore_angle", tl::Variant (), "default"), gsi::arg ("min_projection", tl::Variant (), "0"), gsi::arg ("max_projection", tl::Variant (), "max."), gsi::arg ("shielded", true), gsi::arg ("opposite_filter", db::NoOppositeFilter), gsi::arg ("rect_filter", db::NoSideAllowed), + gsi::constructor ("new_inside_check", &new_inside_check, gsi::arg ("input"), gsi::arg ("d"), gsi::arg ("whole_edges", false), gsi::arg ("metrics", db::Euclidian), gsi::arg ("ignore_angle", tl::Variant (), "default"), gsi::arg ("min_projection", tl::Variant (), "0"), gsi::arg ("max_projection", tl::Variant (), "max."), gsi::arg ("shielded", true), gsi::arg ("opposite_filter", db::NoOppositeFilter), gsi::arg ("rect_filter", db::NoSideAllowed), "@brief Creates a node providing an inside (enclosure) check.\n" ) + - gsi::constructor ("new_perimeter_filter", &new_perimeter_filter, gsi::arg ("input"), gsi::arg ("pmin", 0), gsi::arg ("pmax", std::numeric_limits::perimeter_type>::max (), "max"), gsi::arg ("inverse", false), + gsi::constructor ("new_perimeter_filter", &new_perimeter_filter, gsi::arg ("input"), gsi::arg ("inverse", false), gsi::arg ("pmin", 0), gsi::arg ("pmax", std::numeric_limits::perimeter_type>::max (), "max"), "@brief Creates a node filtering the input by perimeter.\n" "This node renders the input if the perimeter is between pmin and pmax (exclusively). If 'inverse' is set to true, the " "input shape is returned if the perimeter is less than pmin (exclusively) or larger than pmax (inclusively)." ) + - gsi::constructor ("new_area_filter", &new_area_filter, gsi::arg ("input"), gsi::arg ("amin", 0), gsi::arg ("amax", std::numeric_limits::area_type>::max (), "max"), gsi::arg ("inverse", false), + gsi::constructor ("new_area_filter", &new_area_filter, gsi::arg ("input"), gsi::arg ("inverse", false), gsi::arg ("amin", 0), gsi::arg ("amax", std::numeric_limits::area_type>::max (), "max"), "@brief Creates a node filtering the input by area.\n" "This node renders the input if the area is between amin and amax (exclusively). If 'inverse' is set to true, the " "input shape is returned if the area is less than amin (exclusively) or larger than amax (inclusively)." ) + - gsi::constructor ("new_bbox_filter", &new_bbox_filter, gsi::arg ("input"), gsi::arg ("parameter"), gsi::arg ("pmin", 0), gsi::arg ("pmax", std::numeric_limits::area_type>::max (), "max"), gsi::arg ("inverse", false), + gsi::constructor ("new_bbox_filter", &new_bbox_filter, gsi::arg ("input"), gsi::arg ("parameter"), gsi::arg ("inverse", false), gsi::arg ("pmin", 0), gsi::arg ("pmax", std::numeric_limits::area_type>::max (), "max"), "@brief Creates a node filtering the input by bounding box parameters.\n" "This node renders the input if the specified bounding box parameter of the input shape is between pmin and pmax (exclusively). If 'inverse' is set to true, the " "input shape is returned if the parameter is less than pmin (exclusively) or larger than pmax (inclusively)." @@ -422,27 +545,43 @@ Class decl_CompoundRegionOperationNode ("db", " gsi::constructor ("new_rectangle_filter", &new_rectangle_filter, gsi::arg ("input"), gsi::arg ("inverse", false), "@brief Creates a node filtering the input for rectangular shapes (or non-rectangular ones with 'inverse' set to 'true').\n" ) + - gsi::constructor ("new_edges", &new_edges_node, gsi::arg ("input"), + gsi::constructor ("new_edges", &new_edges, gsi::arg ("input"), "@brief Creates a node converting polygons into it's edges.\n" ) + - gsi::constructor ("new_edge_length_filter", &new_edge_length_filter_node, gsi::arg ("input"), gsi::arg ("lmin", 0), gsi::arg ("lmax", std::numeric_limits::max (), "max"), gsi::arg ("inverse", false), + gsi::constructor ("new_edge_length_filter", &new_edge_length_filter, gsi::arg ("input"), gsi::arg ("inverse", false), gsi::arg ("lmin", 0), gsi::arg ("lmax", std::numeric_limits::max (), "max"), "@brief Creates a node filtering edges by their length.\n" ) + - gsi::constructor ("new_edge_orientation_filter", &new_edge_orientation_filter_node, gsi::arg ("input"), gsi::arg ("amin"), gsi::arg ("amax"), gsi::arg ("inverse", false), + gsi::constructor ("new_edge_orientation_filter", &new_edge_orientation_filter, gsi::arg ("input"), gsi::arg ("inverse", false), gsi::arg ("amin"), gsi::arg ("amax"), "@brief Creates a node filtering edges by their orientation.\n" ) + - gsi::constructor ("new_edge_pair_to_polygon", &new_edge_pair_to_polygon_node, gsi::arg ("input"), gsi::arg ("e", 0), - "@brief Creates a node converting edge pairs to polygons.\n" + gsi::constructor ("new_polygons", &new_polygons, gsi::arg ("input"), gsi::arg ("e", 0), + "@brief Creates a node converting the input to polygons.\n" + "@param e The enlargement parameter when converting edges or edge pairs to polygons.\n" ) + - gsi::constructor ("new_edge_pair_to_edges", &new_edge_pair_to_edges_node, gsi::arg ("input"), - "@brief Creates a node converting edge pairs to two edges each.\n" - ) + - gsi::constructor ("new_edge_pair_to_first_edges", &new_edge_pair_to_first_edges_node, gsi::arg ("input"), + gsi::constructor ("new_edge_pair_to_first_edges", &new_edge_pair_to_first_edges, gsi::arg ("input"), "@brief Creates a node delivering the first edge of each edges pair.\n" ) + - gsi::constructor ("new_edge_pair_to_second_edges", &new_edge_pair_to_second_edges_node, gsi::arg ("input"), + gsi::constructor ("new_edge_pair_to_second_edges", &new_edge_pair_to_second_edges, gsi::arg ("input"), "@brief Creates a node delivering the second edge of each edges pair.\n" ) + + gsi::constructor ("new_start_segments", &new_start_segments, gsi::arg ("input"), gsi::arg ("length"), gsi::arg ("fraction"), + "@brief Creates a node delivering a part at the beginning of each input edge.\n" + ) + + gsi::constructor ("new_end_segments", &new_end_segments, gsi::arg ("input"), gsi::arg ("length"), gsi::arg ("fraction"), + "@brief Creates a node delivering a part at the end of each input edge.\n" + ) + + gsi::constructor ("new_centers", &new_centers, gsi::arg ("input"), gsi::arg ("length"), gsi::arg ("fraction"), + "@brief Creates a node delivering a part at the center of each input edge.\n" + ) + + gsi::constructor ("new_extended", &new_extended, gsi::arg ("input"), gsi::arg ("ext_b"), gsi::arg ("ext_e"), gsi::arg ("ext_o"), gsi::arg ("ext_i"), + "@brief Creates a node delivering a polygonized version of the edges with the four extension parameters.\n" + ) + + gsi::constructor ("new_extended_in", &new_extended_in, gsi::arg ("input"), gsi::arg ("e"), + "@brief Creates a node delivering a polygonized, inside-extended version of the edges.\n" + ) + + gsi::constructor ("new_extended_out", &new_extended_out, gsi::arg ("input"), gsi::arg ("e"), + "@brief Creates a node delivering a polygonized, inside-extended version of the edges.\n" + ) + method ("description=", &db::CompoundRegionOperationNode::set_description, gsi::arg ("d"), "@brief Sets the description for this node" ) + diff --git a/src/db/unit_tests/dbCompoundOperationTests.cc b/src/db/unit_tests/dbCompoundOperationTests.cc index 665f12a31..6224bc65d 100644 --- a/src/db/unit_tests/dbCompoundOperationTests.cc +++ b/src/db/unit_tests/dbCompoundOperationTests.cc @@ -499,7 +499,7 @@ TEST(9_LogicalSelectOperation) run_test9 (_this, false); } -TEST(9d_EdgeFilterOperation) +TEST(9d_LogicalSelectOperation) { run_test9 (_this, true); } @@ -575,7 +575,7 @@ TEST(10_LogicalAndNotOperation) run_test10 (_this, false); } -TEST(10d_EdgeFilterOperation) +TEST(10d_LogicalAndNotOperation) { run_test10 (_this, true); } @@ -704,3 +704,48 @@ TEST(12d_EdgeBooleanOperations) { run_test12 (_this, true); } + +void run_test13 (tl::TestBase *_this, bool deep) +{ + db::Layout ly; + { + std::string fn (tl::testsrc ()); + fn += "/testdata/drc/compound_13.gds"; + tl::InputStream stream (fn); + db::Reader reader (stream); + reader.read (ly); + } + + db::RegionCheckOptions check_options; + check_options.metrics = db::Projection; + + db::DeepShapeStore dss; + + db::Region r, r2; + prep_layer (ly, 1, r, dss, deep); + prep_layer (ly, 2, r2, dss, deep); + + db::CompoundRegionOperationPrimaryNode *primary = new db::CompoundRegionOperationPrimaryNode (); + db::CompoundRegionToEdgeProcessingOperationNode *primary_edges = new db::CompoundRegionToEdgeProcessingOperationNode (new db::PolygonToEdgeProcessor (), primary, true); + + db::CompoundRegionEdgeProcessingOperationNode edge_proc (new db::EdgeSegmentSelector (-1, 1000, 0.1), primary_edges, true); + + db::Edges res = r.cop_to_edges (edge_proc); + + unsigned int l1000 = ly.get_layer (db::LayerProperties (1000, 0)); + res.insert_into (&ly, *ly.begin_top_down (), l1000); + + CHECKPOINT(); + db::compare_layouts (_this, ly, make_au ("13", deep)); +} + +TEST(13_EdgeProcessor) +{ + run_test13 (_this, false); +} + +TEST(13d_EdgeProcessor) +{ + run_test13 (_this, true); +} + diff --git a/testdata/drc/compound_13.gds b/testdata/drc/compound_13.gds new file mode 100644 index 000000000..6b2abc7f8 Binary files /dev/null and b/testdata/drc/compound_13.gds differ diff --git a/testdata/drc/compound_au13.gds b/testdata/drc/compound_au13.gds new file mode 100644 index 000000000..a5b5a309b Binary files /dev/null and b/testdata/drc/compound_au13.gds differ diff --git a/testdata/drc/compound_au13d.gds b/testdata/drc/compound_au13d.gds new file mode 100644 index 000000000..bf71747c5 Binary files /dev/null and b/testdata/drc/compound_au13d.gds differ