First implementation of pull* methods

This commit is contained in:
Matthias Koefferlein 2019-10-01 22:06:16 +02:00
parent 1c16cea421
commit 74880a5198
11 changed files with 457 additions and 25 deletions

View File

@ -27,6 +27,7 @@
#include "dbFlatEdges.h"
#include "dbEmptyRegion.h"
#include "dbEmptyEdgePairs.h"
#include "dbEmptyEdges.h"
#include "dbRegion.h"
#include "dbRegionUtils.h"
#include "dbShapeProcessor.h"
@ -337,7 +338,7 @@ AsIfFlatRegion::selected_interacting_generic (const Edges &other, bool inverse)
scanner.reserve2 (other.size ());
std::auto_ptr<FlatRegion> output (new FlatRegion (false));
region_to_edge_interaction_filter<Shapes> filter (output->raw_polygons (), inverse);
region_to_edge_interaction_filter<Shapes, db::Polygon> filter (output->raw_polygons (), inverse);
AddressablePolygonDelivery p (begin_merged (), has_valid_merged_polygons ());
@ -423,6 +424,92 @@ AsIfFlatRegion::selected_interacting_generic (const Region &other, int mode, boo
return output.release ();
}
EdgesDelegate *
AsIfFlatRegion::pull_generic (const Edges &other) const
{
if (other.empty ()) {
return other.delegate ()->clone ();
} else if (empty ()) {
return new EmptyEdges ();
}
db::box_scanner2<db::Polygon, size_t, db::Edge, size_t> scanner (report_progress (), progress_desc ());
scanner.reserve1 (size ());
scanner.reserve2 (other.size ());
std::auto_ptr<FlatEdges> output (new FlatEdges (false));
region_to_edge_interaction_filter<Shapes, db::Edge> filter (output->raw_edges (), false);
AddressablePolygonDelivery p (begin_merged (), has_valid_merged_polygons ());
for ( ; ! p.at_end (); ++p) {
scanner.insert1 (p.operator-> (), 0);
}
AddressableEdgeDelivery e (other.addressable_edges ());
for ( ; ! e.at_end (); ++e) {
scanner.insert2 (e.operator-> (), 0);
}
scanner.process (filter, 1, db::box_convert<db::Polygon> (), db::box_convert<db::Edge> ());
return output.release ();
}
RegionDelegate *
AsIfFlatRegion::pull_generic (const Region &other, int mode, bool touching) const
{
db::EdgeProcessor ep (report_progress (), progress_desc ());
ep.set_base_verbosity (base_verbosity ());
// shortcut
if (empty ()) {
return clone ();
} else if (other.empty ()) {
return new EmptyRegion ();
}
size_t n = 1;
for (RegionIterator p = other.begin (); ! p.at_end (); ++p, ++n) {
if (p->box ().touches (bbox ())) {
ep.insert (*p, n);
}
}
for (RegionIterator p (begin_merged ()); ! p.at_end (); ++p) {
if (mode > 0 || p->box ().touches (other.bbox ())) {
ep.insert (*p, 0);
}
}
db::InteractionDetector id (mode, 0);
id.set_include_touching (touching);
db::EdgeSink es;
ep.process (es, id);
id.finish ();
std::auto_ptr<FlatRegion> output (new FlatRegion (false));
n = 0;
std::set <size_t> selected;
for (db::InteractionDetector::iterator i = id.begin (); i != id.end () && i->first == 0; ++i) {
++n;
selected.insert (i->second);
}
output->reserve (n);
n = 1;
for (RegionIterator p = other.begin (); ! p.at_end (); ++p, ++n) {
if (selected.find (n) != selected.end ()) {
output->raw_polygons ().insert (*p);
}
}
return output.release ();
}
template <class Trans>
void
AsIfFlatRegion::produce_markers_for_grid_check (const db::Polygon &poly, const Trans &tr, db::Coord gx, db::Coord gy, db::Shapes &shapes)

View File

