@@ -401,6 +401,13 @@ DeepRegion::begin_merged () const
401401 }
402402}
403403
404+ RegionIteratorDelegate *
405+ DeepRegion::begin_unmerged () const
406+ {
407+ ensure_unmerged_polygons_valid ();
408+ return begin ();
409+ }
410+
404411std::pair<db::RecursiveShapeIterator, db::ICplxTrans>
405412DeepRegion::begin_iter () const
406413{
@@ -445,6 +452,13 @@ DeepRegion::begin_merged_iter () const
445452 }
446453}
447454
455+ std::pair<db::RecursiveShapeIterator, db::ICplxTrans>
456+ DeepRegion::begin_unmerged_iter () const
457+ {
458+ ensure_unmerged_polygons_valid ();
459+ return begin_iter ();
460+ }
461+
448462bool
449463DeepRegion::empty () const
450464{
@@ -787,6 +801,46 @@ DeepRegion::ensure_merged_polygons_valid () const
787801 }
788802}
789803
804+ void
805+ DeepRegion::ensure_unmerged_polygons_valid () const
806+ {
807+ if (! m_is_merged ||
808+ (deep_layer ().store ()->max_area_ratio () == 0.0 && deep_layer ().store ()->max_vertex_count () == 0 )) {
809+ return ;
810+ }
811+
812+ m_merged_polygons = deep_layer ().derived ();
813+ db::DeepLayer &polygons = const_cast <db::DeepLayer &> (deep_layer ());
814+
815+ m_merged_polygons_valid = true ;
816+ m_is_merged = false ;
817+ m_merged_polygons_boc_hash = deep_layer ().breakout_cells_hash ();
818+
819+ db::Layout &layout = polygons.layout ();
820+ polygons.swap (m_merged_polygons);
821+
822+ for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) {
823+
824+ const db::Shapes &s = c->shapes (m_merged_polygons.layer ());
825+ db::Shapes &st = c->shapes (deep_layer ().layer ());
826+
827+ db::PolygonRefToShapesGenerator pr (&layout, &st);
828+ db::PolygonSplitter splitter (pr, polygons.store ()->max_area_ratio (), polygons.store ()->max_vertex_count ());
829+
830+ splitter.start ();
831+ for (auto p = s.begin (db::ShapeIterator::All); ! p.at_end (); ++p) {
832+ if (p->is_polygon ()) {
833+ pr.set_prop_id (p->prop_id ());
834+ db::Polygon poly;
835+ p->polygon (poly);
836+ splitter.put (poly);
837+ }
838+ }
839+ splitter.flush ();
840+
841+ }
842+ }
843+
790844void
791845DeepRegion::set_is_merged (bool f)
792846{
@@ -826,6 +880,140 @@ DeepRegion::nets (LayoutToNetlist *l2n, NetPropertyMode prop_mode, const tl::Var
826880 return new db::DeepRegion (result);
827881}
828882
883+ namespace {
884+
885+ /* *
886+ * @brief Implements a boolean AND or NOT operation with property handling
887+ */
888+ class DB_PUBLIC PushHierLocalOperationWithProperties
889+ : public local_operation<db::object_with_properties<db::PolygonRef>, db::object_with_properties<db::PolygonRef>, db::object_with_properties<db::PolygonRef> >
890+ {
891+ public:
892+ PushHierLocalOperationWithProperties (double complexity_factor)
893+ : local_operation<db::object_with_properties<db::PolygonRef>, db::object_with_properties<db::PolygonRef>, db::object_with_properties<db::PolygonRef> > (),
894+ m_complexity_factor (complexity_factor)
895+ {
896+ // .. nothing yet ..
897+ }
898+
899+ OnEmptyIntruderHint on_empty_intruder_hint () const { return Copy; }
900+
901+ std::string description () const
902+ {
903+ return tl::to_string (tr (" 'peel' operation" ));
904+ }
905+
906+
907+ 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
908+ {
909+ tl_assert (results.size () == 1 );
910+ auto &result = results.front ();
911+
912+ db::EdgeProcessor ep;
913+
914+ for (auto i = interactions.begin (); i != interactions.end (); ++i) {
915+
916+ const auto &subject = interactions.subject_shape (i->first );
917+ db::properties_id_type prop_id = subject.properties_id ();
918+
919+ if (i->second .empty ()) {
920+
921+ result.insert (subject);
922+
923+ } else {
924+
925+ ep.clear ();
926+
927+ const auto &subject = interactions.subject_shape (i->first );
928+ for (auto e = subject.begin_edge (); ! e.at_end (); ++e) {
929+ ep.insert (*e, 0 );
930+ }
931+
932+ size_t p2 = 1 ;
933+ for (auto ii = i->second .begin (); ii != i->second .end (); ++ii) {
934+ const auto &intruder = interactions.intruder_shape (*ii);
935+ for (auto e = intruder.second .begin_edge (); ! e.at_end (); ++e) {
936+ ep.insert (*e, p2);
937+ }
938+ p2 += 2 ;
939+ }
940+
941+ std::unordered_set<db::object_with_properties<db::PolygonRef> > result1;
942+
943+ db::BooleanOp op (db::BooleanOp::ANotB);
944+ db::polygon_ref_generator_with_properties<db::object_with_properties<db::PolygonRef> > pr (layout, result1, prop_id);
945+ db::PolygonSplitter splitter (pr, proc->area_ratio (), proc->max_vertex_count ());
946+ db::PolygonGenerator pg (splitter, true , true );
947+ ep.set_base_verbosity (50 );
948+ ep.process (pg, op);
949+
950+ if (result1.empty ()) {
951+
952+ // shortcut: nothing to do
953+
954+ } else if (m_complexity_factor < 0.0 ) {
955+
956+ // no complexity limit
957+ result.insert (result1.begin (), result1.end ());
958+
959+ } else if (m_complexity_factor == 0.0 ) {
960+
961+ // only remove shape if it is really entirely covered in this case
962+ result.insert (subject);
963+
964+ } else {
965+
966+ size_t vertices_before = subject.vertices ();
967+ size_t vertices_after = 0 ;
968+ for (auto r = result1.begin (); r != result1.end (); ++r) {
969+ vertices_after += r->vertices ();
970+ }
971+
972+ if (floor (0.5 + m_complexity_factor * vertices_before) >= vertices_after) {
973+ result.insert (result1.begin (), result1.end ());
974+ } else {
975+ result.insert (subject);
976+ }
977+
978+ }
979+
980+ }
981+
982+ }
983+ }
984+
985+ private:
986+ double m_complexity_factor;
987+ };
988+
989+ }
990+
991+ RegionDelegate *
992+ DeepRegion::peel (double complexity_factor) const
993+ {
994+ if (empty ()) {
995+ // we can return "this", as this method is only intended for in-place execution inside Region
996+ return const_cast <DeepRegion *> (this );
997+ }
998+
999+ DeepLayer dl_out (deep_layer ().derived ());
1000+
1001+ PushHierLocalOperationWithProperties op (complexity_factor);
1002+
1003+ 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 ());
1004+ configure_proc (proc);
1005+ proc.set_threads (deep_layer ().store ()->threads ());
1006+ proc.set_area_ratio (deep_layer ().store ()->max_area_ratio ());
1007+ proc.set_max_vertex_count (deep_layer ().store ()->max_vertex_count ());
1008+
1009+ // with this setting, only top-down interactions are considered
1010+ proc.set_top_down (true );
1011+
1012+ proc.run (&op, deep_layer ().layer (), deep_layer ().layer (), dl_out.layer ());
1013+
1014+ return new DeepRegion (dl_out);
1015+ }
1016+
8291017RegionDelegate *
8301018DeepRegion::and_with (const Region &other, PropertyConstraint property_constraint) const
8311019{
@@ -922,6 +1110,10 @@ DeepRegion::andnot_with (const Region &other, PropertyConstraint property_constr
9221110DeepLayer
9231111DeepRegion::and_with_impl (const DeepRegion *other, db::PropertyConstraint property_constraint) const
9241112{
1113+ // booleans run better on simple polygons
1114+ ensure_unmerged_polygons_valid ();
1115+ other->ensure_unmerged_polygons_valid ();
1116+
9251117 DeepLayer dl_out (deep_layer ().derived ());
9261118
9271119 if (pc_skip (property_constraint)) {
@@ -956,6 +1148,10 @@ DeepRegion::and_with_impl (const DeepRegion *other, db::PropertyConstraint prope
9561148DeepLayer
9571149DeepRegion::not_with_impl (const DeepRegion *other, db::PropertyConstraint property_constraint) const
9581150{
1151+ // booleans run better on simple polygons
1152+ ensure_unmerged_polygons_valid ();
1153+ other->ensure_unmerged_polygons_valid ();
1154+
9591155 DeepLayer dl_out (deep_layer ().derived ());
9601156 DeepLayer dl_prep;
9611157
@@ -1059,6 +1255,10 @@ DeepRegion::not_with_impl (const DeepRegion *other, db::PropertyConstraint prope
10591255std::pair<DeepLayer, DeepLayer>
10601256DeepRegion::and_and_not_with (const DeepRegion *other, PropertyConstraint property_constraint) const
10611257{
1258+ // booleans run better on simple polygons
1259+ ensure_unmerged_polygons_valid ();
1260+ other->ensure_unmerged_polygons_valid ();
1261+
10621262 DeepLayer dl_out1 (deep_layer ().derived ());
10631263 DeepLayer dl_out2 (deep_layer ().derived ());
10641264
@@ -1179,6 +1379,10 @@ DeepRegion::add_in_place (const Region &other)
11791379 const DeepRegion *other_deep = dynamic_cast <const DeepRegion *> (other.delegate ());
11801380 if (other_deep) {
11811381
1382+ // NOTE: as we don't benefit from merged shapes here, we prefer unmerged ones
1383+ // for potentially better performance.
1384+ other_deep->ensure_unmerged_polygons_valid ();
1385+
11821386 deep_layer ().add_from (other_deep->deep_layer ());
11831387
11841388 } else {
@@ -1885,6 +2089,10 @@ DeepRegion::sized (coord_type d, unsigned int mode) const
18852089 return clone ();
18862090 }
18872091
2092+ // in case of negative sizing the output polygons will still be merged (on positive sizing they might
2093+ // overlap after size and are not necessarily merged)
2094+ bool will_be_merged = (d < 0 && (merged_semantics () || is_merged ()));
2095+
18882096 const db::DeepLayer &polygons = merged_deep_layer ();
18892097
18902098 db::Layout &layout = const_cast <db::Layout &> (polygons.layout ());
@@ -1904,7 +2112,8 @@ DeepRegion::sized (coord_type d, unsigned int mode) const
19042112 db::Shapes &st = c->shapes (res->deep_layer ().layer ());
19052113
19062114 db::PolygonRefToShapesGenerator pr (&layout, &st);
1907- db::PolygonGenerator pg2 (pr, false /* don't resolve holes*/ , true /* min. coherence*/ );
2115+ db::PolygonSplitter splitter (pr, will_be_merged ? 0.0 : polygons.store ()->max_area_ratio (), will_be_merged ? 0 : polygons.store ()->max_vertex_count ());
2116+ db::PolygonGenerator pg2 (splitter, false /* don't resolve holes*/ , true /* min. coherence*/ );
19082117 db::SizingPolygonFilter siz (pg2, d_with_mag, d_with_mag, mode);
19092118
19102119 for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::All); ! si.at_end (); ++si) {
@@ -1916,11 +2125,7 @@ DeepRegion::sized (coord_type d, unsigned int mode) const
19162125
19172126 }
19182127
1919- // in case of negative sizing the output polygons will still be merged (on positive sizing they might
1920- // overlap after size and are not necessarily merged)
1921- if (d < 0 && (merged_semantics () || is_merged ())) {
1922- res->set_is_merged (true );
1923- }
2128+ res->set_is_merged (will_be_merged);
19242129
19252130 return res.release ();
19262131}
@@ -1938,6 +2143,10 @@ DeepRegion::sized (coord_type dx, coord_type dy, unsigned int mode) const
19382143 return sized (dx, mode);
19392144 }
19402145
2146+ // in case of negative sizing the output polygons will still be merged (on positive sizing they might
2147+ // overlap after size and are not necessarily merged)
2148+ bool will_be_merged = (dx < 0 && dy < 0 && (merged_semantics () || is_merged ()));
2149+
19412150 const db::DeepLayer &polygons = merged_deep_layer ();
19422151
19432152 db::Layout &layout = const_cast <db::Layout &> (polygons.layout ());
@@ -1964,7 +2173,8 @@ DeepRegion::sized (coord_type dx, coord_type dy, unsigned int mode) const
19642173 db::Shapes &st = c->shapes (res->deep_layer ().layer ());
19652174
19662175 db::PolygonRefToShapesGenerator pr (&layout, &st);
1967- db::PolygonGenerator pg2 (pr, false /* don't resolve holes*/ , true /* min. coherence*/ );
2176+ db::PolygonSplitter splitter (pr, will_be_merged ? 0.0 : polygons.store ()->max_area_ratio (), will_be_merged ? 0 : polygons.store ()->max_vertex_count ());
2177+ db::PolygonGenerator pg2 (splitter, false /* don't resolve holes*/ , true /* min. coherence*/ );
19682178 db::SizingPolygonFilter siz (pg2, dx_with_mag, dy_with_mag, mode);
19692179
19702180 for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::All); ! si.at_end (); ++si) {
@@ -1976,11 +2186,7 @@ DeepRegion::sized (coord_type dx, coord_type dy, unsigned int mode) const
19762186
19772187 }
19782188
1979- // in case of negative sizing the output polygons will still be merged (on positive sizing they might
1980- // overlap after size and are not necessarily merged)
1981- if (dx < 0 && dy < 0 && (merged_semantics () || is_merged ())) {
1982- res->set_is_merged (true );
1983- }
2189+ res->set_is_merged (will_be_merged);
19842190
19852191 return res.release ();
19862192}
0 commit comments