diff --git a/build.sh b/build.sh
index c2a7bd11a..e49c132e5 100755
--- a/build.sh
+++ b/build.sh
@@ -560,6 +560,25 @@ else
fi
echo " Installation target: $BIN"
echo " Build directory: $BUILD"
+echo ""
+echo " Build flags:"
+echo " HAVE_RUBY=$HAVE_RUBY"
+echo " HAVE_PYTHON=$HAVE_PYTHON"
+echo " HAVE_QTBINDINGS=$HAVE_QTBINDINGS"
+echo " HAVE_QT=$HAVE_QT"
+echo " HAVE_QT_UITOOLS=$HAVE_QT_UITOOLS"
+echo " HAVE_QT_NETWORK=$HAVE_QT_NETWORK"
+echo " HAVE_QT_SQL=$HAVE_QT_SQL"
+echo " HAVE_QT_SVG=$HAVE_QT_SVG"
+echo " HAVE_QT_PRINTSUPPORT=$HAVE_QT_PRINTSUPPORT"
+echo " HAVE_QT_MULTIMEDIA=$HAVE_QT_MULTIMEDIA"
+echo " HAVE_QT_DESIGNER=$HAVE_QT_DESIGNER"
+echo " HAVE_QT_XML=$HAVE_QT_XML"
+echo " HAVE_64BIT_COORD=$HAVE_64BIT_COORD"
+echo " HAVE_CURL=$HAVE_CURL"
+echo " HAVE_PNG=$HAVE_PNG"
+echo " HAVE_EXPAT=$HAVE_EXPAT"
+echo " RPATH=$RPATH"
mkdir -p $BUILD
@@ -674,6 +693,7 @@ if [ $BUILD_EXPERT = 1 ]; then
QMAKE_CXXFLAGS="$CXXFLAGS"
QMAKE_CXXFLAGS_RELEASE=
QMAKE_CXXFLAGS_DEBUG=
+ QMAKE_LIBS="$LIBS"
QMAKE_LFLAGS="$LDFLAGS"
QMAKE_LFLAGS_RELEASE=
QMAKE_LFLAGS_DEBUG=
diff --git a/src/db/db/dbAsIfFlatEdges.cc b/src/db/db/dbAsIfFlatEdges.cc
index e42d5c29b..fc8cab428 100644
--- a/src/db/db/dbAsIfFlatEdges.cc
+++ b/src/db/db/dbAsIfFlatEdges.cc
@@ -514,6 +514,12 @@ AsIfFlatEdges::extended (coord_type ext_b, coord_type ext_e, coord_type ext_o, c
EdgesDelegate *
AsIfFlatEdges::in (const Edges &other, bool invert) const
{
+ if (other.empty ()) {
+ return invert ? clone () : new EmptyEdges ();
+ } else if (empty ()) {
+ return new EmptyEdges ();
+ }
+
std::set op;
for (EdgesIterator o (other.begin_merged ()); ! o.at_end (); ++o) {
op.insert (*o);
@@ -530,6 +536,34 @@ AsIfFlatEdges::in (const Edges &other, bool invert) const
return new_region.release ();
}
+std::pair
+AsIfFlatEdges::in_and_out (const Edges &other) const
+{
+ if (other.empty ()) {
+ return std::make_pair (new EmptyEdges (), clone ());
+ } else if (empty ()) {
+ return std::make_pair (new EmptyEdges (), new EmptyEdges ());
+ }
+
+ std::set op;
+ for (EdgesIterator o (other.begin_merged ()); ! o.at_end (); ++o) {
+ op.insert (*o);
+ }
+
+ std::unique_ptr in (new FlatEdges (false));
+ std::unique_ptr out (new FlatEdges (false));
+
+ for (EdgesIterator o (begin_merged ()); ! o.at_end (); ++o) {
+ if (op.find (*o) != op.end ()) {
+ in->insert (*o);
+ } else {
+ out->insert (*o);
+ }
+ }
+
+ return std::make_pair (in.release (), out.release ());
+}
+
size_t
AsIfFlatEdges::count () const
{
diff --git a/src/db/db/dbAsIfFlatEdges.h b/src/db/db/dbAsIfFlatEdges.h
index 785b0a677..4a15a91a4 100644
--- a/src/db/db/dbAsIfFlatEdges.h
+++ b/src/db/db/dbAsIfFlatEdges.h
@@ -204,6 +204,7 @@ public:
virtual std::pair selected_inside_pair (const Region &other) const;
virtual EdgesDelegate *in (const Edges &, bool) const;
+ virtual std::pair in_and_out (const Edges &) const;
virtual bool equals (const Edges &other) const;
virtual bool less (const Edges &other) const;
diff --git a/src/db/db/dbAsIfFlatRegion.cc b/src/db/db/dbAsIfFlatRegion.cc
index e0bb9dd4e..842e55eba 100644
--- a/src/db/db/dbAsIfFlatRegion.cc
+++ b/src/db/db/dbAsIfFlatRegion.cc
@@ -148,25 +148,6 @@ AsIfFlatRegion::edges (const EdgeFilterBase *filter) const
return result.release ();
}
-RegionDelegate *
-AsIfFlatRegion::in (const Region &other, bool invert) const
-{
- std::set op;
- for (RegionIterator o (other.begin_merged ()); ! o.at_end (); ++o) {
- op.insert (*o);
- }
-
- std::unique_ptr new_region (new FlatRegion (false));
-
- for (RegionIterator o (begin_merged ()); ! o.at_end (); ++o) {
- if ((op.find (*o) == op.end ()) == invert) {
- new_region->insert (*o);
- }
- }
-
- return new_region.release ();
-}
-
bool
AsIfFlatRegion::is_box () const
{
@@ -401,7 +382,7 @@ private:
}
std::pair
-AsIfFlatRegion::selected_interacting_generic (const Edges &other, InteractingOutputMode output_mode, size_t min_count, size_t max_count) const
+AsIfFlatRegion::in_and_out_generic (const Region &other, InteractingOutputMode output_mode) const
{
OutputPairHolder oph (output_mode, merged_semantics ());
@@ -409,6 +390,56 @@ AsIfFlatRegion::selected_interacting_generic (const Edges &other, InteractingOut
return oph.region_pair ();
}
+ // shortcut
+ if (empty ()) {
+ if (output_mode == Positive || output_mode == Negative) {
+ return std::make_pair (clone (), (RegionDelegate *) 0);
+ } else {
+ return std::make_pair (clone (), clone ());
+ }
+ } else if (other.empty ()) {
+ if (output_mode == Positive) {
+ return std::make_pair (new EmptyRegion (), (RegionDelegate *) 0);
+ } else if (output_mode == Negative) {
+ return std::make_pair (clone (), (RegionDelegate *) 0);
+ } else {
+ return std::make_pair (new EmptyRegion (), clone ());
+ }
+ }
+
+ std::set op;
+ for (RegionIterator o (other.begin_merged ()); ! o.at_end (); ++o) {
+ op.insert (*o);
+ }
+
+ std::unique_ptr new_region (new FlatRegion (false));
+
+ for (RegionIterator o (begin_merged ()); ! o.at_end (); ++o) {
+ if (op.find (*o) != op.end ()) {
+ if (output_mode == Positive || output_mode == PositiveAndNegative) {
+ oph.results () [0]->insert (*o);
+ }
+ } else {
+ if (output_mode == Negative) {
+ oph.results () [0]->insert (*o);
+ } else if (output_mode == PositiveAndNegative) {
+ oph.results () [1]->insert (*o);
+ }
+ }
+ }
+
+ return oph.region_pair ();
+}
+
+std::pair
+AsIfFlatRegion::selected_interacting_generic (const Edges &other, InteractingOutputMode output_mode, size_t min_count, size_t max_count) const
+{
+ OutputPairHolder oph (output_mode, merged_semantics () || is_merged ());
+
+ if (output_mode == None) {
+ return oph.region_pair ();
+ }
+
min_count = std::max (size_t (1), min_count);
// shortcut
@@ -454,7 +485,7 @@ AsIfFlatRegion::selected_interacting_generic (const Edges &other, InteractingOut
std::pair
AsIfFlatRegion::selected_interacting_generic (const Texts &other, InteractingOutputMode output_mode, size_t min_count, size_t max_count) const
{
- OutputPairHolder oph (output_mode, merged_semantics ());
+ OutputPairHolder oph (output_mode, merged_semantics () || is_merged ());
if (output_mode == None) {
return oph.region_pair ();
@@ -500,7 +531,7 @@ AsIfFlatRegion::selected_interacting_generic (const Texts &other, InteractingOut
std::pair
AsIfFlatRegion::selected_interacting_generic (const Region &other, int mode, bool touching, InteractingOutputMode output_mode, size_t min_count, size_t max_count) const
{
- OutputPairHolder oph (output_mode, merged_semantics ());
+ OutputPairHolder oph (output_mode, merged_semantics () || is_merged ());
if (output_mode == None) {
return oph.region_pair ();
@@ -580,7 +611,7 @@ AsIfFlatRegion::pull_generic (const Edges &other) const
std::vector > others;
others.push_back (other.begin_merged ());
- std::unique_ptr output (new FlatEdges (merged_semantics ()));
+ std::unique_ptr output (new FlatEdges (other.merged_semantics () || other.is_merged ()));
std::vector results;
results.push_back (&output->raw_edges ());
@@ -689,7 +720,7 @@ AsIfFlatRegion::pull_generic (const Region &other, int mode, bool touching) cons
std::vector > others;
others.push_back (other.begin_merged ());
- std::unique_ptr output (new FlatRegion (merged_semantics ()));
+ std::unique_ptr output (new FlatRegion (other.merged_semantics () || other.is_merged ()));
std::vector results;
results.push_back (&output->raw_polygons ());
diff --git a/src/db/db/dbAsIfFlatRegion.h b/src/db/db/dbAsIfFlatRegion.h
index d6ec3366c..699431ce3 100644
--- a/src/db/db/dbAsIfFlatRegion.h
+++ b/src/db/db/dbAsIfFlatRegion.h
@@ -265,7 +265,15 @@ public:
return pull_generic (other, 0, false);
}
- virtual RegionDelegate *in (const Region &other, bool invert) const;
+ virtual RegionDelegate *in (const Region &other, bool invert) const
+ {
+ return in_and_out_generic (other, invert ? Negative : Positive).first;
+ }
+
+ virtual std::pair in_and_out (const Region &other) const
+ {
+ return in_and_out_generic (other, PositiveAndNegative);
+ }
virtual bool equals (const Region &other) const;
virtual bool less (const Region &other) const;
@@ -284,6 +292,7 @@ protected:
virtual RegionDelegate *pull_generic (const Region &other, int mode, bool touching) const;
virtual EdgesDelegate *pull_generic (const Edges &other) const;
virtual TextsDelegate *pull_generic (const Texts &other) const;
+ virtual std::pair in_and_out_generic (const Region &other, InteractingOutputMode output_mode) const;
template
static void produce_markers_for_grid_check (const db::Polygon &poly, const Trans &tr, db::Coord gx, db::Coord gy, db::Shapes &shapes);
diff --git a/src/db/db/dbDeepEdges.cc b/src/db/db/dbDeepEdges.cc
index 93dd301d1..e3b40b063 100644
--- a/src/db/db/dbDeepEdges.cc
+++ b/src/db/db/dbDeepEdges.cc
@@ -34,6 +34,7 @@
#include "dbLayoutUtils.h"
#include "dbLocalOperation.h"
#include "dbLocalOperationUtils.h"
+#include "dbRegionLocalOperations.h" // for db::ContainedEdgesLocalOperation
#include "dbHierProcessor.h"
#include "dbEmptyEdges.h"
@@ -1741,8 +1742,62 @@ EdgesDelegate *DeepEdges::pull_generic (const Edges &other) const
EdgesDelegate *DeepEdges::in (const Edges &other, bool invert) const
{
- // TODO: is there a cheaper way?
- return AsIfFlatEdges::in (other, invert);
+ std::unique_ptr dr_holder;
+ const db::DeepEdges *other_deep = dynamic_cast (other.delegate ());
+ if (! other_deep) {
+ // if the other edge collection isn't deep, turn into a top-level only deep edge collection to facilitate re-hierarchization
+ dr_holder.reset (new db::DeepEdges (other, const_cast (*deep_layer ().store ())));
+ other_deep = dr_holder.get ();
+ }
+
+ const db::DeepLayer &edges = merged_deep_layer ();
+
+ DeepLayer dl_out (edges.derived ());
+
+ std::vector output_layers;
+ output_layers.reserve (1);
+ output_layers.push_back (dl_out.layer ());
+
+ db::ContainedEdgesLocalOperation op (invert ? Negative : Positive);
+
+ db::local_processor proc (const_cast (&edges.layout ()), const_cast (&edges.initial_cell ()), &other_deep->deep_layer ().layout (), &other_deep->deep_layer ().initial_cell ());
+ proc.set_base_verbosity (base_verbosity ());
+ proc.set_threads (edges.store ()->threads ());
+
+ proc.run (&op, edges.layer (), other_deep->merged_deep_layer ().layer (), output_layers);
+
+ return new db::DeepEdges (dl_out);
+}
+
+std::pair DeepEdges::in_and_out (const Edges &other) const
+{
+ std::unique_ptr dr_holder;
+ const db::DeepEdges *other_deep = dynamic_cast (other.delegate ());
+ if (! other_deep) {
+ // if the other edge collection isn't deep, turn into a top-level only deep edge collection to facilitate re-hierarchization
+ dr_holder.reset (new db::DeepEdges (other, const_cast (*deep_layer ().store ())));
+ other_deep = dr_holder.get ();
+ }
+
+ const db::DeepLayer &edges = merged_deep_layer ();
+
+ DeepLayer dl_out (edges.derived ());
+ DeepLayer dl_out2 (edges.derived ());
+
+ std::vector output_layers;
+ output_layers.reserve (2);
+ output_layers.push_back (dl_out.layer ());
+ output_layers.push_back (dl_out2.layer ());
+
+ db::ContainedEdgesLocalOperation op (PositiveAndNegative);
+
+ db::local_processor proc (const_cast (&edges.layout ()), const_cast (&edges.initial_cell ()), &other_deep->deep_layer ().layout (), &other_deep->deep_layer ().initial_cell ());
+ proc.set_base_verbosity (base_verbosity ());
+ proc.set_threads (edges.store ()->threads ());
+
+ proc.run (&op, edges.layer (), other_deep->merged_deep_layer ().layer (), output_layers);
+
+ return std::make_pair (new db::DeepEdges (dl_out), new db::DeepEdges (dl_out2));
}
namespace
diff --git a/src/db/db/dbDeepEdges.h b/src/db/db/dbDeepEdges.h
index 1bd84c16f..7fd8730aa 100644
--- a/src/db/db/dbDeepEdges.h
+++ b/src/db/db/dbDeepEdges.h
@@ -156,6 +156,7 @@ public:
virtual RegionDelegate *extended (coord_type ext_b, coord_type ext_e, coord_type ext_o, coord_type ext_i, bool join) const;
virtual EdgesDelegate *in (const Edges &, bool) const;
+ virtual std::pair in_and_out (const Edges &) const;
virtual void insert_into (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const;
diff --git a/src/db/db/dbDeepRegion.cc b/src/db/db/dbDeepRegion.cc
index f38d94228..0f7ea7fd7 100644
--- a/src/db/db/dbDeepRegion.cc
+++ b/src/db/db/dbDeepRegion.cc
@@ -555,6 +555,12 @@ DeepRegion::merged_deep_layer () const
}
}
+bool
+DeepRegion::merged_polygons_available () const
+{
+ return m_is_merged || m_merged_polygons_valid;
+}
+
void
DeepRegion::ensure_merged_polygons_valid () const
{
@@ -850,6 +856,10 @@ DeepRegion::is_box () const
size_t
DeepRegion::count () const
{
+ if (empty ()) {
+ return 0;
+ }
+
size_t n = 0;
const db::Layout &layout = deep_layer ().layout ();
@@ -864,6 +874,10 @@ DeepRegion::count () const
size_t
DeepRegion::hier_count () const
{
+ if (empty ()) {
+ return 0;
+ }
+
size_t n = 0;
const db::Layout &layout = deep_layer ().layout ();
@@ -877,6 +891,10 @@ DeepRegion::hier_count () const
DeepRegion::area_type
DeepRegion::area (const db::Box &box) const
{
+ if (empty ()) {
+ return 0;
+ }
+
if (box.empty ()) {
const db::DeepLayer &polygons = merged_deep_layer ();
@@ -910,6 +928,10 @@ DeepRegion::area (const db::Box &box) const
DeepRegion::perimeter_type
DeepRegion::perimeter (const db::Box &box) const
{
+ if (empty ()) {
+ return 0;
+ }
+
if (box.empty ()) {
const db::DeepLayer &polygons = merged_deep_layer ();
@@ -955,6 +977,10 @@ DeepRegion::to_string (size_t nmax) const
EdgePairsDelegate *
DeepRegion::grid_check (db::Coord gx, db::Coord gy) const
{
+ if (empty ()) {
+ return new EmptyEdgePairs ();
+ }
+
if (gx < 0 || gy < 0) {
throw tl::Exception (tl::to_string (tr ("Grid check requires a positive grid value")));
}
@@ -1013,6 +1039,10 @@ DeepRegion::grid_check (db::Coord gx, db::Coord gy) const
EdgePairsDelegate *
DeepRegion::angle_check (double min, double max, bool inverse) const
{
+ if (empty ()) {
+ return new DeepEdgePairs (deep_layer ().derived ());
+ }
+
const db::DeepLayer &polygons = merged_deep_layer ();
db::Layout &layout = const_cast (polygons.layout ());
@@ -1037,6 +1067,10 @@ DeepRegion::angle_check (double min, double max, bool inverse) const
RegionDelegate *
DeepRegion::snapped (db::Coord gx, db::Coord gy)
{
+ if (empty ()) {
+ return clone ();
+ }
+
if (gx < 0 || gy < 0) {
throw tl::Exception (tl::to_string (tr ("Snapping requires a positive grid value")));
}
@@ -1047,7 +1081,7 @@ DeepRegion::snapped (db::Coord gx, db::Coord gy)
}
if (! gx) {
- return this;
+ return clone ();
}
const db::DeepLayer &polygons = merged_deep_layer ();
@@ -1169,7 +1203,11 @@ public:
EdgesDelegate *
DeepRegion::edges (const EdgeFilterBase *filter) const
{
- if (! filter && merged_semantics ()) {
+ if (empty ()) {
+ return new db::DeepEdges (deep_layer ().derived ());
+ }
+
+ if (! filter && merged_semantics () && ! merged_polygons_available ()) {
// Hierarchical edge detector - no pre-merge required
@@ -1251,6 +1289,10 @@ DeepRegion::edges (const EdgeFilterBase *filter) const
RegionDelegate *
DeepRegion::process_in_place (const PolygonProcessorBase &filter)
{
+ if (empty ()) {
+ return this;
+ }
+
// TODO: implement to be really in-place
return processed (filter);
}
@@ -1258,24 +1300,40 @@ DeepRegion::process_in_place (const PolygonProcessorBase &filter)
EdgesDelegate *
DeepRegion::processed_to_edges (const PolygonToEdgeProcessorBase &filter) const
{
+ if (empty ()) {
+ return new db::DeepEdges (deep_layer ().derived ());
+ }
+
return shape_collection_processed_impl (filter.requires_raw_input () ? deep_layer () : merged_deep_layer (), filter);
}
EdgePairsDelegate *
DeepRegion::processed_to_edge_pairs (const PolygonToEdgePairProcessorBase &filter) const
{
+ if (empty ()) {
+ return new db::DeepEdgePairs (deep_layer ().derived ());
+ }
+
return shape_collection_processed_impl (filter.requires_raw_input () ? deep_layer () : merged_deep_layer (), filter);
}
RegionDelegate *
DeepRegion::processed (const PolygonProcessorBase &filter) const
{
+ if (empty ()) {
+ return clone ();
+ }
+
return shape_collection_processed_impl (filter.requires_raw_input () ? deep_layer () : merged_deep_layer (), filter);
}
RegionDelegate *
DeepRegion::filter_in_place (const PolygonFilterBase &filter)
{
+ if (empty ()) {
+ return this;
+ }
+
// TODO: implement to be really in-place
*this = *apply_filter (filter);
return this;
@@ -1284,6 +1342,10 @@ DeepRegion::filter_in_place (const PolygonFilterBase &filter)
RegionDelegate *
DeepRegion::filtered (const PolygonFilterBase &filter) const
{
+ if (empty ()) {
+ return clone ();
+ }
+
return apply_filter (filter);
}
@@ -1366,6 +1428,10 @@ DeepRegion::apply_filter (const PolygonFilterBase &filter) const
RegionDelegate *
DeepRegion::merged_in_place ()
{
+ if (empty ()) {
+ return this;
+ }
+
ensure_merged_polygons_valid ();
// NOTE: this makes both layers share the same resource
@@ -1378,12 +1444,17 @@ DeepRegion::merged_in_place ()
RegionDelegate *
DeepRegion::merged_in_place (bool min_coherence, unsigned int min_wc)
{
+ // TODO: implement to be really in-place
return merged (min_coherence, min_wc);
}
RegionDelegate *
DeepRegion::merged () const
{
+ if (empty ()) {
+ return clone ();
+ }
+
ensure_merged_polygons_valid ();
db::Layout &layout = const_cast (m_merged_polygons.layout ());
@@ -1402,6 +1473,10 @@ DeepRegion::merged () const
RegionDelegate *
DeepRegion::merged (bool min_coherence, unsigned int min_wc) const
{
+ if (empty ()) {
+ return clone ();
+ }
+
tl::SelfTimer timer (tl::verbosity () > base_verbosity (), "Ensure merged polygons");
db::Layout &layout = const_cast (deep_layer ().layout ());
@@ -1550,13 +1625,6 @@ DeepRegion::sized (coord_type dx, coord_type dy, unsigned int mode) const
return res.release ();
}
-RegionDelegate *
-DeepRegion::in (const Region &other, bool invert) const
-{
- // TODO: this can be optimized maybe ...
- return db::AsIfFlatRegion::in (other, invert);
-}
-
template
static
Output *region_cop_impl (DeepRegion *region, db::CompoundRegionOperationNode &node)
@@ -1643,6 +1711,12 @@ DeepRegion::cop_to_edges (db::CompoundRegionOperationNode &node)
EdgePairsDelegate *
DeepRegion::run_check (db::edge_relation_type rel, bool different_polygons, const Region *other, db::Coord d, const RegionCheckOptions &options) const
{
+ if (empty ()) {
+ return new db::DeepEdgePairs (deep_layer ().derived ());
+ } else if (other && ! is_subject_regionptr (other) && other->empty () && ! options.negative) {
+ return new db::DeepEdgePairs (deep_layer ().derived ());
+ }
+
const db::DeepRegion *other_deep = 0;
unsigned int other_layer = 0;
bool other_is_merged = true;
@@ -1706,6 +1780,10 @@ DeepRegion::run_check (db::edge_relation_type rel, bool different_polygons, cons
EdgePairsDelegate *
DeepRegion::run_single_polygon_check (db::edge_relation_type rel, db::Coord d, const RegionCheckOptions &options) const
{
+ if (empty ()) {
+ return new db::DeepEdgePairs (deep_layer ().derived ());
+ }
+
const db::DeepLayer &polygons = merged_deep_layer ();
EdgeRelationFilter check (rel, d, options.metrics);
@@ -1796,11 +1874,82 @@ private:
}
+std::pair
+DeepRegion::in_and_out_generic (const Region &other, InteractingOutputMode output_mode) const
+{
+ if (output_mode == None) {
+ return std::pair ((RegionDelegate *) 0, (RegionDelegate *) 0);
+ } else if (empty ()) {
+ if (output_mode == PositiveAndNegative) {
+ return std::make_pair (clone (), clone ());
+ } else {
+ return std::make_pair (clone (), (RegionDelegate *) 0);
+ }
+ } else if (other.empty ()) {
+ if (output_mode == PositiveAndNegative) {
+ return std::make_pair (new DeepRegion (deep_layer ().derived ()), clone ());
+ } else if (output_mode == Negative) {
+ return std::make_pair (clone (), (RegionDelegate *) 0);
+ } else {
+ return std::make_pair (new DeepRegion (deep_layer ().derived ()), (RegionDelegate *) 0);
+ }
+ }
+
+ std::unique_ptr dr_holder;
+ const db::DeepRegion *other_deep = dynamic_cast (other.delegate ());
+ if (! other_deep) {
+ // if the other region isn't deep, turn into a top-level only deep region to facilitate re-hierarchization
+ dr_holder.reset (new db::DeepRegion (other, const_cast (*deep_layer ().store ())));
+ other_deep = dr_holder.get ();
+ }
+
+ const db::DeepLayer &polygons = merged_deep_layer ();
+ const db::DeepLayer &other_polygons = other_deep->merged_deep_layer ();
+
+ db::ContainedLocalOperation op (output_mode);
+
+ db::local_processor proc (const_cast (&polygons.layout ()), const_cast (&polygons.initial_cell ()), &other_polygons.layout (), &other_polygons.initial_cell (), polygons.breakout_cells (), other_polygons.breakout_cells ());
+ proc.set_description (progress_desc ());
+ proc.set_report_progress (report_progress ());
+ proc.set_base_verbosity (base_verbosity ());
+ proc.set_threads (polygons.store ()->threads ());
+
+ InteractingResultHolder orh (output_mode, merged_semantics (), polygons);
+
+ proc.run (&op, polygons.layer (), other_polygons.layer (), orh.layers ());
+
+ return orh.result_pair ();
+}
+
std::pair
DeepRegion::selected_interacting_generic (const Region &other, int mode, bool touching, InteractingOutputMode output_mode, size_t min_count, size_t max_count) const
{
if (output_mode == None) {
- return std::pair (0, 0);
+ return std::pair ((RegionDelegate *) 0, (RegionDelegate *) 0);
+ } else if (empty ()) {
+ if (output_mode == PositiveAndNegative) {
+ return std::make_pair (clone (), clone ());
+ } else {
+ return std::make_pair (clone (), (RegionDelegate *) 0);
+ }
+ } else if (other.empty ()) {
+ if (mode > 0 /*outside*/) {
+ if (output_mode == PositiveAndNegative) {
+ return std::make_pair (clone (), new DeepRegion (deep_layer ().derived ()));
+ } else if (output_mode == Negative) {
+ return std::make_pair (new DeepRegion (deep_layer ().derived ()), (RegionDelegate *) 0);
+ } else {
+ return std::make_pair (clone (), (RegionDelegate *) 0);
+ }
+ } else {
+ if (output_mode == PositiveAndNegative) {
+ return std::make_pair (new DeepRegion (deep_layer ().derived ()), clone ());
+ } else if (output_mode == Negative) {
+ return std::make_pair (clone (), (RegionDelegate *) 0);
+ } else {
+ return std::make_pair (new DeepRegion (deep_layer ().derived ()), (RegionDelegate *) 0);
+ }
+ }
}
bool counting = !(min_count == 1 && max_count == std::numeric_limits::max ());
@@ -1818,7 +1967,8 @@ DeepRegion::selected_interacting_generic (const Region &other, int mode, bool to
const db::DeepLayer &polygons = merged_deep_layer ();
// NOTE: on "inside" or with counting, the other polygons must be merged
- const db::DeepLayer &other_polygons = (mode < 0 || counting) ? other_deep->merged_deep_layer () : other_deep->deep_layer ();
+ bool other_needs_merged = (mode < 0 || counting);
+ const db::DeepLayer &other_polygons = other_needs_merged ? other_deep->merged_deep_layer () : other_deep->deep_layer ();
db::InteractingLocalOperation op (mode, touching, output_mode, min_count, max_count, true);
@@ -1832,7 +1982,7 @@ DeepRegion::selected_interacting_generic (const Region &other, int mode, bool to
proc.set_max_vertex_count (polygons.store ()->max_vertex_count ());
}
- bool result_is_merged = (! split_after && ((mode < 0 && other.merged_semantics ()) || other.is_merged ()) && (merged_semantics () || is_merged ()));
+ bool result_is_merged = (! split_after && (merged_semantics () || is_merged ()));
InteractingResultHolder orh (output_mode, result_is_merged, polygons);
proc.run (&op, polygons.layer (), other_polygons.layer (), orh.layers ());
@@ -1843,6 +1993,24 @@ DeepRegion::selected_interacting_generic (const Region &other, int mode, bool to
std::pair
DeepRegion::selected_interacting_generic (const Edges &other, InteractingOutputMode output_mode, size_t min_count, size_t max_count) const
{
+ if (output_mode == None) {
+ return std::pair ((RegionDelegate *) 0, (RegionDelegate *) 0);
+ } else if (empty ()) {
+ if (output_mode == PositiveAndNegative) {
+ return std::make_pair (clone (), clone ());
+ } else {
+ return std::make_pair (clone (), (RegionDelegate *) 0);
+ }
+ } else if (other.empty ()) {
+ if (output_mode == PositiveAndNegative) {
+ return std::make_pair (new DeepRegion (deep_layer ().derived ()), clone ());
+ } else if (output_mode == Negative) {
+ return std::make_pair (clone (), (RegionDelegate *) 0);
+ } else {
+ return std::make_pair (new DeepRegion (deep_layer ().derived ()), (RegionDelegate *) 0);
+ }
+ }
+
bool counting = !(min_count == 1 && max_count == std::numeric_limits::max ());
// with these flag set to true, the resulting polygons are broken again.
@@ -1870,7 +2038,7 @@ DeepRegion::selected_interacting_generic (const Edges &other, InteractingOutputM
proc.set_max_vertex_count (polygons.store ()->max_vertex_count ());
}
- bool result_is_merged = (! split_after && other.is_merged () && (merged_semantics () || is_merged ()));
+ bool result_is_merged = (! split_after && (merged_semantics () || is_merged ()));
InteractingResultHolder orh (output_mode, result_is_merged, polygons);
proc.run (&op, polygons.layer (), counting ? other_deep->merged_deep_layer ().layer () : other_deep->deep_layer ().layer (), orh.layers ());
@@ -1881,6 +2049,12 @@ DeepRegion::selected_interacting_generic (const Edges &other, InteractingOutputM
RegionDelegate *
DeepRegion::pull_generic (const Region &other, int mode, bool touching) const
{
+ if (empty ()) {
+ return clone ();
+ } else if (other.empty ()) {
+ return new DeepRegion (deep_layer ().derived ());
+ }
+
// with these flag set to true, the resulting polygons are broken again.
bool split_after = false;
@@ -1913,15 +2087,17 @@ DeepRegion::pull_generic (const Region &other, int mode, bool touching) const
proc.run (&op, polygons.layer (), other_polygons.layer (), dl_out.layer ());
db::DeepRegion *res = new db::DeepRegion (dl_out);
- if (! split_after && ((mode < 0 && merged_semantics ()) || is_merged ()) && (other.merged_semantics () || other.is_merged ())) {
- res->set_is_merged (true);
- }
+ res->set_is_merged (! split_after && (other.merged_semantics () || other.is_merged ()));
return res;
}
EdgesDelegate *
DeepRegion::pull_generic (const Edges &other) const
{
+ if (empty () || other.empty ()) {
+ return new DeepEdges (deep_layer ().derived ());
+ }
+
std::unique_ptr dr_holder;
const db::DeepEdges *other_deep = dynamic_cast (other.delegate ());
if (! other_deep) {
@@ -1953,6 +2129,10 @@ DeepRegion::pull_generic (const Edges &other) const
TextsDelegate *
DeepRegion::pull_generic (const Texts &other) const
{
+ if (empty () || other.empty ()) {
+ return new DeepTexts (deep_layer ().derived ());
+ }
+
std::unique_ptr dr_holder;
const db::DeepTexts *other_deep = dynamic_cast (other.delegate ());
if (! other_deep) {
@@ -1976,15 +2156,31 @@ DeepRegion::pull_generic (const Texts &other) const
proc.set_threads (polygons.store ()->threads ());
proc.run (&op, polygons.layer (), other_texts.layer (), dl_out.layer ());
- db::DeepTexts *res = new db::DeepTexts (dl_out);
- res->set_is_merged (is_merged ());
- return res;
+ return new db::DeepTexts (dl_out);
}
std::pair
DeepRegion::selected_interacting_generic (const Texts &other, InteractingOutputMode output_mode, size_t min_count, size_t max_count) const
{
+ if (output_mode == None) {
+ return std::pair ((RegionDelegate *) 0, (RegionDelegate *) 0);
+ } else if (empty ()) {
+ if (output_mode == PositiveAndNegative) {
+ return std::make_pair (clone (), clone ());
+ } else {
+ return std::make_pair (clone (), (RegionDelegate *) 0);
+ }
+ } else if (other.empty ()) {
+ if (output_mode == PositiveAndNegative) {
+ return std::make_pair (new DeepRegion (deep_layer ().derived ()), clone ());
+ } else if (output_mode == Negative) {
+ return std::make_pair (clone (), (RegionDelegate *) 0);
+ } else {
+ return std::make_pair (new DeepRegion (deep_layer ().derived ()), (RegionDelegate *) 0);
+ }
+ }
+
// with these flag set to true, the resulting polygons are broken again.
bool split_after = false;
diff --git a/src/db/db/dbDeepRegion.h b/src/db/db/dbDeepRegion.h
index 75ea1961d..a45895bfd 100644
--- a/src/db/db/dbDeepRegion.h
+++ b/src/db/db/dbDeepRegion.h
@@ -133,8 +133,6 @@ public:
virtual RegionDelegate *sized (coord_type d, unsigned int mode) const;
virtual RegionDelegate *sized (coord_type dx, coord_type dy, unsigned int mode) const;
- virtual RegionDelegate *in (const Region &other, bool invert) const;
-
virtual void insert_into (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const;
virtual DeepShapeCollectionDelegateBase *deep ()
@@ -144,6 +142,7 @@ public:
void set_is_merged (bool f);
+ bool merged_polygons_available () const;
const DeepLayer &merged_deep_layer () const;
protected:
@@ -158,6 +157,7 @@ protected:
virtual RegionDelegate *pull_generic (const Region &other, int mode, bool touching) const;
virtual EdgesDelegate *pull_generic (const Edges &other) const;
virtual TextsDelegate *pull_generic (const Texts &other) const;
+ virtual std::pair in_and_out_generic (const Region &other, InteractingOutputMode output_mode) const;
private:
friend class DeepEdges;
diff --git a/src/db/db/dbEdges.h b/src/db/db/dbEdges.h
index 6f2114d41..1524581c8 100644
--- a/src/db/db/dbEdges.h
+++ b/src/db/db/dbEdges.h
@@ -1390,6 +1390,19 @@ public:
return Edges (mp_delegate->in (other, invert));
}
+ /**
+ * @brief Returns all edges which are in the other edge set and which are not.
+ *
+ * This method is equivalent to calling in with invert = false and true, but more efficient.
+ *
+ * Merged semantics applies.
+ */
+ std::pair in_and_out (const Edges &other) const
+ {
+ std::pair p = mp_delegate->in_and_out (other);
+ return std::pair (Edges (p.first), Edges (p.second));
+ }
+
/**
* @brief Returns the nth edge
*
diff --git a/src/db/db/dbEdgesDelegate.h b/src/db/db/dbEdgesDelegate.h
index 59a595f4b..db17aeda4 100644
--- a/src/db/db/dbEdgesDelegate.h
+++ b/src/db/db/dbEdgesDelegate.h
@@ -333,6 +333,7 @@ public:
virtual std::pair selected_inside_pair (const Edges &other) const = 0;
virtual EdgesDelegate *in (const Edges &other, bool invert) const = 0;
+ virtual std::pair in_and_out (const Edges &) const = 0;
virtual const db::Edge *nth (size_t n) const = 0;
virtual bool has_valid_edges () const = 0;
diff --git a/src/db/db/dbEmptyEdges.h b/src/db/db/dbEmptyEdges.h
index 569eada56..4cefa2693 100644
--- a/src/db/db/dbEmptyEdges.h
+++ b/src/db/db/dbEmptyEdges.h
@@ -115,6 +115,7 @@ public:
virtual std::pair selected_inside_pair (const Edges &) const { return std::make_pair (new EmptyEdges (), new EmptyEdges ()); }
virtual EdgesDelegate *in (const Edges &, bool) const { return new EmptyEdges (); }
+ virtual std::pair in_and_out (const Edges &) const { return std::make_pair (new EmptyEdges (), new EmptyEdges ()); }
virtual const db::Edge *nth (size_t) const { tl_assert (false); }
virtual bool has_valid_edges () const { return true; }
diff --git a/src/db/db/dbEmptyRegion.h b/src/db/db/dbEmptyRegion.h
index e5537792d..60c5332d9 100644
--- a/src/db/db/dbEmptyRegion.h
+++ b/src/db/db/dbEmptyRegion.h
@@ -133,6 +133,7 @@ public:
virtual TextsDelegate *pull_interacting (const Texts &) const { return new EmptyTexts (); }
virtual RegionDelegate *pull_overlapping (const Region &) const { return new EmptyRegion (); }
virtual RegionDelegate *in (const Region &, bool) const { return new EmptyRegion (); }
+ virtual std::pair in_and_out (const Region &) const { return std::make_pair (new EmptyRegion (), new EmptyRegion ()); }
virtual bool has_valid_polygons () const { return true; }
virtual bool has_valid_merged_polygons () const { return true; }
diff --git a/src/db/db/dbRegion.h b/src/db/db/dbRegion.h
index af8671d46..3030911e2 100644
--- a/src/db/db/dbRegion.h
+++ b/src/db/db/dbRegion.h
@@ -1602,6 +1602,19 @@ public:
return Region (mp_delegate->in (other, invert));
}
+ /**
+ * @brief Returns all polygons which are in the other region plus the ones which are not
+ *
+ * This method is similar to calling in with inverse = false and true, but more efficient.
+ *
+ * Merged semantics applies.
+ */
+ std::pair in_and_out (const Region &other) const
+ {
+ std::pair p = mp_delegate->in_and_out (other);
+ return std::pair (Region (p.first), Region (p.second));
+ }
+
/**
* @brief Round corners (in-place)
*
diff --git a/src/db/db/dbRegionDelegate.h b/src/db/db/dbRegionDelegate.h
index 985ba48e1..e94737cad 100644
--- a/src/db/db/dbRegionDelegate.h
+++ b/src/db/db/dbRegionDelegate.h
@@ -308,6 +308,7 @@ public:
virtual RegionDelegate *pull_overlapping (const Region &other) const = 0;
virtual TextsDelegate *pull_interacting (const Texts &other) const = 0;
virtual RegionDelegate *in (const Region &other, bool invert) const = 0;
+ virtual std::pair in_and_out (const Region &other) const = 0;
virtual const db::Polygon *nth (size_t n) const = 0;
virtual bool has_valid_polygons () const = 0;
diff --git a/src/db/db/dbRegionLocalOperations.cc b/src/db/db/dbRegionLocalOperations.cc
index d6aa19b9e..f1d543a62 100644
--- a/src/db/db/dbRegionLocalOperations.cc
+++ b/src/db/db/dbRegionLocalOperations.cc
@@ -915,6 +915,81 @@ template class DB_PUBLIC interacting_local_operation
+contained_local_operation::contained_local_operation (InteractingOutputMode output_mode)
+ : m_output_mode (output_mode)
+{
+ // .. nothing yet ..
+}
+
+template
+db::Coord contained_local_operation::dist () const
+{
+ return 1; // touching included for degenerated polygons and edges
+}
+
+template
+void contained_local_operation::do_compute_local (db::Layout * /*layout*/, const shape_interactions &interactions, std::vector > &results, size_t /*max_vertex_count*/, double /*area_ratio*/) const
+{
+ if (m_output_mode == None) {
+ return;
+ } else if (m_output_mode == Positive || m_output_mode == Negative) {
+ tl_assert (results.size () == 1);
+ } else {
+ tl_assert (results.size () == 2);
+ }
+
+ std::set others;
+ for (typename shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) {
+ for (typename shape_interactions::iterator2 j = i->second.begin (); j != i->second.end (); ++j) {
+ others.insert (interactions.intruder_shape (*j).second);
+ }
+ }
+
+ for (typename shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) {
+ const TS &subject = interactions.subject_shape (i->first);
+ if (others.find (subject) != others.end ()) {
+ if (m_output_mode == Positive || m_output_mode == PositiveAndNegative) {
+ results [0].insert (subject);
+ }
+ } else {
+ if (m_output_mode == Negative) {
+ results [0].insert (subject);
+ } else if (m_output_mode == PositiveAndNegative) {
+ results [1].insert (subject);
+ }
+ }
+ }
+}
+
+template
+OnEmptyIntruderHint
+contained_local_operation::on_empty_intruder_hint () const
+{
+ if (m_output_mode == Positive) {
+ return OnEmptyIntruderHint::Drop;
+ } else if (m_output_mode == Negative) {
+ return OnEmptyIntruderHint::Copy;
+ } else if (m_output_mode == PositiveAndNegative) {
+ return OnEmptyIntruderHint::CopyToSecond;
+ } else {
+ return OnEmptyIntruderHint::Ignore;
+ }
+}
+
+template
+std::string contained_local_operation::description () const
+{
+ return tl::to_string (tr ("Select polygons contained in other region"));
+}
+
+// explicit instantiations
+template class DB_PUBLIC contained_local_operation;
+template class DB_PUBLIC contained_local_operation;
+template class DB_PUBLIC contained_local_operation;
+
+// ---------------------------------------------------------------------------------------------------------------
+
template
pull_local_operation::pull_local_operation (int mode, bool touching)
: m_mode (mode), m_touching (touching)
diff --git a/src/db/db/dbRegionLocalOperations.h b/src/db/db/dbRegionLocalOperations.h
index 6d81c2b0d..102076b79 100644
--- a/src/db/db/dbRegionLocalOperations.h
+++ b/src/db/db/dbRegionLocalOperations.h
@@ -351,6 +351,26 @@ public:
typedef pull_with_text_local_operation PullWithTextLocalOperation;
+template
+class contained_local_operation
+ : public local_operation
+{
+public:
+ contained_local_operation (InteractingOutputMode output_mode);
+
+ virtual db::Coord dist () const;
+ virtual void do_compute_local (db::Layout * /*layout*/, const shape_interactions &interactions, std::vector > &results, size_t /*max_vertex_count*/, double /*area_ratio*/) const;
+ virtual OnEmptyIntruderHint on_empty_intruder_hint () const;
+ virtual std::string description () const;
+
+private:
+ InteractingOutputMode m_output_mode;
+};
+
+typedef contained_local_operation ContainedLocalOperation;
+// the implementation is type-agnostic and can be used for edges too
+typedef contained_local_operation ContainedEdgesLocalOperation;
+
} // namespace db
#endif
diff --git a/src/db/db/gsiDeclDbEdges.cc b/src/db/db/gsiDeclDbEdges.cc
index e2977296f..f1ce6d959 100644
--- a/src/db/db/gsiDeclDbEdges.cc
+++ b/src/db/db/gsiDeclDbEdges.cc
@@ -35,7 +35,16 @@
namespace gsi
{
-static db::Edges *new_v ()
+static inline std::vector as_2edges_vector (const std::pair &rp)
+{
+ std::vector res;
+ res.reserve (2);
+ res.push_back (db::Edges (const_cast (rp.first).take_delegate ()));
+ res.push_back (db::Edges (const_cast (rp.second).take_delegate ()));
+ return res;
+}
+
+static db::Edges *new_v ()
{
return new db::Edges ();
}
@@ -166,6 +175,11 @@ static db::Edges not_in (const db::Edges *r, const db::Edges &other)
return r->in (other, true);
}
+static std::vector in_and_out (const db::Edges *r, const db::Edges &other)
+{
+ return as_2edges_vector (r->in_and_out (other));
+}
+
static db::Edges &move_p (db::Edges *r, const db::Vector &p)
{
r->transform (db::Disp (p));
@@ -377,15 +391,6 @@ static size_t id (const db::Edges *e)
return tl::id_of (e->delegate ());
}
-static inline std::vector as_2edges_vector (const std::pair &rp)
-{
- std::vector res;
- res.reserve (2);
- res.push_back (db::Edges (const_cast (rp.first).take_delegate ()));
- res.push_back (db::Edges (const_cast (rp.second).take_delegate ()));
- return res;
-}
-
static std::vector andnot_with_edges (const db::Edges *r, const db::Edges &other)
{
return as_2edges_vector (r->andnot (other));
@@ -1633,16 +1638,24 @@ Class decl_Edges (decl_dbShapeCollection, "db", "Edges",
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
) +
- method_ext ("members_of|#in", &in, gsi::arg ("other"),
+ method_ext ("members_of|in", &in, gsi::arg ("other"),
"@brief Returns all edges which are members of the other edge collection\n"
"This method returns all edges in self which can be found in the other edge collection as well with exactly the same "
"geometry."
) +
- method_ext ("not_members_of|#not_in", ¬_in, gsi::arg ("other"),
+ method_ext ("not_members_of|not_in", ¬_in, gsi::arg ("other"),
"@brief Returns all edges which are not members of the other edge collection\n"
"This method returns all edges in self which can not be found in the other edge collection with exactly the same "
"geometry."
) +
+ method_ext ("in_and_out", &in_and_out, gsi::arg ("other"),
+ "@brief Returns all polygons which are members and not members of the other region\n"
+ "This method is equivalent to calling \\members_of and \\not_members_of, but delivers both results at the same time and "
+ "is more efficient than two separate calls. "
+ "The first element returned is the \\members_of part, the second is the \\not_members_of part.\n"
+ "\n"
+ "This method has been introduced in version 0.28.\n"
+ ) +
method_ext ("is_deep?", &is_deep,
"@brief Returns true if the edge collection is a deep (hierarchical) one\n"
"\n"
diff --git a/src/db/db/gsiDeclDbRegion.cc b/src/db/db/gsiDeclDbRegion.cc
index f7874686b..d3dafb24d 100644
--- a/src/db/db/gsiDeclDbRegion.cc
+++ b/src/db/db/gsiDeclDbRegion.cc
@@ -44,6 +44,15 @@
namespace gsi
{
+static inline std::vector as_2region_vector (const std::pair &rp)
+{
+ std::vector res;
+ res.reserve (2);
+ res.push_back (db::Region (const_cast (rp.first).take_delegate ()));
+ res.push_back (db::Region (const_cast (rp.second).take_delegate ()));
+ return res;
+}
+
static db::Region *new_v ()
{
return new db::Region ();
@@ -430,6 +439,11 @@ static db::Region not_in (const db::Region *r, const db::Region &other)
return r->in (other, true);
}
+static std::vector in_and_out (const db::Region *r, const db::Region &other)
+{
+ return as_2region_vector (r->in_and_out (other));
+}
+
static db::Region rectangles (const db::Region *r)
{
db::RectangleFilter f (false, false);
@@ -605,15 +619,6 @@ static db::EdgePairs separation2 (const db::Region *r, const db::Region &other,
);
}
-static inline std::vector as_2region_vector (const std::pair &rp)
-{
- std::vector res;
- res.reserve (2);
- res.push_back (db::Region (const_cast (rp.first).take_delegate ()));
- res.push_back (db::Region (const_cast (rp.second).take_delegate ()));
- return res;
-}
-
static std::vector andnot (const db::Region *r, const db::Region &other)
{
return as_2region_vector (r->andnot (other));
@@ -2186,16 +2191,24 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region",
"are taken from a hole-less representation (i.e. GDS2 file). Use explicit merge (\\merge method) "
"in order to merge the polygons and detect holes.\n"
) +
- method_ext ("members_of|#in", &in, gsi::arg ("other"),
+ method_ext ("members_of|in", &in, gsi::arg ("other"),
"@brief Returns all polygons which are members of the other region\n"
"This method returns all polygons in self which can be found in the other region as well with exactly the same "
"geometry."
) +
- method_ext ("not_members_of|#not_in", ¬_in, gsi::arg ("other"),
+ method_ext ("not_members_of|not_in", ¬_in, gsi::arg ("other"),
"@brief Returns all polygons which are not members of the other region\n"
"This method returns all polygons in self which can not be found in the other region with exactly the same "
"geometry."
) +
+ method_ext ("in_and_out", &in_and_out, gsi::arg ("other"),
+ "@brief Returns all polygons which are members and not members of the other region\n"
+ "This method is equivalent to calling \\members_of and \\not_members_of, but delivers both results at the same time and "
+ "is more efficient than two separate calls. "
+ "The first element returned is the \\members_of part, the second is the \\not_members_of part.\n"
+ "\n"
+ "This method has been introduced in version 0.28.\n"
+ ) +
method_ext ("rectangles", &rectangles,
"@brief Returns all polygons which are rectangles\n"
"This method returns all polygons in self which are rectangles."
diff --git a/src/db/unit_tests/dbDeepEdgesTests.cc b/src/db/unit_tests/dbDeepEdgesTests.cc
index 05695fb03..5149ce316 100644
--- a/src/db/unit_tests/dbDeepEdgesTests.cc
+++ b/src/db/unit_tests/dbDeepEdgesTests.cc
@@ -1182,3 +1182,113 @@ TEST(19_AndNotWithEdges)
EXPECT_EQ (db::compare (eflat.andnot (ee).second, "(1500,2000;1500,2100);(1100,0;1100,1000);(0,0;0,1000);(100,0;100,3000);(1800,2500;1800,3500);(-1500,0;-1500,1000);(1700,1500;1600,2500)"), true);
}
+TEST(20_in)
+{
+ db::Layout ly;
+ {
+ std::string fn (tl::testdata ());
+ fn += "/algo/deep_region_l31.gds";
+ tl::InputStream stream (fn);
+ db::Reader reader (stream);
+ reader.read (ly);
+ }
+
+ db::cell_index_type top_cell_index = *ly.begin_top_down ();
+ db::Cell &top_cell = ly.cell (top_cell_index);
+
+ db::DeepShapeStore dss;
+
+ unsigned int l1 = ly.get_layer (db::LayerProperties (1, 0));
+ unsigned int l2 = ly.get_layer (db::LayerProperties (2, 0));
+ unsigned int l3 = ly.get_layer (db::LayerProperties (3, 0)); // empty
+
+ db::Edges e1 = db::Edges ((db::Region (db::RecursiveShapeIterator (ly, top_cell, l1), dss)).edges ());
+ db::Edges e2 = db::Edges ((db::Region (db::RecursiveShapeIterator (ly, top_cell, l2), dss)).edges ());
+ db::Edges e3 = db::Edges ((db::Region (db::RecursiveShapeIterator (ly, top_cell, l3), dss)).edges ());
+
+ db::Edges e1r = e1;
+ e1r.set_merged_semantics (false);
+ db::Edges e2r = e2;
+ e2r.set_merged_semantics (false);
+
+ db::Layout target;
+ unsigned int target_top_cell_index = target.add_cell (ly.cell_name (top_cell_index));
+
+ target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (1, 0)), e1);
+ target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (2, 0)), e2);
+
+ target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (10, 0)), e2.in (e1));
+ target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (11, 0)), e2.in (e1, true));
+ target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (12, 0)), e2.in (e3));
+ target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (13, 0)), e2.in (e3, true));
+ target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (14, 0)), e3.in (e1));
+ target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (15, 0)), e3.in (e1, true));
+
+ target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (20, 0)), e2r.in (e1));
+ target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (21, 0)), e2r.in (e1, true));
+
+ target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (30, 0)), e2.in (e1r));
+ target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (31, 0)), e2.in (e1r, true));
+
+ target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (40, 0)), e2r.in (e1r));
+ target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (41, 0)), e2r.in (e1r, true));
+
+ CHECKPOINT();
+ db::compare_layouts (_this, target, tl::testdata () + "/algo/deep_edges_au20.gds");
+}
+
+TEST(20_in_and_out)
+{
+ db::Layout ly;
+ {
+ std::string fn (tl::testdata ());
+ fn += "/algo/deep_region_l31.gds";
+ tl::InputStream stream (fn);
+ db::Reader reader (stream);
+ reader.read (ly);
+ }
+
+ db::cell_index_type top_cell_index = *ly.begin_top_down ();
+ db::Cell &top_cell = ly.cell (top_cell_index);
+
+ db::DeepShapeStore dss;
+
+ unsigned int l1 = ly.get_layer (db::LayerProperties (1, 0));
+ unsigned int l2 = ly.get_layer (db::LayerProperties (2, 0));
+ unsigned int l3 = ly.get_layer (db::LayerProperties (3, 0)); // empty
+
+ db::Edges e1 = db::Edges ((db::Region (db::RecursiveShapeIterator (ly, top_cell, l1), dss)).edges ());
+ db::Edges e2 = db::Edges ((db::Region (db::RecursiveShapeIterator (ly, top_cell, l2), dss)).edges ());
+ db::Edges e3 = db::Edges ((db::Region (db::RecursiveShapeIterator (ly, top_cell, l3), dss)).edges ());
+
+ db::Edges e1r = e1;
+ e1r.set_merged_semantics (false);
+ db::Edges e2r = e2;
+ e2r.set_merged_semantics (false);
+
+ db::Layout target;
+ unsigned int target_top_cell_index = target.add_cell (ly.cell_name (top_cell_index));
+
+ target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (1, 0)), e1);
+ target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (2, 0)), e2);
+
+ target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (10, 0)), e2.in_and_out (e1).first);
+ target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (11, 0)), e2.in_and_out (e1).second);
+ target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (12, 0)), e2.in_and_out (e3).first);
+ target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (13, 0)), e2.in_and_out (e3).second);
+ target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (14, 0)), e3.in_and_out (e1).first);
+ target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (15, 0)), e3.in_and_out (e1).second);
+
+ target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (20, 0)), e2r.in_and_out (e1).first);
+ target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (21, 0)), e2r.in_and_out (e1).second);
+
+ target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (30, 0)), e2.in_and_out (e1r).first);
+ target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (31, 0)), e2.in_and_out (e1r).second);
+
+ target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (40, 0)), e2r.in_and_out (e1r).first);
+ target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (41, 0)), e2r.in_and_out (e1r).second);
+
+ CHECKPOINT();
+ db::compare_layouts (_this, target, tl::testdata () + "/algo/deep_edges_au20.gds");
+}
+
diff --git a/src/db/unit_tests/dbDeepRegionTests.cc b/src/db/unit_tests/dbDeepRegionTests.cc
index fb1dfffbc..d749a8ddf 100644
--- a/src/db/unit_tests/dbDeepRegionTests.cc
+++ b/src/db/unit_tests/dbDeepRegionTests.cc
@@ -880,8 +880,6 @@ TEST(14_Interacting)
db::Region r2 (db::RecursiveShapeIterator (ly, top_cell, l2), dss);
db::Region r6 (db::RecursiveShapeIterator (ly, top_cell, l6), dss);
db::Region r1f (db::RecursiveShapeIterator (ly, top_cell, l1));
- db::Region r2f (db::RecursiveShapeIterator (ly, top_cell, l2));
- db::Region r6f (db::RecursiveShapeIterator (ly, top_cell, l6));
db::Region r1r = r1;
r1r.set_merged_semantics (false);
db::Region r2r = r2;
@@ -889,6 +887,11 @@ TEST(14_Interacting)
db::Region r6r = r6;
r6r.set_merged_semantics (false);
+ db::Edges r1e = r1.edges ();
+ db::Edges r1ef = r1f.edges ();
+ db::Edges r1er = r1r.edges ();
+ r1er.set_merged_semantics (false);
+
{
db::Layout target;
unsigned int target_top_cell_index = target.add_cell (ly.cell_name (top_cell_index));
@@ -947,22 +950,18 @@ TEST(14_Interacting)
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (66, 0)), r6r.selected_overlapping (r1r));
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (67, 0)), r6r.selected_not_overlapping (r1r));
- EXPECT_EQ (r2.selected_interacting (r1).is_merged (), false);
- EXPECT_EQ (r2.selected_interacting (r1.merged ()).is_merged (), true);
- EXPECT_EQ (r2.selected_inside (r1).is_merged (), true);
+ EXPECT_EQ (r2.selected_interacting (r1).is_merged (), true);
EXPECT_EQ (r2r.selected_interacting (r1).is_merged (), false);
- EXPECT_EQ (r2.selected_interacting (r1r).is_merged (), false);
- EXPECT_EQ (r2r.selected_interacting (r1r).is_merged (), false);
+ EXPECT_EQ (r2r.selected_interacting (r1.merged ()).is_merged (), false);
+ EXPECT_EQ (r2.selected_interacting (r1r).is_merged (), true);
+ EXPECT_EQ (r2.selected_inside (r1).is_merged (), true);
+ EXPECT_EQ (r2r.selected_inside (r1).is_merged (), false);
+ EXPECT_EQ (r2.selected_inside (r1).is_merged (), true);
CHECKPOINT();
db::compare_layouts (_this, target, tl::testdata () + "/algo/deep_region_au14a.gds");
}
- db::Edges r1e = r1.edges ();
- db::Edges r1ef = r1f.edges ();
- db::Edges r1er = r1r.edges ();
- r1er.set_merged_semantics (false);
-
{
db::Layout target;
unsigned int target_top_cell_index = target.add_cell (ly.cell_name (top_cell_index));
@@ -976,8 +975,8 @@ TEST(14_Interacting)
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (32, 0)), r6r.selected_interacting (r1er));
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (33, 0)), r6r.selected_not_interacting (r1er));
- EXPECT_EQ (r6.selected_interacting (r1e).is_merged (), false);
- EXPECT_EQ (r6.selected_interacting (r1er).is_merged (), false);
+ EXPECT_EQ (r6.selected_interacting (r1e).is_merged (), true);
+ EXPECT_EQ (r6.selected_interacting (r1er).is_merged (), true);
EXPECT_EQ (r6r.selected_interacting (r1e).is_merged (), false);
EXPECT_EQ (r6r.selected_interacting (r1er).is_merged (), false);
@@ -1470,6 +1469,16 @@ TEST(25_Pull)
db::Region r6r = r6;
r6r.set_merged_semantics (false);
+ db::Edges r1e = r1.edges ();
+ db::Edges r1ef = r1f.edges ();
+ db::Edges r1er = r1r.edges ();
+ r1er.set_merged_semantics (false);
+
+ db::Edges r6e = r6.edges ();
+ db::Edges r6ef = r6f.edges ();
+ db::Edges r6er = r6r.edges ();
+ r6er.set_merged_semantics (false);
+
{
db::Layout target;
unsigned int target_top_cell_index = target.add_cell (ly.cell_name (top_cell_index));
@@ -1499,8 +1508,8 @@ TEST(25_Pull)
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (62, 0)), r2r.pull_overlapping (r6r));
EXPECT_EQ (r2.pull_inside (r6).is_merged (), true);
- EXPECT_EQ (r2.pull_interacting (r6).is_merged (), false);
- EXPECT_EQ (r2r.pull_interacting (r6).is_merged (), false);
+ EXPECT_EQ (r2.pull_interacting (r6).is_merged (), true);
+ EXPECT_EQ (r2r.pull_interacting (r6).is_merged (), true);
EXPECT_EQ (r2.pull_interacting (r6r).is_merged (), false);
EXPECT_EQ (r2r.pull_interacting (r6r).is_merged (), false);
@@ -1508,16 +1517,6 @@ TEST(25_Pull)
db::compare_layouts (_this, target, tl::testdata () + "/algo/deep_region_au25a.gds");
}
- db::Edges r1e = r1.edges ();
- db::Edges r1ef = r1f.edges ();
- db::Edges r1er = r1r.edges ();
- r1er.set_merged_semantics (false);
-
- db::Edges r6e = r6.edges ();
- db::Edges r6ef = r6f.edges ();
- db::Edges r6er = r6r.edges ();
- r6er.set_merged_semantics (false);
-
{
db::Layout target;
unsigned int target_top_cell_index = target.add_cell (ly.cell_name (top_cell_index));
@@ -1800,7 +1799,7 @@ TEST(30a_interact_with_count_region)
EXPECT_EQ (r.selected_interacting (rr2, 2, 5).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_interacting (rr2, 4, 5).to_string (), "");
- EXPECT_EQ (r.selected_not_interacting (empty).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
+ EXPECT_EQ (r.selected_not_interacting (empty).to_string (), "(0,0;0,200;100,200;100,0);(-100,-100;-100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_not_interacting (rr).to_string (), "");
EXPECT_EQ (r.selected_not_interacting (rr, 0, 2).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_not_interacting (rr, 1, 2).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
@@ -1891,7 +1890,7 @@ TEST(30b_interact_with_count_edge)
EXPECT_EQ (r.selected_interacting (rr2, 2, 5).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_interacting (rr2, 4, 5).to_string (), "");
- EXPECT_EQ (r.selected_not_interacting (empty).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
+ EXPECT_EQ (r.selected_not_interacting (empty).to_string (), "(0,0;0,200;100,200;100,0);(-100,-100;-100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_not_interacting (rr).to_string (), "");
EXPECT_EQ (r.selected_not_interacting (rr, 0, 2).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_not_interacting (rr, 1, 2).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
@@ -1981,7 +1980,7 @@ TEST(30c_interact_with_count_text)
EXPECT_EQ (r.selected_interacting (rr2, 2, 5).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_interacting (rr2, 4, 5).to_string (), "");
- EXPECT_EQ (r.selected_not_interacting (empty).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
+ EXPECT_EQ (r.selected_not_interacting (empty).to_string (), "(0,0;0,200;100,200;100,0);(-100,-100;-100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_not_interacting (rr).to_string (), "");
EXPECT_EQ (r.selected_not_interacting (rr, 0, 2).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_not_interacting (rr, 1, 2).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
@@ -2018,6 +2017,115 @@ TEST(30c_interact_with_count_text)
EXPECT_EQ (r.selected_not_interacting (rr, 3, 4).to_string (), "(0,0;0,200;100,200;100,0)");
}
+TEST(31_in)
+{
+ db::Layout ly;
+ {
+ std::string fn (tl::testdata ());
+ fn += "/algo/deep_region_l31.gds";
+ tl::InputStream stream (fn);
+ db::Reader reader (stream);
+ reader.read (ly);
+ }
+
+ db::cell_index_type top_cell_index = *ly.begin_top_down ();
+ db::Cell &top_cell = ly.cell (top_cell_index);
+
+ db::DeepShapeStore dss;
+
+ unsigned int l1 = ly.get_layer (db::LayerProperties (1, 0));
+ unsigned int l2 = ly.get_layer (db::LayerProperties (2, 0));
+ unsigned int l3 = ly.get_layer (db::LayerProperties (3, 0)); // empty
+
+ db::Region r1 (db::RecursiveShapeIterator (ly, top_cell, l1), dss);
+ db::Region r2 (db::RecursiveShapeIterator (ly, top_cell, l2), dss);
+ db::Region r3 (db::RecursiveShapeIterator (ly, top_cell, l3), dss);
+ db::Region r1r = r1;
+ r1r.set_merged_semantics (false);
+ db::Region r2r = r2;
+ r2r.set_merged_semantics (false);
+
+ db::Layout target;
+ unsigned int target_top_cell_index = target.add_cell (ly.cell_name (top_cell_index));
+
+ target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (1, 0)), r1);
+ target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (2, 0)), r2);
+
+ target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (10, 0)), r2.in (r1));
+ target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (11, 0)), r2.in (r1, true));
+ target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (12, 0)), r2.in (r3, false));
+ target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (13, 0)), r2.in (r3, true));
+ target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (14, 0)), r3.in (r1, false));
+ target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (15, 0)), r3.in (r1, true));
+
+ target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (20, 0)), r2r.in (r1));
+ target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (21, 0)), r2r.in (r1, true));
+
+ target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (30, 0)), r2.in (r1r));
+ target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (31, 0)), r2.in (r1r, true));
+
+ target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (40, 0)), r2r.in (r1r));
+ target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (41, 0)), r2r.in (r1r, true));
+
+ CHECKPOINT();
+ db::compare_layouts (_this, target, tl::testdata () + "/algo/deep_region_au31.gds");
+}
+
+TEST(31_in_and_out)
+{
+ db::Layout ly;
+ {
+ std::string fn (tl::testdata ());
+ fn += "/algo/deep_region_l31.gds";
+ tl::InputStream stream (fn);
+ db::Reader reader (stream);
+ reader.read (ly);
+ }
+
+ db::cell_index_type top_cell_index = *ly.begin_top_down ();
+ db::Cell &top_cell = ly.cell (top_cell_index);
+
+ db::DeepShapeStore dss;
+
+ unsigned int l1 = ly.get_layer (db::LayerProperties (1, 0));
+ unsigned int l2 = ly.get_layer (db::LayerProperties (2, 0));
+ unsigned int l3 = ly.get_layer (db::LayerProperties (3, 0)); // empty
+
+ db::Region r1 (db::RecursiveShapeIterator (ly, top_cell, l1), dss);
+ db::Region r2 (db::RecursiveShapeIterator (ly, top_cell, l2), dss);
+ db::Region r3 (db::RecursiveShapeIterator (ly, top_cell, l3), dss);
+
+ db::Region r1r = r1;
+ r1r.set_merged_semantics (false);
+ db::Region r2r = r2;
+ r2r.set_merged_semantics (false);
+
+ db::Layout target;
+ unsigned int target_top_cell_index = target.add_cell (ly.cell_name (top_cell_index));
+
+ target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (1, 0)), r1);
+ target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (2, 0)), r2);
+
+ target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (10, 0)), r2.in_and_out (r1).first);
+ target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (11, 0)), r2.in_and_out (r1).second);
+ target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (12, 0)), r2.in_and_out (r3).first);
+ target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (13, 0)), r2.in_and_out (r3).second);
+ target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (14, 0)), r3.in_and_out (r1).first);
+ target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (15, 0)), r3.in_and_out (r1).second);
+
+ target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (20, 0)), r2r.in_and_out (r1).first);
+ target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (21, 0)), r2r.in_and_out (r1).second);
+
+ target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (30, 0)), r2.in_and_out (r1r).first);
+ target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (31, 0)), r2.in_and_out (r1r).second);
+
+ target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (40, 0)), r2r.in_and_out (r1r).first);
+ target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (41, 0)), r2r.in_and_out (r1r).second);
+
+ CHECKPOINT();
+ db::compare_layouts (_this, target, tl::testdata () + "/algo/deep_region_au31.gds");
+}
+
TEST(100_Integration)
{
db::Layout ly;
diff --git a/src/db/unit_tests/dbEdgesTests.cc b/src/db/unit_tests/dbEdgesTests.cc
index 96d2d4068..7f7fac46b 100644
--- a/src/db/unit_tests/dbEdgesTests.cc
+++ b/src/db/unit_tests/dbEdgesTests.cc
@@ -1121,6 +1121,42 @@ TEST(27)
EXPECT_EQ (db::compare (e.selected_outside_differential (ee).second, "(1100,-1000;1100,2000);(1200,-1000;1200,0);(1300,-800;1300,-200);(1400,1000;1400,1100);(1500,1000;1500,2100);(1600,-800;1600,-200);(1900,1000;1900,2000)"), true);
}
+// Edges::in and Edges:in_and_out
+TEST(28)
+{
+ db::Edges e;
+ e.insert (db::Edge (0, 0, 0, 1000));
+ e.insert (db::Edge (0, 1000, 0, 2000));
+ e.insert (db::Edge (100, 0, 100, 1000));
+
+ db::Edges ee;
+ ee.insert (db::Edge (0, 0, 0, 2000));
+ ee.insert (db::Edge (100, 1000, 0, 2000));
+ ee.insert (db::Edge (100, 0, 100, 1000));
+
+ EXPECT_EQ (db::compare (e.in (db::Edges ()), ""), true);
+ EXPECT_EQ (db::compare (e.in (db::Edges (), true), "(0,0;0,1000);(0,1000;0,2000);(100,0;100,1000)"), true);
+ EXPECT_EQ (db::compare (e.in_and_out (db::Edges ()).first, ""), true);
+ EXPECT_EQ (db::compare (e.in_and_out (db::Edges ()).second, "(0,0;0,1000);(0,1000;0,2000);(100,0;100,1000)"), true);
+ EXPECT_EQ (db::compare (db::Edges ().in (ee), ""), true);
+ EXPECT_EQ (db::compare (db::Edges ().in (ee, true), ""), true);
+ EXPECT_EQ (db::compare (db::Edges ().in_and_out (ee).first, ""), true);
+ EXPECT_EQ (db::compare (db::Edges ().in_and_out (ee).second, ""), true);
+ EXPECT_EQ (db::compare (e.in (ee), "(0,0;0,2000);(100,0;100,1000)"), true);
+ EXPECT_EQ (db::compare (e.in (ee, true), ""), true);
+ EXPECT_EQ (db::compare (e.in_and_out (ee).first, "(0,0;0,2000);(100,0;100,1000)"), true);
+ EXPECT_EQ (db::compare (e.in_and_out (ee).second, ""), true);
+ EXPECT_EQ (db::compare (ee.in (e, true), "(100,1000;0,2000)"), true);
+ EXPECT_EQ (db::compare (ee.in_and_out (e).second, "(100,1000;0,2000)"), true);
+
+ e.set_merged_semantics (false);
+ ee.set_merged_semantics (false);
+
+ EXPECT_EQ (db::compare (e.in (ee), "(100,0;100,1000)"), true);
+ EXPECT_EQ (db::compare (e.in (ee, true), "(0,0;0,1000);(0,1000;0,2000)"), true);
+ EXPECT_EQ (db::compare (ee.in (e, true), "(0,0;0,2000);(100,1000;0,2000)"), true);
+}
+
// GitHub issue #72 (Edges/Region NOT issue)
TEST(100)
{
diff --git a/src/db/unit_tests/dbRegionTests.cc b/src/db/unit_tests/dbRegionTests.cc
index adb905dc1..c29654f1c 100644
--- a/src/db/unit_tests/dbRegionTests.cc
+++ b/src/db/unit_tests/dbRegionTests.cc
@@ -1095,15 +1095,25 @@ TEST(19)
r2.insert (db::Box (db::Point (0, 0), db::Point (20, 30)));
EXPECT_EQ (r1.in (r2, false).to_string (), "(0,0;0,30;20,30;20,0)");
+ EXPECT_EQ (r1.in_and_out (r2).first.to_string (), "(0,0;0,30;20,30;20,0)");
EXPECT_EQ (r1.in (r2, true).to_string (), "");
+ EXPECT_EQ (r1.in (r1, false).to_string (), "(0,0;0,30;20,30;20,0)");
+ EXPECT_EQ (r1.in (r1, true).to_string (), "");
+ EXPECT_EQ (r1.in_and_out (r2).second.to_string (), "");
EXPECT_EQ (r2.in (r1, true).to_string (), "");
r1.set_merged_semantics (false);
r2.set_merged_semantics (false);
EXPECT_EQ (db::compare (r1.in (r2, false), "(0,0;0,20;20,20;20,0);(0,0;0,30;20,30;20,0)"), true);
+ EXPECT_EQ (db::compare (r1.in_and_out (r2).first, "(0,0;0,20;20,20;20,0);(0,0;0,30;20,30;20,0)"), true);
EXPECT_EQ (r1.in (r2, true).to_string (), "(0,0;0,20;10,20;10,0)");
+ EXPECT_EQ (r1.in_and_out (r2).second.to_string (), "(0,0;0,20;10,20;10,0)");
EXPECT_EQ (r2.in (r1, true).to_string (), "(0,0;0,10;20,10;20,0)");
+ EXPECT_EQ (r1.in (db::Region (), false).to_string (), "");
+ EXPECT_EQ (db::compare (r1.in (db::Region (), true), "(0,0;0,20;10,20;10,0);(0,0;0,20;20,20;20,0);(0,0;0,30;20,30;20,0)"), true);
+ EXPECT_EQ (db::Region ().in (r1, false).to_string (), "");
+ EXPECT_EQ (db::Region ().in (r1, true).to_string (), "");
}
TEST(20)
diff --git a/src/doc/doc/about/drc_ref_layer.xml b/src/doc/doc/about/drc_ref_layer.xml
index 323b77638..10321b4c6 100644
--- a/src/doc/doc/about/drc_ref_layer.xml
+++ b/src/doc/doc/about/drc_ref_layer.xml
@@ -1342,6 +1342,44 @@ The following image shows the effect of the "in" method (input1: red, input2: bl
+"in_and_out" - Selects shapes or regions of self which are and which are not contained in the other layer
+
+Usage:
+
+- (in, not_in) = layer.in_and_out(other)
+
+
+This method is equivalent to calling in and not_in, but more
+efficient as it delivers both results in a single call.
+
+This method is available for polygon, text and edge layers. Edges can be selected
+with respect to other edges or polygons. Texts can be selected with respect to
+polygons. Polygons can be selected with respect to edges, texts and other polygons.
+
+The following image shows the effect of the "interacting" method (input1: red, input2: blue):
+
+
+
+ |
+
+
+
+If a single count is given, shapes from self are selected only if they do interact at least with the given
+number of (different) shapes from the other layer. If a min and max count is given, shapes from
+self are selected only if they interact with min_count or more, but a maximum of max_count different shapes
+from the other layer. Two polygons overlapping or touching at two locations are counted as single interactions.
+
+
+
"insert" - Inserts one or many objects into the layer
Usage:
@@ -1448,50 +1486,6 @@ method computing both inside and outside part in a single call.
-"interacting" - Selects shapes or regions of self which touch or overlap shapes from the other region
-
-Usage:
-
-- layer.interacting(other)
-- layer.interacting(other, min_count)
-- layer.interacting(other, min_count, max_count)
-- layer.interacting(other, min_count .. max_count)
-
-
-This method selects all shapes or regions from self which touch or overlap shapes from the other
-region. Unless self is in raw mode (see raw), coherent regions are selected from self,
-otherwise individual shapes are selected.
-It returns a new layer containing the selected shapes. A version which modifies self
-is select_interacting.
-
-This method is available for polygon, text and edge layers. Edges can be selected
-with respect to other edges or polygons. Texts can be selected with respect to
-polygons. Polygons can be selected with respect to edges, texts and other polygons.
-
-The following image shows the effect of the "interacting" method (input1: red, input2: blue):
-
-
-
- |
-
-
-
-If a single count is given, shapes from self are selected only if they do interact at least with the given
-number of (different) shapes from the other layer. If a min and max count is given, shapes from
-self are selected only if they interact with min_count or more, but a maximum of max_count different shapes
-from the other layer. Two polygons overlapping or touching at two locations are counted as single interactions.
-
-
-
"intersections" - Returns the intersection points of intersecting edge segments for two edge collections
Usage:
diff --git a/src/drc/drc/built-in-macros/_drc_layer.rb b/src/drc/drc/built-in-macros/_drc_layer.rb
index abea2dd64..aef166151 100644
--- a/src/drc/drc/built-in-macros/_drc_layer.rb
+++ b/src/drc/drc/built-in-macros/_drc_layer.rb
@@ -2442,6 +2442,13 @@ CODE
# @/tr
# @/table
+ # %DRC%
+ # @name in_and_out
+ # @brief Selects shapes or regions of self which are and which are not contained in the other layer
+ # @synopsis (in, not_in) = layer.in_and_out(other)
+ # This method is equivalent to calling \in and \not_in, but more
+ # efficient as it delivers both results in a single call.
+
# %DRC%
# @name interacting
# @brief Selects shapes or regions of self which touch or overlap shapes from the other region
@@ -2844,6 +2851,24 @@ CODE
CODE
end
+ %w(in_and_out).each do |f|
+ eval <<"CODE"
+ def #{f}(other, *args)
+
+ @engine._context("#{f}") do
+
+ requires_same_type(other)
+ requires_edges_or_region
+
+ res = @engine._tcmd_a2(self.data, 0, self.data.class, self.data.class, :#{f}, other.data)
+ [ DRCLayer::new(@engine, res[0]), DRCLayer::new(@engine, res[1]) ]
+
+ end
+
+ end
+CODE
+ end
+
%w(split_interacting).each do |f|
eval <<"CODE"
def #{f}(other, *args)
diff --git a/src/drc/unit_tests/drcSimpleTests.cc b/src/drc/unit_tests/drcSimpleTests.cc
index 7ba20d07b..ab37a7f8a 100644
--- a/src/drc/unit_tests/drcSimpleTests.cc
+++ b/src/drc/unit_tests/drcSimpleTests.cc
@@ -1376,3 +1376,13 @@ TEST(57d_issue_1190)
{
run_test (_this, "57", true);
}
+
+TEST(58_in_and_out)
+{
+ run_test (_this, "58", false);
+}
+
+TEST(58d_in_and_out)
+{
+ run_test (_this, "58", true);
+}
diff --git a/src/lym/lym/lymMacroCollection.cc b/src/lym/lym/lymMacroCollection.cc
index 3316ef036..e6ac4ee9b 100644
--- a/src/lym/lym/lymMacroCollection.cc
+++ b/src/lym/lym/lymMacroCollection.cc
@@ -422,7 +422,8 @@ void MacroCollection::scan ()
}
}
- std::vector dirs = tl::dir_entries (p, false /*with_files*/, true /*with_dirs*/, true /*without_dotfiles*/);
+ // NOTE: we add files to capture symlinks to directories
+ std::vector dirs = tl::dir_entries (p, true /*with_files*/, true /*with_dirs*/, true /*without_dotfiles*/);
for (auto f = dirs.begin (); f != dirs.end (); ++f) {
std::string fp = tl::combine_path (p, *f);
diff --git a/testdata/algo/deep_edges_au20.gds b/testdata/algo/deep_edges_au20.gds
new file mode 100644
index 000000000..45fee953f
Binary files /dev/null and b/testdata/algo/deep_edges_au20.gds differ
diff --git a/testdata/algo/deep_region_au31.gds b/testdata/algo/deep_region_au31.gds
new file mode 100644
index 000000000..49e69259c
Binary files /dev/null and b/testdata/algo/deep_region_au31.gds differ
diff --git a/testdata/algo/deep_region_l31.gds b/testdata/algo/deep_region_l31.gds
new file mode 100644
index 000000000..1c6661453
Binary files /dev/null and b/testdata/algo/deep_region_l31.gds differ
diff --git a/testdata/drc/drcSimpleTests_58.drc b/testdata/drc/drcSimpleTests_58.drc
new file mode 100644
index 000000000..611071b3c
--- /dev/null
+++ b/testdata/drc/drcSimpleTests_58.drc
@@ -0,0 +1,27 @@
+
+source $drc_test_source
+target $drc_test_target
+
+if $drc_test_deep
+ deep
+end
+
+l1 = input(1, 0)
+l2 = input(2, 0)
+
+l1.output(1, 0)
+l2.output(2, 0)
+
+l1e = l1.edges
+l2e = l2.edges
+
+l2.in(l1).output(10, 0)
+l2.not_in(l1).output(11, 0)
+l2.in_and_out(l1).first.output(12, 0)
+l2.in_and_out(l1).last.output(13, 0)
+
+l2e.in(l1e).output(20, 0)
+l2e.not_in(l1e).output(21, 0)
+l2e.in_and_out(l1e).first.output(22, 0)
+l2e.in_and_out(l1e).last.output(23, 0)
+
diff --git a/testdata/drc/drcSimpleTests_58.gds b/testdata/drc/drcSimpleTests_58.gds
new file mode 100644
index 000000000..1c6661453
Binary files /dev/null and b/testdata/drc/drcSimpleTests_58.gds differ
diff --git a/testdata/drc/drcSimpleTests_au58.gds b/testdata/drc/drcSimpleTests_au58.gds
new file mode 100644
index 000000000..41d44f9a9
Binary files /dev/null and b/testdata/drc/drcSimpleTests_au58.gds differ
diff --git a/testdata/drc/drcSimpleTests_au58d.gds b/testdata/drc/drcSimpleTests_au58d.gds
new file mode 100644
index 000000000..64fdc5841
Binary files /dev/null and b/testdata/drc/drcSimpleTests_au58d.gds differ
diff --git a/testdata/drc/drcSuiteTests_au6.oas b/testdata/drc/drcSuiteTests_au6.oas
index 411786177..b29bc12cd 100644
Binary files a/testdata/drc/drcSuiteTests_au6.oas and b/testdata/drc/drcSuiteTests_au6.oas differ