@ -205,6 +205,26 @@ public:
return selected_interacting_generic (other, 0, false, true);
}
virtual RegionDelegate *pull_inside (const Region &other) const
{
return pull_generic (other, -1, true);
}
virtual RegionDelegate *pull_interacting (const Region &other) const
{
return pull_generic (other, 0, true);
}
virtual EdgesDelegate *pull_interacting (const Edges &other) const
{
return pull_generic (other);
}
virtual RegionDelegate *pull_overlapping (const Region &other) const
{
return pull_generic (other, 0, false);
}
virtual RegionDelegate *in (const Region &other, bool invert) const;
virtual bool equals (const Region &other) const;
@ -220,6 +240,8 @@ protected:
EdgePairsDelegate *run_single_polygon_check (db::edge_relation_type rel, db::Coord d, bool whole_edges, metrics_type metrics, double ignore_angle, distance_type min_projection, distance_type max_projection) const;
RegionDelegate *selected_interacting_generic (const Region &other, int mode, bool touching, bool inverse) const;
RegionDelegate *selected_interacting_generic (const Edges &other, bool inverse) const;
RegionDelegate *pull_generic (const Region &other, int mode, bool touching) const;
EdgesDelegate *pull_generic (const Edges &other) const;
template <class Trans>
static void produce_markers_for_grid_check (const db::Polygon &poly, const Trans &tr, db::Coord gx, db::Coord gy, db::Shapes &shapes);

View File

