Introducing edge modes for DRC 'edges' function - allows easy extraction of convex edges only

This commit is contained in:
Matthias Koefferlein 2024-03-07 21:51:52 +01:00
parent 156f0f4477
commit 853de5b0ae
23 changed files with 405 additions and 34 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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);
}
/**

View File

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

View File

@ -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);
}
}
}

View File

@ -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;
};
/**

View File

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

View File

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

View File

@ -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)");
}

View File

@ -87,6 +87,7 @@ SOURCES = \
dbDeepTextsTests.cc \
dbNetShapeTests.cc \
dbHierNetsProcessorTests.cc \
dbRegionProcessorTests.cc \
dbAsIfFlatRegionTests.cc
INCLUDEPATH += $$TL_INC $$DB_INC $$GSI_INC

View File

@ -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%

View File

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

View File

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

View File

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

View File

@ -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);
}

29
testdata/drc/drcSimpleTests_92.drc vendored Normal file
View File

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

BIN
testdata/drc/drcSimpleTests_92.gds vendored Normal file

Binary file not shown.

BIN
testdata/drc/drcSimpleTests_au92.gds vendored Normal file

Binary file not shown.

BIN
testdata/drc/drcSimpleTests_au92d.gds vendored Normal file

Binary file not shown.