diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index d547472b0..7d9c02da0 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -34,10 +34,10 @@ jobs:
android: true
dotnet: true
haskell: true
- large-packages: false # not working currently
+ large-packages: true
- uses: hmarr/debug-action@v2
- name: Cancel Workflow Action
- uses: styfle/cancel-workflow-action@0.12.0
+ uses: styfle/cancel-workflow-action@0.12.1
- uses: actions/checkout@v4
- name: ccache
uses: hendrikmuhs/ccache-action@v1.2
@@ -52,7 +52,7 @@ jobs:
HOST_CCACHE_DIR="$(ccache -k cache_dir)"
mkdir -p $HOST_CCACHE_DIR
- name: Build wheels # check https://cibuildwheel.readthedocs.io/en/stable/setup/#github-actions
- uses: pypa/cibuildwheel@v2.16.2
+ uses: pypa/cibuildwheel@v2.16.5
# to supply options, put them in 'env', like:
# env:
# CIBW_SOME_OPTION: value
diff --git a/scripts/drc_lvs_doc/create_drc_samples.rb b/scripts/drc_lvs_doc/create_drc_samples.rb
index 5594555be..bbc97987e 100644
--- a/scripts/drc_lvs_doc/create_drc_samples.rb
+++ b/scripts/drc_lvs_doc/create_drc_samples.rb
@@ -177,6 +177,37 @@ run_demo gen, "input.width(1.2, projection)", "drc_width2.png"
run_demo gen, "input.width(1.2, square)", "drc_width3.png"
run_demo gen, "input.width(1.2, whole_edges)", "drc_width4.png"
+class Gen
+ def produce(s1, s2)
+ pts = [
+ RBA::Point::new(0, 0),
+ RBA::Point::new(2000, 0),
+ RBA::Point::new(2000, 2000),
+ RBA::Point::new(0, 2000)
+ ];
+ s1.insert(RBA::Polygon::new(pts))
+ pts = [
+ RBA::Point::new(2000, 2000),
+ RBA::Point::new(4000, 2000),
+ RBA::Point::new(4000, 4000),
+ RBA::Point::new(2000, 4000)
+ ];
+ s1.insert(RBA::Polygon::new(pts))
+ pts = [
+ RBA::Point::new( 500, 4000),
+ RBA::Point::new(2500, 4000),
+ RBA::Point::new(2500, 6000),
+ RBA::Point::new( 500, 6000)
+ ];
+ s1.insert(RBA::Polygon::new(pts))
+ end
+end
+
+gen = Gen::new
+
+run_demo gen, "input.width(1.0)", "drc_width5.png"
+run_demo gen, "input.width(1.0, without_touching_corners)", "drc_width6.png"
+
class Gen
def produce(s1, s2)
pts = [
@@ -381,6 +412,45 @@ run_demo gen, "input1.sep(input2, 1.0, projection,\n" +
" one_side_allowed,\n" +
" two_opposite_sides_allowed)", "drc_separation11.png"
+class Gen
+ def produce(s1, s2)
+ pts = [
+ RBA::Point::new(0, 0),
+ RBA::Point::new(2000, 0),
+ RBA::Point::new(2000, 1500),
+ RBA::Point::new(0, 1500)
+ ];
+ s2.insert(RBA::Polygon::new(pts))
+ pts = [
+ RBA::Point::new(2000, 1500),
+ RBA::Point::new(3500, 1500),
+ RBA::Point::new(3500, 3500),
+ RBA::Point::new(2000, 3500)
+ ];
+ s1.insert(RBA::Polygon::new(pts))
+ pts = [
+ RBA::Point::new(1000, 3500),
+ RBA::Point::new(3000, 3500),
+ RBA::Point::new(3000, 5000),
+ RBA::Point::new(1000, 5000)
+ ];
+ s2.insert(RBA::Polygon::new(pts))
+ pts = [
+ RBA::Point::new(1000, 5500),
+ RBA::Point::new(3000, 5500),
+ RBA::Point::new(3000, 7000),
+ RBA::Point::new(1000, 7000)
+ ];
+ s1.insert(RBA::Polygon::new(pts))
+ end
+end
+
+gen = Gen::new
+
+run_demo gen, "input1.sep(input2, 1.0)", "drc_separation12.png"
+run_demo gen, "input1.sep(input2, 1.0, without_touching_corners)", "drc_separation13.png"
+run_demo gen, "input1.sep(input2, 1.0, without_touching_edges)", "drc_separation14.png"
+
# ...
class Gen
diff --git a/scripts/makedeb.sh b/scripts/makedeb.sh
index bcc8c8a48..b2befb82c 100755
--- a/scripts/makedeb.sh
+++ b/scripts/makedeb.sh
@@ -20,6 +20,10 @@ buildopts=
# TODO: derive this list automatically?
case $target in
+
+debian12)
+ depends="python3-dev, libc6-dev, libgcc-s1, libgit2-1.5, libqt6core5compat6, libqt6designer6, libqt6gui6, libqt6multimedia6, libqt6multimediaquick6, libqt6network6, libqt6printsupport6, libqt6sql6, libqt6svg6, libqt6widgets6, libqt6xml6, libruby3.1, libstdc++6, zlib1g"
+ ;;
ubuntu16)
depends="libqt4-designer (>= 4.8.6), libqt4-xml (>= 4.8.6), libqt4-sql (>= 4.8.6), libqt4-network (>= 4.8.6), libqtcore4 (>= 4.8.6), libqtgui4 (>= 4.8.6), zlib1g (>= 1.2.8), libgit2-24 (>= 0.24.0), libruby2.3 (>= 2.3.1), python3 (>= 3.5.1), libpython3.5 (>= 3.5.1), libstdc++6 (>= 4.6.3), libc6 (>= 2.15)"
# No HTTPS support - that is somewhat useless
@@ -63,7 +67,7 @@ libdir="usr/lib/klayout"
rm -rf $bininstdir
# do the actual build
-./build.sh -j2 \
+./build.sh -j$(nproc) \
-bin $bininstdir \
-build $builddir \
-rpath /$libdir \
diff --git a/src/db/db/dbAsIfFlatEdges.cc b/src/db/db/dbAsIfFlatEdges.cc
index e4a482fe2..4f38b882e 100644
--- a/src/db/db/dbAsIfFlatEdges.cc
+++ b/src/db/db/dbAsIfFlatEdges.cc
@@ -761,12 +761,7 @@ AsIfFlatEdges::run_check (db::edge_relation_type rel, const Edges *other, db::Co
}
}
- EdgeRelationFilter check (rel, d, options.metrics);
- check.set_include_zero (false);
- check.set_whole_edges (options.whole_edges);
- check.set_ignore_angle (options.ignore_angle);
- check.set_min_projection (options.min_projection);
- check.set_max_projection (options.max_projection);
+ EdgeRelationFilter check (rel, d, options);
edge2edge_check_for_edges edge_check (check, *result, other != 0);
scanner.process (edge_check, d, db::box_convert ());
diff --git a/src/db/db/dbAsIfFlatRegion.cc b/src/db/db/dbAsIfFlatRegion.cc
index 54f0b4f3b..5a86535fd 100644
--- a/src/db/db/dbAsIfFlatRegion.cc
+++ b/src/db/db/dbAsIfFlatRegion.cc
@@ -1139,12 +1139,7 @@ AsIfFlatRegion::run_check (db::edge_relation_type rel, bool different_polygons,
db::RegionIterator polygons (needs_merged_primary ? begin_merged () : begin ());
bool primary_is_merged = ! merged_semantics () || needs_merged_primary || is_merged ();
- EdgeRelationFilter check (rel, d, options.metrics);
- check.set_include_zero (false);
- check.set_whole_edges (options.whole_edges);
- check.set_ignore_angle (options.ignore_angle);
- check.set_min_projection (options.min_projection);
- check.set_max_projection (options.max_projection);
+ EdgeRelationFilter check (rel, d, options);
std::vector others;
std::vector foreign;
@@ -1217,12 +1212,7 @@ AsIfFlatRegion::run_single_polygon_check (db::edge_relation_type rel, db::Coord
std::unique_ptr result (new FlatEdgePairs ());
db::PropertyMapper pm (result->properties_repository (), properties_repository ());
- EdgeRelationFilter check (rel, d, options.metrics);
- check.set_include_zero (false);
- check.set_whole_edges (options.whole_edges);
- check.set_ignore_angle (options.ignore_angle);
- check.set_min_projection (options.min_projection);
- check.set_max_projection (options.max_projection);
+ EdgeRelationFilter check (rel, d, options);
for (RegionIterator p (begin_merged ()); ! p.at_end (); ++p) {
diff --git a/src/db/db/dbCommonReader.cc b/src/db/db/dbCommonReader.cc
index 64eb1d85f..e40b88694 100644
--- a/src/db/db/dbCommonReader.cc
+++ b/src/db/db/dbCommonReader.cc
@@ -160,7 +160,7 @@ CommonReaderBase::rename_cell (db::Layout &layout, size_t id, const std::string
// Both cells already exist and are not identical: merge ID-declared cell into the name-declared one
layout.force_update ();
- merge_cell (layout, iname->second.second, iid->second.second);
+ merge_cell (layout, iname->second.second, iid->second.second, true);
iid->second.second = iname->second.second;
}
@@ -235,7 +235,7 @@ CommonReaderBase::cell_for_instance (db::Layout &layout, const std::string &cn)
}
void
-CommonReaderBase::merge_cell (db::Layout &layout, db::cell_index_type target_cell_index, db::cell_index_type src_cell_index) const
+CommonReaderBase::merge_cell (db::Layout &layout, db::cell_index_type target_cell_index, db::cell_index_type src_cell_index, bool with_meta) const
{
const db::Cell &src_cell = layout.cell (src_cell_index);
db::Cell &target_cell = layout.cell (target_cell_index);
@@ -249,11 +249,11 @@ CommonReaderBase::merge_cell (db::Layout &layout, db::cell_index_type target_cel
}
}
- merge_cell_without_instances (layout, target_cell_index, src_cell_index);
+ merge_cell_without_instances (layout, target_cell_index, src_cell_index, with_meta);
}
void
-CommonReaderBase::merge_cell_without_instances (db::Layout &layout, db::cell_index_type target_cell_index, db::cell_index_type src_cell_index) const
+CommonReaderBase::merge_cell_without_instances (db::Layout &layout, db::cell_index_type target_cell_index, db::cell_index_type src_cell_index, bool with_meta) const
{
const db::Cell &src_cell = layout.cell (src_cell_index);
db::Cell &target_cell = layout.cell (target_cell_index);
@@ -268,6 +268,16 @@ CommonReaderBase::merge_cell_without_instances (db::Layout &layout, db::cell_ind
// replace all instances of the new cell with the original one
layout.replace_instances_of (src_cell.cell_index (), target_cell.cell_index ());
+ // merge meta info
+ if (with_meta) {
+ auto ib = layout.begin_meta (src_cell.cell_index ());
+ auto ie = layout.end_meta (src_cell.cell_index ());
+ for (auto i = ib; i != ie; ++i) {
+ layout.add_meta_info (target_cell.cell_index (), i->first, i->second);
+ }
+ }
+ layout.clear_meta (src_cell.cell_index ());
+
// finally delete the new cell
layout.delete_cell (src_cell.cell_index ());
}
@@ -371,7 +381,7 @@ CommonReaderBase::finish (db::Layout &layout)
layout.cell (ci_org).clear_shapes ();
- merge_cell (layout, ci_org, ci_new);
+ merge_cell (layout, ci_org, ci_new, true);
} else if (m_cc_resolution == SkipNewCell && ! layout.cell (ci_org).is_ghost_cell ()) {
@@ -379,11 +389,11 @@ CommonReaderBase::finish (db::Layout &layout)
layout.cell (ci_new).clear_shapes ();
// NOTE: ignore instances -> this saves us a layout update
- merge_cell_without_instances (layout, ci_org, ci_new);
+ merge_cell_without_instances (layout, ci_org, ci_new, false);
} else {
- merge_cell (layout, ci_org, ci_new);
+ merge_cell (layout, ci_org, ci_new, m_cc_resolution != SkipNewCell);
}
diff --git a/src/db/db/dbCommonReader.h b/src/db/db/dbCommonReader.h
index 45afd6cc5..90e98d339 100644
--- a/src/db/db/dbCommonReader.h
+++ b/src/db/db/dbCommonReader.h
@@ -242,12 +242,12 @@ protected:
/**
* @brief Merge (and delete) the src_cell into target_cell
*/
- void merge_cell (db::Layout &layout, db::cell_index_type target_cell_index, db::cell_index_type src_cell_index) const;
+ void merge_cell (db::Layout &layout, db::cell_index_type target_cell_index, db::cell_index_type src_cell_index, bool with_meta) const;
/**
* @brief Merge (and delete) the src_cell into target_cell without instances
*/
- void merge_cell_without_instances (db::Layout &layout, db::cell_index_type target_cell_index, db::cell_index_type src_cell_index) const;
+ void merge_cell_without_instances (db::Layout &layout, db::cell_index_type target_cell_index, db::cell_index_type src_cell_index, bool with_meta) const;
/**
* @brief Gets the layer name map
diff --git a/src/db/db/dbCompoundOperation.cc b/src/db/db/dbCompoundOperation.cc
index 21e23c1c4..be321c493 100644
--- a/src/db/db/dbCompoundOperation.cc
+++ b/src/db/db/dbCompoundOperation.cc
@@ -1625,19 +1625,13 @@ CompoundRegionEdgePairToEdgeProcessingOperationNode::do_compute_local (CompoundR
// ---------------------------------------------------------------------------------------------
CompoundRegionCheckOperationNode::CompoundRegionCheckOperationNode (db::edge_relation_type rel, bool different_polygons, db::Coord d, const db::RegionCheckOptions &options)
- : CompoundRegionMultiInputOperationNode (), m_check (rel, d, options.metrics), m_different_polygons (different_polygons), m_options (options), m_has_other (false), m_is_other_merged (false)
+ : CompoundRegionMultiInputOperationNode (), m_check (rel, d, options), m_different_polygons (different_polygons), m_options (options), m_has_other (false), m_is_other_merged (false)
{
set_description ("check");
-
- m_check.set_include_zero (false);
- m_check.set_whole_edges (options.whole_edges);
- m_check.set_ignore_angle (options.ignore_angle);
- m_check.set_min_projection (options.min_projection);
- m_check.set_max_projection (options.max_projection);
}
CompoundRegionCheckOperationNode::CompoundRegionCheckOperationNode (CompoundRegionOperationNode *input, db::edge_relation_type rel, bool different_polygons, db::Coord d, const db::RegionCheckOptions &options)
- : CompoundRegionMultiInputOperationNode (input), m_check (rel, d, options.metrics), m_different_polygons (different_polygons), m_options (options), m_has_other (false), m_is_other_merged (false)
+ : CompoundRegionMultiInputOperationNode (input), m_check (rel, d, options), m_different_polygons (different_polygons), m_options (options), m_has_other (false), m_is_other_merged (false)
{
set_description ("check");
@@ -1645,16 +1639,10 @@ CompoundRegionCheckOperationNode::CompoundRegionCheckOperationNode (CompoundRegi
if (pc_always_different (m_options.prop_constraint)) {
m_different_polygons = true;
}
-
- m_check.set_include_zero (false);
- m_check.set_whole_edges (options.whole_edges);
- m_check.set_ignore_angle (options.ignore_angle);
- m_check.set_min_projection (options.min_projection);
- m_check.set_max_projection (options.max_projection);
}
CompoundRegionCheckOperationNode::CompoundRegionCheckOperationNode (CompoundRegionOperationNode *input, CompoundRegionOperationNode *other, db::edge_relation_type rel, bool different_polygons, db::Coord d, const db::RegionCheckOptions &options)
- : CompoundRegionMultiInputOperationNode (other), m_check (rel, d, options.metrics), m_different_polygons (different_polygons), m_options (options)
+ : CompoundRegionMultiInputOperationNode (other), m_check (rel, d, options), m_different_polygons (different_polygons), m_options (options)
{
tl_assert (input == 0); // input is a dummy parameter
@@ -1663,12 +1651,6 @@ CompoundRegionCheckOperationNode::CompoundRegionCheckOperationNode (CompoundRegi
m_is_other_merged = other->is_merged ();
set_description ("check");
-
- m_check.set_include_zero (false);
- m_check.set_whole_edges (options.whole_edges);
- m_check.set_ignore_angle (options.ignore_angle);
- m_check.set_min_projection (options.min_projection);
- m_check.set_max_projection (options.max_projection);
}
db::OnEmptyIntruderHint
diff --git a/src/db/db/dbDeepEdges.cc b/src/db/db/dbDeepEdges.cc
index 5a2812207..a9608af23 100644
--- a/src/db/db/dbDeepEdges.cc
+++ b/src/db/db/dbDeepEdges.cc
@@ -2046,12 +2046,7 @@ DeepEdges::run_check (db::edge_relation_type rel, const Edges *other, db::Coord
const db::DeepLayer &edges = merged_deep_layer ();
- EdgeRelationFilter check (rel, d, options.metrics);
- check.set_include_zero (false);
- check.set_whole_edges (options.whole_edges);
- check.set_ignore_angle (options.ignore_angle);
- check.set_min_projection (options.min_projection);
- check.set_max_projection (options.max_projection);
+ EdgeRelationFilter check (rel, d, options);
std::unique_ptr res (new db::DeepEdgePairs (edges.derived ()));
diff --git a/src/db/db/dbDeepRegion.cc b/src/db/db/dbDeepRegion.cc
index ceb7cf0a9..f44f0fca7 100644
--- a/src/db/db/dbDeepRegion.cc
+++ b/src/db/db/dbDeepRegion.cc
@@ -1940,12 +1940,7 @@ DeepRegion::run_check (db::edge_relation_type rel, bool different_polygons, cons
const db::DeepLayer &polygons = needs_merged_primary ? merged_deep_layer () : deep_layer ();
- EdgeRelationFilter check (rel, d, options.metrics);
- check.set_include_zero (false);
- check.set_whole_edges (options.whole_edges);
- check.set_ignore_angle (options.ignore_angle);
- check.set_min_projection (options.min_projection);
- check.set_max_projection (options.max_projection);
+ EdgeRelationFilter check (rel, d, options);
std::unique_ptr res (new db::DeepEdgePairs (polygons.derived ()));
@@ -2008,12 +2003,7 @@ DeepRegion::run_single_polygon_check (db::edge_relation_type rel, db::Coord d, c
double mag = tr.mag ();
db::Coord d_with_mag = db::coord_traits::rounded (d / mag);
- EdgeRelationFilter check (rel, d_with_mag, options.metrics);
- check.set_include_zero (false);
- check.set_whole_edges (options.whole_edges);
- check.set_ignore_angle (options.ignore_angle);
- check.set_min_projection (options.min_projection);
- check.set_max_projection (options.max_projection);
+ EdgeRelationFilter check (rel, d_with_mag, options);
const db::Shapes &shapes = c->shapes (polygons.layer ());
db::Shapes &result = c->shapes (res->deep_layer ().layer ());
diff --git a/src/db/db/dbEdgePairRelations.cc b/src/db/db/dbEdgePairRelations.cc
index 4875b29b4..3e62bd3ca 100644
--- a/src/db/db/dbEdgePairRelations.cc
+++ b/src/db/db/dbEdgePairRelations.cc
@@ -48,17 +48,53 @@ db::Edge::distance_type edge_projection (const db::Edge &a, const db::Edge &b)
return db::coord_traits::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 (zero_distance_mode zd_mode, const db::Edge &a, const db::Edge &b)
+{
+ if (zd_mode == AlwaysIncludeZeroDistance) {
+
+ return true;
+
+ } else if (zd_mode == NeverIncludeZeroDistance) {
+
+ return false;
+
+ } else {
+
+ int s1 = a.side_of (b.p1 ());
+ int s2 = a.side_of (b.p2 ());
+
+ if (s1 == 0 && s2 == 0) {
+ if (zd_mode == IncludeZeroDistanceWhenTouching || zd_mode == IncludeZeroDistanceWhenCollinearAndTouching) {
+ return a.intersect (b);
+ } else if (zd_mode == IncludeZeroDistanceWhenOverlapping) {
+ return a.coincident (b);
+ }
+ } else if ((s1 == 0 || s2 == 0) && a.p1 () != b.p2 () && a.p2 () != b.p1 ()) {
+ if (zd_mode == IncludeZeroDistanceWhenTouching) {
+ return a.intersect (b);
+ }
+ }
+
+ return false;
+
+ }
+}
+
/**
* @brief Returns the part of the "other" edge which is on the inside side of e and within distance d
*
* This function applies Euclidian metrics.
* If no such part is found, this function returns false.
+ *
+ * The input edges are normalized to "width" orientation.
*/
-bool euclidian_near_part_of_edge (bool include_zero, db::coord_traits::distance_type d, const db::Edge &e, const db::Edge &other, db::Edge *output)
+bool euclidian_near_part_of_edge (zero_distance_mode zd_mode, db::coord_traits::distance_type d, const db::Edge &e, const db::Edge &other, db::Edge *output)
{
// Handle the case of point-like basic edge: cannot determine
// orientation
-
if (e.is_degenerate ()) {
return false;
}
@@ -67,11 +103,7 @@ bool euclidian_near_part_of_edge (bool include_zero, db::coord_traits
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.
- if (! include_zero && s1 == 0 && s2 == 0 && e.intersect (g)) {
- include_zero = true;
- }
-
+ bool include_zero = include_zero_flag (zd_mode, e, g);
int thr = include_zero ? 0 : -1;
// keep only part of other which is on the "inside" side of e
@@ -89,18 +121,18 @@ bool euclidian_near_part_of_edge (bool include_zero, db::coord_traits
db::Point o = g.p1 ();
- if (e.side_of (o) >= 0) {
+ if (e.side_of (o) > thr) {
return false;
}
double a = e.double_sq_length ();
- double b = db::sprod (db::Vector (e.p1 () - o), e.d ());
- double c = e.p1 ().sq_double_distance (o) - d * d;
+ double b = db::sprod (db::Vector (e.p1 () - o), e.d ()) / a;
+ double c = (e.p1 ().sq_double_distance (o) - double (d) * double (d)) / a;
- double s = b * b - a * c;
- if (s >= 0) {
- double l1 = std::max (0.0, (-b - sqrt (s)) / a);
- double l2 = std::min (1.0, (-b + sqrt (s)) / a);
+ double s = b * b - c;
+ if (s >= -db::epsilon) {
+ double l1 = std::max (0.0, (-b - sqrt (s)));
+ double l2 = std::min (1.0, (-b + sqrt (s)));
if (l1 <= l2) {
if (output) {
*output = g;
@@ -167,13 +199,13 @@ bool euclidian_near_part_of_edge (bool include_zero, db::coord_traits
db::Point o = i ? e.p2 () : e.p1 ();
double a = g.double_sq_length ();
- double b = db::sprod (db::Vector (g.p1 () - o), g.d ());
- double c = g.p1 ().sq_double_distance (o) - double (d) * double (d);
+ double b = db::sprod (db::Vector (g.p1 () - o), g.d ()) / a;
+ double c = (g.p1 ().sq_double_distance (o) - double (d) * double (d)) / a;
- double s = b * b - a * c;
- if (s >= 0) {
- l1 = std::min (l1, (-b - sqrt (s)) / a);
- l2 = std::max (l2, (-b + sqrt (s)) / a);
+ double s = b * b - c;
+ if (s >= -db::epsilon) {
+ l1 = std::min (l1, -b - sqrt (s));
+ l2 = std::max (l2, -b + sqrt (s));
}
}
@@ -181,7 +213,7 @@ bool euclidian_near_part_of_edge (bool include_zero, db::coord_traits
l1 = std::max (0.0, l1);
l2 = std::min (1.0, l2);
- if (l1 >= l2) {
+ if (l1 > l2 - db::epsilon) {
return false;
} else {
if (output) {
@@ -194,10 +226,12 @@ bool euclidian_near_part_of_edge (bool include_zero, db::coord_traits
/**
* @brief Returns the part of the "other" edge which is on the inside side of e and within distance d
*
- * This function applies Square metrics.
+ * This function applies Projection or Square metrics.
* If no such part is found, this function returns false.
+ *
+ * The input edges are normalized to "width" orientation.
*/
-static bool var_near_part_of_edge (bool include_zero, db::coord_traits::distance_type d, db::coord_traits::distance_type dd, const db::Edge &e, const db::Edge &other, db::Edge *output)
+static bool var_near_part_of_edge (zero_distance_mode zd_mode, db::coord_traits::distance_type d, db::coord_traits::distance_type dd, const db::Edge &e, const db::Edge &other, db::Edge *output)
{
// Handle the case of point-like basic edge: cannot determine
// orientation
@@ -210,11 +244,7 @@ static bool var_near_part_of_edge (bool include_zero, db::coord_traits= 0) {
+ if (e.side_of (g.p1 ()) > thr) {
+ return false;
+ }
+ if (double (e.distance (g.p1 ())) <= -double (d)) {
return false;
}
if (db::sprod (db::Vector (g.p1 () - e.p1 ()), e.d ()) < -(dd * e.double_length ())) {
@@ -314,9 +346,9 @@ static bool var_near_part_of_edge (bool include_zero, db::coord_traits::distance_type d, const db::Edge &e, const db::Edge &other, db::Edge *output)
+bool projected_near_part_of_edge (zero_distance_mode zd_mode, db::coord_traits::distance_type d, const db::Edge &e, const db::Edge &other, db::Edge *output)
{
- return var_near_part_of_edge (include_zero, d, 0, e, other, output);
+ return var_near_part_of_edge (zd_mode, d, 0, e, other, output);
}
/**
@@ -325,20 +357,26 @@ bool projected_near_part_of_edge (bool include_zero, db::coord_traits
* This function applies Square metrics.
* If no such part is found, this function returns false.
*/
-bool square_near_part_of_edge (bool include_zero, db::coord_traits::distance_type d, const db::Edge &e, const db::Edge &other, db::Edge *output)
+bool square_near_part_of_edge (zero_distance_mode zd_mode, db::coord_traits::distance_type d, const db::Edge &e, const db::Edge &other, db::Edge *output)
{
- return var_near_part_of_edge (include_zero, d, d, e, other, output);
+ return var_near_part_of_edge (zd_mode, d, d, e, other, output);
}
// ---------------------------------------------------------------------------------
// Implementation of EdgeRelationFilter
-EdgeRelationFilter::EdgeRelationFilter (edge_relation_type r, distance_type d, metrics_type metrics, double ignore_angle, distance_type min_projection, distance_type max_projection)
- : m_whole_edges (false), m_include_zero (true), m_r (r), m_d (d), m_metrics (metrics), m_ignore_angle (0), m_min_projection (min_projection), m_max_projection (max_projection)
+EdgeRelationFilter::EdgeRelationFilter (edge_relation_type r, distance_type d, metrics_type metrics, double ignore_angle, distance_type min_projection, distance_type max_projection, zero_distance_mode zd_mode)
+ : m_whole_edges (false), m_zero_distance_mode (zd_mode), m_r (r), m_d (d), m_metrics (metrics), m_ignore_angle (0), m_min_projection (min_projection), m_max_projection (max_projection)
{
set_ignore_angle (ignore_angle);
}
+EdgeRelationFilter::EdgeRelationFilter (edge_relation_type r, distance_type d, const EdgesCheckOptions &options)
+ : m_whole_edges (options.whole_edges), m_zero_distance_mode (options.zd_mode), m_r (r), m_d (d), m_metrics (options.metrics), m_ignore_angle (0), m_min_projection (options.min_projection), m_max_projection (options.max_projection)
+{
+ set_ignore_angle (options.ignore_angle);
+}
+
void
EdgeRelationFilter::set_ignore_angle (double a)
{
@@ -399,14 +437,14 @@ EdgeRelationFilter::check (const db::Edge &a, const db::Edge &b, db::EdgePair *o
bool in1, in2;
if (m_metrics == Euclidian) {
- in2 = euclidian_near_part_of_edge (m_include_zero, m_d, an, bn, ! m_whole_edges && output ? &output->second () : 0);
- in1 = euclidian_near_part_of_edge (m_include_zero, m_d, bn, an, ! m_whole_edges && output ? &output->first () : 0);
+ in2 = euclidian_near_part_of_edge (m_zero_distance_mode, m_d, an, bn, ! m_whole_edges && output ? &output->second () : 0);
+ in1 = euclidian_near_part_of_edge (m_zero_distance_mode, m_d, bn, an, ! m_whole_edges && output ? &output->first () : 0);
} else if (m_metrics == Square) {
- in2 = square_near_part_of_edge (m_include_zero, m_d, an, bn, ! m_whole_edges && output ? &output->second () : 0);
- in1 = square_near_part_of_edge (m_include_zero, m_d, bn, an, ! m_whole_edges && output ? &output->first () : 0);
+ in2 = square_near_part_of_edge (m_zero_distance_mode, m_d, an, bn, ! m_whole_edges && output ? &output->second () : 0);
+ in1 = square_near_part_of_edge (m_zero_distance_mode, m_d, bn, an, ! m_whole_edges && output ? &output->first () : 0);
} else {
- in2 = projected_near_part_of_edge (m_include_zero, m_d, an, bn, ! m_whole_edges && output ? &output->second () : 0);
- in1 = projected_near_part_of_edge (m_include_zero, m_d, bn, an, ! m_whole_edges && output ? &output->first () : 0);
+ in2 = projected_near_part_of_edge (m_zero_distance_mode, m_d, an, bn, ! m_whole_edges && output ? &output->second () : 0);
+ in1 = projected_near_part_of_edge (m_zero_distance_mode, m_d, bn, an, ! m_whole_edges && output ? &output->first () : 0);
}
if (in1 && in2) {
diff --git a/src/db/db/dbEdgePairRelations.h b/src/db/db/dbEdgePairRelations.h
index 99b5aec6c..8345b26b1 100644
--- a/src/db/db/dbEdgePairRelations.h
+++ b/src/db/db/dbEdgePairRelations.h
@@ -98,6 +98,111 @@ enum edge_relation_type
InsideRelation = 4
};
+/**
+ * @brief An enum specifying whether how edges with zero distance are handled in checks
+ */
+enum zero_distance_mode {
+
+ /**
+ * @brief Never include zero-distance edges
+ */
+ NeverIncludeZeroDistance = 0,
+
+ /**
+ * @brief Include zero-distance edges when they share at least one common point
+ */
+ IncludeZeroDistanceWhenTouching = 1,
+
+ /**
+ * @brief Include zero-distance edges when they share at least one common point and are collinear
+ */
+ IncludeZeroDistanceWhenCollinearAndTouching = 2,
+
+ /**
+ * @brief Include zero-distance edges when they share more than a single common point (this implies that they are collinear)
+ */
+ IncludeZeroDistanceWhenOverlapping = 3,
+
+ /**
+ * @brief Always include zero-distance edges (hardly useful)
+ */
+ AlwaysIncludeZeroDistance = 4
+};
+
+/**
+ * @brief A structure holding the options for the region checks (space, width, ...)
+ */
+struct DB_PUBLIC EdgesCheckOptions
+{
+ typedef db::coord_traits::distance_type distance_type;
+
+ /**
+ * @brief Constructor
+ */
+ EdgesCheckOptions (bool _whole_edges = false,
+ metrics_type _metrics = db::Euclidian,
+ double _ignore_angle = 90,
+ distance_type _min_projection = 0,
+ distance_type _max_projection = std::numeric_limits::max (),
+ zero_distance_mode _zd_mode = IncludeZeroDistanceWhenTouching)
+ : whole_edges (_whole_edges),
+ metrics (_metrics),
+ ignore_angle (_ignore_angle),
+ min_projection (_min_projection),
+ max_projection (_max_projection),
+ zd_mode (_zd_mode)
+ { }
+
+ /**
+ * @brief Specifies is whole edges are to be delivered
+ *
+ * Without "whole_edges", the parts of
+ * the edges are returned which violate the condition. If "whole_edges" is true, the
+ * result will contain the complete edges participating in the result.
+ */
+ bool whole_edges;
+
+ /**
+ * @brief Measurement metrics
+ *
+ * The metrics parameter specifies which metrics to use. "Euclidian", "Square" and "Projected"
+ * metrics are available.
+ */
+ metrics_type metrics;
+
+ /**
+ * @brief Specifies the obtuse angle threshold
+ *
+ * "ignore_angle" allows specification of a maximum angle that connected edges can have to not participate
+ * in the check. By choosing 90 degree, edges with angles of 90 degree and larger are not checked,
+ * but acute corners are for example.
+ */
+ double ignore_angle;
+
+ /**
+ * @brief Specifies the projection limit's minimum value
+ *
+ * With min_projection and max_projection it is possible to specify how edges must be related
+ * to each other. If the length of the projection of either edge on the other is >= min_projection
+ * or < max_projection, the edges are considered for the check.
+ */
+ distance_type min_projection;
+
+ /**
+ * @brief Specifies the projection limit's maximum value
+ */
+ distance_type max_projection;
+
+ /**
+ * @brief Specifies zero-distance edge handling
+ *
+ * This allows implementing the "kissing corners" case. When set to "IncludeZeroDistanceWhenTouching", kissing corners will
+ * be reported as errors, when set to "NeverIncludeZeroDistance", they won't. Note that with merged inputs, edges
+ * will not overlap except at the corners.
+ */
+ zero_distance_mode zd_mode;
+};
+
/**
* @brief A filter based on the edge pair relation
*
@@ -123,9 +228,14 @@ struct DB_PUBLIC EdgeRelationFilter
* to each other. If the length of the projection of either edge on the other is >= min_projection
* or < max_projection, the edges are considered for the check.
*/
- EdgeRelationFilter (edge_relation_type r, distance_type d, metrics_type metrics = db::Euclidian, double ignore_angle = 90, distance_type min_projection = 0, distance_type max_projection = std::numeric_limits::max ());
+ EdgeRelationFilter (edge_relation_type r, distance_type d, metrics_type metrics = db::Euclidian, double ignore_angle = 90, distance_type min_projection = 0, distance_type max_projection = std::numeric_limits::max (), zero_distance_mode include_zero = AlwaysIncludeZeroDistance);
- /**
+ /**
+ * Constructs an edge relation filter from a CheckOptions structure
+ */
+ EdgeRelationFilter (edge_relation_type r, distance_type d, const EdgesCheckOptions &options);
+
+ /**
* @brief Tests whether two edges fulfil the check fail criterion
*
* If the output pointer is non-null, the object will receive the edge pair that
@@ -150,19 +260,19 @@ struct DB_PUBLIC EdgeRelationFilter
}
/**
- * @brief Sets a flag indicating whether zero distance shall be included in the check
+ * @brief Sets a value indicating whether zero-distance edges shall be included in the check
*/
- void set_include_zero (bool f)
+ void set_zero_distance_mode (zero_distance_mode f)
{
- m_include_zero = f;
+ m_zero_distance_mode = f;
}
/**
- * @brief Gets a flag indicating whether zero distance shall be included in the check
+ * @brief Gets a value indicating whether zero-distance edges shall be included in the check
*/
- bool include_zero () const
+ zero_distance_mode get_zero_distance_mode () const
{
- return m_include_zero;
+ return m_zero_distance_mode;
}
/**
@@ -262,7 +372,7 @@ struct DB_PUBLIC EdgeRelationFilter
private:
bool m_whole_edges;
- bool m_include_zero;
+ zero_distance_mode m_zero_distance_mode;
edge_relation_type m_r;
distance_type m_d;
metrics_type m_metrics;
@@ -273,9 +383,9 @@ private:
// Internal methods exposed for testing purposes
-DB_PUBLIC bool projected_near_part_of_edge (bool include_zero, db::coord_traits::distance_type d, const db::Edge &e, const db::Edge &g, db::Edge *output);
-DB_PUBLIC bool square_near_part_of_edge (bool include_zero, db::coord_traits::distance_type d, const db::Edge &e, const db::Edge &g, db::Edge *output);
-DB_PUBLIC bool euclidian_near_part_of_edge (bool include_zero, db::coord_traits::distance_type d, const db::Edge &e, const db::Edge &g, db::Edge *output);
+DB_PUBLIC bool projected_near_part_of_edge (zero_distance_mode include_zero, db::coord_traits::distance_type d, const db::Edge &e, const db::Edge &g, db::Edge *output);
+DB_PUBLIC bool square_near_part_of_edge (zero_distance_mode include_zero, db::coord_traits::distance_type d, const db::Edge &e, const db::Edge &g, db::Edge *output);
+DB_PUBLIC bool euclidian_near_part_of_edge (zero_distance_mode include_zero, db::coord_traits::distance_type d, const db::Edge &e, const db::Edge &g, db::Edge *output);
DB_PUBLIC db::Edge::distance_type edge_projection (const db::Edge &a, const db::Edge &b);
}
diff --git a/src/db/db/dbEdgesDelegate.h b/src/db/db/dbEdgesDelegate.h
index 919ba5b8a..051d671ee 100644
--- a/src/db/db/dbEdgesDelegate.h
+++ b/src/db/db/dbEdgesDelegate.h
@@ -39,69 +39,6 @@
namespace db {
-/**
- * @brief A structure holding the options for the region checks (space, width, ...)
- */
-struct DB_PUBLIC EdgesCheckOptions
-{
- typedef db::coord_traits::distance_type distance_type;
-
- /**
- * @brief Constructor
- */
- EdgesCheckOptions (bool _whole_edges = false,
- metrics_type _metrics = db::Euclidian,
- double _ignore_angle = 90,
- distance_type _min_projection = 0,
- distance_type _max_projection = std::numeric_limits::max ())
- : whole_edges (_whole_edges),
- metrics (_metrics),
- ignore_angle (_ignore_angle),
- min_projection (_min_projection),
- max_projection (_max_projection)
- { }
-
- /**
- * @brief Specifies is whole edges are to be delivered
- *
- * Without "whole_edges", the parts of
- * the edges are returned which violate the condition. If "whole_edges" is true, the
- * result will contain the complete edges participating in the result.
- */
- bool whole_edges;
-
- /**
- * @brief Measurement metrics
- *
- * The metrics parameter specifies which metrics to use. "Euclidian", "Square" and "Projected"
- * metrics are available.
- */
- metrics_type metrics;
-
- /**
- * @brief Specifies the obtuse angle threshold
- *
- * "ignore_angle" allows specification of a maximum angle that connected edges can have to not participate
- * in the check. By choosing 90 degree, edges with angles of 90 degree and larger are not checked,
- * but acute corners are for example.
- */
- double ignore_angle;
-
- /**
- * @brief Specifies the projection limit's minimum value
- *
- * With min_projection and max_projection it is possible to specify how edges must be related
- * to each other. If the length of the projection of either edge on the other is >= min_projection
- * or < max_projection, the edges are considered for the check.
- */
- distance_type min_projection;
-
- /**
- * @brief Specifies the projection limit's maximum value
- */
- distance_type max_projection;
-};
-
/**
* @brief A base class for edge filters
*/
diff --git a/src/db/db/dbLayout.cc b/src/db/db/dbLayout.cc
index 8ab1e8717..4e29d27ef 100644
--- a/src/db/db/dbLayout.cc
+++ b/src/db/db/dbLayout.cc
@@ -257,6 +257,83 @@ private:
bool m_insert;
};
+struct SetLayoutMetaInfoOp
+ : public LayoutOp
+{
+ SetLayoutMetaInfoOp (db::Layout::meta_info_name_id_type name_id, const db::MetaInfo *f, const db::MetaInfo *t)
+ : m_name_id (name_id), m_has_from (f != 0), m_has_to (t != 0)
+ {
+ if (f) {
+ m_from = *f;
+ }
+ if (t) {
+ m_to = *t;
+ }
+ }
+
+ virtual void redo (db::Layout *layout) const
+ {
+ if (! m_has_to) {
+ layout->remove_meta_info (m_name_id);
+ } else {
+ layout->add_meta_info (m_name_id, m_to);
+ }
+ }
+
+ virtual void undo (db::Layout *layout) const
+ {
+ if (! m_has_from) {
+ layout->remove_meta_info (m_name_id);
+ } else {
+ layout->add_meta_info (m_name_id, m_from);
+ }
+ }
+
+private:
+ db::Layout::meta_info_name_id_type m_name_id;
+ bool m_has_from, m_has_to;
+ db::MetaInfo m_from, m_to;
+};
+
+struct SetCellMetaInfoOp
+ : public LayoutOp
+{
+ SetCellMetaInfoOp (db::cell_index_type ci, db::Layout::meta_info_name_id_type name_id, const db::MetaInfo *f, const db::MetaInfo *t)
+ : m_ci (ci), m_name_id (name_id), m_has_from (f != 0), m_has_to (t != 0)
+ {
+ if (f) {
+ m_from = *f;
+ }
+ if (t) {
+ m_to = *t;
+ }
+ }
+
+ virtual void redo (db::Layout *layout) const
+ {
+ if (! m_has_to) {
+ layout->remove_meta_info (m_ci, m_name_id);
+ } else {
+ layout->add_meta_info (m_ci, m_name_id, m_to);
+ }
+ }
+
+ virtual void undo (db::Layout *layout) const
+ {
+ if (! m_has_from) {
+ layout->remove_meta_info (m_ci, m_name_id);
+ } else {
+ layout->add_meta_info (m_ci, m_name_id, m_from);
+ }
+ }
+
+private:
+ db::cell_index_type m_ci;
+ db::Layout::meta_info_name_id_type m_name_id;
+ bool m_has_from, m_has_to;
+ db::MetaInfo m_from, m_to;
+};
+
// -----------------------------------------------------------------
// Implementation of the ProxyContextInfo class
@@ -848,6 +925,9 @@ Layout::delete_cells (const std::set &cells_to_delete)
// cell child objects that must remain.
for (std::set::const_iterator c = cells_to_delete.begin (); c != cells_to_delete.end (); ++c) {
+ // supports undo
+ clear_meta (*c);
+
if (manager () && manager ()->transacting ()) {
// note the "take" method - this takes out the cell
@@ -917,9 +997,12 @@ Layout::delete_cell (cell_index_type id)
// a backup container for the cell. This is necessary since the ID's within manager are given to
// cell child objects that must remain.
+ // supports undo
+ clear_meta (id);
+
if (manager () && manager ()->transacting ()) {
- // not the "take" method - this takes out the cell
+ // note the "take" method - this takes out the cell
std::string cn (cell_name (id));
manager ()->queue (this, new NewRemoveCellOp (id, cn, true /*remove*/, take_cell (id)));
@@ -1869,18 +1952,36 @@ Layout::meta_info_name_id (const std::string &name) const
void
Layout::clear_meta ()
{
+ if (manager () && manager ()->transacting ()) {
+ for (auto i = m_meta_info.begin (); i != m_meta_info.end (); ++i) {
+ manager ()->queue (this, new SetLayoutMetaInfoOp (i->first, &i->second, 0));
+ }
+ }
+
m_meta_info.clear ();
}
void
Layout::add_meta_info (meta_info_name_id_type name_id, const MetaInfo &i)
{
+ if (manager () && manager ()->transacting ()) {
+ auto e = m_meta_info.find (name_id);
+ manager ()->queue (this, new SetLayoutMetaInfoOp (name_id, e != m_meta_info.end () ? &e->second : 0, &i));
+ }
+
m_meta_info[name_id] = i;
}
void
Layout::remove_meta_info (meta_info_name_id_type name_id)
{
+ if (manager () && manager ()->transacting ()) {
+ auto e = m_meta_info.find (name_id);
+ if (e != m_meta_info.end ()) {
+ manager ()->queue (this, new SetLayoutMetaInfoOp (name_id, &e->second, 0));
+ }
+ }
+
m_meta_info.erase (name_id);
}
@@ -1901,12 +2002,41 @@ Layout::has_meta_info (meta_info_name_id_type name_id) const
void
Layout::clear_meta (db::cell_index_type ci)
{
+ if (manager () && manager ()->transacting ()) {
+ auto ib = begin_meta (ci);
+ auto ie = end_meta (ci);
+ for (auto i = ib; i != ie; ++i) {
+ manager ()->queue (this, new SetCellMetaInfoOp (ci, i->first, &i->second, 0));
+ }
+ }
+
m_meta_info_by_cell.erase (ci);
}
+void
+Layout::clear_all_meta ()
+{
+ clear_meta ();
+ while (! m_meta_info_by_cell.empty ()) {
+ clear_meta (m_meta_info_by_cell.begin ()->first);
+ }
+}
+
void
Layout::add_meta_info (db::cell_index_type ci, meta_info_name_id_type name_id, const MetaInfo &i)
{
+ if (manager () && manager ()->transacting ()) {
+ const MetaInfo *from = 0;
+ auto c = m_meta_info_by_cell.find (ci);
+ if (c != m_meta_info_by_cell.end ()) {
+ auto e = c->second.find (name_id);
+ if (e != c->second.end ()) {
+ from = &e->second;
+ }
+ }
+ manager ()->queue (this, new SetCellMetaInfoOp (ci, name_id, from, &i));
+ }
+
m_meta_info_by_cell[ci][name_id] = i;
}
@@ -1914,6 +2044,18 @@ void
Layout::remove_meta_info (db::cell_index_type ci, meta_info_name_id_type name_id)
{
auto c = m_meta_info_by_cell.find (ci);
+
+ if (manager () && manager ()->transacting ()) {
+ const MetaInfo *from = 0;
+ if (c != m_meta_info_by_cell.end ()) {
+ auto e = c->second.find (name_id);
+ if (e != c->second.end ()) {
+ from = &e->second;
+ }
+ }
+ manager ()->queue (this, new SetCellMetaInfoOp (ci, name_id, from, 0));
+ }
+
if (c != m_meta_info_by_cell.end ()) {
c->second.erase (name_id);
}
@@ -1945,6 +2087,40 @@ Layout::has_meta_info (db::cell_index_type ci, meta_info_name_id_type name_id) c
}
}
+void
+Layout::merge_meta_info (const db::Layout &other)
+{
+ for (auto mi = other.begin_meta (); mi != other.end_meta (); ++mi) {
+ add_meta_info (other.meta_info_name (mi->first), mi->second);
+ }
+}
+
+void
+Layout::merge_meta_info (db::cell_index_type into_cell, const db::Layout &other, db::cell_index_type other_cell)
+{
+ auto mi_begin = other.begin_meta (other_cell);
+ auto mi_end = other.end_meta (other_cell);
+ for (auto mi = mi_begin; mi != mi_end; ++mi) {
+ add_meta_info (into_cell, other.meta_info_name (mi->first), mi->second);
+ }
+}
+
+void
+Layout::merge_meta_info (const db::Layout &other, const db::CellMapping &cm)
+{
+ for (auto i = cm.begin (); i != cm.end (); ++i) {
+ merge_meta_info (i->second, other, i->first);
+ }
+}
+
+void
+Layout::copy_meta_info (const db::Layout &other, const db::CellMapping &cm)
+{
+ for (auto i = cm.begin (); i != cm.end (); ++i) {
+ copy_meta_info (i->second, other, i->first);
+ }
+}
+
void
Layout::swap_layers (unsigned int a, unsigned int b)
{
diff --git a/src/db/db/dbLayout.h b/src/db/db/dbLayout.h
index 7d2598da6..59a4ad19f 100644
--- a/src/db/db/dbLayout.h
+++ b/src/db/db/dbLayout.h
@@ -1993,6 +1993,11 @@ public:
*/
void clear_meta (db::cell_index_type ci);
+ /**
+ * @brief Clears all meta information (cells and layout)
+ */
+ void clear_all_meta ();
+
/**
* @brief Adds meta information for a given cell
* The given meta information object is to the meta information list for the given cell.
@@ -2021,6 +2026,50 @@ public:
}
}
+ /**
+ * @brief Merges meta information from the other layout into self
+ * This applies to the layout-only meta information. Same keys get overwritten, new ones are added.
+ */
+ void merge_meta_info (const db::Layout &other);
+
+ /**
+ * @brief Copies meta information from the other layout into self
+ * This applies to the layout-only meta information. All keys are replaced.
+ */
+ void copy_meta_info (const db::Layout &other)
+ {
+ clear_meta ();
+ merge_meta_info (other);
+ }
+
+ /**
+ * @brief Merges meta information from the other cell into the target cell from sel.
+ * This applies to the cell-specific meta information. Same keys get overwritten, new ones are added.
+ */
+ void merge_meta_info (db::cell_index_type into_cell, const db::Layout &other, db::cell_index_type other_cell);
+
+ /**
+ * @brief Copies meta information from the other cell into the target cell from sel.
+ * This applies to the cell-specific meta information. All keys are replaced.
+ */
+ void copy_meta_info (db::cell_index_type into_cell, const db::Layout &other, db::cell_index_type other_cell)
+ {
+ clear_meta (into_cell);
+ merge_meta_info (into_cell, other, other_cell);
+ }
+
+ /**
+ * @brief Merges meta information from the other cell into the target cell from sel using the given cell mapping.
+ * The cell mapping specifies which meta information to merge from which cell into which cell.
+ */
+ void merge_meta_info (const db::Layout &other, const db::CellMapping &cm);
+
+ /**
+ * @brief Copies meta information from the other cell into the target cell from sel using the given cell mapping.
+ * The cell mapping specifies which meta information to copy from which cell into which cell.
+ */
+ void copy_meta_info (const db::Layout &other, const db::CellMapping &cm);
+
/**
* @brief Gets a value indicating whether a meta info with the given name is present for the given cell
*/
diff --git a/src/db/db/dbLayoutDiff.cc b/src/db/db/dbLayoutDiff.cc
index bc35d4c62..b52e71b02 100644
--- a/src/db/db/dbLayoutDiff.cc
+++ b/src/db/db/dbLayoutDiff.cc
@@ -702,6 +702,29 @@ do_compare_layouts (const db::Layout &a, const db::Cell *top_a, const db::Layout
r.dbu_differs (a.dbu (), b.dbu ());
}
+ if ((flags & layout_diff::f_with_meta) != 0) {
+ std::map > mi;
+ for (auto i = a.begin_meta (); i != a.end_meta (); ++i) {
+ if (i->second.persisted) {
+ mi [a.meta_info_name (i->first)].first = i->second.value;
+ }
+ }
+ for (auto i = b.begin_meta (); i != b.end_meta (); ++i) {
+ if (i->second.persisted) {
+ mi [b.meta_info_name (i->first)].second = i->second.value;
+ }
+ }
+ for (auto i = mi.begin (); i != mi.end (); ++i) {
+ if (i->second.first != i->second.second) {
+ differs = true;
+ if (flags & layout_diff::f_silent) {
+ return false;
+ }
+ r.layout_meta_info_differs (i->first, i->second.first, i->second.second);
+ }
+ }
+ }
+
bool verbose = (flags & layout_diff::f_verbose);
bool no_duplicates = (flags & layout_diff::f_ignore_duplicates);
@@ -928,6 +951,33 @@ do_compare_layouts (const db::Layout &a, const db::Cell *top_a, const db::Layout
r.begin_cell (common_cells [cci], common_cells_a [cci], common_cells_b [cci]);
+ if ((flags & layout_diff::f_with_meta) != 0) {
+ std::map > mi;
+ auto ib = a.begin_meta (common_cells_a [cci]);
+ auto ie = a.end_meta (common_cells_a [cci]);
+ for (auto i = ib; i != ie; ++i) {
+ if (i->second.persisted) {
+ mi [a.meta_info_name (i->first)].first = i->second.value;
+ }
+ }
+ ib = b.begin_meta (common_cells_b [cci]);
+ ie = b.end_meta (common_cells_b [cci]);
+ for (auto i = ib; i != ie; ++i) {
+ if (i->second.persisted) {
+ mi [b.meta_info_name (i->first)].second = i->second.value;
+ }
+ }
+ for (auto i = mi.begin (); i != mi.end (); ++i) {
+ if (i->second.first != i->second.second) {
+ differs = true;
+ if (flags & layout_diff::f_silent) {
+ return false;
+ }
+ r.cell_meta_info_differs (i->first, i->second.first, i->second.second);
+ }
+ }
+ }
+
if (!verbose && cell_a->bbox () != cell_b->bbox ()) {
differs = true;
if (flags & layout_diff::f_silent) {
@@ -1215,6 +1265,7 @@ public:
}
void dbu_differs (double dbu_a, double dbu_b);
+ void layout_meta_info_differs (const std::string &name, const tl::Variant &a, const tl::Variant &b);
void layer_in_a_only (const db::LayerProperties &la);
void layer_in_b_only (const db::LayerProperties &lb);
void layer_name_differs (const db::LayerProperties &la, const db::LayerProperties &lb);
@@ -1222,6 +1273,7 @@ public:
void cell_in_b_only (const std::string &cellname, db::cell_index_type ci);
void cell_name_differs (const std::string &cellname_a, db::cell_index_type cia, const std::string &cellname_b, db::cell_index_type cib);
void begin_cell (const std::string &cellname, db::cell_index_type cia, db::cell_index_type cib);
+ void cell_meta_info_differs (const std::string &name, const tl::Variant &a, const tl::Variant &b);
void bbox_differs (const db::Box &ba, const db::Box &bb);
void begin_inst_differences ();
void instances_in_a (const std::vector &insts_a, const std::vector &cell_names, const db::PropertiesRepository &props);
@@ -1384,6 +1436,16 @@ PrintingDifferenceReceiver::dbu_differs (double dbu_a, double dbu_b)
}
}
+void
+PrintingDifferenceReceiver::layout_meta_info_differs (const std::string &name, const tl::Variant &a, const tl::Variant &b)
+{
+ try {
+ enough (tl::error) << "Global meta info differs - [" << name << "]: " << a << " vs. " << b;
+ } catch (tl::CancelException &) {
+ // ignore cancel exceptions
+ }
+}
+
void
PrintingDifferenceReceiver::layer_in_a_only (const db::LayerProperties &la)
{
@@ -1461,6 +1523,16 @@ PrintingDifferenceReceiver::begin_cell (const std::string &cellname, db::cell_in
m_cellname = cellname;
}
+void
+PrintingDifferenceReceiver::cell_meta_info_differs (const std::string &name, const tl::Variant &a, const tl::Variant &b)
+{
+ try {
+ enough (tl::error) << "Meta info differs in cell " << m_cellname << " - [" << name << "]: " << a << " vs. " << b;
+ } catch (tl::CancelException &) {
+ // ignore cancel exceptions
+ }
+}
+
void
PrintingDifferenceReceiver::begin_inst_differences ()
{
diff --git a/src/db/db/dbLayoutDiff.h b/src/db/db/dbLayoutDiff.h
index ce39f5988..223ddd4f4 100644
--- a/src/db/db/dbLayoutDiff.h
+++ b/src/db/db/dbLayoutDiff.h
@@ -56,6 +56,9 @@ const unsigned int f_no_text_orientation = 0x02;
// Ignore properties
const unsigned int f_no_properties = 0x04;
+// With meta info
+const unsigned int f_with_meta = 0x08;
+
// Do not compare layer names
const unsigned int f_no_layer_names = 0x10;
@@ -94,6 +97,7 @@ public:
virtual ~DifferenceReceiver () { }
virtual void dbu_differs (double /*dbu_a*/, double /*dbu_b*/) { }
+ virtual void layout_meta_info_differs (const std::string & /*name*/, const tl::Variant & /*value_a*/, const tl::Variant & /*value_b*/) { }
virtual void layer_in_a_only (const db::LayerProperties & /*la*/) { }
virtual void layer_in_b_only (const db::LayerProperties & /*lb*/) { }
virtual void layer_name_differs (const db::LayerProperties & /*la*/, const db::LayerProperties & /*lb*/) { }
@@ -102,6 +106,7 @@ public:
virtual void cell_in_b_only (const std::string & /*cellname*/, db::cell_index_type /*ci*/) { }
virtual void bbox_differs (const db::Box & /*ba*/, const db::Box & /*bb*/) { }
virtual void begin_cell (const std::string & /*cellname*/, db::cell_index_type /*cia*/, db::cell_index_type /*cib*/) { }
+ virtual void cell_meta_info_differs (const std::string & /*name*/, const tl::Variant & /*value_a*/, const tl::Variant & /*value_b*/) { }
virtual void begin_inst_differences () { }
virtual void instances_in_a (const std::vector & /*insts_a*/, const std::vector & /*cell_names*/, const db::PropertiesRepository & /*props*/) { }
virtual void instances_in_b (const std::vector & /*insts_b*/, const std::vector & /*cell_names*/, const db::PropertiesRepository & /*props*/) { }
diff --git a/src/db/db/dbLayoutUtils.cc b/src/db/db/dbLayoutUtils.cc
index 1c4a7e0d1..2fe5174fb 100644
--- a/src/db/db/dbLayoutUtils.cc
+++ b/src/db/db/dbLayoutUtils.cc
@@ -252,6 +252,9 @@ merge_layouts (db::Layout &target,
const db::Cell &source_cell = source.cell (*c);
db::Cell &target_cell = target.cell (target_cell_index);
+ // merge meta info
+ target.merge_meta_info (target_cell_index, source, *c);
+
// NOTE: this implementation employs the safe but cumbersome "local transformation" feature.
// This means, all cells are transformed according to the given transformation and their
// references are transformed to account for that effect. This will lead to somewhat strange
diff --git a/src/db/db/dbNetlistDeviceExtractor.cc b/src/db/db/dbNetlistDeviceExtractor.cc
index 6e4bc6ae2..00cbe62a5 100644
--- a/src/db/db/dbNetlistDeviceExtractor.cc
+++ b/src/db/db/dbNetlistDeviceExtractor.cc
@@ -287,19 +287,37 @@ void NetlistDeviceExtractor::extract_without_initialize (db::Layout &layout, db:
extractor_cache_type::const_iterator ec = extractor_cache.find (layer_geometry);
if (ec == extractor_cache.end ()) {
+ log_entry_list log_entries;
+ m_log_entries.swap (log_entries);
+
// do the actual device extraction
extract_devices (layer_geometry);
// push the new devices to the layout
push_new_devices (disp);
- ExtractorCacheValueType &ecv = extractor_cache [layer_geometry];
- ecv.disp = disp;
+ if (m_log_entries.empty ()) {
+
+ // cache unless log entries are produced
+ ExtractorCacheValueType &ecv = extractor_cache [layer_geometry];
+ ecv.disp = disp;
+
+ for (std::map >::const_iterator d = m_new_devices.begin (); d != m_new_devices.end (); ++d) {
+ ecv.devices.push_back (d->second.first);
+ }
+
+ } else {
+
+ // transform the marker geometries from the log entries to match the device
+ db::DVector disp_dbu = db::CplxTrans (dbu ()) * disp;
+ for (auto l = m_log_entries.begin (); l != m_log_entries.end (); ++l) {
+ l->set_geometry (l->geometry ().moved (disp_dbu));
+ }
- for (std::map >::const_iterator d = m_new_devices.begin (); d != m_new_devices.end (); ++d) {
- ecv.devices.push_back (d->second.first);
}
+ m_log_entries.splice (m_log_entries.begin (), log_entries);
+
m_new_devices.clear ();
} else {
diff --git a/src/db/db/dbRegionLocalOperations.h b/src/db/db/dbRegionLocalOperations.h
index 90e91053e..27b09b187 100644
--- a/src/db/db/dbRegionLocalOperations.h
+++ b/src/db/db/dbRegionLocalOperations.h
@@ -113,6 +113,7 @@ enum OppositeFilter
* @brief A structure holding the options for the region checks (space, width, ...)
*/
struct DB_PUBLIC RegionCheckOptions
+ : public EdgesCheckOptions
{
typedef db::coord_traits::distance_type distance_type;
@@ -128,12 +129,9 @@ struct DB_PUBLIC RegionCheckOptions
OppositeFilter _opposite_filter = NoOppositeFilter,
RectFilter _rect_filter = NoRectFilter,
bool _negative = false,
- PropertyConstraint _prop_constraint = IgnoreProperties)
- : whole_edges (_whole_edges),
- metrics (_metrics),
- ignore_angle (_ignore_angle),
- min_projection (_min_projection),
- max_projection (_max_projection),
+ PropertyConstraint _prop_constraint = IgnoreProperties,
+ zero_distance_mode _zd_mode = IncludeZeroDistanceWhenTouching)
+ : EdgesCheckOptions (_whole_edges, _metrics, _ignore_angle, _min_projection, _max_projection, _zd_mode),
shielded (_shielded),
opposite_filter (_opposite_filter),
rect_filter (_rect_filter),
@@ -141,46 +139,6 @@ struct DB_PUBLIC RegionCheckOptions
prop_constraint (_prop_constraint)
{ }
- /**
- * @brief Specifies is whole edges are to be delivered
- *
- * Without "whole_edges", the parts of
- * the edges are returned which violate the condition. If "whole_edges" is true, the
- * result will contain the complete edges participating in the result.
- */
- bool whole_edges;
-
- /**
- * @brief Measurement metrics
- *
- * The metrics parameter specifies which metrics to use. "Euclidian", "Square" and "Projected"
- * metrics are available.
- */
- metrics_type metrics;
-
- /**
- * @brief Specifies the obtuse angle threshold
- *
- * "ignore_angle" allows specification of a maximum angle that connected edges can have to not participate
- * in the check. By choosing 90 degree, edges with angles of 90 degree and larger are not checked,
- * but acute corners are for example.
- */
- double ignore_angle;
-
- /**
- * @brief Specifies the projection limit's minimum value
- *
- * With min_projection and max_projection it is possible to specify how edges must be related
- * to each other. If the length of the projection of either edge on the other is >= min_projection
- * or < max_projection, the edges are considered for the check.
- */
- distance_type min_projection;
-
- /**
- * @brief Specifies the projection limit's maximum value
- */
- distance_type max_projection;
-
/**
* @brief Specifies shielding
*
diff --git a/src/db/db/dbRegionUtils.cc b/src/db/db/dbRegionUtils.cc
index 5084c0332..15b7b8bc7 100644
--- a/src/db/db/dbRegionUtils.cc
+++ b/src/db/db/dbRegionUtils.cc
@@ -359,12 +359,7 @@ SinglePolygonCheck::process (const db::Polygon &polygon, std::vector result;
- EdgeRelationFilter check (m_relation, m_d, m_options.metrics);
- check.set_include_zero (false);
- check.set_whole_edges (m_options.whole_edges);
- check.set_ignore_angle (m_options.ignore_angle);
- check.set_min_projection (m_options.min_projection);
- check.set_max_projection (m_options.max_projection);
+ EdgeRelationFilter check (m_relation, m_d, m_options);
edge2edge_check_negative_or_positive > edge_check (check, result, m_options.negative, false /*=same polygons*/, false /*=same layers*/, m_options.shielded, true /*=symmetric*/);
poly2poly_check poly_check (edge_check);
diff --git a/src/db/db/dbTestSupport.cc b/src/db/db/dbTestSupport.cc
index c93757909..871e66396 100644
--- a/src/db/db/dbTestSupport.cc
+++ b/src/db/db/dbTestSupport.cc
@@ -139,6 +139,7 @@ void compare_layouts (tl::TestBase *_this, const db::Layout &layout, const std::
(n > 0 ? db::layout_diff::f_silent : db::layout_diff::f_verbose)
| ((norm & AsPolygons) != 0 ? db::layout_diff::f_boxes_as_polygons + db::layout_diff::f_paths_as_polygons : 0)
| ((norm & WithArrays) != 0 ? 0 : db::layout_diff::f_flatten_array_insts)
+ | ((norm & WithMeta) == 0 ? 0 : db::layout_diff::f_with_meta)
/*| db::layout_diff::f_no_text_details | db::layout_diff::f_no_text_orientation*/
, tolerance, 100 /*max diff lines*/);
if (equal && n > 0) {
diff --git a/src/db/db/dbTestSupport.h b/src/db/db/dbTestSupport.h
index 4963b2ec4..5369a6e90 100644
--- a/src/db/db/dbTestSupport.h
+++ b/src/db/db/dbTestSupport.h
@@ -58,7 +58,8 @@ enum NormalizationMode
NormFileMask = 7, // bits the extract for file mode
NoContext = 8, // write tmp file without context
AsPolygons = 16, // paths and boxes are treated as polygons
- WithArrays = 32 // do not flatten arrays
+ WithArrays = 32, // do not flatten arrays
+ WithMeta = 64 // with meta info
};
/**
diff --git a/src/db/db/gsiDeclDbCell.cc b/src/db/db/gsiDeclDbCell.cc
index 4a65a4a91..fc32fa381 100644
--- a/src/db/db/gsiDeclDbCell.cc
+++ b/src/db/db/gsiDeclDbCell.cc
@@ -1004,6 +1004,22 @@ static void cell_add_meta_info (db::Cell *cell, const MetaInfo &mi)
}
}
+static void cell_merge_meta_info (db::Cell *cell, const db::Cell *source)
+{
+ if (! source || ! cell->layout () || ! source->layout ()) {
+ return;
+ }
+ cell->layout ()->merge_meta_info (cell->cell_index (), *source->layout (), source->cell_index ());
+}
+
+static void cell_copy_meta_info (db::Cell *cell, const db::Cell *source)
+{
+ if (! source || ! cell->layout () || ! source->layout ()) {
+ return;
+ }
+ cell->layout ()->copy_meta_info (cell->cell_index (), *source->layout (), source->cell_index ());
+}
+
static const tl::Variant &cell_meta_info_value (db::Cell *cell, const std::string &name)
{
if (! cell->layout ()) {
@@ -1755,6 +1771,7 @@ read_options (db::Cell *cell, const std::string &path, const db::LoadLayoutOptio
db::CellMapping cm;
std::vector new_cells = cm.create_single_mapping_full (*cell->layout (), cell->cell_index (), tmp, *tmp.begin_top_down ());
cell->move_tree_shapes (tmp.cell (*tmp.begin_top_down ()), cm);
+ cell->layout ()->merge_meta_info (tmp, cm);
return new_cells;
}
@@ -1834,6 +1851,21 @@ Class decl_Cell ("db", "Cell",
"\n"
"This method has been introduced in version 0.28.8."
) +
+ gsi::method_ext ("merge_meta_info", &cell_merge_meta_info, gsi::arg ("other"),
+ "@brief Merges the meta information from the other cell into this cell\n"
+ "See \\LayoutMetaInfo for details about cells and meta information.\n"
+ "Existing keys in this cell will be overwritten by the respective values from the other cell.\n"
+ "New keys will be added.\n"
+ "\n"
+ "This method has been introduced in version 0.28.16."
+ ) +
+ gsi::method_ext ("copy_meta_info", &cell_copy_meta_info, gsi::arg ("other"),
+ "@brief Copies the meta information from the other cell into this cell\n"
+ "See \\LayoutMetaInfo for details about cells and meta information.\n"
+ "The meta information from this cell will be replaced by the meta information from the other cell.\n"
+ "\n"
+ "This method has been introduced in version 0.28.16."
+ ) +
gsi::method_ext ("clear_meta_info", &cell_clear_meta_info,
"@brief Clears the meta information of the cell\n"
"See \\LayoutMetaInfo for details about cells and meta information.\n"
diff --git a/src/db/db/gsiDeclDbCompoundOperation.cc b/src/db/db/gsiDeclDbCompoundOperation.cc
index dd88ca6d2..782151553 100644
--- a/src/db/db/gsiDeclDbCompoundOperation.cc
+++ b/src/db/db/gsiDeclDbCompoundOperation.cc
@@ -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::zero_distance_mode zd_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 (),
- max_projection.is_nil () ? std::numeric_limits::max () : max_projection.to (),
- 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 ();
+ options.max_projection = max_projection.is_nil () ? std::numeric_limits::max () : max_projection.to ();
+ options.shielded = shielded;
+ options.opposite_filter = opposite_filter;
+ options.rect_filter = rect_filter;
+ options.negative = negative;
+ options.zd_mode = zd_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::zero_distance_mode zd_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::max () : max_projection.to (),
shielded);
options.negative = negative;
+ options.zd_mode = zd_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::zero_distance_mode zd_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, zd_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::zero_distance_mode zd_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, zd_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::zero_distance_mode zd_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, zd_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::zero_distance_mode zd_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::max () : max_projection.to (),
shielded);
options.negative = negative;
+ options.zd_mode = zd_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::zero_distance_mode zd_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, zd_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::zero_distance_mode zd_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, zd_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::zero_distance_mode zd_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, zd_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::zero_distance_mode zd_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, zd_mode, negative);
}
static db::CompoundRegionOperationNode *new_perimeter_filter (db::CompoundRegionOperationNode *input, bool inverse, db::coord_traits::perimeter_type pmin, db::coord_traits::perimeter_type pmax)
@@ -660,31 +666,45 @@ Class 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 ("zero_distance_mode", db::IncludeZeroDistanceWhenTouching, "IncludeZeroDistanceWhenTouching"), gsi::arg ("negative", false),
"@brief Creates a node providing a width check.\n"
+ "\n"
+ "The zero_distance_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 ("zero_distance_mode", db::IncludeZeroDistanceWhenTouching, "IncludeZeroDistanceWhenTouching"), gsi::arg ("negative", false),
"@brief Creates a node providing a space check.\n"
+ "\n"
+ "The zero_distance_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 ("zero_distance_mode", db::IncludeZeroDistanceWhenTouching, "IncludeZeroDistanceWhenTouching"), gsi::arg ("negative", false),
"@brief Creates a node providing a isolated polygons (space between different polygons) check.\n"
+ "\n"
+ "The zero_distance_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 ("zero_distance_mode", db::IncludeZeroDistanceWhenTouching, "IncludeZeroDistanceWhenTouching"), gsi::arg ("negative", false),
"@brief Creates a node providing a intra-polygon space check.\n"
+ "\n"
+ "The zero_distance_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 ("zero_distance_mode", db::IncludeZeroDistanceWhenTouching, "IncludeZeroDistanceWhenTouching"), gsi::arg ("negative", false),
"@brief Creates a node providing a separation check.\n"
+ "\n"
+ "The zero_distance_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 ("zero_distance_mode", db::IncludeZeroDistanceWhenTouching, "IncludeZeroDistanceWhenTouching"), gsi::arg ("negative", false),
"@brief Creates a node providing an overlap check.\n"
+ "\n"
+ "The zero_distance_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 ("zero_distance_mode", db::IncludeZeroDistanceWhenTouching, "IncludeZeroDistanceWhenTouching"), gsi::arg ("negative", false),
"@brief Creates a node providing an inside (enclosure) check.\n"
+ "\n"
+ "The zero_distance_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 ("zero_distance_mode", db::IncludeZeroDistanceWhenTouching, "IncludeZeroDistanceWhenTouching"), 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 zero_distance_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::perimeter_type>::max (), "max"),
"@brief Creates a node filtering the input by perimeter.\n"
@@ -803,9 +823,7 @@ Class 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 decl_dbCompoundRegionLogicalBoolOperationNode_LogicalOp ("db", "LogicalOp",
diff --git a/src/db/db/gsiDeclDbEdges.cc b/src/db/db/gsiDeclDbEdges.cc
index 718b6d16b..f74687b1b 100644
--- a/src/db/db/gsiDeclDbEdges.cc
+++ b/src/db/db/gsiDeclDbEdges.cc
@@ -234,63 +234,69 @@ static db::Edges with_angle3 (const db::Edges *r, db::SpecialEdgeOrientationFilt
return r->filtered (f);
}
-static db::EdgePairs width2 (const db::Edges *r, db::Edges::coord_type d, bool whole_edges, db::metrics_type metrics, const tl::Variant &ignore_angle, const tl::Variant &min_projection, const tl::Variant &max_projection)
+static db::EdgePairs width2 (const db::Edges *r, db::Edges::coord_type d, bool whole_edges, db::metrics_type metrics, const tl::Variant &ignore_angle, const tl::Variant &min_projection, const tl::Variant &max_projection, db::zero_distance_mode zd_mode)
{
return r->width_check (d, db::EdgesCheckOptions (whole_edges,
metrics,
ignore_angle.is_nil () ? 90 : ignore_angle.to_double (),
min_projection.is_nil () ? db::Edges::distance_type (0) : min_projection.to (),
- max_projection.is_nil () ? std::numeric_limits::max () : max_projection.to ())
+ max_projection.is_nil () ? std::numeric_limits::max () : max_projection.to (),
+ zd_mode)
);
}
-static db::EdgePairs space2 (const db::Edges *r, db::Edges::coord_type d, bool whole_edges, db::metrics_type metrics, const tl::Variant &ignore_angle, const tl::Variant &min_projection, const tl::Variant &max_projection)
+static db::EdgePairs space2 (const db::Edges *r, db::Edges::coord_type d, bool whole_edges, db::metrics_type metrics, const tl::Variant &ignore_angle, const tl::Variant &min_projection, const tl::Variant &max_projection, db::zero_distance_mode zd_mode)
{
return r->space_check (d, db::EdgesCheckOptions (whole_edges,
metrics,
ignore_angle.is_nil () ? 90 : ignore_angle.to_double (),
min_projection.is_nil () ? db::Edges::distance_type (0) : min_projection.to (),
- max_projection.is_nil () ? std::numeric_limits::max () : max_projection.to ())
+ max_projection.is_nil () ? std::numeric_limits::max () : max_projection.to (),
+ zd_mode)
);
}
-static db::EdgePairs inside2 (const db::Edges *r, const db::Edges &other, db::Edges::coord_type d, bool whole_edges, db::metrics_type metrics, const tl::Variant &ignore_angle, const tl::Variant &min_projection, const tl::Variant &max_projection)
+static db::EdgePairs inside2 (const db::Edges *r, const db::Edges &other, db::Edges::coord_type d, bool whole_edges, db::metrics_type metrics, const tl::Variant &ignore_angle, const tl::Variant &min_projection, const tl::Variant &max_projection, db::zero_distance_mode zd_mode)
{
return r->inside_check (other, d, db::EdgesCheckOptions (whole_edges,
metrics,
ignore_angle.is_nil () ? 90 : ignore_angle.to_double (),
min_projection.is_nil () ? db::Edges::distance_type (0) : min_projection.to (),
- max_projection.is_nil () ? std::numeric_limits::max () : max_projection.to ())
+ max_projection.is_nil () ? std::numeric_limits::max () : max_projection.to (),
+ zd_mode)
);
}
-static db::EdgePairs overlap2 (const db::Edges *r, const db::Edges &other, db::Edges::coord_type d, bool whole_edges, db::metrics_type metrics, const tl::Variant &ignore_angle, const tl::Variant &min_projection, const tl::Variant &max_projection)
+static db::EdgePairs overlap2 (const db::Edges *r, const db::Edges &other, db::Edges::coord_type d, bool whole_edges, db::metrics_type metrics, const tl::Variant &ignore_angle, const tl::Variant &min_projection, const tl::Variant &max_projection, db::zero_distance_mode zd_mode)
{
return r->overlap_check (other, d, db::EdgesCheckOptions (whole_edges,
metrics,
ignore_angle.is_nil () ? 90 : ignore_angle.to_double (),
min_projection.is_nil () ? db::Edges::distance_type (0) : min_projection.to (),
- max_projection.is_nil () ? std::numeric_limits::max () : max_projection.to ())
+ max_projection.is_nil () ? std::numeric_limits::max () : max_projection.to (),
+ zd_mode)
);
}
-static db::EdgePairs enclosing2 (const db::Edges *r, const db::Edges &other, db::Edges::coord_type d, bool whole_edges, db::metrics_type metrics, const tl::Variant &ignore_angle, const tl::Variant &min_projection, const tl::Variant &max_projection)
+static db::EdgePairs enclosing2 (const db::Edges *r, const db::Edges &other, db::Edges::coord_type d, bool whole_edges, db::metrics_type metrics, const tl::Variant &ignore_angle, const tl::Variant &min_projection, const tl::Variant &max_projection, db::zero_distance_mode zd_mode)
{
return r->enclosing_check (other, d, db::EdgesCheckOptions (whole_edges,
metrics,
ignore_angle.is_nil () ? 90 : ignore_angle.to_double (),
min_projection.is_nil () ? db::Edges::distance_type (0) : min_projection.to (),
- max_projection.is_nil () ? std::numeric_limits::max () : max_projection.to ())
+ max_projection.is_nil () ? std::numeric_limits::max () : max_projection.to (),
+ zd_mode)
);
}
-static db::EdgePairs separation2 (const db::Edges *r, const db::Edges &other, db::Edges::coord_type d, bool whole_edges, db::metrics_type metrics, const tl::Variant &ignore_angle, const tl::Variant &min_projection, const tl::Variant &max_projection)
+static db::EdgePairs separation2 (const db::Edges *r, const db::Edges &other, db::Edges::coord_type d, bool whole_edges, db::metrics_type metrics, const tl::Variant &ignore_angle, const tl::Variant &min_projection, const tl::Variant &max_projection, db::zero_distance_mode zd_mode)
{
return r->separation_check (other, d, db::EdgesCheckOptions (whole_edges,
metrics,
ignore_angle.is_nil () ? 90 : ignore_angle.to_double (),
min_projection.is_nil () ? db::Edges::distance_type (0) : min_projection.to (),
- max_projection.is_nil () ? std::numeric_limits::max () : max_projection.to ())
+ max_projection.is_nil () ? std::numeric_limits::max () : max_projection.to (),
+ zd_mode)
);
}
@@ -1399,7 +1405,7 @@ Class decl_Edges (decl_dbShapeCollection, "db", "Edges",
"\n"
"This variant has been introduced in version 0.27."
) +
- method_ext ("width_check", &width2, 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"),
+ method_ext ("width_check", &width2, 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 ("zero_distance_mode", db::IncludeZeroDistanceWhenTouching, "IncludeZeroDistanceWhenTouching"),
"@brief Performs a width check with options\n"
"@param d The minimum width for which the edges are checked\n"
"@param whole_edges If true, deliver the whole edges\n"
@@ -1407,6 +1413,7 @@ Class decl_Edges (decl_dbShapeCollection, "db", "Edges",
"@param ignore_angle The threshold angle above which no check is performed\n"
"@param min_projection The lower threshold of the projected length of one edge onto another\n"
"@param max_projection The upper threshold of the projected length of one edge onto another\n"
+ "@param zero_distance_mode Specifies how to handle edges with zero distance\n"
"\n"
"If \"whole_edges\" is true, the resulting \\EdgePairs collection will receive the whole "
"edges which contribute in the width check.\n"
@@ -1424,8 +1431,10 @@ Class decl_Edges (decl_dbShapeCollection, "db", "Edges",
"It is sufficient if the projection of one edge on the other matches the specified condition. "
"The projected length must be larger or equal to \"min_projection\" and less than \"max_projection\". "
"If you don't want to specify one threshold, pass nil to the respective value.\n"
+ "\n"
+ "'zero_distance_mode' has been added in version 0.29."
) +
- method_ext ("space_check", &space2, 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"),
+ method_ext ("space_check", &space2, 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 ("zero_distance_mode", db::IncludeZeroDistanceWhenTouching, "IncludeZeroDistanceWhenTouching"),
"@brief Performs a space check with options\n"
"@param d The minimum distance for which the edges are checked\n"
"@param whole_edges If true, deliver the whole edges\n"
@@ -1433,6 +1442,7 @@ Class decl_Edges (decl_dbShapeCollection, "db", "Edges",
"@param ignore_angle The threshold angle above which no check is performed\n"
"@param min_projection The lower threshold of the projected length of one edge onto another\n"
"@param max_projection The upper threshold of the projected length of one edge onto another\n"
+ "@param zero_distance_mode Specifies how to handle edges with zero distance\n"
"\n"
"If \"whole_edges\" is true, the resulting \\EdgePairs collection will receive the whole "
"edges which contribute in the space check.\n"
@@ -1450,8 +1460,10 @@ Class decl_Edges (decl_dbShapeCollection, "db", "Edges",
"It is sufficient if the projection of one edge on the other matches the specified condition. "
"The projected length must be larger or equal to \"min_projection\" and less than \"max_projection\". "
"If you don't want to specify one threshold, pass nil to the respective value.\n"
+ "\n"
+ "'zero_distance_mode' has been added in version 0.29."
) +
- method_ext ("inside_check|enclosed_check", &inside2, 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"),
+ method_ext ("inside_check|enclosed_check", &inside2, 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 ("zero_distance_mode", db::IncludeZeroDistanceWhenTouching, "IncludeZeroDistanceWhenTouching"),
"@brief Performs an inside check with options\n"
"@param d The minimum distance for which the edges are checked\n"
"@param other The other edge collection against which to check\n"
@@ -1460,6 +1472,7 @@ Class decl_Edges (decl_dbShapeCollection, "db", "Edges",
"@param ignore_angle The threshold angle above which no check is performed\n"
"@param min_projection The lower threshold of the projected length of one edge onto another\n"
"@param max_projection The upper threshold of the projected length of one edge onto another\n"
+ "@param zero_distance_mode Specifies how to handle edges with zero distance\n"
"\n"
"If \"whole_edges\" is true, the resulting \\EdgePairs collection will receive the whole "
"edges which contribute in the width check.\n"
@@ -1479,8 +1492,9 @@ Class decl_Edges (decl_dbShapeCollection, "db", "Edges",
"If you don't want to specify one threshold, pass nil to the respective value.\n"
"\n"
"The 'enclosed_check' alias was introduced in version 0.27.5.\n"
+ "'zero_distance_mode' has been added in version 0.29."
) +
- method_ext ("enclosing_check", &enclosing2, 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"),
+ method_ext ("enclosing_check", &enclosing2, 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 ("zero_distance_mode", db::IncludeZeroDistanceWhenTouching, "IncludeZeroDistanceWhenTouching"),
"@brief Performs an enclosing check with options\n"
"@param d The minimum distance for which the edges are checked\n"
"@param other The other edge collection against which to check\n"
@@ -1489,6 +1503,7 @@ Class decl_Edges (decl_dbShapeCollection, "db", "Edges",
"@param ignore_angle The threshold angle above which no check is performed\n"
"@param min_projection The lower threshold of the projected length of one edge onto another\n"
"@param max_projection The upper threshold of the projected length of one edge onto another\n"
+ "@param zero_distance_mode Specifies how to handle edges with zero distance\n"
"\n"
"If \"whole_edges\" is true, the resulting \\EdgePairs collection will receive the whole "
"edges which contribute in the width check.\n"
@@ -1506,8 +1521,10 @@ Class decl_Edges (decl_dbShapeCollection, "db", "Edges",
"It is sufficient if the projection of one edge on the other matches the specified condition. "
"The projected length must be larger or equal to \"min_projection\" and less than \"max_projection\". "
"If you don't want to specify one threshold, pass nil to the respective value.\n"
+ "\n"
+ "'zero_distance_mode' has been added in version 0.29."
) +
- method_ext ("overlap_check", &overlap2, 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"),
+ method_ext ("overlap_check", &overlap2, 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 ("zero_distance_mode", db::IncludeZeroDistanceWhenTouching, "IncludeZeroDistanceWhenTouching"),
"@brief Performs an overlap check with options\n"
"@param d The minimum distance for which the edges are checked\n"
"@param other The other edge collection against which to check\n"
@@ -1516,6 +1533,7 @@ Class decl_Edges (decl_dbShapeCollection, "db", "Edges",
"@param ignore_angle The threshold angle above which no check is performed\n"
"@param min_projection The lower threshold of the projected length of one edge onto another\n"
"@param max_projection The upper threshold of the projected length of one edge onto another\n"
+ "@param zero_distance_mode Specifies how to handle edges with zero distance\n"
"\n"
"If \"whole_edges\" is true, the resulting \\EdgePairs collection will receive the whole "
"edges which contribute in the width check.\n"
@@ -1533,8 +1551,10 @@ Class decl_Edges (decl_dbShapeCollection, "db", "Edges",
"It is sufficient if the projection of one edge on the other matches the specified condition. "
"The projected length must be larger or equal to \"min_projection\" and less than \"max_projection\". "
"If you don't want to specify one threshold, pass nil to the respective value.\n"
+ "\n"
+ "'zero_distance_mode' has been added in version 0.29."
) +
- method_ext ("separation_check", &separation2, 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"),
+ method_ext ("separation_check", &separation2, 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 ("zero_distance_mode", db::IncludeZeroDistanceWhenTouching, "IncludeZeroDistanceWhenTouching"),
"@brief Performs an overlap check with options\n"
"@param d The minimum distance for which the edges are checked\n"
"@param other The other edge collection against which to check\n"
@@ -1543,6 +1563,7 @@ Class decl_Edges (decl_dbShapeCollection, "db", "Edges",
"@param ignore_angle The threshold angle above which no check is performed\n"
"@param min_projection The lower threshold of the projected length of one edge onto another\n"
"@param max_projection The upper threshold of the projected length of one edge onto another\n"
+ "@param zero_distance_mode Specifies how to handle edges with zero distance\n"
"\n"
"If \"whole_edges\" is true, the resulting \\EdgePairs collection will receive the whole "
"edges which contribute in the width check.\n"
@@ -1560,6 +1581,8 @@ Class decl_Edges (decl_dbShapeCollection, "db", "Edges",
"It is sufficient if the projection of one edge on the other matches the specified condition. "
"The projected length must be larger or equal to \"min_projection\" and less than \"max_projection\". "
"If you don't want to specify one threshold, pass nil to the respective value.\n"
+ "\n"
+ "'zero_distance_mode' has been added in version 0.29."
) +
method_ext ("extents", &extents0,
"@brief Returns a region with the bounding boxes of the edges\n"
diff --git a/src/db/db/gsiDeclDbLayout.cc b/src/db/db/gsiDeclDbLayout.cc
index d85fe3687..db8c78233 100644
--- a/src/db/db/gsiDeclDbLayout.cc
+++ b/src/db/db/gsiDeclDbLayout.cc
@@ -1105,12 +1105,54 @@ Class decl_Layout ("db", "Layout",
"\n"
"This method has been introduced in version 0.25."
) +
+ gsi::method ("merge_meta_info", static_cast (&db::Layout::merge_meta_info), gsi::arg ("other"),
+ "@brief Merges the meta information from the other layout into this layout\n"
+ "See \\LayoutMetaInfo for details about cells and meta information.\n"
+ "Existing keys in this layout will be overwritten by the respective values from the other layout.\n"
+ "New keys will be added.\n"
+ "\n"
+ "This method has been introduced in version 0.28.16."
+ ) +
+ gsi::method ("merge_meta_info", static_cast (&db::Layout::merge_meta_info), gsi::arg ("other"), gsi::arg ("cm"),
+ "@brief Merges the meta information from the other layout into this layout for the cells given by the cell mapping\n"
+ "See \\LayoutMetaInfo for details about cells and meta information.\n"
+ "This method will use the source/target cell pairs from the cell mapping object and merge the meta information "
+ "from each source cell from the 'other' layout into the mapped cell inside self.\n"
+ "This method can be used with '\\copy_tree_shapes' and similar to copy meta information in addition to the shapes.\n"
+ "Existing cell-specific keys in this layout will be overwritten by the respective values from the other layout.\n"
+ "New keys will be added.\n"
+ "\n"
+ "This method has been introduced in version 0.28.16."
+ ) +
+ gsi::method ("copy_meta_info", static_cast (&db::Layout::copy_meta_info), gsi::arg ("other"),
+ "@brief Copies the meta information from the other layout into this layout\n"
+ "See \\LayoutMetaInfo for details about cells and meta information.\n"
+ "The meta information from this layout will be replaced by the meta information from the other layout.\n"
+ "\n"
+ "This method has been introduced in version 0.28.16."
+ ) +
+ gsi::method ("copy_meta_info", static_cast (&db::Layout::copy_meta_info), gsi::arg ("other"), gsi::arg ("cm"),
+ "@brief Copies the meta information from the other layout into this layout for the cells given by the cell mapping\n"
+ "See \\LayoutMetaInfo for details about cells and meta information.\n"
+ "This method will use the source/target cell pairs from the cell mapping object and merge the meta information "
+ "from each source cell from the 'other' layout into the mapped cell inside self.\n"
+ "This method can be used with '\\copy_tree_shapes' and similar to copy meta information in addition to the shapes.\n"
+ "All cell-specific keys in this layout will be replaced by the respective values from the other layout.\n"
+ "\n"
+ "This method has been introduced in version 0.28.16."
+ ) +
gsi::method ("clear_meta_info", static_cast (&db::Layout::clear_meta),
"@brief Clears the meta information of the layout\n"
"See \\LayoutMetaInfo for details about layouts and meta information."
"\n"
"This method has been introduced in version 0.28.8."
) +
+ gsi::method ("clear_all_meta_info", static_cast (&db::Layout::clear_all_meta),
+ "@brief Clears all meta information of the layout (cell specific and global)\n"
+ "See \\LayoutMetaInfo for details about layouts and meta information."
+ "\n"
+ "This method has been introduced in version 0.28.16."
+ ) +
gsi::method ("remove_meta_info", static_cast (&db::Layout::remove_meta_info), gsi::arg ("name"),
"@brief Removes meta information from the layout\n"
"See \\LayoutMetaInfo for details about layouts and meta information."
diff --git a/src/db/db/gsiDeclDbLayoutDiff.cc b/src/db/db/gsiDeclDbLayoutDiff.cc
index 84ac3217e..3e8098750 100644
--- a/src/db/db/gsiDeclDbLayoutDiff.cc
+++ b/src/db/db/gsiDeclDbLayoutDiff.cc
@@ -90,6 +90,11 @@ public:
dbu_differs_event (dbu_a, dbu_b);
}
+ virtual void layout_meta_info_differs (const std::string &name, const tl::Variant &value_a, const tl::Variant &value_b)
+ {
+ layout_meta_info_differs_event (name, value_a, value_b);
+ }
+
virtual void layer_in_a_only (const db::LayerProperties &la)
{
layer_in_a_only_event (la);
@@ -132,6 +137,11 @@ public:
begin_cell_event (mp_cell_a, mp_cell_b);
}
+ virtual void cell_meta_info_differs (const std::string &name, const tl::Variant &value_a, const tl::Variant &value_b)
+ {
+ cell_meta_info_differs_event (name, value_a, value_b);
+ }
+
virtual void begin_inst_differences ()
{
begin_inst_differences_event ();
@@ -343,6 +353,7 @@ public:
}
tl::event dbu_differs_event;
+ tl::event layout_meta_info_differs_event;
tl::event layer_in_a_only_event;
tl::event layer_in_b_only_event;
tl::event layer_name_differs_event;
@@ -351,6 +362,7 @@ public:
tl::event cell_in_b_only_event;
tl::event bbox_differs_event;
tl::event begin_cell_event;
+ tl::event cell_meta_info_differs_event;
tl::Event begin_inst_differences_event;
tl::event instance_in_a_only_event;
tl::event instance_in_b_only_event;
@@ -409,6 +421,10 @@ static unsigned int f_no_properties () {
return db::layout_diff::f_no_properties;
}
+static unsigned int f_with_meta () {
+ return db::layout_diff::f_with_meta;
+}
+
static unsigned int f_no_layer_names () {
return db::layout_diff::f_no_layer_names;
}
@@ -450,7 +466,7 @@ gsi::Class decl_LayoutDiff ("db", "LayoutDiff",
"full compare.\n"
"\n"
"This constant can be used for the flags parameter of \\compare_layouts and \\compare_cells. It can be "
- "compared with other constants to form a flag set."
+ "combined with other constants to form a flag set."
) +
gsi::constant ("IgnoreDuplicates", &f_ignore_duplicates,
"@brief Ignore duplicate instances or shapes\n"
@@ -462,17 +478,25 @@ gsi::Class decl_LayoutDiff ("db", "LayoutDiff",
gsi::constant ("NoTextOrientation", &f_no_text_orientation,
"@brief Ignore text orientation\n"
"This constant can be used for the flags parameter of \\compare_layouts and \\compare_cells. It can be "
- "compared with other constants to form a flag set."
+ "combined with other constants to form a flag set."
) +
gsi::constant ("NoProperties", &f_no_properties,
"@brief Ignore properties\n"
"This constant can be used for the flags parameter of \\compare_layouts and \\compare_cells. It can be "
- "compared with other constants to form a flag set."
+ "combined with other constants to form a flag set."
+ ) +
+ gsi::constant ("WithMetaInfo", &f_with_meta,
+ "@brief Ignore meta info\n"
+ "This constant can be used for the flags parameter of \\compare_layouts and \\compare_cells. It can be "
+ "combined with other constants to form a flag set. If present, this option tells the compare algorithm "
+ "to include persisted meta info in the compare.\n"
+ "\n"
+ "This flag has been introduced in version 0.28.16."
) +
gsi::constant ("NoLayerNames", &f_no_layer_names,
"@brief Do not compare layer names\n"
"This constant can be used for the flags parameter of \\compare_layouts and \\compare_cells. It can be "
- "compared with other constants to form a flag set."
+ "combined with other constants to form a flag set."
) +
gsi::constant ("Verbose", &f_verbose,
"@brief Enables verbose mode (gives details about the differences)\n"
@@ -480,22 +504,22 @@ gsi::Class decl_LayoutDiff ("db", "LayoutDiff",
"See the event descriptions for details about the differences in verbose and non-verbose mode.\n"
"\n"
"This constant can be used for the flags parameter of \\compare_layouts and \\compare_cells. It can be "
- "compared with other constants to form a flag set."
+ "combined with other constants to form a flag set."
) +
gsi::constant ("BoxesAsPolygons", &f_boxes_as_polygons,
"@brief Compare boxes to polygons\n"
"This constant can be used for the flags parameter of \\compare_layouts and \\compare_cells. It can be "
- "compared with other constants to form a flag set."
+ "combined with other constants to form a flag set."
) +
gsi::constant ("FlattenArrayInsts", &f_flatten_array_insts,
"@brief Compare array instances instance by instance\n"
"This constant can be used for the flags parameter of \\compare_layouts and \\compare_cells. It can be "
- "compared with other constants to form a flag set."
+ "combined with other constants to form a flag set."
) +
gsi::constant ("PathsAsPolygons", &f_paths_as_polygons,
"@brief Compare paths to polygons\n"
"This constant can be used for the flags parameter of \\compare_layouts and \\compare_cells. It can be "
- "compared with other constants to form a flag set."
+ "combined with other constants to form a flag set."
) +
gsi::constant ("SmartCellMapping", &f_smart_cell_mapping,
"@brief Derive smart cell mapping instead of name mapping (available only if top cells are specified)\n"
@@ -503,7 +527,7 @@ gsi::Class decl_LayoutDiff ("db", "LayoutDiff",
"cells are compared (with \\LayoutDiff#compare with cells instead of layout objects).\n"
"\n"
"This constant can be used for the flags parameter of \\compare_layouts and \\compare_cells. It can be "
- "compared with other constants to form a flag set.\n"
+ "combined with other constants to form a flag set.\n"
) +
gsi::constant ("DontSummarizeMissingLayers", &f_dont_summarize_missing_layers,
"@brief Don't summarize missing layers\n"
@@ -511,12 +535,12 @@ gsi::Class decl_LayoutDiff ("db", "LayoutDiff",
"layer will be reported as difference.\n"
"\n"
"This constant can be used for the flags parameter of \\compare_layouts and \\compare_cells. It can be "
- "compared with other constants to form a flag set."
+ "combined with other constants to form a flag set."
) +
gsi::constant ("NoTextDetails", &f_no_text_details,
"@brief Ignore text details (font, size, presentation)\n"
"This constant can be used for the flags parameter of \\compare_layouts and \\compare_cells. It can be "
- "compared with other constants to form a flag set."
+ "combined with other constants to form a flag set."
) +
gsi::method ("compare", &LayoutDiff::compare_layouts,
gsi::arg("a"),
@@ -593,6 +617,14 @@ gsi::Class decl_LayoutDiff ("db", "LayoutDiff",
gsi::event ("on_dbu_differs", &LayoutDiff::dbu_differs_event, gsi::arg ("dbu_a"), gsi::arg ("dbu_b"),
"@brief This signal indicates a difference in the database units of the layouts\n"
) +
+ gsi::event ("on_layout_meta_info_differs", &LayoutDiff::layout_meta_info_differs_event, gsi::arg ("name"), gsi::arg ("a"), gsi::arg ("b"),
+ "@brief This signal indicates that global meta info differs\n"
+ "Meta information is only compared when \\WithMetaInfo is added to the compare flags.\n"
+ "'a' and 'b' are the values for the first and second layout. 'nil' is passed to these values to indicate "
+ "missing meta information on one side.\n"
+ "\n"
+ "This event has been added in version 0.28.16."
+ ) +
gsi::event ("on_layer_in_a_only", &LayoutDiff::layer_in_a_only_event, gsi::arg ("a"),
"@brief This signal indicates a layer that is present only in the first layout\n"
) +
@@ -619,9 +651,17 @@ gsi::Class decl_LayoutDiff ("db", "LayoutDiff",
"In verbose mode detailed events will be issued indicating the differences.\n"
) +
gsi::event ("on_begin_cell", &LayoutDiff::begin_cell_event, gsi::arg ("ca"), gsi::arg ("cb"),
- "@brief This signal initiates the sequence of events for a cell pair\n"
+ "@brief This signal indicates the sequence of events for a cell pair\n"
"All cell specific events happen between \\begin_cell_event and \\end_cell_event signals."
) +
+ gsi::event ("on_cell_meta_info_differs", &LayoutDiff::cell_meta_info_differs_event, gsi::arg ("name"), gsi::arg ("a"), gsi::arg ("b"),
+ "@brief This signal indicates that meta info between the current cells differs\n"
+ "Meta information is only compared when \\WithMetaInfo is added to the compare flags.\n"
+ "'a' and 'b' are the values for the first and second layout. 'nil' is passed to these values to indicate "
+ "missing meta information on one side.\n"
+ "\n"
+ "This event has been added in version 0.28.16."
+ ) +
gsi::event ("on_begin_inst_differences", &LayoutDiff::begin_inst_differences_event,
"@brief This signal indicates differences in the cell instances\n"
"In verbose mode (see \\Verbose) more events will follow that indicate the instances that are present only "
diff --git a/src/db/db/gsiDeclDbRegion.cc b/src/db/db/gsiDeclDbRegion.cc
index 43b809553..33d13a5de 100644
--- a/src/db/db/gsiDeclDbRegion.cc
+++ b/src/db/db/gsiDeclDbRegion.cc
@@ -526,7 +526,7 @@ static db::Region merged_ext2 (db::Region *r, bool min_coherence, int min_wc)
return r->merged (min_coherence, std::max (0, min_wc - 1));
}
-static db::EdgePairs width2 (const db::Region *r, db::Region::distance_type 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, db::PropertyConstraint prop_constraint)
+static db::EdgePairs width2 (const db::Region *r, db::Region::distance_type 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, db::PropertyConstraint prop_constraint, db::zero_distance_mode zero_distance_mode)
{
return r->width_check (d, db::RegionCheckOptions (whole_edges,
metrics,
@@ -537,11 +537,12 @@ static db::EdgePairs width2 (const db::Region *r, db::Region::distance_type d, b
db::NoOppositeFilter,
db::NoRectFilter,
negative,
- prop_constraint)
+ prop_constraint,
+ zero_distance_mode)
);
}
-static db::EdgePairs notch2 (const db::Region *r, db::Region::distance_type 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, db::PropertyConstraint prop_constraint)
+static db::EdgePairs notch2 (const db::Region *r, db::Region::distance_type 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, db::PropertyConstraint prop_constraint, db::zero_distance_mode zero_distance_mode)
{
return r->notch_check (d, db::RegionCheckOptions (whole_edges,
metrics,
@@ -552,11 +553,12 @@ static db::EdgePairs notch2 (const db::Region *r, db::Region::distance_type d, b
db::NoOppositeFilter,
db::NoRectFilter,
negative,
- prop_constraint)
+ prop_constraint,
+ zero_distance_mode)
);
}
-static db::EdgePairs isolated2 (const db::Region *r, db::Region::distance_type 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, db::RectFilter rect_filter, bool negative, db::PropertyConstraint prop_constraint)
+static db::EdgePairs isolated2 (const db::Region *r, db::Region::distance_type 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, db::RectFilter rect_filter, bool negative, db::PropertyConstraint prop_constraint, db::zero_distance_mode zero_distance_mode)
{
return r->isolated_check (d, db::RegionCheckOptions (whole_edges,
metrics,
@@ -567,11 +569,12 @@ static db::EdgePairs isolated2 (const db::Region *r, db::Region::distance_type d
opposite,
rect_filter,
negative,
- prop_constraint)
+ prop_constraint,
+ zero_distance_mode)
);
}
-static db::EdgePairs space2 (const db::Region *r, db::Region::distance_type 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, db::RectFilter rect_filter, bool negative, db::PropertyConstraint prop_constraint)
+static db::EdgePairs space2 (const db::Region *r, db::Region::distance_type 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, db::RectFilter rect_filter, bool negative, db::PropertyConstraint prop_constraint, db::zero_distance_mode zero_distance_mode)
{
return r->space_check (d, db::RegionCheckOptions (whole_edges,
metrics,
@@ -582,11 +585,12 @@ static db::EdgePairs space2 (const db::Region *r, db::Region::distance_type d, b
opposite,
rect_filter,
negative,
- prop_constraint)
+ prop_constraint,
+ zero_distance_mode)
);
}
-static db::EdgePairs inside2 (const db::Region *r, const db::Region &other, db::Region::distance_type 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, db::RectFilter rect_filter, bool negative, db::PropertyConstraint prop_constraint)
+static db::EdgePairs inside2 (const db::Region *r, const db::Region &other, db::Region::distance_type 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, db::RectFilter rect_filter, bool negative, db::PropertyConstraint prop_constraint, db::zero_distance_mode zero_distance_mode)
{
return r->inside_check (other, d, db::RegionCheckOptions (whole_edges,
metrics,
@@ -597,11 +601,12 @@ static db::EdgePairs inside2 (const db::Region *r, const db::Region &other, db::
opposite,
rect_filter,
negative,
- prop_constraint)
+ prop_constraint,
+ zero_distance_mode)
);
}
-static db::EdgePairs overlap2 (const db::Region *r, const db::Region &other, db::Region::distance_type 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, db::RectFilter rect_filter, bool negative, db::PropertyConstraint prop_constraint)
+static db::EdgePairs overlap2 (const db::Region *r, const db::Region &other, db::Region::distance_type 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, db::RectFilter rect_filter, bool negative, db::PropertyConstraint prop_constraint, db::zero_distance_mode zero_distance_mode)
{
return r->overlap_check (other, d, db::RegionCheckOptions (whole_edges,
metrics,
@@ -612,11 +617,12 @@ static db::EdgePairs overlap2 (const db::Region *r, const db::Region &other, db:
opposite,
rect_filter,
negative,
- prop_constraint)
+ prop_constraint,
+ zero_distance_mode)
);
}
-static db::EdgePairs enclosing2 (const db::Region *r, const db::Region &other, db::Region::distance_type 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, db::RectFilter rect_filter, bool negative, db::PropertyConstraint prop_constraint)
+static db::EdgePairs enclosing2 (const db::Region *r, const db::Region &other, db::Region::distance_type 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, db::RectFilter rect_filter, bool negative, db::PropertyConstraint prop_constraint, db::zero_distance_mode zero_distance_mode)
{
return r->enclosing_check (other, d, db::RegionCheckOptions (whole_edges,
metrics,
@@ -627,11 +633,12 @@ static db::EdgePairs enclosing2 (const db::Region *r, const db::Region &other, d
opposite,
rect_filter,
negative,
- prop_constraint)
+ prop_constraint,
+ zero_distance_mode)
);
}
-static db::EdgePairs separation2 (const db::Region *r, const db::Region &other, db::Region::distance_type 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, db::RectFilter rect_filter, bool negative, db::PropertyConstraint prop_constraint)
+static db::EdgePairs separation2 (const db::Region *r, const db::Region &other, db::Region::distance_type 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, db::RectFilter rect_filter, bool negative, db::PropertyConstraint prop_constraint, db::zero_distance_mode zero_distance_mode)
{
return r->separation_check (other, d, db::RegionCheckOptions (whole_edges,
metrics,
@@ -642,7 +649,8 @@ static db::EdgePairs separation2 (const db::Region *r, const db::Region &other,
opposite,
rect_filter,
negative,
- prop_constraint)
+ prop_constraint,
+ zero_distance_mode)
);
}
@@ -2589,7 +2597,7 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region",
"\n"
"This variant was introduced in version 0.27.\n"
) +
- method_ext ("width_check", &width2, gsi::arg ("d"), gsi::arg ("whole_edges", false), gsi::arg ("metrics", db::metrics_type::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::arg ("property_constraint", db::IgnoreProperties, "IgnoreProperties"),
+ method_ext ("width_check", &width2, gsi::arg ("d"), gsi::arg ("whole_edges", false), gsi::arg ("metrics", db::metrics_type::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::arg ("property_constraint", db::IgnoreProperties, "IgnoreProperties"), gsi::arg ("zero_distance_mode", db::IncludeZeroDistanceWhenTouching, "IncludeZeroDistanceWhenTouching"),
"@brief Performs a width check with options\n"
"@param d The minimum width for which the polygons are checked\n"
"@param whole_edges If true, deliver the whole edges\n"
@@ -2600,6 +2608,7 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region",
"@param shielded Enables shielding\n"
"@param negative If true, edges not violation the condition will be output as pseudo-edge pairs\n"
"@param property_constraint Only \\IgnoreProperties and \\NoPropertyConstraint are allowed - in the last case, properties are copied from the original shapes to the output. "
+ "@param zero_distance_mode Specifies how to handle edges with zero distance\n"
"Other than 'width' allow more options here.\n"
"\n"
"This version is similar to the simple version with one parameter. In addition, it allows "
@@ -2630,9 +2639,10 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region",
"Merged semantics applies for the input of this method (see \\merged_semantics= for a description of this concept)\n"
"\n"
"The 'shielded' and 'negative' options have been introduced in version 0.27. "
- "'property_constraint' has been added in version 0.28.4."
+ "'property_constraint' has been added in version 0.28.4.\n"
+ "'zero_distance_mode' has been added in version 0.29."
) +
- method_ext ("space_check", &space2, gsi::arg ("d"), gsi::arg ("whole_edges", false), gsi::arg ("metrics", db::metrics_type::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::arg ("property_constraint", db::IgnoreProperties, "IgnoreProperties"),
+ method_ext ("space_check", &space2, gsi::arg ("d"), gsi::arg ("whole_edges", false), gsi::arg ("metrics", db::metrics_type::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::arg ("property_constraint", db::IgnoreProperties, "IgnoreProperties"), gsi::arg ("zero_distance_mode", db::IncludeZeroDistanceWhenTouching, "IncludeZeroDistanceWhenTouching"),
"@brief Performs a space check with options\n"
"@param d The minimum space for which the polygons are checked\n"
"@param whole_edges If true, deliver the whole edges\n"
@@ -2644,6 +2654,7 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region",
"@param rect_filter Specifies an error filter for rectangular input shapes\n"
"@param negative If true, edges not violation the condition will be output as pseudo-edge pairs\n"
"@param property_constraint Specifies whether to consider only shapes with a certain property relation\n"
+ "@param zero_distance_mode Specifies how to handle edges with zero distance\n"
"\n"
"If \"whole_edges\" is true, the resulting \\EdgePairs collection will receive the whole "
"edges which contribute in the width check.\n"
@@ -2673,9 +2684,10 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region",
"Merged semantics applies for the input of this method (see \\merged_semantics= for a description of this concept)\n"
"\n"
"The 'shielded', 'negative', 'not_opposite' and 'rect_sides' options have been introduced in version 0.27.\n"
- "'property_constraint' has been added in version 0.28.4."
+ "'property_constraint' has been added in version 0.28.4.\n"
+ "'zero_distance_mode' has been added in version 0.29."
) +
- method_ext ("notch_check", ¬ch2, gsi::arg ("d"), gsi::arg ("whole_edges", false), gsi::arg ("metrics", db::metrics_type::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::arg ("property_constraint", db::IgnoreProperties, "IgnoreProperties"),
+ method_ext ("notch_check", ¬ch2, gsi::arg ("d"), gsi::arg ("whole_edges", false), gsi::arg ("metrics", db::metrics_type::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::arg ("property_constraint", db::IgnoreProperties, "IgnoreProperties"), gsi::arg ("zero_distance_mode", db::IncludeZeroDistanceWhenTouching, "IncludeZeroDistanceWhenTouching"),
"@brief Performs a space check between edges of the same polygon with options\n"
"@param d The minimum space for which the polygons are checked\n"
"@param whole_edges If true, deliver the whole edges\n"
@@ -2687,6 +2699,7 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region",
"@param negative If true, edges not violation the condition will be output as pseudo-edge pairs\n"
"@param property_constraint Specifies whether to consider only shapes with a certain property relation\n"
"@param property_constraint Only \\IgnoreProperties and \\NoPropertyConstraint are allowed - in the last case, properties are copied from the original shapes to the output"
+ "@param zero_distance_mode Specifies how to handle edges with zero distance\n"
"\n"
"This version is similar to the simple version with one parameter. In addition, it allows "
"to specify many more options.\n"
@@ -2716,9 +2729,10 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region",
"Merged semantics applies for the input of this method (see \\merged_semantics= for a description of this concept)\n"
"\n"
"The 'shielded' and 'negative' options have been introduced in version 0.27.\n"
- "'property_constraint' has been added in version 0.28.4."
+ "'property_constraint' has been added in version 0.28.4.\n"
+ "'zero_distance_mode' has been added in version 0.29."
) +
- method_ext ("isolated_check", &isolated2, gsi::arg ("d"), gsi::arg ("whole_edges", false), gsi::arg ("metrics", db::metrics_type::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::arg ("property_constraint", db::IgnoreProperties, "IgnoreProperties"),
+ method_ext ("isolated_check", &isolated2, gsi::arg ("d"), gsi::arg ("whole_edges", false), gsi::arg ("metrics", db::metrics_type::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::arg ("property_constraint", db::IgnoreProperties, "IgnoreProperties"), gsi::arg ("zero_distance_mode", db::IncludeZeroDistanceWhenTouching, "IncludeZeroDistanceWhenTouching"),
"@brief Performs a space check between edges of different polygons with options\n"
"@param d The minimum space for which the polygons are checked\n"
"@param whole_edges If true, deliver the whole edges\n"
@@ -2730,6 +2744,7 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region",
"@param rect_filter Specifies an error filter for rectangular input shapes\n"
"@param negative If true, edges not violation the condition will be output as pseudo-edge pairs\n"
"@param property_constraint Specifies whether to consider only shapes with a certain property relation\n"
+ "@param zero_distance_mode Specifies how to handle edges with zero distance\n"
"\n"
"If \"whole_edges\" is true, the resulting \\EdgePairs collection will receive the whole "
"edges which contribute in the width check.\n"
@@ -2759,9 +2774,10 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region",
"Merged semantics applies for the input of this method (see \\merged_semantics= for a description of this concept)\n"
"\n"
"The 'shielded', 'negative', 'not_opposite' and 'rect_sides' options have been introduced in version 0.27.\n"
- "'property_constraint' has been added in version 0.28.4."
+ "'property_constraint' has been added in version 0.28.4.\n"
+ "'zero_distance_mode' has been added in version 0.29."
) +
- method_ext ("inside_check|enclosed_check", &inside2, gsi::arg ("other"), gsi::arg ("d"), gsi::arg ("whole_edges", false), gsi::arg ("metrics", db::metrics_type::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::arg ("property_constraint", db::IgnoreProperties, "IgnoreProperties"),
+ method_ext ("inside_check|enclosed_check", &inside2, gsi::arg ("other"), gsi::arg ("d"), gsi::arg ("whole_edges", false), gsi::arg ("metrics", db::metrics_type::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::arg ("property_constraint", db::IgnoreProperties, "IgnoreProperties"), gsi::arg ("zero_distance_mode", db::IncludeZeroDistanceWhenTouching, "IncludeZeroDistanceWhenTouching"),
"@brief Performs an inside check with options\n"
"@param d The minimum distance for which the polygons are checked\n"
"@param other The other region against which to check\n"
@@ -2774,6 +2790,7 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region",
"@param rect_filter Specifies an error filter for rectangular input shapes\n"
"@param negative Negative output from the first input\n"
"@param property_constraint Specifies whether to consider only shapes with a certain property relation\n"
+ "@param zero_distance_mode Specifies how to handle edges with zero distance\n"
"\n"
"If \"whole_edges\" is true, the resulting \\EdgePairs collection will receive the whole "
"edges which contribute in the width check.\n"
@@ -2810,9 +2827,10 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region",
"The 'shielded', 'negative', 'not_opposite' and 'rect_sides' options have been introduced in version 0.27. "
"The interpretation of the 'negative' flag has been restriced to first-layout only output in 0.27.1.\n"
"The 'enclosed_check' alias was introduced in version 0.27.5.\n"
- "'property_constraint' has been added in version 0.28.4."
+ "'property_constraint' has been added in version 0.28.4.\n"
+ "'zero_distance_mode' has been added in version 0.29."
) +
- method_ext ("overlap_check", &overlap2, gsi::arg ("other"), gsi::arg ("d"), gsi::arg ("whole_edges", false), gsi::arg ("metrics", db::metrics_type::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::arg ("property_constraint", db::IgnoreProperties, "IgnoreProperties"),
+ method_ext ("overlap_check", &overlap2, gsi::arg ("other"), gsi::arg ("d"), gsi::arg ("whole_edges", false), gsi::arg ("metrics", db::metrics_type::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::arg ("property_constraint", db::IgnoreProperties, "IgnoreProperties"), gsi::arg ("zero_distance_mode", db::IncludeZeroDistanceWhenTouching, "IncludeZeroDistanceWhenTouching"),
"@brief Performs an overlap check with options\n"
"@param d The minimum overlap for which the polygons are checked\n"
"@param other The other region against which to check\n"
@@ -2825,6 +2843,7 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region",
"@param rect_filter Specifies an error filter for rectangular input shapes\n"
"@param negative Negative output from the first input\n"
"@param property_constraint Specifies whether to consider only shapes with a certain property relation\n"
+ "@param zero_distance_mode Specifies how to handle edges with zero distance\n"
"\n"
"If \"whole_edges\" is true, the resulting \\EdgePairs collection will receive the whole "
"edges which contribute in the width check.\n"
@@ -2860,9 +2879,10 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region",
"\n"
"The 'shielded', 'negative', 'not_opposite' and 'rect_sides' options have been introduced in version 0.27. "
"The interpretation of the 'negative' flag has been restriced to first-layout only output in 0.27.1.\n"
- "'property_constraint' has been added in version 0.28.4."
+ "'property_constraint' has been added in version 0.28.4.\n"
+ "'zero_distance_mode' has been added in version 0.29."
) +
- method_ext ("enclosing_check", &enclosing2, gsi::arg ("other"), gsi::arg ("d"), gsi::arg ("whole_edges", false), gsi::arg ("metrics", db::metrics_type::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::arg ("property_constraint", db::IgnoreProperties, "IgnoreProperties"),
+ method_ext ("enclosing_check", &enclosing2, gsi::arg ("other"), gsi::arg ("d"), gsi::arg ("whole_edges", false), gsi::arg ("metrics", db::metrics_type::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::arg ("property_constraint", db::IgnoreProperties, "IgnoreProperties"), gsi::arg ("zero_distance_mode", db::IncludeZeroDistanceWhenTouching, "IncludeZeroDistanceWhenTouching"),
"@brief Performs an enclosing check with options\n"
"@param d The minimum enclosing distance for which the polygons are checked\n"
"@param other The other region against which to check\n"
@@ -2875,6 +2895,7 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region",
"@param rect_filter Specifies an error filter for rectangular input shapes\n"
"@param negative Negative output from the first input\n"
"@param property_constraint Specifies whether to consider only shapes with a certain property relation\n"
+ "@param zero_distance_mode Specifies how to handle edges with zero distance\n"
"\n"
"If \"whole_edges\" is true, the resulting \\EdgePairs collection will receive the whole "
"edges which contribute in the width check.\n"
@@ -2910,9 +2931,10 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region",
"\n"
"The 'shielded', 'negative', 'not_opposite' and 'rect_sides' options have been introduced in version 0.27. "
"The interpretation of the 'negative' flag has been restriced to first-layout only output in 0.27.1.\n"
- "'property_constraint' has been added in version 0.28.4."
+ "'property_constraint' has been added in version 0.28.4.\n"
+ "'zero_distance_mode' has been added in version 0.29."
) +
- method_ext ("separation_check", &separation2, gsi::arg ("other"), gsi::arg ("d"), gsi::arg ("whole_edges", false), gsi::arg ("metrics", db::metrics_type::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::arg ("property_constraint", db::IgnoreProperties, "IgnoreProperties"),
+ method_ext ("separation_check", &separation2, gsi::arg ("other"), gsi::arg ("d"), gsi::arg ("whole_edges", false), gsi::arg ("metrics", db::metrics_type::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::arg ("property_constraint", db::IgnoreProperties, "IgnoreProperties"), gsi::arg ("zero_distance_mode", db::IncludeZeroDistanceWhenTouching, "IncludeZeroDistanceWhenTouching"),
"@brief Performs a separation check with options\n"
"@param d The minimum separation for which the polygons are checked\n"
"@param other The other region against which to check\n"
@@ -2925,6 +2947,7 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region",
"@param rect_filter Specifies an error filter for rectangular input shapes\n"
"@param negative Negative output from the first input\n"
"@param property_constraint Specifies whether to consider only shapes with a certain property relation\n"
+ "@param zero_distance_mode Specifies how to handle edges with zero distance\n"
"\n"
"If \"whole_edges\" is true, the resulting \\EdgePairs collection will receive the whole "
"edges which contribute in the width check.\n"
@@ -2960,7 +2983,8 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region",
"\n"
"The 'shielded', 'negative', 'not_opposite' and 'rect_sides' options have been introduced in version 0.27. "
"The interpretation of the 'negative' flag has been restriced to first-layout only output in 0.27.1.\n"
- "'property_constraint' has been added in version 0.28.4."
+ "'property_constraint' has been added in version 0.28.4.\n"
+ "'zero_distance_mode' has been added in version 0.29."
) +
method_ext ("area", &area1,
"@brief The area of the region\n"
@@ -3239,6 +3263,46 @@ gsi::Enum decl_Metrics ("db", "Metrics",
gsi::ClassExt inject_Metrics_in_Region (decl_Metrics.defs ());
gsi::ClassExt inject_Metrics_in_Edges (decl_Metrics.defs ());
+gsi::Enum decl_ZeroDistanceMode ("db", "ZeroDistanceMode",
+ gsi::enum_const ("NeverIncludeZeroDistance", db::NeverIncludeZeroDistance,
+ "@brief Specifies that check functions should never include edges with zero distance.\n"
+ "With this specification, the check functions will ignore edges which are collinear or touch."
+ ) +
+ gsi::enum_const ("AlwaysIncludeZeroDistance", db::AlwaysIncludeZeroDistance,
+ "@hide\n"
+ "@brief Specifies that check functions should always include edges with zero distance\n"
+ "This mode has little practical value.\n"
+ ) +
+ gsi::enum_const ("IncludeZeroDistanceWhenTouching", db::IncludeZeroDistanceWhenTouching,
+ "@brief Specifies that check functions should include edges when they touch\n"
+ "With this specification, the check functions will also check edges if they share at least one common point. "
+ "This is the mode that includes checking the 'kissing corner' cases. This mode is default for version 0.29 and later. "
+ ) +
+ gsi::enum_const ("IncludeZeroDistanceWhenCollinearAndTouching", db::IncludeZeroDistanceWhenCollinearAndTouching,
+ "@brief Specifies that check functions should include edges when they are collinear and touch\n"
+ "With this specification, the check functions will also check edges if they share at least one common point and are collinear. "
+ "This is the mode that includes checking the 'kissing corner' cases when the kissing edges are collinear. This mode was default up to version 0.28. "
+ ) +
+ gsi::enum_const ("IncludeZeroDistanceWhenOverlapping", db::IncludeZeroDistanceWhenOverlapping,
+ "@brief Specifies that check functions should include edges when they overlap\n"
+ "With this specification, the check functions will also check edges which are collinear and share more than a single point. "
+ "This is the mode that excludes the 'kissing corner' cases."
+ ),
+ "@brief This class represents the zero_distance_mode type for \\Region#width and related checks.\n"
+ "This mode determines how edges with zero distance are treated in the DRC checks. Formally these edges do neither represent "
+ "a space other other relation as they do not face each other. There are three modes available to treat this boundary case: "
+ "Ignore such edges (\\NeverIncludeZeroDistance) or only include them "
+ "if they share at least one common point (\\IncludeZeroDistanceWhenTouching). The latter mode allows activating checks for "
+ "the 'kissing corner' case and is the default mode in most checks."
+ "\n"
+ "This enum has been introduced in version 0.29."
+);
+
+// Inject the Region::ZeroDistanceMode declarations into Region and Edges:
+// (Edges injection has to be done here because only here defs() is available)
+gsi::ClassExt inject_ZeroDistanceMode_in_Region (decl_ZeroDistanceMode.defs ());
+gsi::ClassExt inject_ZeroDistanceMode_in_Edges (decl_ZeroDistanceMode.defs ());
+
gsi::Enum decl_PropertyConstraint ("db", "PropertyConstraint",
gsi::enum_const ("IgnoreProperties", db::IgnoreProperties,
"@brief Specifies to ignore properties\n"
diff --git a/src/db/unit_tests/dbEdgePairRelationsTests.cc b/src/db/unit_tests/dbEdgePairRelationsTests.cc
index c0b3f918f..4b3d7f8c0 100644
--- a/src/db/unit_tests/dbEdgePairRelationsTests.cc
+++ b/src/db/unit_tests/dbEdgePairRelationsTests.cc
@@ -51,139 +51,139 @@ TEST(1)
TEST(2)
{
db::Edge output;
- EXPECT_EQ (euclidian_near_part_of_edge (true, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (0, 10), db::Point (100, 200)), &output), false);
- EXPECT_EQ (euclidian_near_part_of_edge (true, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (0, 200), db::Point (100, 200)), &output), false);
- EXPECT_EQ (euclidian_near_part_of_edge (true, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (0, 50), db::Point (100, 50)), &output), false);
- EXPECT_EQ (euclidian_near_part_of_edge (true, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (0, -50), db::Point (100, -50)), &output), true);
+ EXPECT_EQ (euclidian_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (0, 10), db::Point (100, 200)), &output), false);
+ EXPECT_EQ (euclidian_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (0, 200), db::Point (100, 200)), &output), false);
+ EXPECT_EQ (euclidian_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (0, 50), db::Point (100, 50)), &output), false);
+ EXPECT_EQ (euclidian_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (0, -50), db::Point (100, -50)), &output), true);
EXPECT_EQ (output.to_string (), "(0,-50;100,-50)");
- EXPECT_EQ (euclidian_near_part_of_edge (true, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (0, -50), db::Point (300, -50)), &output), true);
+ EXPECT_EQ (euclidian_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (0, -50), db::Point (300, -50)), &output), true);
EXPECT_EQ (output.to_string (), "(0,-50;187,-50)");
- EXPECT_EQ (euclidian_near_part_of_edge (true, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (100, -50), db::Point (300, -50)), &output), true);
+ EXPECT_EQ (euclidian_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (100, -50), db::Point (300, -50)), &output), true);
EXPECT_EQ (output.to_string (), "(100,-50;187,-50)");
- EXPECT_EQ (euclidian_near_part_of_edge (true, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (-300, -50), db::Point (300, -50)), &output), true);
+ EXPECT_EQ (euclidian_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (-300, -50), db::Point (300, -50)), &output), true);
EXPECT_EQ (output.to_string (), "(-87,-50;187,-50)");
- EXPECT_EQ (euclidian_near_part_of_edge (true, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (-300, -50), db::Point (0, -50)), &output), true);
+ EXPECT_EQ (euclidian_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (-300, -50), db::Point (0, -50)), &output), true);
EXPECT_EQ (output.to_string (), "(-87,-50;0,-50)");
- EXPECT_EQ (euclidian_near_part_of_edge (true, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (-300, -100), db::Point (300, -100)), &output), false);
- EXPECT_EQ (euclidian_near_part_of_edge (true, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (-300, 0), db::Point (300, -100)), &output), true);
+ EXPECT_EQ (euclidian_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (-300, -100), db::Point (300, -100)), &output), false);
+ EXPECT_EQ (euclidian_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (-300, 0), db::Point (300, -100)), &output), true);
EXPECT_EQ (output.to_string (), "(-94,-34;164,-77)");
- EXPECT_EQ (euclidian_near_part_of_edge (true, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (0, 0), db::Point (100, -200)), &output), true);
+ EXPECT_EQ (euclidian_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (0, 0), db::Point (100, -200)), &output), true);
EXPECT_EQ (output.to_string (), "(0,0;50,-100)");
- EXPECT_EQ (euclidian_near_part_of_edge (true, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (40, 0), db::Point (140, -200)), &output), true);
+ EXPECT_EQ (euclidian_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (40, 0), db::Point (140, -200)), &output), true);
EXPECT_EQ (output.to_string (), "(40,0;90,-100)");
- EXPECT_EQ (euclidian_near_part_of_edge (true, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (100, 0), db::Point (200, -200)), &output), true);
+ EXPECT_EQ (euclidian_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (100, 0), db::Point (200, -200)), &output), true);
EXPECT_EQ (output.to_string (), "(100,0;145,-89)");
- EXPECT_EQ (euclidian_near_part_of_edge (true, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (0, -200), db::Point (200, -200)), &output), false);
- EXPECT_EQ (euclidian_near_part_of_edge (true, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (0, 200), db::Point (200, -200)), &output), true);
+ EXPECT_EQ (euclidian_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (0, -200), db::Point (200, -200)), &output), false);
+ EXPECT_EQ (euclidian_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (0, 200), db::Point (200, -200)), &output), true);
EXPECT_EQ (output.to_string (), "(100,0;145,-89)");
- EXPECT_EQ (euclidian_near_part_of_edge (true, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (120, 200), db::Point (120, -200)), &output), true);
+ EXPECT_EQ (euclidian_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (120, 200), db::Point (120, -200)), &output), true);
EXPECT_EQ (output.to_string (), "(120,0;120,-98)");
- EXPECT_EQ (euclidian_near_part_of_edge (true, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (100, 200), db::Point (100, -200)), &output), true);
+ EXPECT_EQ (euclidian_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (100, 200), db::Point (100, -200)), &output), true);
EXPECT_EQ (output.to_string (), "(100,0;100,-100)");
- EXPECT_EQ (euclidian_near_part_of_edge (true, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (80, 200), db::Point (80, -200)), &output), true);
+ EXPECT_EQ (euclidian_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (80, 200), db::Point (80, -200)), &output), true);
EXPECT_EQ (output.to_string (), "(80,0;80,-100)");
- EXPECT_EQ (euclidian_near_part_of_edge (true, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (-80, 200), db::Point (-80, -200)), &output), true);
+ EXPECT_EQ (euclidian_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (-80, 200), db::Point (-80, -200)), &output), true);
EXPECT_EQ (output.to_string (), "(-80,0;-80,-60)");
- EXPECT_EQ (euclidian_near_part_of_edge (true, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (80, 0), db::Point (-200, -200)), &output), true);
+ EXPECT_EQ (euclidian_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (80, 0), db::Point (-200, -200)), &output), true);
EXPECT_EQ (output.to_string (), "(80,0;-45,-89)");
- EXPECT_EQ (euclidian_near_part_of_edge (true, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (-100, 200), db::Point (-100, -200)), &output), false);
- EXPECT_EQ (euclidian_near_part_of_edge (true, 100, db::Edge (), db::Edge (db::Point (-100, 200), db::Point (-100, -200)), &output), false);
- EXPECT_EQ (euclidian_near_part_of_edge (true, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (100, 50), db::Point (100, 50)), &output), false);
- EXPECT_EQ (euclidian_near_part_of_edge (true, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (100, -50), db::Point (100, -50)), &output), true);
+ EXPECT_EQ (euclidian_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (-100, 200), db::Point (-100, -200)), &output), false);
+ EXPECT_EQ (euclidian_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (), db::Edge (db::Point (-100, 200), db::Point (-100, -200)), &output), false);
+ EXPECT_EQ (euclidian_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (100, 50), db::Point (100, 50)), &output), false);
+ EXPECT_EQ (euclidian_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (100, -50), db::Point (100, -50)), &output), true);
EXPECT_EQ (output.to_string (), "(100,-50;100,-50)");
- EXPECT_EQ (euclidian_near_part_of_edge (true, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (50, -50), db::Point (50, -50)), &output), true);
+ EXPECT_EQ (euclidian_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (50, -50), db::Point (50, -50)), &output), true);
EXPECT_EQ (output.to_string (), "(50,-50;50,-50)");
- EXPECT_EQ (euclidian_near_part_of_edge (true, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (190, -50), db::Point (190, -50)), &output), false);
+ EXPECT_EQ (euclidian_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (190, -50), db::Point (190, -50)), &output), false);
}
TEST(3)
{
db::Edge output;
- EXPECT_EQ (square_near_part_of_edge (true, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (0, 200), db::Point (100, 200)), &output), false);
- EXPECT_EQ (square_near_part_of_edge (true, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (0, 50), db::Point (100, 50)), &output), false);
- EXPECT_EQ (square_near_part_of_edge (true, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (0, -50), db::Point (100, -50)), &output), true);
+ EXPECT_EQ (square_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (0, 200), db::Point (100, 200)), &output), false);
+ EXPECT_EQ (square_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (0, 50), db::Point (100, 50)), &output), false);
+ EXPECT_EQ (square_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (0, -50), db::Point (100, -50)), &output), true);
EXPECT_EQ (output.to_string (), "(0,-50;100,-50)");
- EXPECT_EQ (square_near_part_of_edge (true, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (0, -50), db::Point (300, -50)), &output), true);
+ EXPECT_EQ (square_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (0, -50), db::Point (300, -50)), &output), true);
EXPECT_EQ (output.to_string (), "(0,-50;200,-50)");
- EXPECT_EQ (square_near_part_of_edge (true, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (100, -50), db::Point (300, -50)), &output), true);
+ EXPECT_EQ (square_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (100, -50), db::Point (300, -50)), &output), true);
EXPECT_EQ (output.to_string (), "(100,-50;200,-50)");
- EXPECT_EQ (square_near_part_of_edge (true, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (-300, -50), db::Point (300, -50)), &output), true);
+ EXPECT_EQ (square_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (-300, -50), db::Point (300, -50)), &output), true);
EXPECT_EQ (output.to_string (), "(-100,-50;200,-50)");
- EXPECT_EQ (square_near_part_of_edge (true, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (-300, -50), db::Point (0, -50)), &output), true);
+ EXPECT_EQ (square_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (-300, -50), db::Point (0, -50)), &output), true);
EXPECT_EQ (output.to_string (), "(-100,-50;0,-50)");
- EXPECT_EQ (square_near_part_of_edge (true, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (-300, -100), db::Point (300, -100)), &output), false);
- EXPECT_EQ (square_near_part_of_edge (true, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (-300, 0), db::Point (300, -100)), &output), true);
+ EXPECT_EQ (square_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (-300, -100), db::Point (300, -100)), &output), false);
+ EXPECT_EQ (square_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (-300, 0), db::Point (300, -100)), &output), true);
EXPECT_EQ (output.to_string (), "(-100,-33;200,-83)");
- EXPECT_EQ (square_near_part_of_edge (true, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (0, 0), db::Point (100, -200)), &output), true);
+ EXPECT_EQ (square_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (0, 0), db::Point (100, -200)), &output), true);
EXPECT_EQ (output.to_string (), "(0,0;50,-100)");
- EXPECT_EQ (square_near_part_of_edge (true, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (40, 0), db::Point (140, -200)), &output), true);
+ EXPECT_EQ (square_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (40, 0), db::Point (140, -200)), &output), true);
EXPECT_EQ (output.to_string (), "(40,0;90,-100)");
- EXPECT_EQ (square_near_part_of_edge (true, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (100, 0), db::Point (200, -200)), &output), true);
+ EXPECT_EQ (square_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (100, 0), db::Point (200, -200)), &output), true);
EXPECT_EQ (output.to_string (), "(100,0;150,-100)");
- EXPECT_EQ (square_near_part_of_edge (true, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (0, -200), db::Point (200, -200)), &output), false);
- EXPECT_EQ (square_near_part_of_edge (true, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (0, 200), db::Point (200, -200)), &output), true);
+ EXPECT_EQ (square_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (0, -200), db::Point (200, -200)), &output), false);
+ EXPECT_EQ (square_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (0, 200), db::Point (200, -200)), &output), true);
EXPECT_EQ (output.to_string (), "(100,0;150,-100)");
- EXPECT_EQ (square_near_part_of_edge (true, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (120, 200), db::Point (120, -200)), &output), true);
+ EXPECT_EQ (square_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (120, 200), db::Point (120, -200)), &output), true);
EXPECT_EQ (output.to_string (), "(120,0;120,-100)");
- EXPECT_EQ (square_near_part_of_edge (true, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (100, 200), db::Point (100, -200)), &output), true);
+ EXPECT_EQ (square_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (100, 200), db::Point (100, -200)), &output), true);
EXPECT_EQ (output.to_string (), "(100,0;100,-100)");
- EXPECT_EQ (square_near_part_of_edge (true, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (80, 200), db::Point (80, -200)), &output), true);
+ EXPECT_EQ (square_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (80, 200), db::Point (80, -200)), &output), true);
EXPECT_EQ (output.to_string (), "(80,0;80,-100)");
- EXPECT_EQ (square_near_part_of_edge (true, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (-80, 200), db::Point (-80, -200)), &output), true);
+ EXPECT_EQ (square_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (-80, 200), db::Point (-80, -200)), &output), true);
EXPECT_EQ (output.to_string (), "(-80,0;-80,-100)");
- EXPECT_EQ (square_near_part_of_edge (true, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (80, 0), db::Point (-200, -200)), &output), true);
+ EXPECT_EQ (square_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (80, 0), db::Point (-200, -200)), &output), true);
EXPECT_EQ (output.to_string (), "(80,0;-60,-100)");
- EXPECT_EQ (square_near_part_of_edge (true, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (-100, 200), db::Point (-100, -200)), &output), true);
+ EXPECT_EQ (square_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (-100, 200), db::Point (-100, -200)), &output), true);
EXPECT_EQ (output.to_string (), "(-100,0;-100,-100)");
- EXPECT_EQ (square_near_part_of_edge (true, 100, db::Edge (), db::Edge (db::Point (-100, 200), db::Point (-100, -200)), &output), false);
- EXPECT_EQ (square_near_part_of_edge (true, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (100, 50), db::Point (100, 50)), &output), false);
- EXPECT_EQ (square_near_part_of_edge (true, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (100, -50), db::Point (100, -50)), &output), true);
+ EXPECT_EQ (square_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (), db::Edge (db::Point (-100, 200), db::Point (-100, -200)), &output), false);
+ EXPECT_EQ (square_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (100, 50), db::Point (100, 50)), &output), false);
+ EXPECT_EQ (square_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (100, -50), db::Point (100, -50)), &output), true);
EXPECT_EQ (output.to_string (), "(100,-50;100,-50)");
- EXPECT_EQ (square_near_part_of_edge (true, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (50, -50), db::Point (50, -50)), &output), true);
+ EXPECT_EQ (square_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (50, -50), db::Point (50, -50)), &output), true);
EXPECT_EQ (output.to_string (), "(50,-50;50,-50)");
- EXPECT_EQ (square_near_part_of_edge (true, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (190, -50), db::Point (190, -50)), &output), true);
+ EXPECT_EQ (square_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (190, -50), db::Point (190, -50)), &output), true);
EXPECT_EQ (output.to_string (), "(190,-50;190,-50)");
}
TEST(4)
{
db::Edge output;
- EXPECT_EQ (projected_near_part_of_edge (true, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (0, 200), db::Point (100, 200)), &output), false);
- EXPECT_EQ (projected_near_part_of_edge (true, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (0, 50), db::Point (100, 50)), &output), false);
- EXPECT_EQ (projected_near_part_of_edge (true, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (0, -50), db::Point (100, -50)), &output), true);
+ EXPECT_EQ (projected_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (0, 200), db::Point (100, 200)), &output), false);
+ EXPECT_EQ (projected_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (0, 50), db::Point (100, 50)), &output), false);
+ EXPECT_EQ (projected_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (0, -50), db::Point (100, -50)), &output), true);
EXPECT_EQ (output.to_string (), "(0,-50;100,-50)");
- EXPECT_EQ (projected_near_part_of_edge (true, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (0, -50), db::Point (300, -50)), &output), true);
+ EXPECT_EQ (projected_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (0, -50), db::Point (300, -50)), &output), true);
EXPECT_EQ (output.to_string (), "(0,-50;100,-50)");
- EXPECT_EQ (projected_near_part_of_edge (true, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (100, -50), db::Point (300, -50)), &output), false);
- EXPECT_EQ (projected_near_part_of_edge (true, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (-300, -50), db::Point (300, -50)), &output), true);
+ EXPECT_EQ (projected_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (100, -50), db::Point (300, -50)), &output), false);
+ EXPECT_EQ (projected_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (-300, -50), db::Point (300, -50)), &output), true);
EXPECT_EQ (output.to_string (), "(0,-50;100,-50)");
- EXPECT_EQ (projected_near_part_of_edge (true, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (-300, -50), db::Point (0, -50)), &output), false);
- EXPECT_EQ (projected_near_part_of_edge (true, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (-300, -100), db::Point (300, -100)), &output), false);
- EXPECT_EQ (projected_near_part_of_edge (true, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (-300, 0), db::Point (300, -100)), &output), true);
+ EXPECT_EQ (projected_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (-300, -50), db::Point (0, -50)), &output), false);
+ EXPECT_EQ (projected_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (-300, -100), db::Point (300, -100)), &output), false);
+ EXPECT_EQ (projected_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (-300, 0), db::Point (300, -100)), &output), true);
EXPECT_EQ (output.to_string (), "(0,-50;100,-67)");
- EXPECT_EQ (projected_near_part_of_edge (true, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (0, 0), db::Point (100, -200)), &output), true);
+ EXPECT_EQ (projected_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (0, 0), db::Point (100, -200)), &output), true);
EXPECT_EQ (output.to_string (), "(0,0;50,-100)");
- EXPECT_EQ (projected_near_part_of_edge (true, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (40, 0), db::Point (140, -200)), &output), true);
+ EXPECT_EQ (projected_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (40, 0), db::Point (140, -200)), &output), true);
EXPECT_EQ (output.to_string (), "(40,0;90,-100)");
- EXPECT_EQ (projected_near_part_of_edge (true, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (100, 0), db::Point (200, -200)), &output), false);
- EXPECT_EQ (projected_near_part_of_edge (true, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (0, -200), db::Point (200, -200)), &output), false);
- EXPECT_EQ (projected_near_part_of_edge (true, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (0, 200), db::Point (200, -200)), &output), false);
- EXPECT_EQ (projected_near_part_of_edge (true, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (120, 200), db::Point (120, -200)), &output), false);
- EXPECT_EQ (projected_near_part_of_edge (true, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (100, 200), db::Point (100, -200)), &output), true);
+ EXPECT_EQ (projected_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (100, 0), db::Point (200, -200)), &output), false);
+ EXPECT_EQ (projected_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (0, -200), db::Point (200, -200)), &output), false);
+ EXPECT_EQ (projected_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (0, 200), db::Point (200, -200)), &output), false);
+ EXPECT_EQ (projected_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (120, 200), db::Point (120, -200)), &output), false);
+ EXPECT_EQ (projected_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (100, 200), db::Point (100, -200)), &output), true);
EXPECT_EQ (output.to_string (), "(100,0;100,-100)");
- EXPECT_EQ (projected_near_part_of_edge (true, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (80, 200), db::Point (80, -200)), &output), true);
+ EXPECT_EQ (projected_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (80, 200), db::Point (80, -200)), &output), true);
EXPECT_EQ (output.to_string (), "(80,0;80,-100)");
- EXPECT_EQ (projected_near_part_of_edge (true, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (-80, 200), db::Point (-80, -200)), &output), false);
- EXPECT_EQ (projected_near_part_of_edge (true, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (80, 0), db::Point (-200, -200)), &output), true);
+ EXPECT_EQ (projected_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (-80, 200), db::Point (-80, -200)), &output), false);
+ EXPECT_EQ (projected_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (80, 0), db::Point (-200, -200)), &output), true);
EXPECT_EQ (output.to_string (), "(80,0;0,-57)");
- EXPECT_EQ (projected_near_part_of_edge (true, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (-100, 200), db::Point (-100, -200)), &output), false);
- EXPECT_EQ (projected_near_part_of_edge (true, 100, db::Edge (), db::Edge (db::Point (-100, 200), db::Point (-100, -200)), &output), false);
- EXPECT_EQ (projected_near_part_of_edge (true, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (100, 50), db::Point (100, 50)), &output), false);
- EXPECT_EQ (projected_near_part_of_edge (true, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (100, -50), db::Point (100, -50)), &output), true);
+ EXPECT_EQ (projected_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (-100, 200), db::Point (-100, -200)), &output), false);
+ EXPECT_EQ (projected_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (), db::Edge (db::Point (-100, 200), db::Point (-100, -200)), &output), false);
+ EXPECT_EQ (projected_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (100, 50), db::Point (100, 50)), &output), false);
+ EXPECT_EQ (projected_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (100, -50), db::Point (100, -50)), &output), true);
EXPECT_EQ (output.to_string (), "(100,-50;100,-50)");
- EXPECT_EQ (projected_near_part_of_edge (true, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (50, -50), db::Point (50, -50)), &output), true);
+ EXPECT_EQ (projected_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (50, -50), db::Point (50, -50)), &output), true);
EXPECT_EQ (output.to_string (), "(50,-50;50,-50)");
- EXPECT_EQ (projected_near_part_of_edge (true, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (190, -50), db::Point (190, -50)), &output), false);
+ EXPECT_EQ (projected_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (190, -50), db::Point (190, -50)), &output), false);
}
TEST(5)
@@ -291,7 +291,7 @@ TEST(7)
EXPECT_EQ (output.first ().to_string () + ":" + output.second ().to_string (), "(0,0;0,10):(1,30;1,20)");
res = f.check (db::Edge (db::Point (0, 0), db::Point (0, 10)), db::Edge (db::Point (-1, 30), db::Point (-1, 20)), &output);
EXPECT_EQ (res, false);
- f.set_include_zero (false);
+ f.set_zero_distance_mode (db::IncludeZeroDistanceWhenTouching);
res = f.check (db::Edge (db::Point (0, 0), db::Point (0, 10)), db::Edge (db::Point (0, 30), db::Point (0, 20)), &output);
EXPECT_EQ (res, false);
res = f.check (db::Edge (db::Point (0, 0), db::Point (0, 10)), db::Edge (db::Point (1, 30), db::Point (1, 20)), &output);
@@ -300,7 +300,7 @@ TEST(7)
res = f.check (db::Edge (db::Point (0, 0), db::Point (0, 10)), db::Edge (db::Point (-1, 30), db::Point (-1, 20)), &output);
EXPECT_EQ (res, false);
- f.set_include_zero (true);
+ f.set_zero_distance_mode (db::AlwaysIncludeZeroDistance);
res = f.check (db::Edge (db::Point (0, 0), db::Point (0, 10)), db::Edge (db::Point (0, 300), db::Point (0, -200)), &output);
EXPECT_EQ (res, true);
EXPECT_EQ (output.first ().to_string () + ":" + output.second ().to_string (), "(0,0;0,10):(0,110;0,-100)");
@@ -309,7 +309,7 @@ TEST(7)
EXPECT_EQ (output.first ().to_string () + ":" + output.second ().to_string (), "(0,0;0,10):(1,110;1,-100)");
f.set_metrics (db::Square);
- f.set_include_zero (true);
+ f.set_zero_distance_mode (db::AlwaysIncludeZeroDistance);
res = f.check (db::Edge (db::Point (0, 0), db::Point (0, 10)), db::Edge (db::Point (0, 30), db::Point (0, 20)), &output);
EXPECT_EQ (res, true);
EXPECT_EQ (output.first ().to_string () + ":" + output.second ().to_string (), "(0,0;0,10):(0,30;0,20)");
@@ -318,7 +318,7 @@ TEST(7)
EXPECT_EQ (output.first ().to_string () + ":" + output.second ().to_string (), "(0,0;0,10):(1,30;1,20)");
res = f.check (db::Edge (db::Point (0, 0), db::Point (0, 10)), db::Edge (db::Point (-1, 30), db::Point (-1, 20)), &output);
EXPECT_EQ (res, false);
- f.set_include_zero (false);
+ f.set_zero_distance_mode (db::IncludeZeroDistanceWhenTouching);
res = f.check (db::Edge (db::Point (0, 0), db::Point (0, 10)), db::Edge (db::Point (0, 30), db::Point (0, 20)), &output);
EXPECT_EQ (res, false);
res = f.check (db::Edge (db::Point (0, 0), db::Point (0, 10)), db::Edge (db::Point (1, 30), db::Point (1, 20)), &output);
@@ -327,7 +327,7 @@ TEST(7)
res = f.check (db::Edge (db::Point (0, 0), db::Point (0, 10)), db::Edge (db::Point (-1, 30), db::Point (-1, 20)), &output);
EXPECT_EQ (res, false);
- f.set_include_zero (true);
+ f.set_zero_distance_mode (db::AlwaysIncludeZeroDistance);
res = f.check (db::Edge (db::Point (0, 0), db::Point (0, 10)), db::Edge (db::Point (0, 300), db::Point (0, -200)), &output);
EXPECT_EQ (res, true);
EXPECT_EQ (output.first ().to_string () + ":" + output.second ().to_string (), "(0,0;0,10):(0,110;0,-100)");
@@ -336,7 +336,7 @@ TEST(7)
EXPECT_EQ (output.first ().to_string () + ":" + output.second ().to_string (), "(0,0;0,10):(1,110;1,-100)");
f.set_metrics (db::Projection);
- f.set_include_zero (true);
+ f.set_zero_distance_mode (db::AlwaysIncludeZeroDistance);
res = f.check (db::Edge (db::Point (0, 0), db::Point (0, 10)), db::Edge (db::Point (0, 30), db::Point (0, -20)), &output);
EXPECT_EQ (res, true);
EXPECT_EQ (output.first ().to_string () + ":" + output.second ().to_string (), "(0,0;0,10):(0,10;0,0)");
@@ -345,7 +345,7 @@ TEST(7)
EXPECT_EQ (output.first ().to_string () + ":" + output.second ().to_string (), "(0,0;0,10):(1,10;1,0)");
res = f.check (db::Edge (db::Point (0, 0), db::Point (0, 10)), db::Edge (db::Point (-1, 30), db::Point (-1, -20)), &output);
EXPECT_EQ (res, false);
- f.set_include_zero (false);
+ f.set_zero_distance_mode (db::IncludeZeroDistanceWhenTouching);
res = f.check (db::Edge (db::Point (0, 0), db::Point (0, 10)), db::Edge (db::Point (0, 30), db::Point (0, 11)), &output);
EXPECT_EQ (res, false);
res = f.check (db::Edge (db::Point (0, 0), db::Point (0, 10)), db::Edge (db::Point (1, 30), db::Point (1, -20)), &output);
@@ -361,7 +361,7 @@ TEST(8_KissingCornerProblem)
// if the projection is >0.
db::EdgeRelationFilter f (db::WidthRelation, 10);
- f.set_include_zero (false);
+ f.set_zero_distance_mode (db::IncludeZeroDistanceWhenTouching);
db::EdgePair output;
bool res;
@@ -382,8 +382,39 @@ 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_zero_distance_mode (db::IncludeZeroDistanceWhenOverlapping);
+
+ 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_zero_distance_mode (db::NeverIncludeZeroDistance);
+
+ 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, false);
+ 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 = db::EdgeRelationFilter (db::SpaceRelation, 10);
- f.set_include_zero (false);
+ f.set_zero_distance_mode (db::IncludeZeroDistanceWhenTouching);
f.set_metrics (db::Euclidian);
res = f.check (db::Edge (db::Point (0, 100), db::Point (0, 0)), db::Edge (db::Point (0, 101), db::Point (0, 201)), &output);
@@ -401,4 +432,188 @@ TEST(8_KissingCornerProblem)
EXPECT_EQ (output.first ().to_string () + ":" + output.second ().to_string (), "(0,10;0,0):(0,-10;0,0)");
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_zero_distance_mode (db::IncludeZeroDistanceWhenOverlapping);
+
+ 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_zero_distance_mode (db::NeverIncludeZeroDistance);
+
+ f.set_metrics (db::Euclidian);
+ 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, false);
+ 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);
+}
+
+TEST(9_KissingCornerProblemSquareMetrics)
+{
+ // The kissing corner problem is solved by allowing distance-0 width and space relations and checking them
+ // if the projection is >0.
+
+ db::EdgeRelationFilter f (db::WidthRelation, 10);
+ f.set_zero_distance_mode (db::IncludeZeroDistanceWhenTouching);
+ db::EdgePair output;
+ bool res;
+
+ f.set_metrics (db::Square);
+ 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, true);
+ EXPECT_EQ (output.first ().to_string () + ":" + output.second ().to_string (), "(0,90;0,100):(0,110;0,100)");
+ 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, true);
+ EXPECT_EQ (output.first ().to_string () + ":" + output.second ().to_string (), "(0,0;0,10):(0,0;0,-10)");
+ 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_zero_distance_mode (db::NeverIncludeZeroDistance);
+
+ 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, false);
+ 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 = db::EdgeRelationFilter (db::SpaceRelation, 10);
+ f.set_zero_distance_mode (db::IncludeZeroDistanceWhenTouching);
+
+ f.set_metrics (db::Square);
+ 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, true);
+ EXPECT_EQ (output.first ().to_string () + ":" + output.second ().to_string (), "(0,100;0,90):(0,100;0,110)");
+ 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, true);
+ EXPECT_EQ (output.first ().to_string () + ":" + output.second ().to_string (), "(0,10;0,0):(0,-10;0,0)");
+ 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_zero_distance_mode (db::NeverIncludeZeroDistance);
+
+ 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, false);
+ 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);
+}
+
+TEST(10_KissingCornerProblemProjectionMetrics)
+{
+ // The kissing corner problem is solved by allowing distance-0 width and space relations and checking them
+ // if the projection is >0. It is not effective in projection metrics as there is no overlap.
+
+ db::EdgeRelationFilter f (db::WidthRelation, 10);
+ f.set_zero_distance_mode (db::IncludeZeroDistanceWhenTouching);
+ db::EdgePair output;
+ bool res;
+
+ f.set_metrics (db::Projection);
+ 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,50;0,100):(0,100;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_zero_distance_mode (db::NeverIncludeZeroDistance);
+
+ 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, false);
+ 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 = db::EdgeRelationFilter (db::SpaceRelation, 10);
+ f.set_zero_distance_mode (db::IncludeZeroDistanceWhenTouching);
+
+ f.set_metrics (db::Projection);
+ 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,50):(0,50;0,100)");
+ 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_zero_distance_mode (db::NeverIncludeZeroDistance);
+
+ 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, false);
+ 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);
}
diff --git a/src/db/unit_tests/dbLayoutDiffTests.cc b/src/db/unit_tests/dbLayoutDiffTests.cc
index 87ef5f1ba..6fb0d413b 100644
--- a/src/db/unit_tests/dbLayoutDiffTests.cc
+++ b/src/db/unit_tests/dbLayoutDiffTests.cc
@@ -38,6 +38,7 @@ public:
std::string text () const { return m_os.str (); }
void clear () { m_os.str (std::string ()); }
void dbu_differs (double dbu_a, double dbu_b);
+ void layout_meta_info_differs (const std::string &, const tl::Variant &, const tl::Variant &);
void layer_in_a_only (const db::LayerProperties &la);
void layer_in_b_only (const db::LayerProperties &lb);
void layer_name_differs (const db::LayerProperties &la, const db::LayerProperties &lb);
@@ -45,6 +46,7 @@ public:
void cell_in_b_only (const std::string &cellname, db::cell_index_type ci);
void cell_name_differs (const std::string &cellname_a, db::cell_index_type cia, const std::string &cellname_b, db::cell_index_type cib);
void begin_cell (const std::string &cellname, db::cell_index_type cia, db::cell_index_type cib);
+ void cell_meta_info_differs (const std::string &, const tl::Variant &, const tl::Variant &);
void bbox_differs (const db::Box &ba, const db::Box &bb);
void begin_inst_differences ();
void instances_in_a (const std::vector &insts_a, const std::vector &cell_names, const db::PropertiesRepository &props);
@@ -155,6 +157,12 @@ TestDifferenceReceiver::dbu_differs (double dbu_a, double dbu_b)
m_os << "layout_diff: database units differ " << dbu_a << " vs. " << dbu_b << std::endl;
}
+void
+TestDifferenceReceiver::layout_meta_info_differs (const std::string &name, const tl::Variant &va, const tl::Variant &vb)
+{
+ m_os << "layout_diff: global meta info differs " << name << ": " << va.to_string () << " vs. " << vb.to_string () << std::endl;
+}
+
void
TestDifferenceReceiver::layer_in_a_only (const db::LayerProperties &la)
{
@@ -204,6 +212,12 @@ TestDifferenceReceiver::begin_cell (const std::string &cellname, db::cell_index_
m_cellname = cellname;
}
+void
+TestDifferenceReceiver::cell_meta_info_differs (const std::string &name, const tl::Variant &va, const tl::Variant &vb)
+{
+ m_os << "layout_diff: cell meta info differs for cell " << m_cellname << " - " << name << ": " << va.to_string () << " vs. " << vb.to_string () << std::endl;
+}
+
void
TestDifferenceReceiver::begin_inst_differences ()
{
@@ -1704,4 +1718,46 @@ TEST(8)
);
}
+// meta info
+TEST(9)
+{
+ db::Layout a;
+ db::cell_index_type caa = a.add_cell ("A");
+ db::cell_index_type cab = a.add_cell ("B");
+ db::Layout b;
+ db::cell_index_type cba = b.add_cell ("A");
+ db::cell_index_type cbb = b.add_cell ("B");
+
+ a.add_meta_info ("x", db::MetaInfo ("", 17.0, true));
+ a.add_meta_info ("y", db::MetaInfo ("", -1.0, false)); // not persisted
+ a.add_meta_info ("z", db::MetaInfo ("", -1.0, true));
+ a.add_meta_info (caa, "a1", db::MetaInfo ("", "a", true));
+ a.add_meta_info (caa, "a2", db::MetaInfo ("", 42, false)); // not persisted
+ a.add_meta_info (caa, "a3", db::MetaInfo ("", 41, true));
+ a.add_meta_info (cab, "b1", db::MetaInfo ("", "b", true));
+ a.add_meta_info (cab, "b2", db::MetaInfo ("", 3, false)); // not persisted
+ a.add_meta_info (cab, "b3", db::MetaInfo ("", "q", true));
+
+ b.add_meta_info ("x", db::MetaInfo ("", 21.0, true));
+ b.add_meta_info ("y", db::MetaInfo ("", -1.0, true));
+ b.add_meta_info (cba, "a1", db::MetaInfo ("", "aa", true));
+ b.add_meta_info (cba, "a2", db::MetaInfo ("", 42, true));
+ b.add_meta_info (cbb, "b1", db::MetaInfo ("", "bb", true));
+ b.add_meta_info (cbb, "b2", db::MetaInfo ("", 3, true));
+
+ TestDifferenceReceiver r;
+ bool eq = db::compare_layouts (a, b, db::layout_diff::f_verbose | db::layout_diff::f_with_meta, 0, r);
+ EXPECT_EQ (eq, false);
+ EXPECT_EQ (r.text (),
+ "layout_diff: global meta info differs x: 17 vs. 21\n"
+ "layout_diff: global meta info differs y: nil vs. -1\n"
+ "layout_diff: global meta info differs z: -1 vs. nil\n"
+ "layout_diff: cell meta info differs for cell A - a1: a vs. aa\n"
+ "layout_diff: cell meta info differs for cell A - a2: nil vs. 42\n"
+ "layout_diff: cell meta info differs for cell A - a3: 41 vs. nil\n"
+ "layout_diff: cell meta info differs for cell B - b1: b vs. bb\n"
+ "layout_diff: cell meta info differs for cell B - b2: nil vs. 3\n"
+ "layout_diff: cell meta info differs for cell B - b3: q vs. nil\n"
+ );
+}
diff --git a/src/doc/doc/about/drc_ref_layer.xml b/src/doc/doc/about/drc_ref_layer.xml
index 2e5e6b2b9..c8f124c5c 100644
--- a/src/doc/doc/about/drc_ref_layer.xml
+++ b/src/doc/doc/about/drc_ref_layer.xml
@@ -2894,7 +2894,45 @@ The following image shows the effect of the separation check (input1: red, input
-
opposite and rectangle error filtering
+Touching shapes
+
+Like width and space, the separation check also supports the "without_touching_corners" option.
+
+This option will turn off errors that arise due to
+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_corners" option.
+The white line at the top of the bottom red shape is actually an edge pair indicating
+the zero-distance violation of the separation check:
+
+
+
+ |
+ |
+
+
+
+Another option is "without_touching_edges" which turns off errors that arise
+at coincident edges. Formally such edges represent a zero-distance situation, hence
+are flagged by default. Turning off the check in this case can be helpful when
+separating a layer into two parts (e.g. thin/wide metal separation) and an error
+between touching regions is not desired.
+
+The "without_touching_edges" option is a stronger version of "without_touching_corners" and
+makes sense only for two-layer checks.
+
+The following images illustrate the effect of the "without_touching_edges" option:
+
+
+
+ |
+ |
+
+
+
+
Opposite and rectangle error filtering
The options for the separation check are those available for the width or space
method plus opposite and rectangle error filtering.
@@ -3405,10 +3443,15 @@ each other is more or equal than min and less than max
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".
-
transparent : performs the check without shielding (polygon layers only)
-shielded : performs the check with shielding (polygon layers only)
+without_touching_corners : With this option present, touching corners (aka "kissing
+corners") will not yield errors. The default is to produce errors in these cases.
+without_touching_edges : With this option present, coincident edges will not yield errors.
+This is a stronger version of "without_touching_corners" and makes sense only for two-layer checks
+or raw-mode input layers. It is listed here for completeness.
+transparent : Performs the check without shielding (polygon layers only)
+shielded : Performs the check with shielding (polygon layers only)
props_eq , props_ne , props_copy : (only props_copy applies to width check) -
-see "Properties constraints" below.
+See "Properties constraints" below.
Note that without the angle_limit, acute corners will always be reported, since two
@@ -3509,6 +3552,22 @@ shape's properties to the output too:
space_not_connected = metal1_nets.space(0.4.um, props_ne + props_copy)
space_connected = metal1_nets.space(0.4.um, props_eq + props_copy)
+
+
Touching shapes
+
+The "without_touching_corners" 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_corners" option:
+
+
+
+ |
+ |
+
+
"with_angle" - Selects edges by their angle
diff --git a/src/doc/doc/images/drc_separation12.png b/src/doc/doc/images/drc_separation12.png
new file mode 100644
index 000000000..70847f791
Binary files /dev/null and b/src/doc/doc/images/drc_separation12.png differ
diff --git a/src/doc/doc/images/drc_separation13.png b/src/doc/doc/images/drc_separation13.png
new file mode 100644
index 000000000..00de3a91c
Binary files /dev/null and b/src/doc/doc/images/drc_separation13.png differ
diff --git a/src/doc/doc/images/drc_separation14.png b/src/doc/doc/images/drc_separation14.png
new file mode 100644
index 000000000..e9a4cca31
Binary files /dev/null and b/src/doc/doc/images/drc_separation14.png differ
diff --git a/src/doc/doc/images/drc_width5.png b/src/doc/doc/images/drc_width5.png
new file mode 100644
index 000000000..9bb781814
Binary files /dev/null and b/src/doc/doc/images/drc_width5.png differ
diff --git a/src/doc/doc/images/drc_width6.png b/src/doc/doc/images/drc_width6.png
new file mode 100644
index 000000000..50c558bfe
Binary files /dev/null and b/src/doc/doc/images/drc_width6.png differ
diff --git a/src/doc/docDRCLVSResources.qrc b/src/doc/docDRCLVSResources.qrc
index e91766fe5..e4449b7ed 100644
--- a/src/doc/docDRCLVSResources.qrc
+++ b/src/doc/docDRCLVSResources.qrc
@@ -4,6 +4,8 @@
doc/images/drc_width2.png
doc/images/drc_width3.png
doc/images/drc_width4.png
+ doc/images/drc_width5.png
+ doc/images/drc_width6.png
doc/images/drc_width1u.png
doc/images/drc_width2u.png
doc/images/drc_width3u.png
@@ -29,6 +31,9 @@
doc/images/drc_separation9.png
doc/images/drc_separation10.png
doc/images/drc_separation11.png
+ doc/images/drc_separation12.png
+ doc/images/drc_separation13.png
+ doc/images/drc_separation14.png
doc/images/drc_raw1.png
doc/images/drc_raw2.png
doc/images/drc_raw3.png
diff --git a/src/drc/drc/built-in-macros/_drc_cop_integration.rb b/src/drc/drc/built-in-macros/_drc_cop_integration.rb
index 8eebae6fb..40b93cbfe 100644
--- a/src/drc/drc/built-in-macros/_drc_cop_integration.rb
+++ b/src/drc/drc/built-in-macros/_drc_cop_integration.rb
@@ -1485,6 +1485,7 @@ CODE
shielded = nil
opposite_filter = RBA::Region::NoOppositeFilter
rect_filter = RBA::Region::NoRectFilter
+ zd_mode = RBA::Region::IncludeZeroDistanceWhenTouching
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?(DRCZeroDistanceMode)
+ zd_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 << zd_mode
if :#{f} == :width || :#{f} == :space || :#{f} == :notch || :#{f} == :isolated
other && raise("No other layer must be specified for a single-layer check")
diff --git a/src/drc/drc/built-in-macros/_drc_engine.rb b/src/drc/drc/built-in-macros/_drc_engine.rb
index 6cb79e63f..14eb0c842 100644
--- a/src/drc/drc/built-in-macros/_drc_engine.rb
+++ b/src/drc/drc/built-in-macros/_drc_engine.rb
@@ -322,6 +322,18 @@ module DRC
end
end
+ def without_touching_corners(f = true)
+ self._context("without_touching_corners") do
+ DRCZeroDistanceMode::new(f ? RBA::Region::IncludeZeroDistanceWhenOverlapping : RBA::Region::IncludeZeroDistanceWhenTouching)
+ end
+ end
+
+ def without_touching_edges(f = true)
+ self._context("without_touching_edges") do
+ DRCZeroDistanceMode::new(f ? RBA::Region::NeverIncludeZeroDistance : RBA::Region::IncludeZeroDistanceWhenTouching)
+ end
+ end
+
def euclidian
DRCMetrics::new(RBA::Region::Euclidian)
end
diff --git a/src/drc/drc/built-in-macros/_drc_layer.rb b/src/drc/drc/built-in-macros/_drc_layer.rb
index ee4ef6803..ffa80b943 100644
--- a/src/drc/drc/built-in-macros/_drc_layer.rb
+++ b/src/drc/drc/built-in-macros/_drc_layer.rb
@@ -3687,10 +3687,15 @@ 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_corners @/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 without_touching_edges @/b: With this option present, coincident edges will not yield errors.
+ # This is a stronger version of "without_touching_corners" and makes sense only for two-layer checks
+ # or raw-mode input layers. It is listed here for completeness. @/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 +3797,21 @@ CODE
# space_connected = metal1_nets.space(0.4.um, props_eq + props_copy)
# @/code
#
+ # @h3 Touching shapes @/h3
+ #
+ # The "without_touching_corners" 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_corners" option:
+ #
+ # @table
+ # @tr
+ # @td @img(/images/drc_width5.png) @/td
+ # @td @img(/images/drc_width6.png) @/td
+ # @/tr
+ # @/table
# %DRC%
# @name space
@@ -3912,7 +3932,45 @@ 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_corners" option.
+ #
+ # This option will turn off errors that arise due to
+ # 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_corners" option.
+ # The white line at the top of the bottom red shape is actually an edge pair indicating
+ # the zero-distance violation of the separation check:
+ #
+ # @table
+ # @tr
+ # @td @img(/images/drc_separation12.png) @/td
+ # @td @img(/images/drc_separation13.png) @/td
+ # @/tr
+ # @/table
+ #
+ # Another option is "without_touching_edges" which turns off errors that arise
+ # at coincident edges. Formally such edges represent a zero-distance situation, hence
+ # are flagged by default. Turning off the check in this case can be helpful when
+ # separating a layer into two parts (e.g. thin/wide metal separation) and an error
+ # between touching regions is not desired.
+ #
+ # The "without_touching_edges" option is a stronger version of "without_touching_corners" and
+ # makes sense only for two-layer checks.
+ #
+ # The following images illustrate the effect of the "without_touching_edges" option:
+ #
+ # @table
+ # @tr
+ # @td @img(/images/drc_separation12.png) @/td
+ # @td @img(/images/drc_separation14.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 +4179,7 @@ CODE
opposite_filter = RBA::Region::NoOppositeFilter
rect_filter = RBA::Region::NoRectFilter
prop_constraint = RBA::Region::IgnoreProperties
+ zd_mode = RBA::Region::IncludeZeroDistanceWhenTouching
n = 1
args.each do |a|
@@ -4132,6 +4191,8 @@ CODE
negative = true
elsif a.is_a?(DRCPropertiesConstraint)
prop_constraint = a.value
+ elsif a.is_a?(DRCZeroDistanceMode)
+ zd_mode = a.value
elsif a.is_a?(DRCOppositeErrorFilter)
opposite_filter = a.value
elsif a.is_a?(DRCRectangleErrorFilter)
@@ -4185,6 +4246,8 @@ CODE
raise("A rectangle error filter can only be used for polygon layers")
end
+ args << zd_mode
+
border = (metrics == RBA::Region::Square ? value * 1.5 : value)
if :#{f} == :width || :#{f} == :space || :#{f} == :notch || :#{f} == :isolated
diff --git a/src/drc/drc/built-in-macros/_drc_netter.rb b/src/drc/drc/built-in-macros/_drc_netter.rb
index 99823336b..1985cc67c 100644
--- a/src/drc/drc/built-in-macros/_drc_netter.rb
+++ b/src/drc/drc/built-in-macros/_drc_netter.rb
@@ -702,7 +702,8 @@ module DRC
@l2n = RBA::LayoutToNetlist::new(@engine._dss)
else
layout = @engine.source.layout
- @l2n = RBA::LayoutToNetlist::new(layout.top_cell.name, layout.dbu)
+ cell_name = @engine.source.cell_name
+ @l2n = RBA::LayoutToNetlist::new(cell_name, layout.dbu)
end
@l2n.name = "DRC"
diff --git a/src/drc/drc/built-in-macros/_drc_tags.rb b/src/drc/drc/built-in-macros/_drc_tags.rb
index 495f458d1..fd774ebd6 100644
--- a/src/drc/drc/built-in-macros/_drc_tags.rb
+++ b/src/drc/drc/built-in-macros/_drc_tags.rb
@@ -95,6 +95,16 @@ module DRC
end
end
+ # A wrapper for the "zero distance mode" for
+ # the DRC functions. The purpose of this class
+ # is to identify the value by the class.
+ class DRCZeroDistanceMode
+ 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.
diff --git a/src/drc/unit_tests/drcSimpleTests.cc b/src/drc/unit_tests/drcSimpleTests.cc
index 62d620168..1362acee0 100644
--- a/src/drc/unit_tests/drcSimpleTests.cc
+++ b/src/drc/unit_tests/drcSimpleTests.cc
@@ -1617,3 +1617,58 @@ TEST(89_deep_with_mag_cop_size_aniso)
run_test (_this, "89", true);
}
+TEST(90_zero_distance_mode)
+{
+ run_test (_this, "90", false);
+}
+
+TEST(90d_zero_distance_mode)
+{
+ run_test (_this, "90", true);
+}
+
+TEST(91_zero_distance_mode)
+{
+ run_test (_this, "91", false);
+}
+
+TEST(91d_zero_distance_mode)
+{
+ run_test (_this, "91", true);
+}
+
+TEST(92_issue1594_dual_top)
+{
+ std::string rs = tl::testdata ();
+ rs += "/drc/issue_1594.drc";
+
+ std::string input = tl::testdata ();
+ input += "/drc/issue_1594.gds";
+
+ std::string au = tl::testdata ();
+ au += "/drc/issue_1594_au.cir";
+
+ std::string output = this->tmp_file ("tmp.cir");
+
+ {
+ // Set some variables
+ lym::Macro config;
+ config.set_text (tl::sprintf (
+ "$drc_force_gc = true\n"
+ "$drc_test_source = '%s'\n"
+ "$drc_test_target = '%s'\n"
+ , input, output)
+ );
+ config.set_interpreter (lym::Macro::Ruby);
+ EXPECT_EQ (config.run (), 0);
+ }
+
+ lym::Macro drc;
+ drc.load_from (rs);
+ EXPECT_EQ (drc.run (), 0);
+
+ // verify
+
+ CHECKPOINT ();
+ compare_netlists (_this, output, au);
+}
diff --git a/src/edt/edt/EditorOptionsInst.ui b/src/edt/edt/EditorOptionsInst.ui
index 86b3e2c56..5d5c8a5aa 100644
--- a/src/edt/edt/EditorOptionsInst.ui
+++ b/src/edt/edt/EditorOptionsInst.ui
@@ -548,6 +548,23 @@
+
+ scrollArea
+ lib_cbx
+ browse_pb
+ cell_le
+ place_origin_cb
+ scale_le
+ angle_le
+ mirror_cbx
+ array_grp
+ rows_le
+ columns_le
+ row_x_le
+ row_y_le
+ column_x_le
+ column_y_le
+
diff --git a/src/edt/edt/edtPCellParametersPage.cc b/src/edt/edt/edtPCellParametersPage.cc
index a79b6a1d1..2e5488d2e 100644
--- a/src/edt/edt/edtPCellParametersPage.cc
+++ b/src/edt/edt/edtPCellParametersPage.cc
@@ -41,6 +41,8 @@
#include
#include
#include
+#include
+#include
namespace edt
{
@@ -294,32 +296,32 @@ PCellParametersPage::setup (lay::LayoutViewBase *view, int cv_index, const db::P
mp_parameters_area = new QScrollArea (this);
mp_parameters_area->setFrameShape (QFrame::NoFrame);
+ mp_parameters_area->setWidgetResizable (true);
QGridLayout *frame_layout = dynamic_cast (QFrame::layout ());
frame_layout->addWidget (mp_parameters_area, 2, 0, 1, 1);
frame_layout->setRowStretch (2, 1);
- QFrame *fi = new QFrame (mp_parameters_area);
- QWidget *inner_frame = fi;
- fi->setFrameShape (QFrame::NoFrame);
+ mp_main_frame = new QFrame (mp_parameters_area);
+ mp_main_frame->setFrameShape (QFrame::NoFrame);
setFrameShape (QFrame::NoFrame);
- QGridLayout *inner_grid = new QGridLayout (inner_frame);
- inner_frame->setLayout (inner_grid);
+ QGridLayout *main_grid = new QGridLayout (mp_main_frame);
+ mp_main_frame->setLayout (main_grid);
if (m_dense) {
- inner_grid->setContentsMargins (4, 4, 4, 4);
- inner_grid->setHorizontalSpacing (6);
- inner_grid->setVerticalSpacing (2);
+ main_grid->setContentsMargins (4, 4, 4, 4);
+ main_grid->setHorizontalSpacing (6);
+ main_grid->setVerticalSpacing (2);
}
- QWidget *main_frame = inner_frame;
- QGridLayout *main_grid = inner_grid;
-
if (! mp_pcell_decl) {
- mp_parameters_area->setWidget (main_frame);
+ mp_parameters_area->setWidget (mp_main_frame);
update_current_parameters ();
return;
}
+ QWidget *inner_frame = mp_main_frame;
+ QGridLayout *inner_grid = main_grid;
+
int main_row = 0;
int row = 0;
std::string group_title;
@@ -362,7 +364,8 @@ PCellParametersPage::setup (lay::LayoutViewBase *view, int cv_index, const db::P
if (! gt.empty ()) {
// create a new group
- QGroupBox *gb = new QGroupBox (main_frame);
+ QGroupBox *gb = new QGroupBox (mp_main_frame);
+ mp_groups.push_back (gb);
gb->setTitle (tl::to_qstring (gt));
main_grid->addWidget (gb, main_row, 0, 1, 3);
@@ -382,7 +385,7 @@ PCellParametersPage::setup (lay::LayoutViewBase *view, int cv_index, const db::P
// back to the main group
inner_grid = main_grid;
- inner_frame = main_frame;
+ inner_frame = mp_main_frame;
row = main_row;
}
@@ -427,6 +430,9 @@ PCellParametersPage::setup (lay::LayoutViewBase *view, int cv_index, const db::P
hb->setContentsMargins (0, 0, 0, 0);
f->setLayout (hb);
f->setFrameShape (QFrame::NoFrame);
+ QSizePolicy sp = f->sizePolicy ();
+ sp.setHorizontalStretch (1);
+ f->setSizePolicy (sp);
QLineEdit *le = new QLineEdit (f);
hb->addWidget (le);
@@ -434,9 +440,13 @@ PCellParametersPage::setup (lay::LayoutViewBase *view, int cv_index, const db::P
le->setObjectName (tl::to_qstring (p->get_name ()));
m_widgets.push_back (le);
- QLabel *ul = new QLabel (f);
- hb->addWidget (ul, 1);
- ul->setText (tl::to_qstring (p->get_unit ()));
+ if (! p->get_unit ().empty ()) {
+ QLabel *ul = new QLabel (f);
+ hb->addWidget (ul, 1);
+ ul->setText (tl::to_qstring (p->get_unit ()));
+ }
+
+ hb->addStretch (1);
inner_grid->addWidget (f, row, 2);
m_all_widgets.back ().push_back (f);
@@ -450,7 +460,10 @@ PCellParametersPage::setup (lay::LayoutViewBase *view, int cv_index, const db::P
QPushButton *pb = new QPushButton (inner_frame);
pb->setObjectName (tl::to_qstring (p->get_name ()));
pb->setText (tl::to_qstring (description));
- pb->setSizePolicy (QSizePolicy::Fixed, QSizePolicy::Preferred);
+ QSizePolicy sp = pb->sizePolicy ();
+ sp.setHorizontalPolicy (QSizePolicy::Fixed);
+ sp.setHorizontalStretch (1);
+ pb->setSizePolicy (sp);
m_widgets.push_back (pb);
inner_grid->addWidget (pb, row, 2);
@@ -466,6 +479,9 @@ PCellParametersPage::setup (lay::LayoutViewBase *view, int cv_index, const db::P
{
QLineEdit *le = new QLineEdit (inner_frame);
le->setObjectName (tl::to_qstring (p->get_name ()));
+ QSizePolicy sp = le->sizePolicy ();
+ sp.setHorizontalStretch (1);
+ le->setSizePolicy (sp);
m_widgets.push_back (le);
inner_grid->addWidget (le, row, 2);
m_all_widgets.back ().push_back (le);
@@ -476,13 +492,29 @@ PCellParametersPage::setup (lay::LayoutViewBase *view, int cv_index, const db::P
case db::PCellParameterDeclaration::t_layer:
{
- lay::LayerSelectionComboBox *ly = new lay::LayerSelectionComboBox (inner_frame);
+ QFrame *f = new QFrame (inner_frame);
+ QHBoxLayout *hb = new QHBoxLayout (f);
+ hb->setContentsMargins (0, 0, 0, 0);
+ f->setLayout (hb);
+ f->setFrameShape (QFrame::NoFrame);
+ QSizePolicy sp = f->sizePolicy ();
+ sp.setHorizontalStretch (1);
+ f->setSizePolicy (sp);
+
+ lay::LayerSelectionComboBox *ly = new lay::LayerSelectionComboBox (f);
+ hb->addWidget (ly);
ly->set_no_layer_available (true);
ly->set_view (mp_view, m_cv_index, true /*all layers*/);
ly->setObjectName (tl::to_qstring (p->get_name ()));
+ sp = ly->sizePolicy ();
+ sp.setHorizontalPolicy (QSizePolicy::Fixed);
+ ly->setSizePolicy (sp);
m_widgets.push_back (ly);
- inner_grid->addWidget (ly, row, 2);
- m_all_widgets.back ().push_back (ly);
+
+ hb->addStretch (1);
+
+ inner_grid->addWidget (f, row, 2);
+ m_all_widgets.back ().push_back (f);
connect (ly, SIGNAL (activated (int)), this, SLOT (parameter_changed ()));
}
@@ -492,7 +524,9 @@ PCellParametersPage::setup (lay::LayoutViewBase *view, int cv_index, const db::P
{
QCheckBox *cbx = new QCheckBox (inner_frame);
// this makes the checkbox not stretch over the full width - better when navigating with tab
- cbx->setSizePolicy (QSizePolicy (QSizePolicy::Fixed, QSizePolicy::Preferred));
+ QSizePolicy sp = cbx->sizePolicy ();
+ sp.setHorizontalStretch (1);
+ cbx->setSizePolicy (sp);
cbx->setObjectName (tl::to_qstring (p->get_name ()));
m_widgets.push_back (cbx);
inner_grid->addWidget (cbx, row, 2);
@@ -509,8 +543,20 @@ PCellParametersPage::setup (lay::LayoutViewBase *view, int cv_index, const db::P
} else {
- QComboBox *cb = new QComboBox (inner_frame);
+ QFrame *f = new QFrame (inner_frame);
+ QHBoxLayout *hb = new QHBoxLayout (f);
+ hb->setContentsMargins (0, 0, 0, 0);
+ f->setLayout (hb);
+ f->setFrameShape (QFrame::NoFrame);
+ QSizePolicy sp = f->sizePolicy ();
+ sp.setHorizontalStretch (1);
+ f->setSizePolicy (sp);
+
+ QComboBox *cb = new QComboBox (f);
+ hb->addWidget (cb);
cb->setObjectName (tl::to_qstring (p->get_name ()));
+ cb->setSizePolicy (QSizePolicy::Fixed, QSizePolicy::Preferred);
+ cb->setSizeAdjustPolicy (QComboBox::AdjustToContents);
int i = 0;
for (std::vector::const_iterator c = p->get_choices ().begin (); c != p->get_choices ().end (); ++c, ++i) {
@@ -523,21 +569,25 @@ PCellParametersPage::setup (lay::LayoutViewBase *view, int cv_index, const db::P
connect (cb, SIGNAL (activated (int)), this, SLOT (parameter_changed ()));
- cb->setMinimumContentsLength (30);
- cb->setSizeAdjustPolicy (QComboBox::AdjustToMinimumContentsLengthWithIcon);
m_widgets.push_back (cb);
- inner_grid->addWidget (cb, row, 2);
- m_all_widgets.back ().push_back (cb);
+
+ hb->addStretch (1);
+
+ inner_grid->addWidget (f, row, 2);
+ m_all_widgets.back ().push_back (f);
}
++row;
- if (inner_frame == main_frame) {
+ if (inner_frame == mp_main_frame) {
++main_row;
}
}
+ // adds some default buffer space
+ main_grid->setRowStretch (main_row, 1);
+
// initial callback
try {
@@ -556,8 +606,8 @@ PCellParametersPage::setup (lay::LayoutViewBase *view, int cv_index, const db::P
update_widgets_from_states (m_states);
- mp_parameters_area->setWidget (main_frame);
- main_frame->show ();
+ mp_parameters_area->setWidget (mp_main_frame);
+ mp_main_frame->show ();
update_current_parameters ();
}
@@ -944,15 +994,15 @@ PCellParametersPage::update_widgets_from_states (const db::ParameterStates &stat
break;
case db::ParameterState::InfoIcon:
m_icon_widgets [i]->setPixmap (info);
- m_icon_widgets [i]->show ();
+ m_icon_widgets [i]->setVisible (ps.is_visible ());
break;
case db::ParameterState::WarningIcon:
m_icon_widgets [i]->setPixmap (warning);
- m_icon_widgets [i]->show ();
+ m_icon_widgets [i]->setVisible (ps.is_visible ());
break;
case db::ParameterState::ErrorIcon:
m_icon_widgets [i]->setPixmap (error);
- m_icon_widgets [i]->show ();
+ m_icon_widgets [i]->setVisible (ps.is_visible ());
break;
}
@@ -961,6 +1011,12 @@ PCellParametersPage::update_widgets_from_states (const db::ParameterStates &stat
}
set_parameters_internal (states, lazy_evaluation ());
+
+ // QGridLayouts are bad in handling nested QFrame (or QGroupBox) with their own layouts,
+ // so we help a little here:
+ for (auto g = mp_groups.begin (); g != mp_groups.end (); ++g) {
+ (*g)->resize (QSize ((*g)->width (), (*g)->sizeHint ().height ()));
+ }
}
void
diff --git a/src/edt/edt/edtPCellParametersPage.h b/src/edt/edt/edtPCellParametersPage.h
index e16179dff..e6e501399 100644
--- a/src/edt/edt/edtPCellParametersPage.h
+++ b/src/edt/edt/edtPCellParametersPage.h
@@ -29,10 +29,12 @@
#include "tlDeferredExecution.h"
#include
-#include
-#include
-#include
-#include
+
+class QGroupBox;
+class QCheckBox;
+class QLabel;
+class QToolButton;
+class QScrollArea;
namespace lay
{
@@ -150,6 +152,8 @@ private slots:
private:
lay::Dispatcher *mp_dispatcher;
QScrollArea *mp_parameters_area;
+ QFrame *mp_main_frame;
+ std::vector mp_groups;
QLabel *mp_error_label;
QLabel *mp_error_icon;
QLabel *mp_changed_label;
diff --git a/src/lay/lay/layMainWindow.cc b/src/lay/lay/layMainWindow.cc
index 0e705c3e9..0eb2eb397 100644
--- a/src/lay/lay/layMainWindow.cc
+++ b/src/lay/lay/layMainWindow.cc
@@ -1491,7 +1491,11 @@ MainWindow::closeEvent (QCloseEvent *event)
END_PROTECTED
}
- event->ignore ();
+ if (! m_exited) {
+ event->ignore ();
+ } else {
+ event->accept ();
+ }
}
void
diff --git a/src/lay/lay/laySaltController.cc b/src/lay/lay/laySaltController.cc
index 7862bf4cc..4e5e062a2 100644
--- a/src/lay/lay/laySaltController.cc
+++ b/src/lay/lay/laySaltController.cc
@@ -179,6 +179,10 @@ SaltController::install_packages (const std::vector &packages, bool
{
lay::SaltDownloadManager manager;
+ // This method is used for command-line installation ignoring the package index.
+ // Hence we have to download package information here:
+ manager.set_always_download_package_information (true);
+
lay::Salt salt_mine;
if (! m_salt_mine_url.empty ()) {
tl::log << tl::to_string (tr ("Downloading package repository from %1").arg (tl::to_qstring (m_salt_mine_url)));
diff --git a/src/lay/lay/laySaltDownloadManager.cc b/src/lay/lay/laySaltDownloadManager.cc
index 753781d57..ef300f8a4 100644
--- a/src/lay/lay/laySaltDownloadManager.cc
+++ b/src/lay/lay/laySaltDownloadManager.cc
@@ -166,7 +166,7 @@ ConfirmationDialog::finish ()
SaltDownloadManager::SaltDownloadManager ()
{
- // .. nothing yet ..
+ m_always_download_package_information = false;
}
void
@@ -344,7 +344,7 @@ SaltDownloadManager::fetch_missing (const lay::Salt &salt, const lay::Salt &salt
}
- if (! p->downloaded && salt_mine.download_package_information ()) {
+ if (! p->downloaded && (m_always_download_package_information || salt_mine.download_package_information ())) {
// If requested, download package information to complete information from index or dependencies
if (tl::verbosity() >= 10) {
@@ -362,7 +362,7 @@ SaltDownloadManager::fetch_missing (const lay::Salt &salt, const lay::Salt &salt
if (! p->downloaded) {
if (p->name.empty ()) {
- throw tl::Exception (tl::to_string (tr ("No name given package from '%s' (from dependencies or command line installation request)")), p->url);
+ throw tl::Exception (tl::to_string (tr ("No name given for package from '%s' (from dependencies or command line installation request)")), p->url);
}
if (tl::verbosity() >= 10) {
diff --git a/src/lay/lay/laySaltDownloadManager.h b/src/lay/lay/laySaltDownloadManager.h
index 477555ada..ffe408a04 100644
--- a/src/lay/lay/laySaltDownloadManager.h
+++ b/src/lay/lay/laySaltDownloadManager.h
@@ -103,6 +103,22 @@ public:
*/
SaltDownloadManager ();
+ /**
+ * @brief Gets a flag indicating whether to always download package information
+ */
+ bool always_download_package_information () const
+ {
+ return m_always_download_package_information;
+ }
+
+ /**
+ * @brief Sets a flag indicating whether to always download package information
+ */
+ void set_always_download_package_information (bool f)
+ {
+ m_always_download_package_information = f;
+ }
+
/**
* @brief Registers an URL (with version) for download in the given target directory
*
@@ -176,6 +192,7 @@ private:
};
std::vector m_registry;
+ bool m_always_download_package_information;
bool needs_iteration ();
void fetch_missing (const lay::Salt &salt, const lay::Salt &salt_mine, tl::AbsoluteProgress &progress);
diff --git a/src/lay/lay/laySaltGrain.cc b/src/lay/lay/laySaltGrain.cc
index 6139574b3..f9c3cb181 100644
--- a/src/lay/lay/laySaltGrain.cc
+++ b/src/lay/lay/laySaltGrain.cc
@@ -487,7 +487,7 @@ SaltGrain::load (tl::InputStream &p)
void
SaltGrain::save () const
{
- save (tl::to_string (QDir (tl::to_qstring (path ())).filePath (tl::to_qstring (grain_filename))));
+ save (tl::to_string (QDir (tl::to_qstring (path ())).filePath (tl::to_qstring (SaltGrain::spec_file ()))));
}
void
@@ -503,7 +503,7 @@ SaltGrain::from_path (const std::string &path)
QDir dir (tl::to_qstring (path));
SaltGrain g;
- g.load (tl::to_string (dir.filePath (tl::to_qstring (grain_filename))));
+ g.load (tl::to_string (dir.filePath (tl::to_qstring (SaltGrain::spec_file ()))));
g.set_path (tl::to_string (dir.absolutePath ()));
return g;
}
@@ -552,7 +552,7 @@ SaltGrain::stream_from_url (std::string &generic_url, double timeout, tl::InputH
} else {
- return new tl::InputStream (url);
+ return new tl::InputStream (url + "/" + SaltGrain::spec_file ());
}
}
@@ -576,10 +576,10 @@ SaltGrain::is_grain (const std::string &path)
if (path[0] != ':') {
QDir dir (tl::to_qstring (path));
- QString gf = dir.filePath (tl::to_qstring (grain_filename));
+ QString gf = dir.filePath (tl::to_qstring (SaltGrain::spec_file ()));
return QFileInfo (gf).exists ();
} else {
- return QResource (tl::to_qstring (path + "/" + grain_filename)).isValid ();
+ return QResource (tl::to_qstring (path + "/" + SaltGrain::spec_file ())).isValid ();
}
}
diff --git a/src/layui/layui/layBrowser.cc b/src/layui/layui/layBrowser.cc
index e47e56525..edfbf4a26 100644
--- a/src/layui/layui/layBrowser.cc
+++ b/src/layui/layui/layBrowser.cc
@@ -95,6 +95,16 @@ Browser::accept ()
}
}
+void
+Browser::reject ()
+{
+ if (active ()) {
+ m_active = false;
+ deactivated ();
+ QDialog::reject ();
+ }
+}
+
}
#endif
diff --git a/src/layui/layui/layBrowser.h b/src/layui/layui/layBrowser.h
index 03416ce20..30edb4199 100644
--- a/src/layui/layui/layBrowser.h
+++ b/src/layui/layui/layBrowser.h
@@ -138,6 +138,7 @@ private:
void closeEvent (QCloseEvent *);
void accept ();
+ void reject ();
};
}
diff --git a/src/lvs/unit_tests/lvsSimpleTests.cc b/src/lvs/unit_tests/lvsSimpleTests.cc
index cde9e8f7f..d82d5d56d 100644
--- a/src/lvs/unit_tests/lvsSimpleTests.cc
+++ b/src/lvs/unit_tests/lvsSimpleTests.cc
@@ -28,7 +28,7 @@
#include "lymMacro.h"
#include "tlFileUtils.h"
-void run_test (tl::TestBase *_this, const std::string &suffix, const std::string &layout, bool with_l2n = false, const std::string &top = std::string (), bool change_case = false)
+void run_test (tl::TestBase *_this, const std::string &suffix, const std::string &layout, bool with_l2n = false, bool with_lvs = true, const std::string &top = std::string (), bool change_case = false)
{
std::string rs = tl::testdata ();
rs += "/lvs/" + suffix + ".lvs";
@@ -70,7 +70,9 @@ void run_test (tl::TestBase *_this, const std::string &suffix, const std::string
lvs.load_from (rs);
EXPECT_EQ (lvs.run (), 0);
- _this->compare_text_files (output_lvsdb, au_lvsdb);
+ if (with_lvs) {
+ _this->compare_text_files (output_lvsdb, au_lvsdb);
+ }
_this->compare_text_files (output_cir, au_cir);
if (with_l2n) {
_this->compare_text_files (output_l2n, au_l2n);
@@ -121,14 +123,14 @@ TEST(6_simple_pin_swapping)
{
run_test (_this, "ringo_simple_pin_swapping", "ringo.gds");
// change case
- run_test (_this, "ringo_simple_pin_swapping", "ringo.gds", false, std::string (), true);
+ run_test (_this, "ringo_simple_pin_swapping", "ringo.gds", false, true, std::string (), true);
}
TEST(7_net_and_circuit_equivalence)
{
run_test (_this, "ringo_simple_net_and_circuit_equivalence", "ringo_renamed.gds");
// change case
- run_test (_this, "ringo_simple_net_and_circuit_equivalence", "ringo_renamed.gds", false, std::string (), true);
+ run_test (_this, "ringo_simple_net_and_circuit_equivalence", "ringo_renamed.gds", false, true, std::string (), true);
}
TEST(8_simplification)
@@ -166,7 +168,7 @@ TEST(13_simple_ringo_device_subcircuits)
{
run_test (_this, "ringo_device_subcircuits", "ringo.gds");
// change case
- run_test (_this, "ringo_device_subcircuits", "ringo.gds", false, std::string (), true);
+ run_test (_this, "ringo_device_subcircuits", "ringo.gds", false, true, std::string (), true);
}
TEST(14_simple_ringo_mixed_hierarchy)
@@ -181,7 +183,7 @@ TEST(15_simple_dummy_device)
TEST(16_floating)
{
- run_test (_this, "floating", "floating.gds", false, "TOP");
+ run_test (_this, "floating", "floating.gds", false, true, "TOP");
}
TEST(17_layout_variants)
@@ -287,3 +289,9 @@ TEST(31_MustConnect2)
run_test (_this, "must_connect2", "must_connect2.gds");
}
+// issue 1609
+TEST(40_DeviceExtractorErrors)
+{
+ run_test (_this, "custom_resistors", "custom_resistors.gds", true, false /*no LVS*/);
+}
+
diff --git a/src/lvs/unit_tests/lvsTests.cc b/src/lvs/unit_tests/lvsTests.cc
index 40de5d859..616b561e2 100644
--- a/src/lvs/unit_tests/lvsTests.cc
+++ b/src/lvs/unit_tests/lvsTests.cc
@@ -165,7 +165,7 @@ TEST(20_private)
TEST(21_private)
{
- run_test (_this, "test_21.lylvs", "test_21.cir.gz", "test_21.gds.gz", true, "test_21_3.lvsdb");
+ run_test (_this, "test_21.lylvs", "test_21.cir.gz", "test_21.gds.gz", true, "test_21_4.lvsdb");
}
// issue #1021
diff --git a/src/plugins/streamers/dxf/db_plugin/dbDXFReader.cc b/src/plugins/streamers/dxf/db_plugin/dbDXFReader.cc
index ec409cbf2..a5c4b81ed 100644
--- a/src/plugins/streamers/dxf/db_plugin/dbDXFReader.cc
+++ b/src/plugins/streamers/dxf/db_plugin/dbDXFReader.cc
@@ -816,7 +816,9 @@ De Boor algorithm for NURBS
static db::DPoint
b_spline_point (double x, const std::vector > &control_points, int p, const std::vector &t, int &k)
{
- k = (int) (std::lower_bound (t.begin (), t.end (), x - 1e-6) - t.begin ());
+ double eps = 1e-12 * (fabs (t.back ()) + fabs (t.front ()));
+
+ k = (int) (std::lower_bound (t.begin (), t.end (), x - eps) - t.begin ());
--k;
if (k < p) {
k = p;
@@ -1740,6 +1742,7 @@ DXFReader::read_entities (db::Layout &layout, db::Cell &cell, const db::DVector
std::string layer;
unsigned int xy_flag = 0;
int degree = 1;
+ int flags = 0;
while ((g = read_group_code ()) != 0) {
if (g == 8) {
@@ -1763,9 +1766,9 @@ DXFReader::read_entities (db::Layout &layout, db::Cell &cell, const db::DVector
} else if (g == 70) {
- int flags = read_int32 ();
- if (flags != 8 && flags != 12) {
- warn ("Invalid SPLINE flag (code 70): " + tl::to_string (flags) + ". Only types 8 (non-rational) and 12 (rational) are supported currently.");
+ flags = read_int32 ();
+ if ((flags & 2) != 0) {
+ warn ("Invalid SPLINE flag (code 70): " + tl::to_string (flags) + ". Periodic splines not supported currently.");
}
} else if (g == 71) {
@@ -1814,6 +1817,13 @@ DXFReader::read_entities (db::Layout &layout, db::Cell &cell, const db::DVector
}
}
+ } else if ((flags & 1) && m_polyline_mode == 2) {
+
+ // create a polygon for the spline
+ db::DSimplePolygon p;
+ p.assign_hull (new_points.begin (), new_points.end (), tt);
+ cell.shapes (ll.second).insert (safe_from_double (p));
+
} else {
// create a path with width 0 for the spline
diff --git a/src/plugins/streamers/dxf/unit_tests/dbDXFReaderTests.cc b/src/plugins/streamers/dxf/unit_tests/dbDXFReaderTests.cc
index d38d5ed20..87ba522e7 100644
--- a/src/plugins/streamers/dxf/unit_tests/dbDXFReaderTests.cc
+++ b/src/plugins/streamers/dxf/unit_tests/dbDXFReaderTests.cc
@@ -536,3 +536,20 @@ TEST(35c)
db::DXFReaderOptions opt;
run_test_public (_this, "issue_1422c.dxf", "issue_1422c_au.gds.gz", opt);
}
+
+// issue #1592, polyline mode 2
+TEST(36a)
+{
+ db::DXFReaderOptions opt;
+ opt.dbu = 1e-5;
+ opt.polyline_mode = 2;
+ run_test_public (_this, "issue_1592.dxf.gz", "issue_1592a_au.oas.gz", opt, true);
+}
+
+// issue #1592
+TEST(36b)
+{
+ db::DXFReaderOptions opt;
+ opt.dbu = 1e-5;
+ run_test_public (_this, "issue_1592.dxf.gz", "issue_1592b_au.oas.gz", opt, true);
+}
diff --git a/src/plugins/streamers/gds2/unit_tests/dbGDS2Reader.cc b/src/plugins/streamers/gds2/unit_tests/dbGDS2ReaderTests.cc
similarity index 98%
rename from src/plugins/streamers/gds2/unit_tests/dbGDS2Reader.cc
rename to src/plugins/streamers/gds2/unit_tests/dbGDS2ReaderTests.cc
index 4e3774736..c503bab0a 100644
--- a/src/plugins/streamers/gds2/unit_tests/dbGDS2Reader.cc
+++ b/src/plugins/streamers/gds2/unit_tests/dbGDS2ReaderTests.cc
@@ -538,7 +538,7 @@ TEST(4_CollectModeRename)
}
std::string fn_au (tl::testdata () + "/gds/collect_rename_au.gds");
- db::compare_layouts (_this, layout, fn_au, db::WriteGDS2, 1);
+ db::compare_layouts (_this, layout, fn_au, db::NormalizationMode (db::WriteGDS2 | db::WithMeta), 1);
}
TEST(4_CollectModeRenameWithGhost)
@@ -634,7 +634,7 @@ TEST(4_CollectModeOverwrite)
}
std::string fn_au (tl::testdata () + "/gds/collect_overwrite_au.gds");
- db::compare_layouts (_this, layout, fn_au, db::WriteGDS2, 1);
+ db::compare_layouts (_this, layout, fn_au, db::NormalizationMode (db::WriteGDS2 | db::WithMeta), 1);
}
TEST(4_CollectModeSkip)
@@ -658,7 +658,7 @@ TEST(4_CollectModeSkip)
}
std::string fn_au (tl::testdata () + "/gds/collect_skip_au.gds");
- db::compare_layouts (_this, layout, fn_au, db::WriteGDS2, 1);
+ db::compare_layouts (_this, layout, fn_au, db::NormalizationMode (db::WriteGDS2 | db::WithMeta), 1);
}
TEST(4_CollectModeAdd)
@@ -682,7 +682,7 @@ TEST(4_CollectModeAdd)
}
std::string fn_au (tl::testdata () + "/gds/collect_add_au.gds");
- db::compare_layouts (_this, layout, fn_au, db::WriteGDS2, 1);
+ db::compare_layouts (_this, layout, fn_au, db::NormalizationMode (db::WriteGDS2 | db::WithMeta), 1);
}
// border case with multiple padding 0 for SNAME and STRING records
diff --git a/src/plugins/streamers/gds2/unit_tests/dbGDS2Writer.cc b/src/plugins/streamers/gds2/unit_tests/dbGDS2WriterTests.cc
similarity index 100%
rename from src/plugins/streamers/gds2/unit_tests/dbGDS2Writer.cc
rename to src/plugins/streamers/gds2/unit_tests/dbGDS2WriterTests.cc
diff --git a/src/plugins/streamers/gds2/unit_tests/unit_tests.pro b/src/plugins/streamers/gds2/unit_tests/unit_tests.pro
index cc5d39a61..396a6273e 100644
--- a/src/plugins/streamers/gds2/unit_tests/unit_tests.pro
+++ b/src/plugins/streamers/gds2/unit_tests/unit_tests.pro
@@ -6,8 +6,8 @@ TARGET = gds2_tests
include($$PWD/../../../../lib_ut.pri)
SOURCES = \
- dbGDS2Reader.cc \
- dbGDS2Writer.cc \
+ dbGDS2ReaderTests.cc \
+ dbGDS2WriterTests.cc
INCLUDEPATH += $$LAY_INC $$TL_INC $$DB_INC $$GSI_INC $$PWD/../db_plugin $$PWD/../../../common
DEPENDPATH += $$LAY_INC $$TL_INC $$DB_INC $$GSI_INC $$PWD/../db_plugin $$PWD/../../../common
diff --git a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc
index fc9df3080..5f0394057 100644
--- a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc
+++ b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc
@@ -1098,7 +1098,7 @@ LEFDEFReaderState::read_single_map_file (const std::string &path, std::map= 0x030A0000
@@ -123,6 +124,8 @@ public:
#if PY_VERSION_HEX >= 0x030A0000
frame = PyFrame_GetBack(frame);
+ // PyFrame_GetBack returns a strong reference, hence we need to make sure it is released
+ frame_object_ref = (PyObject *) frame;
#else
frame = frame->f_back;
#endif
@@ -182,7 +185,7 @@ PythonInterpreter::PythonInterpreter (bool embedded)
: gsi::Interpreter (0, "pya"),
mp_current_console (0), mp_current_exec_handler (0), m_current_exec_level (0),
m_in_trace (false), m_block_exceptions (false), m_ignore_next_exception (false),
- mp_current_frame (NULL), mp_py3_app_name (0), m_embedded (embedded)
+ mp_current_frame (NULL), m_embedded (embedded)
{
// Don't attempt any additional initialization in the standalone module case
if (! embedded) {
@@ -322,18 +325,15 @@ PythonInterpreter::PythonInterpreter (bool embedded)
#else
// Python 3 requires a unicode string for the application name
- PyObject *an = c2python (app_path);
- tl_assert (an != NULL);
- mp_py3_app_name = PyUnicode_AsWideCharString (an, NULL);
- tl_assert (mp_py3_app_name != NULL);
- Py_DECREF (an);
- Py_SetProgramName (mp_py3_app_name);
+
+ mp_py3_app_name = tl::to_wstring (app_path);
+ Py_SetProgramName (const_cast (mp_py3_app_name.c_str ()));
Py_InitializeEx (0 /*don't set signals*/);
// Set dummy argv[]
// TODO: more?
- wchar_t *argv[1] = { mp_py3_app_name };
+ wchar_t *argv[1] = { const_cast (mp_py3_app_name.c_str()) };
PySys_SetArgvEx (1, argv, 0);
#endif
@@ -368,14 +368,7 @@ PythonInterpreter::~PythonInterpreter ()
sp_interpreter = 0;
if (m_embedded) {
-
Py_Finalize ();
-
- if (mp_py3_app_name) {
- PyMem_Free (mp_py3_app_name);
- mp_py3_app_name = 0;
- }
-
}
}
diff --git a/src/pya/pya/pya.h b/src/pya/pya/pya.h
index 217c87230..ee8d35381 100644
--- a/src/pya/pya/pya.h
+++ b/src/pya/pya/pya.h
@@ -277,7 +277,7 @@ private:
std::string m_debugger_scope;
PyFrameObject *mp_current_frame;
std::map m_file_id_map;
- wchar_t *mp_py3_app_name;
+ std::wstring mp_py3_app_name;
bool m_embedded;
std::unique_ptr m_pya_module;
};
diff --git a/testdata/drc/drcSimpleTests_90.drc b/testdata/drc/drcSimpleTests_90.drc
new file mode 100644
index 000000000..eb85f24ee
--- /dev/null
+++ b/testdata/drc/drcSimpleTests_90.drc
@@ -0,0 +1,34 @@
+
+source $drc_test_source
+target $drc_test_target
+
+if $drc_test_deep
+ deep
+end
+
+l1 = input(1, 0)
+l1_raw = input(1, 0).raw
+l2 = input(2, 0)
+
+l1.output(1, 0)
+l2.output(2, 0)
+
+l1.width(600.nm).output(100, 0)
+l1.width(600.nm, without_touching_corners).output(101, 0)
+l1.width(600.nm, without_touching_edges).output(102, 0)
+
+l1.space(600.nm).output(200, 0)
+l1.space(600.nm, without_touching_corners).output(201, 0)
+l1.space(600.nm, without_touching_edges).output(202, 0)
+l1_raw.space(600.nm).output(210, 0)
+l1_raw.space(600.nm, without_touching_corners).output(211, 0)
+l1_raw.space(600.nm, without_touching_edges).output(212, 0)
+
+l1.sep(l2, 600.nm).output(300, 0)
+l1.sep(l2, 600.nm, without_touching_corners).output(301, 0)
+l1.sep(l2, 600.nm, without_touching_edges).output(302, 0)
+
+l1.drc(space < 600.nm).output(400, 0)
+l1.drc(space(without_touching_corners) < 600.nm).output(401, 0)
+l1.drc(space(without_touching_edges) < 600.nm).output(402, 0)
+
diff --git a/testdata/drc/drcSimpleTests_90.gds b/testdata/drc/drcSimpleTests_90.gds
new file mode 100644
index 000000000..1fedad706
Binary files /dev/null and b/testdata/drc/drcSimpleTests_90.gds differ
diff --git a/testdata/drc/drcSimpleTests_91.drc b/testdata/drc/drcSimpleTests_91.drc
new file mode 100644
index 000000000..0b79b7773
--- /dev/null
+++ b/testdata/drc/drcSimpleTests_91.drc
@@ -0,0 +1,34 @@
+
+source $drc_test_source
+target $drc_test_target
+
+if $drc_test_deep
+ deep
+end
+
+l1 = input(1, 0)
+
+l1.output(1, 0)
+
+l1.space(600.nm).output(100, 0)
+l1.space(600.nm, without_touching_corners).output(101, 0)
+l1.space(600.nm, without_touching_edges).output(102, 0)
+l1.space(600.nm, DRCZeroDistanceMode::new(RBA::ZeroDistanceMode::IncludeZeroDistanceWhenCollinearAndTouching)).output(103, 0)
+
+l1.space(600.nm, projection).output(110, 0)
+l1.space(600.nm, projection, without_touching_corners).output(111, 0)
+l1.space(600.nm, projection, without_touching_edges).output(112, 0)
+l1.space(600.nm, projection, DRCZeroDistanceMode::new(RBA::ZeroDistanceMode::IncludeZeroDistanceWhenCollinearAndTouching)).output(113, 0)
+
+l1.space(600.nm, square).output(120, 0)
+l1.space(600.nm, square, without_touching_corners).output(121, 0)
+l1.space(600.nm, square, without_touching_edges).output(122, 0)
+l1.space(600.nm, square, DRCZeroDistanceMode::new(RBA::ZeroDistanceMode::IncludeZeroDistanceWhenCollinearAndTouching)).output(123, 0)
+
+l1.data.min_coherence = true
+
+l1.space(600.nm).output(200, 0)
+l1.space(600.nm, without_touching_corners).output(201, 0)
+l1.space(600.nm, without_touching_edges).output(202, 0)
+l1.space(600.nm, DRCZeroDistanceMode::new(RBA::ZeroDistanceMode::IncludeZeroDistanceWhenCollinearAndTouching)).output(203, 0)
+
diff --git a/testdata/drc/drcSimpleTests_91.gds b/testdata/drc/drcSimpleTests_91.gds
new file mode 100644
index 000000000..ab89a181d
Binary files /dev/null and b/testdata/drc/drcSimpleTests_91.gds differ
diff --git a/testdata/drc/drcSimpleTests_au90.gds b/testdata/drc/drcSimpleTests_au90.gds
new file mode 100644
index 000000000..42058a4a8
Binary files /dev/null and b/testdata/drc/drcSimpleTests_au90.gds differ
diff --git a/testdata/drc/drcSimpleTests_au90d.gds b/testdata/drc/drcSimpleTests_au90d.gds
new file mode 100644
index 000000000..42058a4a8
Binary files /dev/null and b/testdata/drc/drcSimpleTests_au90d.gds differ
diff --git a/testdata/drc/drcSimpleTests_au91.gds b/testdata/drc/drcSimpleTests_au91.gds
new file mode 100644
index 000000000..ff5c26d23
Binary files /dev/null and b/testdata/drc/drcSimpleTests_au91.gds differ
diff --git a/testdata/drc/drcSimpleTests_au91d.gds b/testdata/drc/drcSimpleTests_au91d.gds
new file mode 100644
index 000000000..ff5c26d23
Binary files /dev/null and b/testdata/drc/drcSimpleTests_au91d.gds differ
diff --git a/testdata/drc/issue_1594.drc b/testdata/drc/issue_1594.drc
new file mode 100644
index 000000000..63d7ea7dc
--- /dev/null
+++ b/testdata/drc/issue_1594.drc
@@ -0,0 +1,15 @@
+source($drc_test_source, "TOP1")
+
+# This is just a smoke test without actual devices
+
+l1 = input(1, 0)
+l2 = input(2, 0)
+l3 = input(3, 0)
+
+connect(l1, l2)
+connect(l2, l3)
+
+writer = RBA::NetlistSpiceWriter::new
+
+netlist.write($drc_test_target, writer, "netlist")
+
diff --git a/testdata/drc/issue_1594.gds b/testdata/drc/issue_1594.gds
new file mode 100644
index 000000000..fa9036ee3
Binary files /dev/null and b/testdata/drc/issue_1594.gds differ
diff --git a/testdata/drc/issue_1594_au.cir b/testdata/drc/issue_1594_au.cir
new file mode 100644
index 000000000..ea8030c0a
--- /dev/null
+++ b/testdata/drc/issue_1594_au.cir
@@ -0,0 +1,5 @@
+* netlist
+
+* cell TOP1
+.SUBCKT TOP1
+.ENDS TOP1
diff --git a/testdata/dxf/issue_1592.dxf.gz b/testdata/dxf/issue_1592.dxf.gz
new file mode 100644
index 000000000..76ddf557d
Binary files /dev/null and b/testdata/dxf/issue_1592.dxf.gz differ
diff --git a/testdata/dxf/issue_1592a_au.oas.gz b/testdata/dxf/issue_1592a_au.oas.gz
new file mode 100644
index 000000000..61bce16f7
Binary files /dev/null and b/testdata/dxf/issue_1592a_au.oas.gz differ
diff --git a/testdata/dxf/issue_1592b_au.oas.gz b/testdata/dxf/issue_1592b_au.oas.gz
new file mode 100644
index 000000000..a55226a25
Binary files /dev/null and b/testdata/dxf/issue_1592b_au.oas.gz differ
diff --git a/testdata/gds/collect_add_au.gds b/testdata/gds/collect_add_au.gds
index ca0206610..ec52fb206 100644
Binary files a/testdata/gds/collect_add_au.gds and b/testdata/gds/collect_add_au.gds differ
diff --git a/testdata/gds/collect_added.gds b/testdata/gds/collect_added.gds
index e4882b6d8..2e366a6a0 100644
Binary files a/testdata/gds/collect_added.gds and b/testdata/gds/collect_added.gds differ
diff --git a/testdata/gds/collect_basic.gds b/testdata/gds/collect_basic.gds
index 9fad7517e..b9c8c7e63 100644
Binary files a/testdata/gds/collect_basic.gds and b/testdata/gds/collect_basic.gds differ
diff --git a/testdata/gds/collect_overwrite_au.gds b/testdata/gds/collect_overwrite_au.gds
index e4790a23d..b77fbcde9 100644
Binary files a/testdata/gds/collect_overwrite_au.gds and b/testdata/gds/collect_overwrite_au.gds differ
diff --git a/testdata/gds/collect_rename_au.gds b/testdata/gds/collect_rename_au.gds
index af98c817f..f66ca2fde 100644
Binary files a/testdata/gds/collect_rename_au.gds and b/testdata/gds/collect_rename_au.gds differ
diff --git a/testdata/gds/collect_skip_au.gds b/testdata/gds/collect_skip_au.gds
index 5a0b96fa9..7b77e88e0 100644
Binary files a/testdata/gds/collect_skip_au.gds and b/testdata/gds/collect_skip_au.gds differ
diff --git a/testdata/lefdef/patternname/au.oas.gz b/testdata/lefdef/patternname/au.oas.gz
index f63a96863..b6ae4e87d 100644
Binary files a/testdata/lefdef/patternname/au.oas.gz and b/testdata/lefdef/patternname/au.oas.gz differ
diff --git a/testdata/lvs/custom_resistors.cir b/testdata/lvs/custom_resistors.cir
new file mode 100644
index 000000000..f49736e76
--- /dev/null
+++ b/testdata/lvs/custom_resistors.cir
@@ -0,0 +1,18 @@
+
+* cell TOP
+.SUBCKT TOP
+* cell instance $1 r180 *1 2,2.6
+X$1 6 1 A
+* cell instance $2 r0 *1 2.2,1
+X$2 6 5 A
+* device instance $1 r0 *1 0.8,0.75 RPP1
+R$1 2 1 0.555555555556 RPP1
+.ENDS TOP
+
+* cell A
+* pin
+* pin
+.SUBCKT A 1 2
+* device instance $1 r0 *1 -0.2,0.4 RPP1
+R$1 1 2 1.25 RPP1
+.ENDS A
diff --git a/testdata/lvs/custom_resistors.gds b/testdata/lvs/custom_resistors.gds
new file mode 100644
index 000000000..df4b2d400
Binary files /dev/null and b/testdata/lvs/custom_resistors.gds differ
diff --git a/testdata/lvs/custom_resistors.l2n.1 b/testdata/lvs/custom_resistors.l2n.1
new file mode 100644
index 000000000..1047b4c0a
--- /dev/null
+++ b/testdata/lvs/custom_resistors.l2n.1
@@ -0,0 +1,103 @@
+#%l2n-klayout
+W(TOP)
+U(0.001)
+L(l4 '15/0')
+L(l3 '16/0')
+L(l1)
+C(l4 l4 l3 l1)
+C(l3 l4 l3)
+C(l1 l4 l1)
+H(E B('Resistor shape does not touch marker border in exactly two places') C(TOP) X('device-extract') Q('(0.8,0.75;0.8,1.15;1,1.15;1,0.75)'))
+H(E B('Resistor shape does not touch marker border in exactly two places') C(TOP) X('device-extract') Q('(0,0.75;0,1.15;0.2,1.15;0.2,0.75)'))
+H(E B('Resistor shape does not touch marker border in exactly two places') C(A) X('device-extract') Q('(0.85,-0.4;0.85,-0.2;1.25,-0.2;1.25,-0.4)'))
+K(RPP1 RES)
+D(D$RPP1 RPP1
+ T(A
+ R(l1 (0 400) (200 300))
+ )
+ T(B
+ R(l1 (0 1200) (200 250))
+ )
+)
+D(D$RPP1$1 RPP1
+ T(A
+ R(l1 (0 0) (250 200))
+ )
+ T(B
+ R(l1 (750 0) (250 200))
+ )
+)
+X(A
+ R((-200 -450) (1750 1350))
+ N(1
+ R(l4 (-150 450) (100 100))
+ R(l3 (-150 -150) (200 500))
+ R(l1 (-200 -500) (250 200))
+ )
+ N(2
+ R(l4 (650 450) (100 100))
+ R(l4 (-100 -900) (100 100))
+ R(l3 (-150 200) (200 650))
+ R(l3 (-200 -1000) (200 500))
+ R(l1 (-250 300) (250 200))
+ R(l1 (-200 -1000) (250 200))
+ )
+ N(3
+ R(l4 (1450 -350) (100 100))
+ )
+ P(1)
+ P(2)
+ D(1 D$RPP1$1
+ Y(-200 400)
+ E(R 1.25)
+ E(L 0.5)
+ E(W 0.2)
+ E(A 0.1)
+ E(P 1.4)
+ T(A 1)
+ T(B 2)
+ )
+)
+X(TOP
+ R((-50 450) (3800 2600))
+ N(1
+ R(l4 (850 2050) (100 100))
+ R(l3 (-150 -150) (500 200))
+ R(l1 (-500 -250) (200 250))
+ )
+ N(2
+ R(l4 (850 1250) (100 100))
+ R(l4 (-100 -100) (100 100))
+ R(l4 (-900 -100) (100 100))
+ R(l3 (200 -150) (650 200))
+ R(l3 (-1000 -200) (500 200))
+ R(l1 (300 -250) (200 300))
+ R(l1 (-1000 -300) (200 250))
+ )
+ N(3
+ R(l4 (50 450) (100 100))
+ )
+ N(4
+ R(l4 (850 450) (100 100))
+ )
+ N(5)
+ N(6)
+ D(1 D$RPP1
+ Y(800 750)
+ E(R 0.555555555556)
+ E(L 0.333333333333)
+ E(W 0.3)
+ E(A 0.1)
+ E(P 1.26666666667)
+ T(A 2)
+ T(B 1)
+ )
+ X(1 A O(180) Y(2000 2600)
+ P(0 6)
+ P(1 1)
+ )
+ X(2 A Y(2200 1000)
+ P(0 6)
+ P(1 5)
+ )
+)
diff --git a/testdata/lvs/custom_resistors.l2n.2 b/testdata/lvs/custom_resistors.l2n.2
new file mode 100644
index 000000000..17deb7617
--- /dev/null
+++ b/testdata/lvs/custom_resistors.l2n.2
@@ -0,0 +1,103 @@
+#%l2n-klayout
+W(TOP)
+U(0.001)
+L(l4 '15/0')
+L(l3 '16/0')
+L(l1)
+C(l4 l4 l3 l1)
+C(l3 l4 l3)
+C(l1 l4 l1)
+H(E B('Resistor shape does not touch marker border in exactly two places') C(TOP) X('device-extract') Q('(0,0.75;0,1.15;0.2,1.15;0.2,0.75)'))
+H(E B('Resistor shape does not touch marker border in exactly two places') C(TOP) X('device-extract') Q('(0.8,0.75;0.8,1.15;1,1.15;1,0.75)'))
+H(E B('Resistor shape does not touch marker border in exactly two places') C(A) X('device-extract') Q('(0.85,-0.4;0.85,-0.2;1.25,-0.2;1.25,-0.4)'))
+K(RPP1 RES)
+D(D$RPP1 RPP1
+ T(A
+ R(l1 (0 400) (200 300))
+ )
+ T(B
+ R(l1 (0 1200) (200 250))
+ )
+)
+D(D$RPP1$1 RPP1
+ T(A
+ R(l1 (0 0) (250 200))
+ )
+ T(B
+ R(l1 (750 0) (250 200))
+ )
+)
+X(A
+ R((-200 -450) (1750 1350))
+ N(1
+ R(l4 (-150 450) (100 100))
+ R(l3 (-150 -150) (200 500))
+ R(l1 (-200 -500) (250 200))
+ )
+ N(2
+ R(l4 (650 450) (100 100))
+ R(l4 (-100 -900) (100 100))
+ R(l3 (-150 200) (200 650))
+ R(l3 (-200 -1000) (200 500))
+ R(l1 (-250 300) (250 200))
+ R(l1 (-200 -1000) (250 200))
+ )
+ N(3
+ R(l4 (1450 -350) (100 100))
+ )
+ P(1)
+ P(2)
+ D(1 D$RPP1$1
+ Y(-200 400)
+ E(R 1.25)
+ E(L 0.5)
+ E(W 0.2)
+ E(A 0.1)
+ E(P 1.4)
+ T(A 1)
+ T(B 2)
+ )
+)
+X(TOP
+ R((-50 450) (3800 2600))
+ N(1
+ R(l4 (850 2050) (100 100))
+ R(l3 (-150 -150) (500 200))
+ R(l1 (-500 -250) (200 250))
+ )
+ N(2
+ R(l4 (850 1250) (100 100))
+ R(l4 (-100 -100) (100 100))
+ R(l4 (-900 -100) (100 100))
+ R(l3 (200 -150) (650 200))
+ R(l3 (-1000 -200) (500 200))
+ R(l1 (300 -250) (200 300))
+ R(l1 (-1000 -300) (200 250))
+ )
+ N(3
+ R(l4 (50 450) (100 100))
+ )
+ N(4
+ R(l4 (850 450) (100 100))
+ )
+ N(5)
+ N(6)
+ D(1 D$RPP1
+ Y(800 750)
+ E(R 0.555555555556)
+ E(L 0.333333333333)
+ E(W 0.3)
+ E(A 0.1)
+ E(P 1.26666666667)
+ T(A 2)
+ T(B 1)
+ )
+ X(1 A O(180) Y(2000 2600)
+ P(0 6)
+ P(1 1)
+ )
+ X(2 A Y(2200 1000)
+ P(0 6)
+ P(1 5)
+ )
+)
diff --git a/testdata/lvs/custom_resistors.lvs b/testdata/lvs/custom_resistors.lvs
new file mode 100644
index 000000000..78072f645
--- /dev/null
+++ b/testdata/lvs/custom_resistors.lvs
@@ -0,0 +1,86 @@
+
+source($lvs_test_source, "TOP")
+
+report_netlist($lvs_test_target_l2n)
+target_netlist($lvs_test_target_cir)
+
+deep
+
+# -------------------------------------------------------------------
+# Layers
+
+poly_dg = input(13, 0)
+cont = input(15, 0)
+met1_dg = input(16, 0)
+sblk = input(34, 0)
+rp_1 = sblk & poly_dg
+p1trm = poly_dg - rp_1
+
+class ResistorExtractor < RBA::GenericDeviceExtractor
+
+ def initialize(name, sheet_rho)
+ self.name = name
+ @sheet_rho = sheet_rho
+ end
+
+ def setup
+ define_layer("C", "Conductor")
+ define_layer("R", "Resistor")
+ register_device_class(RBA::DeviceClassResistor::new)
+ end
+
+ def get_connectivity(layout, layers)
+ # this "connectivity" forms the shape clusters that make up the device
+ conn = RBA::Connectivity::new
+ conn.connect(layers[0], layers[1]) # collect touching contacts
+ conn.connect(layers[1], layers[1]) # combine resistor shapes into one area
+ conn
+ end
+
+ def extract_devices(layer_geometry)
+ # layer_geometry provides the input layers in the order they are defined with "define_layer"
+ conductor = layer_geometry[0]
+ resistor = layer_geometry[1]
+
+ resistor_regions = resistor.merged
+
+ resistor_regions.each do |r|
+ terminals = conductor.interacting(RBA::Region::new(r))
+ if terminals.size != 2
+ error("Resistor shape does not touch marker border in exactly two places", r)
+ else
+ double_width = 0
+ (terminals.edges & resistor.edges).merged.each do |e|
+ double_width += e.length
+ end
+ # A = L*W
+ # -> L = A/W
+ a = r.area*dbu*dbu
+ w = (double_width / 2.0)*dbu
+ l = a / w
+
+ device = create_device
+ device.set_parameter(RBA::DeviceClassResistor::PARAM_R, @sheet_rho * l / w);
+
+ device.set_parameter(RBA::DeviceClassResistor::PARAM_A, a)
+ device.set_parameter(RBA::DeviceClassResistor::PARAM_L, l)
+ device.set_parameter(RBA::DeviceClassResistor::PARAM_P, 2*l+2*w)
+ device.set_parameter(RBA::DeviceClassResistor::PARAM_W, w)
+ define_terminal(device, "A", "C", terminals[0]);
+ define_terminal(device, "B", "C", terminals[1]);
+ end
+ end
+ end
+end
+
+extract_devices(ResistorExtractor::new("RPP1", 0.5), # intentionally wrong: 1565.15/5
+ { "C" => p1trm, "R" => rp_1 })
+
+connect(met1_dg, cont)
+connect(p1trm, cont)
+
+begin
+ netlist
+rescue => ex
+end
+
diff --git a/testdata/ruby/dbEdgesTest.rb b/testdata/ruby/dbEdgesTest.rb
index 1a0910a9d..f64dc910e 100644
--- a/testdata/ruby/dbEdgesTest.rb
+++ b/testdata/ruby/dbEdgesTest.rb
@@ -476,6 +476,48 @@ class DBEdges_TestClass < TestBase
assert_equal((r2 | r1).width_check(60, true, RBA::Edges::Projection, nil, 50, nil).to_s, "(120,20;120,380)/(130,380;130,20)")
assert_equal((r2 | r1).width_check(60, true, RBA::Edges::Projection, nil, nil, 50).to_s, "(50,200;50,220)/(100,400;100,0)")
+ # kissing corner/separation case
+
+ r1 = RBA::Region::new
+ r1.insert(RBA::Box::new(0, 0, 100, 200))
+ r1 = r1.edges
+
+ r2 = RBA::Region::new
+ r2.insert(RBA::Box::new(100, 200, 200, 400))
+ r2 = r2.edges
+
+ r3a = RBA::Region::new
+ r3a.insert(RBA::Box::new(-10, 0, 110, 100))
+ r3a = r3a.edges
+
+ r3b = RBA::Region::new
+ r3b.insert(RBA::Box::new(10, 0, 90, 100))
+ r3b = r3b.edges
+
+ assert_equal(csort((r2 | r1).width_check(60, false, RBA::Edges::Euclidian, nil, nil, nil).to_s), csort("(100,200;100,140)/(100,200;100,260);(160,200;100,200)/(40,200;100,200)"))
+ assert_equal(csort((r2 | r1).width_check(60, false, RBA::Edges::Euclidian, nil, nil, nil, RBA::Edges::NeverIncludeZeroDistance).to_s), csort(""))
+ assert_equal(csort((r2 | r1).width_check(60, false, RBA::Edges::Euclidian, nil, nil, nil, RBA::Edges::IncludeZeroDistanceWhenTouching).to_s), csort("(100,200;100,140)/(100,200;100,260);(160,200;100,200)/(40,200;100,200)"))
+
+ assert_equal(csort((r2 | r1).space_check(60, false, RBA::Edges::Euclidian, nil, nil, nil).to_s), csort("(100,200;100,140)/(100,200;100,260);(160,200;100,200)/(40,200;100,200)"))
+ assert_equal(csort((r2 | r1).space_check(60, false, RBA::Edges::Euclidian, nil, nil, nil, RBA::Edges::NeverIncludeZeroDistance).to_s), csort(""))
+ assert_equal(csort((r2 | r1).space_check(60, false, RBA::Edges::Euclidian, nil, nil, nil, RBA::Edges::IncludeZeroDistanceWhenTouching).to_s), csort("(100,200;100,140)/(100,200;100,260);(160,200;100,200)/(40,200;100,200)"))
+
+ assert_equal(csort(r1.separation_check(r2, 60, false, RBA::Edges::Euclidian, nil, nil, nil).to_s), csort("(100,200;100,140)/(100,200;100,260);(40,200;100,200)/(160,200;100,200)"))
+ assert_equal(csort(r1.separation_check(r2, 60, false, RBA::Edges::Euclidian, nil, nil, nil, RBA::Edges::NeverIncludeZeroDistance).to_s), csort(""))
+ assert_equal(csort(r1.separation_check(r2, 60, false, RBA::Edges::Euclidian, nil, nil, nil, RBA::Edges::IncludeZeroDistanceWhenTouching).to_s), csort("(100,200;100,140)/(100,200;100,260);(40,200;100,200)/(160,200;100,200)"))
+
+ assert_equal(csort(r1.inside_check(r3b, 60, false, RBA::Edges::Euclidian, nil, nil, nil).to_s), csort("(100,0;0,0)/(90,0;10,0)"))
+ assert_equal(csort(r1.inside_check(r3b, 60, false, RBA::Edges::Euclidian, nil, nil, nil, RBA::Edges::NeverIncludeZeroDistance).to_s), csort(""))
+ assert_equal(csort(r1.inside_check(r3b, 60, false, RBA::Edges::Euclidian, nil, nil, nil, RBA::Edges::IncludeZeroDistanceWhenTouching).to_s), csort("(100,0;0,0)/(90,0;10,0)"))
+
+ assert_equal(csort(r1.enclosing_check(r3a, 60, false, RBA::Edges::Euclidian, nil, nil, nil).to_s), csort("(100,0;0,0)/(110,0;-10,0)"))
+ assert_equal(csort(r1.enclosing_check(r3a, 60, false, RBA::Edges::Euclidian, nil, nil, nil, RBA::Edges::NeverIncludeZeroDistance).to_s), csort(""))
+ assert_equal(csort(r1.enclosing_check(r3a, 60, false, RBA::Edges::Euclidian, nil, nil, nil, RBA::Edges::IncludeZeroDistanceWhenTouching).to_s), csort("(100,0;0,0)/(110,0;-10,0)"))
+
+ assert_equal(csort(r1.overlap_check(r2, 60, false, RBA::Edges::Euclidian, nil, nil, nil).to_s), csort("(100,200;100,140)/(100,200;100,260);(40,200;100,200)/(160,200;100,200)"))
+ assert_equal(csort(r1.overlap_check(r2, 60, false, RBA::Edges::Euclidian, nil, nil, nil, RBA::Edges::NeverIncludeZeroDistance).to_s), csort(""))
+ assert_equal(csort(r1.overlap_check(r2, 60, false, RBA::Edges::Euclidian, nil, nil, nil, RBA::Edges::IncludeZeroDistanceWhenTouching).to_s), csort("(100,200;100,140)/(100,200;100,260);(40,200;100,200)/(160,200;100,200)"))
+
end
# with..
diff --git a/testdata/ruby/dbLayoutTests2.rb b/testdata/ruby/dbLayoutTests2.rb
index b5dbb9a50..bf5349645 100644
--- a/testdata/ruby/dbLayoutTests2.rb
+++ b/testdata/ruby/dbLayoutTests2.rb
@@ -23,6 +23,10 @@ end
load("test_prologue.rb")
+def mi2s(obj)
+ obj.each_meta_info.collect { |mi| mi.name + ":" + mi.value.to_s }.sort.join(";")
+end
+
class DBLayoutTests2_TestClass < TestBase
# LayerInfo
@@ -1253,6 +1257,175 @@ class DBLayoutTests2_TestClass < TestBase
end
+ # Cell#read and meta info (issue #1609)
+ def test_16
+
+ tmp = File::join($ut_testtmp, "test16.gds")
+
+ ly1 = RBA::Layout::new
+ a = ly1.create_cell("A")
+ b = ly1.create_cell("B")
+ a.insert(RBA::DCellInstArray::new(b, RBA::Trans::new))
+
+ a.add_meta_info(RBA::LayoutMetaInfo::new("am1", 42.0, "", true))
+ a.add_meta_info(RBA::LayoutMetaInfo::new("am2", "u", "", true))
+ assert_equal(mi2s(a), "am1:42.0;am2:u")
+
+ b.add_meta_info(RBA::LayoutMetaInfo::new("bm1", 17, "", true))
+ assert_equal(mi2s(b), "bm1:17")
+
+ ly1.add_meta_info(RBA::LayoutMetaInfo::new("lm1", -2.0, "", true))
+ ly1.add_meta_info(RBA::LayoutMetaInfo::new("lm2", "v", "", true))
+ assert_equal(mi2s(ly1), "lm1:-2.0;lm2:v")
+
+ ly1.write(tmp)
+
+ ly2 = RBA::Layout::new
+ top = ly2.create_cell("TOP")
+ a = ly2.create_cell("A")
+ c = ly2.create_cell("C")
+ top.insert(RBA::DCellInstArray::new(a, RBA::Trans::new))
+ a.insert(RBA::DCellInstArray::new(c, RBA::Trans::new))
+
+ top.add_meta_info(RBA::LayoutMetaInfo::new("topm1", "abc"))
+ assert_equal(mi2s(top), "topm1:abc")
+ a.add_meta_info(RBA::LayoutMetaInfo::new("am1", "a number"))
+ a.add_meta_info(RBA::LayoutMetaInfo::new("am3", 0))
+ assert_equal(mi2s(a), "am1:a number;am3:0")
+ c.add_meta_info(RBA::LayoutMetaInfo::new("cm1", 3))
+ assert_equal(mi2s(c), "cm1:3")
+
+ ly2.add_meta_info(RBA::LayoutMetaInfo::new("lm1", 5))
+ assert_equal(mi2s(ly2), "lm1:5")
+
+ a.read(tmp)
+ # not modified
+ assert_equal(mi2s(ly2), "lm1:5")
+ # merged
+ assert_equal(mi2s(a), "am1:42.0;am2:u;am3:0")
+ # not modified
+ assert_equal(mi2s(c), "cm1:3")
+
+ b2 = ly2.cell("B")
+ # imported
+ assert_equal(mi2s(b2), "bm1:17")
+
+ puts "done."
+
+ end
+
+ # Layout, meta info diverse
+ def test_17
+
+ manager = RBA::Manager::new
+
+ ly = RBA::Layout::new(manager)
+ a = ly.create_cell("A")
+
+ manager.transaction("trans")
+ ly.add_meta_info(RBA::LayoutMetaInfo::new("lm1", 17))
+ a.add_meta_info(RBA::LayoutMetaInfo::new("am1", "u"))
+ manager.commit
+
+ assert_equal(mi2s(ly), "lm1:17")
+ assert_equal(mi2s(a), "am1:u")
+
+ manager.undo
+ assert_equal(mi2s(ly), "")
+ assert_equal(mi2s(a), "")
+
+ manager.redo
+ assert_equal(mi2s(ly), "lm1:17")
+ assert_equal(mi2s(a), "am1:u")
+
+ manager.transaction("trans")
+ ly.add_meta_info(RBA::LayoutMetaInfo::new("lm1", 117))
+ a.add_meta_info(RBA::LayoutMetaInfo::new("am1", "v"))
+ manager.commit
+
+ assert_equal(mi2s(ly), "lm1:117")
+ assert_equal(mi2s(a), "am1:v")
+
+ manager.undo
+ assert_equal(mi2s(ly), "lm1:17")
+ assert_equal(mi2s(a), "am1:u")
+
+ manager.redo
+ assert_equal(mi2s(ly), "lm1:117")
+ assert_equal(mi2s(a), "am1:v")
+
+ manager.undo
+ assert_equal(mi2s(ly), "lm1:17")
+ assert_equal(mi2s(a), "am1:u")
+
+ manager.transaction("trans")
+ ly.remove_meta_info("lm1")
+ a.remove_meta_info("am1")
+ a.remove_meta_info("doesnotexist")
+ manager.commit
+
+ assert_equal(mi2s(ly), "")
+ assert_equal(mi2s(a), "")
+
+ manager.undo
+ assert_equal(mi2s(ly), "lm1:17")
+ assert_equal(mi2s(a), "am1:u")
+
+ manager.transaction("trans")
+ ly.clear_all_meta_info
+ manager.commit
+
+ assert_equal(mi2s(ly), "")
+ assert_equal(mi2s(a), "")
+
+ manager.undo
+ assert_equal(mi2s(ly), "lm1:17")
+ assert_equal(mi2s(a), "am1:u")
+
+ manager.redo
+ assert_equal(mi2s(ly), "")
+ assert_equal(mi2s(a), "")
+
+ ly2 = RBA::Layout::new
+ ly.add_meta_info(RBA::LayoutMetaInfo::new("lm1", 17))
+ ly2.add_meta_info(RBA::LayoutMetaInfo::new("lm2", 42))
+ assert_equal(mi2s(ly), "lm1:17")
+ ly.merge_meta_info(ly2)
+ assert_equal(mi2s(ly), "lm1:17;lm2:42")
+ ly.copy_meta_info(ly2)
+ assert_equal(mi2s(ly), "lm2:42")
+
+ a = ly.create_cell("A")
+ a.add_meta_info(RBA::LayoutMetaInfo::new("am1", "u"))
+ b = ly2.create_cell("B")
+ b.add_meta_info(RBA::LayoutMetaInfo::new("bm1", "v"))
+
+ assert_equal(mi2s(a), "am1:u")
+ a.merge_meta_info(b)
+ assert_equal(mi2s(a), "am1:u;bm1:v")
+ a.copy_meta_info(b)
+ assert_equal(mi2s(a), "bm1:v")
+
+ ly = RBA::Layout::new
+ ly2 = RBA::Layout::new
+
+ a = ly.create_cell("A")
+ a.add_meta_info(RBA::LayoutMetaInfo::new("am1", "u"))
+ ly2.create_cell("X")
+ b = ly2.create_cell("B")
+ b.add_meta_info(RBA::LayoutMetaInfo::new("bm1", "v"))
+
+ cm = RBA::CellMapping::new
+ cm.map(b.cell_index, a.cell_index)
+
+ assert_equal(mi2s(a), "am1:u")
+ ly.merge_meta_info(ly2, cm)
+ assert_equal(mi2s(a), "am1:u;bm1:v")
+ ly.copy_meta_info(ly2, cm)
+ assert_equal(mi2s(a), "bm1:v")
+
+ end
+
end
load("test_epilogue.rb")
diff --git a/testdata/ruby/dbRegionTest.rb b/testdata/ruby/dbRegionTest.rb
index de204bc3d..e0abb515b 100644
--- a/testdata/ruby/dbRegionTest.rb
+++ b/testdata/ruby/dbRegionTest.rb
@@ -550,6 +550,44 @@ class DBRegion_TestClass < TestBase
assert_equal((r1 | r2).merged.width_check(60, true, RBA::Region::Projection, nil, 50, nil).to_s, "(120,20;120,380)|(130,380;130,20)")
assert_equal((r1 | r2).merged.width_check(60, true, RBA::Region::Projection, nil, nil, 50).to_s, "(50,200;50,220)|(100,400;100,0)")
+ # kissing corner/separation case
+
+ r1 = RBA::Region::new
+ r1.insert(RBA::Box::new(0, 0, 100, 200))
+
+ r2 = RBA::Region::new
+ r2.insert(RBA::Box::new(100, 200, 200, 400))
+
+ r3a = RBA::Region::new
+ r3a.insert(RBA::Box::new(-10, 0, 110, 100))
+
+ r3b = RBA::Region::new
+ r3b.insert(RBA::Box::new(10, 0, 90, 100))
+
+ assert_equal(csort((r2 | r1).width_check(60, false, RBA::Edges::Euclidian, nil, nil, nil).to_s), csort("(100,200;100,140)|(100,200;100,260);(40,200;100,200)|(160,200;100,200)"))
+ assert_equal(csort((r2 | r1).width_check(60, false, RBA::Edges::Euclidian, nil, nil, nil, true, false, RBA::Region::IgnoreProperties, RBA::Region::NeverIncludeZeroDistance).to_s), csort(""))
+ assert_equal(csort((r2 | r1).width_check(60, false, RBA::Edges::Euclidian, nil, nil, nil, true, false, RBA::Region::IgnoreProperties, RBA::Region::IncludeZeroDistanceWhenTouching).to_s), csort("(100,200;100,140)|(100,200;100,260);(40,200;100,200)|(160,200;100,200)"))
+
+ assert_equal(csort((r2 | r1).space_check(60, false, RBA::Edges::Euclidian, nil, nil, nil).to_s), csort("(100,200;100,140)|(100,200;100,260);(40,200;100,200)|(160,200;100,200)"))
+ assert_equal(csort((r2 | r1).space_check(60, false, RBA::Edges::Euclidian, nil, nil, nil, true, RBA::Region::NoOppositeFilter, RBA::Region::NoRectFilter, false, RBA::Region::IgnoreProperties, RBA::Region::NeverIncludeZeroDistance).to_s), csort(""))
+ assert_equal(csort((r2 | r1).space_check(60, false, RBA::Edges::Euclidian, nil, nil, nil, true, RBA::Region::NoOppositeFilter, RBA::Region::NoRectFilter, false, RBA::Region::IgnoreProperties, RBA::Region::IncludeZeroDistanceWhenTouching).to_s), csort("(100,200;100,140)|(100,200;100,260);(40,200;100,200)|(160,200;100,200)"))
+
+ assert_equal(csort(r1.separation_check(r2, 60, false, RBA::Edges::Euclidian, nil, nil, nil).to_s), csort("(100,200;100,140)/(100,200;100,260);(40,200;100,200)/(160,200;100,200)"))
+ assert_equal(csort(r1.separation_check(r2, 60, false, RBA::Edges::Euclidian, nil, nil, nil, true, RBA::Region::NoOppositeFilter, RBA::Region::NoRectFilter, false, RBA::Region::IgnoreProperties, RBA::Region::NeverIncludeZeroDistance).to_s), csort(""))
+ assert_equal(csort(r1.separation_check(r2, 60, false, RBA::Edges::Euclidian, nil, nil, nil, true, RBA::Region::NoOppositeFilter, RBA::Region::NoRectFilter, false, RBA::Region::IgnoreProperties, RBA::Region::IncludeZeroDistanceWhenTouching).to_s), csort("(100,200;100,140)/(100,200;100,260);(40,200;100,200)/(160,200;100,200)"))
+
+ assert_equal(csort(r1.inside_check(r3b, 60, false, RBA::Edges::Euclidian, nil, nil, nil).to_s), csort("(100,0;0,0)/(90,0;10,0)"))
+ assert_equal(csort(r1.inside_check(r3b, 60, false, RBA::Edges::Euclidian, nil, nil, nil, true, RBA::Region::NoOppositeFilter, RBA::Region::NoRectFilter, false, RBA::Region::IgnoreProperties, RBA::Region::NeverIncludeZeroDistance).to_s), csort(""))
+ assert_equal(csort(r1.inside_check(r3b, 60, false, RBA::Edges::Euclidian, nil, nil, nil, true, RBA::Region::NoOppositeFilter, RBA::Region::NoRectFilter, false, RBA::Region::IgnoreProperties, RBA::Region::IncludeZeroDistanceWhenTouching).to_s), csort("(100,0;0,0)/(90,0;10,0)"))
+
+ assert_equal(csort(r1.enclosing_check(r3a, 60, false, RBA::Edges::Euclidian, nil, nil, nil).to_s), csort("(100,0;0,0)/(110,0;-10,0)"))
+ assert_equal(csort(r1.enclosing_check(r3a, 60, false, RBA::Edges::Euclidian, nil, nil, nil, true, RBA::Region::NoOppositeFilter, RBA::Region::NoRectFilter, false, RBA::Region::IgnoreProperties, RBA::Region::NeverIncludeZeroDistance).to_s), csort(""))
+ assert_equal(csort(r1.enclosing_check(r3a, 60, false, RBA::Edges::Euclidian, nil, nil, nil, true, RBA::Region::NoOppositeFilter, RBA::Region::NoRectFilter, false, RBA::Region::IgnoreProperties, RBA::Region::IncludeZeroDistanceWhenTouching).to_s), csort("(100,0;0,0)/(110,0;-10,0)"))
+
+ assert_equal(csort(r1.overlap_check(r2, 60, false, RBA::Edges::Euclidian, nil, nil, nil).to_s), csort("(100,200;100,140)/(100,200;100,260);(40,200;100,200)/(160,200;100,200)"))
+ assert_equal(csort(r1.overlap_check(r2, 60, false, RBA::Edges::Euclidian, nil, nil, nil, true, RBA::Region::NoOppositeFilter, RBA::Region::NoRectFilter, false, RBA::Region::IgnoreProperties, RBA::Region::NeverIncludeZeroDistance).to_s), csort(""))
+ assert_equal(csort(r1.overlap_check(r2, 60, false, RBA::Edges::Euclidian, nil, nil, nil, true, RBA::Region::NoOppositeFilter, RBA::Region::NoRectFilter, false, RBA::Region::IgnoreProperties, RBA::Region::IncludeZeroDistanceWhenTouching).to_s), csort("(100,200;100,140)/(100,200;100,260);(40,200;100,200)/(160,200;100,200)"))
+
end
# Others