@ -1617,8 +1617,82 @@ private:
mutable db::EdgeProcessor m_ep;
};
class PullLocalOperation
: public local_operation<db::PolygonRef, db::PolygonRef, db::PolygonRef>
{
public:
PullLocalOperation (int mode, bool touching)
: m_mode (mode), m_touching (touching)
{
// .. nothing yet ..
}
virtual void compute_local (db::Layout * /*layout*/, const shape_interactions<db::PolygonRef, db::PolygonRef> &interactions, std::unordered_set<db::PolygonRef> &result, size_t /*max_vertex_count*/, double /*area_ratio*/) const
{
m_ep.clear ();
std::set<db::PolygonRef> others;
for (shape_interactions<db::PolygonRef, db::PolygonRef>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
for (shape_interactions<db::PolygonRef, db::PolygonRef>::iterator2 j = i->second.begin (); j != i->second.end (); ++j) {
others.insert (interactions.intruder_shape (*j));
}
}
for (shape_interactions<db::PolygonRef, db::PolygonRef>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
const db::PolygonRef &subject = interactions.subject_shape (i->first);
for (db::PolygonRef::polygon_edge_iterator e = subject.begin_edge (); ! e.at_end(); ++e) {
m_ep.insert (*e, 0);
}
}
size_t n = 1;
for (std::set<db::PolygonRef>::const_iterator o = others.begin (); o != others.end (); ++o, ++n) {
for (db::PolygonRef::polygon_edge_iterator e = o->begin_edge (); ! e.at_end(); ++e) {
m_ep.insert (*e, n);
}
}
db::InteractionDetector id (m_mode, 0);
id.set_include_touching (m_touching);
db::EdgeSink es;
m_ep.process (es, id);
id.finish ();
n = 0;
std::set <size_t> selected;
for (db::InteractionDetector::iterator i = id.begin (); i != id.end () && i->first == 0; ++i) {
++n;
selected.insert (i->second);
}
n = 1;
for (std::set<db::PolygonRef>::const_iterator o = others.begin (); o != others.end (); ++o, ++n) {
if (selected.find (n) != selected.end ()) {
result.insert (*o);
}
}
}
virtual on_empty_intruder_mode on_empty_intruder_hint () const
{
return Drop;
}
virtual std::string description () const
{
return tl::to_string (tr ("Pull regions by their geometric relation to first (interacting, inside)"));
}
private:
int m_mode;
bool m_touching;
mutable db::EdgeProcessor m_ep;
};
struct ResultInserter
{
typedef db::Polygon value_type;
ResultInserter (db::Layout *layout, std::unordered_set<db::PolygonRef> &result)
: mp_layout (layout), mp_result (&result)
{
@ -1635,6 +1709,25 @@ private:
std::unordered_set<db::PolygonRef> *mp_result;
};
struct EdgeResultInserter
{
typedef db::Edge value_type;
EdgeResultInserter (std::unordered_set<db::Edge> &result)
: mp_result (&result)
{
// .. nothing yet ..
}
void insert (const db::Edge &e)
{
(*mp_result).insert (e);
}
private:
std::unordered_set<db::Edge> *mp_result;
};
class InteractingWithEdgeLocalOperation
: public local_operation<db::PolygonRef, db::Edge, db::PolygonRef>
{
@ -1652,7 +1745,7 @@ public:
ResultInserter inserter (layout, result);
region_to_edge_interaction_filter<ResultInserter> filter (inserter, m_inverse);
for (shape_interactions<db::PolygonRef, db::PolygonRef>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
for (shape_interactions<db::PolygonRef, db::Edge>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
for (shape_interactions<db::PolygonRef, db::Edge>::iterator2 j = i->second.begin (); j != i->second.end (); ++j) {
m_scanner.insert2 (& interactions.intruder_shape (*j), 0);
}
@ -1688,7 +1781,7 @@ public:
virtual std::string description () const
{
return tl::to_string (tr ("Select regions by their geometric relation (interacting, inside, outside ..)"));
return tl::to_string (tr ("Select regions by their geometric relation to edges"));
}
private:
@ -1696,6 +1789,55 @@ private:
mutable db::box_scanner2<db::Polygon, size_t, db::Edge, size_t> m_scanner;
};
class PullWithEdgeLocalOperation
: public local_operation<db::PolygonRef, db::Edge, db::Edge>
{
public:
PullWithEdgeLocalOperation ()
{
// .. nothing yet ..
}
virtual void compute_local (db::Layout *, const shape_interactions<db::PolygonRef, db::Edge> &interactions, std::unordered_set<db::Edge> &result, size_t /*max_vertex_count*/, double /*area_ratio*/) const
{
m_scanner.clear ();
EdgeResultInserter inserter (result);
region_to_edge_interaction_filter<EdgeResultInserter> filter (inserter, false);
for (shape_interactions<db::PolygonRef, db::Edge>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
for (shape_interactions<db::PolygonRef, db::Edge>::iterator2 j = i->second.begin (); j != i->second.end (); ++j) {
m_scanner.insert2 (& interactions.intruder_shape (*j), 0);
}
}
std::list<db::Polygon> heap;
for (shape_interactions<db::PolygonRef, db::PolygonRef>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
const db::PolygonRef &subject = interactions.subject_shape (i->first);
heap.push_back (subject.obj ().transformed (subject.trans ()));
m_scanner.insert1 (&heap.back (), 0);
}
m_scanner.process (filter, 1, db::box_convert<db::Polygon> (), db::box_convert<db::Edge> ());
}
virtual on_empty_intruder_mode on_empty_intruder_hint () const
{
return Drop;
}
virtual std::string description () const
{
return tl::to_string (tr ("Select edges from second by their geometric relation to first"));
}
private:
mutable db::box_scanner2<db::Polygon, size_t, db::Edge, size_t> m_scanner;
};
}
RegionDelegate *
@ -1766,4 +1908,60 @@ DeepRegion::selected_interacting_generic (const Edges &other, bool inverse) cons
return res;
}
RegionDelegate *
DeepRegion::pull_generic (const Region &other, int mode, bool touching) const
{
// with these flag set to true, the resulting polygons are broken again.
bool split_after = false;
const db::DeepRegion *other_deep = dynamic_cast<const db::DeepRegion *> (other.delegate ());
if (! other_deep) {
return db::AsIfFlatRegion::pull_generic (other, mode, touching);
}
ensure_merged_polygons_valid ();
DeepLayer dl_out (m_deep_layer.derived ());
db::PullLocalOperation op (mode, touching);
db::local_processor<db::PolygonRef, db::PolygonRef, db::PolygonRef> proc (const_cast<db::Layout *> (&m_deep_layer.layout ()), const_cast<db::Cell *> (&m_deep_layer.initial_cell ()), &other_deep->deep_layer ().layout (), &other_deep->deep_layer ().initial_cell ());
proc.set_base_verbosity (base_verbosity ());
proc.set_threads (m_deep_layer.store ()->threads ());
if (split_after) {
proc.set_area_ratio (m_deep_layer.store ()->max_area_ratio ());
proc.set_max_vertex_count (m_deep_layer.store ()->max_vertex_count ());
}
proc.run (&op, m_merged_polygons.layer (), other_deep->deep_layer ().layer (), dl_out.layer ());
db::DeepRegion *res = new db::DeepRegion (dl_out);
if (! split_after) {
res->set_is_merged (true);
}
return res;
}
EdgesDelegate *
DeepRegion::pull_generic (const Edges &other) const
{
const db::DeepEdges *other_deep = dynamic_cast<const db::DeepEdges *> (other.delegate ());
if (! other_deep) {
return db::AsIfFlatRegion::pull_generic (other);
}
ensure_merged_polygons_valid ();
DeepLayer dl_out (m_deep_layer.derived ());
db::PullWithEdgeLocalOperation op;
db::local_processor<db::PolygonRef, db::Edge, db::Edge> proc (const_cast<db::Layout *> (&m_deep_layer.layout ()), const_cast<db::Cell *> (&m_deep_layer.initial_cell ()), &other_deep->deep_layer ().layout (), &other_deep->deep_layer ().initial_cell ());
proc.set_base_verbosity (base_verbosity ());
proc.set_threads (m_deep_layer.store ()->threads ());
proc.run (&op, m_merged_polygons.layer (), other_deep->deep_layer ().layer (), dl_out.layer ());
return new db::DeepEdges (dl_out);
}
}

