mirror of https://github.com/KLayout/klayout.git
Flat edge booleans enhancements
- Basic support for dots (only dots-vs.-dots) - Some shortcuts for efficiency
This commit is contained in:
parent
91e68cef02
commit
fc787b19e3
|
|
@ -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 ());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
Binary file not shown.
Loading…
Reference in New Issue