From 91407ddaa97183c65144549362e52c259298825b Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Wed, 20 Feb 2019 21:40:43 +0100 Subject: [PATCH] Added tests for region processors. --- src/db/db/db.pro | 6 +- src/db/db/dbDeepEdges.cc | 2 + src/db/db/dbRegionProcessors.cc | 187 ++++++++++++++ src/db/db/dbRegionProcessors.h | 335 +++++++++++++++++++++++++ src/db/db/gsiDeclDbRegion.cc | 130 ++-------- src/db/unit_tests/dbDeepRegionTests.cc | 54 +++- src/db/unit_tests/dbRegion.cc | 33 +++ testdata/algo/deep_region_au21.gds | Bin 0 -> 10478 bytes 8 files changed, 633 insertions(+), 114 deletions(-) create mode 100644 src/db/db/dbRegionProcessors.cc create mode 100644 src/db/db/dbRegionProcessors.h create mode 100644 testdata/algo/deep_region_au21.gds diff --git a/src/db/db/db.pro b/src/db/db/db.pro index 38eb8638d..f74dd864e 100644 --- a/src/db/db/db.pro +++ b/src/db/db/db.pro @@ -171,7 +171,8 @@ SOURCES = \ dbDeepEdges.cc \ dbDeepEdgePairs.cc \ dbRegionUtils.cc \ - dbEdgesUtils.cc + dbEdgesUtils.cc \ + dbRegionProcessors.cc HEADERS = \ dbArray.h \ @@ -307,7 +308,8 @@ HEADERS = \ dbDeepEdges.h \ dbDeepEdgePairs.h \ dbRegionUtils.h \ - dbEdgesUtils.h + dbEdgesUtils.h \ + dbRegionProcessors.h !equals(HAVE_QT, "0") { diff --git a/src/db/db/dbDeepEdges.cc b/src/db/db/dbDeepEdges.cc index d7dc9c3cc..ea66d4bbe 100644 --- a/src/db/db/dbDeepEdges.cc +++ b/src/db/db/dbDeepEdges.cc @@ -1003,6 +1003,8 @@ RegionDelegate *DeepEdges::extended (coord_type ext_b, coord_type ext_e, coord_t db::Layout &layout = const_cast (m_merged_edges.layout ()); db::Cell &top_cell = const_cast (m_merged_edges.initial_cell ()); + // TODO: there is a special case when we'd need a MagnificationAndOrientationReducer: + // dots formally don't have an orientation, hence the interpretation is x and y. db::MagnificationReducer red; db::cell_variants_collector vars (red); vars.collect (m_merged_edges.layout (), m_merged_edges.initial_cell ()); diff --git a/src/db/db/dbRegionProcessors.cc b/src/db/db/dbRegionProcessors.cc new file mode 100644 index 000000000..4ee7b8830 --- /dev/null +++ b/src/db/db/dbRegionProcessors.cc @@ -0,0 +1,187 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2019 Matthias Koefferlein + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +#include "dbRegionProcessors.h" +#include "dbPolygon.h" +#include "dbPolygonGenerators.h" + +namespace db +{ + +// ----------------------------------------------------------------------------------- +// CornerDetectorCore implementation + +CornerDetectorCore::CornerDetectorCore (double angle_start, double angle_end) +{ + m_t_start = db::CplxTrans(1.0, angle_start, false, db::DVector ()); + m_t_end = db::CplxTrans(1.0, angle_end, false, db::DVector ()); + + m_big_angle = (angle_end - angle_start + db::epsilon) > 180.0; + m_all = (angle_end - angle_start - db::epsilon) > 360.0; +} + +void CornerDetectorCore::detect_corners (const db::Polygon &poly, const CornerPointDelivery &delivery) const +{ + size_t n = poly.holes () + 1; + for (size_t i = 0; i < n; ++i) { + + const db::Polygon::contour_type &ctr = poly.contour (int (i)); + size_t nn = ctr.size (); + if (nn > 2) { + + db::Point pp = ctr [nn - 2]; + db::Point pt = ctr [nn - 1]; + for (size_t j = 0; j < nn; ++j) { + + db::Point pn = ctr [j]; + + if (m_all) { + delivery.make_point (pt); + } else { + + db::Vector vin (pt - pp); + db::DVector vout (pn - pt); + + db::DVector v1 = m_t_start * vin; + db::DVector v2 = m_t_end * vin; + + bool vp1 = db::vprod_sign (v1, vout) >= 0; + bool vp2 = db::vprod_sign (v2, vout) <= 0; + + if (m_big_angle && (vp1 || vp2)) { + delivery.make_point (pt); + } else if (! m_big_angle && vp1 && vp2) { + if (db::sprod_sign (v1, vout) > 0 && db::sprod_sign (v2, vout) > 0) { + delivery.make_point (pt); + } + } + + } + + pp = pt; + pt = pn; + + } + + } + + } +} + +// ----------------------------------------------------------------------------------- +// Extents implementation + +void Extents::process (const db::Polygon &poly, std::vector &result) const +{ + db::Box box = poly.box ().enlarged (db::Vector (m_dx, m_dy)); + if (! box.empty ()) { + result.push_back (db::Polygon (box)); + } +} + +const TransformationReducer *Extents::vars () const +{ + if (m_dx == 0 && m_dy == 0) { + return 0; + } else if (m_dx == m_dy) { + return & m_isotropic_reducer; + } else { + return & m_anisotropic_reducer; + } +} + +// ----------------------------------------------------------------------------------- +// RelativeExtents implementation + +void RelativeExtents::process (const db::Polygon &poly, std::vector &result) const +{ + db::Box b = poly.box (); + db::Point p1 (b.left () + db::coord_traits::rounded (m_fx1 * b.width ()), + b.bottom () + db::coord_traits::rounded (m_fy1 * b.height ())); + db::Point p2 (b.left () + db::coord_traits::rounded (m_fx2 * b.width ()), + b.bottom () + db::coord_traits::rounded (m_fy2 * b.height ())); + db::Box box = db::Box (p1, p2).enlarged (db::Vector (m_dx, m_dy)); + if (! box.empty ()) { + result.push_back (db::Polygon (box)); + } +} + +const TransformationReducer *RelativeExtents::vars () const +{ + if (m_dx == 0 && m_dy == 0 && fabs (m_fx1) < db::epsilon && fabs (m_fy1) < db::epsilon && fabs (m_fx2) < db::epsilon && fabs (m_fy2) < db::epsilon) { + return 0; + } else if (m_dx == m_dy && fabs (m_fx1 - m_fy1) < db::epsilon && fabs (1.0 - (m_fx1 + m_fx2)) < db::epsilon && fabs (m_fx2 - m_fy2) < db::epsilon && fabs (1.0 - (m_fy1 + m_fy2)) < db::epsilon) { + return & m_isotropic_reducer; + } else { + return & m_anisotropic_reducer; + } +} + +// ----------------------------------------------------------------------------------- +// RelativeExtentsAsEdges implementation + +void RelativeExtentsAsEdges::process (const db::Polygon &poly, std::vector &result) const +{ + db::Box b = poly.box (); + db::Point p1 (b.left () + db::coord_traits::rounded (m_fx1 * b.width ()), + b.bottom () + db::coord_traits::rounded (m_fy1 * b.height ())); + db::Point p2 (b.left () + db::coord_traits::rounded (m_fx2 * b.width ()), + b.bottom () + db::coord_traits::rounded (m_fy2 * b.height ())); + result.push_back (db::Edge (p1, p2)); +} + +const TransformationReducer *RelativeExtentsAsEdges::vars () const +{ + return & m_anisotropic_reducer; +} + +bool RelativeExtentsAsEdges::result_must_not_be_merged () const +{ + // don't merge if the results will just be points + return (fabs (m_fx1 - m_fx2) < db::epsilon && fabs (m_fy1 - m_fy2) < db::epsilon); +} + +// ----------------------------------------------------------------------------------- +// ConvexDecomposition implementation + +void ConvexDecomposition::process (const db::Polygon &poly, std::vector &result) const +{ + db::SimplePolygonContainer sp; + db::decompose_convex (poly, m_mode, sp); + for (std::vector ::const_iterator i = sp.polygons ().begin (); i != sp.polygons ().end (); ++i) { + result.push_back (db::simple_polygon_to_polygon (*i)); + } +} + +// ----------------------------------------------------------------------------------- +// TrapezoidDecomposition implementation + +void TrapezoidDecomposition::process (const db::Polygon &poly, std::vector &result) const +{ + db::SimplePolygonContainer sp; + db::decompose_trapezoids (poly, m_mode, sp); + for (std::vector ::const_iterator i = sp.polygons ().begin (); i != sp.polygons ().end (); ++i) { + result.push_back (db::simple_polygon_to_polygon (*i)); + } +} + +} diff --git a/src/db/db/dbRegionProcessors.h b/src/db/db/dbRegionProcessors.h new file mode 100644 index 000000000..04b77a56e --- /dev/null +++ b/src/db/db/dbRegionProcessors.h @@ -0,0 +1,335 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2019 Matthias Koefferlein + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + + +#ifndef HDR_dbRegionProcessors +#define HDR_dbRegionProcessors + +#include "dbCommon.h" +#include "dbRegionDelegate.h" +#include "dbPolygonTools.h" + +namespace db +{ + +// ----------------------------------------------------------------------------------- +// Corner detection + +/** + * @brief An interface to accept corners + */ +class DB_PUBLIC CornerPointDelivery +{ +public: + virtual void make_point (const db::Point &pt) const = 0; +}; + +/** + * @brief An interface to accept corners and turns them into rectangles with 2*dim x 2*dim + */ +class DB_PUBLIC CornerRectDelivery + : public CornerPointDelivery +{ +public: + CornerRectDelivery (db::Coord dim, std::vector &result) + : m_d (dim, dim), mp_result (&result) + { } + + virtual void make_point (const db::Point &pt) const + { + mp_result->push_back (db::Polygon (db::Box (pt - m_d, pt + m_d))); + } + +private: + db::Vector m_d; + std::vector *mp_result; +}; + +/** + * @brief An interface to accept corners and turns them into degenerated edges (dots) + */ +class DB_PUBLIC CornerDotDelivery + : public CornerPointDelivery +{ +public: + CornerDotDelivery (std::vector &result) + : mp_result (&result) + { } + + virtual void make_point (const db::Point &pt) const + { + mp_result->push_back (db::Edge (pt, pt)); + } + +private: + db::Vector m_d; + std::vector *mp_result; +}; + +/** + * @brief A helper class implementing the core corner detection algorithm + */ +class DB_PUBLIC CornerDetectorCore +{ +public: + CornerDetectorCore (double angle_start, double angle_end); + virtual ~CornerDetectorCore () { } + + void detect_corners (const db::Polygon &poly, const CornerPointDelivery &delivery) const; + +private: + db::CplxTrans m_t_start, m_t_end; + bool m_big_angle, m_all; +}; + +/** + * @brief A corner detector delivering small retangles (2*dim x 2*dim) per detected corner + */ +class DB_PUBLIC CornersAsRectangles + : public db::PolygonProcessorBase, private CornerDetectorCore +{ +public: + CornersAsRectangles (double angle_start, double angle_end, db::Coord dim = 1) + : CornerDetectorCore (angle_start, angle_end), m_dim (dim) + { + // .. nothing yet .. + } + + void process (const db::Polygon &poly, std::vector &result) const + { + detect_corners (poly, CornerRectDelivery (m_dim, result)); + } + + virtual const TransformationReducer *vars () const { return &m_vars; } + virtual bool result_is_merged () const { return false; } // overlaps may happen + virtual bool result_must_not_be_merged () const { return false; } + virtual bool requires_raw_input () const { return false; } + virtual bool wants_variants () const { return false; } + +private: + db::Coord m_dim; + db::MagnificationReducer m_vars; +}; + +/** + * @brief A corner detector delivering degenerated edges (dots) for the corners + */ +class DB_PUBLIC CornersAsDots + : public db::PolygonToEdgeProcessorBase, private CornerDetectorCore +{ +public: + CornersAsDots (double angle_start, double angle_end) + : CornerDetectorCore (angle_start, angle_end) + { + // .. nothing yet .. + } + + void process (const db::Polygon &poly, std::vector &result) const + { + detect_corners (poly, CornerDotDelivery (result)); + } + + virtual const TransformationReducer *vars () const { return 0; } + virtual bool result_is_merged () const { return false; } + virtual bool result_must_not_be_merged () const { return true; } // to preserve dots + virtual bool requires_raw_input () const { return false; } + virtual bool wants_variants () const { return false; } +}; + +// ----------------------------------------------------------------------------------- +// Extents + +/** + * @brief A processor delivering the extents (bounding box) of the merged polygons + * This processor allows over- or undersizing of the resulting box by a given amount + */ +class DB_PUBLIC Extents + : public db::PolygonProcessorBase +{ +public: + Extents (db::Coord dx, db::Coord dy) + : m_dx (dx), m_dy (dy) + { + // .. nothing yet .. + } + + void process (const db::Polygon &poly, std::vector &result) const; + + virtual const TransformationReducer *vars () const; + virtual bool result_is_merged () const { return false; } + virtual bool result_must_not_be_merged () const { return false; } + virtual bool requires_raw_input () const { return false; } + virtual bool wants_variants () const { return true; } + +private: + db::Coord m_dx, m_dy; + db::MagnificationAndOrientationReducer m_anisotropic_reducer; + db::MagnificationReducer m_isotropic_reducer; +}; + +/** + * @brief A processor delivering the relative extents (bounding box) of the merged polygons + * This processor allows over- or undersizing of the resulting box by a given amount and delivery + * of a box relative to the original box. + */ +class DB_PUBLIC RelativeExtents + : public db::PolygonProcessorBase +{ +public: + RelativeExtents (double fx1, double fy1, double fx2, double fy2, db::Coord dx, db::Coord dy) + : m_fx1 (fx1), m_fy1 (fy1), m_fx2 (fx2), m_fy2 (fy2), m_dx (dx), m_dy (dy) + { + // .. nothing yet .. + } + + void process (const db::Polygon &poly, std::vector &result) const; + + virtual const TransformationReducer *vars () const; + virtual bool result_is_merged () const { return false; } + virtual bool result_must_not_be_merged () const { return false; } + virtual bool requires_raw_input () const { return false; } + virtual bool wants_variants () const { return false; } // variants are too common, so don't do this + +private: + double m_fx1, m_fy1, m_fx2, m_fy2; + db::Coord m_dx, m_dy; + db::MagnificationAndOrientationReducer m_anisotropic_reducer; + db::MagnificationReducer m_isotropic_reducer; +}; + +/** + * @brief A processor delivers one edge per merged polygon + * The edge runs from the relative coordinate fx1, fy1 (0: left/bottom, 1: right/top) to + * fx2, fy2. + * This processor allows over- or undersizing of the resulting box by a given amount and delivery + * of a box relative to the original box. + */ +class DB_PUBLIC RelativeExtentsAsEdges + : public db::PolygonToEdgeProcessorBase +{ +public: + RelativeExtentsAsEdges (double fx1, double fy1, double fx2, double fy2) + : m_fx1 (fx1), m_fy1 (fy1), m_fx2 (fx2), m_fy2 (fy2) + { + // .. nothing yet .. + } + + void process (const db::Polygon &poly, std::vector &result) const; + + virtual const TransformationReducer *vars () const; + virtual bool result_is_merged () const { return false; } + virtual bool result_must_not_be_merged () const; + virtual bool requires_raw_input () const { return false; } + virtual bool wants_variants () const { return false; } // variants are too common, so don't do this + +private: + double m_fx1, m_fy1, m_fx2, m_fy2; + db::MagnificationAndOrientationReducer m_anisotropic_reducer; +}; + +/** + * @brief A decomposition processor to deliver convex-only polygons + */ +class DB_PUBLIC ConvexDecomposition + : public db::PolygonProcessorBase +{ +public: + ConvexDecomposition (db::PreferredOrientation mode) + : m_mode (mode) + { + // .. nothing yet .. + } + + void process (const db::Polygon &poly, std::vector &result) const; + + virtual const TransformationReducer *vars () const { return &m_vars; } + virtual bool result_is_merged () const { return false; } + virtual bool result_must_not_be_merged () const { return true; } // would spoil the decomposition otherwise + virtual bool requires_raw_input () const { return false; } + virtual bool wants_variants () const { return true; } + +private: + db::PreferredOrientation m_mode; + db::OrientationReducer m_vars; +}; + +/** + * @brief A decomposition processor to deliver trapezoids + */ +class DB_PUBLIC TrapezoidDecomposition + : public db::PolygonProcessorBase +{ +public: + TrapezoidDecomposition (db::TrapezoidDecompositionMode mode) + : m_mode (mode) + { + // .. nothing yet .. + } + + void process (const db::Polygon &poly, std::vector &result) const; + + virtual const TransformationReducer *vars () const { return &m_vars; } + virtual bool result_is_merged () const { return false; } + virtual bool result_must_not_be_merged () const { return true; } // would spoil the decomposition otherwise + virtual bool requires_raw_input () const { return false; } + virtual bool wants_variants () const { return true; } + +private: + db::TrapezoidDecompositionMode m_mode; + db::OrientationReducer m_vars; +}; + +/** + * @brief Computes the Minkowsky sum between the polygons and the given object + * The object can be Edge, Polygon, Box and std::vector + */ +template +class DB_PUBLIC minkowsky_sum_computation + : public db::PolygonProcessorBase +{ +public: + minkowsky_sum_computation (const Object &q) + : m_q (q) + { + // .. nothing yet .. + } + + void process (const db::Polygon &poly, std::vector &result) const + { + result.push_back (db::minkowsky_sum (poly, m_q, false)); + } + + // TODO: could be less if the object is symmetric + virtual const TransformationReducer *vars () const { return &m_vars; } + virtual bool result_is_merged () const { return false; } + virtual bool result_must_not_be_merged () const { return false; } + virtual bool requires_raw_input () const { return false; } + virtual bool wants_variants () const { return true; } + +private: + Object m_q; + db::MagnificationAndOrientationReducer m_vars; +}; + +} + +#endif diff --git a/src/db/db/gsiDeclDbRegion.cc b/src/db/db/gsiDeclDbRegion.cc index 57d9b0dca..daaa37a5a 100644 --- a/src/db/db/gsiDeclDbRegion.cc +++ b/src/db/db/gsiDeclDbRegion.cc @@ -30,6 +30,7 @@ #include "dbShapes.h" #include "dbDeepShapeStore.h" #include "dbRegion.h" +#include "dbRegionProcessors.h" #include "tlGlobPattern.h" #include @@ -149,67 +150,14 @@ static typename Delivery::container_type *texts (const db::Region *r, const std: return new_texts (r->iter (), pat, pattern); } -template -static typename Delivery::container_type *corners (const db::Region *r, double angle_start, double angle_end) +static db::Edges corners_to_dots (const db::Region *r, double angle_start, double angle_end) { - db::CplxTrans t_start (1.0, angle_start, false, db::DVector ()); - db::CplxTrans t_end (1.0, angle_end, false, db::DVector ()); + return r->processed (db::CornersAsDots (angle_start, angle_end)); +} - bool big_angle = (angle_end - angle_start + db::epsilon) > 180.0; - bool all = (angle_end - angle_start - db::epsilon) > 360.0; - - Delivery delivery; - - for (db::Region::const_iterator p = r->begin_merged (); ! p.at_end (); ++p) { - - size_t n = p->holes () + 1; - for (size_t i = 0; i < n; ++i) { - - const db::Polygon::contour_type &ctr = p->contour (int (i)); - size_t nn = ctr.size (); - if (nn > 2) { - - db::Point pp = ctr [nn - 2]; - db::Point pt = ctr [nn - 1]; - for (size_t j = 0; j < nn; ++j) { - - db::Point pn = ctr [j]; - - if (all) { - delivery.insert (pt); - } else { - - db::Vector vin (pt - pp); - db::DVector vout (pn - pt); - - db::DVector v1 = t_start * vin; - db::DVector v2 = t_end * vin; - - bool vp1 = db::vprod_sign (v1, vout) >= 0; - bool vp2 = db::vprod_sign (v2, vout) <= 0; - - if (big_angle && (vp1 || vp2)) { - delivery.insert (pt); - } else if (! big_angle && vp1 && vp2) { - if (db::sprod_sign (v1, vout) > 0 && db::sprod_sign (v2, vout) > 0) { - delivery.insert (pt); - } - } - - } - - pp = pt; - pt = pn; - - } - - } - - } - - } - - return delivery.container.release (); +static db::Region corners_to_boxes (const db::Region *r, double angle_start, double angle_end, db::Coord dim) +{ + return r->processed (db::CornersAsRectangles (angle_start, angle_end, dim)); } static db::Region *new_si (const db::RecursiveShapeIterator &si) @@ -304,38 +252,22 @@ static void insert_si2 (db::Region *r, db::RecursiveShapeIterator si, db::ICplxT static db::Region minkowsky_sum_pe (const db::Region *r, const db::Edge &e) { - db::Region o; - for (db::Region::const_iterator p = r->begin_merged (); ! p.at_end (); ++p) { - o.insert (db::minkowsky_sum (*p, e, false)); - } - return o; + return r->processed (db::minkowsky_sum_computation (e)); } static db::Region minkowsky_sum_pp (const db::Region *r, const db::Polygon &q) { - db::Region o; - for (db::Region::const_iterator p = r->begin_merged (); ! p.at_end (); ++p) { - o.insert (db::minkowsky_sum (*p, q, false)); - } - return o; + return r->processed (db::minkowsky_sum_computation (q)); } static db::Region minkowsky_sum_pb (const db::Region *r, const db::Box &q) { - db::Region o; - for (db::Region::const_iterator p = r->begin_merged (); ! p.at_end (); ++p) { - o.insert (db::minkowsky_sum (*p, q, false)); - } - return o; + return r->processed (db::minkowsky_sum_computation (q)); } static db::Region minkowsky_sum_pc (const db::Region *r, const std::vector &q) { - db::Region o; - for (db::Region::const_iterator p = r->begin_merged (); ! p.at_end (); ++p) { - o.insert (db::minkowsky_sum (*p, q, false)); - } - return o; + return r->processed (db::minkowsky_sum_computation > (q)); } static db::Region &move_p (db::Region *r, const db::Vector &p) @@ -362,12 +294,7 @@ static db::Region moved_xy (const db::Region *r, db::Coord x, db::Coord y) static db::Region extents2 (const db::Region *r, db::Coord dx, db::Coord dy) { - db::Region e; - e.reserve (r->size ()); - for (db::Region::const_iterator i = r->begin_merged (); ! i.at_end (); ++i) { - e.insert (i->box ().enlarged (db::Vector (dx, dy))); - } - return e; + return r->processed (db::Extents (dx, dy)); } static db::Region extents1 (const db::Region *r, db::Coord d) @@ -382,33 +309,12 @@ static db::Region extents0 (const db::Region *r) static db::Region extent_refs (const db::Region *r, double fx1, double fy1, double fx2, double fy2, db::Coord dx, db::Coord dy) { - db::Region e; - e.reserve (r->size ()); - for (db::Region::const_iterator i = r->begin_merged (); ! i.at_end (); ++i) { - db::Box b = i->box (); - db::Point p1 (b.left () + db::coord_traits::rounded (fx1 * b.width ()), - b.bottom () + db::coord_traits::rounded (fy1 * b.height ())); - db::Point p2 (b.left () + db::coord_traits::rounded (fx2 * b.width ()), - b.bottom () + db::coord_traits::rounded (fy2 * b.height ())); - e.insert (db::Box (p1, p2).enlarged (db::Vector (dx, dy))); - } - return e; + return r->processed (db::RelativeExtents (fx1, fy1, fx2, fy2, dx, dy)); } static db::Edges extent_refs_edges (const db::Region *r, double fx1, double fy1, double fx2, double fy2) { - db::Edges e; - e.set_merged_semantics (false); - e.reserve (r->size ()); - for (db::Region::const_iterator i = r->begin_merged (); ! i.at_end (); ++i) { - db::Box b = i->box (); - db::Point p1 (b.left () + db::coord_traits::rounded (fx1 * b.width ()), - b.bottom () + db::coord_traits::rounded (fy1 * b.height ())); - db::Point p2 (b.left () + db::coord_traits::rounded (fx2 * b.width ()), - b.bottom () + db::coord_traits::rounded (fy2 * b.height ())); - e.insert (db::Edge (p1, p2)); - } - return e; + return r->processed (db::RelativeExtentsAsEdges (fx1, fy1, fx2, fy2)); } static db::Region with_perimeter1 (const db::Region *r, db::Region::perimeter_type perimeter, bool inverse) @@ -1196,11 +1102,13 @@ Class decl_Region ("db", "Region", "@hide\n" "This method is provided for DRC implementation.\n" ) + - factory_ext ("corners", &corners, gsi::arg ("angle_start", -180.0), gsi::arg ("angle_end", 180.0), + method_ext ("corners", &corners_to_boxes, gsi::arg ("angle_start", -180.0), gsi::arg ("angle_end", 180.0), gsi::arg ("dim", 1), "@brief This method will select all corners whose attached edges satisfy the angle condition.\n" "\n" "The angle values specify a range of angles: all corners whose attached edges form an angle " - "between angle_start and angle_end will be reported as small (2x2 DBU) boxes. The angle is measured " + "between angle_start and angle_end will be reported boxes with 2*dim x 2*dim dimension. The default dimension is 2x2 DBU.\n" + "\n" + "The angle is measured " "between the incoming and the outcoming edge in mathematical sense: a positive value is a turn left " "while a negative value is a turn right. Since polygon contours are oriented clockwise, positive " "angles will report concave corners while negative ones report convex ones.\n" @@ -1209,7 +1117,7 @@ Class decl_Region ("db", "Region", "\n" "This function has been introduced in version 0.25.\n" ) + - method_ext ("corners_dots", &corners, gsi::arg ("angle_start", -180.0), gsi::arg ("angle_end", 180.0), + method_ext ("corners_dots", &corners_to_dots, gsi::arg ("angle_start", -180.0), gsi::arg ("angle_end", 180.0), "@brief This method will select all corners whose attached edges satisfy the angle condition.\n" "\n" "This method is similar to \\corners, but delivers an \\Edges collection with dot-like edges for each corner.\n" diff --git a/src/db/unit_tests/dbDeepRegionTests.cc b/src/db/unit_tests/dbDeepRegionTests.cc index 65b0d908f..8f10a29e1 100644 --- a/src/db/unit_tests/dbDeepRegionTests.cc +++ b/src/db/unit_tests/dbDeepRegionTests.cc @@ -27,6 +27,7 @@ #include "dbRegion.h" #include "dbEdges.h" #include "dbRegionUtils.h" +#include "dbRegionProcessors.h" #include "dbEdgesUtils.h" #include "dbDeepShapeStore.h" #include "tlUnitTest.h" @@ -1050,7 +1051,7 @@ TEST(19_GridCheck) db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/deep_region_au19.gds"); } -TEST(19_AngleCheck) +TEST(20_AngleCheck) { db::Layout ly; { @@ -1083,6 +1084,57 @@ TEST(19_AngleCheck) db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/deep_region_au20.gds"); } +TEST(21_Processors) +{ + db::Layout ly; + { + std::string fn (tl::testsrc ()); + fn += "/testdata/algo/deep_region_area_peri_l1.gds"; + tl::InputStream stream (fn); + db::Reader reader (stream); + reader.read (ly); + } + + db::cell_index_type top_cell_index = *ly.begin_top_down (); + db::Cell &top_cell = ly.cell (top_cell_index); + + db::DeepShapeStore dss; + + unsigned int l1 = ly.get_layer (db::LayerProperties (1, 0)); + db::Region r1 (db::RecursiveShapeIterator (ly, top_cell, l1), dss); + + db::Layout target; + unsigned int target_top_cell_index = target.add_cell (ly.cell_name (top_cell_index)); + + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (1, 0)), r1); + + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (10, 0)), r1.processed (db::CornersAsDots (-180.0, 180.0))); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (11, 0)), r1.processed (db::CornersAsDots (0.0, 180.0))); + db::Region ext; + r1.processed (db::CornersAsDots (0.0, 180.0)).extended (ext, 1000, 1000, 2000, 2000); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (12, 0)), ext); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (13, 0)), r1.processed (db::CornersAsRectangles (-180.0, 180.0, 2000))); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (14, 0)), r1.processed (db::CornersAsRectangles (0.0, 180.0, 2000))); + + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (20, 0)), r1.processed (db::Extents (0, 0))); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (21, 0)), r1.processed (db::Extents (1000, 2000))); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (22, 0)), r1.processed (db::RelativeExtents (0, 0, 1.0, 1.0, 0, 0))); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (23, 0)), r1.processed (db::RelativeExtents (0.25, 0.4, 0.75, 0.6, 1000, 2000))); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (24, 0)), r1.processed (db::RelativeExtentsAsEdges (0, 0, 1.0, 1.0))); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (25, 0)), r1.processed (db::RelativeExtentsAsEdges (0.5, 0.5, 0.5, 0.5))); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (26, 0)), r1.processed (db::RelativeExtentsAsEdges (0.25, 0.4, 0.75, 0.6))); + + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (30, 0)), r1.processed (db::minkowsky_sum_computation (db::Box (-1000, -2000, 3000, 4000)))); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (31, 0)), r1.processed (db::minkowsky_sum_computation (db::Edge (-1000, 0, 3000, 0)))); + + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (40, 0)), r1.processed (db::TrapezoidDecomposition (db::TD_htrapezoids))); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (41, 0)), r1.processed (db::ConvexDecomposition (db::PO_vertical))); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (42, 0)), r1.processed (db::ConvexDecomposition (db::PO_horizontal))); + + CHECKPOINT(); + db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/deep_region_au21.gds"); +} + TEST(100_Integration) { db::Layout ly; diff --git a/src/db/unit_tests/dbRegion.cc b/src/db/unit_tests/dbRegion.cc index 706647a2c..6fb883ae1 100644 --- a/src/db/unit_tests/dbRegion.cc +++ b/src/db/unit_tests/dbRegion.cc @@ -25,6 +25,7 @@ #include "dbRegion.h" #include "dbRegionUtils.h" +#include "dbRegionProcessors.h" #include "dbEdgesUtils.h" #include "dbBoxScanner.h" @@ -1340,6 +1341,38 @@ TEST(30c) EXPECT_EQ (r.to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)"); } +TEST(100_Processors) +{ + db::Region r; + r.insert (db::Box (db::Point (0, 0), db::Point (100, 200))); + r.insert (db::Box (db::Point (0, 300), db::Point (200, 400))); + r.insert (db::Box (db::Point (0, 300), db::Point (200, 400))); + r.insert (db::Box (db::Point (100, 300), db::Point (200, 500))); + + EXPECT_EQ (r.processed (db::CornersAsDots (-180.0, 180.0)).to_string (), "(100,0;100,0);(0,0;0,0);(0,200;0,200);(100,200;100,200);(200,300;200,300);(0,300;0,300);(0,400;0,400);(100,400;100,400);(100,500;100,500);(200,500;200,500)"); + EXPECT_EQ (r.processed (db::CornersAsDots (0.0, 180.0)).to_string (), "(100,400;100,400)"); + db::Region ext; + r.processed (db::CornersAsDots (0.0, 180.0)).extended (ext, 10, 10, 20, 20); + EXPECT_EQ (ext.to_string (), "(90,380;90,420;110,420;110,380)"); + EXPECT_EQ (r.processed (db::CornersAsRectangles (-180.0, 180.0, 2)).to_string (), "(98,-2;98,2;102,2;102,-2);(-2,-2;-2,2;2,2;2,-2);(-2,198;-2,202;2,202;2,198);(98,198;98,202;102,202;102,198);(198,298;198,302;202,302;202,298);(-2,298;-2,302;2,302;2,298);(-2,398;-2,402;2,402;2,398);(98,398;98,402;102,402;102,398);(98,498;98,502;102,502;102,498);(198,498;198,502;202,502;202,498)"); + EXPECT_EQ (r.processed (db::CornersAsRectangles (0.0, 180.0, 2)).to_string (), "(98,398;98,402;102,402;102,398)"); + + EXPECT_EQ (r.processed (db::Extents (0, 0)).to_string (), "(0,0;0,200;100,200;100,0);(0,300;0,500;200,500;200,300)"); + EXPECT_EQ (r.processed (db::Extents (10, 20)).to_string (), "(-10,-20;-10,220;110,220;110,-20);(-10,280;-10,520;210,520;210,280)"); + EXPECT_EQ (r.processed (db::RelativeExtents (0, 0, 1.0, 1.0, 0, 0)).to_string (), "(0,0;0,200;100,200;100,0);(0,300;0,500;200,500;200,300)"); + EXPECT_EQ (r.processed (db::RelativeExtents (0.25, 0.4, 0.75, 0.6, 10, 20)).to_string (), "(15,60;15,140;85,140;85,60);(40,360;40,440;160,440;160,360)"); + EXPECT_EQ (r.processed (db::RelativeExtentsAsEdges (0, 0, 1.0, 1.0)).to_string (), "(0,0;100,200);(0,300;200,500)"); + EXPECT_EQ (r.processed (db::RelativeExtentsAsEdges (0.5, 0.5, 0.5, 0.5)).to_string (), "(50,100;50,100);(100,400;100,400)"); + EXPECT_EQ (r.processed (db::RelativeExtentsAsEdges (0.25, 0.4, 0.75, 0.6)).to_string (), "(25,80;75,120);(50,380;150,420)"); + + EXPECT_EQ (r.processed (db::minkowsky_sum_computation (db::Box (-10, -20, 30, 40))).to_string (), "(-10,-20;-10,240;130,240;130,-20);(-10,280;-10,440;90,440;90,540;230,540;230,280)"); + EXPECT_EQ (r.processed (db::minkowsky_sum_computation (db::Edge (-10, 0, 30, 0))).to_string (), "(-10,0;-10,200;130,200;130,0);(-10,300;-10,400;90,400;90,500;230,500;230,300)"); + + EXPECT_EQ (r.processed (db::TrapezoidDecomposition (db::TD_htrapezoids)).to_string (), "(0,0;0,200;100,200;100,0);(100,300;100,500;200,500;200,300);(0,300;0,400;100,400;100,300)"); + EXPECT_EQ (r.processed (db::ConvexDecomposition (db::PO_vertical)).to_string (), "(0,0;0,200;100,200;100,0);(100,300;100,500;200,500;200,300);(0,300;0,400;100,400;100,300)"); + EXPECT_EQ (r.processed (db::ConvexDecomposition (db::PO_horizontal)).to_string (), "(0,0;0,200;100,200;100,0);(100,400;100,500;200,500;200,400);(0,300;0,400;200,400;200,300)"); +} + TEST(issue_228) { db::Region r; diff --git a/testdata/algo/deep_region_au21.gds b/testdata/algo/deep_region_au21.gds new file mode 100644 index 0000000000000000000000000000000000000000..e166ba578ce4a88b700fd50023204a3a56b39352 GIT binary patch literal 10478 zcmeHNUud007C+xja(k1u8rQgurfegMrrmDW7SSq;wAp>=s%U8alZwkmLC6ZS7L=`s zs1Hhfk>G=r6{O3$yMew4U1_Tp`k>N+f)Ruu72_Wy58@UDH;BFC`JFT8elz!GzWd#~ z**6RE7thRZX3m*&&YYPqRHaH~k~U_QHJ?+3hUgNyif#yhr&^_Y>+i>jhI;yL+Wp-1 zx4iSOb2t3%_^%JYbk7~Mv9Ewvt&U&0ov61)R9#=;k*gO}h-m9zk8>wpb?%KfDqRD~Odr{8+dB{I`$T|HXx@|Q4F*z{eZwUF{KIPme?>P7EQ$)Y~hG=-Fp~->D z@7MJYdw%tDXi>YchyTk~8DzX|)Mk~H$f`Z-(lo2@EK%?ivMx)rh9;c*^mXU{J598? z9%=Xs&-xA4boHQEkdf%xH=TR!bdLLeP>U;CzZQ#c3dh^FsQtDr>Nsp&85f9gunUUT zuVuV3Kc091c-OHP0OK9Z<=4F$=@;;cupV%+9_}Y&D4JX_^q|fEDryiG5AS)w3efFW|>nW;MsY<*arq7ps;*VRy0p|1nmjR^u3L#B6AxC{{Q3Y7B1f)qOqoW{%AkM@{GZ zhvP-Digv^g#zTx@JVW>zs%}N=m)qi}Se2Vg5Nm3q4s%t&U)5OUy6v}Iw+(RJ^fOd& z)ypy>TDP%p{NIfDw+=S}WWDsrI{KOzmfA@+STTx&2jdth0>% zZO#hzzuoMAHLcsDx}V6o`B65F|M%If{_@$Z$puBrHnY^K)jMvVX!tqLC|(U)ZQ9lF zYK{PF*|f{KXP2~Pt;7bm)Gn^@`$ivaL`1Ni>T|m&+qWQy|9AbK(TFC@lD)vQm^B+M zK5|C-c8_}Xnq#hVfc3w0CR`my>dL%(Yz&^S=Y)=G=!h=iZ(M65YI0YdA%d168Ab-SGkMS1a7q_Af|pt^~`o!Zmcp!ipO!7u%It zVWejVEcQC7aLxPL&vkxDe3d+woa_9ObLXarS%M{5usB#A%dxV*j=B0{Q)F08jeHqs(JD7UvaV8Fs+pydx~jKW%+OR>r*z!?_A>@wj0n z{IHPK>Ki^6L}xs1-y0q#0^g`D4CnIyrZ%T(FG-fd`d#*iP>D3mSC$>}7xc#5*6JybBwaHvpJfaF*Sc>?Zd(sWPW92Q22t( zv-Tps_z#aGe#86*!hawy@Sn=pr2Yql-j(BwQ$V*NVT__QMC zI?LJ4(B$L37O81163nkJh}N#-!T0S6{n4)Z6Uh0K`8gtg`t~Frwn9H3@-Oz!(Bw_|H(Wp0imrZO7S*q-Kh5+1 zZ8=AiGbZQ1ct-dHWIplzq=C#6c{~2szF*z*4NcCNnqStK?ElfXkLJ4&>h_y?-%yF` z9Vx$`aEid!?SS8?hovqKYF4YRqk4HIepr7#yVR%+Ghf9wr5JJLBA+c|MOJtKhFT;8EYt=u71#K685;7O);)=junMD7*0y zSAQ$MDHpKr{=&HjPZOQl>f9q^k(bz)hFkGBIANCHEKd)x#~E&0#HoSTYCSzrH9Rn@ zSrv#XPWda2zZI`+$R0jhxGGWhk40x_a-dkSrdib1C;TvraMhlzXUiKVvWR{8Xy}J* zJie&+EsVk(_2FPq~QSMV5`e zx^|&|!0$@`fZxb)o#-F&yU;)Qk`%5#dete~zZU+vDSbD^TN3iSBF5A4IUYj)Y2s_X fZhbM%`E?G&3GCReO5$$}y}k4!Y;Lty literal 0 HcmV?d00001