View File

@ -240,6 +240,8 @@ private:
EdgePairsDelegate *run_single_polygon_check (db::edge_relation_type rel, db::Coord d, bool whole_edges, metrics_type metrics, double ignore_angle, distance_type min_projection, distance_type max_projection) const;
RegionDelegate *selected_interacting_generic (const Region &other, int mode, bool touching, bool inverse) const;
RegionDelegate *selected_interacting_generic (const Edges &other, bool inverse) const;
RegionDelegate *pull_generic (const Region &other, int mode, bool touching) const;
EdgesDelegate *pull_generic (const Edges &other) const;
const DeepLayer &merged_deep_layer () const
{

View File

@ -26,6 +26,7 @@
#include "dbCommon.h"
#include "dbRegionDelegate.h"
#include "dbEmptyEdges.h"
namespace db {
@ -106,6 +107,10 @@ public:
virtual RegionDelegate *selected_not_interacting (const Edges &) const { return new EmptyRegion (); }
virtual RegionDelegate *selected_overlapping (const Region &) const { return new EmptyRegion (); }
virtual RegionDelegate *selected_not_overlapping (const Region &) const { return new EmptyRegion (); }
virtual RegionDelegate *pull_inside (const Region &) const { return new EmptyRegion (); }
virtual RegionDelegate *pull_interacting (const Region &) const { return new EmptyRegion (); }
virtual EdgesDelegate *pull_interacting (const Edges &) const { return new EmptyEdges (); }
virtual RegionDelegate *pull_overlapping (const Region &) const { return new EmptyRegion (); }
virtual RegionDelegate *in (const Region &, bool) const { return new EmptyRegion (); }
virtual bool has_valid_polygons () const { return true; }

View File

@ -178,6 +178,8 @@ public:
}
}
db::Shapes &raw_edges () { return m_edges; }
protected:
virtual void merged_semantics_changed ();
virtual Box compute_bbox () const;
@ -187,8 +189,6 @@ protected:
private:
friend class AsIfFlatEdges;
db::Shapes &raw_edges () { return m_edges; }
FlatEdges &operator= (const FlatEdges &other);
bool m_is_merged;

View File

