mirror of https://github.com/KLayout/klayout.git
Introducing edge modes for DRC 'edges' function - allows easy extraction of convex edges only
This commit is contained in:
parent
156f0f4477
commit
853de5b0ae
|
|
@ -143,7 +143,7 @@ AsIfFlatRegion::to_string (size_t nmax) const
|
|||
}
|
||||
|
||||
EdgesDelegate *
|
||||
AsIfFlatRegion::edges (const EdgeFilterBase *filter) const
|
||||
AsIfFlatRegion::edges (const EdgeFilterBase *filter, const PolygonToEdgeProcessorBase *proc) const
|
||||
{
|
||||
std::unique_ptr<FlatEdges> result (new FlatEdges ());
|
||||
db::PropertyMapper pm (result->properties_repository (), properties_repository ());
|
||||
|
|
@ -154,17 +154,41 @@ AsIfFlatRegion::edges (const EdgeFilterBase *filter) const
|
|||
}
|
||||
result->reserve (n);
|
||||
|
||||
std::vector<db::Edge> heap;
|
||||
|
||||
for (RegionIterator p (begin_merged ()); ! p.at_end (); ++p) {
|
||||
|
||||
db::properties_id_type prop_id = p.prop_id ();
|
||||
for (db::Polygon::polygon_edge_iterator e = p->begin_edge (); ! e.at_end (); ++e) {
|
||||
if (! filter || filter->selected (*e)) {
|
||||
if (prop_id != 0) {
|
||||
result->insert (db::EdgeWithProperties (*e, pm (prop_id)));
|
||||
} else {
|
||||
result->insert (*e);
|
||||
|
||||
if (proc) {
|
||||
|
||||
heap.clear ();
|
||||
proc->process (*p, heap);
|
||||
|
||||
for (auto e = heap.begin (); e != heap.end (); ++e) {
|
||||
if (! filter || filter->selected (*e)) {
|
||||
if (prop_id != 0) {
|
||||
result->insert (db::EdgeWithProperties (*e, pm (prop_id)));
|
||||
} else {
|
||||
result->insert (*e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
for (db::Polygon::polygon_edge_iterator e = p->begin_edge (); ! e.at_end (); ++e) {
|
||||
if (! filter || filter->selected (*e)) {
|
||||
if (prop_id != 0) {
|
||||
result->insert (db::EdgeWithProperties (*e, pm (prop_id)));
|
||||
} else {
|
||||
result->insert (*e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return result.release ();
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ public:
|
|||
|
||||
virtual RegionDelegate *scaled_and_snapped (db::Coord gx, db::Coord mx, db::Coord dx, db::Coord gy, db::Coord my, db::Coord dy);
|
||||
|
||||
virtual EdgesDelegate *edges (const EdgeFilterBase *) const;
|
||||
virtual EdgesDelegate *edges (const EdgeFilterBase *filter, const db::PolygonToEdgeProcessorBase *proc) const;
|
||||
|
||||
virtual RegionDelegate *process_in_place (const PolygonProcessorBase &filter)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1335,7 +1335,7 @@ DeepRegion::snapped (db::Coord gx, db::Coord gy)
|
|||
}
|
||||
|
||||
EdgesDelegate *
|
||||
DeepRegion::edges (const EdgeFilterBase *filter) const
|
||||
DeepRegion::edges (const EdgeFilterBase *filter, const PolygonToEdgeProcessorBase *proc) const
|
||||
{
|
||||
std::unique_ptr<db::DeepEdges> res (new db::DeepEdges (deep_layer ().derived ()));
|
||||
|
||||
|
|
@ -1343,7 +1343,7 @@ DeepRegion::edges (const EdgeFilterBase *filter) const
|
|||
return res.release ();
|
||||
}
|
||||
|
||||
if (! filter && merged_semantics () && ! merged_polygons_available ()) {
|
||||
if (! proc && ! filter && merged_semantics () && ! merged_polygons_available ()) {
|
||||
|
||||
// Hierarchical edge detector - no pre-merge required
|
||||
|
||||
|
|
@ -1388,15 +1388,32 @@ DeepRegion::edges (const EdgeFilterBase *filter) const
|
|||
const db::Shapes &s = c->shapes (polygons.layer ());
|
||||
db::Shapes &st = c->shapes (res->deep_layer ().layer ());
|
||||
|
||||
std::vector<db::Edge> heap;
|
||||
|
||||
for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::All); ! si.at_end (); ++si) {
|
||||
|
||||
db::Polygon poly;
|
||||
si->polygon (poly);
|
||||
|
||||
for (db::Polygon::polygon_edge_iterator e = poly.begin_edge (); ! e.at_end (); ++e) {
|
||||
if (! filter || filter->selected ((*e).transformed (tr))) {
|
||||
st.insert (db::EdgeWithProperties (*e, pm (si->prop_id ())));
|
||||
if (proc) {
|
||||
|
||||
heap.clear ();
|
||||
proc->process (poly, heap);
|
||||
|
||||
for (auto e = heap.begin (); e != heap.end (); ++e) {
|
||||
if (! filter || filter->selected ((*e).transformed (tr))) {
|
||||
st.insert (db::EdgeWithProperties (*e, pm (si->prop_id ())));
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
for (db::Polygon::polygon_edge_iterator e = poly.begin_edge (); ! e.at_end (); ++e) {
|
||||
if (! filter || filter->selected ((*e).transformed (tr))) {
|
||||
st.insert (db::EdgeWithProperties (*e, pm (si->prop_id ())));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -119,7 +119,7 @@ public:
|
|||
|
||||
virtual RegionDelegate *snapped (db::Coord gx, db::Coord gy);
|
||||
|
||||
virtual EdgesDelegate *edges (const EdgeFilterBase *) const;
|
||||
virtual EdgesDelegate *edges (const EdgeFilterBase *filter, const db::PolygonToEdgeProcessorBase *proc) const;
|
||||
|
||||
virtual RegionDelegate *process_in_place (const PolygonProcessorBase &filter);
|
||||
virtual RegionDelegate *processed (const PolygonProcessorBase &filter) const;
|
||||
|
|
|
|||
|
|
@ -176,7 +176,7 @@ EmptyRegion::angle_check (double, double, bool) const
|
|||
}
|
||||
|
||||
EdgesDelegate *
|
||||
EmptyRegion::edges (const EdgeFilterBase *) const
|
||||
EmptyRegion::edges (const EdgeFilterBase *, const PolygonToEdgeProcessorBase *) const
|
||||
{
|
||||
return new EmptyEdges ();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ public:
|
|||
virtual RegionDelegate *scaled_and_snapped_in_place (db::Coord, db::Coord, db::Coord, db::Coord, db::Coord, db::Coord) { return this; }
|
||||
virtual RegionDelegate *scaled_and_snapped (db::Coord, db::Coord, db::Coord, db::Coord, db::Coord, db::Coord) { return new EmptyRegion (); }
|
||||
|
||||
virtual EdgesDelegate *edges (const EdgeFilterBase *) const;
|
||||
virtual EdgesDelegate *edges (const EdgeFilterBase *, const PolygonToEdgeProcessorBase *) const;
|
||||
virtual RegionDelegate *filter_in_place (const PolygonFilterBase &) { return this; }
|
||||
virtual RegionDelegate *filtered (const PolygonFilterBase &) const { return new EmptyRegion (); }
|
||||
virtual RegionDelegate *process_in_place (const PolygonProcessorBase &) { return this; }
|
||||
|
|
|
|||
|
|
@ -770,7 +770,7 @@ public:
|
|||
*/
|
||||
Edges edges () const
|
||||
{
|
||||
return Edges (mp_delegate->edges (0));
|
||||
return Edges (mp_delegate->edges (0, 0));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -783,7 +783,34 @@ public:
|
|||
*/
|
||||
Edges edges (const EdgeFilterBase &filter) const
|
||||
{
|
||||
return mp_delegate->edges (&filter);
|
||||
return mp_delegate->edges (&filter, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns an edge set containing all edges of the polygons in this region
|
||||
*
|
||||
* Merged semantics applies. In merged semantics, only full, outer edges are delivered.
|
||||
* This version allows specifying a polygon to edge processor with additional features
|
||||
* like extraction of convex edges only.
|
||||
*/
|
||||
Edges edges (const db::PolygonToEdgeProcessorBase &proc) const
|
||||
{
|
||||
return Edges (mp_delegate->edges (0, &proc));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns an edge set containing all edges of the polygons in this region
|
||||
*
|
||||
* This version allows one to specify a filter by which the edges are filtered before they are
|
||||
* returned.
|
||||
*
|
||||
* Merged semantics applies. In merged semantics, only full, outer edges are delivered.
|
||||
* This version allows specifying a polygon to edge processor with additional features
|
||||
* like extraction of convex edges only.
|
||||
*/
|
||||
Edges edges (const EdgeFilterBase &filter, const db::PolygonToEdgeProcessorBase &proc) const
|
||||
{
|
||||
return mp_delegate->edges (&filter, &proc);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -267,7 +267,7 @@ public:
|
|||
virtual RegionDelegate *scaled_and_snapped_in_place (db::Coord gx, db::Coord mx, db::Coord dx, db::Coord gy, db::Coord my, db::Coord dy) = 0;
|
||||
virtual RegionDelegate *scaled_and_snapped (db::Coord gx, db::Coord mx, db::Coord dx, db::Coord gy, db::Coord my, db::Coord dy) = 0;
|
||||
|
||||
virtual EdgesDelegate *edges (const EdgeFilterBase *filter) const = 0;
|
||||
virtual EdgesDelegate *edges (const EdgeFilterBase *filter, const db::PolygonToEdgeProcessorBase *proc) const = 0;
|
||||
virtual RegionDelegate *filter_in_place (const PolygonFilterBase &filter) = 0;
|
||||
virtual RegionDelegate *filtered (const PolygonFilterBase &filter) const = 0;
|
||||
virtual RegionDelegate *process_in_place (const PolygonProcessorBase &filter) = 0;
|
||||
|
|
|
|||
|
|
@ -136,10 +136,71 @@ bool RelativeExtentsAsEdges::result_must_not_be_merged () const
|
|||
// -----------------------------------------------------------------------------------
|
||||
// PolygonToEdgeProcessor implementation
|
||||
|
||||
PolygonToEdgeProcessor::PolygonToEdgeProcessor (PolygonToEdgeProcessor::EdgeMode mode)
|
||||
: m_mode (mode)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
inline void
|
||||
next (db::Polygon::contour_type::simple_iterator &iter, const db::Polygon::contour_type &contour)
|
||||
{
|
||||
if (++iter == contour.end ()) {
|
||||
iter = contour.begin ();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
contour_to_edges (const db::Polygon::contour_type &contour, PolygonToEdgeProcessor::EdgeMode mode, std::vector<db::Edge> &result)
|
||||
{
|
||||
if (contour.size () < 3) {
|
||||
return;
|
||||
}
|
||||
|
||||
db::Polygon::contour_type::simple_iterator pm1 = contour.begin ();
|
||||
db::Polygon::contour_type::simple_iterator p0 = pm1;
|
||||
next (p0, contour);
|
||||
db::Polygon::contour_type::simple_iterator p1 = p0;
|
||||
next (p1, contour);
|
||||
db::Polygon::contour_type::simple_iterator p2 = p1;
|
||||
next (p2, contour);
|
||||
|
||||
while (pm1 != contour.end ()) {
|
||||
|
||||
int s1 = db::vprod_sign (*p0 - *pm1, *p1 - *p0);
|
||||
int s2 = db::vprod_sign (*p1 - *p0, *p2 - *p1);
|
||||
|
||||
if (mode == PolygonToEdgeProcessor::All ||
|
||||
(mode == PolygonToEdgeProcessor::Convex && s1 < 0 && s2 < 0) ||
|
||||
(mode == PolygonToEdgeProcessor::Concave && s1 > 0 && s2 > 0) ||
|
||||
(mode == PolygonToEdgeProcessor::StepOut && s1 > 0 && s2 < 0) ||
|
||||
(mode == PolygonToEdgeProcessor::StepIn && s1 < 0 && s2 > 0) ||
|
||||
(mode == PolygonToEdgeProcessor::Step && s1 * s2 < 0)) {
|
||||
result.push_back (db::Edge (*p0, *p1));
|
||||
}
|
||||
|
||||
++pm1;
|
||||
next (p0, contour);
|
||||
next (p1, contour);
|
||||
next (p2, contour);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void PolygonToEdgeProcessor::process (const db::Polygon &poly, std::vector<db::Edge> &result) const
|
||||
{
|
||||
for (db::Polygon::polygon_edge_iterator e = poly.begin_edge (); ! e.at_end (); ++e) {
|
||||
result.push_back (*e);
|
||||
if (m_mode == All) {
|
||||
|
||||
for (db::Polygon::polygon_edge_iterator e = poly.begin_edge (); ! e.at_end (); ++e) {
|
||||
result.push_back (*e);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
for (unsigned int i = 0; i < poly.holes () + 1; ++i) {
|
||||
contour_to_edges (poly.contour (i), m_mode, result);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -293,12 +293,14 @@ class DB_PUBLIC PolygonToEdgeProcessor
|
|||
: public db::PolygonToEdgeProcessorBase
|
||||
{
|
||||
public:
|
||||
PolygonToEdgeProcessor ()
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
enum EdgeMode { All = 0, Convex, Concave, StepIn, StepOut, Step };
|
||||
|
||||
PolygonToEdgeProcessor (EdgeMode mode = All);
|
||||
|
||||
void process (const db::Polygon &poly, std::vector<db::Edge> &result) const;
|
||||
|
||||
private:
|
||||
EdgeMode m_mode;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -316,13 +316,13 @@ static db::CompoundRegionOperationNode *new_minkowski_sum_node4 (db::CompoundReg
|
|||
return new db::CompoundRegionProcessingOperationNode (new db::minkowski_sum_computation<std::vector<db::Point> > (p), input, true /*processor is owned*/);
|
||||
}
|
||||
|
||||
static db::CompoundRegionOperationNode *new_edges (db::CompoundRegionOperationNode *input)
|
||||
static db::CompoundRegionOperationNode *new_edges (db::CompoundRegionOperationNode *input, db::PolygonToEdgeProcessor::EdgeMode edge_mode)
|
||||
{
|
||||
check_non_null (input, "input");
|
||||
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*/);
|
||||
return new db::CompoundRegionToEdgeProcessingOperationNode (new db::PolygonToEdgeProcessor (edge_mode), input, true /*processor is owned*/);
|
||||
} else {
|
||||
input->keep ();
|
||||
return input;
|
||||
|
|
@ -726,8 +726,12 @@ Class<db::CompoundRegionOperationNode> decl_CompoundRegionOperationNode ("db", "
|
|||
"@brief Creates a node filtering the input for rectangular or square shapes.\n"
|
||||
"If 'is_square' is true, only squares will be selected. If 'inverse' is true, the non-rectangle/non-square shapes are returned.\n"
|
||||
) +
|
||||
gsi::constructor ("new_edges", &new_edges, gsi::arg ("input"),
|
||||
gsi::constructor ("new_edges", &new_edges, gsi::arg ("input"), gsi::arg ("mode", db::PolygonToEdgeProcessor::All, "All"),
|
||||
"@brief Creates a node converting polygons into its edges.\n"
|
||||
"The 'mode' argument allows selecting specific edges when generating edges from a polygon. "
|
||||
"See \\EdgeMode for the various options. By default, all edges are generated from polygons.\n"
|
||||
"\n"
|
||||
"The 'mode' argument has been added in version 0.29."
|
||||
) +
|
||||
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<db::Edge::distance_type>::max (), "max"),
|
||||
"@brief Creates a node filtering edges by their length.\n"
|
||||
|
|
|
|||
|
|
@ -780,6 +780,13 @@ size_dvm (db::Region *region, const db::Vector &dv, unsigned int mode)
|
|||
return *region;
|
||||
}
|
||||
|
||||
static db::Edges
|
||||
edges (const db::Region *region, db::PolygonToEdgeProcessor::EdgeMode mode)
|
||||
{
|
||||
db::PolygonToEdgeProcessor proc (mode);
|
||||
return region->edges (proc);
|
||||
}
|
||||
|
||||
static db::Point default_origin;
|
||||
|
||||
// provided by gsiDeclDbPolygon.cc:
|
||||
|
|
@ -2237,15 +2244,20 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"If the region is not merged, this method may return false even\n"
|
||||
"if the merged region would be a box.\n"
|
||||
) +
|
||||
method ("edges", (db::Edges (db::Region::*) () const) &db::Region::edges,
|
||||
method_ext ("edges", &edges, gsi::arg ("mode", db::PolygonToEdgeProcessor::All, "All"),
|
||||
"@brief Returns an edge collection representing all edges of the polygons in this region\n"
|
||||
"This method will decompose the polygons into the individual edges. Edges making up the hulls "
|
||||
"of the polygons are oriented clockwise while edges making up the holes are oriented counterclockwise.\n"
|
||||
"\n"
|
||||
"The 'mode' parameter allows selecting specific edges, such as convex or concave ones. By default, "
|
||||
"all edges are selected.\n"
|
||||
"\n"
|
||||
"The edge collection returned can be manipulated in various ways. See \\Edges for a description of the "
|
||||
"possibilities of the edge collection.\n"
|
||||
"features of the edge collection.\n"
|
||||
"\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
"\n"
|
||||
"The mode argument has been added in version 0.29."
|
||||
) +
|
||||
factory_ext ("decompose_convex", &decompose_convex<db::Shapes>, gsi::arg ("preferred_orientation", po_any (), "\\Polygon#PO_any"),
|
||||
"@brief Decomposes the region into convex pieces.\n"
|
||||
|
|
@ -3239,6 +3251,33 @@ gsi::Enum<db::metrics_type> decl_Metrics ("db", "Metrics",
|
|||
gsi::ClassExt<db::Region> inject_Metrics_in_Region (decl_Metrics.defs ());
|
||||
gsi::ClassExt<db::Edges> inject_Metrics_in_Edges (decl_Metrics.defs ());
|
||||
|
||||
gsi::Enum<db::PolygonToEdgeProcessor::EdgeMode> decl_EdgeMode ("db", "EdgeMode",
|
||||
gsi::enum_const ("All", db::PolygonToEdgeProcessor::All,
|
||||
"@brief Selects all edges\n"
|
||||
) +
|
||||
gsi::enum_const ("Concave", db::PolygonToEdgeProcessor::Concave,
|
||||
"@brief Selects only concave edges\n"
|
||||
) +
|
||||
gsi::enum_const ("Convex", db::PolygonToEdgeProcessor::Convex,
|
||||
"@brief Selects only convex edges\n"
|
||||
) +
|
||||
gsi::enum_const ("Step", db::PolygonToEdgeProcessor::Step,
|
||||
"@brief Selects only step edges leading inside or outside\n"
|
||||
) +
|
||||
gsi::enum_const ("StepIn", db::PolygonToEdgeProcessor::StepIn,
|
||||
"@brief Selects only step edges leading inside\n"
|
||||
) +
|
||||
gsi::enum_const ("StepOut", db::PolygonToEdgeProcessor::StepOut,
|
||||
"@brief Selects only step edges leading outside\n"
|
||||
),
|
||||
"@brief This class represents the edge mode type for \\Region#edges.\n"
|
||||
"\n"
|
||||
"This enum has been introduced in version 0.29."
|
||||
);
|
||||
|
||||
// Inject the Region::EdgeMode declarations into Region:
|
||||
gsi::ClassExt<db::Region> inject_EdgeMode_in_Region (decl_EdgeMode.defs ());
|
||||
|
||||
gsi::Enum<db::PropertyConstraint> decl_PropertyConstraint ("db", "PropertyConstraint",
|
||||
gsi::enum_const ("IgnoreProperties", db::IgnoreProperties,
|
||||
"@brief Specifies to ignore properties\n"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,80 @@
|
|||
|
||||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2024 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 "tlUnitTest.h"
|
||||
#include "tlString.h"
|
||||
|
||||
#include "dbRegionProcessors.h"
|
||||
|
||||
|
||||
TEST(1_RegionToEdgesProcessor)
|
||||
{
|
||||
db::Point hull[] = {
|
||||
db::Point (0, 0),
|
||||
db::Point (0, 1000),
|
||||
db::Point (1000, 1000),
|
||||
db::Point (1000, 2000),
|
||||
db::Point (2000, 2000),
|
||||
db::Point (2000, 1000),
|
||||
db::Point (3000, 1000),
|
||||
db::Point (3000, 0)
|
||||
};
|
||||
|
||||
db::Point hole[] = {
|
||||
db::Point (100, 100),
|
||||
db::Point (2900, 100),
|
||||
db::Point (2900, 900),
|
||||
db::Point (100, 900)
|
||||
};
|
||||
|
||||
db::Polygon poly;
|
||||
poly.assign_hull (hull + 0, hull + sizeof (hull) / sizeof (hull[0]));
|
||||
poly.insert_hole (hole + 0, hole + sizeof (hole) / sizeof (hole[0]));
|
||||
|
||||
std::vector<db::Edge> result;
|
||||
|
||||
result.clear ();
|
||||
db::PolygonToEdgeProcessor ().process (poly, result);
|
||||
EXPECT_EQ (tl::join (result.begin (), result.end (), ";"), "(0,0;0,1000);(0,1000;1000,1000);(1000,1000;1000,2000);(1000,2000;2000,2000);(2000,2000;2000,1000);(2000,1000;3000,1000);(3000,1000;3000,0);(3000,0;0,0);(100,100;2900,100);(2900,100;2900,900);(2900,900;100,900);(100,900;100,100)");
|
||||
|
||||
result.clear ();
|
||||
db::PolygonToEdgeProcessor (db::PolygonToEdgeProcessor::Concave).process (poly, result);
|
||||
EXPECT_EQ (tl::join (result.begin (), result.end (), ";"), "(2900,100;2900,900);(2900,900;100,900);(100,900;100,100);(100,100;2900,100)");
|
||||
|
||||
result.clear ();
|
||||
db::PolygonToEdgeProcessor (db::PolygonToEdgeProcessor::Convex).process (poly, result);
|
||||
EXPECT_EQ (tl::join (result.begin (), result.end (), ";"), "(1000,2000;2000,2000);(3000,1000;3000,0);(3000,0;0,0);(0,0;0,1000)");
|
||||
|
||||
result.clear ();
|
||||
db::PolygonToEdgeProcessor (db::PolygonToEdgeProcessor::Step).process (poly, result);
|
||||
EXPECT_EQ (tl::join (result.begin (), result.end (), ";"), "(0,1000;1000,1000);(1000,1000;1000,2000);(2000,2000;2000,1000);(2000,1000;3000,1000)");
|
||||
|
||||
result.clear ();
|
||||
db::PolygonToEdgeProcessor (db::PolygonToEdgeProcessor::StepOut).process (poly, result);
|
||||
EXPECT_EQ (tl::join (result.begin (), result.end (), ";"), "(1000,1000;1000,2000);(2000,1000;3000,1000)");
|
||||
|
||||
result.clear ();
|
||||
db::PolygonToEdgeProcessor (db::PolygonToEdgeProcessor::StepIn).process (poly, result);
|
||||
EXPECT_EQ (tl::join (result.begin (), result.end (), ";"), "(0,1000;1000,1000);(2000,2000;2000,1000)");
|
||||
}
|
||||
|
|
@ -87,6 +87,7 @@ SOURCES = \
|
|||
dbDeepTextsTests.cc \
|
||||
dbNetShapeTests.cc \
|
||||
dbHierNetsProcessorTests.cc \
|
||||
dbRegionProcessorTests.cc \
|
||||
dbAsIfFlatRegionTests.cc
|
||||
|
||||
INCLUDEPATH += $$TL_INC $$DB_INC $$GSI_INC
|
||||
|
|
|
|||
|
|
@ -989,6 +989,7 @@ CODE
|
|||
# @name edges
|
||||
# @brief Converts the input shapes into edges
|
||||
# @synopsis expression.edges
|
||||
# @synopsis expression.edges(mode)
|
||||
#
|
||||
# Polygons will be separated into edges forming their contours. Edge pairs will be
|
||||
# decomposed into individual edges.
|
||||
|
|
@ -1001,9 +1002,31 @@ CODE
|
|||
# @code
|
||||
# out = in.drc(primary.edges)
|
||||
# @/code
|
||||
#
|
||||
# The "mode" argument allows selecting specific edges from polygons.
|
||||
# Allows values are: "convex", "concave", "step", "step_in" and "step_out".
|
||||
# "step" generates edges only that provide a step between two other
|
||||
# edges. "step_in" creates edges that make a step towards the inside of
|
||||
# the polygon and "step_out" creates edges that make a step towards the
|
||||
# outside (hull contours in clockwise orientation, holes counterclockwise):
|
||||
#
|
||||
# @code
|
||||
# out = in.drc(primary.edges(convex))
|
||||
# @/code
|
||||
#
|
||||
# The mode argument is ignored when translating other objects than
|
||||
# polygons.
|
||||
|
||||
def edges
|
||||
return DRCOpNodeFilter::new(@engine, self, :new_edges, "edges")
|
||||
def edges(mode = nil)
|
||||
if mode
|
||||
if ! mode.is_a?(DRC::DRCEdgeMode)
|
||||
raise "The mode argument needs to be a mode type (convex, concave, step, step_in or step_out)"
|
||||
end
|
||||
mode = mode.value
|
||||
else
|
||||
mode = RBA::EdgeMode::All
|
||||
end
|
||||
return DRCOpNodeFilter::new(@engine, self, :new_edges, "edges", mode)
|
||||
end
|
||||
|
||||
# %DRC%
|
||||
|
|
|
|||
|
|
@ -255,6 +255,26 @@ module DRC
|
|||
DRCJoinFlag::new(true)
|
||||
end
|
||||
|
||||
def convex
|
||||
DRCEdgeMode::new(RBA::EdgeMode::Convex)
|
||||
end
|
||||
|
||||
def concave
|
||||
DRCEdgeMode::new(RBA::EdgeMode::Concave)
|
||||
end
|
||||
|
||||
def step_in
|
||||
DRCEdgeMode::new(RBA::EdgeMode::StepIn)
|
||||
end
|
||||
|
||||
def step_out
|
||||
DRCEdgeMode::new(RBA::EdgeMode::StepOut)
|
||||
end
|
||||
|
||||
def step
|
||||
DRCEdgeMode::new(RBA::EdgeMode::Step)
|
||||
end
|
||||
|
||||
def padding_zero
|
||||
DRCDensityPadding::new(:zero)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -3387,6 +3387,8 @@ CODE
|
|||
# %DRC%
|
||||
# @name edges
|
||||
# @brief Decomposes the layer into single edges
|
||||
# @synopsis layer.edges
|
||||
# @synopsis layer.edges(mode)
|
||||
#
|
||||
# Edge pair collections are decomposed into the individual edges that make up
|
||||
# the edge pairs. Polygon layers are decomposed into the edges making up the
|
||||
|
|
@ -3395,13 +3397,37 @@ CODE
|
|||
#
|
||||
# Merged semantics applies, i.e. the result reflects merged polygons rather than
|
||||
# individual ones unless raw mode is chosen.
|
||||
#
|
||||
# The "mode" argument allows selecting specific edges from polygons.
|
||||
# Allows values are: "convex", "concave", "step", "step_in" and "step_out".
|
||||
# "step" generates edges only that provide a step between two other
|
||||
# edges. "step_in" creates edges that make a step towards the inside of
|
||||
# the polygon and "step_out" creates edges that make a step towards the
|
||||
# outside (hull contours in clockwise orientation, holes counterclockwise):
|
||||
#
|
||||
# @code
|
||||
# out = in.edges(convex)
|
||||
# @/code
|
||||
#
|
||||
# This feature is only available for polygon layers.
|
||||
|
||||
%w(edges).each do |f|
|
||||
eval <<"CODE"
|
||||
def #{f}
|
||||
def #{f}(mode = nil)
|
||||
if mode
|
||||
if ! mode.is_a?(DRC::DRCEdgeMode)
|
||||
raise "The mode argument needs to be a mode type (convex, concave, step, step_in or step_out)"
|
||||
end
|
||||
if ! self.data.is_a?(RBA::Region)
|
||||
raise "The mode argument is only available for polygon layers"
|
||||
end
|
||||
mode = mode.value
|
||||
else
|
||||
mode = RBA::EdgeMode::All
|
||||
end
|
||||
@engine._context("#{f}") do
|
||||
if self.data.is_a?(RBA::Region)
|
||||
DRCLayer::new(@engine, @engine._tcmd(self.data, 0, RBA::Edges, :#{f}))
|
||||
DRCLayer::new(@engine, @engine._tcmd(self.data, 0, RBA::Edges, :#{f}, mode))
|
||||
elsif self.data.is_a?(RBA::EdgePairs)
|
||||
DRCLayer::new(@engine, @engine._cmd(self.data, :#{f}))
|
||||
else
|
||||
|
|
|
|||
|
|
@ -57,6 +57,14 @@ module DRC
|
|||
end
|
||||
end
|
||||
|
||||
# A wrapper for the edge mode value for Region#edges
|
||||
class DRCEdgeMode
|
||||
attr_accessor :value
|
||||
def initialize(v)
|
||||
self.value = v
|
||||
end
|
||||
end
|
||||
|
||||
# A wrapper for the join flag for extended
|
||||
class DRCJoinFlag
|
||||
attr_accessor :value
|
||||
|
|
|
|||
|
|
@ -1636,3 +1636,13 @@ TEST(91d_edge_booleans_with_dots)
|
|||
{
|
||||
run_test (_this, "91", true);
|
||||
}
|
||||
|
||||
TEST(92_edge_modes)
|
||||
{
|
||||
run_test (_this, "92", false);
|
||||
}
|
||||
|
||||
TEST(92d_edge_modes)
|
||||
{
|
||||
run_test (_this, "92", true);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,29 @@
|
|||
|
||||
source $drc_test_source
|
||||
target $drc_test_target
|
||||
|
||||
if $drc_test_deep
|
||||
deep
|
||||
end
|
||||
|
||||
l1 = input(1, 0)
|
||||
l2 = input(2, 0)
|
||||
|
||||
l1.output(1, 0)
|
||||
l2.output(2, 0)
|
||||
|
||||
l2.edges.output(100, 0)
|
||||
l2.edges(convex).output(101, 0)
|
||||
l2.edges(concave).output(102, 0)
|
||||
l2.edges(step).output(103, 0)
|
||||
l2.edges(step_in).output(104, 0)
|
||||
l2.edges(step_out).output(105, 0)
|
||||
|
||||
l2.drc(primary.edges).output(200, 0)
|
||||
l2.drc(primary.edges(convex)).output(201, 0)
|
||||
l2.drc(primary.edges(concave)).output(202, 0)
|
||||
l2.drc(primary.edges(step)).output(203, 0)
|
||||
l2.drc(primary.edges(step_in)).output(204, 0)
|
||||
l2.drc(primary.edges(step_out)).output(205, 0)
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue