Hierarchical implementation of edge/edge booleans.

This commit is contained in:
Matthias Koefferlein 2019-02-17 15:07:16 +01:00
parent 8e5bffcf18
commit e6ee1c064e
6 changed files with 218 additions and 8 deletions

View File

@ -28,6 +28,9 @@
#include "dbEdgeBoolean.h"
#include "dbCellMapping.h"
#include "dbLayoutUtils.h"
#include "dbLocalOperation.h"
#include "dbHierProcessor.h"
#include "dbEmptyEdges.h"
namespace db
{
@ -506,10 +509,42 @@ EdgesDelegate *DeepEdges::merged () const
return res.release ();
}
DeepLayer
DeepEdges::and_or_not_with (const DeepEdges *other, bool and_op) const
{
DeepLayer dl_out (m_deep_layer.derived ());
db::EdgeBoolAndOrNotLocalOperation op (and_op);
db::local_processor<db::Edge, db::Edge, db::Edge> proc (const_cast<db::Layout *> (&m_deep_layer.layout ()), const_cast<db::Cell *> (&m_deep_layer.initial_cell ()), &other->deep_layer ().layout (), &other->deep_layer ().initial_cell ());
proc.set_base_verbosity (base_verbosity ());
proc.set_threads (m_deep_layer.store ()->threads ());
proc.set_area_ratio (m_deep_layer.store ()->max_area_ratio ());
proc.set_max_vertex_count (m_deep_layer.store ()->max_vertex_count ());
proc.run (&op, m_deep_layer.layer (), other->deep_layer ().layer (), dl_out.layer ());
return dl_out;
}
EdgesDelegate *DeepEdges::and_with (const Edges &other) const
{
// TODO: implement
return AsIfFlatEdges::and_with (other);
const DeepEdges *other_deep = dynamic_cast <const DeepEdges *> (other.delegate ());
if (empty () || other.empty ()) {
// Nothing to do
return new EmptyEdges ();
} else if (! other_deep) {
return AsIfFlatEdges::and_with (other);
} else {
return new DeepEdges (and_or_not_with (other_deep, true));
}
}
EdgesDelegate *DeepEdges::and_with (const Region &other) const
@ -520,8 +555,27 @@ EdgesDelegate *DeepEdges::and_with (const Region &other) const
EdgesDelegate *DeepEdges::not_with (const Edges &other) const
{
// TODO: implement
return AsIfFlatEdges::not_with (other);
const DeepEdges *other_deep = dynamic_cast <const DeepEdges *> (other.delegate ());
if (empty ()) {
// Nothing to do
return new EmptyEdges ();
} else if (other.empty ()) {
// Nothing to do
return clone ();
} else if (! other_deep) {
return AsIfFlatEdges::not_with (other);
} else {
return new DeepEdges (and_or_not_with (other_deep, false));
}
}
EdgesDelegate *DeepEdges::not_with (const Region &other) const
@ -532,14 +586,39 @@ EdgesDelegate *DeepEdges::not_with (const Region &other) const
EdgesDelegate *DeepEdges::xor_with (const Edges &other) const
{
// TODO: implement
return AsIfFlatEdges::xor_with (other);
const DeepEdges *other_deep = dynamic_cast <const DeepEdges *> (other.delegate ());
if (empty ()) {
// Nothing to do
return other.delegate ()->clone ();
} else if (other.empty ()) {
// Nothing to do
return clone ();
} else if (! other_deep) {
return AsIfFlatEdges::xor_with (other);
} else {
// Implement XOR as (A-B)+(B-A) - only this implementation
// is compatible with the local processor scheme
DeepLayer n1 (and_or_not_with (other_deep, false));
DeepLayer n2 (other_deep->and_or_not_with (this, false));
n1.add_from (n2);
return new DeepEdges (n1);
}
}
EdgesDelegate *DeepEdges::or_with (const Edges &other) const
{
// TODO: implement
return AsIfFlatEdges::or_with (other);
// NOTE: in the hierarchical case we don't do a merge on "or": just map to add
return add (other);
}
EdgesDelegate *

View File

@ -169,6 +169,7 @@ private:
void init ();
void ensure_merged_edges_valid () const;
DeepLayer and_or_not_with(const DeepEdges *other, bool and_op) const;
EdgePairs run_check (db::edge_relation_type rel, const Edges *other, db::Coord d, bool whole_edges, metrics_type metrics, double ignore_angle, distance_type min_projection, distance_type max_projection) const;
};

View File