@ -1355,6 +1355,46 @@ public:
return Region (mp_delegate->selected_not_overlapping (other));
}
/**
* @brief Returns all polygons of "other" which are inside polygons of this region
*
* Merged semantics applies.
*/
Region pull_inside (const Region &other) const
{
return Region (mp_delegate->pull_inside (other));
}
/**
* @brief Returns all edges of "other" which are interacting (touching or overlapping with) polygons of this region
*
* Merged semantics applies.
*/
Edges pull_interacting (const Edges &other) const
{
return Edges (mp_delegate->pull_interacting (other));
}
/**
* @brief Returns all polygons of "other" which are interacting (touching or overlapping with) polygons of this region
*
* Merged semantics applies.
*/
Region pull_interacting (const Region &other) const
{
return Region (mp_delegate->pull_interacting (other));
}
/**
* @brief Returns all polygons of "other" which are overlapping with polygons of this region
*
* Merged semantics applies.
*/
Region pull_overlapping (const Region &other) const
{
return Region (mp_delegate->pull_overlapping (other));
}
/**
* @brief Returns the holes
*

View File

@ -294,6 +294,10 @@ public:
virtual RegionDelegate *selected_not_interacting (const Edges &other) const = 0;
virtual RegionDelegate *selected_overlapping (const Region &other) const = 0;
virtual RegionDelegate *selected_not_overlapping (const Region &other) const = 0;
virtual RegionDelegate *pull_inside (const Region &other) const = 0;
virtual RegionDelegate *pull_interacting (const Region &other) const = 0;
virtual EdgesDelegate *pull_interacting (const Edges &other) const = 0;
virtual RegionDelegate *pull_overlapping (const Region &other) const = 0;
virtual RegionDelegate *in (const Region &other, bool invert) const = 0;
virtual const db::Polygon *nth (size_t n) const = 0;

View File

@ -288,22 +288,47 @@ Poly2PolyCheckBase::enter (const db::Polygon &o1, size_t p1, const db::Polygon &
// -------------------------------------------------------------------------------------
// RegionToEdgeInteractionFilterBase implementation
RegionToEdgeInteractionFilterBase::RegionToEdgeInteractionFilterBase (bool inverse)
namespace
{
template <class OutputType>
struct edge_or_polygon;
template <>
struct edge_or_polygon<db::Polygon>
{
const db::Polygon *operator() (const db::Polygon *p, const db::Edge *) const { return p; }
};
template <>
struct edge_or_polygon<db::Edge>
{
const db::Edge *operator() (const db::Polygon *, const db::Edge *e) const { return e; }
};
}
template <class OutputType>
region_to_edge_interaction_filter_base<OutputType>::region_to_edge_interaction_filter_base (bool inverse)
: m_inverse (inverse)
{
// .. nothing yet ..
}
template <class OutputType>
void
RegionToEdgeInteractionFilterBase::preset (const db::Polygon *poly)
region_to_edge_interaction_filter_base<OutputType>::preset (const OutputType *s)
{
m_seen.insert (poly);
m_seen.insert (s);
}
template <class OutputType>
void
RegionToEdgeInteractionFilterBase::add (const db::Polygon *p, size_t, const db::Edge *e, size_t)
region_to_edge_interaction_filter_base<OutputType>::add (const db::Polygon *p, size_t, const db::Edge *e, size_t)
{
if ((m_seen.find (p) == m_seen.end ()) != m_inverse) {
const OutputType *o = edge_or_polygon<OutputType> () (p, e);
if ((m_seen.find (o) == m_seen.end ()) != m_inverse) {
// A polygon and an edge interact if the edge is either inside completely
// of at least one edge of the polygon intersects with the edge
@ -320,23 +345,28 @@ RegionToEdgeInteractionFilterBase::add (const db::Polygon *p, size_t, const db::
if (interacts) {
if (m_inverse) {
m_seen.erase (p);
m_seen.erase (o);
} else {
m_seen.insert (p);
put (*p);
m_seen.insert (o);
put (*o);
}
}
}
}
template <class OutputType>
void
RegionToEdgeInteractionFilterBase::fill_output ()
region_to_edge_interaction_filter_base<OutputType>::fill_output ()
{
for (std::set<const db::Polygon *>::const_iterator p = m_seen.begin (); p != m_seen.end (); ++p) {
put (**p);
for (typename std::set<const OutputType *>::const_iterator s = m_seen.begin (); s != m_seen.end (); ++s) {
put (**s);
}
}
// explicit instantiations
template class region_to_edge_interaction_filter_base<db::Polygon>;
template class region_to_edge_interaction_filter_base<db::Edge>;
}

View File

@ -481,40 +481,41 @@ public:
/**
* @brief A helper class for the region to edge interaction functionality
*/
class DB_PUBLIC RegionToEdgeInteractionFilterBase
template <class OutputType>
class DB_PUBLIC region_to_edge_interaction_filter_base
: public db::box_scanner_receiver2<db::Polygon, size_t, db::Edge, size_t>
{
public:
RegionToEdgeInteractionFilterBase (bool inverse);
region_to_edge_interaction_filter_base (bool inverse);
void preset (const db::Polygon *poly);
void preset (const OutputType *s);
void add (const db::Polygon *p, size_t, const db::Edge *e, size_t);
void fill_output ();
protected:
virtual void put (const db::Polygon &poly) const = 0;
virtual void put (const OutputType &s) const = 0;
private:
std::set<const db::Polygon *> m_seen;
std::set<const OutputType *> m_seen;
bool m_inverse;
};
/**
* @brief A helper class for the region to edge interaction functionality
*/
template <class OutputContainer>
template <class OutputContainer, class OutputType = typename OutputContainer::value_type>
class DB_PUBLIC_TEMPLATE region_to_edge_interaction_filter
: public RegionToEdgeInteractionFilterBase
: public region_to_edge_interaction_filter_base<OutputType>
{
public:
region_to_edge_interaction_filter (OutputContainer &output, bool inverse)
: RegionToEdgeInteractionFilterBase (inverse), mp_output (&output)
: region_to_edge_interaction_filter_base<OutputType> (inverse), mp_output (&output)
{
// .. nothing yet ..
}
protected:
virtual void put (const db::Polygon &poly) const
virtual void put (const OutputType &poly) const
{
mp_output->insert (poly);
}

View File

@ -1600,6 +1600,49 @@ Class<db::Region> decl_Region ("db", "Region",
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
) +
method ("pull_inside", &db::Region::pull_inside, gsi::arg ("other"),
"@brief Returns all polygons of \"other\" which are inside polygons of this region\n"
"The \"pull_...\" methods are similar to \"selected_...\" but work the opposite way: they "
"select shapes from the argument region rather than self. In a deep (hierarchical) context "
"the output region will be hierarchically aligned with self, so the \"pull_...\" methods "
"provide a way for rehierarchisation.\n"
"\n"
"@return The region after the polygons have been selected (from other)\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"\n"
"This method has been introduced in version 0.26.1\n"
) +
method ("pull_overlapping", &db::Region::pull_overlapping, gsi::arg ("other"),
"@brief Returns all polygons of \"other\" which are overlapping polygons of this region\n"
"See \\pull_inside for a description of the \"pull_...\" methods.\n"
"\n"
"@return The region after the polygons have been selected (from other)\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"\n"
"This method has been introduced in version 0.26.1\n"
) +
method ("pull_interacting", static_cast<db::Region (db::Region::*) (const db::Region &) const> (&db::Region::pull_interacting), gsi::arg ("other"),
"@brief Returns all polygons of \"other\" which are interacting with (overlapping, touching) polygons of this region\n"
"See \\pull_inside for a description of the \"pull_...\" methods.\n"
"\n"
"@return The region after the polygons have been selected (from other)\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"\n"
"This method has been introduced in version 0.26.1\n"
) +
method ("pull_interacting", static_cast<db::Edges (db::Region::*) (const db::Edges &) const> (&db::Region::pull_interacting), gsi::arg ("other"),
"@brief Returns all edges of \"other\" which are interacting with polygons of this region\n"
"See \\pull_inside for a description of the \"pull_...\" methods.\n"
"\n"
"@return The edge collection after the edges have been selected (from other)\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"\n"
"This method has been introduced in version 0.26.1\n"
) +
method ("is_box?", &db::Region::is_box,
"@brief Returns true, if the region is a simple box\n"
"\n"