WIP: enabling booleans with property constraints

This commit is contained in:
Matthias Koefferlein 2023-01-15 20:23:32 +01:00
parent f3e610b6e8
commit b7c515bf91
18 changed files with 1008 additions and 250 deletions

View File

@ -288,6 +288,7 @@ HEADERS = \
dbPolygonTools.h \
dbPolygonGenerators.h \
dbPropertiesRepository.h \
dbPropertyConstraint.h \
dbReader.h \
dbRecursiveInstanceIterator.h \
dbRecursiveShapeIterator.h \

View File

@ -1428,7 +1428,7 @@ AsIfFlatRegion::sized (coord_type dx, coord_type dy, unsigned int mode) const
}
RegionDelegate *
AsIfFlatRegion::and_with (const Region &other) const
AsIfFlatRegion::and_with (const Region &other, PropertyConstraint property_constraint) const
{
if (empty () || other.empty ()) {
@ -1479,6 +1479,8 @@ AsIfFlatRegion::and_with (const Region &other) const
} else {
// @@@ TODO: implement property constraint
// Generic case
db::EdgeProcessor ep (report_progress (), progress_desc ());
ep.set_base_verbosity (base_verbosity ());
@ -1515,7 +1517,7 @@ AsIfFlatRegion::and_with (const Region &other) const
}
RegionDelegate *
AsIfFlatRegion::not_with (const Region &other) const
AsIfFlatRegion::not_with (const Region &other, PropertyConstraint property_constraint) const
{
if (empty ()) {
@ -1534,6 +1536,8 @@ AsIfFlatRegion::not_with (const Region &other) const
} else {
// @@@ TODO: implement property constraint
// Generic case
db::EdgeProcessor ep (report_progress (), progress_desc ());
ep.set_base_verbosity (base_verbosity ());
@ -1571,7 +1575,7 @@ AsIfFlatRegion::not_with (const Region &other) const
std::pair<RegionDelegate *, RegionDelegate *>
AsIfFlatRegion::andnot_with (const Region &other) const
AsIfFlatRegion::andnot_with (const Region &other, PropertyConstraint property_constraint) const
{
if (empty ()) {
@ -1590,6 +1594,8 @@ AsIfFlatRegion::andnot_with (const Region &other) const
} else {
// @@@ TODO: implement property constraint
// Generic case
db::EdgeProcessor ep (report_progress (), progress_desc ());
ep.set_base_verbosity (base_verbosity ());

View File

@ -122,11 +122,11 @@ public:
virtual RegionDelegate *sized (coord_type d, unsigned int mode) const;
virtual RegionDelegate *sized (coord_type dx, coord_type dy, unsigned int mode) const;
virtual RegionDelegate *and_with (const Region &other) const;
virtual RegionDelegate *not_with (const Region &other) const;
virtual RegionDelegate *and_with (const Region &other, PropertyConstraint property_constraint) const;
virtual RegionDelegate *not_with (const Region &other, PropertyConstraint property_constraint) const;
virtual RegionDelegate *xor_with (const Region &other) const;
virtual RegionDelegate *or_with (const Region &other) const;
virtual std::pair<RegionDelegate *, RegionDelegate *> andnot_with (const Region &) const;
virtual std::pair<RegionDelegate *, RegionDelegate *> andnot_with (const Region &other, PropertyConstraint property_constraint) const;
virtual RegionDelegate *add_in_place (const Region &other)
{

View File

@ -699,7 +699,7 @@ DeepRegion::insert_into (db::Layout *layout, db::cell_index_type into_cell, unsi
}
RegionDelegate *
DeepRegion::and_with (const Region &other) const
DeepRegion::and_with (const Region &other, PropertyConstraint property_constraint) const
{
const DeepRegion *other_deep = dynamic_cast <const DeepRegion *> (other.delegate ());
@ -713,17 +713,17 @@ DeepRegion::and_with (const Region &other) const
} else if (! other_deep) {
return AsIfFlatRegion::and_with (other);
return AsIfFlatRegion::and_with (other, property_constraint);
} else {
return new DeepRegion (and_or_not_with (other_deep, true));
return new DeepRegion (and_or_not_with (other_deep, true, property_constraint));
}
}
RegionDelegate *
DeepRegion::not_with (const Region &other) const
DeepRegion::not_with (const Region &other, PropertyConstraint property_constraint) const
{
const DeepRegion *other_deep = dynamic_cast <const DeepRegion *> (other.delegate ());
@ -733,11 +733,11 @@ DeepRegion::not_with (const Region &other) const
} else if (! other_deep) {
return AsIfFlatRegion::not_with (other);
return AsIfFlatRegion::not_with (other, property_constraint);
} else {
return new DeepRegion (and_or_not_with (other_deep, false));
return new DeepRegion (and_or_not_with (other_deep, false, property_constraint));
}
}
@ -750,7 +750,7 @@ DeepRegion::or_with (const Region &other) const
}
std::pair<RegionDelegate *, RegionDelegate *>
DeepRegion::andnot_with (const Region &other) const
DeepRegion::andnot_with (const Region &other, PropertyConstraint property_constraint) const
{
const DeepRegion *other_deep = dynamic_cast <const DeepRegion *> (other.delegate ());
@ -764,39 +764,59 @@ DeepRegion::andnot_with (const Region &other) const
} else if (! other_deep) {
return AsIfFlatRegion::andnot_with (other);
return AsIfFlatRegion::andnot_with (other, property_constraint);
} else {
std::pair<DeepLayer, DeepLayer> res = and_and_not_with (other_deep);
std::pair<DeepLayer, DeepLayer> res = and_and_not_with (other_deep, property_constraint);
return std::make_pair (new DeepRegion (res.first), new DeepRegion (res.second));
}
}
DeepLayer
DeepRegion::and_or_not_with (const DeepRegion *other, bool and_op) const
DeepRegion::and_or_not_with (const DeepRegion *other, bool and_op, db::PropertyConstraint property_constraint) const
{
DeepLayer dl_out (deep_layer ().derived ());
db::BoolAndOrNotLocalOperation op (and_op);
if (property_constraint == db::NoPropertyConstraint) {
db::local_processor<db::PolygonRef, db::PolygonRef, db::PolygonRef> proc (const_cast<db::Layout *> (&deep_layer ().layout ()), const_cast<db::Cell *> (&deep_layer ().initial_cell ()), &other->deep_layer ().layout (), &other->deep_layer ().initial_cell (), deep_layer ().breakout_cells (), other->deep_layer ().breakout_cells ());
proc.set_base_verbosity (base_verbosity ());
proc.set_description (progress_desc ());
proc.set_report_progress (report_progress ());
proc.set_threads (deep_layer ().store ()->threads ());
proc.set_area_ratio (deep_layer ().store ()->max_area_ratio ());
proc.set_max_vertex_count (deep_layer ().store ()->max_vertex_count ());
db::BoolAndOrNotLocalOperation op (and_op);
proc.run (&op, deep_layer ().layer (), other->deep_layer ().layer (), dl_out.layer ());
db::local_processor<db::PolygonRef, db::PolygonRef, db::PolygonRef> proc (const_cast<db::Layout *> (&deep_layer ().layout ()), const_cast<db::Cell *> (&deep_layer ().initial_cell ()), &other->deep_layer ().layout (), &other->deep_layer ().initial_cell (), deep_layer ().breakout_cells (), other->deep_layer ().breakout_cells ());
proc.set_base_verbosity (base_verbosity ());
proc.set_description (progress_desc ());
proc.set_report_progress (report_progress ());
proc.set_threads (deep_layer ().store ()->threads ());
proc.set_area_ratio (deep_layer ().store ()->max_area_ratio ());
proc.set_max_vertex_count (deep_layer ().store ()->max_vertex_count ());
proc.run (&op, deep_layer ().layer (), other->deep_layer ().layer (), dl_out.layer ());
} else {
db::BoolAndOrNotLocalOperationWithProperties op (and_op, &deep_layer ().layout (), &other->deep_layer ().layout (), property_constraint);
db::local_processor<db::PolygonRefWithProperties, db::PolygonRefWithProperties, db::PolygonRefWithProperties> proc (const_cast<db::Layout *> (&deep_layer ().layout ()), const_cast<db::Cell *> (&deep_layer ().initial_cell ()), &other->deep_layer ().layout (), &other->deep_layer ().initial_cell (), deep_layer ().breakout_cells (), other->deep_layer ().breakout_cells ());
proc.set_base_verbosity (base_verbosity ());
proc.set_description (progress_desc ());
proc.set_report_progress (report_progress ());
proc.set_threads (deep_layer ().store ()->threads ());
proc.set_area_ratio (deep_layer ().store ()->max_area_ratio ());
proc.set_max_vertex_count (deep_layer ().store ()->max_vertex_count ());
proc.run (&op, deep_layer ().layer (), other->deep_layer ().layer (), dl_out.layer ());
}
return dl_out;
}
std::pair<DeepLayer, DeepLayer>
DeepRegion::and_and_not_with (const DeepRegion *other) const
DeepRegion::and_and_not_with (const DeepRegion *other, PropertyConstraint property_constraint) const
{
// @@@ TODO: implement property_constraint
DeepLayer dl_out1 (deep_layer ().derived ());
DeepLayer dl_out2 (deep_layer ().derived ());
@ -845,8 +865,8 @@ DeepRegion::xor_with (const Region &other) const
// 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));
DeepLayer n1 (and_or_not_with (other_deep, false, db::NoPropertyConstraint));
DeepLayer n2 (other_deep->and_or_not_with (this, false, db::NoPropertyConstraint));
n1.add_from (n2);
return new DeepRegion (n1);

View File

@ -99,11 +99,11 @@ public:
virtual RegionDelegate *cop_to_region (db::CompoundRegionOperationNode &node);
virtual EdgesDelegate *cop_to_edges (db::CompoundRegionOperationNode &node);
virtual RegionDelegate *and_with (const Region &other) const;
virtual RegionDelegate *not_with (const Region &other) const;
virtual RegionDelegate *and_with (const Region &other, db::PropertyConstraint property_constraint) const;
virtual RegionDelegate *not_with (const Region &other, db::PropertyConstraint property_constraint) const;
virtual RegionDelegate *xor_with (const Region &other) const;
virtual RegionDelegate *or_with (const Region &other) const;
virtual std::pair<RegionDelegate *, RegionDelegate *> andnot_with (const Region &) const;
virtual std::pair<RegionDelegate *, RegionDelegate *> andnot_with (const Region &, db::PropertyConstraint property_constraint) const;
virtual RegionDelegate *add_in_place (const Region &other);
virtual RegionDelegate *add (const Region &other) const;
@ -174,8 +174,8 @@ private:
void init ();
void ensure_merged_polygons_valid () const;
DeepLayer and_or_not_with(const DeepRegion *other, bool and_op) const;
std::pair<DeepLayer, DeepLayer> and_and_not_with (const DeepRegion *other) const;
DeepLayer and_or_not_with(const DeepRegion *other, bool and_op, PropertyConstraint property_constraint) const;
std::pair<DeepLayer, DeepLayer> and_and_not_with (const DeepRegion *other, PropertyConstraint property_constraint) const;
DeepRegion *apply_filter (const PolygonFilterBase &filter) const;
template <class Result, class OutputContainer> OutputContainer *processed_impl (const polygon_processor<Result> &filter) const;

View File

@ -98,9 +98,9 @@ public:
virtual RegionDelegate *sized (coord_type, unsigned int) const { return new EmptyRegion (); }
virtual RegionDelegate *sized (coord_type, coord_type, unsigned int) const { return new EmptyRegion (); }
virtual RegionDelegate *and_with (const Region &) const { return new EmptyRegion (); }
virtual RegionDelegate *not_with (const Region &) const { return new EmptyRegion (); }
virtual std::pair<RegionDelegate *, RegionDelegate *> andnot_with (const Region &) const { return std::make_pair (new EmptyRegion (), new EmptyRegion ()); }
virtual RegionDelegate *and_with (const Region &, db::PropertyConstraint) const { return new EmptyRegion (); }
virtual RegionDelegate *not_with (const Region &, db::PropertyConstraint) const { return new EmptyRegion (); }
virtual std::pair<RegionDelegate *, RegionDelegate *> andnot_with (const Region &, db::PropertyConstraint) const { return std::make_pair (new EmptyRegion (), new EmptyRegion ()); }
virtual RegionDelegate *xor_with (const Region &other) const;
virtual RegionDelegate *or_with (const Region &other) const;
virtual RegionDelegate *add_in_place (const Region &other);

View File

@ -1042,36 +1042,6 @@ private:
}
};
template <class T>
struct addressable_object_from_shape
{
const T *operator () (const db::Shape &shape)
{
typename T::tag object_tag;
return shape.basic_ptr (object_tag);
}
};
template <>
struct addressable_object_from_shape<db::NetShape>
{
const NetShape *operator () (const db::Shape &shape)
{
if (shape.type () == db::Shape::TextRef) {
m_heap.push_back (db::NetShape (shape.text_ref ()));
return &m_heap.back ();
} else if (shape.type () == db::Shape::PolygonRef) {
m_heap.push_back (db::NetShape (shape.polygon_ref ()));
return &m_heap.back ();
} else {
tl_assert (false);
}
}
private:
std::list<NetShape> m_heap;
};
template <class T>
struct attr_accessor
{

View File

@ -197,14 +197,12 @@ public:
shape_type operator() (const shape_type &s) const
{
// CAUTION: no property ID translation happens here (reasoning: the main use case is fake ID for net tagging)
return shape_type (shape_reference_translator<Basic>::operator () (s), s.properties_id ());
}
template <class Trans>
shape_type operator() (const shape_type &s, const Trans &tr) const
{
// CAUTION: no property ID translation happens here (reasoning: the main use case is fake ID for net tagging)
return shape_type (shape_reference_translator<Basic>::operator () (s, tr), s.properties_id ());
}
};
@ -445,7 +443,7 @@ template class DB_PUBLIC local_processor_cell_context<db::Polygon, db::Text, db:
template class DB_PUBLIC local_processor_cell_context<db::Polygon, db::Edge, db::Polygon>;
template class DB_PUBLIC local_processor_cell_context<db::Polygon, db::Text, db::Text>;
template class DB_PUBLIC local_processor_cell_context<db::Polygon, db::Edge, db::Edge>;
template class DB_PUBLIC local_processor_cell_context<db::PolygonRefWithProperties, db::PolygonRefWithProperties, db::PolygonRef>;
template class DB_PUBLIC local_processor_cell_context<db::PolygonRefWithProperties, db::PolygonRefWithProperties, db::PolygonRefWithProperties>;
template class DB_PUBLIC local_processor_cell_context<db::PolygonRef, db::PolygonRef, db::PolygonRef>;
template class DB_PUBLIC local_processor_cell_context<db::PolygonRef, db::Edge, db::PolygonRef>;
template class DB_PUBLIC local_processor_cell_context<db::PolygonRef, db::PolygonRef, db::EdgePair>;
@ -759,7 +757,7 @@ template class DB_PUBLIC local_processor_cell_contexts<db::Polygon, db::Edge, db
template class DB_PUBLIC local_processor_cell_contexts<db::Polygon, db::Edge, db::Edge>;
template class DB_PUBLIC local_processor_cell_contexts<db::Polygon, db::Text, db::Polygon>;
template class DB_PUBLIC local_processor_cell_contexts<db::Polygon, db::Text, db::Text>;
template class DB_PUBLIC local_processor_cell_contexts<db::PolygonRefWithProperties, db::PolygonRefWithProperties, db::PolygonRef>;
template class DB_PUBLIC local_processor_cell_contexts<db::PolygonRefWithProperties, db::PolygonRefWithProperties, db::PolygonRefWithProperties>;
template class DB_PUBLIC local_processor_cell_contexts<db::PolygonRef, db::PolygonRef, db::PolygonRef>;
template class DB_PUBLIC local_processor_cell_contexts<db::PolygonRef, db::Edge, db::PolygonRef>;
template class DB_PUBLIC local_processor_cell_contexts<db::PolygonRef, db::PolygonRef, db::EdgePair>;
@ -1064,6 +1062,7 @@ private:
void add_shapes_from_intruder_inst (unsigned int id1, const db::Cell &intruder_cell, const db::ICplxTrans &tn, unsigned int /*inst_id*/, const db::Box &region)
{
db::shape_reference_translator<TI> rt (mp_subject_layout);
db::shape_to_object<TI> s2o;
// Look up all shapes from the intruder instance which interact with the subject shape
// (given through region)
@ -1074,7 +1073,7 @@ private:
// NOTE: we intentionally rewrite to the *subject* layout - this way polygon refs in the context come from the
// subject, not from the intruder.
TI ref2 = rt (*si.shape ().basic_ptr (typename TI::tag ()), tn * si.trans ());
TI ref2 = rt (s2o (si.shape ()), tn * si.trans ());
// reuse the same id for shapes from the same instance -> this avoid duplicates with different IDs on
// the intruder side.
@ -1335,7 +1334,7 @@ template class DB_PUBLIC local_processor_context_computation_task<db::Polygon, d
template class DB_PUBLIC local_processor_context_computation_task<db::Polygon, db::Text, db::Text>;
template class DB_PUBLIC local_processor_context_computation_task<db::Polygon, db::Edge, db::Polygon>;
template class DB_PUBLIC local_processor_context_computation_task<db::Polygon, db::Edge, db::Edge>;
template class DB_PUBLIC local_processor_context_computation_task<db::PolygonRefWithProperties, db::PolygonRefWithProperties, db::PolygonRef>;
template class DB_PUBLIC local_processor_context_computation_task<db::PolygonRefWithProperties, db::PolygonRefWithProperties, db::PolygonRefWithProperties>;
template class DB_PUBLIC local_processor_context_computation_task<db::PolygonRef, db::PolygonRef, db::PolygonRef>;
template class DB_PUBLIC local_processor_context_computation_task<db::PolygonRef, db::TextRef, db::TextRef>;
template class DB_PUBLIC local_processor_context_computation_task<db::PolygonRef, db::TextRef, db::PolygonRef>;
@ -1398,7 +1397,7 @@ template class DB_PUBLIC local_processor_result_computation_task<db::Polygon, db
template class DB_PUBLIC local_processor_result_computation_task<db::Polygon, db::Text, db::Text>;
template class DB_PUBLIC local_processor_result_computation_task<db::Polygon, db::Edge, db::Polygon>;
template class DB_PUBLIC local_processor_result_computation_task<db::Polygon, db::Edge, db::Edge>;
template class DB_PUBLIC local_processor_result_computation_task<db::PolygonRefWithProperties, db::PolygonRefWithProperties, db::PolygonRef>;
template class DB_PUBLIC local_processor_result_computation_task<db::PolygonRefWithProperties, db::PolygonRefWithProperties, db::PolygonRefWithProperties>;
template class DB_PUBLIC local_processor_result_computation_task<db::PolygonRef, db::PolygonRef, db::PolygonRef>;
template class DB_PUBLIC local_processor_result_computation_task<db::PolygonRef, db::Edge, db::PolygonRef>;
template class DB_PUBLIC local_processor_result_computation_task<db::PolygonRef, db::PolygonRef, db::EdgePair>;
@ -1712,6 +1711,7 @@ void local_processor<TS, TI, TR>::compute_contexts (local_processor_contexts<TS,
// TODO: can we shortcut this if interactions is empty?
{
db::box_scanner2<db::CellInstArray, int, TI, int> scanner;
db::addressable_object_from_shape<TI> heap;
interaction_registration_inst2shape<TS, TI, TR> rec (mp_subject_layout, contexts.subject_layer (), dist, &interactions);
for (db::Cell::const_iterator i = subject_cell->begin (); !i.at_end (); ++i) {
@ -1728,7 +1728,7 @@ void local_processor<TS, TI, TR>::compute_contexts (local_processor_contexts<TS,
for (std::map<unsigned int, const db::Shapes *>::const_iterator im = intruder_shapes.begin (); im != intruder_shapes.end (); ++im) {
for (db::Shapes::shape_iterator i = im->second->begin (shape_flags<TI> ()); !i.at_end (); ++i) {
scanner.insert2 (i->basic_ptr (typename TI::tag ()), im->first);
scanner.insert2 (heap (*i), im->first);
}
}
@ -1880,11 +1880,12 @@ struct scan_shape2shape_same_layer
operator () (const db::Shapes *subject_shapes, unsigned int subject_id0, const std::set<TI> &intruders, unsigned int intruder_layer_index, shape_interactions<TS, TI> &interactions, db::Coord dist) const
{
db::box_scanner2<TS, int, TI, int> scanner;
db::addressable_object_from_shape<TS> heap;
interaction_registration_shape1<TS, TI> rec (&interactions, intruder_layer_index);
unsigned int id = subject_id0;
for (db::Shapes::shape_iterator i = subject_shapes->begin (shape_flags<TS> ()); !i.at_end (); ++i) {
const TS *ref = i->basic_ptr (typename TS::tag ());
const TS *ref = heap (*i);
scanner.insert1 (ref, id++);
}
@ -1904,12 +1905,12 @@ struct scan_shape2shape_same_layer<T, T>
operator () (const db::Shapes *subject_shapes, unsigned int subject_id0, const std::set<T> &intruders, unsigned int intruder_layer, shape_interactions<T, T> &interactions, db::Coord dist) const
{
db::box_scanner<T, int> scanner;
db::addressable_object_from_shape<T> heap;
interaction_registration_shape1<T, T> rec (&interactions, intruder_layer);
unsigned int id = subject_id0;
for (db::Shapes::shape_iterator i = subject_shapes->begin (shape_flags<T> ()); !i.at_end (); ++i) {
const T *ref = i->basic_ptr (typename T::tag ());
scanner.insert (ref, id++);
scanner.insert (heap (*i), id++);
}
// TODO: can we confine this search to the subject's (sized) bounding box?
@ -1928,12 +1929,13 @@ struct scan_shape2shape_different_layers
operator () (db::Layout *layout, const db::Shapes *subject_shapes, const db::Shapes *intruder_shapes, unsigned int subject_id0, const std::set<TI> *intruders, unsigned int intruder_layer_index, shape_interactions<TS, TI> &interactions, db::Coord dist) const
{
db::box_scanner2<TS, int, TI, int> scanner;
db::addressable_object_from_shape<TS> sheap;
db::addressable_object_from_shape<TI> iheap;
interaction_registration_shape2shape<TS, TI> rec (layout, &interactions, intruder_layer_index);
unsigned int id = subject_id0;
for (db::Shapes::shape_iterator i = subject_shapes->begin (shape_flags<TS> ()); !i.at_end (); ++i, ++id) {
const TS *ref = i->basic_ptr (typename TS::tag ());
scanner.insert1 (ref, id);
scanner.insert1 (sheap (*i), id);
}
// TODO: can we confine this search to the subject's (sized) bounding box?
@ -1952,7 +1954,7 @@ struct scan_shape2shape_different_layers
unsigned int id = subject_id0;
for (db::Shapes::shape_iterator i = intruder_shapes->begin (shape_flags<TI> ()); !i.at_end (); ++i, ++id) {
unsigned int iid = interactions.next_id ();
scanner.insert2 (i->basic_ptr (typename TI::tag ()), iid);
scanner.insert2 (iheap (*i), iid);
rec.same (id, iid);
}
@ -1960,7 +1962,7 @@ struct scan_shape2shape_different_layers
// TODO: can we confine this search to the subject's (sized) bounding box?
for (db::Shapes::shape_iterator i = intruder_shapes->begin (shape_flags<TI> ()); !i.at_end (); ++i) {
scanner.insert2 (i->basic_ptr (typename TI::tag ()), interactions.next_id ());
scanner.insert2 (iheap (*i), interactions.next_id ());
}
}
@ -1976,6 +1978,7 @@ void
local_processor<TS, TI, TR>::compute_local_cell (const db::local_processor_contexts<TS, TI, TR> &contexts, db::Cell *subject_cell, const db::Cell *intruder_cell, const local_operation<TS, TI, TR> *op, const typename local_processor_cell_contexts<TS, TI, TR>::context_key_type &intruders, std::vector<std::unordered_set<TR> > &result) const
{
const db::Shapes *subject_shapes = &subject_cell->shapes (contexts.subject_layer ());
db::shape_to_object<TS> s2o;
shape_interactions<TS, TI> interactions;
@ -1990,8 +1993,7 @@ local_processor<TS, TI, TR>::compute_local_cell (const db::local_processor_conte
}
if (op->on_empty_intruder_hint () != OnEmptyIntruderHint::Drop) {
const TS *ref = i->basic_ptr (typename TS::tag ());
interactions.add_subject (id, *ref);
interactions.add_subject (id, s2o (*i));
}
}
@ -2035,11 +2037,12 @@ local_processor<TS, TI, TR>::compute_local_cell (const db::local_processor_conte
if (! subject_shapes->empty () && ! ((! intruder_cell || intruder_cell->begin ().at_end ()) && intruders.first.empty ())) {
db::box_scanner2<TS, int, db::CellInstArray, int> scanner;
db::addressable_object_from_shape<TS> heap;
interaction_registration_shape2inst<TS, TI> rec (mp_subject_layout, mp_intruder_layout, ail, il_index, op->dist (), &interactions);
unsigned int id = subject_id0;
for (db::Shapes::shape_iterator i = subject_shapes->begin (shape_flags<TS> ()); !i.at_end (); ++i) {
scanner.insert1 (i->basic_ptr (typename TS::tag ()), id++);
scanner.insert1 (heap (*i), id++);
}
unsigned int inst_id = 0;
@ -2414,7 +2417,7 @@ template class DB_PUBLIC local_processor<db::Polygon, db::Text, db::Polygon>;
template class DB_PUBLIC local_processor<db::Polygon, db::Text, db::Text>;
template class DB_PUBLIC local_processor<db::Polygon, db::Edge, db::Polygon>;
template class DB_PUBLIC local_processor<db::Polygon, db::Edge, db::Edge>;
template class DB_PUBLIC local_processor<db::PolygonRefWithProperties, db::PolygonRefWithProperties, db::PolygonRef>;
template class DB_PUBLIC local_processor<db::PolygonRefWithProperties, db::PolygonRefWithProperties, db::PolygonRefWithProperties>;
template class DB_PUBLIC local_processor<db::PolygonRef, db::PolygonRef, db::PolygonRef>;
template class DB_PUBLIC local_processor<db::PolygonRef, db::Edge, db::PolygonRef>;
template class DB_PUBLIC local_processor<db::PolygonRef, db::Edge, db::Edge>;

View File

@ -29,10 +29,12 @@
#include "dbPolygonTools.h"
#include "dbLocalOperationUtils.h"
#include "dbEdgeBoolean.h"
#include "dbLayoutUtils.h"
#include "tlLog.h"
#include "tlTimer.h"
#include "tlInternational.h"
#include "tlProgress.h"
#include "tlSList.h"
namespace db
{
@ -92,7 +94,7 @@ template class DB_PUBLIC local_operation<db::Polygon, db::Text, db::Polygon>;
template class DB_PUBLIC local_operation<db::Polygon, db::Text, db::Text>;
template class DB_PUBLIC local_operation<db::Polygon, db::Edge, db::Polygon>;
template class DB_PUBLIC local_operation<db::Polygon, db::Edge, db::Edge>;
template class DB_PUBLIC local_operation<db::PolygonRefWithProperties, db::PolygonRefWithProperties, db::PolygonRef>;
template class DB_PUBLIC local_operation<db::PolygonRefWithProperties, db::PolygonRefWithProperties, db::PolygonRefWithProperties>;
template class DB_PUBLIC local_operation<db::PolygonRef, db::PolygonRef, db::PolygonRef>;
template class DB_PUBLIC local_operation<db::PolygonRef, db::Text, db::PolygonRef>;
template class DB_PUBLIC local_operation<db::PolygonRef, db::TextRef, db::PolygonRef>;
@ -188,6 +190,127 @@ BoolAndOrNotLocalOperation::do_compute_local (db::Layout *layout, const shape_in
}
}
// ---------------------------------------------------------------------------------------------
// BoolAndOrNotLocalOperationWithProperties implementation
BoolAndOrNotLocalOperationWithProperties::BoolAndOrNotLocalOperationWithProperties (bool is_and, const db::Layout *subject_layout, const db::Layout *intruder_layout, db::PropertyConstraint property_constraint)
: m_is_and (is_and), m_property_constraint (property_constraint), mp_subject_layout (subject_layout), mp_intruder_layout (intruder_layout)
{
// .. nothing yet ..
}
OnEmptyIntruderHint
BoolAndOrNotLocalOperationWithProperties::on_empty_intruder_hint () const
{
return m_is_and ? Drop : Copy;
}
std::string
BoolAndOrNotLocalOperationWithProperties::description () const
{
return m_is_and ? tl::to_string (tr ("AND operation")) : tl::to_string (tr ("NOT operation"));
}
void
BoolAndOrNotLocalOperationWithProperties::do_compute_local (db::Layout *layout, const shape_interactions<db::PolygonRefWithProperties, db::PolygonRefWithProperties> &interactions, std::vector<std::unordered_set<db::PolygonRefWithProperties> > &results, size_t max_vertex_count, double area_ratio) const
{
db::PropertyMapper pms (*layout, *mp_subject_layout);
db::PropertyMapper pmi (*layout, *mp_intruder_layout);
// @@@ TODO: implement different property constraint etc.
tl_assert (results.size () == 1);
std::unordered_set<db::PolygonRefWithProperties> &result = results.front ();
db::EdgeProcessor ep;
std::map<db::properties_id_type, std::pair<tl::slist<db::PolygonRef>, std::set<db::PolygonRef> > > by_prop_id;
for (shape_interactions<db::PolygonRefWithProperties, db::PolygonRefWithProperties>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
const db::PolygonRefWithProperties &subject = interactions.subject_shape (i->first);
if (i->second.empty ()) {
if (! m_is_and) {
result.insert (db::PolygonRefWithProperties (subject, pms (subject.properties_id ())));
}
} else {
db::properties_id_type prop_id_s = (m_property_constraint != db::NoPropertyConstraint ? pms (subject.properties_id ()) : 0);
std::pair<tl::slist<db::PolygonRef>, std::set<db::PolygonRef> > &shapes_by_prop = by_prop_id [prop_id_s];
shapes_by_prop.first.push_front (subject);
for (shape_interactions<db::PolygonRefWithProperties, db::PolygonRefWithProperties>::iterator2 j = i->second.begin (); j != i->second.end (); ++j) {
const db::PolygonRefWithProperties &intruder = interactions.intruder_shape (*j).second;
db::properties_id_type prop_id_i = (m_property_constraint != db::NoPropertyConstraint ? pmi (intruder.properties_id ()) : 0);
if ((prop_id_i != prop_id_s) == (m_property_constraint == db::DifferentPropertiesConstraint)) {
shapes_by_prop.second.insert (intruder);
}
}
}
}
for (auto p2s = by_prop_id.begin (); p2s != by_prop_id.end (); ++p2s) {
ep.clear ();
size_t p1 = 0, p2 = 1;
const std::set<db::PolygonRef> &others = p2s->second.second;
db::properties_id_type prop_id = p2s->first;
for (auto s = p2s->second.first.begin (); s != p2s->second.first.end (); ++s) {
const db::PolygonRef &subject = *s;
if (others.find (subject) != others.end ()) {
if (m_is_and) {
result.insert (db::PolygonRefWithProperties (subject, prop_id));
}
} else if (others.empty ()) {
// shortcut (not: keep, and: drop)
if (! m_is_and) {
result.insert (db::PolygonRefWithProperties (subject, prop_id));
}
} else {
for (db::PolygonRef::polygon_edge_iterator e = subject.begin_edge (); ! e.at_end(); ++e) {
ep.insert (*e, p1);
}
p1 += 2;
}
}
if (! others.empty () && p1 > 0) {
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, p2);
}
p2 += 2;
}
std::unordered_set<db::PolygonRef> result_wo_props;
db::BooleanOp op (m_is_and ? db::BooleanOp::And : db::BooleanOp::ANotB);
db::PolygonRefGenerator pr (layout, result_wo_props);
db::PolygonSplitter splitter (pr, area_ratio, max_vertex_count);
db::PolygonGenerator pg (splitter, true, true);
ep.set_base_verbosity (50);
ep.process (pg, op);
for (auto r = result_wo_props.begin (); r != result_wo_props.end (); ++r) {
result.insert (db::PolygonRefWithProperties (*r, prop_id));
}
}
}
}
// ---------------------------------------------------------------------------------------------
// TwoBoolAndNotLocalOperation implementation

View File

@ -30,6 +30,7 @@
#include "dbLayout.h"
#include "dbEdgeBoolean.h"
#include "dbEdgeProcessor.h"
#include "dbPropertyConstraint.h"
#include <unordered_map>
#include <unordered_set>
@ -146,6 +147,25 @@ private:
bool m_is_and;
};
/**
* @brief Implements a boolean AND or NOT operation
*/
class DB_PUBLIC BoolAndOrNotLocalOperationWithProperties
: public local_operation<db::PolygonRefWithProperties, db::PolygonRefWithProperties, db::PolygonRefWithProperties>
{
public:
BoolAndOrNotLocalOperationWithProperties (bool is_and, const db::Layout *subject_layout, const db::Layout *intruder_layout, db::PropertyConstraint property_constraint);
virtual void do_compute_local (db::Layout *layout, const shape_interactions<db::PolygonRefWithProperties, db::PolygonRefWithProperties> &interactions, std::vector<std::unordered_set<db::PolygonRefWithProperties> > &result, size_t max_vertex_count, double area_ratio) const;
virtual OnEmptyIntruderHint on_empty_intruder_hint () const;
virtual std::string description () const;
private:
bool m_is_and;
db::PropertyConstraint m_property_constraint;
const db::Layout *mp_subject_layout, *mp_intruder_layout;
};
/**
* @brief Implements a boolean AND plus NOT operation
*

View File

@ -27,6 +27,9 @@
#include "dbText.h"
#include "dbShapeRepository.h"
#include "dbBoxConvert.h"
#include "dbShape.h"
#include "dbShapeFlags.h" // for addressable_object_from_shape
#include "tlSList.h"
namespace db {
@ -172,6 +175,28 @@ struct box_convert<db::NetShape>
}
};
template <>
struct addressable_object_from_shape<db::NetShape>
{
typedef db::NetShape value_type;
const value_type *operator () (const db::Shape &shape)
{
if (shape.type () == db::Shape::TextRef) {
m_heap.push_back (db::NetShape (shape.text_ref ()));
return &m_heap.back ();
} else if (shape.type () == db::Shape::PolygonRef) {
m_heap.push_back (db::NetShape (shape.polygon_ref ()));
return &m_heap.back ();
} else {
tl_assert (false);
}
}
private:
tl::slist<NetShape> m_heap;
};
}
#endif

View File

@ -0,0 +1,57 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2023 Matthias Koefferlein
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef HDR_dbPropertyConstraint
#define HDR_dbPropertyConstraint
#include "dbCommon.h"
namespace db
{
/**
* @brief Specifies a property constraint for some operations
*/
enum PropertyConstraint
{
/**
* @brief No constraint, shapes are processed regardless of their properties
*/
NoPropertyConstraint = 0,
/**
* @brief Shapes are processed if their properties are the same
*/
SamePropertiesConstraint = 1,
/**
* @brief Shapes are processed if their properties are different
*/
DifferentPropertiesConstraint = 2
};
}
#endif

View File

@ -1036,7 +1036,15 @@ public:
*/
Region operator& (const Region &other) const
{
return Region (mp_delegate->and_with (other));
return Region (mp_delegate->and_with (other, db::NoPropertyConstraint));
}
/**
* @brief Boolean AND operator with options
*/
Region bool_and (const Region &other, PropertyConstraint prop_constraint = db::NoPropertyConstraint) const
{
return Region (mp_delegate->and_with (other, prop_constraint));
}
/**
@ -1047,7 +1055,19 @@ public:
*/
Region &operator&= (const Region &other)
{
set_delegate (mp_delegate->and_with (other));
set_delegate (mp_delegate->and_with (other, db::NoPropertyConstraint));
return *this;
}
/**
* @brief In-place boolean AND operator with options
*
* This method does not necessarily merge the region. To ensure the region
* is merged, call merge afterwards.
*/
Region &bool_and_with (const Region &other, PropertyConstraint prop_constraint = db::NoPropertyConstraint)
{
set_delegate (mp_delegate->and_with (other, prop_constraint));
return *this;
}
@ -1056,7 +1076,15 @@ public:
*/
Region operator- (const Region &other) const
{
return Region (mp_delegate->not_with (other));
return Region (mp_delegate->not_with (other, db::NoPropertyConstraint));
}
/**
* @brief Boolean NOT operator with options
*/
Region bool_not (const Region &other, PropertyConstraint prop_constraint = db::NoPropertyConstraint) const
{
return Region (mp_delegate->not_with (other, prop_constraint));
}
/**
@ -1067,7 +1095,19 @@ public:
*/
Region &operator-= (const Region &other)
{
set_delegate (mp_delegate->not_with (other));
set_delegate (mp_delegate->not_with (other, db::NoPropertyConstraint));
return *this;
}
/**
* @brief In-place boolean NOT operator with options
*
* This method does not necessarily merge the region. To ensure the region
* is merged, call merge afterwards.
*/
Region bool_not_with (const Region &other, PropertyConstraint prop_constraint = db::NoPropertyConstraint)
{
set_delegate (mp_delegate->not_with (other, prop_constraint));
return *this;
}
@ -1134,9 +1174,9 @@ public:
*
* The first region delivered will be the AND result, the second one the NOT result.
*/
std::pair<Region, Region> andnot (const Region &other) const
std::pair<Region, Region> andnot (const Region &other, PropertyConstraint prop_constraint = db::NoPropertyConstraint) const
{
std::pair<RegionDelegate *, RegionDelegate *> res = mp_delegate->andnot_with (other);
std::pair<RegionDelegate *, RegionDelegate *> res = mp_delegate->andnot_with (other, prop_constraint);
return std::make_pair (Region (res.first), Region (res.second));
}

View File

@ -273,13 +273,13 @@ public:
virtual RegionDelegate *sized (coord_type d, unsigned int mode) const = 0;
virtual RegionDelegate *sized (coord_type dx, coord_type dy, unsigned int mode) const = 0;
virtual RegionDelegate *and_with (const Region &other) const = 0;
virtual RegionDelegate *not_with (const Region &other) const = 0;
virtual RegionDelegate *and_with (const Region &other, PropertyConstraint prop_constraint) const = 0;
virtual RegionDelegate *not_with (const Region &other, PropertyConstraint prop_constraint) const = 0;
virtual RegionDelegate *xor_with (const Region &other) const = 0;
virtual RegionDelegate *or_with (const Region &other) const = 0;
virtual RegionDelegate *add_in_place (const Region &other) = 0;
virtual RegionDelegate *add (const Region &other) const = 0;
virtual std::pair<RegionDelegate *, RegionDelegate *> andnot_with (const Region &other) const = 0;
virtual std::pair<RegionDelegate *, RegionDelegate *> andnot_with (const Region &other, PropertyConstraint prop_constraint) const = 0;
virtual RegionDelegate *selected_outside (const Region &other) const = 0;
virtual RegionDelegate *selected_not_outside (const Region &other) const = 0;

View File

@ -29,6 +29,7 @@
#include "dbLocalOperation.h"
#include "dbEdgeProcessor.h"
#include "dbRegionCheckUtils.h"
#include "dbPropertyConstraint.h"
#include <vector>
#include <unordered_set>

View File

@ -26,71 +26,134 @@
#include "dbCommon.h"
#include "dbShapes.h"
#include "tlSList.h"
namespace db
{
template <class T> unsigned int shape_flags ();
template <class T> unsigned int shape_flags_pure ();
template <> inline unsigned int shape_flags<db::PolygonRef> () { return 1 << db::ShapeIterator::PolygonRef; }
template <> inline unsigned int shape_flags_pure<db::PolygonRef> () { return 1 << db::ShapeIterator::PolygonRef; }
template <> inline unsigned int shape_flags<db::TextRef> () { return 1 << db::ShapeIterator::TextRef; }
template <> inline unsigned int shape_flags_pure<db::TextRef> () { return 1 << db::ShapeIterator::TextRef; }
template <> inline unsigned int shape_flags<db::Box> () { return db::ShapeIterator::Boxes; }
template <> inline unsigned int shape_flags_pure<db::Box> () { return 1 << db::ShapeIterator::Box; }
template <> inline unsigned int shape_flags<db::Path> () { return db::ShapeIterator::Paths; }
template <> inline unsigned int shape_flags_pure<db::Path> () { return 1 << db::ShapeIterator::Path; }
template <> inline unsigned int shape_flags<db::Polygon> () { return db::ShapeIterator::Polygons; }
template <> inline unsigned int shape_flags_pure<db::Polygon> () { return 1 << db::ShapeIterator::Polygon; }
template <> inline unsigned int shape_flags<db::Edge> () { return db::ShapeIterator::Edges; }
template <> inline unsigned int shape_flags_pure<db::Edge> () { return 1 << db::ShapeIterator::Edge; }
template <> inline unsigned int shape_flags<db::EdgePair> () { return db::ShapeIterator::EdgePairs; }
template <> inline unsigned int shape_flags_pure<db::EdgePair> () { return 1 << db::ShapeIterator::EdgePair; }
template <> inline unsigned int shape_flags<db::Text> () { return db::ShapeIterator::Texts; }
template <> inline unsigned int shape_flags_pure<db::Text> () { return 1 << db::ShapeIterator::Text; }
template <> inline unsigned int shape_flags<db::PolygonRefWithProperties> () { return db::ShapeIterator::Properties | shape_flags_pure<db::PolygonRef> (); }
template <> inline unsigned int shape_flags_pure<db::PolygonRefWithProperties> () { return db::ShapeIterator::Properties | shape_flags_pure<db::PolygonRef> (); }
template <> inline unsigned int shape_flags<db::TextRefWithProperties> () { return db::ShapeIterator::Properties | shape_flags_pure<db::TextRef> (); }
template <> inline unsigned int shape_flags_pure<db::TextRefWithProperties> () { return db::ShapeIterator::Properties | shape_flags_pure<db::TextRef> (); }
template <> inline unsigned int shape_flags<db::BoxWithProperties> () { return db::ShapeIterator::Properties | shape_flags_pure<db::Box> (); }
template <> inline unsigned int shape_flags_pure<db::BoxWithProperties> () { return db::ShapeIterator::Properties | shape_flags_pure<db::Box> (); }
template <> inline unsigned int shape_flags<db::PathWithProperties> () { return db::ShapeIterator::Properties | shape_flags_pure<db::Path> (); }
template <> inline unsigned int shape_flags_pure<db::PathWithProperties> () { return db::ShapeIterator::Properties | shape_flags_pure<db::Path> (); }
template <> inline unsigned int shape_flags<db::PolygonWithProperties> () { return db::ShapeIterator::Properties | shape_flags_pure<db::Polygon> (); }
template <> inline unsigned int shape_flags_pure<db::PolygonWithProperties> () { return db::ShapeIterator::Properties | shape_flags_pure<db::Polygon> (); }
template <> inline unsigned int shape_flags<db::EdgeWithProperties> () { return db::ShapeIterator::Properties | shape_flags_pure<db::Edge> (); }
template <> inline unsigned int shape_flags_pure<db::EdgeWithProperties> () { return db::ShapeIterator::Properties | shape_flags_pure<db::Edge> (); }
template <> inline unsigned int shape_flags<db::EdgePairWithProperties> () { return db::ShapeIterator::Properties | shape_flags_pure<db::EdgePair> (); }
template <> inline unsigned int shape_flags_pure<db::EdgePairWithProperties> () { return db::ShapeIterator::Properties | shape_flags_pure<db::EdgePair> (); }
template <> inline unsigned int shape_flags<db::TextWithProperties> () { return db::ShapeIterator::Properties | shape_flags_pure<db::Text> (); }
template <> inline unsigned int shape_flags_pure<db::TextWithProperties> () { return db::ShapeIterator::Properties | shape_flags_pure<db::Text> (); }
template <class T>
struct DB_PUBLIC shape_to_object
struct shape_flags_traits
{
void set (const db::Shape &) { }
const T *get (const db::Shape &s) const { return s.basic_ptr (typename T::tag ()); }
static unsigned int generic () { return 0; }
static unsigned int pure () { return 0; }
};
template <>
struct shape_flags_traits<db::PolygonRef>
{
static unsigned int generic () { return 1 << db::ShapeIterator::PolygonRef; }
static unsigned int pure () { return 1 << db::ShapeIterator::PolygonRef; }
};
template <>
struct DB_PUBLIC shape_to_object<db::Polygon>
struct shape_flags_traits<db::TextRef>
{
static unsigned int generic () { return 1 << db::ShapeIterator::TextRef; }
static unsigned int pure () { return 1 << db::ShapeIterator::TextRef; }
};
template <>
struct shape_flags_traits<db::Box>
{
static unsigned int generic () { return db::ShapeIterator::Boxes; }
static unsigned int pure () { return 1 << db::ShapeIterator::Box; }
};
template <>
struct shape_flags_traits<db::Path>
{
static unsigned int generic () { return db::ShapeIterator::Paths; }
static unsigned int pure () { return 1 << db::ShapeIterator::Path; }
};
template <>
struct shape_flags_traits<db::Polygon>
{
static unsigned int generic () { return db::ShapeIterator::Polygons; }
static unsigned int pure () { return 1 << db::ShapeIterator::Polygon; }
};
template <>
struct shape_flags_traits<db::SimplePolygon>
{
static unsigned int generic () { return db::ShapeIterator::Polygons; }
static unsigned int pure () { return 1 << db::ShapeIterator::SimplePolygon; }
};
template <>
struct shape_flags_traits<db::Edge>
{
static unsigned int generic () { return db::ShapeIterator::Edges; }
static unsigned int pure () { return 1 << db::ShapeIterator::Edge; }
};
template <>
struct shape_flags_traits<db::EdgePair>
{
static unsigned int generic () { return db::ShapeIterator::EdgePairs; }
static unsigned int pure () { return 1 << db::ShapeIterator::EdgePair; }
};
template <>
struct shape_flags_traits<db::Text>
{
static unsigned int generic () { return db::ShapeIterator::Texts; }
static unsigned int pure () { return 1 << db::ShapeIterator::Text; }
};
template <class T>
struct shape_flags_traits<db::object_with_properties<T> >
{
static unsigned int generic () { return shape_flags_traits<T>::generic (); }
static unsigned int pure () { return shape_flags_traits<T>::pure (); }
};
template <class T> unsigned int shape_flags () { return shape_flags_traits<T>::generic (); }
template <class T> unsigned int shape_flags_pure () { return shape_flags_traits<T>::pure (); }
/**
* @brief Converter helpers for changing a shape to an object of a specific type
*
* These converters a volatile. The pointer delivered is not valid after the next object has
* been retrieved.
*/
template <class T>
struct DB_PUBLIC shape_to_object_impl
{
typedef T value_type;
void set (const db::Shape &) { }
const value_type *get (const db::Shape &s) const { return s.basic_ptr (typename T::tag ()); }
};
template <class T>
struct DB_PUBLIC shape_to_object_impl<db::object_with_properties<T> >
{
typedef db::object_with_properties<T> value_type;
void set (const db::Shape &s)
{
if (! s.has_prop_id ()) {
m_shape = value_type (*s.basic_ptr (typename T::tag ()), 0);
}
}
const value_type *get (const db::Shape &s) const
{
if (! s.has_prop_id ()) {
return &m_shape;
} else {
return s.basic_ptr (typename value_type::tag ());
}
}
private:
value_type m_shape;
};
template <>
struct DB_PUBLIC shape_to_object_impl<db::Polygon>
{
typedef db::Polygon value_type;
@ -102,7 +165,27 @@ private:
};
template <>
struct DB_PUBLIC shape_to_object<db::SimplePolygon>
struct DB_PUBLIC shape_to_object_impl<db::PolygonWithProperties>
{
typedef db::PolygonWithProperties value_type;
void set (const db::Shape &s)
{
s.polygon (m_shape);
m_shape.properties_id (s.prop_id ());
}
const value_type *get (const db::Shape &) const
{
return &m_shape;
}
private:
value_type m_shape;
};
template <>
struct DB_PUBLIC shape_to_object_impl<db::SimplePolygon>
{
typedef db::SimplePolygon value_type;
@ -114,7 +197,27 @@ private:
};
template <>
struct DB_PUBLIC shape_to_object<db::Path>
struct DB_PUBLIC shape_to_object_impl<db::SimplePolygonWithProperties>
{
typedef db::SimplePolygonWithProperties value_type;
void set (const db::Shape &s)
{
s.simple_polygon (m_shape);
m_shape.properties_id (s.prop_id ());
}
const value_type *get (const db::Shape &) const
{
return &m_shape;
}
private:
value_type m_shape;
};
template <>
struct DB_PUBLIC shape_to_object_impl<db::Path>
{
typedef db::Path value_type;
@ -126,7 +229,27 @@ private:
};
template <>
struct DB_PUBLIC shape_to_object<db::Text>
struct DB_PUBLIC shape_to_object_impl<db::PathWithProperties>
{
typedef db::PathWithProperties value_type;
void set (const db::Shape &s)
{
s.path (m_shape);
m_shape.properties_id (s.prop_id ());
}
const value_type *get (const db::Shape &) const
{
return &m_shape;
}
private:
value_type m_shape;
};
template <>
struct DB_PUBLIC shape_to_object_impl<db::Text>
{
typedef db::Text value_type;
@ -138,17 +261,395 @@ private:
};
template <>
struct DB_PUBLIC shape_to_object<db::Box>
struct DB_PUBLIC shape_to_object_impl<db::TextWithProperties>
{
typedef db::TextWithProperties value_type;
void set (const db::Shape &s)
{
s.text (m_shape);
m_shape.properties_id (s.prop_id ());
}
const value_type *get (const db::Shape &) const
{
return &m_shape;
}
private:
value_type m_shape;
};
template <>
struct DB_PUBLIC shape_to_object_impl<db::Box>
{
typedef db::Box value_type;
void set (const db::Shape *s) { s->box (m_shape); }
void set (const db::Shape &s) { s.box (m_shape); }
const value_type *get (const db::Shape *) const { return &m_shape; }
private:
value_type m_shape;
};
template <>
struct DB_PUBLIC shape_to_object_impl<db::BoxWithProperties>
{
typedef db::BoxWithProperties value_type;
void set (const db::Shape &s)
{
s.box (m_shape);
m_shape.properties_id (s.prop_id ());
}
const value_type *get (const db::Shape &) const
{
return &m_shape;
}
private:
value_type m_shape;
};
template <class T>
struct DB_PUBLIC shape_to_object
: public shape_to_object_impl<T>
{
const typename shape_to_object_impl<T>::value_type &operator() (const db::Shape &s)
{
shape_to_object_impl<T>::set (s);
return *shape_to_object_impl<T>::get (s);
}
};
/**
* @brief Implements an addressable object heap
*
* This object can deliver addressable objects from shapes. It will keep temporary objects
* internally if required.
*/
template <class T>
struct addressable_object_from_shape
{
typedef T value_type;
const T *operator () (const db::Shape &shape)
{
typename T::tag object_tag;
return shape.basic_ptr (object_tag);
}
};
template <class T>
struct addressable_object_from_shape<db::object_with_properties<T> >
{
typedef db::object_with_properties<T> value_type;
const db::object_with_properties<T> *operator () (const db::Shape &shape)
{
if (shape.has_prop_id ()) {
typename db::object_with_properties<T>::tag object_tag;
return shape.basic_ptr (object_tag);
} else {
typename T::tag object_tag;
m_heap.push_back (db::object_with_properties<T> (*shape.basic_ptr (object_tag), 0));
return &m_heap.back ();
}
}
private:
tl::slist<db::object_with_properties<T> > m_heap;
};
template <>
struct addressable_object_from_shape<db::Box>
{
typedef db::Box value_type;
const value_type *operator () (const db::Shape &shape)
{
if (shape.type () == db::Shape::Box) {
return shape.basic_ptr (value_type::tag ());
} else {
m_heap.push_front (value_type ());
shape.box (m_heap.front ());
return &m_heap.front ();
}
}
private:
tl::slist<value_type> m_heap;
};
template <>
struct addressable_object_from_shape<db::BoxWithProperties>
{
typedef db::BoxWithProperties value_type;
const value_type *operator () (const db::Shape &shape)
{
if (shape.has_prop_id () && shape.type () == db::Shape::Box) {
return shape.basic_ptr (value_type::tag ());
} else {
m_heap.push_front (value_type ());
shape.box (m_heap.front ());
m_heap.front ().properties_id (shape.prop_id ());
return &m_heap.front ();
}
}
private:
tl::slist<value_type> m_heap;
};
template <>
struct addressable_object_from_shape<db::Polygon>
{
typedef db::Polygon value_type;
const value_type *operator () (const db::Shape &shape)
{
if (shape.type () == db::Shape::Polygon) {
return shape.basic_ptr (value_type::tag ());
} else {
m_heap.push_front (value_type ());
shape.polygon (m_heap.front ());
return &m_heap.front ();
}
}
private:
tl::slist<value_type> m_heap;
};
template <>
struct addressable_object_from_shape<db::PolygonWithProperties>
{
typedef db::PolygonWithProperties value_type;
const value_type *operator () (const db::Shape &shape)
{
if (shape.has_prop_id () && shape.type () == db::Shape::Polygon) {
return shape.basic_ptr (value_type::tag ());
} else {
m_heap.push_front (value_type ());
shape.polygon (m_heap.front ());
m_heap.front ().properties_id (shape.prop_id ());
return &m_heap.front ();
}
}
private:
tl::slist<value_type> m_heap;
};
template <>
struct addressable_object_from_shape<db::SimplePolygon>
{
typedef db::SimplePolygon value_type;
const value_type *operator () (const db::Shape &shape)
{
if (shape.type () == db::Shape::SimplePolygon) {
return shape.basic_ptr (value_type::tag ());
} else {
m_heap.push_front (value_type ());
shape.simple_polygon (m_heap.front ());
return &m_heap.front ();
}
}
private:
tl::slist<value_type> m_heap;
};
template <>
struct addressable_object_from_shape<db::SimplePolygonWithProperties>
{
typedef db::SimplePolygonWithProperties value_type;
const value_type *operator () (const db::Shape &shape)
{
if (shape.has_prop_id () && shape.type () == db::Shape::SimplePolygon) {
return shape.basic_ptr (value_type::tag ());
} else {
m_heap.push_front (value_type ());
shape.simple_polygon (m_heap.front ());
m_heap.front ().properties_id (shape.prop_id ());
return &m_heap.front ();
}
}
private:
tl::slist<value_type> m_heap;
};
template <>
struct addressable_object_from_shape<db::Path>
{
typedef db::Path value_type;
const value_type *operator () (const db::Shape &shape)
{
if (shape.type () == db::Shape::Path) {
return shape.basic_ptr (value_type::tag ());
} else {
m_heap.push_front (value_type ());
shape.path (m_heap.front ());
return &m_heap.front ();
}
}
private:
tl::slist<value_type> m_heap;
};
template <>
struct addressable_object_from_shape<db::PathWithProperties>
{
typedef db::PathWithProperties value_type;
const value_type *operator () (const db::Shape &shape)
{
if (shape.has_prop_id () && shape.type () == db::Shape::Path) {
return shape.basic_ptr (value_type::tag ());
} else {
m_heap.push_front (value_type ());
shape.path (m_heap.front ());
m_heap.front ().properties_id (shape.prop_id ());
return &m_heap.front ();
}
}
private:
tl::slist<value_type> m_heap;
};
template <>
struct addressable_object_from_shape<db::Edge>
{
typedef db::Edge value_type;
const value_type *operator () (const db::Shape &shape)
{
if (shape.type () == db::Shape::Edge) {
return shape.basic_ptr (value_type::tag ());
} else {
m_heap.push_front (value_type ());
shape.edge (m_heap.front ());
return &m_heap.front ();
}
}
private:
tl::slist<value_type> m_heap;
};
template <>
struct addressable_object_from_shape<db::EdgeWithProperties>
{
typedef db::EdgeWithProperties value_type;
const value_type *operator () (const db::Shape &shape)
{
if (shape.has_prop_id () && shape.type () == db::Shape::Edge) {
return shape.basic_ptr (value_type::tag ());
} else {
m_heap.push_front (value_type ());
shape.edge (m_heap.front ());
m_heap.front ().properties_id (shape.prop_id ());
return &m_heap.front ();
}
}
private:
tl::slist<value_type> m_heap;
};
template <>
struct addressable_object_from_shape<db::EdgePair>
{
typedef db::EdgePair value_type;
const value_type *operator () (const db::Shape &shape)
{
if (shape.type () == db::Shape::EdgePair) {
return shape.basic_ptr (value_type::tag ());
} else {
m_heap.push_front (value_type ());
shape.edge_pair (m_heap.front ());
return &m_heap.front ();
}
}
private:
tl::slist<value_type> m_heap;
};
template <>
struct addressable_object_from_shape<db::EdgePairWithProperties>
{
typedef db::EdgePairWithProperties value_type;
const value_type *operator () (const db::Shape &shape)
{
if (shape.has_prop_id () && shape.type () == db::Shape::EdgePair) {
return shape.basic_ptr (value_type::tag ());
} else {
m_heap.push_front (value_type ());
shape.edge_pair (m_heap.front ());
m_heap.front ().properties_id (shape.prop_id ());
return &m_heap.front ();
}
}
private:
tl::slist<value_type> m_heap;
};
template <>
struct addressable_object_from_shape<db::Text>
{
typedef db::Text value_type;
const value_type *operator () (const db::Shape &shape)
{
if (shape.type () == db::Shape::Text) {
return shape.basic_ptr (value_type::tag ());
} else {
m_heap.push_front (value_type ());
shape.text (m_heap.front ());
return &m_heap.front ();
}
}
private:
tl::slist<value_type> m_heap;
};
template <>
struct addressable_object_from_shape<db::TextWithProperties>
{
typedef db::TextWithProperties value_type;
const value_type *operator () (const db::Shape &shape)
{
if (shape.has_prop_id () && shape.type () == db::Shape::Text) {
return shape.basic_ptr (value_type::tag ());
} else {
m_heap.push_front (value_type ());
shape.text (m_heap.front ());
m_heap.front ().properties_id (shape.prop_id ());
return &m_heap.front ();
}
}
private:
tl::slist<value_type> m_heap;
};
}
#endif

View File

@ -619,9 +619,9 @@ static db::EdgePairs separation2 (const db::Region *r, const db::Region &other,
);
}
static std::vector<db::Region> andnot (const db::Region *r, const db::Region &other)
static std::vector<db::Region> andnot (const db::Region *r, const db::Region &other, db::PropertyConstraint prop_constraint)
{
return as_2region_vector (r->andnot (other));
return as_2region_vector (r->andnot (other, prop_constraint));
}
static std::vector<db::Region> split_inside (const db::Region *r, const db::Region &other)
@ -1595,7 +1595,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
) +
method_ext ("andnot", &andnot, gsi::arg ("other"),
method_ext ("andnot", &andnot, gsi::arg ("other"), gsi::arg ("property_constraint", db::NoPropertyConstraint),
"@brief Returns the boolean AND and NOT between self and the other region\n"
"\n"
"@return A two-element array of regions with the first one being the AND result and the second one being the NOT result\n"
@ -1613,6 +1613,18 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"This method will compute the boolean AND (intersection) between two regions. "
"The result is often but not necessarily always merged.\n"
) +
method ("and", &db::Region::bool_and, gsi::arg ("other"), gsi::arg ("property_constraint", db::NoPropertyConstraint),
"@brief Returns the boolean AND between self and the other region\n"
"\n"
"@return The result of the boolean AND operation\n"
"\n"
"This method will compute the boolean AND (intersection) between two regions. "
"The result is often but not necessarily always merged.\n"
"It allows specification of a property constaint - e.g. only performing the boolean operation between "
"shapes with the same user properties.\n"
"\n"
"This variant has been introduced in version 0.28.4."
) +
method ("&=", &db::Region::operator&=, gsi::arg ("other"),
"@brief Performs the boolean AND between self and the other region\n"
"\n"
@ -1621,6 +1633,18 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"This method will compute the boolean AND (intersection) between two regions. "
"The result is often but not necessarily always merged.\n"
) +
method ("and_with", &db::Region::bool_and_with, gsi::arg ("other"), gsi::arg ("property_constraint", db::NoPropertyConstraint),
"@brief Performs the boolean AND between self and the other region\n"
"\n"
"@return The region after modification (self)\n"
"\n"
"This method will compute the boolean AND (intersection) between two regions. "
"The result is often but not necessarily always merged.\n"
"It allows specification of a property constaint - e.g. only performing the boolean operation between "
"shapes with the same user properties.\n"
"\n"
"This variant has been introduced in version 0.28.4."
) +
method ("-", &db::Region::operator-, gsi::arg ("other"),
"@brief Returns the boolean NOT between self and the other region\n"
"\n"
@ -1629,6 +1653,14 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"This method will compute the boolean NOT (intersection) between two regions. "
"The result is often but not necessarily always merged.\n"
) +
method ("not", &db::Region::bool_not, gsi::arg ("other"), gsi::arg ("property_constraint", db::NoPropertyConstraint),
"@brief Returns the boolean NOT between self and the other region\n"
"\n"
"@return The result of the boolean NOT operation\n"
"\n"
"This method will compute the boolean NOT (intersection) between two regions. "
"The result is often but not necessarily always merged.\n"
) +
method ("-=", &db::Region::operator-=, gsi::arg ("other"),
"@brief Performs the boolean NOT between self and the other region\n"
"\n"
@ -1637,6 +1669,14 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"This method will compute the boolean NOT (intersection) between two regions. "
"The result is often but not necessarily always merged.\n"
) +
method ("not_with", &db::Region::bool_not_with, gsi::arg ("other"), gsi::arg ("property_constraint", db::NoPropertyConstraint),
"@brief Performs the boolean NOT between self and the other region\n"
"\n"
"@return The region after modification (self)\n"
"\n"
"This method will compute the boolean NOT (intersection) between two regions. "
"The result is often but not necessarily always merged.\n"
) +
method ("^", &db::Region::operator^, gsi::arg ("other"),
"@brief Returns the boolean XOR between self and the other region\n"
"\n"
@ -3055,6 +3095,32 @@ gsi::EnumIn<db::Region, db::metrics_type> decl_Region_Metrics ("db", "Metrics",
gsi::ClassExt<db::Region> inject_Metrics_in_parent (decl_Region_Metrics.defs ());
gsi::ClassExt<db::Edges> inject_Metrics_in_Edges (decl_Region_Metrics.defs ());
gsi::EnumIn<db::Region, db::PropertyConstraint> decl_Region_PropertyConstraint ("db", "PropertyConstraint",
gsi::enum_const ("NoPropertyConstraint", db::NoPropertyConstraint,
"@brief Specifies not to apply any property constraint\n"
"When using this constraint - for example on a boolean operation - shapes are considered "
"regardless of their user properties."
) +
gsi::enum_const ("SamePropertiesConstraint", db::SamePropertiesConstraint,
"@brief Specifies to consider shapes only if their user properties are the same\n"
"When using this constraint - for example on a boolean operation - shapes are considered "
"only if their user properties are the same."
) +
gsi::enum_const ("DifferentPropertiesConstraint", db::DifferentPropertiesConstraint,
"@brief Specifies to consider shapes only if their user properties are different\n"
"When using this constraint - for example on a boolean operation - shapes are considered "
"only if their user properties are different."
),
"@brief This class represents the property constraint for boolean and check functions.\n"
"\n"
"This enum has been introduced in version 0.28.4."
);
// Inject the Region::PropertyConstraint declarations into Region and Edges:
// (Edges injection has to be done here because only here defs() is available)
gsi::ClassExt<db::Region> inject_PropertyConstraint_in_parent (decl_Region_PropertyConstraint.defs ());
gsi::ClassExt<db::Edges> inject_PropertyConstraint_in_Edges (decl_Region_PropertyConstraint.defs ());
gsi::EnumIn<db::Region, db::RectFilter> decl_Region_RectFilter ("db", "RectFilter",
gsi::enum_const ("NoRectFilter", db::RectFilter::NoRectFilter,
"@brief Specifies no filtering"

View File

@ -40,92 +40,6 @@ static unsigned int define_layer (db::Layout &ly, db::LayerMap &lmap, int gds_la
return lid;
}
class BoolBetweenNets
: public db::local_operation<db::PolygonRefWithProperties, db::PolygonRefWithProperties, db::PolygonRef>
{
public:
BoolBetweenNets (bool is_and, bool connected)
: m_is_and (is_and), m_connected (connected)
{
// .. nothing yet ..
}
db::OnEmptyIntruderHint
on_empty_intruder_hint () const
{
return m_is_and ? db::Drop : db::Copy;
}
std::string
description () const
{
return m_is_and ? tl::to_string (tr ("AND operation")) : tl::to_string (tr ("NOT operation"));
}
void
do_compute_local (db::Layout *layout, const db::shape_interactions<db::PolygonRefWithProperties, db::PolygonRefWithProperties> &interactions, std::vector<std::unordered_set<db::PolygonRef> > &results, size_t max_vertex_count, double area_ratio) const
{
tl_assert (results.size () == 1);
std::unordered_set<db::PolygonRef> &result = results.front ();
db::EdgeProcessor ep;
// NOTE: is guess we do not need to handle subject/subject interactions ...
for (auto i = interactions.begin (); i != interactions.end (); ++i) {
const db::PolygonRefWithProperties &subject = interactions.subject_shape (i->first);
bool any_intruder = false;
for (auto j = i->second.begin (); j != i->second.end () && ! any_intruder; ++j) {
const db::PolygonRefWithProperties &other = interactions.intruder_shape (*j).second;
any_intruder = ((other.properties_id () == subject.properties_id ()) == m_connected);
}
if (! any_intruder) {
// shortcut (not: keep, and: drop)
if (! m_is_and) {
result.insert (subject);
}
} else {
ep.clear ();
for (db::PolygonRef::polygon_edge_iterator e = subject.begin_edge (); ! e.at_end(); ++e) {
ep.insert (*e, 0);
}
for (auto j = i->second.begin (); j != i->second.end (); ++j) {
const db::PolygonRefWithProperties &other = interactions.intruder_shape (*j).second;
if ((other.properties_id () == subject.properties_id ()) == m_connected) {
for (db::PolygonRef::polygon_edge_iterator e = other.begin_edge (); ! e.at_end(); ++e) {
ep.insert (*e, 1);
}
}
}
db::BooleanOp op (m_is_and ? db::BooleanOp::And : db::BooleanOp::ANotB);
db::PolygonRefGenerator pr (layout, result);
db::PolygonSplitter splitter (pr, area_ratio, max_vertex_count);
db::PolygonGenerator pg (splitter, true, true);
ep.set_base_verbosity (50);
ep.process (pg, op);
}
}
}
private:
bool m_is_and;
bool m_connected;
};
TEST(0_Develop)
{
db::Layout ly;
@ -210,15 +124,26 @@ TEST(0_Develop)
lmap_write [wvia1 = ly2.insert_layer (db::LayerProperties (16, 0))] = l2n.layer_by_name ("via1");
lmap_write [wmetal2 = ly2.insert_layer (db::LayerProperties (17, 0))] = l2n.layer_by_name ("metal2");
l2n.build_all_nets (cm, ly2, lmap_write, "NET_", db::LayoutToNetlist::NetIDOnly, tl::Variant (), db::LayoutToNetlist::BNH_SubcircuitCells, "SC_", 0 /*don't produce devices*/);
l2n.build_all_nets (cm, ly2, lmap_write, "NET_", db::LayoutToNetlist::NetNameAndIDOnly, tl::Variant (1), db::LayoutToNetlist::BNH_SubcircuitCells, "SC_", 0 /*don't produce devices*/);
unsigned int out = ly2.insert_layer (db::LayerProperties (1000, 0));
unsigned int out1 = ly2.insert_layer (db::LayerProperties (1000, 0));
unsigned int out2 = ly2.insert_layer (db::LayerProperties (1001, 0));
unsigned int out3 = ly2.insert_layer (db::LayerProperties (1002, 0));
db::local_processor<db::PolygonRefWithProperties, db::PolygonRefWithProperties, db::PolygonRef> proc (&ly2, &top2);
BoolBetweenNets n2n (true, true);
proc.run (&n2n, wmetal1, wmetal2, out);
db::local_processor<db::PolygonRefWithProperties, db::PolygonRefWithProperties, db::PolygonRefWithProperties> proc (&ly2, &top2);
{
db::BoolAndOrNotLocalOperationWithProperties n2n (true, &ly2, &ly2, db::SamePropertiesConstraint);
proc.run (&n2n, wmetal1, wmetal2, out1);
}
{
db::BoolAndOrNotLocalOperationWithProperties n2n (true, &ly2, &ly2, db::DifferentPropertiesConstraint);
proc.run (&n2n, wmetal1, wmetal2, out2);
}
{
db::BoolAndOrNotLocalOperationWithProperties n2n (true, &ly2, &ly2, db::NoPropertyConstraint);
proc.run (&n2n, wmetal1, wmetal2, out3);
}
// @@@ may no work correctly as we have used fake prop ids
{
db::SaveLayoutOptions options;