mirror of https://github.com/KLayout/klayout.git
Experimental feature: Region#peel to reduce hierarchical load
This commit is contained in:
parent
b7d18af0e1
commit
adb81262a4
|
|
@ -138,6 +138,11 @@ public:
|
|||
|
||||
virtual RegionDelegate *add (const Region &other) const;
|
||||
|
||||
virtual RegionDelegate *peel (double /*complexity_factor*/) const
|
||||
{
|
||||
return const_cast<AsIfFlatRegion *> (this);
|
||||
}
|
||||
|
||||
virtual RegionDelegate *selected_outside (const Region &other) const
|
||||
{
|
||||
return selected_interacting_generic (other, 1, false, Positive, size_t (1), std::numeric_limits<size_t>::max ()).first;
|
||||
|
|
|
|||
|
|
@ -880,6 +880,140 @@ DeepRegion::nets (LayoutToNetlist *l2n, NetPropertyMode prop_mode, const tl::Var
|
|||
return new db::DeepRegion (result);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
/**
|
||||
* @brief Implements a boolean AND or NOT operation with property handling
|
||||
*/
|
||||
class DB_PUBLIC PushHierLocalOperationWithProperties
|
||||
: public local_operation<db::object_with_properties<db::PolygonRef>, db::object_with_properties<db::PolygonRef>, db::object_with_properties<db::PolygonRef> >
|
||||
{
|
||||
public:
|
||||
PushHierLocalOperationWithProperties (double complexity_factor)
|
||||
: local_operation<db::object_with_properties<db::PolygonRef>, db::object_with_properties<db::PolygonRef>, db::object_with_properties<db::PolygonRef> > (),
|
||||
m_complexity_factor (complexity_factor)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
OnEmptyIntruderHint on_empty_intruder_hint () const { return Copy; }
|
||||
|
||||
std::string description () const
|
||||
{
|
||||
return tl::to_string (tr ("'peel' operation"));
|
||||
}
|
||||
|
||||
|
||||
virtual void do_compute_local (db::Layout *layout, db::Cell * /*subject_cell*/, const shape_interactions<db::object_with_properties<db::PolygonRef>, db::object_with_properties<db::PolygonRef> > &interactions, std::vector<std::unordered_set<db::object_with_properties<db::PolygonRef> > > &results, const db::LocalProcessorBase *proc) const
|
||||
{
|
||||
tl_assert (results.size () == 1);
|
||||
auto &result = results.front ();
|
||||
|
||||
db::EdgeProcessor ep;
|
||||
|
||||
for (auto i = interactions.begin (); i != interactions.end (); ++i) {
|
||||
|
||||
const auto &subject = interactions.subject_shape (i->first);
|
||||
db::properties_id_type prop_id = subject.properties_id ();
|
||||
|
||||
if (i->second.empty ()) {
|
||||
|
||||
result.insert (subject);
|
||||
|
||||
} else {
|
||||
|
||||
ep.clear ();
|
||||
|
||||
const auto &subject = interactions.subject_shape (i->first);
|
||||
for (auto e = subject.begin_edge (); ! e.at_end(); ++e) {
|
||||
ep.insert (*e, 0);
|
||||
}
|
||||
|
||||
size_t p2 = 1;
|
||||
for (auto ii = i->second.begin (); ii != i->second.end (); ++ii) {
|
||||
const auto &intruder = interactions.intruder_shape (*ii);
|
||||
for (auto e = intruder.second.begin_edge (); ! e.at_end(); ++e) {
|
||||
ep.insert (*e, p2);
|
||||
}
|
||||
p2 += 2;
|
||||
}
|
||||
|
||||
std::unordered_set<db::object_with_properties<db::PolygonRef> > result1;
|
||||
|
||||
db::BooleanOp op (db::BooleanOp::ANotB);
|
||||
db::polygon_ref_generator_with_properties<db::object_with_properties<db::PolygonRef> > pr (layout, result1, prop_id);
|
||||
db::PolygonSplitter splitter (pr, proc->area_ratio (), proc->max_vertex_count ());
|
||||
db::PolygonGenerator pg (splitter, true, true);
|
||||
ep.set_base_verbosity (50);
|
||||
ep.process (pg, op);
|
||||
|
||||
if (result1.empty ()) {
|
||||
|
||||
// shortcut: nothing to do
|
||||
|
||||
} else if (m_complexity_factor < 0.0) {
|
||||
|
||||
// no complexity limit
|
||||
result.insert (result1.begin (), result1.end ());
|
||||
|
||||
} else if (m_complexity_factor == 0.0) {
|
||||
|
||||
// only remove shape if it is really entirely covered in this case
|
||||
result.insert (subject);
|
||||
|
||||
} else {
|
||||
|
||||
size_t vertices_before = subject.vertices ();
|
||||
size_t vertices_after = 0;
|
||||
for (auto r = result1.begin (); r != result1.end (); ++r) {
|
||||
vertices_after += r->vertices ();
|
||||
}
|
||||
|
||||
if (floor (0.5 + m_complexity_factor * vertices_before) >= vertices_after) {
|
||||
result.insert (result1.begin (), result1.end ());
|
||||
} else {
|
||||
result.insert (subject);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
double m_complexity_factor;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
RegionDelegate *
|
||||
DeepRegion::peel (double complexity_factor) const
|
||||
{
|
||||
if (empty ()) {
|
||||
// we can return "this", as this method is only intended for in-place execution inside Region
|
||||
return const_cast<DeepRegion *> (this);
|
||||
}
|
||||
|
||||
DeepLayer dl_out (deep_layer ().derived ());
|
||||
|
||||
PushHierLocalOperationWithProperties op (complexity_factor);
|
||||
|
||||
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 ()), deep_layer ().breakout_cells ());
|
||||
configure_proc (proc);
|
||||
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 ());
|
||||
|
||||
// with this setting, only top-down interactions are considered
|
||||
proc.set_top_down (true);
|
||||
|
||||
proc.run (&op, deep_layer ().layer (), deep_layer ().layer (), dl_out.layer ());
|
||||
|
||||
return new DeepRegion (dl_out);
|
||||
}
|
||||
|
||||
RegionDelegate *
|
||||
DeepRegion::and_with (const Region &other, PropertyConstraint property_constraint) const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -140,6 +140,8 @@ public:
|
|||
virtual RegionDelegate *sized_inside (const Region &inside, bool outside, coord_type d, int steps, unsigned int mode) const;
|
||||
virtual RegionDelegate *sized_inside (const Region &inside, bool outside, coord_type dx, coord_type dy, int steps, unsigned int mode) const;
|
||||
|
||||
virtual RegionDelegate *peel (double complexity_factor) const;
|
||||
|
||||
virtual void insert_into (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const;
|
||||
|
||||
virtual RegionDelegate *nets (LayoutToNetlist *l2n, NetPropertyMode prop_mode, const tl::Variant &net_prop_name, const std::vector<const Net *> *nets) const;
|
||||
|
|
|
|||
|
|
@ -111,6 +111,8 @@ public:
|
|||
virtual RegionDelegate *add_in_place (const Region &other);
|
||||
virtual RegionDelegate *add (const Region &other) const;
|
||||
|
||||
virtual RegionDelegate *peel (double /*complexity_factor*/) const { return new EmptyRegion (); }
|
||||
|
||||
virtual RegionDelegate *selected_outside (const Region &) const { return new EmptyRegion (); }
|
||||
virtual RegionDelegate *selected_not_outside (const Region &) const { return new EmptyRegion (); }
|
||||
virtual std::pair<RegionDelegate *, RegionDelegate *> selected_outside_pair (const Region &) const { return std::make_pair (new EmptyRegion (), new EmptyRegion ()); }
|
||||
|
|
|
|||
|
|
@ -744,7 +744,7 @@ local_processor_result_computation_task<TS, TI, TR>::perform ()
|
|||
// LocalProcessorBase implementation
|
||||
|
||||
LocalProcessorBase::LocalProcessorBase ()
|
||||
: m_report_progress (true), m_nthreads (0), m_max_vertex_count (0), m_area_ratio (0.0), m_boolean_core (false),
|
||||
: m_report_progress (true), m_nthreads (0), m_max_vertex_count (0), m_area_ratio (0.0), m_top_down (false), m_boolean_core (false),
|
||||
m_base_verbosity (30), mp_vars (0), mp_current_cell (0)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
|
|
@ -1034,84 +1034,90 @@ void local_processor<TS, TI, TR>::compute_contexts (local_processor_contexts<TS,
|
|||
}
|
||||
}
|
||||
|
||||
// TODO: can we shortcut this if interactions is empty?
|
||||
for (std::vector<unsigned int>::const_iterator il = contexts.intruder_layers ().begin (); il != contexts.intruder_layers ().end (); ++il) {
|
||||
// in top-down mode we are not interested in cell-to-cell interactions, nor shape-to-instance interactions
|
||||
// except local ones (shape-to-child cells), hence we skip this part
|
||||
if (! top_down ()) {
|
||||
|
||||
db::box_convert <db::CellInstArray, true> inst_bci (*mp_intruder_layout, contexts.actual_intruder_layer (*il));
|
||||
// TODO: can we shortcut this if interactions is empty?
|
||||
for (std::vector<unsigned int>::const_iterator il = contexts.intruder_layers ().begin (); il != contexts.intruder_layers ().end (); ++il) {
|
||||
|
||||
db::box_scanner2<db::CellInstArray, int, db::CellInstArray, int> scanner;
|
||||
interaction_registration_inst2inst<TS, TI, TR> rec (mp_subject_layout, contexts.subject_layer (), mp_intruder_layout, contexts.actual_intruder_layer (*il), contexts.is_foreign (*il), dist, &interactions);
|
||||
db::box_convert <db::CellInstArray, true> inst_bci (*mp_intruder_layout, contexts.actual_intruder_layer (*il));
|
||||
|
||||
unsigned int id = 0;
|
||||
db::box_scanner2<db::CellInstArray, int, db::CellInstArray, int> scanner;
|
||||
interaction_registration_inst2inst<TS, TI, TR> rec (mp_subject_layout, contexts.subject_layer (), mp_intruder_layout, contexts.actual_intruder_layer (*il), contexts.is_foreign (*il), dist, &interactions);
|
||||
|
||||
if (subject_cell == intruder_cell) {
|
||||
unsigned int id = 0;
|
||||
|
||||
// Use the same id's for same instances - this way we can easily detect same instances
|
||||
// and don't make them self-interacting
|
||||
if (subject_cell == intruder_cell) {
|
||||
|
||||
for (db::Cell::const_iterator i = subject_cell->begin (); !i.at_end (); ++i) {
|
||||
unsigned int iid = ++id;
|
||||
if (! inst_bcs (i->cell_inst ()).empty () && ! subject_cell_is_breakout (i->cell_index ())) {
|
||||
scanner.insert1 (&i->cell_inst (), iid);
|
||||
}
|
||||
if (! inst_bci (i->cell_inst ()).empty () && ! intruder_cell_is_breakout (i->cell_index ())) {
|
||||
scanner.insert2 (&i->cell_inst (), iid);
|
||||
}
|
||||
}
|
||||
// Use the same id's for same instances - this way we can easily detect same instances
|
||||
// and don't make them self-interacting
|
||||
|
||||
} else {
|
||||
|
||||
for (db::Cell::const_iterator i = subject_cell->begin (); !i.at_end (); ++i) {
|
||||
if (! inst_bcs (i->cell_inst ()).empty () && ! subject_cell_is_breakout (i->cell_index ())) {
|
||||
scanner.insert1 (&i->cell_inst (), ++id);
|
||||
}
|
||||
}
|
||||
|
||||
if (intruder_cell) {
|
||||
for (db::Cell::const_iterator i = intruder_cell->begin (); !i.at_end (); ++i) {
|
||||
for (db::Cell::const_iterator i = subject_cell->begin (); !i.at_end (); ++i) {
|
||||
unsigned int iid = ++id;
|
||||
if (! inst_bcs (i->cell_inst ()).empty () && ! subject_cell_is_breakout (i->cell_index ())) {
|
||||
scanner.insert1 (&i->cell_inst (), iid);
|
||||
}
|
||||
if (! inst_bci (i->cell_inst ()).empty () && ! intruder_cell_is_breakout (i->cell_index ())) {
|
||||
scanner.insert2 (&i->cell_inst (), ++id);
|
||||
scanner.insert2 (&i->cell_inst (), iid);
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
for (db::Cell::const_iterator i = subject_cell->begin (); !i.at_end (); ++i) {
|
||||
if (! inst_bcs (i->cell_inst ()).empty () && ! subject_cell_is_breakout (i->cell_index ())) {
|
||||
scanner.insert1 (&i->cell_inst (), ++id);
|
||||
}
|
||||
}
|
||||
|
||||
if (intruder_cell) {
|
||||
for (db::Cell::const_iterator i = intruder_cell->begin (); !i.at_end (); ++i) {
|
||||
if (! inst_bci (i->cell_inst ()).empty () && ! intruder_cell_is_breakout (i->cell_index ())) {
|
||||
scanner.insert2 (&i->cell_inst (), ++id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for (std::set<db::CellInstArray>::const_iterator i = intruders.first.begin (); i != intruders.first.end (); ++i) {
|
||||
if (! inst_bci (*i).empty ()) {
|
||||
scanner.insert2 (i.operator-> (), ++id);
|
||||
}
|
||||
}
|
||||
|
||||
scanner.process (rec, dist, inst_bcs, inst_bci);
|
||||
|
||||
}
|
||||
|
||||
for (std::set<db::CellInstArray>::const_iterator i = intruders.first.begin (); i != intruders.first.end (); ++i) {
|
||||
if (! inst_bci (*i).empty ()) {
|
||||
scanner.insert2 (i.operator-> (), ++id);
|
||||
if (! intruders.second.empty () || ! intruder_shapes.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) {
|
||||
if (! inst_bcs (i->cell_inst ()).empty () && ! subject_cell_is_breakout (i->cell_index ())) {
|
||||
scanner.insert1 (&i->cell_inst (), 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
scanner.process (rec, dist, inst_bcs, inst_bci);
|
||||
|
||||
}
|
||||
|
||||
if (! intruders.second.empty () || ! intruder_shapes.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) {
|
||||
if (! inst_bcs (i->cell_inst ()).empty () && ! subject_cell_is_breakout (i->cell_index ())) {
|
||||
scanner.insert1 (&i->cell_inst (), 0);
|
||||
for (typename std::map<unsigned int, std::set<TI> >::const_iterator il = intruders.second.begin (); il != intruders.second.end (); ++il) {
|
||||
for (typename std::set<TI>::const_iterator i = il->second.begin (); i != il->second.end (); ++i) {
|
||||
scanner.insert2 (i.operator-> (), il->first);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (typename std::map<unsigned int, std::set<TI> >::const_iterator il = intruders.second.begin (); il != intruders.second.end (); ++il) {
|
||||
for (typename std::set<TI>::const_iterator i = il->second.begin (); i != il->second.end (); ++i) {
|
||||
scanner.insert2 (i.operator-> (), il->first);
|
||||
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 (heap (*i), im->first);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 (heap (*i), im->first);
|
||||
}
|
||||
}
|
||||
scanner.process (rec, dist, inst_bcs, db::box_convert<TI> ());
|
||||
|
||||
scanner.process (rec, dist, inst_bcs, db::box_convert<TI> ());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -1417,14 +1423,14 @@ local_processor<TS, TI, TR>::compute_local_cell (const db::local_processor_conte
|
|||
}
|
||||
}
|
||||
|
||||
// local shapes vs. child cell
|
||||
|
||||
db::box_convert<db::CellInstArray, true> inst_bci (*mp_intruder_layout, ail);
|
||||
|
||||
typename std::map<unsigned int, std::set<TI> >::const_iterator ipl = intruders.second.find (*il);
|
||||
static std::set<TI> empty_intruders;
|
||||
|
||||
if (! subject_shapes->empty () && (intruder_shapes || ipl != intruders.second.end ())) {
|
||||
// local shapes vs. local shapes
|
||||
|
||||
if (! top_down () && ! subject_shapes->empty () && (intruder_shapes || ipl != intruders.second.end ())) {
|
||||
|
||||
if (subject_cell == intruder_cell && contexts.subject_layer () == ail && !foreign) {
|
||||
|
||||
|
|
@ -1439,6 +1445,8 @@ local_processor<TS, TI, TR>::compute_local_cell (const db::local_processor_conte
|
|||
|
||||
}
|
||||
|
||||
// local shapes vs. child cells
|
||||
|
||||
if (! subject_shapes->empty () && ! ((! intruder_cell || intruder_cell->begin ().at_end ()) && intruders.first.empty ())) {
|
||||
|
||||
db::box_scanner2<TS, int, db::CellInstArray, int> scanner;
|
||||
|
|
@ -1452,7 +1460,7 @@ local_processor<TS, TI, TR>::compute_local_cell (const db::local_processor_conte
|
|||
|
||||
unsigned int inst_id = 0;
|
||||
|
||||
if (subject_cell == intruder_cell && contexts.subject_layer () == ail && !foreign) {
|
||||
if (! top_down () && subject_cell == intruder_cell && contexts.subject_layer () == ail && !foreign) {
|
||||
|
||||
// Same cell, same layer -> no shape to child instance interactions because this will be taken care of
|
||||
// by the instances themselves (and their intruders). This also means, we prefer to deal with
|
||||
|
|
|
|||
|
|
@ -465,6 +465,16 @@ public:
|
|||
return m_nthreads;
|
||||
}
|
||||
|
||||
void set_top_down (bool f)
|
||||
{
|
||||
m_top_down = f;
|
||||
}
|
||||
|
||||
bool top_down () const
|
||||
{
|
||||
return m_top_down;
|
||||
}
|
||||
|
||||
void set_max_vertex_count (size_t max_vertex_count)
|
||||
{
|
||||
m_max_vertex_count = max_vertex_count;
|
||||
|
|
@ -525,6 +535,7 @@ private:
|
|||
unsigned int m_nthreads;
|
||||
size_t m_max_vertex_count;
|
||||
double m_area_ratio;
|
||||
bool m_top_down;
|
||||
bool m_boolean_core;
|
||||
int m_base_verbosity;
|
||||
const db::VariantsCollectorBase *mp_vars;
|
||||
|
|
|
|||
|
|
@ -1331,6 +1331,25 @@ public:
|
|||
return std::make_pair (Region (res.first), Region (res.second));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief For deep regions, remove parts of shapes which are covered by child cell shapes (push shapes into hierarchy)
|
||||
*
|
||||
* This will reduce the hierarchical load. This means that shapes that do not add information
|
||||
* will be removed, so their interactions with child cells does not need to be considered.
|
||||
* These shapes are - maybe partially - "peeled" from upper hierarchy layers.
|
||||
*
|
||||
* The complexity factor indicates by how much the complexity of the resulting polygons
|
||||
* (counted in terms of vertexes) can increase before a shape is left as it was.
|
||||
* A negative complexity factor indicates, that no such limit exists. A zero complexity factor
|
||||
* means that only shapes are removed if they are covered entirely by shapes from below the
|
||||
* hierarchy.
|
||||
*/
|
||||
Region &peel (double complexity_factor = 0.0)
|
||||
{
|
||||
set_delegate (mp_delegate->peel (complexity_factor));
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Selects all polygons of this region which are completely outside polygons from the other region
|
||||
*
|
||||
|
|
|
|||
|
|
@ -248,6 +248,8 @@ public:
|
|||
virtual RegionDelegate *add (const Region &other) const = 0;
|
||||
virtual std::pair<RegionDelegate *, RegionDelegate *> andnot_with (const Region &other, PropertyConstraint prop_constraint) const = 0;
|
||||
|
||||
virtual RegionDelegate *peel (double complexity_factor) const = 0;
|
||||
|
||||
virtual RegionDelegate *selected_outside (const Region &other) const = 0;
|
||||
virtual RegionDelegate *selected_not_outside (const Region &other) const = 0;
|
||||
virtual std::pair<RegionDelegate *, RegionDelegate *> selected_outside_pair (const Region &other) const = 0;
|
||||
|
|
|
|||
|
|
@ -2732,6 +2732,20 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"\n"
|
||||
"This method has been introduced in version 0.29.3."
|
||||
) +
|
||||
method ("peel", &db::Region::peel, gsi::arg ("complexity_factor", -1.0, "unlimited"),
|
||||
"@brief Removes shapes parts which are overlapping with child cell shapes, reducing hierarchical load.\n"
|
||||
"\n"
|
||||
"This method will reduce the hierarchical load. This means that shapes that do not add information\n"
|
||||
"will be removed, so their interactions with child cells does not need to be considered.\n"
|
||||
"These shapes are - maybe partially - \"peeled\" from upper hierarchy layers.\n"
|
||||
"\n"
|
||||
"The complexity factor determines if the subtraction is rejected when the complexity - measured as polygon "
|
||||
"vertex count - increases by more than the given factor. This allows trading off hierarchical complexity vs. "
|
||||
"polygon complexity. A negative factor means no rejection. A factor of zero means that only shapes are removed "
|
||||
"which are entirely covered by shapes from below the hierarchy.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.30.8."
|
||||
) +
|
||||
method_ext ("andnot", &andnot, gsi::arg ("other"), gsi::arg ("property_constraint", db::IgnoreProperties, "IgnoreProperties"),
|
||||
"@brief Returns the boolean AND and NOT between self and the other region\n"
|
||||
"\n"
|
||||
|
|
|
|||
|
|
@ -3290,3 +3290,54 @@ TEST(processed_delivers_polygon_refs)
|
|||
|
||||
EXPECT_EQ (rx.to_string (), "(0,0;0,2000;2000,2000;2000,0);(0,0;0,2000;2000,2000;2000,0/200,200;1800,200;1800,1800;200,1800){n=>42}");
|
||||
}
|
||||
|
||||
TEST(deep_region_peel)
|
||||
{
|
||||
db::Layout ly;
|
||||
{
|
||||
std::string fn (tl::testdata ());
|
||||
fn += "/algo/deep_region_peel.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 l1 = ly.get_layer (db::LayerProperties (1, 0));
|
||||
unsigned int l2 = ly.get_layer (db::LayerProperties (2, 0));
|
||||
|
||||
db::RecursiveShapeIterator si1 (ly, top_cell, l1);
|
||||
si1.apply_property_translator (db::PropertiesTranslator::make_pass_all ());
|
||||
|
||||
db::RecursiveShapeIterator si2 (ly, top_cell, l2);
|
||||
si2.apply_property_translator (db::PropertiesTranslator::make_pass_all ());
|
||||
|
||||
db::Region r1 (si1, dss);
|
||||
db::Region r2 (si2, dss);
|
||||
|
||||
unsigned int l1001 = ly.get_layer (db::LayerProperties (1001, 0));
|
||||
unsigned int l1002 = ly.get_layer (db::LayerProperties (1002, 0));
|
||||
unsigned int l1011 = ly.get_layer (db::LayerProperties (1011, 0));
|
||||
unsigned int l1012 = ly.get_layer (db::LayerProperties (1012, 0));
|
||||
unsigned int l1021 = ly.get_layer (db::LayerProperties (1021, 0));
|
||||
unsigned int l1022 = ly.get_layer (db::LayerProperties (1022, 0));
|
||||
unsigned int l1031 = ly.get_layer (db::LayerProperties (1031, 0));
|
||||
unsigned int l1032 = ly.get_layer (db::LayerProperties (1032, 0));
|
||||
|
||||
db::Region (r1).peel (-1.0).insert_into (&ly, top_cell_index, l1001);
|
||||
db::Region (r2).peel (-1.0).insert_into (&ly, top_cell_index, l1002);
|
||||
db::Region (r1).peel (0.0).insert_into (&ly, top_cell_index, l1011);
|
||||
db::Region (r2).peel (0.0).insert_into (&ly, top_cell_index, l1012);
|
||||
db::Region (r1).peel (2.0).insert_into (&ly, top_cell_index, l1021);
|
||||
db::Region (r2).peel (2.0).insert_into (&ly, top_cell_index, l1022);
|
||||
db::Region (r1).peel (4.0).insert_into (&ly, top_cell_index, l1031);
|
||||
db::Region (r2).peel (4.0).insert_into (&ly, top_cell_index, l1032);
|
||||
|
||||
CHECKPOINT();
|
||||
db::compare_layouts (_this, ly, tl::testdata () + "/algo/deep_region_peel_au.gds");
|
||||
}
|
||||
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue