DRC integration of new features

This commit is contained in:
Matthias Koefferlein 2024-01-24 18:36:29 +01:00
parent fcdec05863
commit 78c5e229ff
10 changed files with 206 additions and 61 deletions

View File

@ -48,6 +48,37 @@ db::Edge::distance_type edge_projection (const db::Edge &a, const db::Edge &b)
return db::coord_traits<db::Coord>::rounded (a.double_length () * fabs (l2 - l1));
}
/**
* @brief Gets a flag indicating whether zero distance is included in the checks
*/
static bool include_zero_flag (collinear_mode_type coll_mode, const db::Edge &a, const db::Edge &b)
{
if (coll_mode == AlwaysIncludeCollinear) {
return true;
} else if (coll_mode == AlwaysIncludeCollinear) {
return false;
} else {
int s1 = a.side_of (b.p1 ());
int s2 = a.side_of (b.p2 ());
if (s1 == 0 && s2 == 0) {
if (coll_mode == IncludeCollinearWhenTouch) {
return a.intersect (b);
} else if (coll_mode == IncludeCollinearWhenOverlap) {
return a.coincident (b);
}
}
return false;
}
}
/**
* @brief Returns the part of the "other" edge which is on the inside side of e and within distance d
*
@ -67,12 +98,7 @@ bool euclidian_near_part_of_edge (collinear_mode_type coll_mode, db::coord_trait
int s1 = e.side_of (g.p1 ());
int s2 = e.side_of (g.p2 ());
// "kissing corner" issue: force include zero if the edges are collinear and overlap.
bool include_zero = (coll_mode == AlwaysIncludeCollinear);
if (coll_mode == IncludeCollinearWhenTouch && s1 == 0 && s2 == 0 && e.intersect (g)) {
include_zero = true;
}
bool include_zero = include_zero_flag (coll_mode, e, g);
int thr = include_zero ? 0 : -1;
// keep only part of other which is on the "inside" side of e
@ -211,12 +237,7 @@ static bool var_near_part_of_edge (collinear_mode_type coll_mode, db::coord_trai
int s1 = e.side_of (g.p1 ());
int s2 = e.side_of (g.p2 ());
// "kissing corner" issue: force include zero if the edges are collinear and overlap
bool include_zero = (coll_mode == AlwaysIncludeCollinear);
if (coll_mode == IncludeCollinearWhenTouch && s1 == 0 && s2 == 0 && e.intersect (g)) {
include_zero = true;
}
bool include_zero = include_zero_flag (coll_mode, e, g);
int thr = include_zero ? 0 : -1;
// keep only part of other which is on the "inside" side of e

View File

@ -108,14 +108,19 @@ enum collinear_mode_type {
NeverIncludeCollinear = 0,
/**
* @brief include collinear edges when they touch (e.g. kissing corner case)
* @brief include collinear edges when they share at least one common point
*/
IncludeCollinearWhenTouch = 1,
/**
* @brief include collinear edges when they share more than a single common point
*/
IncludeCollinearWhenOverlap = 2,
/**
* @brief always include collinear edges
*/
AlwaysIncludeCollinear = 2
AlwaysIncludeCollinear = 3
};
/**

View File

@ -130,8 +130,8 @@ struct DB_PUBLIC RegionCheckOptions
RectFilter _rect_filter = NoRectFilter,
bool _negative = false,
PropertyConstraint _prop_constraint = IgnoreProperties,
collinear_mode_type _include_zero = IncludeCollinearWhenTouch)
: EdgesCheckOptions (_whole_edges, _metrics, _ignore_angle, _min_projection, _max_projection, _include_zero),
collinear_mode_type _coll_mode = IncludeCollinearWhenTouch)
: EdgesCheckOptions (_whole_edges, _metrics, _ignore_angle, _min_projection, _max_projection, _coll_mode),
shielded (_shielded),
opposite_filter (_opposite_filter),
rect_filter (_rect_filter),

View File

@ -390,23 +390,27 @@ static db::CompoundRegionOperationNode *new_edge_pair_to_second_edges (db::Compo
return new db::CompoundRegionEdgePairToEdgeProcessingOperationNode (new db::EdgePairToSecondEdgesProcessor (), input, true /*processor is owned*/);
}
static db::CompoundRegionOperationNode *new_check_node (db::CompoundRegionOperationNode *other, db::edge_relation_type rel, bool different_polygons, db::Coord d, bool whole_edges, db::metrics_type metrics, const tl::Variant &ignore_angle, const tl::Variant &min_projection, const tl::Variant &max_projection, bool shielded, db::OppositeFilter opposite_filter, db::RectFilter rect_filter, bool negative)
static db::CompoundRegionOperationNode *new_check_node (db::CompoundRegionOperationNode *other, db::edge_relation_type rel, bool different_polygons, db::Coord d, bool whole_edges, db::metrics_type metrics, const tl::Variant &ignore_angle, const tl::Variant &min_projection, const tl::Variant &max_projection, bool shielded, db::OppositeFilter opposite_filter, db::RectFilter rect_filter, db::collinear_mode_type collinear_mode, bool negative)
{
check_non_null (other, "other");
return new db::CompoundRegionCheckOperationNode (0, other, rel, different_polygons, d,
db::RegionCheckOptions (whole_edges,
metrics,
ignore_angle.is_nil () ? 90 : ignore_angle.to_double (),
min_projection.is_nil () ? db::Region::distance_type (0) : min_projection.to<db::Region::distance_type> (),
max_projection.is_nil () ? std::numeric_limits<db::Region::distance_type>::max () : max_projection.to<db::Region::distance_type> (),
shielded,
opposite_filter,
rect_filter,
negative)
);
db::RegionCheckOptions options;
options.whole_edges = whole_edges;
options.metrics = metrics;
options.ignore_angle = ignore_angle.is_nil () ? 90 : ignore_angle.to_double ();
options.min_projection = min_projection.is_nil () ? db::Region::distance_type (0) : min_projection.to<db::Region::distance_type> ();
options.max_projection = max_projection.is_nil () ? std::numeric_limits<db::Region::distance_type>::max () : max_projection.to<db::Region::distance_type> ();
options.shielded = shielded;
options.opposite_filter = opposite_filter;
options.rect_filter = rect_filter;
options.negative = negative;
options.collinear_mode = collinear_mode;
return new db::CompoundRegionCheckOperationNode (0, other, rel, different_polygons, d, options);
}
static db::CompoundRegionOperationNode *new_width_check (db::Coord d, bool whole_edges, db::metrics_type metrics, const tl::Variant &ignore_angle, const tl::Variant &min_projection, const tl::Variant &max_projection, bool shielded, bool negative)
static db::CompoundRegionOperationNode *new_width_check (db::Coord d, bool whole_edges, db::metrics_type metrics, const tl::Variant &ignore_angle, const tl::Variant &min_projection, const tl::Variant &max_projection, bool shielded, db::collinear_mode_type collinear_mode, bool negative)
{
db::RegionCheckOptions options (whole_edges,
metrics,
@ -415,28 +419,29 @@ static db::CompoundRegionOperationNode *new_width_check (db::Coord d, bool whole
max_projection.is_nil () ? std::numeric_limits<db::Region::distance_type>::max () : max_projection.to<db::Region::distance_type> (),
shielded);
options.negative = negative;
options.collinear_mode = collinear_mode;
return new db::CompoundRegionToEdgePairProcessingOperationNode (new db::SinglePolygonCheck (db::WidthRelation, d, options), new_primary (), true /*processor is owned*/);
}
static db::CompoundRegionOperationNode *new_space_or_isolated_check (db::Coord d, bool whole_edges, db::metrics_type metrics, const tl::Variant &ignore_angle, const tl::Variant &min_projection, const tl::Variant &max_projection, bool shielded, db::OppositeFilter opposite_filter, db::RectFilter rect_filter, bool negative, bool isolated)
static db::CompoundRegionOperationNode *new_space_or_isolated_check (db::Coord d, bool whole_edges, db::metrics_type metrics, const tl::Variant &ignore_angle, const tl::Variant &min_projection, const tl::Variant &max_projection, bool shielded, db::OppositeFilter opposite_filter, db::RectFilter rect_filter, db::collinear_mode_type collinear_mode, bool negative, bool isolated)
{
// NOTE: we have to use the "foreign" scheme with a filter because only this scheme
// guarantees that all subject shapes are visited and receive all intruders. Having all intruders is crucial for the
// semantics of the "drc" feature
return new_check_node (new_foreign (), db::SpaceRelation, isolated, d, whole_edges, metrics, ignore_angle, min_projection, max_projection, shielded, opposite_filter, rect_filter, negative);
return new_check_node (new_foreign (), db::SpaceRelation, isolated, d, whole_edges, metrics, ignore_angle, min_projection, max_projection, shielded, opposite_filter, rect_filter, collinear_mode, negative);
}
static db::CompoundRegionOperationNode *new_space_check (db::Coord d, bool whole_edges, db::metrics_type metrics, const tl::Variant &ignore_angle, const tl::Variant &min_projection, const tl::Variant &max_projection, bool shielded, db::OppositeFilter opposite_filter, db::RectFilter rect_filter, bool negative)
static db::CompoundRegionOperationNode *new_space_check (db::Coord d, bool whole_edges, db::metrics_type metrics, const tl::Variant &ignore_angle, const tl::Variant &min_projection, const tl::Variant &max_projection, bool shielded, db::OppositeFilter opposite_filter, db::RectFilter rect_filter, db::collinear_mode_type collinear_mode, bool negative)
{
return new_space_or_isolated_check (d, whole_edges, metrics, ignore_angle, min_projection, max_projection, shielded, opposite_filter, rect_filter, negative, false);
return new_space_or_isolated_check (d, whole_edges, metrics, ignore_angle, min_projection, max_projection, shielded, opposite_filter, rect_filter, collinear_mode, negative, false);
}
static db::CompoundRegionOperationNode *new_isolated_check (db::Coord d, bool whole_edges, db::metrics_type metrics, const tl::Variant &ignore_angle, const tl::Variant &min_projection, const tl::Variant &max_projection, bool shielded, db::OppositeFilter opposite_filter, db::RectFilter rect_filter, bool negative)
static db::CompoundRegionOperationNode *new_isolated_check (db::Coord d, bool whole_edges, db::metrics_type metrics, const tl::Variant &ignore_angle, const tl::Variant &min_projection, const tl::Variant &max_projection, bool shielded, db::OppositeFilter opposite_filter, db::RectFilter rect_filter, db::collinear_mode_type collinear_mode, bool negative)
{
return new_space_or_isolated_check (d, whole_edges, metrics, ignore_angle, min_projection, max_projection, shielded, opposite_filter, rect_filter, negative, true);
return new_space_or_isolated_check (d, whole_edges, metrics, ignore_angle, min_projection, max_projection, shielded, opposite_filter, rect_filter, collinear_mode, negative, true);
}
static db::CompoundRegionOperationNode *new_notch_check (db::Coord d, bool whole_edges, db::metrics_type metrics, const tl::Variant &ignore_angle, const tl::Variant &min_projection, const tl::Variant &max_projection, bool shielded, bool negative)
static db::CompoundRegionOperationNode *new_notch_check (db::Coord d, bool whole_edges, db::metrics_type metrics, const tl::Variant &ignore_angle, const tl::Variant &min_projection, const tl::Variant &max_projection, bool shielded, db::collinear_mode_type collinear_mode, bool negative)
{
db::RegionCheckOptions options (whole_edges,
metrics,
@ -445,27 +450,28 @@ static db::CompoundRegionOperationNode *new_notch_check (db::Coord d, bool whole
max_projection.is_nil () ? std::numeric_limits<db::Region::distance_type>::max () : max_projection.to<db::Region::distance_type> (),
shielded);
options.negative = negative;
options.collinear_mode = collinear_mode;
return new db::CompoundRegionToEdgePairProcessingOperationNode (new db::SinglePolygonCheck (db::SpaceRelation, d, options), new_primary (), true /*processor is owned*/);
}
static db::CompoundRegionOperationNode *new_separation_check (db::CompoundRegionOperationNode *other, db::Coord d, bool whole_edges, db::metrics_type metrics, const tl::Variant &ignore_angle, const tl::Variant &min_projection, const tl::Variant &max_projection, bool shielded, db::OppositeFilter opposite_filter, db::RectFilter rect_filter, bool negative)
static db::CompoundRegionOperationNode *new_separation_check (db::CompoundRegionOperationNode *other, db::Coord d, bool whole_edges, db::metrics_type metrics, const tl::Variant &ignore_angle, const tl::Variant &min_projection, const tl::Variant &max_projection, bool shielded, db::OppositeFilter opposite_filter, db::RectFilter rect_filter, db::collinear_mode_type collinear_mode, bool negative)
{
return new_check_node (other, db::SpaceRelation, true, d, whole_edges, metrics, ignore_angle, min_projection, max_projection, shielded, opposite_filter, rect_filter, negative);
return new_check_node (other, db::SpaceRelation, true, d, whole_edges, metrics, ignore_angle, min_projection, max_projection, shielded, opposite_filter, rect_filter, collinear_mode, negative);
}
static db::CompoundRegionOperationNode *new_overlap_check (db::CompoundRegionOperationNode *other, db::Coord d, bool whole_edges, db::metrics_type metrics, const tl::Variant &ignore_angle, const tl::Variant &min_projection, const tl::Variant &max_projection, bool shielded, db::OppositeFilter opposite_filter, db::RectFilter rect_filter, bool negative)
static db::CompoundRegionOperationNode *new_overlap_check (db::CompoundRegionOperationNode *other, db::Coord d, bool whole_edges, db::metrics_type metrics, const tl::Variant &ignore_angle, const tl::Variant &min_projection, const tl::Variant &max_projection, bool shielded, db::OppositeFilter opposite_filter, db::RectFilter rect_filter, db::collinear_mode_type collinear_mode, bool negative)
{
return new_check_node (other, db::WidthRelation, true, d, whole_edges, metrics, ignore_angle, min_projection, max_projection, shielded, opposite_filter, rect_filter, negative);
return new_check_node (other, db::WidthRelation, true, d, whole_edges, metrics, ignore_angle, min_projection, max_projection, shielded, opposite_filter, rect_filter, collinear_mode, negative);
}
static db::CompoundRegionOperationNode *new_enclosing_check (db::CompoundRegionOperationNode *other, db::Coord d, bool whole_edges, db::metrics_type metrics, const tl::Variant &ignore_angle, const tl::Variant &min_projection, const tl::Variant &max_projection, bool shielded, db::OppositeFilter opposite_filter, db::RectFilter rect_filter, bool negative)
static db::CompoundRegionOperationNode *new_enclosing_check (db::CompoundRegionOperationNode *other, db::Coord d, bool whole_edges, db::metrics_type metrics, const tl::Variant &ignore_angle, const tl::Variant &min_projection, const tl::Variant &max_projection, bool shielded, db::OppositeFilter opposite_filter, db::RectFilter rect_filter, db::collinear_mode_type collinear_mode, bool negative)
{
return new_check_node (other, db::OverlapRelation, true, d, whole_edges, metrics, ignore_angle, min_projection, max_projection, shielded, opposite_filter, rect_filter, negative);
return new_check_node (other, db::OverlapRelation, true, d, whole_edges, metrics, ignore_angle, min_projection, max_projection, shielded, opposite_filter, rect_filter, collinear_mode, negative);
}
static db::CompoundRegionOperationNode *new_enclosed_check (db::CompoundRegionOperationNode *other, db::Coord d, bool whole_edges, db::metrics_type metrics, const tl::Variant &ignore_angle, const tl::Variant &min_projection, const tl::Variant &max_projection, bool shielded, db::OppositeFilter opposite_filter, db::RectFilter rect_filter, bool negative)
static db::CompoundRegionOperationNode *new_enclosed_check (db::CompoundRegionOperationNode *other, db::Coord d, bool whole_edges, db::metrics_type metrics, const tl::Variant &ignore_angle, const tl::Variant &min_projection, const tl::Variant &max_projection, bool shielded, db::OppositeFilter opposite_filter, db::RectFilter rect_filter, db::collinear_mode_type collinear_mode, bool negative)
{
return new_check_node (other, db::InsideRelation, true, d, whole_edges, metrics, ignore_angle, min_projection, max_projection, shielded, opposite_filter, rect_filter, negative);
return new_check_node (other, db::InsideRelation, true, d, whole_edges, metrics, ignore_angle, min_projection, max_projection, shielded, opposite_filter, rect_filter, collinear_mode, negative);
}
static db::CompoundRegionOperationNode *new_perimeter_filter (db::CompoundRegionOperationNode *input, bool inverse, db::coord_traits<db::Coord>::perimeter_type pmin, db::coord_traits<db::Coord>::perimeter_type pmax)
@ -660,31 +666,45 @@ Class<db::CompoundRegionOperationNode> decl_CompoundRegionOperationNode ("db", "
gsi::constructor ("new_minkowski_sum|#new_minkowsky_sum", &new_minkowski_sum_node4, gsi::arg ("input"), gsi::arg ("p"),
"@brief Creates a node providing a Minkowski sum with a point sequence forming a contour.\n"
) +
gsi::constructor ("new_width_check", &new_width_check, gsi::arg ("d"), gsi::arg ("whole_edges", false), gsi::arg ("metrics", db::Euclidian, "Euclidian"), gsi::arg ("ignore_angle", tl::Variant (), "default"), gsi::arg ("min_projection", tl::Variant (), "0"), gsi::arg ("max_projection", tl::Variant (), "max."), gsi::arg ("shielded", true), gsi::arg ("negative", false),
gsi::constructor ("new_width_check", &new_width_check, gsi::arg ("d"), gsi::arg ("whole_edges", false), gsi::arg ("metrics", db::Euclidian, "Euclidian"), gsi::arg ("ignore_angle", tl::Variant (), "default"), gsi::arg ("min_projection", tl::Variant (), "0"), gsi::arg ("max_projection", tl::Variant (), "max."), gsi::arg ("shielded", true), gsi::arg ("collinear_mode", db::IncludeCollinearWhenTouch), gsi::arg ("negative", false),
"@brief Creates a node providing a width check.\n"
"\n"
"The collinear_mode argument has been inserted in version 0.29.\n"
) +
gsi::constructor ("new_space_check", &new_space_check, gsi::arg ("d"), gsi::arg ("whole_edges", false), gsi::arg ("metrics", db::Euclidian, "Euclidian"), gsi::arg ("ignore_angle", tl::Variant (), "default"), gsi::arg ("min_projection", tl::Variant (), "0"), gsi::arg ("max_projection", tl::Variant (), "max."), gsi::arg ("shielded", true), gsi::arg ("opposite_filter", db::NoOppositeFilter, "NoOppositeFilter"), gsi::arg ("rect_filter", db::NoRectFilter, "NoRectFilter"), gsi::arg ("negative", false),
gsi::constructor ("new_space_check", &new_space_check, gsi::arg ("d"), gsi::arg ("whole_edges", false), gsi::arg ("metrics", db::Euclidian, "Euclidian"), gsi::arg ("ignore_angle", tl::Variant (), "default"), gsi::arg ("min_projection", tl::Variant (), "0"), gsi::arg ("max_projection", tl::Variant (), "max."), gsi::arg ("shielded", true), gsi::arg ("opposite_filter", db::NoOppositeFilter, "NoOppositeFilter"), gsi::arg ("rect_filter", db::NoRectFilter, "NoRectFilter"), gsi::arg ("collinear_mode", db::IncludeCollinearWhenTouch), gsi::arg ("negative", false),
"@brief Creates a node providing a space check.\n"
"\n"
"The collinear_mode argument has been inserted in version 0.29.\n"
) +
gsi::constructor ("new_isolated_check", &new_isolated_check, gsi::arg ("d"), gsi::arg ("whole_edges", false), gsi::arg ("metrics", db::Euclidian, "Euclidian"), gsi::arg ("ignore_angle", tl::Variant (), "default"), gsi::arg ("min_projection", tl::Variant (), "0"), gsi::arg ("max_projection", tl::Variant (), "max."), gsi::arg ("shielded", true), gsi::arg ("opposite_filter", db::NoOppositeFilter, "NoOppositeFilter"), gsi::arg ("rect_filter", db::NoRectFilter, "NoRectFilter"), gsi::arg ("negative", false),
gsi::constructor ("new_isolated_check", &new_isolated_check, gsi::arg ("d"), gsi::arg ("whole_edges", false), gsi::arg ("metrics", db::Euclidian, "Euclidian"), gsi::arg ("ignore_angle", tl::Variant (), "default"), gsi::arg ("min_projection", tl::Variant (), "0"), gsi::arg ("max_projection", tl::Variant (), "max."), gsi::arg ("shielded", true), gsi::arg ("opposite_filter", db::NoOppositeFilter, "NoOppositeFilter"), gsi::arg ("rect_filter", db::NoRectFilter, "NoRectFilter"), gsi::arg ("collinear_mode", db::IncludeCollinearWhenTouch), gsi::arg ("negative", false),
"@brief Creates a node providing a isolated polygons (space between different polygons) check.\n"
"\n"
"The collinear_mode argument has been inserted in version 0.29.\n"
) +
gsi::constructor ("new_notch_check", &new_notch_check, gsi::arg ("d"), gsi::arg ("whole_edges", false), gsi::arg ("metrics", db::Euclidian, "Euclidian"), gsi::arg ("ignore_angle", tl::Variant (), "default"), gsi::arg ("min_projection", tl::Variant (), "0"), gsi::arg ("max_projection", tl::Variant (), "max."), gsi::arg ("shielded", true), gsi::arg ("negative", false),
gsi::constructor ("new_notch_check", &new_notch_check, gsi::arg ("d"), gsi::arg ("whole_edges", false), gsi::arg ("metrics", db::Euclidian, "Euclidian"), gsi::arg ("ignore_angle", tl::Variant (), "default"), gsi::arg ("min_projection", tl::Variant (), "0"), gsi::arg ("max_projection", tl::Variant (), "max."), gsi::arg ("shielded", true), gsi::arg ("collinear_mode", db::IncludeCollinearWhenTouch), gsi::arg ("negative", false),
"@brief Creates a node providing a intra-polygon space check.\n"
"\n"
"The collinear_mode argument has been inserted in version 0.29.\n"
) +
gsi::constructor ("new_separation_check", &new_separation_check, gsi::arg ("other"), gsi::arg ("d"), gsi::arg ("whole_edges", false), gsi::arg ("metrics", db::Euclidian, "Euclidian"), gsi::arg ("ignore_angle", tl::Variant (), "default"), gsi::arg ("min_projection", tl::Variant (), "0"), gsi::arg ("max_projection", tl::Variant (), "max."), gsi::arg ("shielded", true), gsi::arg ("opposite_filter", db::NoOppositeFilter, "NoOppositeFilter"), gsi::arg ("rect_filter", db::NoRectFilter, "NoRectFilter"), gsi::arg ("negative", false),
gsi::constructor ("new_separation_check", &new_separation_check, gsi::arg ("other"), gsi::arg ("d"), gsi::arg ("whole_edges", false), gsi::arg ("metrics", db::Euclidian, "Euclidian"), gsi::arg ("ignore_angle", tl::Variant (), "default"), gsi::arg ("min_projection", tl::Variant (), "0"), gsi::arg ("max_projection", tl::Variant (), "max."), gsi::arg ("shielded", true), gsi::arg ("opposite_filter", db::NoOppositeFilter, "NoOppositeFilter"), gsi::arg ("rect_filter", db::NoRectFilter, "NoRectFilter"), gsi::arg ("collinear_mode", db::IncludeCollinearWhenTouch), gsi::arg ("negative", false),
"@brief Creates a node providing a separation check.\n"
"\n"
"The collinear_mode argument has been inserted in version 0.29.\n"
) +
gsi::constructor ("new_overlap_check", &new_overlap_check, gsi::arg ("other"), gsi::arg ("d"), gsi::arg ("whole_edges", false), gsi::arg ("metrics", db::Euclidian, "Euclidian"), gsi::arg ("ignore_angle", tl::Variant (), "default"), gsi::arg ("min_projection", tl::Variant (), "0"), gsi::arg ("max_projection", tl::Variant (), "max."), gsi::arg ("shielded", true), gsi::arg ("opposite_filter", db::NoOppositeFilter, "NoOppositeFilter"), gsi::arg ("rect_filter", db::NoRectFilter, "NoRectFilter"), gsi::arg ("negative", false),
gsi::constructor ("new_overlap_check", &new_overlap_check, gsi::arg ("other"), gsi::arg ("d"), gsi::arg ("whole_edges", false), gsi::arg ("metrics", db::Euclidian, "Euclidian"), gsi::arg ("ignore_angle", tl::Variant (), "default"), gsi::arg ("min_projection", tl::Variant (), "0"), gsi::arg ("max_projection", tl::Variant (), "max."), gsi::arg ("shielded", true), gsi::arg ("opposite_filter", db::NoOppositeFilter, "NoOppositeFilter"), gsi::arg ("rect_filter", db::NoRectFilter, "NoRectFilter"), gsi::arg ("collinear_mode", db::IncludeCollinearWhenTouch), gsi::arg ("negative", false),
"@brief Creates a node providing an overlap check.\n"
"\n"
"The collinear_mode argument has been inserted in version 0.29.\n"
) +
gsi::constructor ("new_enclosing_check", &new_enclosing_check, gsi::arg ("other"), gsi::arg ("d"), gsi::arg ("whole_edges", false), gsi::arg ("metrics", db::Euclidian, "Euclidian"), gsi::arg ("ignore_angle", tl::Variant (), "default"), gsi::arg ("min_projection", tl::Variant (), "0"), gsi::arg ("max_projection", tl::Variant (), "max."), gsi::arg ("shielded", true), gsi::arg ("opposite_filter", db::NoOppositeFilter, "NoOppositeFilter"), gsi::arg ("rect_filter", db::NoRectFilter, "NoRectFilter"), gsi::arg ("negative", false),
gsi::constructor ("new_enclosing_check", &new_enclosing_check, gsi::arg ("other"), gsi::arg ("d"), gsi::arg ("whole_edges", false), gsi::arg ("metrics", db::Euclidian, "Euclidian"), gsi::arg ("ignore_angle", tl::Variant (), "default"), gsi::arg ("min_projection", tl::Variant (), "0"), gsi::arg ("max_projection", tl::Variant (), "max."), gsi::arg ("shielded", true), gsi::arg ("opposite_filter", db::NoOppositeFilter, "NoOppositeFilter"), gsi::arg ("rect_filter", db::NoRectFilter, "NoRectFilter"), gsi::arg ("collinear_mode", db::IncludeCollinearWhenTouch), gsi::arg ("negative", false),
"@brief Creates a node providing an inside (enclosure) check.\n"
"\n"
"The collinear_mode argument has been inserted in version 0.29.\n"
) +
gsi::constructor ("new_enclosed_check", &new_enclosed_check, gsi::arg ("other"), gsi::arg ("d"), gsi::arg ("whole_edges", false), gsi::arg ("metrics", db::Euclidian, "Euclidian"), gsi::arg ("ignore_angle", tl::Variant (), "default"), gsi::arg ("min_projection", tl::Variant (), "0"), gsi::arg ("max_projection", tl::Variant (), "max."), gsi::arg ("shielded", true), gsi::arg ("opposite_filter", db::NoOppositeFilter, "NoOppositeFilter"), gsi::arg ("rect_filter", db::NoRectFilter, "NoRectFilter"), gsi::arg ("negative", false),
gsi::constructor ("new_enclosed_check", &new_enclosed_check, gsi::arg ("other"), gsi::arg ("d"), gsi::arg ("whole_edges", false), gsi::arg ("metrics", db::Euclidian, "Euclidian"), gsi::arg ("ignore_angle", tl::Variant (), "default"), gsi::arg ("min_projection", tl::Variant (), "0"), gsi::arg ("max_projection", tl::Variant (), "max."), gsi::arg ("shielded", true), gsi::arg ("opposite_filter", db::NoOppositeFilter, "NoOppositeFilter"), gsi::arg ("rect_filter", db::NoRectFilter, "NoRectFilter"), gsi::arg ("collinear_mode", db::IncludeCollinearWhenTouch), gsi::arg ("negative", false),
"@brief Creates a node providing an enclosed (secondary enclosing primary) check.\n"
"\n"
"This method has been added in version 0.27.5.\n"
"This method has been added in version 0.27.5. The collinear_mode argument has been inserted in version 0.29.\n"
) +
gsi::constructor ("new_perimeter_filter", &new_perimeter_filter, gsi::arg ("input"), gsi::arg ("inverse", false), gsi::arg ("pmin", 0), gsi::arg ("pmax", std::numeric_limits<db::coord_traits<db::Coord>::perimeter_type>::max (), "max"),
"@brief Creates a node filtering the input by perimeter.\n"
@ -803,9 +823,7 @@ Class<db::CompoundRegionOperationNode> decl_CompoundRegionOperationNode ("db", "
"\n"
"The search distance for intruder shapes is determined by the operation and computed from the operation's requirements.\n"
"\n"
"NOTE: this feature is experimental and not deployed into the the DRC framework yet.\n"
"\n"
"This class has been introduced in version 0.27."
"This class has been introduced in version 0.27. The API is considered internal and will change without notice."
);
gsi::EnumIn<db::CompoundRegionOperationNode, db::CompoundRegionLogicalBoolOperationNode::LogicalOp> decl_dbCompoundRegionLogicalBoolOperationNode_LogicalOp ("db", "LogicalOp",

View File

@ -3274,7 +3274,12 @@ gsi::Enum<db::collinear_mode_type> decl_CollinearMode ("db", "CollinearMode",
) +
gsi::enum_const ("IncludeCollinearWhenTouch", db::IncludeCollinearWhenTouch,
"@brief Specifies that check functions should include collinear edges when they touch\n"
"With this specification, the check functions will also check edges which are collinear, but only if they touch in at least one point. "
"With this specification, the check functions will also check edges which are collinear, but only if they share at least one point. "
"This is the mode that allows checking the 'kissing corner' cases."
) +
gsi::enum_const ("IncludeCollinearWhenOverlap", db::IncludeCollinearWhenOverlap,
"@brief Specifies that check functions should include collinear edges when they overlap\n"
"With this specification, the check functions will also check edges which are collinear, but only if they share more than a single point. "
"This is the mode that allows checking the 'kissing corner' cases."
),
"@brief This class represents the collinear_mode type for \\Region#width and related checks.\n"

View File

@ -382,6 +382,22 @@ TEST(8_KissingCornerProblem)
res = f.check (db::Edge (db::Point (0, 0), db::Point (0, 100)), db::Edge (db::Point (0, -1), db::Point (0, -100)), &output);
EXPECT_EQ (res, false);
f.set_collinear_mode (db::IncludeCollinearWhenOverlap);
res = f.check (db::Edge (db::Point (0, 0), db::Point (0, 100)), db::Edge (db::Point (0, 201), db::Point (0, 101)), &output);
EXPECT_EQ (res, false);
res = f.check (db::Edge (db::Point (1, 0), db::Point (1, 100)), db::Edge (db::Point (0, 201), db::Point (0, 0)), &output);
EXPECT_EQ (res, false);
res = f.check (db::Edge (db::Point (0, 0), db::Point (0, 100)), db::Edge (db::Point (0, 200), db::Point (0, 100)), &output);
EXPECT_EQ (res, false);
res = f.check (db::Edge (db::Point (0, 0), db::Point (0, 100)), db::Edge (db::Point (0, 200), db::Point (0, 50)), &output);
EXPECT_EQ (res, true);
EXPECT_EQ (output.first ().to_string () + ":" + output.second ().to_string (), "(0,40;0,100):(0,110;0,50)");
res = f.check (db::Edge (db::Point (0, 0), db::Point (0, 100)), db::Edge (db::Point (0, 0), db::Point (0, -100)), &output);
EXPECT_EQ (res, false);
res = f.check (db::Edge (db::Point (0, 0), db::Point (0, 100)), db::Edge (db::Point (0, -1), db::Point (0, -100)), &output);
EXPECT_EQ (res, false);
f.set_collinear_mode (db::NeverIncludeCollinear);
res = f.check (db::Edge (db::Point (0, 0), db::Point (0, 100)), db::Edge (db::Point (0, 201), db::Point (0, 101)), &output);
@ -417,6 +433,22 @@ TEST(8_KissingCornerProblem)
res = f.check (db::Edge (db::Point (0, 100), db::Point (0, 0)), db::Edge (db::Point (0, -100), db::Point (0, -1)), &output);
EXPECT_EQ (res, false);
f.set_collinear_mode (db::IncludeCollinearWhenOverlap);
res = f.check (db::Edge (db::Point (0, 100), db::Point (0, 0)), db::Edge (db::Point (0, 101), db::Point (0, 201)), &output);
EXPECT_EQ (res, false);
res = f.check (db::Edge (db::Point (1, 100), db::Point (1, 0)), db::Edge (db::Point (0, 0), db::Point (0, 200)), &output);
EXPECT_EQ (res, false);
res = f.check (db::Edge (db::Point (0, 100), db::Point (0, 0)), db::Edge (db::Point (0, 100), db::Point (0, 200)), &output);
EXPECT_EQ (res, false);
res = f.check (db::Edge (db::Point (0, 100), db::Point (0, 0)), db::Edge (db::Point (0, 50), db::Point (0, 200)), &output);
EXPECT_EQ (res, true);
EXPECT_EQ (output.first ().to_string () + ":" + output.second ().to_string (), "(0,100;0,40):(0,50;0,110)");
res = f.check (db::Edge (db::Point (0, 100), db::Point (0, 0)), db::Edge (db::Point (0, -100), db::Point (0, 0)), &output);
EXPECT_EQ (res, false);
res = f.check (db::Edge (db::Point (0, 100), db::Point (0, 0)), db::Edge (db::Point (0, -100), db::Point (0, -1)), &output);
EXPECT_EQ (res, false);
f.set_collinear_mode (db::NeverIncludeCollinear);
f.set_metrics (db::Euclidian);

View File

@ -1485,6 +1485,7 @@ CODE
shielded = nil
opposite_filter = RBA::Region::NoOppositeFilter
rect_filter = RBA::Region::NoRectFilter
collinear_mode = RBA::Region::IncludeCollinearWhenTouch
n = 1
args.each do |a|
@ -1492,6 +1493,10 @@ CODE
metrics = a.value
elsif a.is_a?(DRCWholeEdges)
whole_edges = a.value
elsif a.is_a?(DRCPropertiesConstraint)
prop_constraint = a.value
elsif a.is_a?(DRCCollinearMode)
collinear_mode = a.value
elsif a.is_a?(DRCOppositeErrorFilter)
opposite_filter = a.value
elsif a.is_a?(DRCRectangleErrorFilter)
@ -1523,6 +1528,8 @@ CODE
elsif rect_filter != RBA::Region::NoRectFilter
raise("A rectangle error filter cannot be used with this check")
end
args << collinear_mode
if :#{f} == :width || :#{f} == :space || :#{f} == :notch || :#{f} == :isolated
other && raise("No other layer must be specified for a single-layer check")

View File

@ -322,6 +322,12 @@ module DRC
end
end
def without_touching(f = true)
self._context("without_touching") do
DRCCollinearMode::new(f ? RBA::Region::IncludeCollinearWhenOverlap : RBA::Region::IncludeCollinearWhenTouch)
end
end
def euclidian
DRCMetrics::new(RBA::Region::Euclidian)
end

View File

@ -3687,10 +3687,12 @@ CODE
# but is more intuitive, as "projecting" is written with a condition, like
# "projecting < 2.um". Available operators are: "==", "<", "<=", ">" and ">=".
# Double-bounded ranges are also available, like: "0.5 <= projecting < 2.0". @/li
# @li @b transparent @/b: performs the check without shielding (polygon layers only) @/li
# @li @b shielded @/b: performs the check with shielding (polygon layers only) @/li
# @li @b without_touching @/b: With this option present, touching corners (aka "kissing
# corners") will not yield errors. The default is to produce errors in these cases. @/li
# @li @b transparent @/b: Performs the check without shielding (polygon layers only) @/li
# @li @b shielded @/b: Performs the check with shielding (polygon layers only) @/li
# @li @b props_eq @/b, @b props_ne @/b, @b props_copy @/b: (only props_copy applies to width check) -
# see "Properties constraints" below. @/li
# See "Properties constraints" below. @/li
# @/ul
#
# Note that without the angle_limit, acute corners will always be reported, since two
@ -3792,6 +3794,22 @@ CODE
# space_connected = metal1_nets.space(0.4.um, props_eq + props_copy)
# @/code
#
# @h3 Touching shapes @/h3
#
# The \without_touching option will turn off errors that arise due to
# the "kissing corner" configuration (or "checkerboard pattern"). Formally
# this is a width violation across the diagonal, but when considering this
# configuration as disconnected boxes, no error should be reported.
#
# The following images illustrate the effect of the \without_touching option:
#
# @table
# @tr
# @td @img(/images/drc_width5.png) @/td
# @td @img(/images/drc_width6.png) @/td
# @/tr
# @/table
#
# %DRC%
# @name space
@ -3912,7 +3930,25 @@ CODE
# @/tr
# @/table
#
# @h3 opposite and rectangle error filtering @/h3
# @h3 Touching shapes @/h3
#
# Like \width and \space, the separation check also supports the \without_touching option.
#
# This option will turn off errors that arise due to
# collinear edges touching in one corner (the "kissing corners" configuration).
# By default, such edges will yield an error, as they
# form a zero-distance situation. With this option in place, no errors will be reported.
#
# The following images illustrate the effect of the \without_touching option:
#
# @table
# @tr
# @td @img(/images/drc_separation12.png) @/td
# @td @img(/images/drc_separation13.png) @/td
# @/tr
# @/table
#
# @h3 Opposite and rectangle error filtering @/h3
#
# The options for the separation check are those available for the \width or \space
# method plus opposite and rectangle error filtering.
@ -4121,6 +4157,7 @@ CODE
opposite_filter = RBA::Region::NoOppositeFilter
rect_filter = RBA::Region::NoRectFilter
prop_constraint = RBA::Region::IgnoreProperties
collinear_mode = RBA::Region::IncludeCollinearWhenTouch
n = 1
args.each do |a|
@ -4132,6 +4169,8 @@ CODE
negative = true
elsif a.is_a?(DRCPropertiesConstraint)
prop_constraint = a.value
elsif a.is_a?(DRCCollinearMode)
collinear_mode = a.value
elsif a.is_a?(DRCOppositeErrorFilter)
opposite_filter = a.value
elsif a.is_a?(DRCRectangleErrorFilter)
@ -4185,6 +4224,8 @@ CODE
raise("A rectangle error filter can only be used for polygon layers")
end
args << collinear_mode
border = (metrics == RBA::Region::Square ? value * 1.5 : value)
if :#{f} == :width || :#{f} == :space || :#{f} == :notch || :#{f} == :isolated

View File

@ -95,6 +95,16 @@ module DRC
end
end
# A wrapper for the "collinear mode" for
# the DRC functions. The purpose of this class
# is to identify the value by the class.
class DRCCollinearMode
attr_accessor :value
def initialize(v)
self.value = v
end
end
# A wrapper for the "as_dots" or "as_boxes" flag for
# some DRC functions. The purpose of this class
# is to identify the value by the class.