Added tests for Region's andnot.

This commit is contained in:
Matthias Koefferlein 2020-06-14 18:12:17 +02:00
parent 966c351958
commit d141c0895d
11 changed files with 222 additions and 16 deletions

View File

@ -1115,6 +1115,71 @@ AsIfFlatRegion::not_with (const Region &other) const
}
}
std::pair<RegionDelegate *, RegionDelegate *>
AsIfFlatRegion::andnot_with (const Region &other) const
{
if (empty ()) {
// Nothing to do
return std::make_pair (new EmptyRegion (), new EmptyRegion ());
} else if (other.empty () && ! strict_handling ()) {
// Nothing to do
return std::make_pair (new EmptyRegion (), clone ());
} else if (! bbox ().overlaps (other.bbox ()) && ! strict_handling ()) {
// Nothing to do
return std::make_pair (new EmptyRegion (), clone ());
} else {
// Generic case
db::EdgeProcessor ep (report_progress (), progress_desc ());
ep.set_base_verbosity (base_verbosity ());
// count edges and reserve memory
size_t n = 0;
for (RegionIterator p (begin ()); ! p.at_end (); ++p) {
n += p->vertices ();
}
for (RegionIterator p (other.begin ()); ! p.at_end (); ++p) {
n += p->vertices ();
}
ep.reserve (n);
// insert the polygons into the processor
n = 0;
for (RegionIterator p (begin ()); ! p.at_end (); ++p, n += 2) {
ep.insert (*p, n);
}
n = 1;
for (RegionIterator p (other.begin ()); ! p.at_end (); ++p, n += 2) {
ep.insert (*p, n);
}
std::auto_ptr<FlatRegion> new_region1 (new FlatRegion (true));
db::BooleanOp op1 (db::BooleanOp::And);
db::ShapeGenerator pc1 (new_region1->raw_polygons (), true /*clear*/);
db::PolygonGenerator pg1 (pc1, false /*don't resolve holes*/, min_coherence ());
std::auto_ptr<FlatRegion> new_region2 (new FlatRegion (true));
db::BooleanOp op2 (db::BooleanOp::ANotB);
db::ShapeGenerator pc2 (new_region2->raw_polygons (), true /*clear*/);
db::PolygonGenerator pg2 (pc2, false /*don't resolve holes*/, min_coherence ());
std::vector<std::pair<db::EdgeSink *, db::EdgeEvaluatorBase *> > procs;
procs.push_back (std::make_pair (&pg1, &op1));
procs.push_back (std::make_pair (&pg2, &op2));
ep.process (procs);
return std::make_pair (new_region1.release (), new_region2.release ());
}
}
RegionDelegate *
AsIfFlatRegion::xor_with (const Region &other) const
{

View File

@ -154,6 +154,7 @@ public:
virtual RegionDelegate *not_with (const Region &other) const;
virtual RegionDelegate *xor_with (const Region &other) const;
virtual RegionDelegate *or_with (const Region &other) const;
virtual std::pair<RegionDelegate *, RegionDelegate *> andnot_with (const Region &) const;
virtual RegionDelegate *add_in_place (const Region &other)
{

View File

@ -542,6 +542,31 @@ DeepRegion::not_with (const Region &other) const
}
}
std::pair<RegionDelegate *, RegionDelegate *>
DeepRegion::andnot_with (const Region &other) const
{
const DeepRegion *other_deep = dynamic_cast <const DeepRegion *> (other.delegate ());
if (empty ()) {
return std::make_pair (clone (), clone ());
} else if (other.empty ()) {
return std::make_pair (other.delegate ()->clone (), clone ());
} else if (! other_deep) {
return AsIfFlatRegion::andnot_with (other);
} else {
std::pair<DeepLayer, DeepLayer> res = and_and_not_with (other_deep);
return std::make_pair (new DeepRegion (res.first), new DeepRegion (res.second));
}
}
DeepLayer
DeepRegion::and_or_not_with (const DeepRegion *other, bool and_op) const
{
@ -560,6 +585,32 @@ DeepRegion::and_or_not_with (const DeepRegion *other, bool and_op) const
return dl_out;
}
std::pair<DeepLayer, DeepLayer>
DeepRegion::and_and_not_with (const DeepRegion *other) const
{
DeepLayer dl_out1 (deep_layer ().derived ());
DeepLayer dl_out2 (deep_layer ().derived ());
db::TwoBoolAndNotLocalOperation op;
db::local_processor<db::PolygonRef, db::PolygonRef, db::PolygonRef> proc (const_cast<db::Layout *> (&deep_layer ().layout ()), const_cast<db::Cell *> (&deep_layer ().initial_cell ()), &other->deep_layer ().layout (), &other->deep_layer ().initial_cell (), deep_layer ().breakout_cells (), other->deep_layer ().breakout_cells ());
proc.set_base_verbosity (base_verbosity ());
proc.set_threads (deep_layer ().store ()->threads ());
proc.set_area_ratio (deep_layer ().store ()->max_area_ratio ());
proc.set_max_vertex_count (deep_layer ().store ()->max_vertex_count ());
std::vector<unsigned int> il;
il.push_back (other->deep_layer ().layer ());
std::vector<unsigned int> ol;
ol.push_back (dl_out1.layer ());
ol.push_back (dl_out2.layer ());
proc.run (&op, deep_layer ().layer (), il, ol);
return std::make_pair (dl_out1, dl_out2);
}
RegionDelegate *
DeepRegion::xor_with (const Region &other) const
{

View File

@ -83,6 +83,7 @@ public:
virtual RegionDelegate *and_with (const Region &other) const;
virtual RegionDelegate *not_with (const Region &other) const;
virtual RegionDelegate *xor_with (const Region &other) const;
virtual std::pair<RegionDelegate *, RegionDelegate *> andnot_with (const Region &) const;
virtual RegionDelegate *add_in_place (const Region &other);
virtual RegionDelegate *add (const Region &other) const;
@ -184,6 +185,7 @@ private:
void ensure_merged_polygons_valid () const;
const DeepLayer &merged_deep_layer () const;
DeepLayer and_or_not_with(const DeepRegion *other, bool and_op) const;
std::pair<DeepLayer, DeepLayer> and_and_not_with (const DeepRegion *other) const;
EdgePairsDelegate *run_check (db::edge_relation_type rel, bool different_polygons, const Region *other, db::Coord d, bool whole_edges, metrics_type metrics, double ignore_angle, distance_type min_projection, distance_type max_projection) const;
EdgePairsDelegate *run_single_polygon_check (db::edge_relation_type rel, db::Coord d, bool whole_edges, metrics_type metrics, double ignore_angle, distance_type min_projection, distance_type max_projection) const;
virtual RegionDelegate *selected_interacting_generic (const Region &other, int mode, bool touching, bool inverse) const;

View File

@ -95,6 +95,7 @@ public:
virtual RegionDelegate *and_with (const Region &) const { return new EmptyRegion (); }
virtual RegionDelegate *not_with (const Region &) const { return new EmptyRegion (); }
virtual std::pair<RegionDelegate *, RegionDelegate *> andnot_with (const Region &) const { return std::make_pair (new EmptyRegion (), new EmptyRegion ()); }
virtual RegionDelegate *xor_with (const Region &other) const;
virtual RegionDelegate *or_with (const Region &other) const;
virtual RegionDelegate *add_in_place (const Region &other);

View File

@ -1145,6 +1145,17 @@ public:
return *this;
}
/**
* @brief Two-bool ANDNOT operation
*
* The first region delivered will be the AND result, the second one the NOT result.
*/
std::pair<Region, Region> andnot (const Region &other) const
{
std::pair<RegionDelegate *, RegionDelegate *> res = mp_delegate->andnot_with (other);
return std::make_pair (Region (res.first), Region (res.second));
}
/**
* @brief Selects all polygons of this region which are completly outside polygons from the other region
*

View File

@ -263,6 +263,7 @@ public:
virtual RegionDelegate *or_with (const Region &other) const = 0;
virtual RegionDelegate *add_in_place (const Region &other) = 0;
virtual RegionDelegate *add (const Region &other) const = 0;
virtual std::pair<RegionDelegate *, RegionDelegate *> andnot_with (const Region &other) const = 0;
virtual RegionDelegate *selected_outside (const Region &other) const = 0;
virtual RegionDelegate *selected_not_outside (const Region &other) const = 0;

View File

@ -548,6 +548,17 @@ static db::EdgePairs separation2 (const db::Region *r, const db::Region &other,
max_projection.is_nil () ? std::numeric_limits<db::Region::distance_type>::max () : max_projection.to<db::Region::distance_type> ());
}
static std::vector<db::Region> andnot (const db::Region *r, const db::Region &other)
{
std::pair<db::Region, db::Region> rp = r->andnot (other);
std::vector<db::Region> res;
res.resize (2, db::Region ());
res [0] = rp.first;
res [1] = rp.second;
return res;
}
static int euclidian_metrics ()
{
return db::Euclidian;
@ -1311,6 +1322,16 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
) +
method_ext ("andnot", &andnot, gsi::arg ("other"),
"@brief Returns the boolean AND and NOT between self and the other region\n"
"\n"
"@return A two-element array of regions with the first one being the AND result and the second one being the NOT result\n"
"\n"
"This method will compute the boolean AND and NOT between two regions simultaneously. "
"Because this requires a single sweep only, using this method is faster than doing AND and NOT separately.\n"
"\n"
"This method has been added in version 0.27.\n"
) +
method ("&", &db::Region::operator&, gsi::arg ("other"),
"@brief Returns the boolean AND between self and the other region\n"
"\n"

View File

@ -172,6 +172,13 @@ TEST(3_BoolAndNot)
db::Region r42minus3 = r42 - r3;
db::Region r42minus42 = r42 - r42;
db::Region tr2minus3 = r2.andnot (r3).second;
db::Region tr2minusbox = r2.andnot (box).second;
db::Region tr2minus42 = r2.andnot (r42).second;
db::Region trboxminus3 = box.andnot (r3).second;
db::Region tr42minus3 = r42.andnot (r3).second;
db::Region tr42minus42 = r42.andnot (r42).second;
db::Region r2and3 = r2 & r3;
db::Region r2andbox = r2 & box;
db::Region r2and42 = r2 & r42;
@ -179,27 +186,58 @@ TEST(3_BoolAndNot)
db::Region r42and3 = r42 & r3;
db::Region r42and42 = r42 & r42;
db::Region tr2and3 = r2.andnot (r3).first;
db::Region tr2andbox = r2.andnot (box).first;
db::Region tr2and42 = r2.andnot (r42).first;
db::Region trboxand3 = box.andnot (r3).first;
db::Region tr42and3 = r42.andnot (r3).first;
db::Region tr42and42 = r42.andnot (r42).first;
EXPECT_EQ (r2and3.is_merged (), false);
db::Layout target;
unsigned int target_top_cell_index = target.add_cell (ly.cell_name (top_cell_index));
{
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 (10, 0)), r2minus3);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (11, 0)), r2minusbox);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (12, 0)), r2minus42);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (13, 0)), rboxminus3);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (14, 0)), r42minus3);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (15, 0)), r42minus42);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (10, 0)), r2minus3);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (11, 0)), r2minusbox);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (12, 0)), r2minus42);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (13, 0)), rboxminus3);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (14, 0)), r42minus3);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (15, 0)), r42minus42);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (20, 0)), r2and3);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (21, 0)), r2andbox);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (22, 0)), r2and42);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (23, 0)), rboxand3);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (24, 0)), r42and3);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (25, 0)), r42and42);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (20, 0)), r2and3);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (21, 0)), r2andbox);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (22, 0)), r2and42);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (23, 0)), rboxand3);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (24, 0)), r42and3);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (25, 0)), r42and42);
CHECKPOINT();
db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/deep_region_au3.gds");
CHECKPOINT();
db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/deep_region_au3.gds");
}
{
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 (10, 0)), tr2minus3);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (11, 0)), tr2minusbox);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (12, 0)), tr2minus42);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (13, 0)), trboxminus3);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (14, 0)), tr42minus3);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (15, 0)), tr42minus42);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (20, 0)), tr2and3);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (21, 0)), tr2andbox);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (22, 0)), tr2and42);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (23, 0)), trboxand3);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (24, 0)), tr42and3);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (25, 0)), tr42and42);
CHECKPOINT();
db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/deep_region_au3b.gds");
}
}
TEST(4_Add)

View File

@ -202,6 +202,13 @@ TEST(3)
EXPECT_EQ ((db::Region () & r).to_string (), "");
EXPECT_EQ ((db::Region () & r).empty (), true);
EXPECT_EQ (r.andnot(rr).first.to_string (), "(10,20;10,220;110,220;110,20)");
EXPECT_EQ (rr.andnot(r).first.to_string (), "(10,20;10,220;110,220;110,20)");
EXPECT_EQ (r.andnot(db::Region ()).first.to_string (), "");
EXPECT_EQ (r.andnot(db::Region ()).first.empty (), true);
EXPECT_EQ (db::Region ().andnot(r).first.to_string (), "");
EXPECT_EQ (db::Region ().andnot(r).first.empty (), true);
r &= rr;
EXPECT_EQ (r.is_box (), true);
EXPECT_EQ (r.empty (), false);
@ -289,6 +296,14 @@ TEST(7)
EXPECT_EQ ((db::Region () - r).empty (), true);
EXPECT_EQ ((db::Region () - r).is_merged (), true);
EXPECT_EQ (r.andnot(db::Region (db::Box (db::Point (10, 20), db::Point (110, 220)))).second.to_string (), "(-100,-100;-100,400;200,400;200,-100/10,20;110,20;110,220;10,220)");
EXPECT_EQ (r.andnot(db::Region ()).second.to_string (), "(0,0;0,200;100,200;100,0);(-100,-100;-100,400;200,400;200,-100)");
EXPECT_EQ (r.andnot(db::Region ()).second.empty (), false);
EXPECT_EQ (r.andnot(db::Region ()).second.is_merged (), false);
EXPECT_EQ (db::Region ().andnot(r).second.to_string (), "");
EXPECT_EQ (db::Region ().andnot(r).second.empty (), true);
EXPECT_EQ (db::Region ().andnot(r).second.is_merged (), true);
r -= db::Region (db::Box (db::Point (10, 20), db::Point (110, 220)));
EXPECT_EQ (r.is_box (), false);
EXPECT_EQ (r.empty (), false);

BIN
testdata/algo/deep_region_au3b.gds vendored Normal file

Binary file not shown.