Edge/edge and edge/polygon interaction test ported to hierarchical mode.

This commit is contained in:
Matthias Koefferlein 2019-02-17 18:36:15 +01:00
parent 7ef0451ca8
commit c40f147dc7
6 changed files with 379 additions and 202 deletions

View File

@ -195,149 +195,62 @@ AsIfFlatEdges::to_string (size_t nmax) const
return os.str ();
}
namespace
{
/**
* @brief A helper class for the edge to region interaction functionality which acts as an edge pair receiver
*
* Note: This special scanner uses pointers to two different objects: edges and polygons.
* It uses odd value pointers to indicate pointers to polygons and even value pointers to indicate
* pointers to edges.
*
* There is a special box converter which is able to sort that out as well.
*/
template <class OutputContainer>
class edge_to_region_interaction_filter
: public db::box_scanner_receiver<char, size_t>
{
public:
edge_to_region_interaction_filter (OutputContainer &output)
: mp_output (&output)
{
// .. nothing yet ..
}
void add (const char *o1, size_t p1, const char *o2, size_t p2)
{
const db::Edge *e = 0;
const db::Polygon *p = 0;
// Note: edges have property 0 and have even-valued pointers.
// Polygons have property 1 and odd-valued pointers.
if (p1 == 0 && p2 == 1) {
e = reinterpret_cast<const db::Edge *> (o1);
p = reinterpret_cast<const db::Polygon *> (o2 - 1);
} else if (p1 == 1 && p2 == 0) {
e = reinterpret_cast<const db::Edge *> (o2);
p = reinterpret_cast<const db::Polygon *> (o1 - 1);
}
if (e && p && m_seen.find (e) == m_seen.end ()) {
if (db::interact (*p, *e)) {
m_seen.insert (e);
mp_output->insert (*e);
}
}
}
private:
OutputContainer *mp_output;
std::set<const db::Edge *> m_seen;
};
/**
* @brief A special box converter that splits the pointers into polygon and edge pointers
*/
struct EdgeOrRegionBoxConverter
{
typedef db::Box box_type;
db::Box operator() (const char &c) const
{
// Note: edges have property 0 and have even-valued pointers.
// Polygons have property 1 and odd-valued pointers.
const char *cp = &c;
if ((size_t (cp) & 1) == 1) {
// it's a polygon
return (reinterpret_cast<const db::Polygon *> (cp - 1))->box ();
} else {
// it's an edge
const db::Edge *e = reinterpret_cast<const db::Edge *> (cp);
return db::Box (e->p1 (), e->p2 ());
}
}
};
}
EdgesDelegate *
AsIfFlatEdges::selected_interacting (const Region &other) const
AsIfFlatEdges::selected_interacting_generic (const Region &other, bool inverse) const
{
// shortcuts
if (other.empty () || empty ()) {
return new EmptyEdges ();
}
db::box_scanner<char, size_t> scanner (report_progress (), progress_desc ());
scanner.reserve (size () + other.size ());
db::box_scanner2<db::Edge, size_t, db::Polygon, size_t> scanner (report_progress (), progress_desc ());
AddressableEdgeDelivery e (begin_merged (), has_valid_merged_edges ());
for ( ; ! e.at_end (); ++e) {
scanner.insert ((char *) e.operator-> (), 0);
scanner.insert1 (e.operator-> (), 0);
}
AddressablePolygonDelivery p = other.addressable_polygons ();
for ( ; ! p.at_end (); ++p) {
scanner.insert ((char *) p.operator-> () + 1, 1);
scanner.insert2 (p.operator-> (), 1);
}
std::auto_ptr<FlatEdges> output (new FlatEdges (true));
edge_to_region_interaction_filter<FlatEdges> filter (*output);
EdgeOrRegionBoxConverter bc;
scanner.process (filter, 1, bc);
if (! inverse) {
edge_to_region_interaction_filter<FlatEdges> filter (*output);
scanner.process (filter, 1, db::box_convert<db::Edge> (), db::box_convert<db::Polygon> ());
} else {
std::set<db::Edge> interacting;
edge_to_region_interaction_filter<std::set<db::Edge> > filter (interacting);
scanner.process (filter, 1, db::box_convert<db::Edge> (), db::box_convert<db::Polygon> ());
for (EdgesIterator o (begin_merged ()); ! o.at_end (); ++o) {
if (interacting.find (*o) == interacting.end ()) {
output->insert (*o);
}
}
}
return output.release ();
}
EdgesDelegate *
AsIfFlatEdges::selected_interacting (const Region &other) const
{
return selected_interacting_generic (other, false);
}
EdgesDelegate *
AsIfFlatEdges::selected_not_interacting (const Region &other) const
{
// shortcuts
if (other.empty () || empty ()) {
return clone ();
}
db::box_scanner<char, size_t> scanner (report_progress (), progress_desc ());
scanner.reserve (size () + other.size ());
AddressableEdgeDelivery e (begin_merged (), has_valid_merged_edges ());
for ( ; ! e.at_end (); ++e) {
scanner.insert ((char *) e.operator-> (), 0);
}
AddressablePolygonDelivery p = other.addressable_polygons ();
for ( ; ! p.at_end (); ++p) {
scanner.insert ((char *) p.operator-> () + 1, 1);
}
std::set<db::Edge> interacting;
edge_to_region_interaction_filter<std::set<db::Edge> > filter (interacting);
EdgeOrRegionBoxConverter bc;
scanner.process (filter, 1, bc);
std::auto_ptr<FlatEdges> output (new FlatEdges (true));
for (EdgesIterator o (begin_merged ()); ! o.at_end (); ++o) {
if (interacting.find (*o) == interacting.end ()) {
output->insert (*o);
}
}
return output.release ();
return selected_interacting_generic (other, true);
}
namespace
@ -483,99 +396,57 @@ AsIfFlatEdges::centers (length_type length, double fraction) const
return segments (0, length, fraction);
}
namespace
EdgesDelegate *
AsIfFlatEdges::selected_interacting_generic (const Edges &edges, bool inverse) const
{
db::box_scanner<db::Edge, size_t> scanner (report_progress (), progress_desc ());
/**
* @brief A helper class for the edge interaction functionality which acts as an edge pair receiver
*/
template <class OutputContainer>
class edge_interaction_filter
: public db::box_scanner_receiver<db::Edge, size_t>
{
public:
edge_interaction_filter (OutputContainer &output)
: mp_output (&output)
{
// .. nothing yet ..
AddressableEdgeDelivery e (begin_merged (), has_valid_merged_edges ());
for ( ; ! e.at_end (); ++e) {
scanner.insert (e.operator-> (), 0);
}
void add (const db::Edge *o1, size_t p1, const db::Edge *o2, size_t p2)
{
// Select the edges which intersect
if (p1 != p2) {
const db::Edge *o = p1 > p2 ? o2 : o1;
const db::Edge *oo = p1 > p2 ? o1 : o2;
if (o->intersect (*oo)) {
if (m_seen.insert (o).second) {
mp_output->insert (*o);
}
AddressableEdgeDelivery ee = edges.addressable_edges ();
for ( ; ! ee.at_end (); ++ee) {
scanner.insert (ee.operator-> (), 1);
}
std::auto_ptr<FlatEdges> output (new FlatEdges (true));
if (! inverse) {
edge_interaction_filter<FlatEdges> filter (*output);
scanner.process (filter, 1, db::box_convert<db::Edge> ());
} else {
std::set<db::Edge> interacting;
edge_interaction_filter<std::set<db::Edge> > filter (interacting);
scanner.process (filter, 1, db::box_convert<db::Edge> ());
for (EdgesIterator o (begin_merged ()); ! o.at_end (); ++o) {
if (interacting.find (*o) == interacting.end ()) {
output->insert (*o);
}
}
}
private:
OutputContainer *mp_output;
std::set<const db::Edge *> m_seen;
};
return output.release ();
}
EdgesDelegate *
AsIfFlatEdges::selected_interacting (const Edges &other) const
{
db::box_scanner<db::Edge, size_t> scanner (report_progress (), progress_desc ());
scanner.reserve (size () + other.size ());
AddressableEdgeDelivery e (begin_merged (), has_valid_merged_edges ());
for ( ; ! e.at_end (); ++e) {
scanner.insert (e.operator-> (), 0);
}
AddressableEdgeDelivery ee = other.addressable_edges ();
for ( ; ! ee.at_end (); ++ee) {
scanner.insert (ee.operator-> (), 1);
}
std::auto_ptr<FlatEdges> output (new FlatEdges (true));
edge_interaction_filter<FlatEdges> filter (*output);
scanner.process (filter, 1, db::box_convert<db::Edge> ());
return output.release ();
return selected_interacting_generic (other, false);
}
EdgesDelegate *
AsIfFlatEdges::selected_not_interacting (const Edges &other) const
{
db::box_scanner<db::Edge, size_t> scanner (report_progress (), progress_desc ());
scanner.reserve (size () + other.size ());
AddressableEdgeDelivery e (begin_merged (), has_valid_merged_edges ());
for ( ; ! e.at_end (); ++e) {
scanner.insert (e.operator-> (), 0);
}
AddressableEdgeDelivery ee = other.addressable_edges ();
for ( ; ! ee.at_end (); ++ee) {
scanner.insert (ee.operator-> (), 1);
}
std::set<db::Edge> interacting;
edge_interaction_filter<std::set<db::Edge> > filter (interacting);
scanner.process (filter, 1, db::box_convert<db::Edge> ());
std::auto_ptr<FlatEdges> output (new FlatEdges (true));
for (EdgesIterator o (begin_merged ()); ! o.at_end (); ++o) {
if (interacting.find (*o) == interacting.end ()) {
output->insert (*o);
}
}
return output.release ();
return selected_interacting_generic (other, true);
}
EdgesDelegate *

View File

@ -27,6 +27,8 @@
#include "dbCommon.h"
#include "dbBoxScanner.h"
#include "dbEdgesDelegate.h"
#include "dbBoxScanner.h"
#include "dbPolygonTools.h"
#include <map>
#include <vector>
@ -35,6 +37,74 @@ namespace db {
class PolygonSink;
/**
* @brief A helper class for the edge interaction functionality which acts as an edge pair receiver
*/
template <class OutputContainer>
class edge_interaction_filter
: public db::box_scanner_receiver<db::Edge, size_t>
{
public:
edge_interaction_filter (OutputContainer &output)
: mp_output (&output)
{
// .. nothing yet ..
}
void add (const db::Edge *o1, size_t p1, const db::Edge *o2, size_t p2)
{
// Select the edges which intersect
if (p1 != p2) {
const db::Edge *o = p1 > p2 ? o2 : o1;
const db::Edge *oo = p1 > p2 ? o1 : o2;
if (o->intersect (*oo)) {
if (m_seen.insert (o).second) {
mp_output->insert (*o);
}
}
}
}
private:
OutputContainer *mp_output;
std::set<const db::Edge *> m_seen;
};
/**
* @brief A helper class for the edge to region interaction functionality which acts as an edge pair receiver
*
* Note: This special scanner uses pointers to two different objects: edges and polygons.
* It uses odd value pointers to indicate pointers to polygons and even value pointers to indicate
* pointers to edges.
*
* There is a special box converter which is able to sort that out as well.
*/
template <class OutputContainer>
class edge_to_region_interaction_filter
: public db::box_scanner_receiver2<db::Edge, size_t, db::Polygon, size_t>
{
public:
edge_to_region_interaction_filter (OutputContainer &output)
: mp_output (&output)
{
// .. nothing yet ..
}
void add (const db::Edge *e, size_t, const db::Polygon *p, size_t)
{
if (m_seen.find (e) == m_seen.end ()) {
if (db::interact (*p, *e)) {
m_seen.insert (e);
mp_output->insert (*e);
}
}
}
private:
OutputContainer *mp_output;
std::set<const db::Edge *> m_seen;
};
/**
* @brief A helper class to turn joined edge sequences into polygons
*
@ -186,6 +256,8 @@ protected:
EdgePairs run_check (db::edge_relation_type rel, const Edges *other, db::Coord d, bool whole_edges, metrics_type metrics, double ignore_angle, distance_type min_projection, distance_type max_projection) const;
static db::Polygon extended_edge (const db::Edge &edge, coord_type ext_b, coord_type ext_e, coord_type ext_o, coord_type ext_i);
static db::Edge compute_partial (const db::Edge &edge, int mode, length_type length, double fraction);
virtual EdgesDelegate *selected_interacting_generic (const Edges &edges, bool inverse) const;
virtual EdgesDelegate *selected_interacting_generic (const Region &region, bool inverse) const;
private:
AsIfFlatEdges &operator= (const AsIfFlatEdges &other);

View File

@ -956,33 +956,221 @@ EdgesDelegate *DeepEdges::centers (length_type length, double fraction) const
return segments (0, length, fraction);
}
namespace
{
class Edge2EdgeInteractingLocalOperation
: public local_operation<db::Edge, db::Edge, db::Edge>
{
public:
Edge2EdgeInteractingLocalOperation (bool inverse)
: m_inverse (inverse)
{
// .. nothing yet ..
}
virtual void compute_local (db::Layout * /*layout*/, const shape_interactions<db::Edge, db::Edge> &interactions, std::unordered_set<db::Edge> &result, size_t /*max_vertex_count*/, double /*area_ratio*/) const
{
db::box_scanner<db::Edge, size_t> scanner;
std::set<db::Edge> others;
for (shape_interactions<db::Edge, db::Edge>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
for (shape_interactions<db::Edge, db::Edge>::iterator2 j = i->second.begin (); j != i->second.end (); ++j) {
others.insert (interactions.intruder_shape (*j));
}
}
for (shape_interactions<db::Edge, db::Edge>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
const db::Edge &subject = interactions.subject_shape (i->first);
scanner.insert (&subject, 0);
}
for (std::set<db::Edge>::const_iterator o = others.begin (); o != others.end (); ++o) {
scanner.insert (o.operator-> (), 1);
}
if (m_inverse) {
std::unordered_set<db::Edge> interacting;
edge_interaction_filter<std::unordered_set<db::Edge> > filter (interacting);
scanner.process (filter, 1, db::box_convert<db::Edge> ());
for (shape_interactions<db::Edge, db::Edge>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
const db::Edge &subject = interactions.subject_shape (i->first);
if (interacting.find (subject) == interacting.end ()) {
result.insert (subject);
}
}
} else {
edge_interaction_filter<std::unordered_set<db::Edge> > filter (result);
scanner.process (filter, 1, db::box_convert<db::Edge> ());
}
}
virtual on_empty_intruder_mode on_empty_intruder_hint () const
{
if (m_inverse) {
return Copy;
} else {
return Drop;
}
}
virtual std::string description () const
{
return tl::to_string (tr ("Select interacting edges"));
}
private:
bool m_inverse;
};
class Edge2PolygonInteractingLocalOperation
: public local_operation<db::Edge, db::PolygonRef, db::Edge>
{
public:
Edge2PolygonInteractingLocalOperation (bool inverse)
: m_inverse (inverse)
{
// .. nothing yet ..
}
virtual void compute_local (db::Layout * /*layout*/, const shape_interactions<db::Edge, db::PolygonRef> &interactions, std::unordered_set<db::Edge> &result, size_t /*max_vertex_count*/, double /*area_ratio*/) const
{
db::box_scanner2<db::Edge, size_t, db::Polygon, size_t> scanner;
std::set<db::PolygonRef> others;
for (shape_interactions<db::Edge, db::PolygonRef>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
for (shape_interactions<db::Edge, db::PolygonRef>::iterator2 j = i->second.begin (); j != i->second.end (); ++j) {
others.insert (interactions.intruder_shape (*j));
}
}
for (shape_interactions<db::Edge, db::Edge>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
const db::Edge &subject = interactions.subject_shape (i->first);
scanner.insert1 (&subject, 0);
}
std::list<db::Polygon> heap;
for (std::set<db::PolygonRef>::const_iterator o = others.begin (); o != others.end (); ++o) {
heap.push_back (o->obj ().transformed (o->trans ()));
scanner.insert2 (& heap.back (), 1);
}
if (m_inverse) {
std::unordered_set<db::Edge> interacting;
edge_to_region_interaction_filter<std::unordered_set<db::Edge> > filter (interacting);
scanner.process (filter, 1, db::box_convert<db::Edge> (), db::box_convert<db::Polygon> ());
for (shape_interactions<db::Edge, db::Edge>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
const db::Edge &subject = interactions.subject_shape (i->first);
if (interacting.find (subject) == interacting.end ()) {
result.insert (subject);
}
}
} else {
edge_to_region_interaction_filter<std::unordered_set<db::Edge> > filter (result);
scanner.process (filter, 1, db::box_convert<db::Edge> (), db::box_convert<db::Polygon> ());
}
}
virtual on_empty_intruder_mode on_empty_intruder_hint () const
{
if (m_inverse) {
return Copy;
} else {
return Drop;
}
}
virtual std::string description () const
{
return tl::to_string (tr ("Select interacting edges"));
}
private:
bool m_inverse;
};
}
EdgesDelegate *
DeepEdges::selected_interacting_generic (const Region &other, bool inverse) const
{
const db::DeepRegion *other_deep = dynamic_cast<const db::DeepRegion *> (other.delegate ());
if (! other_deep) {
return db::AsIfFlatEdges::selected_interacting_generic (other, inverse);
}
ensure_merged_edges_valid ();
DeepLayer dl_out (m_deep_layer.derived ());
db::Edge2PolygonInteractingLocalOperation op (inverse);
db::local_processor<db::Edge, db::PolygonRef, 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_edges.layer (), other_deep->deep_layer ().layer (), dl_out.layer ());
return new db::DeepEdges (dl_out);
}
EdgesDelegate *
DeepEdges::selected_interacting_generic (const Edges &other, bool inverse) const
{
const db::DeepEdges *other_deep = dynamic_cast<const db::DeepEdges *> (other.delegate ());
if (! other_deep) {
return db::AsIfFlatEdges::selected_interacting_generic (other, inverse);
}
ensure_merged_edges_valid ();
DeepLayer dl_out (m_deep_layer.derived ());
db::Edge2EdgeInteractingLocalOperation op (inverse);
db::local_processor<db::Edge, 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_edges.layer (), other_deep->deep_layer ().layer (), dl_out.layer ());
return new db::DeepEdges (dl_out);
}
EdgesDelegate *DeepEdges::selected_interacting (const Edges &other) const
{
// TODO: implement
return AsIfFlatEdges::selected_interacting (other);
return selected_interacting_generic (other, false);
}
EdgesDelegate *DeepEdges::selected_not_interacting (const Edges &other) const
{
// TODO: implement
return AsIfFlatEdges::selected_not_interacting (other);
return selected_interacting_generic (other, true);
}
EdgesDelegate *DeepEdges::selected_interacting (const Region &other) const
{
// TODO: implement
return AsIfFlatEdges::selected_interacting (other);
return selected_interacting_generic (other, false);
}
EdgesDelegate *DeepEdges::selected_not_interacting (const Region &other) const
{
// TODO: implement
return AsIfFlatEdges::selected_not_interacting (other);
return selected_interacting_generic (other, true);
}
EdgesDelegate *DeepEdges::in (const Edges &other, bool invert) const
{
// TODO: implement
// TODO: is there a cheaper way?
return AsIfFlatEdges::in (other, invert);
}

