Flat edge booleans enhancements

- Basic support for dots (only dots-vs.-dots)
- Some shortcuts for efficiency
This commit is contained in:
Matthias Koefferlein 2024-03-06 18:46:52 +01:00
parent 91e68cef02
commit fc787b19e3
5 changed files with 277 additions and 49 deletions

View File

@ -757,9 +757,123 @@ AsIfFlatEdges::run_check (db::edge_relation_type rel, const Edges *other, db::Co
return result.release ();
}
EdgesDelegate *
AsIfFlatEdges::merged () const
{
if (empty ()) {
return new db::EmptyEdges ();
} else {
return boolean (0, EdgeOr);
}
}
EdgesDelegate *
AsIfFlatEdges::and_with (const Edges &other) const
{
if (empty () || other.empty ()) {
return new db::EmptyEdges ();
} else {
return boolean (&other, EdgeAnd);
}
}
EdgesDelegate *
AsIfFlatEdges::not_with (const Edges &other) const
{
if (empty ()) {
return new db::EmptyEdges ();
} else if (other.empty ()) {
return clone ();
} else {
return boolean (&other, EdgeNot);
}
}
std::pair<EdgesDelegate *, EdgesDelegate *>
AsIfFlatEdges::andnot_with (const Edges &other) const
{
if (empty ()) {
return std::make_pair (new db::EmptyEdges (), new db::EmptyEdges ());
} else if (other.empty ()) {
return std::make_pair (new db::EmptyEdges (), clone ());
} else {
return boolean_andnot (&other);
}
}
EdgesDelegate *
AsIfFlatEdges::and_with (const Region &other) const
{
if (empty () || other.empty ()) {
return new db::EmptyEdges ();
} else {
return edge_region_op (other, db::EdgePolygonOp::Inside, true /*include borders*/).first;
}
}
EdgesDelegate *
AsIfFlatEdges::not_with (const Region &other) const
{
if (empty ()) {
return new db::EmptyEdges ();
} else if (other.empty ()) {
return clone ();
} else {
return edge_region_op (other, db::EdgePolygonOp::Outside, true /*include borders*/).first;
}
}
std::pair<EdgesDelegate *, EdgesDelegate *>
AsIfFlatEdges::andnot_with (const Region &other) const
{
if (empty ()) {
return std::make_pair (new db::EmptyEdges (), new db::EmptyEdges ());
} else if (other.empty ()) {
return std::make_pair (new db::EmptyEdges (), clone ());
} else {
return edge_region_op (other, db::EdgePolygonOp::Both, true /*include borders*/);
}
}
EdgesDelegate *
AsIfFlatEdges::xor_with (const Edges &other) const
{
if (empty ()) {
return other.delegate ()->clone ();
} else if (other.empty ()) {
return clone ();
} else {
return boolean (&other, EdgeXor);
}
}
EdgesDelegate *
AsIfFlatEdges::or_with (const Edges &other) const
{
if (empty ()) {
return other.delegate ()->clone ();
} else if (other.empty ()) {
return clone ();
} else {
return boolean (&other, EdgeOr);
}
}
EdgesDelegate *
AsIfFlatEdges::intersections (const Edges &other) const
{
if (empty () || other.empty ()) {
return new db::EmptyEdges ();
} else {
return boolean (&other, EdgeIntersections);
}
}
EdgesDelegate *
AsIfFlatEdges::boolean (const Edges *other, EdgeBoolOp op) const
{
std::set<db::Edge> dots, other_dots;
std::unique_ptr<FlatEdges> output (new FlatEdges (true));
EdgeBooleanClusterCollectorToShapes cluster_collector (&output->raw_edges (), op);
@ -769,8 +883,10 @@ AsIfFlatEdges::boolean (const Edges *other, EdgeBoolOp op) const
AddressableEdgeDelivery e (begin ());
for ( ; ! e.at_end (); ++e) {
if (! e->is_degenerate ()) {
if (op == EdgeIntersections || ! e->is_degenerate ()) {
scanner.insert (e.operator-> (), 0);
} else if (op != EdgeOr) {
dots.insert (*e);
}
}
@ -779,20 +895,58 @@ AsIfFlatEdges::boolean (const Edges *other, EdgeBoolOp op) const
if (other) {
ee = other->addressable_edges ();
for ( ; ! ee.at_end (); ++ee) {
if (! ee->is_degenerate ()) {
if (op == EdgeIntersections || ! ee->is_degenerate ()) {
scanner.insert (ee.operator-> (), 1);
} else if (op != EdgeOr) {
other_dots.insert (*ee);
}
}
}
scanner.process (cluster_collector, 1, db::box_convert<db::Edge> ());
// process dots
// NOTE: currently, dots vs. dots is supported, but not dots vs. edges
if (op == EdgeOr) {
for (auto i = dots.begin (); i != dots.end (); ++i) {
output->insert (*i);
}
for (auto i = other_dots.begin (); i != other_dots.end (); ++i) {
output->insert (*i);
}
} else if (op == EdgeNot) {
for (auto i = dots.begin (); i != dots.end (); ++i) {
if (other_dots.find (*i) == other_dots.end ()) {
output->insert (*i);
}
}
} else if (op == EdgeXor) {
for (auto i = dots.begin (); i != dots.end (); ++i) {
if (other_dots.find (*i) == other_dots.end ()) {
output->insert (*i);
}
}
for (auto i = other_dots.begin (); i != other_dots.end (); ++i) {
if (dots.find (*i) == dots.end ()) {
output->insert (*i);
}
}
} else if (op == EdgeAnd) {
for (auto i = dots.begin (); i != dots.end (); ++i) {
if (other_dots.find (*i) != other_dots.end ()) {
output->insert (*i);
}
}
}
return output.release ();
}
std::pair<EdgesDelegate *, EdgesDelegate *>
AsIfFlatEdges::boolean_andnot (const Edges *other) const
{
std::set<db::Edge> dots, other_dots;
std::unique_ptr<FlatEdges> output (new FlatEdges (true));
std::unique_ptr<FlatEdges> output2 (new FlatEdges (true));
EdgeBooleanClusterCollectorToShapes cluster_collector (&output->raw_edges (), EdgeAndNot, &output2->raw_edges ());
@ -805,6 +959,8 @@ AsIfFlatEdges::boolean_andnot (const Edges *other) const
for ( ; ! e.at_end (); ++e) {
if (! e->is_degenerate ()) {
scanner.insert (e.operator-> (), 0);
} else {
dots.insert (*e);
}
}
@ -815,12 +971,24 @@ AsIfFlatEdges::boolean_andnot (const Edges *other) const
for ( ; ! ee.at_end (); ++ee) {
if (! ee->is_degenerate ()) {
scanner.insert (ee.operator-> (), 1);
} else {
other_dots.insert (*ee);
}
}
}
scanner.process (cluster_collector, 1, db::box_convert<db::Edge> ());
// process dots
// NOTE: currently, dots vs. dots is supported, but not dots vs. edges
for (auto i = dots.begin (); i != dots.end (); ++i) {
if (other_dots.find (*i) == other_dots.end ()) {
output2->insert (*i);
} else {
output->insert (*i);
}
}
return std::make_pair (output.release (), output2.release ());
}

View File

@ -107,55 +107,25 @@ public:
return merged ();
}
virtual EdgesDelegate *merged () const
{
return boolean (0, EdgeOr);
}
virtual EdgesDelegate *merged () const;
virtual EdgesDelegate *and_with (const Edges &other) const
{
return boolean (&other, EdgeAnd);
}
virtual EdgesDelegate *and_with (const Edges &other) const;
virtual EdgesDelegate *not_with (const Edges &other) const
{
return boolean (&other, EdgeNot);
}
virtual EdgesDelegate *not_with (const Edges &other) const;
virtual std::pair<EdgesDelegate *, EdgesDelegate *> andnot_with (const Edges &other) const
{
return boolean_andnot (&other);
}
virtual std::pair<EdgesDelegate *, EdgesDelegate *> andnot_with (const Edges &other) const;
virtual EdgesDelegate *and_with (const Region &other) const
{
return edge_region_op (other, db::EdgePolygonOp::Inside, true /*include borders*/).first;
}
virtual EdgesDelegate *and_with (const Region &other) const;
virtual EdgesDelegate *not_with (const Region &other) const
{
return edge_region_op (other, db::EdgePolygonOp::Outside, true /*include borders*/).first;
}
virtual EdgesDelegate *not_with (const Region &other) const;
virtual std::pair<EdgesDelegate *, EdgesDelegate *> andnot_with (const Region &other) const
{
return edge_region_op (other, db::EdgePolygonOp::Both, true /*include borders*/);
}
virtual std::pair<EdgesDelegate *, EdgesDelegate *> andnot_with (const Region &other) const;
virtual EdgesDelegate *xor_with (const Edges &other) const
{
return boolean (&other, EdgeXor);
}
virtual EdgesDelegate *xor_with (const Edges &other) const;
virtual EdgesDelegate *or_with (const Edges &other) const
{
return boolean (&other, EdgeOr);
}
virtual EdgesDelegate *or_with (const Edges &other) const;
virtual EdgesDelegate *intersections (const Edges &other) const
{
return boolean (&other, EdgeIntersections);
}
virtual EdgesDelegate *intersections (const Edges &other) const;
virtual EdgesDelegate *add_in_place (const Edges &other)
{

View File

@ -272,13 +272,6 @@ struct EdgeBooleanClusterCollector
// .. nothing yet ..
}
EdgeBooleanClusterCollector (OutputContainer *output, OutputContainer *intersections, EdgeBoolOp op)
: db::cluster_collector<db::Edge, size_t, EdgeBooleanCluster<OutputContainer> > (EdgeBooleanCluster<OutputContainer> (output, op), op != EdgeAnd /*report single*/),
mp_output (output), mp_intersections (intersections)
{
// .. nothing yet ..
}
void add (const db::Edge *o1, size_t p1, const db::Edge *o2, size_t p2)
{
// Select edges which are:

View File

@ -22,12 +22,14 @@
#include "tlUnitTest.h"
#include "tlStream.h"
#include "dbEdges.h"
#include "dbEdgesUtils.h"
#include "dbPolygonTools.h"
#include "dbRegion.h"
#include "dbTestSupport.h"
#include "dbReader.h"
#include <cstdlib>
@ -1255,6 +1257,101 @@ TEST(30)
EXPECT_EQ (e.selected_interacting_differential (r2, size_t (2), size_t(3)).second.to_string (), "(0,0;200,0)");
}
// borrowed from deep edges tests
TEST(31)
{
db::Layout ly;
{
std::string fn (tl::testdata ());
fn += "/algo/deep_region_l1.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);
unsigned int l2 = ly.get_layer (db::LayerProperties (2, 0));
unsigned int l3 = ly.get_layer (db::LayerProperties (3, 0));
unsigned int lempty = ly.insert_layer ();
db::Region r2 (db::RecursiveShapeIterator (ly, top_cell, l2));
db::Region r3 (db::RecursiveShapeIterator (ly, top_cell, l3));
db::Region r2and3 = r2 & r3;
db::Edges e2 = r2.edges ();
db::Edges e3 = r3.edges ();
db::Edges e3copy = r3.edges ();
db::Edges e2and3 = r2and3.edges ();
db::Edges eempty (db::RecursiveShapeIterator (ly, top_cell, lempty));
db::Edges edots = e2and3.processed (db::EdgeSegmentSelector (-1, 0, 0));
db::Edges edotscopy = e2and3.processed (db::EdgeSegmentSelector (-1, 0, 0));
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 (2, 0)), r2);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (3, 0)), r3);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (10, 0)), e3);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (11, 0)), e2and3);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (12, 0)), edots);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (13, 0)), edots.merged ());
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (20, 0)), e3 & e2and3);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (21, 0)), e3 & edots);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (22, 0)), e3 & eempty);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (23, 0)), e3 & e3copy);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (24, 0)), eempty & e2and3);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (25, 0)), edots & edotscopy);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (26, 0)), edots & e2);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (30, 0)), e3 - e2and3);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (31, 0)), e3 - edots);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (32, 0)), e3 - eempty);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (33, 0)), e3 - e3copy);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (34, 0)), eempty - e2and3);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (35, 0)), edots - edotscopy);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (36, 0)), edots - e2);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (40, 0)), e3 ^ e2and3);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (41, 0)), e3 ^ edots);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (42, 0)), e3 ^ eempty);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (43, 0)), e3 ^ e3copy);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (44, 0)), eempty ^ e2and3);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (45, 0)), edots ^ edotscopy);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (46, 0)), edots ^ e2);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (50, 0)), e3.andnot(e2and3).first);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (51, 0)), e3.andnot(edots).first);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (52, 0)), e3.andnot(eempty).first);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (53, 0)), e3.andnot(e3copy).first);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (54, 0)), eempty.andnot(e2and3).first);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (55, 0)), edots.andnot(edotscopy).first);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (56, 0)), edots.andnot(e2).first);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (60, 0)), e3.andnot(e2and3).second);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (61, 0)), e3.andnot(edots).second);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (62, 0)), e3.andnot(eempty).second);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (63, 0)), e3.andnot(e3copy).second);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (64, 0)), eempty.andnot(e2and3).second);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (65, 0)), edots.andnot(edotscopy).second);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (66, 0)), edots.andnot(e2).second);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (70, 0)), e3.intersections(e2and3));
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (71, 0)), e3.intersections(edots));
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (72, 0)), e3.intersections(eempty));
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (73, 0)), e3.intersections(e3copy));
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (74, 0)), eempty.intersections(e2and3));
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (75, 0)), edots.intersections(edotscopy));
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (76, 0)), edots.intersections(e2));
// test, whether dots are not merged
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (77, 0)), edots.intersections(e2).select_interacting(e2));
CHECKPOINT();
db::compare_layouts (_this, target, tl::testdata () + "/algo/deep_edges_au3_flat.gds");
}
// GitHub issue #72 (Edges/Region NOT issue)
TEST(100)
{

BIN
testdata/algo/deep_edges_au3_flat.gds vendored Normal file

Binary file not shown.