Merge branch 'performance' into wip

This commit is contained in:
Matthias Koefferlein 2022-11-11 21:55:39 +01:00
commit aadb8510d2
11 changed files with 331 additions and 75 deletions

View File

@ -1037,7 +1037,11 @@ AsIfFlatRegion::run_check (db::edge_relation_type rel, bool different_polygons,
{
#if defined(USE_LOCAL_PROCESSOR)
db::RegionIterator polygons (begin_merged ());
bool needs_merged_primary = different_polygons || options.needs_merged ();
needs_merged_primary = true; // @@@
db::RegionIterator polygons (needs_merged_primary ? begin_merged () : begin ());
bool primary_is_merged = ! merged_semantics () || needs_merged_primary || is_merged ();
EdgeRelationFilter check (rel, d, options.metrics);
check.set_include_zero (false);
@ -1059,9 +1063,12 @@ AsIfFlatRegion::run_check (db::edge_relation_type rel, bool different_polygons,
if (other == subject_regionptr () || other == foreign_regionptr ()) {
foreign.push_back (other == foreign_regionptr ());
others.push_back (begin_merged ());
other_is_merged = primary_is_merged;
} else {
foreign.push_back (false);
if (options.whole_edges) {
if (! other->merged_semantics ()) {
other_is_merged = true;
} else if (options.whole_edges) {
// NOTE: whole edges needs both inputs merged
others.push_back (other->begin_merged ());
other_is_merged = true;
@ -1072,7 +1079,7 @@ AsIfFlatRegion::run_check (db::edge_relation_type rel, bool different_polygons,
has_other = true;
}
db::check_local_operation<db::Polygon, db::Polygon> op (check, different_polygons, has_other, other_is_merged, options);
db::check_local_operation<db::Polygon, db::Polygon> op (check, different_polygons, primary_is_merged, has_other, other_is_merged, options);
std::unique_ptr<FlatEdgePairs> output (new FlatEdgePairs ());
std::vector<db::Shapes *> results;

View File

@ -1555,10 +1555,13 @@ CompoundRegionCheckOperationNode::CompoundRegionCheckOperationNode (CompoundRegi
m_check.set_max_projection (options.max_projection);
}
CompoundRegionCheckOperationNode::CompoundRegionCheckOperationNode (CompoundRegionOperationNode * /*input*/, CompoundRegionOperationNode *other, db::edge_relation_type rel, bool different_polygons, db::Coord d, const db::RegionCheckOptions &options)
CompoundRegionCheckOperationNode::CompoundRegionCheckOperationNode (CompoundRegionOperationNode *input, CompoundRegionOperationNode *other, db::edge_relation_type rel, bool different_polygons, db::Coord d, const db::RegionCheckOptions &options)
: CompoundRegionMultiInputOperationNode (other), m_check (rel, d, options.metrics), m_different_polygons (different_polygons), m_options (options)
{
tl_assert (input == 0); // input is a dummy parameter
m_has_other = other->has_external_inputs ();
// @@@ needs a concept to deal with merged/non-merged inputs
m_is_other_merged = other->is_merged ();
set_description ("check");
@ -1585,7 +1588,9 @@ CompoundRegionCheckOperationNode::computed_dist () const
void
CompoundRegionCheckOperationNode::do_compute_local (CompoundRegionOperationCache * /*cache*/, db::Layout *layout, const shape_interactions<db::Polygon, db::Polygon> &interactions, std::vector<std::unordered_set<db::EdgePair> > &results, size_t max_vertex_count, double area_ratio) const
{
db::check_local_operation<db::Polygon, db::Polygon> op (m_check, m_different_polygons, m_has_other, m_is_other_merged, m_options);
// @@@ needs a concept to deal with merged/non-merged primary
bool is_merged = true;
db::check_local_operation<db::Polygon, db::Polygon> op (m_check, m_different_polygons, is_merged, m_has_other, m_is_other_merged, m_options);
tl_assert (results.size () == 1);
if (results.front ().empty ()) {
@ -1601,7 +1606,9 @@ CompoundRegionCheckOperationNode::do_compute_local (CompoundRegionOperationCache
void
CompoundRegionCheckOperationNode::do_compute_local (CompoundRegionOperationCache * /*cache*/, db::Layout *layout, const shape_interactions<db::PolygonRef, db::PolygonRef> &interactions, std::vector<std::unordered_set<db::EdgePair> > &results, size_t max_vertex_count, double area_ratio) const
{
db::check_local_operation<db::PolygonRef, db::PolygonRef> op (m_check, m_different_polygons, m_has_other, m_is_other_merged, m_options);
// @@@ needs a concept to deal with merged/non-merged primary
bool is_merged = true;
db::check_local_operation<db::PolygonRef, db::PolygonRef> op (m_check, m_different_polygons, is_merged, m_has_other, m_is_other_merged, m_options);
tl_assert (results.size () == 1);
if (results.front ().empty ()) {

View File

@ -1647,16 +1647,23 @@ DeepRegion::run_check (db::edge_relation_type rel, bool different_polygons, cons
unsigned int other_layer = 0;
bool other_is_merged = true;
bool needs_merged_primary = different_polygons || options.needs_merged ();
bool primary_is_merged = ! merged_semantics () || needs_merged_primary || is_merged ();
if (other == subject_regionptr ()) {
other_layer = subject_idlayer ();
other_is_merged = primary_is_merged;
} else if (other == foreign_regionptr ()) {
other_layer = foreign_idlayer ();
other_is_merged = primary_is_merged;
} else {
other_deep = dynamic_cast<const db::DeepRegion *> (other->delegate ());
if (! other_deep) {
return db::AsIfFlatRegion::run_check (rel, different_polygons, other, d, options);
}
if (options.whole_edges) {
if (! other->merged_semantics ()) {
other_is_merged = true;
} else if (options.whole_edges) {
// NOTE: whole edges needs both inputs merged
other_layer = other_deep->merged_deep_layer ().layer ();
other_is_merged = true;
@ -1666,7 +1673,7 @@ DeepRegion::run_check (db::edge_relation_type rel, bool different_polygons, cons
}
}
const db::DeepLayer &polygons = merged_deep_layer ();
const db::DeepLayer &polygons = needs_merged_primary ? merged_deep_layer () : deep_layer ();
EdgeRelationFilter check (rel, d, options.metrics);
check.set_include_zero (false);
@ -1677,7 +1684,7 @@ DeepRegion::run_check (db::edge_relation_type rel, bool different_polygons, cons
std::unique_ptr<db::DeepEdgePairs> res (new db::DeepEdgePairs (polygons.derived ()));
db::CheckLocalOperation op (check, different_polygons, other_deep != 0, other_is_merged, options);
db::CheckLocalOperation op (check, different_polygons, primary_is_merged, other_deep != 0, other_is_merged, options);
db::local_processor<db::PolygonRef, db::PolygonRef, db::EdgePair> proc (const_cast<db::Layout *> (&polygons.layout ()),
const_cast<db::Cell *> (&polygons.initial_cell ()),

View File

@ -252,8 +252,15 @@ namespace std
h = hfunc_coord (o.bgn_ext (), h);
h = hfunc_coord (o.end_ext (), h);
h = hfunc_coord (o.width (), h);
// NOTE: using too many points for the hash function just slows down the code.
unsigned int n = 20;
for (typename db::path<C>::iterator p = o.begin (); p != o.end (); ++p) {
h = hfunc (*p, h);
if (--n == 0) {
h = hfunc (o.points (), h);
break;
} else {
h = hfunc (*p, h);
}
}
return h;
}
@ -280,8 +287,15 @@ namespace std
template <class C>
size_t hfunc (const db::polygon_contour<C> &o, size_t h)
{
// NOTE: using too many points for the hash function just slows down the code.
unsigned int n = 20;
for (typename db::polygon_contour<C>::simple_iterator i = o.begin (); i != o.end (); ++i) {
h = hfunc (*i, h);
if (--n == 0) {
h = hfunc (o.size (), h);
break;
} else {
h = hfunc (*i, h);
}
}
return h;
}
@ -309,8 +323,15 @@ namespace std
size_t hfunc (const db::polygon<C> &o, size_t h)
{
h = hfunc (o.hull (), h);
// NOTE: using too many points for the hash function just slows down the code.
unsigned int n = 20;
for (size_t i = 0; i < o.holes (); ++i) {
h = hfunc (o.hole (int (i)), h);
if (--n == 0) {
h = hfunc (o.holes (), h);
break;
} else {
h = hfunc (o.hole (int (i)), h);
}
}
return h;
}

View File

@ -189,15 +189,22 @@ public:
typedef typename Ref::shape_type shape_type;
typedef typename Ref::trans_type ref_trans_type;
shape_reference_translator_with_trans_from_shape_ref (db::Layout *target_layout, const Trans &trans)
: mp_layout (target_layout), m_trans (trans), m_ref_trans (trans), m_bare_trans (Trans (m_ref_trans.inverted ()) * trans)
shape_reference_translator_with_trans_from_shape_ref (db::Layout *target_layout)
: mp_layout (target_layout)
{
// .. nothing yet ..
}
void set_trans (const Trans &trans)
{
m_trans = trans;
m_ref_trans = ref_trans_type (trans);
m_bare_trans = Trans (m_ref_trans.inverted ()) * trans;
}
Ref operator() (const Ref &ref) const
{
typename std::unordered_map<const shape_type *, std::pair<const shape_type *, ref_trans_type> >::const_iterator m = m_cache.find (ref.ptr ());
auto m = m_cache.find (std::make_pair (ref.ptr (), m_bare_trans));
if (m != m_cache.end ()) {
return Ref (m->second.first, ref_trans_type (m_trans * Trans (ref.trans ())) * m->second.second);
@ -214,7 +221,7 @@ public:
ptr = mp_layout->shape_repository ().repository (typename shape_type::tag ()).insert (sh);
}
m_cache[ref.ptr ()] = std::make_pair (ptr, red_trans);
m_cache[std::make_pair (ref.ptr (), m_bare_trans)] = std::make_pair (ptr, red_trans);
return Ref (ptr, ref_trans_type (m_trans * Trans (ref.trans ())) * red_trans);
@ -226,7 +233,7 @@ private:
Trans m_trans;
ref_trans_type m_ref_trans;
Trans m_bare_trans;
mutable std::unordered_map<const shape_type *, std::pair<const shape_type *, ref_trans_type> > m_cache;
mutable std::unordered_map<std::pair<const shape_type *, Trans>, std::pair<const shape_type *, ref_trans_type> > m_cache;
};
template <class Trans>
@ -234,8 +241,8 @@ class shape_reference_translator_with_trans<db::PolygonRef, Trans>
: public shape_reference_translator_with_trans_from_shape_ref<db::PolygonRef, Trans>
{
public:
shape_reference_translator_with_trans (db::Layout *target_layout, const Trans &trans)
: shape_reference_translator_with_trans_from_shape_ref<db::PolygonRef, Trans> (target_layout, trans)
shape_reference_translator_with_trans (db::Layout *target_layout)
: shape_reference_translator_with_trans_from_shape_ref<db::PolygonRef, Trans> (target_layout)
{
// .. nothing yet ..
}
@ -247,12 +254,16 @@ class shape_reference_translator_with_trans
public:
typedef Sh shape_type;
shape_reference_translator_with_trans (db::Layout * /*target_layout*/, const Trans &trans)
: m_trans (trans)
shape_reference_translator_with_trans (db::Layout * /*target_layout*/)
{
// .. nothing yet ..
}
void set_trans (const Trans &trans)
{
m_trans = trans;
}
shape_type operator() (const shape_type &s) const
{
return s.transformed (m_trans);
@ -331,11 +342,11 @@ template <class TS, class TI, class TR>
local_processor_cell_context<TS, TI, TR> &
local_processor_cell_context<TS, TI, TR>::operator= (const local_processor_cell_context &other)
{
if (this != &other) {
m_propagated = other.m_propagated;
m_drops = other.m_drops;
}
return *this;
if (this != &other) {
m_propagated = other.m_propagated;
m_drops = other.m_drops;
}
return *this;
}
template <class TS, class TI, class TR>
@ -353,13 +364,20 @@ local_processor_cell_context<TS, TI, TR>::propagate (unsigned int output_layer,
return;
}
db::Layout *subject_layout = 0;
shape_reference_translator_with_trans<TR, db::ICplxTrans> rt (subject_layout);
for (typename std::vector<local_processor_cell_drop<TS, TI, TR> >::const_iterator d = m_drops.begin (); d != m_drops.end (); ++d) {
tl_assert (d->parent_context != 0);
tl_assert (d->parent != 0);
db::Layout *subject_layout = d->parent->layout ();
shape_reference_translator_with_trans<TR, db::ICplxTrans> rt (subject_layout, d->cell_inst);
if (subject_layout != d->parent->layout ()) {
subject_layout = d->parent->layout ();
rt = shape_reference_translator_with_trans<TR, db::ICplxTrans> (subject_layout);
}
rt.set_trans (d->cell_inst);
std::vector<TR> new_refs;
new_refs.reserve (res.size ());
for (typename std::unordered_set<TR>::const_iterator r = res.begin (); r != res.end (); ++r) {
@ -1180,7 +1198,7 @@ public:
typedef std::unordered_map<std::pair<db::cell_index_type, db::ICplxTrans>, interactions_value_type> interactions_type;
interaction_registration_inst2shape (db::Layout *subject_layout, unsigned int subject_layer, db::Coord dist, interactions_type *result)
: mp_subject_layout (subject_layout), m_subject_layer (subject_layer), m_dist (dist), mp_result (result)
: mp_subject_layout (subject_layout), m_subject_layer (subject_layer), m_dist (dist), mp_result (result), m_rt (subject_layout)
{
// nothing yet ..
}
@ -1195,6 +1213,7 @@ private:
unsigned int m_subject_layer;
db::Coord m_dist;
interactions_type *mp_result;
db::shape_reference_translator_with_trans<TI, db::ICplxTrans> m_rt;
void
collect_instance_shape_interactions (const db::CellInstArray *inst, unsigned int layer, const TI &ref, db::Coord dist)
@ -1211,7 +1230,7 @@ private:
if (! cbox.empty ()) {
db::ICplxTrans tni = tn.inverted ();
db::shape_reference_translator_with_trans<TI, db::ICplxTrans> rt (mp_subject_layout, tni);
m_rt.set_trans (tni);
std::set<TI> *shapes = 0;
@ -1223,7 +1242,7 @@ private:
if (! shapes) {
shapes = & (*mp_result) [std::make_pair (cell.cell_index (), tn)].second [layer];
}
shapes->insert (rt (ref));
shapes->insert (m_rt (ref));
}
}

View File

@ -3076,6 +3076,7 @@ public:
typedef typename Poly::coord_type coord_type;
typedef typename Poly::point_type point_type;
typedef typename Poly::box_type box_type;
typedef typename Poly::edge_type edge_type;
typedef Trans trans_type;
typedef Poly polygon_type;
typedef db::polygon_edge_iterator<Poly, trans_type> polygon_edge_iterator;

View File

@ -468,6 +468,14 @@ poly2poly_check<PolygonType>::enter (const PolygonType &o, size_t p)
}
}
template <class PolygonType>
void
poly2poly_check<PolygonType>::enter (const poly2poly_check<PolygonType>::edge_type &e, size_t p)
{
m_edge_heap.push_back (e);
m_scanner.insert (& m_edge_heap.back (), p);
}
// TODO: move to generic header
static bool interact (const db::Box &box, const db::Edge &e)
{
@ -496,6 +504,16 @@ poly2poly_check<PolygonType>::enter (const PolygonType &o, size_t p, const poly2
}
}
template <class PolygonType>
void
poly2poly_check<PolygonType>::enter (const poly2poly_check<PolygonType>::edge_type &e, size_t p, const poly2poly_check<PolygonType>::box_type &box)
{
if (! box.empty () && interact (box, e)) {
m_edge_heap.push_back (e);
m_scanner.insert (& m_edge_heap.back (), p);
}
}
template <class PolygonType>
void
poly2poly_check<PolygonType>::process ()

View File

@ -310,6 +310,7 @@ class DB_PUBLIC poly2poly_check
{
public:
typedef typename PolygonType::box_type box_type;
typedef typename PolygonType::edge_type edge_type;
poly2poly_check (Edge2EdgeCheckBase &output);
poly2poly_check ();
@ -321,6 +322,8 @@ public:
void connect (Edge2EdgeCheckBase &output);
void enter (const PolygonType &o, size_t p);
void enter (const PolygonType &o, size_t p, const box_type &search_box);
void enter (const edge_type &o, size_t p);
void enter (const edge_type &o, size_t p, const box_type &search_box);
void process ();
private:

View File

@ -122,8 +122,8 @@ static bool shields_interaction (const db::EdgePair &ep, const P &poly)
}
template <class TS, class TI>
check_local_operation<TS, TI>::check_local_operation (const EdgeRelationFilter &check, bool different_polygons, bool has_other, bool other_is_merged, const db::RegionCheckOptions &options)
: m_check (check), m_different_polygons (different_polygons), m_has_other (has_other), m_other_is_merged (other_is_merged), m_options (options)
check_local_operation<TS, TI>::check_local_operation (const EdgeRelationFilter &check, bool different_polygons, bool is_merged, bool has_other, bool other_is_merged, const db::RegionCheckOptions &options)
: m_check (check), m_different_polygons (different_polygons), m_is_merged (is_merged), m_has_other (has_other), m_other_is_merged (other_is_merged), m_options (options)
{
// .. nothing yet ..
}
@ -208,12 +208,15 @@ check_local_operation<TS, TI>::do_compute_local (db::Layout *layout, const shape
edge2edge_check_negative_or_positive<std::unordered_set<db::EdgePair> > edge_check (m_check, result, intra_polygon_result, m_options.negative, m_different_polygons, m_has_other, m_options.shielded, symmetric_edge_pairs);
poly2poly_check<TS> poly_check (edge_check);
std::list<TS> heap;
std::unordered_set<TI> polygons;
std::unordered_set<TS> spolygons;
db::EdgeProcessor ep;
ep.set_base_verbosity (50);
std::set<unsigned int> ids;
for (typename shape_interactions<TS, TI>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
for (typename shape_interactions<TS, TI>::iterator2 j = i->second.begin (); j != i->second.end (); ++j) {
for (auto i = interactions.begin (); i != interactions.end (); ++i) {
for (auto j = i->second.begin (); j != i->second.end (); ++j) {
ids.insert (*j);
}
}
@ -226,13 +229,13 @@ check_local_operation<TS, TI>::do_compute_local (db::Layout *layout, const shape
db::Vector e (edge_check.distance (), edge_check.distance ());
db::Box subject_box;
for (typename shape_interactions<TS, TI>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
for (auto i = interactions.begin (); i != interactions.end (); ++i) {
subject_box += db::box_convert<TS> () (interactions.subject_shape (i->first));
}
if (edge_check.requires_different_layers ()) {
db::Box intruder_box;
for (std::set<unsigned int>::const_iterator id = ids.begin (); id != ids.end (); ++id) {
for (auto id = ids.begin (); id != ids.end (); ++id) {
intruder_box += db::box_convert<TI> () (interactions.intruder_shape (*id).second);
}
common_box = subject_box.enlarged (e) & intruder_box.enlarged (e);
@ -245,14 +248,50 @@ check_local_operation<TS, TI>::do_compute_local (db::Layout *layout, const shape
if (m_has_other) {
size_t n = 0;
for (typename shape_interactions<TS, TI>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
const TS &subject = interactions.subject_shape (i->first);
if (! take_all) {
poly_check.enter (subject, n, common_box);
} else {
poly_check.enter (subject, n);
if (m_is_merged || (interactions.size () == 1 && interactions.subject_shape (interactions.begin ()->first).is_box ())) {
for (auto i = interactions.begin (); i != interactions.end (); ++i) {
const TS &subject = interactions.subject_shape (i->first);
if (! take_all) {
poly_check.enter (subject, n, common_box);
} else {
poly_check.enter (subject, n);
}
n += 2;
}
n += 2;
} else {
// merge needed for the subject shapes
ep.clear ();
size_t nn = 0;
for (auto i = interactions.begin (); i != interactions.end (); ++i) {
const TS &is = interactions.subject_shape (i->first);
for (typename TS::polygon_edge_iterator e = is.begin_edge (); ! e.at_end (); ++e) {
ep.insert (*e, nn);
}
++nn;
}
spolygons.clear ();
db::polygon_ref_generator<TS> ps (layout, spolygons);
db::PolygonGenerator pg (ps, false /*don't resolve holes*/, false);
db::SimpleMerge op (1 /*wc>0*/);
ep.process (pg, op);
for (auto o = spolygons.begin (); o != spolygons.end (); ++o) {
if (! take_all) {
poly_check.enter (*o, n, common_box);
} else {
poly_check.enter (*o, n);
}
n += 2;
}
}
// merge the intruders to remove inner edges
@ -266,20 +305,19 @@ check_local_operation<TS, TI>::do_compute_local (db::Layout *layout, const shape
// NOTE: this local merge is not necessarily giving the same results than a global merge before running
// the processor. Reason: the search range is limited, hence not all necessary components may have been
// captured.
db::EdgeProcessor ep;
ep.set_base_verbosity (50);
ep.clear ();
size_t i = 0;
size_t nn = 0;
for (std::set<unsigned int>::const_iterator id = ids.begin (); id != ids.end (); ++id) {
for (auto id = ids.begin (); id != ids.end (); ++id) {
const TI &is = interactions.intruder_shape (*id).second;
for (typename TI::polygon_edge_iterator e = is.begin_edge (); ! e.at_end (); ++e) {
ep.insert (*e, i);
for (auto e = is.begin_edge (); ! e.at_end (); ++e) {
ep.insert (*e, nn);
}
++i;
++nn;
}
// @@@ Use edges directly
polygons.clear ();
db::polygon_ref_generator<TI> ps (layout, polygons);
@ -288,7 +326,7 @@ check_local_operation<TS, TI>::do_compute_local (db::Layout *layout, const shape
ep.process (pg, op);
n = 1;
for (typename std::unordered_set<TI>::const_iterator o = polygons.begin (); o != polygons.end (); ++o) {
for (auto o = polygons.begin (); o != polygons.end (); ++o) {
if (! take_all) {
poly_check.enter (*o, n, common_box);
} else {
@ -300,7 +338,7 @@ check_local_operation<TS, TI>::do_compute_local (db::Layout *layout, const shape
} else {
n = 1;
for (std::set<unsigned int>::const_iterator id = ids.begin (); id != ids.end (); ++id) {
for (auto id = ids.begin (); id != ids.end (); ++id) {
if (! take_all) {
poly_check.enter (interactions.intruder_shape (*id).second, n, common_box);
} else {
@ -313,34 +351,155 @@ check_local_operation<TS, TI>::do_compute_local (db::Layout *layout, const shape
} else {
// NOTE: we need to eliminate identical shapes from intruders and subjects because those will shield
if (m_is_merged || (interactions.size () == 1 && ids.empty () && interactions.subject_shape (interactions.begin ()->first).is_box ())) {
size_t n = 0;
// no merge required
for (typename shape_interactions<TS, TI>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
// we can't directly insert because TS may be != TI
const TS &ts = interactions.subject_shape (i->first);
insert_into_hash (polygons, ts);
if (! take_all) {
poly_check.enter (ts, n, common_box);
} else {
poly_check.enter (ts, n);
}
n += 2;
}
// NOTE: we need to eliminate identical shapes from intruders and subjects because those will shield
n = 1;
size_t n = 0;
std::unordered_set<TI> subjects;
for (std::set<unsigned int>::const_iterator id = ids.begin (); id != ids.end (); ++id) {
const TI &ti = interactions.intruder_shape (*id).second;
if (polygons.find (ti) == polygons.end ()) {
for (auto i = interactions.begin (); i != interactions.end (); ++i) {
// we can't directly insert because TS may be != TI
const TS &ts = interactions.subject_shape (i->first);
insert_into_hash (subjects, ts);
if (! take_all) {
poly_check.enter (ti, n, common_box);
poly_check.enter (ts, n, common_box);
} else {
poly_check.enter (ti, n);
poly_check.enter (ts, n);
}
n += 2;
}
n = 1;
for (auto id = ids.begin (); id != ids.end (); ++id) {
const TI &ti = interactions.intruder_shape (*id).second;
if (subjects.find (ti) == subjects.end ()) {
if (! take_all) {
poly_check.enter (ti, n, common_box);
} else {
poly_check.enter (ti, n);
}
}
}
} else if (ids.empty ()) {
// merge needed for the subject shapes - no intruders present so this is the simple case
size_t n = 0;
ep.clear ();
size_t nn = 0;
for (auto i = interactions.begin (); i != interactions.end (); ++i) {
const TS &ts = interactions.subject_shape (i->first);
for (auto e = ts.begin_edge (); ! e.at_end (); ++e) {
ep.insert (*e, nn);
}
++nn;
}
// @@@ Use edges directly
spolygons.clear ();
db::polygon_ref_generator<TS> ps (layout, spolygons);
db::PolygonGenerator pg (ps, false /*don't resolve holes*/, false);
db::SimpleMerge op (1 /*wc>0*/);
ep.process (pg, op);
for (auto o = spolygons.begin (); o != spolygons.end (); ++o) {
if (! take_all) {
poly_check.enter (*o, n, common_box);
} else {
poly_check.enter (*o, n);
}
n += 2;
}
} else {
// merge needed for the subject and intruder shapes - we merge both and then
// separate edges into those from the subject and those from intruder shapes.
ep.clear ();
size_t nn = 0;
for (auto i = interactions.begin (); i != interactions.end (); ++i) {
const TS &ts = interactions.subject_shape (i->first);
for (auto e = ts.begin_edge (); ! e.at_end (); ++e) {
ep.insert (*e, nn);
}
++nn;
}
for (auto id = ids.begin (); id != ids.end (); ++id) {
const TI &ti = interactions.intruder_shape (*id).second;
for (auto e = ti.begin_edge (); ! e.at_end (); ++e) {
ep.insert (*e, nn);
}
++nn;
}
std::vector<typename TS::edge_type> edges;
db::EdgeContainer ee (edges);
db::SimpleMerge op (1 /*wc>0*/);
ep.process (ee, op);
ep.clear ();
std::vector<typename TS::edge_type> subject_edges;
size_t sz = 0;
for (auto i = interactions.begin (); i != interactions.end (); ++i) {
const TS &ts = interactions.subject_shape (i->first);
sz += ts.vertices ();
}
subject_edges.reserve (sz);
for (auto i = interactions.begin (); i != interactions.end (); ++i) {
const TS &ts = interactions.subject_shape (i->first);
for (auto e = ts.begin_edge (); ! e.at_end (); ++e) {
subject_edges.push_back (*e);
}
}
for (size_t n = 0; n <= 1; ++n) {
std::set<typename TI::edge_type> partial_edges;
EdgeBooleanClusterCollector<std::set<typename TI::edge_type> > cluster_collector (&partial_edges, n == 0 ? db::EdgeAnd : db::EdgeNot);
db::box_scanner<typename TI::edge_type, size_t> scanner;
scanner.reserve (edges.size () + subject_edges.size ());
for (auto i = edges.begin (); i != edges.end (); ++i) {
if (! i->is_degenerate ()) {
scanner.insert (i.operator-> (), 0);
}
}
for (auto i = subject_edges.begin (); i != subject_edges.end (); ++i) {
if (! i->is_degenerate ()) {
scanner.insert (i.operator-> (), 1);
}
}
scanner.process (cluster_collector, 1, db::box_convert<typename TI::edge_type> ());
for (auto e = partial_edges.begin (); e != partial_edges.end (); ++e) {
if (! take_all) {
poly_check.enter (*e, n, common_box);
} else {
poly_check.enter (*e, n);
}
}
}
}
}

View File

@ -197,6 +197,19 @@ struct DB_PUBLIC RegionCheckOptions
* @brief Specifies whether to produce negative output
*/
bool negative;
/**
* @brief Gets a value indicating whether merged primary input is required
*/
bool needs_merged () const
{
return negative
|| rect_filter != NoRectFilter
|| opposite_filter != NoOppositeFilter
|| max_projection != std::numeric_limits<distance_type>::max ()
|| min_projection != 0
|| whole_edges;
}
};
template <class TS, class TI>
@ -204,7 +217,7 @@ class check_local_operation
: public local_operation<TS, TI, db::EdgePair>
{
public:
check_local_operation (const EdgeRelationFilter &check, bool different_polygons, bool has_other, bool other_is_merged, const db::RegionCheckOptions &options);
check_local_operation (const EdgeRelationFilter &check, bool different_polygons, bool is_merged, bool has_other, bool other_is_merged, const db::RegionCheckOptions &options);
virtual db::Coord dist () const;
virtual OnEmptyIntruderHint on_empty_intruder_hint () const;
@ -216,6 +229,7 @@ public:
private:
EdgeRelationFilter m_check;
bool m_different_polygons;
bool m_is_merged;
bool m_has_other;
bool m_other_is_merged;
db::RegionCheckOptions m_options;

View File

@ -390,7 +390,7 @@ static db::CompoundRegionOperationNode *new_edge_pair_to_second_edges (db::Compo
static db::CompoundRegionOperationNode *new_check_node (db::CompoundRegionOperationNode *other, db::edge_relation_type rel, bool different_polygons, db::Coord d, bool whole_edges, db::metrics_type metrics, const tl::Variant &ignore_angle, const tl::Variant &min_projection, const tl::Variant &max_projection, bool shielded, db::OppositeFilter opposite_filter, db::RectFilter rect_filter, bool negative)
{
check_non_null (other, "other");
return new db::CompoundRegionCheckOperationNode (new_primary (), other, rel, different_polygons, d,
return new db::CompoundRegionCheckOperationNode (0, other, rel, different_polygons, d,
db::RegionCheckOptions (whole_edges,
metrics,
ignore_angle.is_nil () ? 90 : ignore_angle.to_double (),