mirror of https://github.com/KLayout/klayout.git
Hierarchical implementation of edge to region operations.
This commit is contained in:
parent
e6ee1c064e
commit
61d766bd4c
|
|
@ -21,7 +21,9 @@
|
|||
*/
|
||||
|
||||
#include "dbEdges.h"
|
||||
#include "dbRegion.h"
|
||||
#include "dbDeepEdges.h"
|
||||
#include "dbDeepRegion.h"
|
||||
#include "dbHierNetworkProcessor.h"
|
||||
#include "dbCellGraphUtils.h"
|
||||
#include "dbCellVariants.h"
|
||||
|
|
@ -527,6 +529,24 @@ DeepEdges::and_or_not_with (const DeepEdges *other, bool and_op) const
|
|||
return dl_out;
|
||||
}
|
||||
|
||||
DeepLayer
|
||||
DeepEdges::edge_region_op (const DeepRegion *other, bool outside, bool include_borders) const
|
||||
{
|
||||
DeepLayer dl_out (m_deep_layer.derived ());
|
||||
|
||||
db::EdgeToPolygonLocalOperation op (outside, include_borders);
|
||||
|
||||
db::local_processor<db::Edge, db::PolygonRef, 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
|
||||
{
|
||||
const DeepEdges *other_deep = dynamic_cast <const DeepEdges *> (other.delegate ());
|
||||
|
|
@ -549,8 +569,27 @@ EdgesDelegate *DeepEdges::and_with (const Edges &other) const
|
|||
|
||||
EdgesDelegate *DeepEdges::and_with (const Region &other) const
|
||||
{
|
||||
// TODO: implement
|
||||
return AsIfFlatEdges::and_with (other);
|
||||
const DeepRegion *other_deep = dynamic_cast <const DeepRegion *> (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 (edge_region_op (other_deep, false /*outside*/, true /*include borders*/));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
EdgesDelegate *DeepEdges::not_with (const Edges &other) const
|
||||
|
|
@ -580,8 +619,27 @@ EdgesDelegate *DeepEdges::not_with (const Edges &other) const
|
|||
|
||||
EdgesDelegate *DeepEdges::not_with (const Region &other) const
|
||||
{
|
||||
// TODO: implement
|
||||
return AsIfFlatEdges::not_with (other);
|
||||
const DeepRegion *other_deep = dynamic_cast <const DeepRegion *> (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 (edge_region_op (other_deep, true /*outside*/, true /*include borders*/));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
EdgesDelegate *DeepEdges::xor_with (const Edges &other) const
|
||||
|
|
@ -663,14 +721,52 @@ EdgesDelegate *DeepEdges::add (const Edges &other) const
|
|||
|
||||
EdgesDelegate *DeepEdges::inside_part (const Region &other) const
|
||||
{
|
||||
// TODO: implement
|
||||
return AsIfFlatEdges::inside_part (other);
|
||||
const DeepRegion *other_deep = dynamic_cast <const DeepRegion *> (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 (edge_region_op (other_deep, false /*outside*/, false /*include borders*/));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
EdgesDelegate *DeepEdges::outside_part (const Region &other) const
|
||||
{
|
||||
// TODO: implement
|
||||
return AsIfFlatEdges::outside_part (other);
|
||||
const DeepRegion *other_deep = dynamic_cast <const DeepRegion *> (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 (edge_region_op (other_deep, true /*outside*/, false /*include borders*/));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
RegionDelegate *DeepEdges::extended (coord_type ext_b, coord_type ext_e, coord_type ext_o, coord_type ext_i, bool join) const
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@
|
|||
namespace db {
|
||||
|
||||
class Edges;
|
||||
class DeepRegion;
|
||||
|
||||
/**
|
||||
* @brief Provides hierarchical edges implementation
|
||||
|
|
@ -170,6 +171,7 @@ private:
|
|||
void init ();
|
||||
void ensure_merged_edges_valid () const;
|
||||
DeepLayer and_or_not_with(const DeepEdges *other, bool and_op) const;
|
||||
DeepLayer edge_region_op (const DeepRegion *other, bool outside, bool include_borders) 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;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -241,5 +241,70 @@ EdgeBoolAndOrNotLocalOperation::compute_local (db::Layout * /*layout*/, const sh
|
|||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------------------
|
||||
// EdgeToPolygonLocalOperation implementation
|
||||
|
||||
EdgeToPolygonLocalOperation::EdgeToPolygonLocalOperation (bool outside, bool include_borders)
|
||||
: m_outside (outside), m_include_borders (include_borders)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
local_operation<db::Edge, db::PolygonRef, db::Edge>::on_empty_intruder_mode
|
||||
EdgeToPolygonLocalOperation::on_empty_intruder_hint () const
|
||||
{
|
||||
return m_outside ? local_operation::Copy : local_operation::Drop;
|
||||
}
|
||||
|
||||
std::string
|
||||
EdgeToPolygonLocalOperation::description () const
|
||||
{
|
||||
return tl::to_string (m_outside ? tr ("Edge to polygon AND/INSIDE") : tr ("Edge to polygons NOT/OUTSIDE"));
|
||||
}
|
||||
|
||||
void
|
||||
EdgeToPolygonLocalOperation::compute_local (db::Layout * /*layout*/, const shape_interactions<db::Edge, db::PolygonRef> &interactions, std::unordered_set<db::Edge> &result, size_t /*max_vertex_count*/, double /*area_ratio*/) const
|
||||
{
|
||||
db::EdgeProcessor ep;
|
||||
|
||||
std::set<db::PolygonRef> others;
|
||||
for (shape_interactions<db::Edge, db::PolygonRef>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
|
||||
for (shape_interactions<db::Edge, db::PolygonRef>::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::PolygonRef>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
|
||||
|
||||
const db::Edge &subject = interactions.subject_shape (i->first);
|
||||
if (i->second.empty ()) {
|
||||
// shortcut (outside: keep, otherwise: drop)
|
||||
if (m_outside) {
|
||||
result.insert (subject);
|
||||
}
|
||||
} else {
|
||||
ep.insert (subject, 1);
|
||||
any_subject = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (! others.empty () || any_subject) {
|
||||
|
||||
for (std::set<db::PolygonRef>::const_iterator o = others.begin (); o != others.end (); ++o) {
|
||||
for (db::PolygonRef::polygon_edge_iterator e = o->begin_edge (); ! e.at_end (); ++e) {
|
||||
ep.insert (*e, 0);
|
||||
}
|
||||
}
|
||||
|
||||
db::EdgeToEdgeSetGenerator cc (result);
|
||||
db::EdgePolygonOp op (m_outside, m_include_borders);
|
||||
ep.process (cc, op);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -164,6 +164,30 @@ private:
|
|||
bool m_is_and;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Implements a boolean AND or NOT operation between edges and polygons (polygons as intruders)
|
||||
*
|
||||
* "AND" is implemented by "outside == false", "NOT" by "outside == true" with "include_borders == true".
|
||||
* With "include_borders == false" the operations are "INSIDE" and "OUTSIDE".
|
||||
*/
|
||||
class DB_PUBLIC EdgeToPolygonLocalOperation
|
||||
: public local_operation<db::Edge, db::PolygonRef, db::Edge>
|
||||
{
|
||||
public:
|
||||
EdgeToPolygonLocalOperation (bool outside, bool include_borders);
|
||||
|
||||
virtual void compute_local (db::Layout *layout, const shape_interactions<db::Edge, db::PolygonRef> &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 m_include_borders ? 1 : 0; }
|
||||
|
||||
private:
|
||||
bool m_outside;
|
||||
bool m_include_borders;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -42,6 +42,20 @@ void PolygonRefGenerator::put (const db::Polygon &polygon)
|
|||
mp_polyrefs->insert (db::PolygonRef (polygon, mp_layout->shape_repository ()));
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------
|
||||
// class EdgeToEdgeSetGenerator
|
||||
|
||||
EdgeToEdgeSetGenerator::EdgeToEdgeSetGenerator (std::unordered_set<db::Edge> &edges)
|
||||
: mp_edges (&edges)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
void EdgeToEdgeSetGenerator::put (const db::Edge &edge)
|
||||
{
|
||||
mp_edges->insert (edge);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------
|
||||
// class PolygonRefGenerator
|
||||
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ class PolygonRefGenerator
|
|||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Constructor specifying an external vector for storing the polygons
|
||||
* @brief Constructor
|
||||
*/
|
||||
PolygonRefGenerator (db::Layout *layout, std::unordered_set<db::PolygonRef> &polyrefs);
|
||||
|
||||
|
|
@ -55,6 +55,24 @@ private:
|
|||
std::unordered_set<db::PolygonRef> *mp_polyrefs;
|
||||
};
|
||||
|
||||
class EdgeToEdgeSetGenerator
|
||||
: public EdgeSink
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Constructor
|
||||
*/
|
||||
EdgeToEdgeSetGenerator (std::unordered_set<db::Edge> &edges);
|
||||
|
||||
/**
|
||||
* @brief Implementation of the PolygonSink interface
|
||||
*/
|
||||
virtual void put (const db::Edge &edge);
|
||||
|
||||
private:
|
||||
std::unordered_set<db::Edge> *mp_edges;
|
||||
};
|
||||
|
||||
class PolygonRefToShapesGenerator
|
||||
: public PolygonSink
|
||||
{
|
||||
|
|
|
|||
|
|
@ -148,3 +148,48 @@ TEST(3_Edge2EdgeBooleans)
|
|||
db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/deep_edges_au3.gds");
|
||||
}
|
||||
|
||||
TEST(4_Edge2PolygonBooleans)
|
||||
{
|
||||
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::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 & r2);
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (11, 0)), e3 & r2and3);
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (12, 0)), e3 - r2);
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (13, 0)), e3 - r2and3);
|
||||
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (20, 0)), e3.inside_part (r2));
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (21, 0)), e3.inside_part (r2and3));
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (22, 0)), e3.outside_part (r2));
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (23, 0)), e3.outside_part (r2and3));
|
||||
|
||||
CHECKPOINT();
|
||||
db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/deep_edges_au4.gds");
|
||||
}
|
||||
|
||||
|
|
|
|||
Binary file not shown.
Loading…
Reference in New Issue