@ -29,6 +29,7 @@
#include "dbPolygonGenerators.h"
#include "dbPolygonTools.h"
#include "dbLocalOperationUtils.h"
#include "dbEdgeBoolean.h"
#include "tlLog.h"
#include "tlTimer.h"
#include "tlInternational.h"
@ -173,5 +174,72 @@ std::string SelfOverlapMergeLocalOperation::description () const
return tl::sprintf (tl::to_string (tr ("Self-overlap (wrap count %d)")), int (m_wrap_count));
}
// ---------------------------------------------------------------------------------------------
// EdgeBoolAndOrNotLocalOperation implementation
EdgeBoolAndOrNotLocalOperation::EdgeBoolAndOrNotLocalOperation (bool is_and)
: m_is_and (is_and)
{
// .. nothing yet ..
}
local_operation<db::Edge, db::Edge, db::Edge>::on_empty_intruder_mode
EdgeBoolAndOrNotLocalOperation::on_empty_intruder_hint () const
{
return m_is_and ? local_operation::Drop : local_operation::Copy;
}
std::string
EdgeBoolAndOrNotLocalOperation::description () const
{
return m_is_and ? tl::to_string (tr ("Edge AND operation")) : tl::to_string (tr ("Edge NOT operation"));
}
void
EdgeBoolAndOrNotLocalOperation::compute_local (db::Layout * /*layout*/, const shape_interactions<db::Edge, db::Edge> &interactions, std::unordered_set<db::Edge> &result, size_t /*max_vertex_count*/, double /*area_ratio*/) const
{
EdgeBooleanClusterCollector<std::unordered_set<db::Edge> > cluster_collector (&result, m_is_and ? EdgeAnd : EdgeNot);
db::box_scanner<db::Edge, size_t> scanner;
std::set<db::Edge> others;
for (shape_interactions<db::Edge, db::Edge>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
for (shape_interactions<db::Edge, db::Edge>::iterator2 j = i->second.begin (); j != i->second.end (); ++j) {
others.insert (interactions.intruder_shape (*j));
}
}
bool any_subject = false;
for (shape_interactions<db::Edge, db::Edge>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
const db::Edge &subject = interactions.subject_shape (i->first);
if (others.find (subject) != others.end ()) {
if (m_is_and) {
result.insert (subject);
}
} else if (i->second.empty ()) {
// shortcut (not: keep, and: drop)
if (! m_is_and) {
result.insert (subject);
}
} else {
scanner.insert (&subject, 0);
any_subject = true;
}
}
if (! others.empty () || any_subject) {
for (std::set<db::Edge>::const_iterator o = others.begin (); o != others.end (); ++o) {
scanner.insert (o.operator-> (), 1);
}
scanner.process (cluster_collector, 1, db::box_convert<db::Edge> ());
}
}
}

View File

@ -144,6 +144,26 @@ private:
unsigned int m_wrap_count;
};
/**
* @brief Implements a boolean AND or NOT operation between edges
*/
class DB_PUBLIC EdgeBoolAndOrNotLocalOperation
: public local_operation<db::Edge, db::Edge, db::Edge>
{
public:
EdgeBoolAndOrNotLocalOperation (bool is_and);
virtual void compute_local (db::Layout *layout, const shape_interactions<db::Edge, db::Edge> &interactions, std::unordered_set<db::Edge> &result, size_t max_vertex_count, double area_ratio) const;
virtual on_empty_intruder_mode on_empty_intruder_hint () const;
virtual std::string description () const;
// edge interaction distance is 1 to force overlap between edges and edge/boxes
virtual db::Coord dist () const { return 1; }
private:
bool m_is_and;
};
}
#endif

View File

@ -25,6 +25,7 @@
#include "dbReader.h"
#include "dbTestSupport.h"
#include "dbEdges.h"
#include "dbRegion.h"
#include "dbDeepShapeStore.h"
#include "tlUnitTest.h"
#include "tlStream.h"
@ -106,3 +107,44 @@ TEST(2_MergeEdges)
db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/deep_edges_au2.gds");
}
TEST(3_Edge2EdgeBooleans)
{
db::Layout ly;
{
std::string fn (tl::testsrc ());
fn += "/testdata/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);
db::DeepShapeStore dss;
unsigned int l2 = ly.get_layer (db::LayerProperties (2, 0));
unsigned int l3 = ly.get_layer (db::LayerProperties (3, 0));
db::Region r2 (db::RecursiveShapeIterator (ly, top_cell, l2), dss);
db::Region r3 (db::RecursiveShapeIterator (ly, top_cell, l3), dss);
db::Region r2and3 = r2 & r3;
db::Edges e3 = r3.edges ();
db::Edges e2and3 = r2and3.edges ();
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 (20, 0)), e3 & e2and3);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (21, 0)), e3 - e2and3);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (22, 0)), e3 ^ e2and3);
CHECKPOINT();
db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/deep_edges_au3.gds");
}

BIN
testdata/algo/deep_edges_au3.gds vendored Normal file

Binary file not shown.