Added tests for region processors.

This commit is contained in:
Matthias Koefferlein 2019-02-20 21:40:43 +01:00
parent 503707f361
commit 91407ddaa9
8 changed files with 633 additions and 114 deletions

View File

@ -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") {

View File

@ -1003,6 +1003,8 @@ RegionDelegate *DeepEdges::extended (coord_type ext_b, coord_type ext_e, coord_t
db::Layout &layout = const_cast<db::Layout &> (m_merged_edges.layout ());
db::Cell &top_cell = const_cast<db::Cell &> (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<db::MagnificationReducer> vars (red);
vars.collect (m_merged_edges.layout (), m_merged_edges.initial_cell ());

View File

@ -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<db::Polygon> &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<db::Polygon> &result) const
{
db::Box b = poly.box ();
db::Point p1 (b.left () + db::coord_traits<db::Coord>::rounded (m_fx1 * b.width ()),
b.bottom () + db::coord_traits<db::Coord>::rounded (m_fy1 * b.height ()));
db::Point p2 (b.left () + db::coord_traits<db::Coord>::rounded (m_fx2 * b.width ()),
b.bottom () + db::coord_traits<db::Coord>::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<db::Edge> &result) const
{
db::Box b = poly.box ();
db::Point p1 (b.left () + db::coord_traits<db::Coord>::rounded (m_fx1 * b.width ()),
b.bottom () + db::coord_traits<db::Coord>::rounded (m_fy1 * b.height ()));
db::Point p2 (b.left () + db::coord_traits<db::Coord>::rounded (m_fx2 * b.width ()),
b.bottom () + db::coord_traits<db::Coord>::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<db::Polygon> &result) const
{
db::SimplePolygonContainer sp;
db::decompose_convex (poly, m_mode, sp);
for (std::vector <db::SimplePolygon>::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<db::Polygon> &result) const
{
db::SimplePolygonContainer sp;
db::decompose_trapezoids (poly, m_mode, sp);
for (std::vector <db::SimplePolygon>::const_iterator i = sp.polygons ().begin (); i != sp.polygons ().end (); ++i) {
result.push_back (db::simple_polygon_to_polygon (*i));
}
}
}

View File

@ -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<db::Polygon> &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<db::Polygon> *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<db::Edge> &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<db::Edge> *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<db::Polygon> &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<db::Edge> &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<db::Polygon> &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<db::Polygon> &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<db::Edge> &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<db::Polygon> &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<db::Polygon> &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<Point>
*/
template <class Object>
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<db::Polygon> &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

View File

@ -30,6 +30,7 @@
#include "dbShapes.h"
#include "dbDeepShapeStore.h"
#include "dbRegion.h"
#include "dbRegionProcessors.h"
#include "tlGlobPattern.h"
#include <memory>
@ -149,67 +150,14 @@ static typename Delivery::container_type *texts (const db::Region *r, const std:
return new_texts<Delivery> (r->iter (), pat, pattern);
}
template <class Delivery>
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<db::Edge> (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<db::Polygon> (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<db::Box> (q));
}
static db::Region minkowsky_sum_pc (const db::Region *r, const std::vector<db::Point> &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<std::vector<db::Point> > (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<db::Coord>::rounded (fx1 * b.width ()),
b.bottom () + db::coord_traits<db::Coord>::rounded (fy1 * b.height ()));
db::Point p2 (b.left () + db::coord_traits<db::Coord>::rounded (fx2 * b.width ()),
b.bottom () + db::coord_traits<db::Coord>::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<db::Coord>::rounded (fx1 * b.width ()),
b.bottom () + db::coord_traits<db::Coord>::rounded (fy1 * b.height ()));
db::Point p2 (b.left () + db::coord_traits<db::Coord>::rounded (fx2 * b.width ()),
b.bottom () + db::coord_traits<db::Coord>::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<db::Region> decl_Region ("db", "Region",
"@hide\n"
"This method is provided for DRC implementation.\n"
) +
factory_ext ("corners", &corners<BoxDelivery>, 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<db::Region> decl_Region ("db", "Region",
"\n"
"This function has been introduced in version 0.25.\n"
) +
method_ext ("corners_dots", &corners<DotDelivery>, 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"

View File

@ -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> (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> (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;

View File

@ -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> (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> (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;

BIN
testdata/algo/deep_region_au21.gds vendored Normal file

Binary file not shown.