View File

@ -174,6 +174,8 @@ private:
DeepLayer edge_region_op (const DeepRegion *other, bool outside, bool include_borders) const;
EdgePairs run_check (db::edge_relation_type rel, const Edges *other, db::Coord d, bool whole_edges, metrics_type metrics, double ignore_angle, distance_type min_projection, distance_type max_projection) const;
EdgesDelegate *segments (int mode, length_type length, double fraction) const;
EdgesDelegate *selected_interacting_generic (const Edges &edges, bool invert) const;
EdgesDelegate *selected_interacting_generic (const Region &region, bool invert) const;
};
}

View File

@ -342,3 +342,47 @@ TEST(7_Partial)
db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/deep_edges_au7.gds");
}
TEST(8_SelectInteracting)
{
db::Layout ly;
{
std::string fn (tl::testsrc ());
fn += "/testdata/algo/deep_region_l1.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 l2 = ly.get_layer (db::LayerProperties (2, 0));
unsigned int l3 = ly.get_layer (db::LayerProperties (3, 0));
db::Region r2 (db::RecursiveShapeIterator (ly, top_cell, l2), dss);
db::Region r3 (db::RecursiveShapeIterator (ly, top_cell, l3), dss);
db::Edges e2 = r2.edges ();
db::Edges e3 = r3.edges ();
db::Layout target;
unsigned int target_top_cell_index = target.add_cell (ly.cell_name (top_cell_index));
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (2, 0)), r2);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (3, 0)), r3);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (10, 0)), e2.selected_interacting (e3));
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (11, 0)), e2.selected_not_interacting (e3));
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (12, 0)), e3.selected_interacting (e2));
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (13, 0)), e3.selected_not_interacting (e2));
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (20, 0)), e2.selected_interacting (r3));
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (21, 0)), e2.selected_not_interacting (r3));
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (22, 0)), e3.selected_interacting (r2));
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (23, 0)), e3.selected_not_interacting (r2));
CHECKPOINT();
db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/deep_edges_au8.gds");
}

BIN
testdata/algo/deep_edges_au8.gds vendored Normal file

Binary file not shown.