mirror of https://github.com/KLayout/klayout.git
Corner detection feature: tests, bug fixes, enhancements (inclusive/exclusive angle constraints)
This commit is contained in:
parent
bc63f98622
commit
ddf36290fa
|
|
@ -30,11 +30,14 @@ namespace db
|
|||
// -----------------------------------------------------------------------------------
|
||||
// CornerDetectorCore implementation
|
||||
|
||||
CornerDetectorCore::CornerDetectorCore (double angle_start, double angle_end)
|
||||
CornerDetectorCore::CornerDetectorCore (double angle_start, bool include_angle_start, double angle_end, bool include_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_include_start = include_angle_start;
|
||||
m_include_end = include_angle_end;
|
||||
|
||||
m_big_angle = (angle_end - angle_start + db::epsilon) > 180.0;
|
||||
m_all = (angle_end - angle_start - db::epsilon) > 360.0;
|
||||
}
|
||||
|
|
@ -64,15 +67,18 @@ void CornerDetectorCore::detect_corners (const db::Polygon &poly, const CornerPo
|
|||
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;
|
||||
int vps1 = db::vprod_sign (v1, vout);
|
||||
int vps2 = db::vprod_sign (v2, vout);
|
||||
bool opp1 = vps1 == 0 && (db::sprod_sign (v1, vout) < 0);
|
||||
bool opp2 = vps2 == 0 && (db::sprod_sign (v2, vout) < 0);
|
||||
|
||||
bool vp1 = !opp1 && (m_include_start ? (db::vprod_sign (v1, vout) >= 0) : (db::vprod_sign (v1, vout) > 0));
|
||||
bool vp2 = !opp2 && (m_include_end ? (db::vprod_sign (v2, vout) <= 0) : (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);
|
||||
}
|
||||
delivery.make_point (pt);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -91,13 +91,14 @@ private:
|
|||
class DB_PUBLIC CornerDetectorCore
|
||||
{
|
||||
public:
|
||||
CornerDetectorCore (double angle_start, double angle_end);
|
||||
CornerDetectorCore (double angle_start, bool include_angle_start, double angle_end, bool include_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_include_start, m_include_end;
|
||||
bool m_big_angle, m_all;
|
||||
};
|
||||
|
||||
|
|
@ -108,8 +109,8 @@ 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)
|
||||
CornersAsRectangles (double angle_start, bool include_angle_start, double angle_end, bool include_angle_end, db::Coord dim = 1)
|
||||
: CornerDetectorCore (angle_start, include_angle_start, angle_end, include_angle_end), m_dim (dim)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
|
@ -137,8 +138,8 @@ class DB_PUBLIC CornersAsDots
|
|||
: public db::PolygonToEdgeProcessorBase, private CornerDetectorCore
|
||||
{
|
||||
public:
|
||||
CornersAsDots (double angle_start, double angle_end)
|
||||
: CornerDetectorCore (angle_start, angle_end)
|
||||
CornersAsDots (double angle_start, bool include_angle_start, double angle_end, bool include_angle_end)
|
||||
: CornerDetectorCore (angle_start, include_angle_start, angle_end, include_angle_end)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
|
|
|||
|
|
@ -214,16 +214,16 @@ static db::CompoundRegionOperationNode *new_count_filter (db::CompoundRegionOper
|
|||
return new db::CompoundRegionCountFilterNode (input, invert, min_count, max_count);
|
||||
}
|
||||
|
||||
static db::CompoundRegionOperationNode *new_corners_as_rectangles (db::CompoundRegionOperationNode *input, double angle_start, double angle_end, db::Coord dim = 1)
|
||||
static db::CompoundRegionOperationNode *new_corners_as_rectangles (db::CompoundRegionOperationNode *input, double angle_start, bool include_angle_start, double angle_end, bool include_angle_end, db::Coord dim = 1)
|
||||
{
|
||||
check_non_null (input, "input");
|
||||
return new db::CompoundRegionProcessingOperationNode (new db::CornersAsRectangles (angle_start, angle_end, dim), input, true /*processor is owned*/, dim /*dist adder*/);
|
||||
return new db::CompoundRegionProcessingOperationNode (new db::CornersAsRectangles (angle_start, include_angle_start, angle_end, include_angle_end, dim), input, true /*processor is owned*/, dim /*dist adder*/);
|
||||
}
|
||||
|
||||
static db::CompoundRegionOperationNode *new_corners_as_dots (db::CompoundRegionOperationNode *input, double angle_start, double angle_end)
|
||||
static db::CompoundRegionOperationNode *new_corners_as_dots (db::CompoundRegionOperationNode *input, double angle_start, bool include_angle_start, double angle_end, bool include_angle_end)
|
||||
{
|
||||
check_non_null (input, "input");
|
||||
return new db::CompoundRegionToEdgeProcessingOperationNode (new db::CornersAsDots (angle_start, angle_end), input, true /*processor is owned*/);
|
||||
return new db::CompoundRegionToEdgeProcessingOperationNode (new db::CornersAsDots (angle_start, include_angle_start, angle_end, include_angle_end), input, true /*processor is owned*/);
|
||||
}
|
||||
|
||||
static db::CompoundRegionOperationNode *new_extents (db::CompoundRegionOperationNode *input, db::Coord e)
|
||||
|
|
@ -584,10 +584,10 @@ Class<db::CompoundRegionOperationNode> decl_CompoundRegionOperationNode ("db", "
|
|||
gsi::constructor ("new_count_filter", &new_count_filter, gsi::arg ("inputs"), gsi::arg ("invert", false), gsi::arg ("min_count", size_t (0)), gsi::arg ("max_count", std::numeric_limits<size_t>::max ()),
|
||||
"@brief Creates a node selecting results but their shape count.\n"
|
||||
) +
|
||||
gsi::constructor ("new_corners_as_rectangles", &new_corners_as_rectangles, gsi::arg ("input"), gsi::arg ("angle_start"), gsi::arg ("angle_end"), gsi::arg ("dim"),
|
||||
gsi::constructor ("new_corners_as_rectangles", &new_corners_as_rectangles, gsi::arg ("input"), gsi::arg ("angle_min"), gsi::arg ("include_angle_min"), gsi::arg ("angle_max"), gsi::arg ("include_angle_max"), gsi::arg ("dim"),
|
||||
"@brief Creates a node turning corners into rectangles.\n"
|
||||
) +
|
||||
gsi::constructor ("new_corners_as_dots", &new_corners_as_dots, gsi::arg ("input"), gsi::arg ("angle_start"), gsi::arg ("angle_end"),
|
||||
gsi::constructor ("new_corners_as_dots", &new_corners_as_dots, gsi::arg ("input"), gsi::arg ("angle_min"), gsi::arg ("include_angle_min"), gsi::arg ("angle_max"), gsi::arg ("include_angle_max"),
|
||||
"@brief Creates a node turning corners into dots (single-point edges).\n"
|
||||
) +
|
||||
gsi::constructor ("new_extents", &new_extents, gsi::arg ("input"), gsi::arg ("e", 0),
|
||||
|
|
|
|||
|
|
@ -112,14 +112,14 @@ static db::Region *texts_as_boxes2 (const db::Region *r, db::DeepShapeStore &dss
|
|||
return new db::Region (r->texts_as_boxes (pat, pattern, enl, dss));
|
||||
}
|
||||
|
||||
static db::Edges corners_to_dots (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, bool include_angle_start, bool include_angle_end)
|
||||
{
|
||||
return r->processed (db::CornersAsDots (angle_start, angle_end));
|
||||
return r->processed (db::CornersAsDots (angle_start, include_angle_start, angle_end, include_angle_end));
|
||||
}
|
||||
|
||||
static db::Region corners_to_boxes (const db::Region *r, double angle_start, double angle_end, db::Coord dim)
|
||||
static db::Region corners_to_boxes (const db::Region *r, double angle_start, double angle_end, db::Coord dim, bool include_angle_start, bool include_angle_end)
|
||||
{
|
||||
return r->processed (db::CornersAsRectangles (angle_start, angle_end, dim));
|
||||
return r->processed (db::CornersAsRectangles (angle_start, include_angle_start, angle_end, include_angle_end, dim));
|
||||
}
|
||||
|
||||
static db::Region *new_si (const db::RecursiveShapeIterator &si)
|
||||
|
|
@ -1121,11 +1121,14 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"@hide\n"
|
||||
"This method is provided for DRC implementation.\n"
|
||||
) +
|
||||
method_ext ("corners", &corners_to_boxes, gsi::arg ("angle_start", -180.0), gsi::arg ("angle_end", 180.0), gsi::arg ("dim", 1),
|
||||
method_ext ("corners", &corners_to_boxes, gsi::arg ("angle_min", -180.0), gsi::arg ("angle_max", 180.0), gsi::arg ("dim", 1), gsi::arg ("include_min_angle", true), gsi::arg ("include_max_angle", true),
|
||||
"@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 boxes with 2*dim x 2*dim dimension. The default dimension is 2x2 DBU.\n"
|
||||
"between angle_min and angle_max will be reported boxes with 2*dim x 2*dim dimension. The default dimension is 2x2 DBU.\n"
|
||||
"\n"
|
||||
"If 'include_angle_min' is true, the angle condition is >= min. angle, otherwise it is > min. angle. "
|
||||
"Same for 'include_angle_,ax' and the max. angle.\n"
|
||||
"\n"
|
||||
"The angle is measured "
|
||||
"between the incoming and the outcoming edge in mathematical sense: a positive value is a turn left "
|
||||
|
|
@ -1134,14 +1137,14 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"\n"
|
||||
"A similar function that reports corners as point-like edges is \\corners_dots.\n"
|
||||
"\n"
|
||||
"This function has been introduced in version 0.25.\n"
|
||||
"This function has been introduced in version 0.25. 'include_min_angle' and 'include_max_angle' have been added in version 0.27.\n"
|
||||
) +
|
||||
method_ext ("corners_dots", &corners_to_dots, 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), gsi::arg ("include_min_angle", true), gsi::arg ("include_max_angle", true),
|
||||
"@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"
|
||||
"\n"
|
||||
"This function has been introduced in version 0.25.\n"
|
||||
"This function has been introduced in version 0.25. 'include_min_angle' and 'include_max_angle' have been added in version 0.27.\n"
|
||||
) +
|
||||
method ("merge", (db::Region &(db::Region::*) ()) &db::Region::merge,
|
||||
"@brief Merge the region\n"
|
||||
|
|
|
|||
|
|
@ -835,10 +835,10 @@ void run_test15 (tl::TestBase *_this, bool deep)
|
|||
|
||||
db::CompoundRegionOperationPrimaryNode *primary = new db::CompoundRegionOperationPrimaryNode ();
|
||||
|
||||
db::CompoundRegionProcessingOperationNode *corners1 = new db::CompoundRegionProcessingOperationNode (new db::CornersAsRectangles (-180.0, 180.0, 1), primary, true /*processor is owned*/);
|
||||
db::CompoundRegionProcessingOperationNode *corners1 = new db::CompoundRegionProcessingOperationNode (new db::CornersAsRectangles (-180.0, true, 180.0, true, 1), primary, true /*processor is owned*/);
|
||||
db::CompoundRegionCountFilterNode count1 (corners1, false, 5, 10000);
|
||||
|
||||
db::CompoundRegionToEdgeProcessingOperationNode *corners2 = new db::CompoundRegionToEdgeProcessingOperationNode (new db::CornersAsDots (-180.0, 180.0), primary, true /*processor is owned*/);
|
||||
db::CompoundRegionToEdgeProcessingOperationNode *corners2 = new db::CompoundRegionToEdgeProcessingOperationNode (new db::CornersAsDots (-180.0, true, 180.0, true), primary, true /*processor is owned*/);
|
||||
db::CompoundRegionCountFilterNode count2 (corners2, true, 5, 10000);
|
||||
|
||||
EXPECT_EQ (count1.result_type () == db::CompoundRegionJoinOperationNode::Region, true);
|
||||
|
|
|
|||
|
|
@ -1220,13 +1220,13 @@ TEST(21_Processors)
|
|||
|
||||
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)));
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (10, 0)), r1.processed (db::CornersAsDots (-180.0, true, 180.0, true)));
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (11, 0)), r1.processed (db::CornersAsDots (0.0, true, 180.0, true)));
|
||||
db::Region ext;
|
||||
r1.processed (db::CornersAsDots (0.0, 180.0)).extended (ext, 1000, 1000, 2000, 2000);
|
||||
r1.processed (db::CornersAsDots (0.0, true, 180.0, true)).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 (13, 0)), r1.processed (db::CornersAsRectangles (-180.0, true, 180.0, true, 2000)));
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (14, 0)), r1.processed (db::CornersAsRectangles (0.0, true, 180.0, true, 2000)));
|
||||
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (20, 0)), r1.processed (db::extents_processor<db::Polygon> (0, 0)));
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (21, 0)), r1.processed (db::extents_processor<db::Polygon> (1000, 2000)));
|
||||
|
|
|
|||
|
|
@ -1979,13 +1979,17 @@ TEST(100_Processors)
|
|||
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)");
|
||||
EXPECT_EQ (r.processed (db::CornersAsDots (-180.0, true, 180.0, true)).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, true, 180.0, true)).to_string (), "(100,400;100,400)");
|
||||
EXPECT_EQ (r.processed (db::CornersAsDots (-90.0, true, 90.0, true)).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 (-90.0, false, 90.0, true)).to_string (), "(100,400;100,400)");
|
||||
EXPECT_EQ (r.processed (db::CornersAsDots (-90.0, true, 90.0, false)).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,500;100,500);(200,500;200,500)");
|
||||
EXPECT_EQ (r.processed (db::CornersAsDots (-90.0, false, 90.0, false)).to_string (), "");
|
||||
db::Region ext;
|
||||
r.processed (db::CornersAsDots (0.0, 180.0)).extended (ext, 10, 10, 20, 20);
|
||||
r.processed (db::CornersAsDots (0.0, true, 180.0, true)).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::CornersAsRectangles (-180.0, true, 180.0, true, 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, true, 180.0, true, 2)).to_string (), "(98,398;98,402;102,402;102,398)");
|
||||
|
||||
EXPECT_EQ (r.processed (db::extents_processor<db::Polygon> (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_processor<db::Polygon> (10, 20)).to_string (), "(-10,-20;-10,220;110,220;110,-20);(-10,280;-10,520;210,520;210,280)");
|
||||
|
|
|
|||
|
|
@ -455,7 +455,7 @@ CODE
|
|||
else
|
||||
raise("Invalid argument (#{as_dots.inspect}) for 'corners' method")
|
||||
end
|
||||
DRCOpNodeCornersFilter::new(@engine, self, as_dots)
|
||||
DRCOpNodeCornersFilter::new(@engine, as_dots, self)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -536,12 +536,12 @@ CODE
|
|||
end
|
||||
|
||||
if as_edges
|
||||
return DRCOpNodeRelativeExtents::new(self, true, *f)
|
||||
return DRCOpNodeRelativeExtents::new(@engine, true, self, *f)
|
||||
else
|
||||
# add oversize for point- and edge-like regions
|
||||
zero_area = (f[0] - f[2]).abs < 1e-7 || (f[1] - f[3]).abs < 1e-7
|
||||
f += [ zero_area ? 1 : 0 ] * 2
|
||||
return DRCOpNodeRelativeExtents::new(self, false, *f)
|
||||
return DRCOpNodeRelativeExtents::new(@engine, false, self, *f)
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -1207,7 +1207,7 @@ class DRCOpNodeCountFilter < DRCOpNodeWithCompare
|
|||
args = [ self.input.create_node(cache), self.inverse ]
|
||||
args << (self.gt ? @engine._make_numeric_value(self.gt) + 1 : (self.ge ? @engine._make_numeric_value(self.ge) : 0))
|
||||
if self.lt || self.le
|
||||
args << (self.lt ? @engine._make_numeric_value(self.lt) : @engine._make_numeric_value(self.le) - 1)
|
||||
args << (self.lt ? @engine._make_numeric_value(self.lt) : @engine._make_numeric_value(self.le) + 1)
|
||||
end
|
||||
RBA::CompoundRegionOperationNode::new_count_filter(*args)
|
||||
end
|
||||
|
|
@ -1240,7 +1240,7 @@ class DRCOpNodeAreaFilter < DRCOpNodeWithCompare
|
|||
args = [ self.input.create_node(cache), self.inverse ]
|
||||
args << (self.gt ? @engine._make_area_value(self.gt) + 1 : (self.ge ? @engine._make_area_value(self.ge) : 0))
|
||||
if self.lt || self.le
|
||||
args << (self.lt ? @engine._make_area_value(self.lt) : @engine._make_area_value(self.le) - 1)
|
||||
args << (self.lt ? @engine._make_area_value(self.lt) : @engine._make_area_value(self.le) + 1)
|
||||
end
|
||||
RBA::CompoundRegionOperationNode::new_area_filter(*args)
|
||||
end
|
||||
|
|
@ -1281,7 +1281,7 @@ class DRCOpNodeEdgeLengthFilter < DRCOpNodeWithCompare
|
|||
args = [ n, self.inverse ]
|
||||
args << (self.gt ? @engine._make_value(self.gt) + 1 : (self.ge ? @engine._make_value(self.ge) : 0))
|
||||
if self.lt || self.le
|
||||
args << (self.lt ? @engine._make_value(self.lt) : @engine._make_value(self.le) - 1)
|
||||
args << (self.lt ? @engine._make_value(self.lt) : @engine._make_value(self.le) + 1)
|
||||
end
|
||||
|
||||
RBA::CompoundRegionOperationNode::new_edge_length_filter(*args)
|
||||
|
|
@ -1324,7 +1324,7 @@ class DRCOpNodeEdgeOrientationFilter < DRCOpNodeWithCompare
|
|||
args = [ n, self.inverse ]
|
||||
angle_delta = 1e-6
|
||||
args << (self.gt ? self.gt + angle_delta : (self.ge ? self.ge : -180.0))
|
||||
args << (self.lt ? self.lt : (self.le ? self.le - angle_delta : 180.0))
|
||||
args << (self.lt ? self.lt : (self.le ? self.le + angle_delta : 180.0))
|
||||
|
||||
RBA::CompoundRegionOperationNode::new_edge_orientation_filter(*args)
|
||||
|
||||
|
|
@ -1358,7 +1358,7 @@ class DRCOpNodePerimeterFilter < DRCOpNodeWithCompare
|
|||
args = [ self.input.create_node(cache), self.inverse ]
|
||||
args << (self.gt ? @engine._make_value(self.gt) + 1 : (self.ge ? @engine._make_value(self.ge) : 0))
|
||||
if self.lt || self.le
|
||||
args << (self.lt ? @engine._make_value(self.lt) : @engine._make_value(self.le) - 1)
|
||||
args << (self.lt ? @engine._make_value(self.lt) : @engine._make_value(self.le) + 1)
|
||||
end
|
||||
RBA::CompoundRegionOperationNode::new_perimeter_filter(*args)
|
||||
end
|
||||
|
|
@ -1390,7 +1390,7 @@ class DRCOpNodeInteractingWithCount < DRCOpNodeWithCompare
|
|||
args = [ self.a.create_node(cache), self.b.create_node(cache), self.inverse ]
|
||||
args << (self.gt ? self.gt + 1 : (self.ge ? self.ge : 0))
|
||||
if self.lt || self.le
|
||||
args << (self.lt ? self.lt : self.le - 1)
|
||||
args << (self.lt ? self.lt : self.le + 1)
|
||||
end
|
||||
factory = { :covering => :new_enclosing,
|
||||
:overlapping => :new_overlapping,
|
||||
|
|
@ -1549,7 +1549,7 @@ class DRCOpNodeBBoxParameterFilter < DRCOpNodeWithCompare
|
|||
args = [ self.input.create_node(cache), self.inverse ]
|
||||
args << (self.gt ? @engine._make_value(self.gt) + 1 : (self.ge ? @engine._make_value(self.ge) : 0))
|
||||
if self.lt || self.le
|
||||
args << (self.lt ? @engine._make_value(self.lt) : @engine._make_value(self.le) - 1)
|
||||
args << (self.lt ? @engine._make_value(self.lt) : @engine._make_value(self.le) + 1)
|
||||
end
|
||||
RBA::CompoundRegionOperationNode::new_perimeter_filter(*args)
|
||||
end
|
||||
|
|
@ -1565,8 +1565,7 @@ end
|
|||
class DRCOpNodeCornersFilter < DRCOpNodeWithCompare
|
||||
|
||||
attr_accessor :input
|
||||
attr_accessor :parameter
|
||||
attr_accessor :inverse
|
||||
attr_accessor :as_dots
|
||||
|
||||
def initialize(engine, as_dots, input)
|
||||
super(engine)
|
||||
|
|
@ -1577,14 +1576,15 @@ class DRCOpNodeCornersFilter < DRCOpNodeWithCompare
|
|||
|
||||
def do_create_node(cache)
|
||||
args = [ self.input.create_node(cache) ]
|
||||
angle_delta = 1e-6
|
||||
args << (self.gt ? self.gt + angle_delta : (self.ge ? self.ge : -180.0))
|
||||
args << (self.lt ? self.lt : (self.le ? self.le - angle_delta : 180.0))
|
||||
args << (self.gt ? self.gt : (self.ge ? self.ge : -180.0))
|
||||
args << (self.gt ? false : true)
|
||||
args << (self.lt ? self.lt : (self.le ? self.le : 180.0))
|
||||
args << (self.lt ? false : true)
|
||||
if self.as_dots
|
||||
RBA::CompoundRegionOperationNode::new_corners_as_dots_node(*args)
|
||||
RBA::CompoundRegionOperationNode::new_corners_as_dots(*args)
|
||||
else
|
||||
args << 2 # dimension is 2x2 DBU
|
||||
RBA::CompoundRegionOperationNode::new_corners_as_rectangles_node(*args)
|
||||
RBA::CompoundRegionOperationNode::new_corners_as_rectangles(*args)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -1595,11 +1595,17 @@ class DRCOpNodeRelativeExtents < DRCOpNode
|
|||
attr_accessor :input
|
||||
attr_accessor :as_edges, :fx1, :fx2, :fy1, :fy2, :dx, :dy
|
||||
|
||||
def initialize(engine, input, as_edges, fx1, fx2, fy1, fy2, dx = 0, dy = 0)
|
||||
def initialize(engine, as_edges, input, fx1, fx2, fy1, fy2, dx = 0, dy = 0)
|
||||
super(engine)
|
||||
self.input = input
|
||||
self.as_edges = as_edges
|
||||
self.description = "extents"
|
||||
self.fx1 = fx1
|
||||
self.fx2 = fx2
|
||||
self.fy1 = fy1
|
||||
self.fy2 = fy2
|
||||
self.dx = dx
|
||||
self.dy = dy
|
||||
end
|
||||
|
||||
def dump(indent)
|
||||
|
|
@ -1611,10 +1617,11 @@ class DRCOpNodeRelativeExtents < DRCOpNode
|
|||
end
|
||||
|
||||
def do_create_node(cache)
|
||||
node = self.input.create_node(cache)
|
||||
if !self.as_edges
|
||||
RBA::CompoundRegionOperationNode::new_relative_extents_as_edges(self.input, self.fx1, self.fx2, self.fy1, self.fy2, self.dx, self.dy)
|
||||
RBA::CompoundRegionOperationNode::new_relative_extents(node, self.fx1, self.fx2, self.fy1, self.fy2, self.dx, self.dy)
|
||||
else
|
||||
RBA::CompoundRegionOperationNode::new_relative_extents_as_edges(self.input, self.fx1, self.fx2, self.fy1, self.fy2)
|
||||
RBA::CompoundRegionOperationNode::new_relative_extents_as_edges(node, self.fx1, self.fx2, self.fy1, self.fy2)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -429,13 +429,20 @@ CODE
|
|||
# %DRC%
|
||||
# @name corners
|
||||
# @brief Selects all polygons which are rectilinear
|
||||
# @synopsis corners (in condition)
|
||||
# @synopsis corners(layer)
|
||||
# @synopsis corners([ options ]) (in condition)
|
||||
# @synopsis corners(layer [, options ])
|
||||
#
|
||||
# This function can be used with a layer argument in which case it
|
||||
# is equivalent to "layer.corners" (see \Layer#corners). Without a layer
|
||||
# argument, "corners" represents the corner generator/filter in primary shapes for
|
||||
# \DRC# expressions (see \Layer#drc and \DRC#corners for more details).
|
||||
#
|
||||
# Like the layer-based version, the "corners" operator accepts the
|
||||
# output type option: "as_dots" for dot-like edges and "as_boxes" for
|
||||
# small (2x2 DBU) box markers.
|
||||
#
|
||||
# The "corners" operator can be put into a condition which means it's
|
||||
# applied to coners meeting a particular angle constraint.
|
||||
|
||||
def _cop_corners(as_dots = DRCAsDots::new(false))
|
||||
# NOTE: this method is a fallback for the respective global ones which route to DRCLayer or here.
|
||||
|
|
|
|||
|
|
@ -118,3 +118,13 @@ TEST(5d)
|
|||
{
|
||||
run_test (_this, "5", true);
|
||||
}
|
||||
|
||||
TEST(6)
|
||||
{
|
||||
run_test (_this, "6", false);
|
||||
}
|
||||
|
||||
TEST(6d)
|
||||
{
|
||||
run_test (_this, "6", true);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -470,13 +470,13 @@ class DBRegion_TestClass < TestBase
|
|||
assert_equal(r3a.separation_check(r1, 15, false, RBA::Region::Projection, nil, 380, 500).to_s, "")
|
||||
assert_equal(r3a.separation_check(r1, 15, false, RBA::Region::Projection, nil, 0, 300).to_s, "(-10,10;-10,0)/(0,0;0,10)")
|
||||
|
||||
assert_equal(r3b.overlap_check(r1, 15).to_s, "(10,10;10,-10)/(0,0;0,21);(-10,10;10,10)/(21,0;0,0)")
|
||||
assert_equal(r3b.overlap_check(r1, 15, false, RBA::Region::Projection, nil, nil, nil).to_s, "(10,10;10,0)/(0,0;0,10);(0,10;10,10)/(10,0;0,0)")
|
||||
assert_equal(r3b.overlap_check(r1, 15, true, RBA::Region::Projection, nil, nil, nil).to_s, "(10,10;10,-10)/(0,0;0,200);(-10,10;10,10)/(100,0;0,0)")
|
||||
assert_equal(r3b.overlap_check(r1, 15).to_s, "(-10,10;10,10)/(21,0;0,0);(10,10;10,-10)/(0,0;0,21)")
|
||||
assert_equal(r3b.overlap_check(r1, 15, false, RBA::Region::Projection, nil, nil, nil).to_s, "(0,10;10,10)/(10,0;0,0);(10,10;10,0)/(0,0;0,10)")
|
||||
assert_equal(r3b.overlap_check(r1, 15, true, RBA::Region::Projection, nil, nil, nil).to_s, "(-10,10;10,10)/(100,0;0,0);(10,10;10,-10)/(0,0;0,200)")
|
||||
assert_equal(r3b.overlap_check(r1, 15, true, RBA::Region::Projection, 0.0, nil, nil).to_s, "")
|
||||
assert_equal(r3b.overlap_check(r1, 15, false, RBA::Region::Projection, nil, 0, 500).to_s, "(10,10;10,0)/(0,0;0,10);(0,10;10,10)/(10,0;0,0)")
|
||||
assert_equal(r3b.overlap_check(r1, 15, false, RBA::Region::Projection, nil, 0, 500).to_s, "(0,10;10,10)/(10,0;0,0);(10,10;10,0)/(0,0;0,10)")
|
||||
assert_equal(r3b.overlap_check(r1, 15, false, RBA::Region::Projection, nil, 380, 500).to_s, "")
|
||||
assert_equal(r3b.overlap_check(r1, 15, false, RBA::Region::Projection, nil, 0, 300).to_s, "(10,10;10,0)/(0,0;0,10);(0,10;10,10)/(10,0;0,0)")
|
||||
assert_equal(r3b.overlap_check(r1, 15, false, RBA::Region::Projection, nil, 0, 300).to_s, "(0,10;10,10)/(10,0;0,0);(10,10;10,0)/(0,0;0,10)")
|
||||
|
||||
assert_equal((r1 | r2).merged.isolated_check(25).to_s, "(120,20;120,380)/(100,395;100,5)")
|
||||
assert_equal((r1 | r2).merged.isolated_check(25, false, RBA::Region::Projection, nil, nil, nil).to_s, "(120,20;120,380)/(100,380;100,20)")
|
||||
|
|
@ -497,9 +497,9 @@ class DBRegion_TestClass < TestBase
|
|||
assert_equal((r1 | r2).merged.notch_check(25, true, RBA::Region::Projection, nil, 40, 50).to_s, "(0,200;50,200)/(50,220;10,220)")
|
||||
assert_equal((r1 | r2).merged.notch_check(25, true, RBA::Region::Projection, nil, nil, 40).to_s, "")
|
||||
|
||||
assert_equal((r1 | r2).merged.space_check(25).to_s, "(0,200;50,200)/(50,220;10,220);(100,395;100,5)/(120,20;120,380)")
|
||||
assert_equal((r1 | r2).merged.space_check(25, false, RBA::Region::Projection, nil, nil, nil).to_s, "(10,200;50,200)/(50,220;10,220);(100,380;100,20)/(120,20;120,380)")
|
||||
assert_equal((r1 | r2).merged.space_check(25, true, RBA::Region::Projection, nil, nil, nil).to_s, "(0,200;50,200)/(50,220;10,220);(100,400;100,0)/(120,20;120,380)")
|
||||
assert_equal((r1 | r2).merged.space_check(25).to_s, "(100,395;100,5)/(120,20;120,380);(0,200;50,200)/(50,220;10,220)")
|
||||
assert_equal((r1 | r2).merged.space_check(25, false, RBA::Region::Projection, nil, nil, nil).to_s, "(100,380;100,20)/(120,20;120,380);(10,200;50,200)/(50,220;10,220)")
|
||||
assert_equal((r1 | r2).merged.space_check(25, true, RBA::Region::Projection, nil, nil, nil).to_s, "(100,400;100,0)/(120,20;120,380);(0,200;50,200)/(50,220;10,220)")
|
||||
assert_equal((r1 | r2).merged.space_check(25, true, RBA::Region::Projection, 0.0, nil, nil).to_s, "")
|
||||
assert_equal((r1 | r2).merged.space_check(25, true, RBA::Region::Projection, nil, 50, nil).to_s, "(100,400;100,0)/(120,20;120,380)")
|
||||
assert_equal((r1 | r2).merged.space_check(25, true, RBA::Region::Projection, nil, nil, 50).to_s, "(0,200;50,200)/(50,220;10,220)")
|
||||
|
|
|
|||
Loading…
Reference in New Issue