mirror of https://github.com/KLayout/klayout.git
Hierarchical implementation of edge/edge booleans.
This commit is contained in:
parent
8e5bffcf18
commit
e6ee1c064e
|
|
@ -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 *
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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> ());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
|
||||
|
|
|
|||
Binary file not shown.
Loading…
Reference in New Issue