Merge pull request #1649 from KLayout/wip

Wip
This commit is contained in:
Matthias Köfferlein
2024-03-23 15:45:52 +01:00
committed by GitHub
85 changed files with 2910 additions and 828 deletions
+282 -159
View File
@@ -28,6 +28,7 @@
#include "dbEmptyEdges.h"
#include "dbEdges.h"
#include "dbEdgesUtils.h"
#include "dbEdgesLocalOperations.h"
#include "dbEdgeBoolean.h"
#include "dbBoxConvert.h"
#include "dbRegion.h"
@@ -39,6 +40,7 @@
#include "dbPolygonGenerators.h"
#include "dbPolygon.h"
#include "dbPath.h"
#include "dbHierProcessor.h"
#include <sstream>
@@ -94,104 +96,105 @@ AsIfFlatEdges::to_string (size_t nmax) const
return os.str ();
}
EdgesDelegate *
AsIfFlatEdges::selected_interacting_generic (const Region &other, EdgeInteractionMode mode, bool inverse) const
namespace {
class OutputPairHolder
{
// shortcuts
if (other.empty () || empty ()) {
return ((mode == EdgesOutside) == inverse) ? new EmptyEdges () : clone ();
}
public:
OutputPairHolder (int inverse, bool merged_semantics)
{
m_e1.reset (new FlatEdges (merged_semantics));
m_results.push_back (& m_e1->raw_edges ());
db::box_scanner2<db::Edge, size_t, db::Polygon, size_t> scanner (report_progress (), progress_desc ());
AddressableEdgeDelivery e (begin_merged ());
for ( ; ! e.at_end (); ++e) {
scanner.insert1 (e.operator-> (), 0);
}
AddressablePolygonDelivery p = (mode == EdgesInside ? other.addressable_merged_polygons () : other.addressable_polygons ());
for ( ; ! p.at_end (); ++p) {
scanner.insert2 (p.operator-> (), 1);
}
std::unique_ptr<FlatEdges> output (new FlatEdges (true));
if (! inverse) {
edge_to_region_interaction_filter<FlatEdges> filter (output.get (), mode);
scanner.process (filter, 1, db::box_convert<db::Edge> (), db::box_convert<db::Polygon> ());
} else {
std::set<db::Edge> result;
edge_to_region_interaction_filter<std::set<db::Edge> > filter (&result, mode);
scanner.process (filter, 1, db::box_convert<db::Edge> (), db::box_convert<db::Polygon> ());
for (EdgesIterator o (begin_merged ()); ! o.at_end (); ++o) {
if (result.find (*o) == result.end ()) {
output->insert (*o);
}
if (inverse == 0) {
m_e2.reset (new FlatEdges (merged_semantics));
m_results.push_back (& m_e2->raw_edges ());
}
}
return output.release ();
std::pair<EdgesDelegate *, EdgesDelegate *> region_pair ()
{
return std::make_pair (m_e1.release (), m_e2.release ());
}
const std::vector<db::Shapes *> &results () { return m_results; }
private:
std::unique_ptr<FlatEdges> m_e1, m_e2;
std::vector<db::Shapes *> m_results;
};
}
EdgesDelegate *
AsIfFlatEdges::selected_interacting_generic (const Edges &edges, EdgeInteractionMode mode, bool inverse) const
AsIfFlatEdges::selected_interacting_generic (const Region &other, EdgeInteractionMode mode, bool inverse, size_t min_count, size_t max_count) const
{
min_count = std::max (size_t (1), min_count);
// shortcuts
if (edges.empty () || empty ()) {
if (max_count < min_count || other.empty () || empty ()) {
return ((mode == EdgesOutside) == inverse) ? new EmptyEdges () : clone ();
}
db::box_scanner<db::Edge, size_t> scanner (report_progress (), progress_desc ());
bool counting = !(min_count == 1 && max_count == std::numeric_limits<size_t>::max ());
OutputPairHolder oph (inverse ? 1 : -1, merged_semantics () || is_merged ());
AddressableEdgeDelivery e (begin_merged ());
db::EdgesIterator edges (begin_merged ());
for ( ; ! e.at_end (); ++e) {
scanner.insert (e.operator-> (), 0);
db::edge_to_polygon_interacting_local_operation<db::Polygon> op (mode, inverse ? db::edge_to_polygon_interacting_local_operation<db::Polygon>::Inverse : db::edge_to_polygon_interacting_local_operation<db::Polygon>::Normal, min_count, max_count);
db::local_processor<db::Edge, db::Polygon, db::Edge> proc;
proc.set_base_verbosity (base_verbosity ());
proc.set_description (progress_desc ());
proc.set_report_progress (report_progress ());
std::vector<generic_shape_iterator<db::Polygon> > others;
// NOTE: with counting the other region needs to be merged
others.push_back (counting || mode != EdgesInteract ? other.begin_merged () : other.begin ());
proc.run_flat (edges, others, std::vector<bool> (), &op, oph.results ());
return oph.region_pair ().first;
}
EdgesDelegate *
AsIfFlatEdges::selected_interacting_generic (const Edges &other, EdgeInteractionMode mode, bool inverse, size_t min_count, size_t max_count) const
{
min_count = std::max (size_t (1), min_count);
// shortcuts
if (max_count < min_count || other.empty () || empty ()) {
return ((mode == EdgesOutside) == inverse) ? new EmptyEdges () : clone ();
}
// NOTE: "inside" needs merged edges for the other edges as the algorithm works edge by edge
AddressableEdgeDelivery ee = (mode == EdgesInside ? edges.addressable_merged_edges () : edges.addressable_edges ());
bool counting = !(min_count == 1 && max_count == std::numeric_limits<size_t>::max ());
OutputPairHolder oph (inverse ? 1 : -1, merged_semantics () || is_merged ());
for ( ; ! ee.at_end (); ++ee) {
scanner.insert (ee.operator-> (), 1);
}
db::EdgesIterator edges (begin_merged ());
std::unique_ptr<FlatEdges> output (new FlatEdges (true));
db::Edge2EdgeInteractingLocalOperation op (mode, inverse ? db::Edge2EdgeInteractingLocalOperation::Inverse : db::Edge2EdgeInteractingLocalOperation::Normal, min_count, max_count);
if (! inverse) {
db::local_processor<db::Edge, db::Edge, db::Edge> proc;
proc.set_base_verbosity (base_verbosity ());
proc.set_description (progress_desc ());
proc.set_report_progress (report_progress ());
edge_interaction_filter<FlatEdges> filter (*output, mode);
scanner.process (filter, 1, db::box_convert<db::Edge> ());
std::vector<generic_shape_iterator<db::Edge> > others;
// NOTE: with counting the other edge collection needs to be merged
others.push_back (counting || mode != EdgesInteract ? other.begin_merged () : other.begin ());
} else {
proc.run_flat (edges, others, std::vector<bool> (), &op, oph.results ());
std::set<db::Edge> result;
edge_interaction_filter<std::set<db::Edge> > filter (result, mode);
scanner.process (filter, 1, db::box_convert<db::Edge> ());
for (EdgesIterator o (begin_merged ()); ! o.at_end (); ++o) {
if (result.find (*o) == result.end ()) {
output->insert (*o);
}
}
}
return output.release ();
return oph.region_pair ().first;
}
std::pair<EdgesDelegate *, EdgesDelegate *>
AsIfFlatEdges::selected_interacting_pair_generic (const Region &region, EdgeInteractionMode mode) const
AsIfFlatEdges::selected_interacting_pair_generic (const Region &other, EdgeInteractionMode mode, size_t min_count, size_t max_count) const
{
min_count = std::max (size_t (1), min_count);
// shortcuts
if (region.empty () || empty ()) {
if (max_count < min_count || other.empty () || empty ()) {
if (mode != EdgesOutside) {
return std::make_pair (new EmptyEdges (), clone ());
} else {
@@ -199,43 +202,34 @@ AsIfFlatEdges::selected_interacting_pair_generic (const Region &region, EdgeInte
}
}
db::box_scanner2<db::Edge, size_t, db::Polygon, size_t> scanner (report_progress (), progress_desc ());
bool counting = !(min_count == 1 && max_count == std::numeric_limits<size_t>::max ());
OutputPairHolder oph (0, merged_semantics () || is_merged ());
AddressableEdgeDelivery e (begin_merged ());
db::EdgesIterator edges (begin_merged ());
for ( ; ! e.at_end (); ++e) {
scanner.insert1 (e.operator-> (), 0);
}
db::edge_to_polygon_interacting_local_operation<db::Polygon> op (mode, db::edge_to_polygon_interacting_local_operation<db::Polygon>::Both, min_count, max_count);
AddressablePolygonDelivery p = region.addressable_merged_polygons ();
db::local_processor<db::Edge, db::Polygon, db::Edge> proc;
proc.set_base_verbosity (base_verbosity ());
proc.set_description (progress_desc ());
proc.set_report_progress (report_progress ());
for ( ; ! p.at_end (); ++p) {
scanner.insert2 (p.operator-> (), 1);
}
std::vector<generic_shape_iterator<db::Polygon> > others;
// NOTE: with counting the other region needs to be merged
others.push_back (counting || mode != EdgesInteract ? other.begin_merged () : other.begin ());
std::unique_ptr<FlatEdges> output (new FlatEdges (true));
std::unique_ptr<FlatEdges> output2 (new FlatEdges (true));
proc.run_flat (edges, others, std::vector<bool> (), &op, oph.results ());
std::set<db::Edge> result;
edge_to_region_interaction_filter<std::set<db::Edge> > filter (&result, mode);
scanner.process (filter, 1, db::box_convert<db::Edge> (), db::box_convert<db::Polygon> ());
for (EdgesIterator o (begin_merged ()); ! o.at_end (); ++o) {
if (result.find (*o) == result.end ()) {
output2->insert (*o);
} else {
output->insert (*o);
}
}
return std::make_pair (output.release (), output2.release ());
return oph.region_pair ();
}
std::pair<EdgesDelegate *, EdgesDelegate *>
AsIfFlatEdges::selected_interacting_pair_generic (const Edges &other, EdgeInteractionMode mode) const
AsIfFlatEdges::selected_interacting_pair_generic (const Edges &other, EdgeInteractionMode mode, size_t min_count, size_t max_count) const
{
min_count = std::max (size_t (1), min_count);
// shortcuts
if (other.empty () || empty ()) {
if (max_count < min_count || other.empty () || empty ()) {
if (mode != EdgesOutside) {
return std::make_pair (new EmptyEdges (), clone ());
} else {
@@ -243,36 +237,25 @@ AsIfFlatEdges::selected_interacting_pair_generic (const Edges &other, EdgeIntera
}
}
db::box_scanner<db::Edge, size_t> scanner (report_progress (), progress_desc ());
bool counting = !(min_count == 1 && max_count == std::numeric_limits<size_t>::max ());
OutputPairHolder oph (0, merged_semantics () || is_merged ());
AddressableEdgeDelivery e (begin_merged ());
db::EdgesIterator edges (begin_merged ());
for ( ; ! e.at_end (); ++e) {
scanner.insert (e.operator-> (), 0);
}
db::Edge2EdgeInteractingLocalOperation op (mode, db::Edge2EdgeInteractingLocalOperation::Both, min_count, max_count);
AddressableEdgeDelivery ee = other.addressable_merged_edges ();
db::local_processor<db::Edge, db::Edge, db::Edge> proc;
proc.set_base_verbosity (base_verbosity ());
proc.set_description (progress_desc ());
proc.set_report_progress (report_progress ());
for ( ; ! ee.at_end (); ++ee) {
scanner.insert (ee.operator-> (), 1);
}
std::vector<generic_shape_iterator<db::Edge> > others;
// NOTE: with counting the other edge collection needs to be merged
others.push_back (counting || mode != EdgesInteract ? other.begin_merged () : other.begin ());
std::unique_ptr<FlatEdges> output (new FlatEdges (true));
std::unique_ptr<FlatEdges> output2 (new FlatEdges (true));
proc.run_flat (edges, others, std::vector<bool> (), &op, oph.results ());
std::set<db::Edge> results;
edge_interaction_filter<std::set<db::Edge> > filter (results, mode);
scanner.process (filter, 1, db::box_convert<db::Edge> ());
for (EdgesIterator o (begin_merged ()); ! o.at_end (); ++o) {
if (results.find (*o) == results.end ()) {
output2->insert (*o);
} else {
output->insert (*o);
}
}
return std::make_pair (output.release (), output2.release ());
return oph.region_pair ();
}
@@ -294,7 +277,7 @@ AsIfFlatEdges::pull_generic (const Edges &edges) const
}
std::unique_ptr<FlatEdges> output (new FlatEdges (true));
edge_interaction_filter<FlatEdges> filter (*output, EdgesInteract);
edge_interaction_filter<FlatEdges> filter (*output, EdgesInteract, size_t (1), std::numeric_limits<size_t>::max ());
scanner.process (filter, 1, db::box_convert<db::Edge> ());
return output.release ();
@@ -324,7 +307,7 @@ AsIfFlatEdges::pull_generic (const Region &other) const
std::unique_ptr<FlatRegion> output (new FlatRegion (true));
edge_to_region_interaction_filter<FlatRegion> filter (output.get (), EdgesInteract);
edge_to_polygon_interaction_filter<FlatRegion> filter (output.get (), EdgesInteract, size_t (1), std::numeric_limits<size_t>::max ());
scanner.process (filter, 1, db::box_convert<db::Edge> (), db::box_convert<db::Polygon> ());
return output.release ();
@@ -343,111 +326,111 @@ AsIfFlatEdges::pull_interacting (const Region &other) const
}
EdgesDelegate *
AsIfFlatEdges::selected_interacting (const Edges &other) const
AsIfFlatEdges::selected_interacting (const Edges &other, size_t min_count, size_t max_count) const
{
return selected_interacting_generic (other, EdgesInteract, false);
return selected_interacting_generic (other, EdgesInteract, false, min_count, max_count);
}
EdgesDelegate *
AsIfFlatEdges::selected_not_interacting (const Edges &other) const
AsIfFlatEdges::selected_not_interacting (const Edges &other, size_t min_count, size_t max_count) const
{
return selected_interacting_generic (other, EdgesInteract, true);
return selected_interacting_generic (other, EdgesInteract, true, min_count, max_count);
}
EdgesDelegate *
AsIfFlatEdges::selected_interacting (const Region &other) const
AsIfFlatEdges::selected_interacting (const Region &other, size_t min_count, size_t max_count) const
{
return selected_interacting_generic (other, EdgesInteract, false);
return selected_interacting_generic (other, EdgesInteract, false, min_count, max_count);
}
EdgesDelegate *
AsIfFlatEdges::selected_not_interacting (const Region &other) const
AsIfFlatEdges::selected_not_interacting (const Region &other, size_t min_count, size_t max_count) const
{
return selected_interacting_generic (other, EdgesInteract, true);
return selected_interacting_generic (other, EdgesInteract, true, min_count, max_count);
}
std::pair<EdgesDelegate *, EdgesDelegate *>
AsIfFlatEdges::selected_interacting_pair (const Region &other) const
AsIfFlatEdges::selected_interacting_pair (const Region &other, size_t min_count, size_t max_count) const
{
return selected_interacting_pair_generic (other, EdgesInteract);
return selected_interacting_pair_generic (other, EdgesInteract, min_count, max_count);
}
std::pair<EdgesDelegate *, EdgesDelegate *>
AsIfFlatEdges::selected_interacting_pair (const Edges &other) const
AsIfFlatEdges::selected_interacting_pair (const Edges &other, size_t min_count, size_t max_count) const
{
return selected_interacting_pair_generic (other, EdgesInteract);
return selected_interacting_pair_generic (other, EdgesInteract, min_count, max_count);
}
EdgesDelegate *
AsIfFlatEdges::selected_outside (const Region &other) const
{
return selected_interacting_generic (other, EdgesOutside, false);
return selected_interacting_generic (other, EdgesOutside, false, size_t (1), std::numeric_limits<size_t>::max ());
}
EdgesDelegate *
AsIfFlatEdges::selected_not_outside (const Region &other) const
{
return selected_interacting_generic (other, EdgesOutside, true);
return selected_interacting_generic (other, EdgesOutside, true, size_t (1), std::numeric_limits<size_t>::max ());
}
std::pair<EdgesDelegate *, EdgesDelegate *>
AsIfFlatEdges::selected_outside_pair (const Region &other) const
{
return selected_interacting_pair_generic (other, EdgesOutside);
return selected_interacting_pair_generic (other, EdgesOutside, size_t (1), std::numeric_limits<size_t>::max ());
}
EdgesDelegate *
AsIfFlatEdges::selected_inside (const Region &other) const
{
return selected_interacting_generic (other, EdgesInside, false);
return selected_interacting_generic (other, EdgesInside, false, size_t (1), std::numeric_limits<size_t>::max ());
}
EdgesDelegate *
AsIfFlatEdges::selected_not_inside (const Region &other) const
{
return selected_interacting_generic (other, EdgesInside, true);
return selected_interacting_generic (other, EdgesInside, true, size_t (1), std::numeric_limits<size_t>::max ());
}
std::pair<EdgesDelegate *, EdgesDelegate *>
AsIfFlatEdges::selected_inside_pair (const Region &other) const
{
return selected_interacting_pair_generic (other, EdgesInside);
return selected_interacting_pair_generic (other, EdgesInside, size_t (1), std::numeric_limits<size_t>::max ());
}
EdgesDelegate *
AsIfFlatEdges::selected_outside (const Edges &other) const
{
return selected_interacting_generic (other, EdgesOutside, false);
return selected_interacting_generic (other, EdgesOutside, false, size_t (1), std::numeric_limits<size_t>::max ());
}
EdgesDelegate *
AsIfFlatEdges::selected_not_outside (const Edges &other) const
{
return selected_interacting_generic (other, EdgesOutside, true);
return selected_interacting_generic (other, EdgesOutside, true, size_t (1), std::numeric_limits<size_t>::max ());
}
std::pair<EdgesDelegate *, EdgesDelegate *>
AsIfFlatEdges::selected_outside_pair (const Edges &other) const
{
return selected_interacting_pair_generic (other, EdgesOutside);
return selected_interacting_pair_generic (other, EdgesOutside, size_t (1), std::numeric_limits<size_t>::max ());
}
EdgesDelegate *
AsIfFlatEdges::selected_inside (const Edges &other) const
{
return selected_interacting_generic (other, EdgesInside, false);
return selected_interacting_generic (other, EdgesInside, false, size_t (1), std::numeric_limits<size_t>::max ());
}
EdgesDelegate *
AsIfFlatEdges::selected_not_inside (const Edges &other) const
{
return selected_interacting_generic (other, EdgesInside, true);
return selected_interacting_generic (other, EdgesInside, true, size_t (1), std::numeric_limits<size_t>::max ());
}
std::pair<EdgesDelegate *, EdgesDelegate *>
AsIfFlatEdges::selected_inside_pair (const Edges &other) const
{
return selected_interacting_pair_generic (other, EdgesInside);
return selected_interacting_pair_generic (other, EdgesInside, size_t (1), std::numeric_limits<size_t>::max ());
}
@@ -769,6 +752,118 @@ AsIfFlatEdges::run_check (db::edge_relation_type rel, const Edges *other, db::Co
return result.release ();
}
EdgesDelegate *
AsIfFlatEdges::merged () const
{
if (empty ()) {
return new db::EmptyEdges ();
} else {
return boolean (0, EdgeOr);
}
}
EdgesDelegate *
AsIfFlatEdges::and_with (const Edges &other) const
{
if (empty () || other.empty ()) {
return new db::EmptyEdges ();
} else {
return boolean (&other, EdgeAnd);
}
}
EdgesDelegate *
AsIfFlatEdges::not_with (const Edges &other) const
{
if (empty ()) {
return new db::EmptyEdges ();
} else if (other.empty ()) {
return clone ();
} else {
return boolean (&other, EdgeNot);
}
}
std::pair<EdgesDelegate *, EdgesDelegate *>
AsIfFlatEdges::andnot_with (const Edges &other) const
{
if (empty ()) {
return std::make_pair (new db::EmptyEdges (), new db::EmptyEdges ());
} else if (other.empty ()) {
return std::make_pair (new db::EmptyEdges (), clone ());
} else {
return boolean_andnot (&other);
}
}
EdgesDelegate *
AsIfFlatEdges::and_with (const Region &other) const
{
if (empty () || other.empty ()) {
return new db::EmptyEdges ();
} else {
return edge_region_op (other, db::EdgePolygonOp::Inside, true /*include borders*/).first;
}
}
EdgesDelegate *
AsIfFlatEdges::not_with (const Region &other) const
{
if (empty ()) {
return new db::EmptyEdges ();
} else if (other.empty ()) {
return clone ();
} else {
return edge_region_op (other, db::EdgePolygonOp::Outside, true /*include borders*/).first;
}
}
std::pair<EdgesDelegate *, EdgesDelegate *>
AsIfFlatEdges::andnot_with (const Region &other) const
{
if (empty ()) {
return std::make_pair (new db::EmptyEdges (), new db::EmptyEdges ());
} else if (other.empty ()) {
return std::make_pair (new db::EmptyEdges (), clone ());
} else {
return edge_region_op (other, db::EdgePolygonOp::Both, true /*include borders*/);
}
}
EdgesDelegate *
AsIfFlatEdges::xor_with (const Edges &other) const
{
if (empty ()) {
return other.delegate ()->clone ();
} else if (other.empty ()) {
return clone ();
} else {
return boolean (&other, EdgeXor);
}
}
EdgesDelegate *
AsIfFlatEdges::or_with (const Edges &other) const
{
if (empty ()) {
return other.delegate ()->clone ();
} else if (other.empty ()) {
return clone ();
} else {
return boolean (&other, EdgeOr);
}
}
EdgesDelegate *
AsIfFlatEdges::intersections (const Edges &other) const
{
if (empty () || other.empty ()) {
return new db::EmptyEdges ();
} else {
return boolean (&other, EdgeIntersections);
}
}
EdgesDelegate *
AsIfFlatEdges::boolean (const Edges *other, EdgeBoolOp op) const
{
@@ -781,9 +876,7 @@ AsIfFlatEdges::boolean (const Edges *other, EdgeBoolOp op) const
AddressableEdgeDelivery e (begin ());
for ( ; ! e.at_end (); ++e) {
if (! e->is_degenerate ()) {
scanner.insert (e.operator-> (), 0);
}
scanner.insert (e.operator-> (), 0);
}
AddressableEdgeDelivery ee;
@@ -791,9 +884,7 @@ AsIfFlatEdges::boolean (const Edges *other, EdgeBoolOp op) const
if (other) {
ee = other->addressable_edges ();
for ( ; ! ee.at_end (); ++ee) {
if (! ee->is_degenerate ()) {
scanner.insert (ee.operator-> (), 1);
}
scanner.insert (ee.operator-> (), 1);
}
}
@@ -815,9 +906,7 @@ AsIfFlatEdges::boolean_andnot (const Edges *other) const
AddressableEdgeDelivery e (begin ());
for ( ; ! e.at_end (); ++e) {
if (! e->is_degenerate ()) {
scanner.insert (e.operator-> (), 0);
}
scanner.insert (e.operator-> (), 0);
}
AddressableEdgeDelivery ee;
@@ -825,9 +914,7 @@ AsIfFlatEdges::boolean_andnot (const Edges *other) const
if (other) {
ee = other->addressable_edges ();
for ( ; ! ee.at_end (); ++ee) {
if (! ee->is_degenerate ()) {
scanner.insert (ee.operator-> (), 1);
}
scanner.insert (ee.operator-> (), 1);
}
}
@@ -852,6 +939,8 @@ AsIfFlatEdges::edge_region_op (const Region &other, db::EdgePolygonOp::mode_t mo
db::EdgeProcessor ep (report_progress (), progress_desc ());
bool has_dots = false;
for (db::Region::const_iterator p = other.begin (); ! p.at_end (); ++p) {
if (p->box ().touches (bbox ())) {
ep.insert (*p, 0);
@@ -859,7 +948,11 @@ AsIfFlatEdges::edge_region_op (const Region &other, db::EdgePolygonOp::mode_t mo
}
for (EdgesIterator e (begin ()); ! e.at_end (); ++e) {
ep.insert (*e, 1);
if (e->is_degenerate ()) {
has_dots = true;
} else {
ep.insert (*e, 1);
}
}
std::unique_ptr<FlatEdges> output_second;
@@ -874,6 +967,36 @@ AsIfFlatEdges::edge_region_op (const Region &other, db::EdgePolygonOp::mode_t mo
db::EdgePolygonOp op (mode, include_borders);
ep.process (cc, op);
// process dots which are not captured by the booleans using the interaction function
if (has_dots) {
std::unique_ptr<FlatEdges> dots (new FlatEdges (false));
for (EdgesIterator e (begin ()); ! e.at_end (); ++e) {
if (e->is_degenerate ()) {
dots->insert (*e);
}
}
std::pair<EdgesDelegate *, EdgesDelegate *> res (0, 0);
if (mode == EdgePolygonOp::Both) {
res = dots->selected_interacting_pair_generic (other, include_borders ? EdgesInteract : EdgesInside, size_t (1), std::numeric_limits<size_t>::max ());
} else if (mode == EdgePolygonOp::Inside) {
res.first = dots->selected_interacting_generic (other, include_borders ? EdgesInteract : EdgesInside, false, size_t (1), std::numeric_limits<size_t>::max ());
} else if (mode == EdgePolygonOp::Outside) {
res.first = dots->selected_interacting_generic (other, include_borders ? EdgesInteract : EdgesOutside, include_borders, size_t (1), std::numeric_limits<size_t>::max ());
}
if (res.first) {
output->add_in_place (db::Edges (res.first));
}
if (res.second) {
output_second->add_in_place (db::Edges (res.second));
}
}
return std::make_pair (output.release (), output_second.release ());
}
+20 -50
View File
@@ -107,55 +107,25 @@ public:
return merged ();
}
virtual EdgesDelegate *merged () const
{
return boolean (0, EdgeOr);
}
virtual EdgesDelegate *merged () const;
virtual EdgesDelegate *and_with (const Edges &other) const
{
return boolean (&other, EdgeAnd);
}
virtual EdgesDelegate *and_with (const Edges &other) const;
virtual EdgesDelegate *not_with (const Edges &other) const
{
return boolean (&other, EdgeNot);
}
virtual EdgesDelegate *not_with (const Edges &other) const;
virtual std::pair<EdgesDelegate *, EdgesDelegate *> andnot_with (const Edges &other) const
{
return boolean_andnot (&other);
}
virtual std::pair<EdgesDelegate *, EdgesDelegate *> andnot_with (const Edges &other) const;
virtual EdgesDelegate *and_with (const Region &other) const
{
return edge_region_op (other, db::EdgePolygonOp::Inside, true /*include borders*/).first;
}
virtual EdgesDelegate *and_with (const Region &other) const;
virtual EdgesDelegate *not_with (const Region &other) const
{
return edge_region_op (other, db::EdgePolygonOp::Outside, true /*include borders*/).first;
}
virtual EdgesDelegate *not_with (const Region &other) const;
virtual std::pair<EdgesDelegate *, EdgesDelegate *> andnot_with (const Region &other) const
{
return edge_region_op (other, db::EdgePolygonOp::Both, true /*include borders*/);
}
virtual std::pair<EdgesDelegate *, EdgesDelegate *> andnot_with (const Region &other) const;
virtual EdgesDelegate *xor_with (const Edges &other) const
{
return boolean (&other, EdgeXor);
}
virtual EdgesDelegate *xor_with (const Edges &other) const;
virtual EdgesDelegate *or_with (const Edges &other) const
{
return boolean (&other, EdgeOr);
}
virtual EdgesDelegate *or_with (const Edges &other) const;
virtual EdgesDelegate *intersections (const Edges &other) const
{
return boolean (&other, EdgeIntersections);
}
virtual EdgesDelegate *intersections (const Edges &other) const;
virtual EdgesDelegate *add_in_place (const Edges &other)
{
@@ -183,12 +153,12 @@ public:
virtual EdgesDelegate *pull_interacting (const Edges &) const;
virtual RegionDelegate *pull_interacting (const Region &) const;
virtual EdgesDelegate *selected_interacting (const Edges &) const;
virtual EdgesDelegate *selected_not_interacting (const Edges &) const;
virtual EdgesDelegate *selected_interacting (const Region &) const;
virtual EdgesDelegate *selected_not_interacting (const Region &) const;
virtual std::pair<EdgesDelegate *, EdgesDelegate *> selected_interacting_pair (const Region &other) const;
virtual std::pair<EdgesDelegate *, EdgesDelegate *> selected_interacting_pair (const Edges &other) const;
virtual EdgesDelegate *selected_interacting (const Edges &, size_t min_count, size_t max_count) const;
virtual EdgesDelegate *selected_not_interacting (const Edges &, size_t min_count, size_t max_count) const;
virtual EdgesDelegate *selected_interacting (const Region &, size_t min_count, size_t max_count) const;
virtual EdgesDelegate *selected_not_interacting (const Region &, size_t min_count, size_t max_count) const;
virtual std::pair<EdgesDelegate *, EdgesDelegate *> selected_interacting_pair (const Region &other, size_t min_count, size_t max_count) const;
virtual std::pair<EdgesDelegate *, EdgesDelegate *> selected_interacting_pair (const Edges &other, size_t min_count, size_t max_count) const;
virtual EdgesDelegate *selected_outside (const Edges &other) const;
virtual EdgesDelegate *selected_not_outside (const Edges &other) const;
@@ -217,10 +187,10 @@ protected:
EdgePairsDelegate *run_check (db::edge_relation_type rel, const Edges *other, db::Coord d, const EdgesCheckOptions &options) const;
virtual EdgesDelegate *pull_generic (const Edges &edges) const;
virtual RegionDelegate *pull_generic (const Region &region) const;
virtual EdgesDelegate *selected_interacting_generic (const Edges &edges, EdgeInteractionMode mode, bool inverse) const;
virtual std::pair<EdgesDelegate *, EdgesDelegate *> selected_interacting_pair_generic (const Edges &edges, EdgeInteractionMode mode) const;
virtual EdgesDelegate *selected_interacting_generic (const Region &region, EdgeInteractionMode mode, bool inverse) const;
virtual std::pair<EdgesDelegate *, EdgesDelegate *> selected_interacting_pair_generic (const Region &region, EdgeInteractionMode mode) const;
virtual EdgesDelegate *selected_interacting_generic (const Edges &edges, EdgeInteractionMode mode, bool inverse, size_t min_count, size_t max_count) const;
virtual std::pair<EdgesDelegate *, EdgesDelegate *> selected_interacting_pair_generic (const Edges &edges, EdgeInteractionMode mode, size_t min_count, size_t max_count) const;
virtual EdgesDelegate *selected_interacting_generic (const Region &region, EdgeInteractionMode mode, bool inverse, size_t min_count, size_t max_count) const;
virtual std::pair<EdgesDelegate *, EdgesDelegate *> selected_interacting_pair_generic (const Region &region, EdgeInteractionMode mode, size_t min_count, size_t max_count) const;
AsIfFlatEdges &operator= (const AsIfFlatEdges &other);
AsIfFlatEdges (const AsIfFlatEdges &other);
+31 -7
View File
@@ -143,7 +143,7 @@ AsIfFlatRegion::to_string (size_t nmax) const
}
EdgesDelegate *
AsIfFlatRegion::edges (const EdgeFilterBase *filter) const
AsIfFlatRegion::edges (const EdgeFilterBase *filter, const PolygonToEdgeProcessorBase *proc) const
{
std::unique_ptr<FlatEdges> result (new FlatEdges ());
db::PropertyMapper pm (result->properties_repository (), properties_repository ());
@@ -154,17 +154,41 @@ AsIfFlatRegion::edges (const EdgeFilterBase *filter) const
}
result->reserve (n);
std::vector<db::Edge> heap;
for (RegionIterator p (begin_merged ()); ! p.at_end (); ++p) {
db::properties_id_type prop_id = p.prop_id ();
for (db::Polygon::polygon_edge_iterator e = p->begin_edge (); ! e.at_end (); ++e) {
if (! filter || filter->selected (*e)) {
if (prop_id != 0) {
result->insert (db::EdgeWithProperties (*e, pm (prop_id)));
} else {
result->insert (*e);
if (proc) {
heap.clear ();
proc->process (*p, heap);
for (auto e = heap.begin (); e != heap.end (); ++e) {
if (! filter || filter->selected (*e)) {
if (prop_id != 0) {
result->insert (db::EdgeWithProperties (*e, pm (prop_id)));
} else {
result->insert (*e);
}
}
}
} else {
for (db::Polygon::polygon_edge_iterator e = p->begin_edge (); ! e.at_end (); ++e) {
if (! filter || filter->selected (*e)) {
if (prop_id != 0) {
result->insert (db::EdgeWithProperties (*e, pm (prop_id)));
} else {
result->insert (*e);
}
}
}
}
}
return result.release ();
+7 -7
View File
@@ -84,7 +84,7 @@ public:
virtual RegionDelegate *scaled_and_snapped (db::Coord gx, db::Coord mx, db::Coord dx, db::Coord gy, db::Coord my, db::Coord dy);
virtual EdgesDelegate *edges (const EdgeFilterBase *) const;
virtual EdgesDelegate *edges (const EdgeFilterBase *filter, const db::PolygonToEdgeProcessorBase *proc) const;
virtual RegionDelegate *process_in_place (const PolygonProcessorBase &filter)
{
@@ -137,32 +137,32 @@ public:
virtual RegionDelegate *selected_outside (const Region &other) const
{
return selected_interacting_generic (other, 1, false, Positive, size_t (0), std::numeric_limits<size_t>::max ()).first;
return selected_interacting_generic (other, 1, false, Positive, size_t (1), std::numeric_limits<size_t>::max ()).first;
}
virtual RegionDelegate *selected_not_outside (const Region &other) const
{
return selected_interacting_generic (other, 1, false, Negative, size_t (0), std::numeric_limits<size_t>::max ()).first;
return selected_interacting_generic (other, 1, false, Negative, size_t (1), std::numeric_limits<size_t>::max ()).first;
}
virtual std::pair<RegionDelegate *, RegionDelegate *> selected_outside_pair (const Region &other) const
{
return selected_interacting_generic (other, 1, false, PositiveAndNegative, size_t (0), std::numeric_limits<size_t>::max ());
return selected_interacting_generic (other, 1, false, PositiveAndNegative, size_t (1), std::numeric_limits<size_t>::max ());
}
virtual RegionDelegate *selected_inside (const Region &other) const
{
return selected_interacting_generic (other, -1, true, Positive, size_t (0), std::numeric_limits<size_t>::max ()).first;
return selected_interacting_generic (other, -1, true, Positive, size_t (1), std::numeric_limits<size_t>::max ()).first;
}
virtual RegionDelegate *selected_not_inside (const Region &other) const
{
return selected_interacting_generic (other, -1, true, Negative, size_t (0), std::numeric_limits<size_t>::max ()).first;
return selected_interacting_generic (other, -1, true, Negative, size_t (1), std::numeric_limits<size_t>::max ()).first;
}
virtual std::pair<RegionDelegate *, RegionDelegate *> selected_inside_pair (const Region &other) const
{
return selected_interacting_generic (other, -1, true, PositiveAndNegative, size_t (0), std::numeric_limits<size_t>::max ());
return selected_interacting_generic (other, -1, true, PositiveAndNegative, size_t (1), std::numeric_limits<size_t>::max ());
}
virtual RegionDelegate *selected_enclosing (const Region &other, size_t min_count, size_t max_count) const
+9 -1
View File
@@ -1079,7 +1079,7 @@ public:
m_cl.erase (cli);
}
} else if (m_report_single) {
} else if (m_report_single && m_ignore_single.find (obj) == m_ignore_single.end ()) {
// single-object entry: create a cluster and feed it a single-object signature
Cluster cl (m_cl_template);
@@ -1089,6 +1089,13 @@ public:
}
}
void ignore_single (const Obj *o)
{
if (m_report_single) {
m_ignore_single.insert (o);
}
}
void add_asymm (const Obj *o1, const Prop &p1, const Obj *o2, const Prop &p2)
{
om_iterator_type om1 = m_om.find (om_key_type (o1, p1));
@@ -1166,6 +1173,7 @@ private:
bool m_report_single;
cl_type m_cl;
om_type m_om;
std::set<const Obj *> m_ignore_single;
};
}
+108 -377
View File
@@ -914,10 +914,19 @@ EdgesDelegate *DeepEdges::merged () const
return res.release ();
}
DeepLayer
std::pair<DeepLayer, DeepLayer>
DeepEdges::and_or_not_with (const DeepEdges *other, EdgeBoolOp op) const
{
std::vector<unsigned int> output_layers;
DeepLayer dl_out (deep_layer ().derived ());
output_layers.push_back (dl_out.layer ());
DeepLayer dl_out2;
if (op == EdgeAndNot) {
dl_out2 = DeepLayer (deep_layer ().derived ());
output_layers.push_back (dl_out2.layer ());
}
db::EdgeBoolAndOrNotLocalOperation local_op (op);
@@ -927,14 +936,34 @@ DeepEdges::and_or_not_with (const DeepEdges *other, EdgeBoolOp op) const
proc.set_area_ratio (deep_layer ().store ()->max_area_ratio ());
proc.set_max_vertex_count (deep_layer ().store ()->max_vertex_count ());
proc.run (&local_op, deep_layer ().layer (), other->deep_layer ().layer (), dl_out.layer ());
proc.run (&local_op, deep_layer ().layer (), other->deep_layer ().layer (), output_layers);
return dl_out;
return std::make_pair (dl_out, dl_out2);
}
std::pair<DeepLayer, DeepLayer>
DeepEdges::edge_region_op (const DeepRegion *other, EdgePolygonOp::mode_t mode, bool include_borders) const
{
// first, extract dots
DeepLayer dots (deep_layer ().derived ());
bool has_dots = false;
db::Layout &layout = const_cast<db::Layout &> (dots.layout ());
for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) {
const db::Shapes &s = c->shapes (deep_layer ().layer ());
db::Shapes &st = c->shapes (dots.layer ());
for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::Edges); ! si.at_end (); ++si) {
if (si->edge ().is_degenerate ()) {
st.insert (*si);
has_dots = true;
}
}
}
// normal processing (dots will vanish)
std::vector<unsigned int> output_layers;
DeepLayer dl_out (deep_layer ().derived ());
@@ -956,6 +985,29 @@ DeepEdges::edge_region_op (const DeepRegion *other, EdgePolygonOp::mode_t mode,
proc.run (&op, deep_layer ().layer (), other->deep_layer ().layer (), output_layers);
if (has_dots) {
// process dots
std::pair<EdgesDelegate *, EdgesDelegate *> res (0, 0);
if (mode == EdgePolygonOp::Both) {
res = db::DeepEdges (dots).selected_interacting_pair_generic_impl (other, include_borders ? EdgesInteract : EdgesInside, size_t (1), std::numeric_limits<size_t>::max ());
} else if (mode == EdgePolygonOp::Inside) {
res.first = db::DeepEdges (dots).selected_interacting_generic_impl (other, include_borders ? EdgesInteract : EdgesInside, false, size_t (1), std::numeric_limits<size_t>::max ());
} else if (mode == EdgePolygonOp::Outside) {
res.first = db::DeepEdges (dots).selected_interacting_generic_impl (other, include_borders ? EdgesInteract : EdgesOutside, include_borders, size_t (1), std::numeric_limits<size_t>::max ());
}
if (res.first) {
db::DeepEdges (dl_out).add_in_place (db::Edges (res.first));
}
if (res.second) {
db::DeepEdges (dl_out2).add_in_place (db::Edges (res.second));
}
}
return std::make_pair (dl_out, dl_out2);
}
@@ -963,17 +1015,22 @@ EdgesDelegate *DeepEdges::intersections (const Edges &other) const
{
const DeepEdges *other_deep = dynamic_cast <const DeepEdges *> (other.delegate ());
if (empty () || other.empty ()) {
if (empty ()) {
return clone ();
} else if (other.empty ()) {
// NOTE: we do not use "EmptyEdges" as we want to maintain
return new DeepEdges (deep_layer ().derived ());
} else if (! other_deep) {
return AsIfFlatEdges::intersections (other);
} else {
return new DeepEdges (and_or_not_with (other_deep, EdgeIntersections));
return new DeepEdges (and_or_not_with (other_deep, EdgeIntersections).first);
}
}
@@ -997,7 +1054,7 @@ EdgesDelegate *DeepEdges::and_with (const Edges &other) const
} else {
return new DeepEdges (and_or_not_with (other_deep, EdgeAnd));
return new DeepEdges (and_or_not_with (other_deep, EdgeAnd).first);
}
}
@@ -1016,7 +1073,7 @@ EdgesDelegate *DeepEdges::not_with (const Edges &other) const
} else {
return new DeepEdges (and_or_not_with (other_deep, EdgeNot));
return new DeepEdges (and_or_not_with (other_deep, EdgeNot).first);
}
}
@@ -1092,7 +1149,7 @@ EdgesDelegate *DeepEdges::not_with (const Region &other) const
std::pair<EdgesDelegate *, EdgesDelegate *>
DeepEdges::andnot_with (const Edges &other) const
{
const DeepRegion *other_deep = dynamic_cast <const DeepRegion *> (other.delegate ());
const DeepEdges *other_deep = dynamic_cast <const DeepEdges *> (other.delegate ());
if (empty ()) {
@@ -1109,7 +1166,7 @@ DeepEdges::andnot_with (const Edges &other) const
} else {
auto res = edge_region_op (other_deep, EdgePolygonOp::Both, true /*include borders*/);
auto res = and_or_not_with (other_deep, EdgeAndNot);
return std::make_pair (new DeepEdges (res.first), new DeepEdges (res.second));
}
@@ -1135,8 +1192,8 @@ EdgesDelegate *DeepEdges::xor_with (const Edges &other) const
// Implement XOR as (A-B)+(B-A) - only this implementation
// is compatible with the local processor scheme
DeepLayer n1 (and_or_not_with (other_deep, EdgeNot));
DeepLayer n2 (other_deep->and_or_not_with (this, EdgeNot));
DeepLayer n1 (and_or_not_with (other_deep, EdgeNot).first);
DeepLayer n2 (other_deep->and_or_not_with (this, EdgeNot).first);
n1.add_from (n2);
return new DeepEdges (n1);
@@ -1354,362 +1411,8 @@ RegionDelegate *DeepEdges::extended (coord_type ext_b, coord_type ext_e, coord_t
return res.release ();
}
namespace
{
class Edge2EdgeInteractingLocalOperation
: public local_operation<db::Edge, db::Edge, db::Edge>
{
public:
enum output_mode_t { Normal, Inverse, Both };
Edge2EdgeInteractingLocalOperation (EdgeInteractionMode mode, output_mode_t output_mode)
: m_mode (mode), m_output_mode (output_mode)
{
// .. nothing yet ..
}
virtual db::Coord dist () const
{
// touching is sufficient
return 1;
}
virtual void do_compute_local (db::Layout * /*layout*/, db::Cell * /*cell*/, const shape_interactions<db::Edge, db::Edge> &interactions, std::vector<std::unordered_set<db::Edge> > &results, const db::LocalProcessorBase * /*proc*/) const
{
tl_assert (results.size () == (m_output_mode == Both ? 2 : 1));
std::unordered_set<db::Edge> &result = results.front ();
std::unordered_set<db::Edge> *result2 = 0;
if (m_output_mode == Both) {
result2 = &results[1];
}
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).second);
}
}
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_output_mode == Inverse || m_output_mode == Both) {
std::unordered_set<db::Edge> interacting;
edge_interaction_filter<std::unordered_set<db::Edge> > filter (interacting, m_mode);
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 ()) {
if (m_output_mode != Both) {
result.insert (subject);
} else {
result2->insert (subject);
}
} else if (m_output_mode == Both) {
result.insert (subject);
}
}
} else {
edge_interaction_filter<std::unordered_set<db::Edge> > filter (result, m_mode);
scanner.process (filter, 1, db::box_convert<db::Edge> ());
}
}
virtual OnEmptyIntruderHint on_empty_intruder_hint () const
{
if (m_mode == EdgesOutside) {
return m_output_mode == Both ? Copy : (m_output_mode == Inverse ? Drop : Copy);
} else {
return m_output_mode == Both ? CopyToSecond : (m_output_mode == Inverse ? Copy : Drop);
}
}
virtual std::string description () const
{
return tl::to_string (tr ("Select interacting edges"));
}
private:
EdgeInteractionMode m_mode;
output_mode_t m_output_mode;
};
class Edge2EdgePullLocalOperation
: public local_operation<db::Edge, db::Edge, db::Edge>
{
public:
Edge2EdgePullLocalOperation ()
{
// .. nothing yet ..
}
virtual db::Coord dist () const
{
// touching is sufficient
return 1;
}
virtual void do_compute_local (db::Layout * /*layout*/, db::Cell * /*cell*/, const shape_interactions<db::Edge, db::Edge> &interactions, std::vector<std::unordered_set<db::Edge> > &results, const db::LocalProcessorBase * /*proc*/) const
{
tl_assert (results.size () == 1);
std::unordered_set<db::Edge> &result = results.front ();
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).second);
}
}
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, 1);
}
for (std::set<db::Edge>::const_iterator o = others.begin (); o != others.end (); ++o) {
scanner.insert (o.operator-> (), 0);
}
edge_interaction_filter<std::unordered_set<db::Edge> > filter (result, EdgesInteract);
scanner.process (filter, 1, db::box_convert<db::Edge> ());
}
virtual OnEmptyIntruderHint on_empty_intruder_hint () const
{
return Drop;
}
virtual std::string description () const
{
return tl::to_string (tr ("Select interacting edges from other"));
}
};
class Edge2PolygonInteractingLocalOperation
: public local_operation<db::Edge, db::PolygonRef, db::Edge>
{
public:
enum output_mode_t { Normal, Inverse, Both };
Edge2PolygonInteractingLocalOperation (EdgeInteractionMode mode, output_mode_t output_mode)
: m_mode (mode), m_output_mode (output_mode)
{
// .. nothing yet ..
}
virtual db::Coord dist () const
{
// touching is sufficient
return 1;
}
virtual void do_compute_local (db::Layout * /*layout*/, db::Cell * /*cell*/, const shape_interactions<db::Edge, db::PolygonRef> &interactions, std::vector<std::unordered_set<db::Edge> > &results, const db::LocalProcessorBase * /*proc*/) const
{
tl_assert (results.size () == size_t (m_output_mode == Both ? 2 : 1));
std::unordered_set<db::Edge> &result = results.front ();
std::unordered_set<db::Edge> *result2 = 0;
if (m_output_mode == Both) {
result2 = &results[1];
}
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).second);
}
}
for (shape_interactions<db::Edge, db::PolygonRef>::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_output_mode == Inverse || m_output_mode == Both) {
std::unordered_set<db::Edge> interacting;
edge_to_region_interaction_filter<std::unordered_set<db::Edge> > filter (&interacting, m_mode);
scanner.process (filter, 1, db::box_convert<db::Edge> (), db::box_convert<db::Polygon> ());
for (shape_interactions<db::Edge, db::PolygonRef>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
const db::Edge &subject = interactions.subject_shape (i->first);
if (interacting.find (subject) == interacting.end ()) {
if (m_output_mode != Both) {
result.insert (subject);
} else {
result2->insert (subject);
}
} else if (m_output_mode == Both) {
result.insert (subject);
}
}
} else {
edge_to_region_interaction_filter<std::unordered_set<db::Edge> > filter (&result, m_mode);
scanner.process (filter, 1, db::box_convert<db::Edge> (), db::box_convert<db::Polygon> ());
}
}
virtual OnEmptyIntruderHint on_empty_intruder_hint () const
{
if (m_mode == EdgesOutside) {
return m_output_mode == Both ? Copy : (m_output_mode == Inverse ? Drop : Copy);
} else {
return m_output_mode == Both ? CopyToSecond : (m_output_mode == Inverse ? Copy : Drop);
}
}
virtual std::string description () const
{
if (m_mode == EdgesInteract) {
if (m_output_mode == Inverse) {
return tl::to_string (tr ("Select non-interacting edges"));
} else if (m_output_mode == Normal) {
return tl::to_string (tr ("Select interacting edges"));
} else {
return tl::to_string (tr ("Select interacting and non-interacting edges"));
}
} else if (m_mode == EdgesInside) {
if (m_output_mode == Inverse) {
return tl::to_string (tr ("Select non-inside edges"));
} else if (m_output_mode == Normal) {
return tl::to_string (tr ("Select inside edges"));
} else {
return tl::to_string (tr ("Select inside and non-inside edges"));
}
} else if (m_mode == EdgesOutside) {
if (m_output_mode == Inverse) {
return tl::to_string (tr ("Select non-outside edges"));
} else if (m_output_mode == Normal) {
return tl::to_string (tr ("Select outside edges"));
} else {
return tl::to_string (tr ("Select outside and non-outside edges"));
}
}
return std::string ();
}
private:
EdgeInteractionMode m_mode;
output_mode_t m_output_mode;
};
struct ResultInserter
{
typedef db::Polygon value_type;
ResultInserter (db::Layout *layout, std::unordered_set<db::PolygonRef> &result)
: mp_layout (layout), mp_result (&result)
{
// .. nothing yet ..
}
void insert (const db::Polygon &p)
{
(*mp_result).insert (db::PolygonRef (p, mp_layout->shape_repository ()));
}
private:
db::Layout *mp_layout;
std::unordered_set<db::PolygonRef> *mp_result;
};
class Edge2PolygonPullLocalOperation
: public local_operation<db::Edge, db::PolygonRef, db::PolygonRef>
{
public:
Edge2PolygonPullLocalOperation ()
{
// .. nothing yet ..
}
virtual db::Coord dist () const
{
// touching is sufficient
return 1;
}
virtual void do_compute_local (db::Layout *layout, db::Cell * /*cell*/, const shape_interactions<db::Edge, db::PolygonRef> &interactions, std::vector<std::unordered_set<db::PolygonRef> > &results, const db::LocalProcessorBase * /*proc*/) const
{
tl_assert (results.size () == 1);
std::unordered_set<db::PolygonRef> &result = results.front ();
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).second);
}
}
for (shape_interactions<db::Edge, db::PolygonRef>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
const db::Edge &subject = interactions.subject_shape (i->first);
scanner.insert1 (&subject, 1);
}
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 (), 0);
}
ResultInserter inserter (layout, result);
edge_to_region_interaction_filter<ResultInserter> filter (&inserter, EdgesInteract);
scanner.process (filter, 1, db::box_convert<db::Edge> (), db::box_convert<db::Polygon> ());
}
virtual OnEmptyIntruderHint on_empty_intruder_hint () const
{
return Drop;
}
virtual std::string description () const
{
return tl::to_string (tr ("Select interacting regions"));
}
};
}
EdgesDelegate *
DeepEdges::selected_interacting_generic (const Region &other, EdgeInteractionMode mode, bool inverse) const
DeepEdges::selected_interacting_generic (const Region &other, EdgeInteractionMode mode, bool inverse, size_t min_count, size_t max_count) const
{
std::unique_ptr<db::DeepRegion> dr_holder;
const db::DeepRegion *other_deep = dynamic_cast<const db::DeepRegion *> (other.delegate ());
@@ -1719,23 +1422,33 @@ DeepEdges::selected_interacting_generic (const Region &other, EdgeInteractionMod
other_deep = dr_holder.get ();
}
return selected_interacting_generic_impl (other_deep, mode, inverse, min_count, max_count);
}
EdgesDelegate *
DeepEdges::selected_interacting_generic_impl (const DeepRegion *other_deep, EdgeInteractionMode mode, bool inverse, size_t min_count, size_t max_count) const
{
min_count = std::max (size_t (1), min_count);
bool counting = !(min_count == 1 && max_count == std::numeric_limits<size_t>::max ());
const db::DeepLayer &edges = merged_deep_layer ();
DeepLayer dl_out (edges.derived ());
db::Edge2PolygonInteractingLocalOperation op (mode, inverse ? db::Edge2PolygonInteractingLocalOperation::Inverse : db::Edge2PolygonInteractingLocalOperation::Normal);
db::edge_to_polygon_interacting_local_operation<db::PolygonRef> op (mode, inverse ? db::edge_to_polygon_interacting_local_operation<db::PolygonRef>::Inverse : db::edge_to_polygon_interacting_local_operation<db::PolygonRef>::Normal, min_count, max_count);
db::local_processor<db::Edge, db::PolygonRef, db::Edge> proc (const_cast<db::Layout *> (&edges.layout ()), const_cast<db::Cell *> (&edges.initial_cell ()), &other_deep->deep_layer ().layout (), &other_deep->deep_layer ().initial_cell (), edges.breakout_cells (), other_deep->deep_layer ().breakout_cells ());
proc.set_base_verbosity (base_verbosity ());
proc.set_threads (edges.store ()->threads ());
proc.run (&op, edges.layer (), (mode == EdgesInside ? other_deep->merged_deep_layer () : other_deep->deep_layer ()).layer (), dl_out.layer ());
// NOTE: with counting the other region needs to be merged
proc.run (&op, edges.layer (), (counting || mode != EdgesInteract ? other_deep->merged_deep_layer () : other_deep->deep_layer ()).layer (), dl_out.layer ());
return new db::DeepEdges (dl_out);
}
std::pair<EdgesDelegate *, EdgesDelegate *>
DeepEdges::selected_interacting_pair_generic (const Region &other, EdgeInteractionMode mode) const
DeepEdges::selected_interacting_pair_generic (const Region &other, EdgeInteractionMode mode, size_t min_count, size_t max_count) const
{
std::unique_ptr<db::DeepRegion> dr_holder;
const db::DeepRegion *other_deep = dynamic_cast<const db::DeepRegion *> (other.delegate ());
@@ -1745,6 +1458,15 @@ DeepEdges::selected_interacting_pair_generic (const Region &other, EdgeInteracti
other_deep = dr_holder.get ();
}
return selected_interacting_pair_generic_impl (other_deep, mode, min_count, max_count);
}
std::pair<EdgesDelegate *, EdgesDelegate *>
DeepEdges::selected_interacting_pair_generic_impl (const db::DeepRegion *other_deep, EdgeInteractionMode mode, size_t min_count, size_t max_count) const
{
min_count = std::max (size_t (1), min_count);
bool counting = !(min_count == 1 && max_count == std::numeric_limits<size_t>::max ());
const db::DeepLayer &edges = merged_deep_layer ();
DeepLayer dl_out (edges.derived ());
@@ -1755,20 +1477,24 @@ DeepEdges::selected_interacting_pair_generic (const Region &other, EdgeInteracti
output_layers.push_back (dl_out.layer ());
output_layers.push_back (dl_out2.layer ());
db::Edge2PolygonInteractingLocalOperation op (mode, db::Edge2PolygonInteractingLocalOperation::Both);
db::edge_to_polygon_interacting_local_operation<db::PolygonRef> op (mode, db::edge_to_polygon_interacting_local_operation<db::PolygonRef>::Both, min_count, max_count);
db::local_processor<db::Edge, db::PolygonRef, db::Edge> proc (const_cast<db::Layout *> (&edges.layout ()), const_cast<db::Cell *> (&edges.initial_cell ()), &other_deep->deep_layer ().layout (), &other_deep->deep_layer ().initial_cell (), edges.breakout_cells (), other_deep->deep_layer ().breakout_cells ());
proc.set_base_verbosity (base_verbosity ());
proc.set_threads (edges.store ()->threads ());
proc.run (&op, edges.layer (), other_deep->merged_deep_layer ().layer (), output_layers);
// NOTE: with counting the other region needs to be merged
proc.run (&op, edges.layer (), (counting || mode != EdgesInteract ? other_deep->merged_deep_layer () : other_deep->deep_layer ()).layer (), output_layers);
return std::make_pair (new db::DeepEdges (dl_out), new db::DeepEdges (dl_out2));
}
EdgesDelegate *
DeepEdges::selected_interacting_generic (const Edges &other, EdgeInteractionMode mode, bool inverse) const
DeepEdges::selected_interacting_generic (const Edges &other, EdgeInteractionMode mode, bool inverse, size_t min_count, size_t max_count) const
{
min_count = std::max (size_t (1), min_count);
bool counting = !(min_count == 1 && max_count == std::numeric_limits<size_t>::max ());
std::unique_ptr<db::DeepEdges> dr_holder;
const db::DeepEdges *other_deep = dynamic_cast<const db::DeepEdges *> (other.delegate ());
if (! other_deep) {
@@ -1781,20 +1507,24 @@ DeepEdges::selected_interacting_generic (const Edges &other, EdgeInteractionMode
DeepLayer dl_out (edges.derived ());
db::Edge2EdgeInteractingLocalOperation op (mode, inverse ? db::Edge2EdgeInteractingLocalOperation::Inverse : db::Edge2EdgeInteractingLocalOperation::Normal);
db::Edge2EdgeInteractingLocalOperation op (mode, inverse ? db::Edge2EdgeInteractingLocalOperation::Inverse : db::Edge2EdgeInteractingLocalOperation::Normal, min_count, max_count);
db::local_processor<db::Edge, db::Edge, db::Edge> proc (const_cast<db::Layout *> (&edges.layout ()), const_cast<db::Cell *> (&edges.initial_cell ()), &other_deep->deep_layer ().layout (), &other_deep->deep_layer ().initial_cell (), edges.breakout_cells (), other_deep->deep_layer ().breakout_cells ());
proc.set_base_verbosity (base_verbosity ());
proc.set_threads (edges.store ()->threads ());
proc.run (&op, edges.layer (), (mode == EdgesInside ? other_deep->merged_deep_layer () : other_deep->deep_layer ()).layer (), dl_out.layer ());
// NOTE: with counting the other region needs to be merged
proc.run (&op, edges.layer (), (counting || mode != EdgesInteract ? other_deep->merged_deep_layer () : other_deep->deep_layer ()).layer (), dl_out.layer ());
return new db::DeepEdges (dl_out);
}
std::pair<EdgesDelegate *, EdgesDelegate *>
DeepEdges::selected_interacting_pair_generic (const Edges &other, EdgeInteractionMode mode) const
DeepEdges::selected_interacting_pair_generic (const Edges &other, EdgeInteractionMode mode, size_t min_count, size_t max_count) const
{
min_count = std::max (size_t (1), min_count);
bool counting = !(min_count == 1 && max_count == std::numeric_limits<size_t>::max ());
std::unique_ptr<db::DeepEdges> dr_holder;
const db::DeepEdges *other_deep = dynamic_cast<const db::DeepEdges *> (other.delegate ());
if (! other_deep) {
@@ -1813,13 +1543,14 @@ DeepEdges::selected_interacting_pair_generic (const Edges &other, EdgeInteractio
output_layers.push_back (dl_out.layer ());
output_layers.push_back (dl_out2.layer ());
db::Edge2EdgeInteractingLocalOperation op (mode, db::Edge2EdgeInteractingLocalOperation::Both);
db::Edge2EdgeInteractingLocalOperation op (mode, db::Edge2EdgeInteractingLocalOperation::Both, min_count, max_count);
db::local_processor<db::Edge, db::Edge, db::Edge> proc (const_cast<db::Layout *> (&edges.layout ()), const_cast<db::Cell *> (&edges.initial_cell ()), &other_deep->deep_layer ().layout (), &other_deep->deep_layer ().initial_cell (), edges.breakout_cells (), other_deep->deep_layer ().breakout_cells ());
proc.set_base_verbosity (base_verbosity ());
proc.set_threads (edges.store ()->threads ());
proc.run (&op, edges.layer (), other_deep->merged_deep_layer ().layer (), output_layers);
// NOTE: with counting the other region needs to be merged
proc.run (&op, edges.layer (), (counting || mode != EdgesInteract ? other_deep->merged_deep_layer () : other_deep->deep_layer ()).layer (), output_layers);
return std::make_pair (new db::DeepEdges (dl_out), new db::DeepEdges (dl_out2));
}
+7 -5
View File
@@ -188,15 +188,17 @@ private:
void init ();
void ensure_merged_edges_valid () const;
DeepLayer and_or_not_with(const DeepEdges *other, EdgeBoolOp op) const;
std::pair<DeepLayer, DeepLayer> and_or_not_with (const DeepEdges *other, EdgeBoolOp op) const;
std::pair<DeepLayer, DeepLayer> edge_region_op (const DeepRegion *other, EdgePolygonOp::mode_t op, bool include_borders) const;
EdgePairsDelegate *run_check (db::edge_relation_type rel, const Edges *other, db::Coord d, const db::EdgesCheckOptions &options) const;
virtual EdgesDelegate *pull_generic (const Edges &edges) const;
virtual RegionDelegate *pull_generic (const Region &region) const;
virtual EdgesDelegate *selected_interacting_generic (const Edges &edges, EdgeInteractionMode mode, bool inverse) const;
virtual std::pair<EdgesDelegate *, EdgesDelegate *> selected_interacting_pair_generic (const Edges &edges, EdgeInteractionMode mode) const;
virtual EdgesDelegate *selected_interacting_generic (const Region &region, EdgeInteractionMode mode, bool inverse) const;
virtual std::pair<EdgesDelegate *, EdgesDelegate *> selected_interacting_pair_generic (const Region &region, EdgeInteractionMode mode) const;
virtual EdgesDelegate *selected_interacting_generic (const Edges &edges, EdgeInteractionMode mode, bool inverse, size_t min_count, size_t max_count) const;
virtual std::pair<EdgesDelegate *, EdgesDelegate *> selected_interacting_pair_generic (const Edges &edges, EdgeInteractionMode mode, size_t min_count, size_t max_count) const;
virtual EdgesDelegate *selected_interacting_generic (const Region &region, EdgeInteractionMode mode, bool inverse, size_t min_count, size_t max_count) const;
virtual std::pair<EdgesDelegate *, EdgesDelegate *> selected_interacting_pair_generic (const Region &region, EdgeInteractionMode mode, size_t min_count, size_t max_count) const;
EdgesDelegate *selected_interacting_generic_impl (const DeepRegion *other_deep, EdgeInteractionMode mode, bool inverse, size_t min_count, size_t max_count) const;
std::pair<EdgesDelegate *, EdgesDelegate *> selected_interacting_pair_generic_impl (const DeepRegion *other_deep, EdgeInteractionMode mode, size_t min_count, size_t max_count) const;
DeepEdges *apply_filter (const EdgeFilterBase &filter) const;
template <class Result, class OutputContainer> OutputContainer *processed_impl (const edge_processor<Result> &filter) const;
+22 -5
View File
@@ -1335,7 +1335,7 @@ DeepRegion::snapped (db::Coord gx, db::Coord gy)
}
EdgesDelegate *
DeepRegion::edges (const EdgeFilterBase *filter) const
DeepRegion::edges (const EdgeFilterBase *filter, const PolygonToEdgeProcessorBase *proc) const
{
std::unique_ptr<db::DeepEdges> res (new db::DeepEdges (deep_layer ().derived ()));
@@ -1343,7 +1343,7 @@ DeepRegion::edges (const EdgeFilterBase *filter) const
return res.release ();
}
if (! filter && merged_semantics () && ! merged_polygons_available ()) {
if (! proc && ! filter && merged_semantics () && ! merged_polygons_available ()) {
// Hierarchical edge detector - no pre-merge required
@@ -1388,15 +1388,32 @@ DeepRegion::edges (const EdgeFilterBase *filter) const
const db::Shapes &s = c->shapes (polygons.layer ());
db::Shapes &st = c->shapes (res->deep_layer ().layer ());
std::vector<db::Edge> heap;
for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::All); ! si.at_end (); ++si) {
db::Polygon poly;
si->polygon (poly);
for (db::Polygon::polygon_edge_iterator e = poly.begin_edge (); ! e.at_end (); ++e) {
if (! filter || filter->selected ((*e).transformed (tr))) {
st.insert (db::EdgeWithProperties (*e, pm (si->prop_id ())));
if (proc) {
heap.clear ();
proc->process (poly, heap);
for (auto e = heap.begin (); e != heap.end (); ++e) {
if (! filter || filter->selected ((*e).transformed (tr))) {
st.insert (db::EdgeWithProperties (*e, pm (si->prop_id ())));
}
}
} else {
for (db::Polygon::polygon_edge_iterator e = poly.begin_edge (); ! e.at_end (); ++e) {
if (! filter || filter->selected ((*e).transformed (tr))) {
st.insert (db::EdgeWithProperties (*e, pm (si->prop_id ())));
}
}
}
}
+1 -1
View File
@@ -119,7 +119,7 @@ public:
virtual RegionDelegate *snapped (db::Coord gx, db::Coord gy);
virtual EdgesDelegate *edges (const EdgeFilterBase *) const;
virtual EdgesDelegate *edges (const EdgeFilterBase *filter, const db::PolygonToEdgeProcessorBase *proc) const;
virtual RegionDelegate *process_in_place (const PolygonProcessorBase &filter);
virtual RegionDelegate *processed (const PolygonProcessorBase &filter) const;
+137 -36
View File
@@ -86,14 +86,14 @@ struct EdgeBooleanCluster
{
typedef db::Edge::coord_type coord_type;
EdgeBooleanCluster (OutputContainer *output, EdgeBoolOp op)
: mp_output (output), mp_output2 (0), m_op (op)
EdgeBooleanCluster (OutputContainer *output, std::set<db::Point> *dots, EdgeBoolOp op)
: mp_output (output), mp_output2 (0), mp_dots (dots), mp_dots2 (0), m_op (op)
{
// .. nothing yet ..
}
EdgeBooleanCluster (OutputContainer *output, OutputContainer *output2, EdgeBoolOp op)
: mp_output (output), mp_output2 (output2), m_op (op)
EdgeBooleanCluster (OutputContainer *output, OutputContainer *output2, std::set<db::Point> *dots, std::set<db::Point> *dots2, EdgeBoolOp op)
: mp_output (output), mp_output2 (output2), mp_dots (dots), mp_dots2 (dots2), m_op (op)
{
// .. nothing yet ..
}
@@ -106,24 +106,55 @@ struct EdgeBooleanCluster
if (begin () + 1 == end ()) {
if (begin ()->second == 0) {
if (m_op == EdgeAndNot) {
mp_output2->insert (*(begin ()->first));
if (begin ()->first->is_degenerate ()) {
if (mp_dots) {
mp_dots2->insert (begin ()->first->p1 ());
}
} else if (mp_output2) {
mp_output2->insert (*(begin ()->first));
}
} else if (m_op != EdgeAnd) {
mp_output->insert (*(begin ()->first));
if (begin ()->first->is_degenerate ()) {
if (mp_dots) {
mp_dots->insert (begin ()->first->p1 ());
}
} else if (mp_output) {
mp_output->insert (*(begin ()->first));
}
}
} else {
if (m_op != EdgeAnd && m_op != EdgeNot && m_op != EdgeAndNot) {
mp_output->insert (*(begin ()->first));
if (begin ()->first->is_degenerate ()) {
if (mp_dots) {
mp_dots->insert (begin ()->first->p1 ());
}
} else if (mp_output) {
mp_output->insert (*(begin ()->first));
}
}
}
return;
}
db::Edge r = *begin ()->first;
// search first non-degenerate, longest
iterator main = end ();
for (iterator i = begin (); i != end (); ++i) {
if (! i->first->is_degenerate () && (main == end () || main->first->length () < i->first->length ())) {
main = i;
}
}
if (main == end ()) {
return;
}
db::Edge r = *main->first;
double l1 = 0.0, l2 = r.double_length ();
double n = 1.0 / l2;
db::Point p1 = r.p1 (), p2 = r.p2 ();
for (iterator o = begin () + 1; o != end (); ++o) {
for (iterator o = begin (); o != end (); ++o) {
double ll1 = db::sprod (db::Vector (o->first->p1 () - r.p1 ()), r.d ()) * n;
double ll2 = db::sprod (db::Vector (o->first->p2 () - r.p1 ()), r.d ()) * n;
if (ll1 < l1) {
@@ -245,6 +276,7 @@ struct EdgeBooleanCluster
private:
OutputContainer *mp_output, *mp_output2;
std::set<db::Point> *mp_dots, *mp_dots2;
db::EdgeBoolOp m_op;
};
@@ -253,15 +285,8 @@ struct EdgeBooleanClusterCollector
: public db::cluster_collector<db::Edge, size_t, EdgeBooleanCluster<OutputContainer> >
{
EdgeBooleanClusterCollector (OutputContainer *output, EdgeBoolOp op, OutputContainer *output2 = 0)
: db::cluster_collector<db::Edge, size_t, EdgeBooleanCluster<OutputContainer> > (EdgeBooleanCluster<OutputContainer> (output, output2, op == EdgeIntersections ? EdgeAnd : op), op != EdgeAnd && op != EdgeIntersections /*report single*/),
mp_output (output), mp_intersections (op == EdgeIntersections ? output : 0)
{
// .. nothing yet ..
}
EdgeBooleanClusterCollector (OutputContainer *output, OutputContainer *intersections, EdgeBoolOp op)
: db::cluster_collector<db::Edge, size_t, EdgeBooleanCluster<OutputContainer> > (EdgeBooleanCluster<OutputContainer> (output, op), op != EdgeAnd /*report single*/),
mp_output (output), mp_intersections (intersections)
: db::cluster_collector<db::Edge, size_t, EdgeBooleanCluster<OutputContainer> > (EdgeBooleanCluster<OutputContainer> (output, output2, &m_dots, &m_dots2, op == EdgeIntersections ? EdgeAnd : op), op != EdgeAnd && op != EdgeIntersections /*report single*/),
mp_output (output), mp_output2 (output2), m_op (op)
{
// .. nothing yet ..
}
@@ -281,11 +306,78 @@ struct EdgeBooleanClusterCollector
db::cluster_collector<db::Edge, size_t, EdgeBooleanCluster<OutputContainer> >::add (o1, p1, o2, p2);
} else if (mp_intersections && p1 != p2) {
} else {
// dots vs. edge or dot is handled here, no need to copy dots
if (o1->is_degenerate ()) {
this->ignore_single (o1);
}
if (o2->is_degenerate ()) {
this->ignore_single (o2);
}
if (m_op == EdgeIntersections) {
if (p1 != p2) {
std::pair<bool, db::Point> ip = o1->intersect_point (*o2);
if (ip.first) {
m_dots.insert (ip.second);
}
}
} else if (m_op == EdgeAndNot) {
// handle case of dot vs. edge or dot
if (p1 != p2 && (o1->is_degenerate () || o2->is_degenerate ())) {
std::pair<bool, db::Point> ip = o1->intersect_point (*o2);
if (ip.first) {
m_dots.insert (ip.second);
}
if (o1->is_degenerate () && ! ip.first) {
m_dots2.insert (o1->p1 ());
}
}
} else if (m_op == EdgeAnd) {
// handle case of dot vs. edge or dot
if (p1 != p2 && (o1->is_degenerate () || o2->is_degenerate ())) {
std::pair<bool, db::Point> ip = o1->intersect_point (*o2);
if (ip.first) {
m_dots.insert (ip.second);
}
}
} else if (m_op == EdgeNot) {
// handle case of dot vs. edge or dot
if (p1 != p2 && o1->is_degenerate ()) {
std::pair<bool, db::Point> ip = o1->intersect_point (*o2);
if (! ip.first) {
m_dots.insert (o1->p1 ());
}
}
} else if (m_op == EdgeOr) {
// forward dots
if (o1->is_degenerate ()) {
m_dots.insert (o1->p1 ());
}
if (o2->is_degenerate ()) {
m_dots.insert (o2->p1 ());
}
} else if (m_op == EdgeXor) {
// handle case of dot vs. edge or dot
if (p1 != p2 && o1->is_degenerate () && o2->is_degenerate ()) {
if (o1->p1 () != o2->p1 ()) {
m_dots.insert (o1->p1 ());
m_dots.insert (o2->p1 ());
}
}
std::pair<bool, db::Point> ip = o1->intersect_point (*o2);
if (ip.first) {
m_intersections.insert (ip.second);
}
}
@@ -340,35 +432,44 @@ struct EdgeBooleanClusterCollector
};
/**
* @brief Finalizes the implementation for "EdgeIntersections"
* @brief Finalizes the implementation for "sections"
* This method pushes those points which don't interact with the edges to the output container
* as degenerate edges. It needs to be called after the pass has been made.
*/
void finalize (bool)
{
if (m_intersections.empty ()) {
add_orphan_dots (m_dots, mp_output);
if (mp_output2) {
add_orphan_dots (m_dots2, mp_output2);
}
}
private:
OutputContainer *mp_output, *mp_output2;
EdgeBoolOp m_op;
std::set<db::Point> m_dots, m_dots2;
static void add_orphan_dots (const std::set<db::Point> &dots, OutputContainer *output)
{
if (dots.empty ()) {
return;
}
db::box_scanner2<db::Edge, size_t, db::Point, size_t> intersections_to_edge_scanner;
for (typename OutputContainer::const_iterator e = mp_output->begin (); e != mp_output->end (); ++e) {
intersections_to_edge_scanner.insert1 (e.operator-> (), 0);
db::box_scanner2<db::Edge, size_t, db::Point, size_t> dots_to_edge_scanner;
for (typename OutputContainer::const_iterator e = output->begin (); e != output->end (); ++e) {
dots_to_edge_scanner.insert1 (e.operator-> (), 0);
}
for (std::set<db::Point>::const_iterator p = m_intersections.begin (); p != m_intersections.end (); ++p) {
intersections_to_edge_scanner.insert2 (p.operator-> (), 0);
for (std::set<db::Point>::const_iterator p = dots.begin (); p != dots.end (); ++p) {
dots_to_edge_scanner.insert2 (p.operator-> (), 0);
}
std::set<db::Point> points_to_remove;
RemovePointsOnEdges rpoe (points_to_remove);
intersections_to_edge_scanner.process (rpoe, 1, db::box_convert<db::Edge> (), db::box_convert<db::Point> ());
dots_to_edge_scanner.process (rpoe, 1, db::box_convert<db::Edge> (), db::box_convert<db::Point> ());
std::set_difference (dots.begin (), dots.end (), points_to_remove.begin (), points_to_remove.end (), PointInserter (output));
std::set_difference (m_intersections.begin (), m_intersections.end (), points_to_remove.begin (), points_to_remove.end (), PointInserter (mp_intersections));
}
private:
OutputContainer *mp_output;
OutputContainer *mp_intersections;
std::set<db::Point> m_intersections;
};
/**
+20 -20
View File
@@ -991,9 +991,9 @@ public:
* Merged semantics applies. If merged semantics is chosen, the connected edge parts will be
* selected as a whole.
*/
Edges &select_interacting (const Region &other)
Edges &select_interacting (const Region &other, size_t min_count = 1, size_t max_count = std::numeric_limits<size_t>::max ())
{
set_delegate (mp_delegate->selected_interacting (other));
set_delegate (mp_delegate->selected_interacting (other, min_count, max_count));
return *this;
}
@@ -1002,9 +1002,9 @@ public:
*
* This method is an out-of-place version of select_interacting.
*/
Edges selected_interacting (const Region &other) const
Edges selected_interacting (const Region &other, size_t min_count = 1, size_t max_count = std::numeric_limits<size_t>::max ()) const
{
return Edges (mp_delegate->selected_interacting (other));
return Edges (mp_delegate->selected_interacting (other, min_count, max_count));
}
/**
@@ -1013,9 +1013,9 @@ public:
* Merged semantics applies. If merged semantics is chosen, the connected edge parts will be
* selected as a whole.
*/
Edges &select_not_interacting (const Region &other)
Edges &select_not_interacting (const Region &other, size_t min_count = 1, size_t max_count = std::numeric_limits<size_t>::max ())
{
set_delegate (mp_delegate->selected_not_interacting (other));
set_delegate (mp_delegate->selected_not_interacting (other, min_count, max_count));
return *this;
}
@@ -1024,17 +1024,17 @@ public:
*
* This method is an out-of-place version of select_not_interacting.
*/
Edges selected_not_interacting (const Region &other) const
Edges selected_not_interacting (const Region &other, size_t min_count = 1, size_t max_count = std::numeric_limits<size_t>::max ()) const
{
return Edges (mp_delegate->selected_not_interacting (other));
return Edges (mp_delegate->selected_not_interacting (other, min_count, max_count));
}
/**
* @brief Returns all edges of this edge set which do not overlap or touch with polygons from the region together with the ones that do not
*/
std::pair<Edges, Edges> selected_interacting_differential (const Region &other) const
std::pair<Edges, Edges> selected_interacting_differential (const Region &other, size_t min_count = 1, size_t max_count = std::numeric_limits<size_t>::max ()) const
{
std::pair<db::EdgesDelegate *, db::EdgesDelegate *> p = mp_delegate->selected_interacting_pair (other);
std::pair<db::EdgesDelegate *, db::EdgesDelegate *> p = mp_delegate->selected_interacting_pair (other, min_count, max_count);
return std::pair<Edges, Edges> (Edges (p.first), Edges (p.second));
}
@@ -1280,9 +1280,9 @@ public:
* Merged semantics applies. If merged semantics is chosen, the connected edge parts will be
* selected as a whole.
*/
Edges &select_interacting (const Edges &other)
Edges &select_interacting (const Edges &other, size_t min_count = 1, size_t max_count = std::numeric_limits<size_t>::max ())
{
set_delegate (mp_delegate->selected_interacting (other));
set_delegate (mp_delegate->selected_interacting (other, min_count, max_count));
return *this;
}
@@ -1291,17 +1291,17 @@ public:
*
* This method is an out-of-place version of select_interacting.
*/
Edges selected_interacting (const Edges &other) const
Edges selected_interacting (const Edges &other, size_t min_count = 1, size_t max_count = std::numeric_limits<size_t>::max ()) const
{
return Edges (mp_delegate->selected_interacting (other));
return Edges (mp_delegate->selected_interacting (other, min_count, max_count));
}
/**
* @brief Returns all edges of this edge set which do not overlap or touch with edges from the other edge set together with the ones that do not
*/
std::pair<Edges, Edges> selected_interacting_differential (const Edges &other) const
std::pair<Edges, Edges> selected_interacting_differential (const Edges &other, size_t min_count = 1, size_t max_count = std::numeric_limits<size_t>::max ()) const
{
std::pair<db::EdgesDelegate *, db::EdgesDelegate *> p = mp_delegate->selected_interacting_pair (other);
std::pair<db::EdgesDelegate *, db::EdgesDelegate *> p = mp_delegate->selected_interacting_pair (other, min_count, max_count);
return std::pair<Edges, Edges> (Edges (p.first), Edges (p.second));
}
@@ -1311,9 +1311,9 @@ public:
* Merged semantics applies. If merged semantics is chosen, the connected edge parts will be
* selected as a whole.
*/
Edges &select_not_interacting (const Edges &other)
Edges &select_not_interacting (const Edges &other, size_t min_count = 1, size_t max_count = std::numeric_limits<size_t>::max ())
{
set_delegate (mp_delegate->selected_not_interacting (other));
set_delegate (mp_delegate->selected_not_interacting (other, min_count, max_count));
return *this;
}
@@ -1322,9 +1322,9 @@ public:
*
* This method is an out-of-place version of select_not_interacting.
*/
Edges selected_not_interacting (const Edges &other) const
Edges selected_not_interacting (const Edges &other, size_t min_count = 1, size_t max_count = std::numeric_limits<size_t>::max ()) const
{
return Edges (mp_delegate->selected_not_interacting (other));
return Edges (mp_delegate->selected_not_interacting (other, min_count, max_count));
}
/**
+6 -6
View File
@@ -255,12 +255,12 @@ public:
virtual std::pair<EdgesDelegate *, EdgesDelegate *> inside_outside_part_pair (const Region &other) const = 0;
virtual RegionDelegate *pull_interacting (const Region &) const = 0;
virtual EdgesDelegate *pull_interacting (const Edges &) const = 0;
virtual EdgesDelegate *selected_interacting (const Region &other) const = 0;
virtual EdgesDelegate *selected_not_interacting (const Region &other) const = 0;
virtual EdgesDelegate *selected_interacting (const Edges &other) const = 0;
virtual EdgesDelegate *selected_not_interacting (const Edges &other) const = 0;
virtual std::pair<EdgesDelegate *, EdgesDelegate *> selected_interacting_pair (const Region &other) const = 0;
virtual std::pair<EdgesDelegate *, EdgesDelegate *> selected_interacting_pair (const Edges &other) const = 0;
virtual EdgesDelegate *selected_interacting (const Region &other, size_t min_count, size_t max_count) const = 0;
virtual EdgesDelegate *selected_not_interacting (const Region &other, size_t min_count, size_t max_count) const = 0;
virtual EdgesDelegate *selected_interacting (const Edges &other, size_t min_count, size_t max_count) const = 0;
virtual EdgesDelegate *selected_not_interacting (const Edges &other, size_t min_count, size_t max_count) const = 0;
virtual std::pair<EdgesDelegate *, EdgesDelegate *> selected_interacting_pair (const Region &other, size_t min_count, size_t max_count) const = 0;
virtual std::pair<EdgesDelegate *, EdgesDelegate *> selected_interacting_pair (const Edges &other, size_t min_count, size_t max_count) const = 0;
virtual EdgesDelegate *selected_outside (const Region &other) const = 0;
virtual EdgesDelegate *selected_not_outside (const Region &other) const = 0;
+355
View File
@@ -94,6 +94,9 @@ EdgeBoolAndOrNotLocalOperation::do_compute_local (db::Layout * /*layout*/, db::C
if (! is_and) {
result.insert (subject);
}
if (result2) {
result2->insert (subject);
}
} else {
scanner.insert (&subject, 0);
any_subject = true;
@@ -199,5 +202,357 @@ EdgeToPolygonLocalOperation::do_compute_local (db::Layout * /*layout*/, db::Cell
}
}
// ---------------------------------------------------------------------------------------------
// Edge2EdgeInteractingLocalOperation implementation
Edge2EdgeInteractingLocalOperation::Edge2EdgeInteractingLocalOperation (EdgeInteractionMode mode, output_mode_t output_mode, size_t min_count, size_t max_count)
: m_mode (mode), m_output_mode (output_mode), m_min_count (min_count), m_max_count (max_count)
{
// .. nothing yet ..
}
db::Coord Edge2EdgeInteractingLocalOperation::dist () const
{
// touching is sufficient
return 1;
}
void Edge2EdgeInteractingLocalOperation::do_compute_local (db::Layout * /*layout*/, db::Cell * /*cell*/, const shape_interactions<db::Edge, db::Edge> &interactions, std::vector<std::unordered_set<db::Edge> > &results, const db::LocalProcessorBase * /*proc*/) const
{
tl_assert (results.size () == (m_output_mode == Both ? 2 : 1));
std::unordered_set<db::Edge> &result = results.front ();
std::unordered_set<db::Edge> *result2 = 0;
if (m_output_mode == Both) {
result2 = &results[1];
}
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).second);
}
}
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_output_mode == Inverse || m_output_mode == Both) {
std::unordered_set<db::Edge> interacting;
edge_interaction_filter<std::unordered_set<db::Edge> > filter (interacting, m_mode, m_min_count, m_max_count);
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 ()) {
if (m_output_mode != Both) {
result.insert (subject);
} else {
result2->insert (subject);
}
} else if (m_output_mode == Both) {
result.insert (subject);
}
}
} else {
edge_interaction_filter<std::unordered_set<db::Edge> > filter (result, m_mode, m_min_count, m_max_count);
scanner.process (filter, 1, db::box_convert<db::Edge> ());
}
}
OnEmptyIntruderHint Edge2EdgeInteractingLocalOperation::on_empty_intruder_hint () const
{
if (m_mode == EdgesOutside) {
return m_output_mode == Both ? Copy : (m_output_mode == Inverse ? Drop : Copy);
} else {
return m_output_mode == Both ? CopyToSecond : (m_output_mode == Inverse ? Copy : Drop);
}
}
std::string Edge2EdgeInteractingLocalOperation::description () const
{
return tl::to_string (tr ("Select interacting edges"));
}
// ---------------------------------------------------------------------------------------------
// Edge2EdgePullLocalOperation implementation
Edge2EdgePullLocalOperation::Edge2EdgePullLocalOperation ()
{
// .. nothing yet ..
}
db::Coord Edge2EdgePullLocalOperation::dist () const
{
// touching is sufficient
return 1;
}
void Edge2EdgePullLocalOperation::do_compute_local (db::Layout * /*layout*/, db::Cell * /*cell*/, const shape_interactions<db::Edge, db::Edge> &interactions, std::vector<std::unordered_set<db::Edge> > &results, const db::LocalProcessorBase * /*proc*/) const
{
tl_assert (results.size () == 1);
std::unordered_set<db::Edge> &result = results.front ();
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).second);
}
}
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, 1);
}
for (std::set<db::Edge>::const_iterator o = others.begin (); o != others.end (); ++o) {
scanner.insert (o.operator-> (), 0);
}
edge_interaction_filter<std::unordered_set<db::Edge> > filter (result, EdgesInteract, size_t (1), std::numeric_limits<size_t>::max ());
scanner.process (filter, 1, db::box_convert<db::Edge> ());
}
OnEmptyIntruderHint Edge2EdgePullLocalOperation::on_empty_intruder_hint () const
{
return Drop;
}
std::string Edge2EdgePullLocalOperation::description () const
{
return tl::to_string (tr ("Select interacting edges from other"));
}
// ---------------------------------------------------------------------------------------------
// Edge2EdgePullLocalOperation implementation
template <class TI>
edge_to_polygon_interacting_local_operation<TI>::edge_to_polygon_interacting_local_operation (EdgeInteractionMode mode, output_mode_t output_mode, size_t min_count, size_t max_count)
: m_mode (mode), m_output_mode (output_mode), m_min_count (min_count), m_max_count (max_count)
{
// .. nothing yet ..
}
template <class TI>
db::Coord edge_to_polygon_interacting_local_operation<TI>::dist () const
{
// touching is sufficient
return 1;
}
static const db::Polygon *deref (const db::Polygon &poly, std::list<db::Polygon> &)
{
return &poly;
}
static const db::Polygon *deref (const db::PolygonRef &pref, std::list<db::Polygon> &heap)
{
heap.push_back (pref.obj ().transformed (pref.trans ()));
return & heap.back ();
}
template <class TI>
void edge_to_polygon_interacting_local_operation<TI>::do_compute_local (db::Layout * /*layout*/, db::Cell * /*cell*/, const shape_interactions<db::Edge, TI> &interactions, std::vector<std::unordered_set<db::Edge> > &results, const db::LocalProcessorBase * /*proc*/) const
{
tl_assert (results.size () == size_t (m_output_mode == Both ? 2 : 1));
std::unordered_set<db::Edge> &result = results.front ();
std::unordered_set<db::Edge> *result2 = 0;
if (m_output_mode == Both) {
result2 = &results[1];
}
db::box_scanner2<db::Edge, size_t, db::Polygon, size_t> scanner;
std::set<TI> others;
for (typename shape_interactions<db::Edge, TI>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
for (typename shape_interactions<db::Edge, TI>::iterator2 j = i->second.begin (); j != i->second.end (); ++j) {
others.insert (interactions.intruder_shape (*j).second);
}
}
for (typename shape_interactions<db::Edge, TI>::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 (typename std::set<TI>::const_iterator o = others.begin (); o != others.end (); ++o) {
scanner.insert2 (deref (*o, heap), 1);
}
if (m_output_mode == Inverse || m_output_mode == Both) {
std::unordered_set<db::Edge> interacting;
edge_to_polygon_interaction_filter<std::unordered_set<db::Edge> > filter (&interacting, m_mode, m_min_count, m_max_count);
scanner.process (filter, 1, db::box_convert<db::Edge> (), db::box_convert<db::Polygon> ());
for (typename shape_interactions<db::Edge, TI>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
const db::Edge &subject = interactions.subject_shape (i->first);
if (interacting.find (subject) == interacting.end ()) {
if (m_output_mode != Both) {
result.insert (subject);
} else {
result2->insert (subject);
}
} else if (m_output_mode == Both) {
result.insert (subject);
}
}
} else {
edge_to_polygon_interaction_filter<std::unordered_set<db::Edge> > filter (&result, m_mode, m_min_count, m_max_count);
scanner.process (filter, 1, db::box_convert<db::Edge> (), db::box_convert<db::Polygon> ());
}
}
template <class TI>
OnEmptyIntruderHint edge_to_polygon_interacting_local_operation<TI>::on_empty_intruder_hint () const
{
if (m_mode == EdgesOutside) {
return m_output_mode == Both ? Copy : (m_output_mode == Inverse ? Drop : Copy);
} else {
return m_output_mode == Both ? CopyToSecond : (m_output_mode == Inverse ? Copy : Drop);
}
}
template <class TI>
std::string edge_to_polygon_interacting_local_operation<TI>::description () const
{
if (m_mode == EdgesInteract) {
if (m_output_mode == Inverse) {
return tl::to_string (tr ("Select non-interacting edges"));
} else if (m_output_mode == Normal) {
return tl::to_string (tr ("Select interacting edges"));
} else {
return tl::to_string (tr ("Select interacting and non-interacting edges"));
}
} else if (m_mode == EdgesInside) {
if (m_output_mode == Inverse) {
return tl::to_string (tr ("Select non-inside edges"));
} else if (m_output_mode == Normal) {
return tl::to_string (tr ("Select inside edges"));
} else {
return tl::to_string (tr ("Select inside and non-inside edges"));
}
} else if (m_mode == EdgesOutside) {
if (m_output_mode == Inverse) {
return tl::to_string (tr ("Select non-outside edges"));
} else if (m_output_mode == Normal) {
return tl::to_string (tr ("Select outside edges"));
} else {
return tl::to_string (tr ("Select outside and non-outside edges"));
}
}
return std::string ();
}
template class edge_to_polygon_interacting_local_operation<db::Polygon>;
template class edge_to_polygon_interacting_local_operation<db::PolygonRef>;
// ---------------------------------------------------------------------------------------------
// Edge2EdgePullLocalOperation implementation
namespace {
struct ResultInserter
{
typedef db::Polygon value_type;
ResultInserter (db::Layout *layout, std::unordered_set<db::PolygonRef> &result)
: mp_layout (layout), mp_result (&result)
{
// .. nothing yet ..
}
void insert (const db::Polygon &p)
{
(*mp_result).insert (db::PolygonRef (p, mp_layout->shape_repository ()));
}
private:
db::Layout *mp_layout;
std::unordered_set<db::PolygonRef> *mp_result;
};
}
Edge2PolygonPullLocalOperation::Edge2PolygonPullLocalOperation ()
{
// .. nothing yet ..
}
db::Coord Edge2PolygonPullLocalOperation::dist () const
{
// touching is sufficient
return 1;
}
void Edge2PolygonPullLocalOperation::do_compute_local (db::Layout *layout, db::Cell * /*cell*/, const shape_interactions<db::Edge, db::PolygonRef> &interactions, std::vector<std::unordered_set<db::PolygonRef> > &results, const db::LocalProcessorBase * /*proc*/) const
{
tl_assert (results.size () == 1);
std::unordered_set<db::PolygonRef> &result = results.front ();
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).second);
}
}
for (shape_interactions<db::Edge, db::PolygonRef>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
const db::Edge &subject = interactions.subject_shape (i->first);
scanner.insert1 (&subject, 1);
}
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 (), 0);
}
ResultInserter inserter (layout, result);
edge_to_polygon_interaction_filter<ResultInserter> filter (&inserter, EdgesInteract, size_t (1), std::numeric_limits<size_t>::max ());
scanner.process (filter, 1, db::box_convert<db::Edge> (), db::box_convert<db::Polygon> ());
}
OnEmptyIntruderHint Edge2PolygonPullLocalOperation::on_empty_intruder_hint () const
{
return Drop;
}
std::string Edge2PolygonPullLocalOperation::description () const
{
return tl::to_string (tr ("Select interacting regions"));
}
}
+76
View File
@@ -31,6 +31,7 @@
#include "dbEdgeBoolean.h"
#include "dbEdgeProcessor.h"
#include "dbLocalOperation.h"
#include "dbEdgesUtils.h"
namespace db
{
@@ -79,6 +80,81 @@ private:
bool m_include_borders;
};
/**
* @brief Implements edge-to-edge interactions
*/
class DB_PUBLIC Edge2EdgeInteractingLocalOperation
: public local_operation<db::Edge, db::Edge, db::Edge>
{
public:
enum output_mode_t { Normal, Inverse, Both };
Edge2EdgeInteractingLocalOperation (EdgeInteractionMode mode, output_mode_t output_mode, size_t min_count, size_t max_count);
virtual db::Coord dist () const;
virtual void do_compute_local (db::Layout * /*layout*/, db::Cell * /*cell*/, const shape_interactions<db::Edge, db::Edge> &interactions, std::vector<std::unordered_set<db::Edge> > &results, const db::LocalProcessorBase * /*proc*/) const;
virtual OnEmptyIntruderHint on_empty_intruder_hint () const;
virtual std::string description () const;
private:
EdgeInteractionMode m_mode;
output_mode_t m_output_mode;
size_t m_min_count, m_max_count;
};
/**
* @brief Implements edge-to-edge interactions (pull mode)
*/
class DB_PUBLIC Edge2EdgePullLocalOperation
: public local_operation<db::Edge, db::Edge, db::Edge>
{
public:
Edge2EdgePullLocalOperation ();
virtual db::Coord dist () const;
virtual void do_compute_local (db::Layout * /*layout*/, db::Cell * /*cell*/, const shape_interactions<db::Edge, db::Edge> &interactions, std::vector<std::unordered_set<db::Edge> > &results, const db::LocalProcessorBase * /*proc*/) const;
virtual OnEmptyIntruderHint on_empty_intruder_hint () const;
virtual std::string description () const;
};
/**
* @brief Implements edge-to-polygon interactions
*/
template<class TI>
class DB_PUBLIC edge_to_polygon_interacting_local_operation
: public local_operation<db::Edge, TI, db::Edge>
{
public:
enum output_mode_t { Normal, Inverse, Both };
edge_to_polygon_interacting_local_operation (EdgeInteractionMode mode, output_mode_t output_mode, size_t min_count, size_t max_count);
virtual db::Coord dist () const;
virtual void do_compute_local (db::Layout * /*layout*/, db::Cell * /*cell*/, const shape_interactions<db::Edge, TI> &interactions, std::vector<std::unordered_set<db::Edge> > &results, const db::LocalProcessorBase * /*proc*/) const;
virtual OnEmptyIntruderHint on_empty_intruder_hint () const;
virtual std::string description () const;
private:
EdgeInteractionMode m_mode;
output_mode_t m_output_mode;
size_t m_min_count, m_max_count;
};
/**
* @brief Implements edge-to-polygon interactions (pull mode)
*/
class DB_PUBLIC Edge2PolygonPullLocalOperation
: public local_operation<db::Edge, db::PolygonRef, db::PolygonRef>
{
public:
Edge2PolygonPullLocalOperation ();
virtual db::Coord dist () const;
virtual void do_compute_local (db::Layout *layout, db::Cell * /*cell*/, const shape_interactions<db::Edge, db::PolygonRef> &interactions, std::vector<std::unordered_set<db::PolygonRef> > &results, const db::LocalProcessorBase * /*proc*/) const;
virtual OnEmptyIntruderHint on_empty_intruder_hint () const;
virtual std::string description () const;
};
}
#endif
+23 -10
View File
@@ -189,17 +189,22 @@ EdgeSegmentSelector::process (const db::Edge &edge, std::vector<db::Edge> &res)
{
double l = std::max (edge.double_length () * m_fraction, double (m_length));
db::DVector ds;
if (! edge.is_degenerate ()) {
ds = db::DVector (edge.d ()) * (l / edge.double_length ());
}
if (m_mode < 0) {
res.push_back (db::Edge (edge.p1 (), db::Point (db::DPoint (edge.p1 ()) + db::DVector (edge.d ()) * (l / edge.double_length ()))));
res.push_back (db::Edge (edge.p1 (), db::Point (db::DPoint (edge.p1 ()) + ds)));
} else if (m_mode > 0) {
res.push_back (db::Edge (db::Point (db::DPoint (edge.p2 ()) - db::DVector (edge.d ()) * (l / edge.double_length ())), edge.p2 ()));
res.push_back (db::Edge (db::Point (db::DPoint (edge.p2 ()) - ds), edge.p2 ()));
} else {
db::DVector dl = db::DVector (edge.d ()) * (0.5 * l / edge.double_length ());
db::DVector dl = ds * 0.5;
db::DPoint center = db::DPoint (edge.p1 ()) + db::DVector (edge.p2 () - edge.p1 ()) * 0.5;
res.push_back (db::Edge (db::Point (center - dl), db::Point (center + dl)));
@@ -403,16 +408,24 @@ struct DetectTagEdgeSink
static bool
edge_is_inside_or_outside (bool outside, const db::Edge &a, const db::Polygon &b)
{
db::EdgeProcessor ep;
ep.insert (b, 0);
if (a.is_degenerate ()) {
ep.insert (a, 1);
return ((db::inside_poly (b.begin_edge (), a.p1 ()) <= 0) == outside);
DetectTagEdgeSink es (outside ? 1 : 2); // 2 is the "outside" tag in "Both" mode -> this makes inside fail
db::EdgePolygonOp op (db::EdgePolygonOp::Both, true /*include borders*/);
ep.process (es, op);
} else {
return es.result;
db::EdgeProcessor ep;
ep.insert (b, 0);
ep.insert (a, 1);
DetectTagEdgeSink es (outside ? 1 : 2); // 2 is the "outside" tag in "Both" mode -> this makes inside fail
db::EdgePolygonOp op (db::EdgePolygonOp::Both, !outside /*include borders in inside*/);
ep.process (es, op);
return es.result;
}
}
bool edge_is_inside (const db::Edge &a, const db::Polygon &b)
+82 -15
View File
@@ -339,16 +339,39 @@ class edge_interaction_filter
: public db::box_scanner_receiver<db::Edge, size_t>
{
public:
edge_interaction_filter (OutputContainer &output, EdgeInteractionMode mode)
: mp_output (&output), m_mode (mode)
edge_interaction_filter (OutputContainer &output, EdgeInteractionMode mode, size_t min_count, size_t max_count)
: mp_output (&output), m_mode (mode), m_min_count (min_count), m_max_count (max_count)
{
// .. nothing yet ..
// NOTE: "counting" does not really make much sense in Outside mode ...
m_counting = !(min_count == 1 && max_count == std::numeric_limits<size_t>::max ());
tl_assert (!m_counting || mode != EdgesOutside);
}
void finish (const db::Edge *o, size_t p)
{
if (p == 0 && m_mode == EdgesOutside && m_seen.find (o) == m_seen.end ()) {
mp_output->insert (*o);
if (p != 0) {
return;
}
if (m_counting) {
size_t count = 0;
auto i = m_counts.find (o);
if (i != m_counts.end ()) {
count = i->second;
}
bool match = (count >= m_min_count && count <= m_max_count);
if (match == (m_mode != EdgesOutside)) {
mp_output->insert (*o);
}
} else {
if (m_mode == EdgesOutside && m_seen.find (o) == m_seen.end ()) {
mp_output->insert (*o);
}
}
}
@@ -363,14 +386,22 @@ public:
if ((m_mode == EdgesInteract && db::edge_interacts (*o, *oo)) ||
(m_mode == EdgesInside && db::edge_is_inside (*o, *oo))) {
if (m_seen.insert (o).second) {
mp_output->insert (*o);
if (m_counting) {
m_counts[o] += 1;
} else {
if (m_seen.insert (o).second) {
mp_output->insert (*o);
}
}
} else if (m_mode == EdgesOutside && ! db::edge_is_outside (*o, *oo)) {
// In this case we need to collect edges which are outside always - we report those on "finished".
m_seen.insert (o);
if (m_counting) {
m_counts[o] += 1;
} else {
m_seen.insert (o);
}
}
@@ -380,7 +411,10 @@ public:
private:
OutputContainer *mp_output;
std::set<const db::Edge *> m_seen;
std::map<const db::Edge *, size_t> m_counts;
EdgeInteractionMode m_mode;
size_t m_min_count, m_max_count;
bool m_counting;
};
/**
@@ -408,20 +442,39 @@ DB_PUBLIC bool edge_is_outside (const db::Edge &a, const db::Polygon &b);
* There is a special box converter which is able to sort that out as well.
*/
template <class OutputContainer, class OutputType = typename OutputContainer::value_type>
class edge_to_region_interaction_filter
class edge_to_polygon_interaction_filter
: public db::box_scanner_receiver2<db::Edge, size_t, db::Polygon, size_t>
{
public:
edge_to_region_interaction_filter (OutputContainer *output, EdgeInteractionMode mode)
: mp_output (output), m_mode (mode)
edge_to_polygon_interaction_filter (OutputContainer *output, EdgeInteractionMode mode, size_t min_count, size_t max_count)
: mp_output (output), m_mode (mode), m_min_count (min_count), m_max_count (max_count)
{
// .. nothing yet ..
// NOTE: "counting" does not really make much sense in Outside mode ...
m_counting = !(min_count == 1 && max_count == std::numeric_limits<size_t>::max ());
tl_assert (!m_counting || mode != EdgesOutside);
}
void finish (const OutputType *o)
{
if (m_mode == EdgesOutside && m_seen.find (o) == m_seen.end ()) {
mp_output->insert (*o);
if (m_counting) {
size_t count = 0;
auto i = m_counts.find (o);
if (i != m_counts.end ()) {
count = i->second;
}
bool match = (count >= m_min_count && count <= m_max_count);
if (match == (m_mode != EdgesOutside)) {
mp_output->insert (*o);
}
} else {
if (m_mode == EdgesOutside && m_seen.find (o) == m_seen.end ()) {
mp_output->insert (*o);
}
}
}
@@ -448,7 +501,18 @@ public:
const OutputType *ep = 0;
tl::select (ep, e, p);
if (m_seen.find (ep) == m_seen.end ()) {
if (m_counting) {
if ((m_mode == EdgesInteract && db::edge_interacts (*e, *p)) ||
(m_mode == EdgesInside && db::edge_is_inside (*e, *p)) ||
(m_mode == EdgesOutside && ! db::edge_is_outside (*e, *p))) {
// we report the result on "finish" here.
m_counts[ep] += 1;
}
} else if (m_seen.find (ep) == m_seen.end ()) {
if ((m_mode == EdgesInteract && db::edge_interacts (*e, *p)) ||
(m_mode == EdgesInside && db::edge_is_inside (*e, *p))) {
@@ -468,8 +532,11 @@ public:
private:
OutputContainer *mp_output;
std::map<const OutputType *, size_t> m_counts;
std::set<const OutputType *> m_seen;
EdgeInteractionMode m_mode;
size_t m_min_count, m_max_count;
bool m_counting;
};
/**
+6 -6
View File
@@ -94,12 +94,12 @@ public:
virtual RegionDelegate *pull_interacting (const Region &) const;
virtual EdgesDelegate *pull_interacting (const Edges &) const { return new EmptyEdges (); }
virtual EdgesDelegate *selected_interacting (const Edges &) const { return new EmptyEdges (); }
virtual EdgesDelegate *selected_not_interacting (const Edges &) const { return new EmptyEdges (); }
virtual EdgesDelegate *selected_interacting (const Region &) const { return new EmptyEdges (); }
virtual EdgesDelegate *selected_not_interacting (const Region &) const { return new EmptyEdges (); }
virtual std::pair<EdgesDelegate *, EdgesDelegate *> selected_interacting_pair (const Region &) const { return std::make_pair (new EmptyEdges (), new EmptyEdges ()); }
virtual std::pair<EdgesDelegate *, EdgesDelegate *> selected_interacting_pair (const Edges &) const { return std::make_pair (new EmptyEdges (), new EmptyEdges ()); }
virtual EdgesDelegate *selected_interacting (const Edges &, size_t, size_t) const { return new EmptyEdges (); }
virtual EdgesDelegate *selected_not_interacting (const Edges &, size_t, size_t) const { return new EmptyEdges (); }
virtual EdgesDelegate *selected_interacting (const Region &, size_t, size_t) const { return new EmptyEdges (); }
virtual EdgesDelegate *selected_not_interacting (const Region &, size_t, size_t) const { return new EmptyEdges (); }
virtual std::pair<EdgesDelegate *, EdgesDelegate *> selected_interacting_pair (const Region &, size_t, size_t) const { return std::make_pair (new EmptyEdges (), new EmptyEdges ()); }
virtual std::pair<EdgesDelegate *, EdgesDelegate *> selected_interacting_pair (const Edges &, size_t, size_t) const { return std::make_pair (new EmptyEdges (), new EmptyEdges ()); }
virtual EdgesDelegate *selected_outside (const Region &) const { return new EmptyEdges (); }
virtual EdgesDelegate *selected_not_outside (const Region &) const { return new EmptyEdges (); }
+1 -1
View File
@@ -176,7 +176,7 @@ EmptyRegion::angle_check (double, double, bool) const
}
EdgesDelegate *
EmptyRegion::edges (const EdgeFilterBase *) const
EmptyRegion::edges (const EdgeFilterBase *, const PolygonToEdgeProcessorBase *) const
{
return new EmptyEdges ();
}
+1 -1
View File
@@ -82,7 +82,7 @@ public:
virtual RegionDelegate *scaled_and_snapped_in_place (db::Coord, db::Coord, db::Coord, db::Coord, db::Coord, db::Coord) { return this; }
virtual RegionDelegate *scaled_and_snapped (db::Coord, db::Coord, db::Coord, db::Coord, db::Coord, db::Coord) { return new EmptyRegion (); }
virtual EdgesDelegate *edges (const EdgeFilterBase *) const;
virtual EdgesDelegate *edges (const EdgeFilterBase *, const PolygonToEdgeProcessorBase *) const;
virtual RegionDelegate *filter_in_place (const PolygonFilterBase &) { return this; }
virtual RegionDelegate *filtered (const PolygonFilterBase &) const { return new EmptyRegion (); }
virtual RegionDelegate *process_in_place (const PolygonProcessorBase &) { return this; }
+2 -6
View File
@@ -133,9 +133,7 @@ FlatEdges::ensure_merged_edges_valid () const
scanner.reserve (mp_edges->size ());
for (EdgesIterator e (begin ()); ! e.at_end (); ++e) {
if (! e->is_degenerate ()) {
scanner.insert (&*e, 0);
}
scanner.insert (&*e, 0);
}
scanner.process (cluster_collector, 1, db::box_convert<db::Edge> ());
@@ -145,9 +143,7 @@ FlatEdges::ensure_merged_edges_valid () const
std::map<db::properties_id_type, std::vector<const db::Edge *> > edges_by_props;
for (EdgesIterator e (begin ()); ! e.at_end (); ++e) {
if (! e->is_degenerate ()) {
edges_by_props [e.prop_id ()].push_back (e.operator-> ());
}
edges_by_props [e.prop_id ()].push_back (e.operator-> ());
}
for (auto s2p = edges_by_props.begin (); s2p != edges_by_props.end (); ++s2p) {
+5
View File
@@ -2575,6 +2575,7 @@ template class DB_PUBLIC local_processor_cell_contexts<db::PolygonRef, db::Edge,
template class DB_PUBLIC local_processor_cell_contexts<db::PolygonRef, db::PolygonRef, db::EdgePair>;
template class DB_PUBLIC local_processor_cell_contexts<db::Polygon, db::Polygon, db::EdgePair>;
template class DB_PUBLIC local_processor_cell_contexts<db::Edge, db::PolygonRef, db::Edge>;
template class DB_PUBLIC local_processor_cell_contexts<db::Edge, db::Polygon, db::Edge>;
template class DB_PUBLIC local_processor_cell_contexts<db::Edge, db::Edge, db::Edge>;
template class DB_PUBLIC local_processor_cell_contexts<db::Edge, db::Edge, db::EdgePair>;
@@ -2591,6 +2592,7 @@ template class DB_PUBLIC shape_interactions<db::PolygonRef, db::Text>;
template class DB_PUBLIC shape_interactions<db::PolygonRef, db::Edge>;
template class DB_PUBLIC shape_interactions<db::Edge, db::Edge>;
template class DB_PUBLIC shape_interactions<db::Edge, db::PolygonRef>;
template class DB_PUBLIC shape_interactions<db::Edge, db::Polygon>;
template class DB_PUBLIC shape_interactions<db::TextRef, db::TextRef>;
template class DB_PUBLIC shape_interactions<db::TextRef, db::PolygonRef>;
@@ -2621,6 +2623,7 @@ template class DB_PUBLIC local_processor_context_computation_task<db::Polygon, d
template class DB_PUBLIC local_processor_context_computation_task<db::Polygon, db::Polygon, db::Edge>;
template class DB_PUBLIC local_processor_context_computation_task<db::Edge, db::Edge, db::Edge>;
template class DB_PUBLIC local_processor_context_computation_task<db::Edge, db::PolygonRef, db::Edge>;
template class DB_PUBLIC local_processor_context_computation_task<db::Edge, db::Polygon, db::Edge>;
template class DB_PUBLIC local_processor_context_computation_task<db::Edge, db::Edge, db::EdgePair>;
template class DB_PUBLIC local_processor_context_computation_task<db::Edge, db::PolygonRef, db::PolygonRef>;
@@ -2644,6 +2647,7 @@ template class DB_PUBLIC local_processor_result_computation_task<db::PolygonRef,
template class DB_PUBLIC local_processor_result_computation_task<db::Polygon, db::Polygon, db::EdgePair>;
template class DB_PUBLIC local_processor_result_computation_task<db::Edge, db::Edge, db::Edge>;
template class DB_PUBLIC local_processor_result_computation_task<db::Edge, db::PolygonRef, db::Edge>;
template class DB_PUBLIC local_processor_result_computation_task<db::Edge, db::Polygon, db::Edge>;
template class DB_PUBLIC local_processor_result_computation_task<db::Edge, db::Edge, db::EdgePair>;
// explicit instantiations
@@ -2671,6 +2675,7 @@ template class DB_PUBLIC local_processor<db::Polygon, db::Polygon, db::EdgePair>
template class DB_PUBLIC local_processor<db::Polygon, db::Polygon, db::Edge>;
template class DB_PUBLIC local_processor<db::Edge, db::Edge, db::Edge>;
template class DB_PUBLIC local_processor<db::Edge, db::PolygonRef, db::Edge>;
template class DB_PUBLIC local_processor<db::Edge, db::Polygon, db::Edge>;
template class DB_PUBLIC local_processor<db::Edge, db::PolygonRef, db::PolygonRef>;
template class DB_PUBLIC local_processor<db::Edge, db::Edge, db::EdgePair>;
template class DB_PUBLIC local_processor<db::TextRef, db::PolygonRef, db::TextRef>;
+1
View File
@@ -101,6 +101,7 @@ template class DB_PUBLIC local_operation<db::Polygon, db::Polygon, db::EdgePair>
template class DB_PUBLIC local_operation<db::Polygon, db::TextRef, db::TextRef>;
template class DB_PUBLIC local_operation<db::Edge, db::Edge, db::Edge>;
template class DB_PUBLIC local_operation<db::Edge, db::PolygonRef, db::Edge>;
template class DB_PUBLIC local_operation<db::Edge, db::Polygon, db::Edge>;
template class DB_PUBLIC local_operation<db::Edge, db::PolygonRef, db::PolygonRef>;
template class DB_PUBLIC local_operation<db::Edge, db::Edge, db::EdgePair>;
template class DB_PUBLIC local_operation<db::TextRef, db::PolygonRef, db::PolygonRef>;
+10 -3
View File
@@ -556,16 +556,23 @@ Region::texts_as_dots (const std::string &pat, bool pattern, db::DeepShapeStore
fill_texts (si.first, pat, pattern, dot_delivery<db::FlatEdges> (), res.get (), si.second, dr);
return Edges (res.release ());
Edges edges (res.release ());
edges.set_merged_semantics (false);
return edges;
}
db::Edges edges;
text_shape_receiver<dot_delivery<db::Shapes> > pipe = text_shape_receiver<dot_delivery<db::Shapes> > (dot_delivery<db::Shapes> (), pat, pattern, dr);
if (dr && dr->deep_layer ().store () == &store) {
return Edges (new db::DeepEdges (store.create_copy (dr->deep_layer (), &pipe)));
edges = Edges (new db::DeepEdges (store.create_copy (dr->deep_layer (), &pipe)));
} else {
return Edges (new db::DeepEdges (store.create_custom_layer (si.first, &pipe, si.second)));
edges = Edges (new db::DeepEdges (store.create_custom_layer (si.first, &pipe, si.second)));
}
edges.set_merged_semantics (false);
return edges;
}
Region
+29 -2
View File
@@ -770,7 +770,7 @@ public:
*/
Edges edges () const
{
return Edges (mp_delegate->edges (0));
return Edges (mp_delegate->edges (0, 0));
}
/**
@@ -783,7 +783,34 @@ public:
*/
Edges edges (const EdgeFilterBase &filter) const
{
return mp_delegate->edges (&filter);
return mp_delegate->edges (&filter, 0);
}
/**
* @brief Returns an edge set containing all edges of the polygons in this region
*
* Merged semantics applies. In merged semantics, only full, outer edges are delivered.
* This version allows specifying a polygon to edge processor with additional features
* like extraction of convex edges only.
*/
Edges edges (const db::PolygonToEdgeProcessorBase &proc) const
{
return Edges (mp_delegate->edges (0, &proc));
}
/**
* @brief Returns an edge set containing all edges of the polygons in this region
*
* This version allows one to specify a filter by which the edges are filtered before they are
* returned.
*
* Merged semantics applies. In merged semantics, only full, outer edges are delivered.
* This version allows specifying a polygon to edge processor with additional features
* like extraction of convex edges only.
*/
Edges edges (const EdgeFilterBase &filter, const db::PolygonToEdgeProcessorBase &proc) const
{
return mp_delegate->edges (&filter, &proc);
}
/**
+1 -1
View File
@@ -133,7 +133,7 @@ Edge2EdgeCheckBase::finish (const Edge *o, size_t p)
std::set<db::Edge> partial_edges;
db::EdgeBooleanCluster<std::set<db::Edge> > ec (&partial_edges, db::EdgeNot);
db::EdgeBooleanCluster<std::set<db::Edge> > ec (&partial_edges, 0, db::EdgeNot);
ec.add (o, 0);
for (std::multimap<std::pair<db::Edge, size_t>, size_t>::const_iterator i = i0; i != m_e2ep.end () && i->first == k; ++i) {
+1 -1
View File
@@ -211,7 +211,7 @@ public:
virtual RegionDelegate *scaled_and_snapped_in_place (db::Coord gx, db::Coord mx, db::Coord dx, db::Coord gy, db::Coord my, db::Coord dy) = 0;
virtual RegionDelegate *scaled_and_snapped (db::Coord gx, db::Coord mx, db::Coord dx, db::Coord gy, db::Coord my, db::Coord dy) = 0;
virtual EdgesDelegate *edges (const EdgeFilterBase *filter) const = 0;
virtual EdgesDelegate *edges (const EdgeFilterBase *filter, const db::PolygonToEdgeProcessorBase *proc) const = 0;
virtual RegionDelegate *filter_in_place (const PolygonFilterBase &filter) = 0;
virtual RegionDelegate *filtered (const PolygonFilterBase &filter) const = 0;
virtual RegionDelegate *process_in_place (const PolygonProcessorBase &filter) = 0;
+96 -2
View File
@@ -136,10 +136,104 @@ bool RelativeExtentsAsEdges::result_must_not_be_merged () const
// -----------------------------------------------------------------------------------
// PolygonToEdgeProcessor implementation
PolygonToEdgeProcessor::PolygonToEdgeProcessor (PolygonToEdgeProcessor::EdgeMode mode)
: m_mode (mode)
{
// .. nothing yet ..
}
inline void
next (db::Polygon::contour_type::simple_iterator &iter, const db::Polygon::contour_type &contour)
{
if (++iter == contour.end ()) {
iter = contour.begin ();
}
}
static void
contour_to_edges (const db::Polygon::contour_type &contour, PolygonToEdgeProcessor::EdgeMode mode, std::vector<db::Edge> &result)
{
if (contour.size () < 3) {
return;
}
db::Polygon::contour_type::simple_iterator pm1 = contour.begin ();
db::Polygon::contour_type::simple_iterator p0 = pm1;
next (p0, contour);
db::Polygon::contour_type::simple_iterator p1 = p0;
next (p1, contour);
db::Polygon::contour_type::simple_iterator p2 = p1;
next (p2, contour);
while (pm1 != contour.end ()) {
int s1 = db::vprod_sign (*p0 - *pm1, *p1 - *p0);
int s2 = db::vprod_sign (*p1 - *p0, *p2 - *p1);
bool take = true;
switch (mode) {
case PolygonToEdgeProcessor::All:
default:
break;
case PolygonToEdgeProcessor::Convex:
take = s1 < 0 && s2 < 0;
break;
case PolygonToEdgeProcessor::NotConvex:
take = ! (s1 < 0 && s2 < 0);
break;
case PolygonToEdgeProcessor::Concave:
take = s1 > 0 && s2 > 0;
break;
case PolygonToEdgeProcessor::NotConcave:
take = ! (s1 > 0 && s2 > 0);
break;
case PolygonToEdgeProcessor::StepOut:
take = s1 > 0 && s2 < 0;
break;
case PolygonToEdgeProcessor::NotStepOut:
take = ! (s1 > 0 && s2 < 0);
break;
case PolygonToEdgeProcessor::StepIn:
take = s1 < 0 && s2 > 0;
break;
case PolygonToEdgeProcessor::NotStepIn:
take = ! (s1 < 0 && s2 > 0);
break;
case PolygonToEdgeProcessor::Step:
take = s1 * s2 < 0;
break;
case PolygonToEdgeProcessor::NotStep:
take = ! (s1 * s2 < 0);
break;
}
if (take) {
result.push_back (db::Edge (*p0, *p1));
}
++pm1;
next (p0, contour);
next (p1, contour);
next (p2, contour);
}
}
void PolygonToEdgeProcessor::process (const db::Polygon &poly, std::vector<db::Edge> &result) const
{
for (db::Polygon::polygon_edge_iterator e = poly.begin_edge (); ! e.at_end (); ++e) {
result.push_back (*e);
if (m_mode == All) {
for (db::Polygon::polygon_edge_iterator e = poly.begin_edge (); ! e.at_end (); ++e) {
result.push_back (*e);
}
} else {
for (unsigned int i = 0; i < poly.holes () + 1; ++i) {
contour_to_edges (poly.contour (i), m_mode, result);
}
}
}
+7 -4
View File
@@ -293,12 +293,15 @@ class DB_PUBLIC PolygonToEdgeProcessor
: public db::PolygonToEdgeProcessorBase
{
public:
PolygonToEdgeProcessor ()
{
// .. nothing yet ..
}
enum EdgeMode { All = 0, Convex, Concave, StepIn, StepOut, Step,
NotConvex, NotConcave, NotStepIn, NotStepOut, NotStep };
PolygonToEdgeProcessor (EdgeMode mode = All);
void process (const db::Polygon &poly, std::vector<db::Edge> &result) const;
private:
EdgeMode m_mode;
};
/**
+10 -6
View File
@@ -316,13 +316,13 @@ static db::CompoundRegionOperationNode *new_minkowski_sum_node4 (db::CompoundReg
return new db::CompoundRegionProcessingOperationNode (new db::minkowski_sum_computation<std::vector<db::Point> > (p), input, true /*processor is owned*/);
}
static db::CompoundRegionOperationNode *new_edges (db::CompoundRegionOperationNode *input)
static db::CompoundRegionOperationNode *new_edges (db::CompoundRegionOperationNode *input, db::PolygonToEdgeProcessor::EdgeMode edge_mode)
{
check_non_null (input, "input");
if (input->result_type () == db::CompoundRegionOperationNode::EdgePairs) {
return new db::CompoundRegionEdgePairToEdgeProcessingOperationNode (new db::EdgePairToEdgesProcessor (), input, true /*processor is owned*/);
} else if (input->result_type () == db::CompoundRegionOperationNode::Region) {
return new db::CompoundRegionToEdgeProcessingOperationNode (new db::PolygonToEdgeProcessor (), input, true /*processor is owned*/);
return new db::CompoundRegionToEdgeProcessingOperationNode (new db::PolygonToEdgeProcessor (edge_mode), input, true /*processor is owned*/);
} else {
input->keep ();
return input;
@@ -567,13 +567,13 @@ Class<db::CompoundRegionOperationNode> decl_CompoundRegionOperationNode ("db", "
gsi::constructor ("new_geometrical_boolean", &new_geometrical_boolean, gsi::arg ("op"), gsi::arg ("a"), gsi::arg ("b"),
"@brief Creates a node representing a geometrical boolean operation between the inputs.\n"
) +
gsi::constructor ("new_interacting", &new_interacting, gsi::arg ("a"), gsi::arg ("b"), gsi::arg ("inverse", false), gsi::arg ("min_count", size_t (0)), gsi::arg ("max_count", std::numeric_limits<size_t>::max (), "unlimited"),
gsi::constructor ("new_interacting", &new_interacting, gsi::arg ("a"), gsi::arg ("b"), gsi::arg ("inverse", false), gsi::arg ("min_count", size_t (1)), gsi::arg ("max_count", std::numeric_limits<size_t>::max (), "unlimited"),
"@brief Creates a node representing an interacting selection operation between the inputs.\n"
) +
gsi::constructor ("new_overlapping", &new_overlapping, gsi::arg ("a"), gsi::arg ("b"), gsi::arg ("inverse", false), gsi::arg ("min_count", size_t (0)), gsi::arg ("max_count", std::numeric_limits<size_t>::max (), "unlimited"),
gsi::constructor ("new_overlapping", &new_overlapping, gsi::arg ("a"), gsi::arg ("b"), gsi::arg ("inverse", false), gsi::arg ("min_count", size_t (1)), gsi::arg ("max_count", std::numeric_limits<size_t>::max (), "unlimited"),
"@brief Creates a node representing an overlapping selection operation between the inputs.\n"
) +
gsi::constructor ("new_enclosing", &new_enclosing, gsi::arg ("a"), gsi::arg ("b"), gsi::arg ("inverse", false), gsi::arg ("min_count", size_t (0)), gsi::arg ("max_count", std::numeric_limits<size_t>::max (), "unlimited"),
gsi::constructor ("new_enclosing", &new_enclosing, gsi::arg ("a"), gsi::arg ("b"), gsi::arg ("inverse", false), gsi::arg ("min_count", size_t (1)), gsi::arg ("max_count", std::numeric_limits<size_t>::max (), "unlimited"),
"@brief Creates a node representing an inside selection operation between the inputs.\n"
) +
gsi::constructor ("new_inside", &new_inside, gsi::arg ("a"), gsi::arg ("b"), gsi::arg ("inverse", false),
@@ -746,8 +746,12 @@ Class<db::CompoundRegionOperationNode> decl_CompoundRegionOperationNode ("db", "
"@brief Creates a node filtering the input for rectangular or square shapes.\n"
"If 'is_square' is true, only squares will be selected. If 'inverse' is true, the non-rectangle/non-square shapes are returned.\n"
) +
gsi::constructor ("new_edges", &new_edges, gsi::arg ("input"),
gsi::constructor ("new_edges", &new_edges, gsi::arg ("input"), gsi::arg ("mode", db::PolygonToEdgeProcessor::All, "All"),
"@brief Creates a node converting polygons into its edges.\n"
"The 'mode' argument allows selecting specific edges when generating edges from a polygon. "
"See \\EdgeMode for the various options. By default, all edges are generated from polygons.\n"
"\n"
"The 'mode' argument has been added in version 0.29."
) +
gsi::constructor ("new_edge_length_filter", &new_edge_length_filter, gsi::arg ("input"), gsi::arg ("inverse", false), gsi::arg ("lmin", 0), gsi::arg ("lmax", std::numeric_limits<db::Edge::distance_type>::max (), "max"),
"@brief Creates a node filtering edges by their length.\n"
+69 -23
View File
@@ -656,14 +656,14 @@ static std::vector<db::Edges> split_outside_with_region (const db::Edges *r, con
return as_2edges_vector (r->selected_outside_differential (other));
}
static std::vector<db::Edges> split_interacting_with_edges (const db::Edges *r, const db::Edges &other)
static std::vector<db::Edges> split_interacting_with_edges (const db::Edges *r, const db::Edges &other, size_t min_count, size_t max_count)
{
return as_2edges_vector (r->selected_interacting_differential (other));
return as_2edges_vector (r->selected_interacting_differential (other, min_count, max_count));
}
static std::vector<db::Edges> split_interacting_with_region (const db::Edges *r, const db::Region &other)
static std::vector<db::Edges> split_interacting_with_region (const db::Edges *r, const db::Region &other, size_t min_count, size_t max_count)
{
return as_2edges_vector (r->selected_interacting_differential (other));
return as_2edges_vector (r->selected_interacting_differential (other, min_count, max_count));
}
@@ -1233,61 +1233,107 @@ Class<db::Edges> decl_Edges (decl_dbShapeCollection, "db", "Edges",
"\n"
"The 'join_with' alias has been introduced in version 0.28.12."
) +
method ("interacting", (db::Edges (db::Edges::*) (const db::Edges &) const) &db::Edges::selected_interacting, gsi::arg ("other"),
method ("interacting", (db::Edges (db::Edges::*) (const db::Edges &, size_t, size_t) const) &db::Edges::selected_interacting, gsi::arg ("other"), gsi::arg ("min_count", size_t (1)), gsi::arg ("max_count", size_t (std::numeric_limits<size_t>::max ()), "unlimited"),
"@brief Returns the edges of this edge collection which overlap or touch edges from the other edge collection\n"
"\n"
"@return A new edge collection containing the edges overlapping or touching edges from the other edge collection\n"
"\n"
"'min_count' and 'max_count' impose a constraint on the number of times an edge of this collection "
"has to interact with (different) edges of the other collection to make the edge selected. An edge is "
"selected by this method if the number of edges interacting with an edge of this collection is between min_count and max_count "
"(including max_count).\n"
"\n"
"'min_count' and 'max_count' have been introduced in version 0.29."
) +
method ("not_interacting", (db::Edges (db::Edges::*) (const db::Edges &) const) &db::Edges::selected_not_interacting, gsi::arg ("other"),
method ("not_interacting", (db::Edges (db::Edges::*) (const db::Edges &, size_t, size_t) const) &db::Edges::selected_not_interacting, gsi::arg ("other"), gsi::arg ("min_count", size_t (1)), gsi::arg ("max_count", size_t (std::numeric_limits<size_t>::max ()), "unlimited"),
"@brief Returns the edges of this edge collection which do not overlap or touch edges from the other edge collection\n"
"\n"
"@return A new edge collection containing the edges not overlapping or touching edges from the other edge collection\n"
) +
method ("select_interacting", (db::Edges &(db::Edges::*) (const db::Edges &)) &db::Edges::select_interacting, gsi::arg ("other"),
"\n"
"'min_count' and 'max_count' impose a constraint on the number of times an edge of this collection "
"has to interact with (different) edges of the other collection to make the edge selected. An edge is "
"not selected by this method if the number of edges interacting with an edge of this collection is between min_count and max_count "
"(including max_count).\n"
"\n"
"'min_count' and 'max_count' have been introduced in version 0.29."
) +
method ("select_interacting", (db::Edges &(db::Edges::*) (const db::Edges &, size_t, size_t)) &db::Edges::select_interacting, gsi::arg ("other"), gsi::arg ("min_count", size_t (1)), gsi::arg ("max_count", size_t (std::numeric_limits<size_t>::max ()), "unlimited"),
"@brief Selects the edges from this edge collection which overlap or touch edges from the other edge collection\n"
"\n"
"@return The edge collection after the edges have been selected (self)\n"
) +
method ("select_not_interacting", (db::Edges &(db::Edges::*) (const db::Edges &)) &db::Edges::select_not_interacting, gsi::arg ("other"),
"\n"
"This is the in-place version of \\interacting - i.e. self is modified rather than a new collection is returned.\n"
"\n"
"'min_count' and 'max_count' have been introduced in version 0.29."
) +
method ("select_not_interacting", (db::Edges &(db::Edges::*) (const db::Edges &, size_t, size_t)) &db::Edges::select_not_interacting, gsi::arg ("other"), gsi::arg ("min_count", size_t (1)), gsi::arg ("max_count", size_t (std::numeric_limits<size_t>::max ()), "unlimited"),
"@brief Selects the edges from this edge collection which do not overlap or touch edges from the other edge collection\n"
"\n"
"@return The edge collection after the edges have been selected (self)\n"
) +
method_ext ("split_interacting", &split_interacting_with_edges, gsi::arg ("other"),
"\n"
"This is the in-place version of \\not_interacting - i.e. self is modified rather than a new collection is returned.\n"
"\n"
"'min_count' and 'max_count' have been introduced in version 0.29."
) +
method_ext ("split_interacting", &split_interacting_with_edges, gsi::arg ("other"), gsi::arg ("min_count", size_t (1)), gsi::arg ("max_count", size_t (std::numeric_limits<size_t>::max ()), "unlimited"),
"@brief Selects the edges from this edge collection which do and do not interact with edges from the other collection\n"
"\n"
"@return A two-element list of edge collections (first: interacting, second: non-interacting)\n"
"\n"
"This method provides a faster way to compute both interacting and non-interacting edges compared to using separate methods. "
"It has been introduced in version 0.28."
"It has been introduced in version 0.28.\n"
"'min_count' and 'max_count' have been introduced in version 0.29."
) +
method ("interacting", (db::Edges (db::Edges::*) (const db::Region &) const) &db::Edges::selected_interacting, gsi::arg ("other"),
method ("interacting", (db::Edges (db::Edges::*) (const db::Region &, size_t, size_t) const) &db::Edges::selected_interacting, gsi::arg ("other"), gsi::arg ("min_count", size_t (1)), gsi::arg ("max_count", size_t (std::numeric_limits<size_t>::max ()), "unlimited"),
"@brief Returns the edges from this edge collection which overlap or touch polygons from the region\n"
"\n"
"@return A new edge collection containing the edges overlapping or touching polygons from the region\n"
) +
method ("not_interacting", (db::Edges (db::Edges::*) (const db::Region &) const) &db::Edges::selected_not_interacting, gsi::arg ("other"),
"\n"
"'min_count' and 'max_count' impose a constraint on the number of times an edge of this collection "
"has to interact with (different) polygons of the other region to make the edge selected. An edge is "
"selected by this method if the number of polygons interacting with an edge of this collection is between min_count and max_count "
"(including max_count).\n"
"\n"
"'min_count' and 'max_count' have been introduced in version 0.29."
) +
method ("not_interacting", (db::Edges (db::Edges::*) (const db::Region &, size_t, size_t) const) &db::Edges::selected_not_interacting, gsi::arg ("other"), gsi::arg ("min_count", size_t (1)), gsi::arg ("max_count", size_t (std::numeric_limits<size_t>::max ()), "unlimited"),
"@brief Returns the edges from this edge collection which do not overlap or touch polygons from the region\n"
"\n"
"@return A new edge collection containing the edges not overlapping or touching polygons from the region\n"
) +
method ("select_interacting", (db::Edges &(db::Edges::*) (const db::Region &)) &db::Edges::select_interacting, gsi::arg ("other"),
"\n"
"'min_count' and 'max_count' impose a constraint on the number of times an edge of this collection "
"has to interact with (different) polygons of the other region to make the edge selected. An edge is "
"not selected by this method if the number of polygons interacting with an edge of this collection is between min_count and max_count "
"(including max_count).\n"
"\n"
"'min_count' and 'max_count' have been introduced in version 0.29."
) +
method ("select_interacting", (db::Edges &(db::Edges::*) (const db::Region &, size_t, size_t)) &db::Edges::select_interacting, gsi::arg ("other"), gsi::arg ("min_count", size_t (1)), gsi::arg ("max_count", size_t (std::numeric_limits<size_t>::max ()), "unlimited"),
"@brief Selects the edges from this edge collection which overlap or touch polygons from the region\n"
"\n"
"@return The edge collection after the edges have been selected (self)\n"
) +
method ("select_not_interacting", (db::Edges &(db::Edges::*) (const db::Region &)) &db::Edges::select_not_interacting, gsi::arg ("other"),
"\n"
"This is the in-place version of \\interacting - i.e. self is modified rather than a new collection is returned.\n"
"\n"
"'min_count' and 'max_count' have been introduced in version 0.29."
) +
method ("select_not_interacting", (db::Edges &(db::Edges::*) (const db::Region &, size_t, size_t)) &db::Edges::select_not_interacting, gsi::arg ("other"), gsi::arg ("min_count", size_t (1)), gsi::arg ("max_count", size_t (std::numeric_limits<size_t>::max ()), "unlimited"),
"@brief Selects the edges from this edge collection which do not overlap or touch polygons from the region\n"
"\n"
"@return The edge collection after the edges have been selected (self)\n"
) +
method_ext ("split_interacting", &split_interacting_with_region, gsi::arg ("other"),
"\n"
"This is the in-place version of \\not_interacting - i.e. self is modified rather than a new collection is returned.\n"
"\n"
"'min_count' and 'max_count' have been introduced in version 0.29."
) +
method_ext ("split_interacting", &split_interacting_with_region, gsi::arg ("other"), gsi::arg ("min_count", size_t (1)), gsi::arg ("max_count", size_t (std::numeric_limits<size_t>::max ()), "unlimited"),
"@brief Selects the edges from this edge collection which do and do not interact with polygons from the other region\n"
"\n"
"@return A two-element list of edge collections (first: interacting, second: non-interacting)\n"
"\n"
"This method provides a faster way to compute both interacting and non-interacting edges compared to using separate methods. "
"It has been introduced in version 0.28."
"It has been introduced in version 0.28.\n"
"'min_count' and 'max_count' have been introduced in version 0.29."
) +
method ("inside", (db::Edges (db::Edges::*) (const db::Edges &) const) &db::Edges::selected_inside, gsi::arg ("other"),
"@brief Returns the edges of this edge collection which are inside (completely covered by) edges from the other edge collection\n"
+63 -16
View File
@@ -31,6 +31,39 @@
namespace gsi
{
template <class C>
static std::vector<C> split_poly (const C *p)
{
std::vector<C> parts;
db::split_polygon (*p, parts);
return parts;
}
template <class C>
static void break_polygon (const C &poly, size_t max_vertex_count, double max_area_ratio, std::vector<C> &result)
{
if ((max_vertex_count > 0 && poly.vertices () > max_vertex_count) ||
(max_area_ratio > 0 && poly.area_ratio () > max_area_ratio)) {
std::vector<C> split_polygons;
db::split_polygon (poly, split_polygons);
for (auto p = split_polygons.begin (); p != split_polygons.end (); ++p) {
break_polygon (*p, max_vertex_count, max_area_ratio, result);
}
} else {
result.push_back (poly);
}
}
template <class C>
static std::vector<C> break_poly (const C *p, size_t max_vertex_count, double max_area_ratio)
{
std::vector<C> parts;
break_polygon (*p, max_vertex_count, max_area_ratio, parts);
return parts;
}
// ---------------------------------------------------------------
// simple polygon binding
@@ -245,13 +278,6 @@ struct simple_polygon_defs
return db::interact (*p, spoly);
}
static std::vector<C> split_poly (const C *p)
{
std::vector<C> parts;
db::split_polygon (*p, parts);
return parts;
}
static gsi::Methods methods ()
{
return
@@ -508,7 +534,7 @@ struct simple_polygon_defs
"\n"
"This method was introduced in version 0.25.\n"
) +
method_ext ("split", &split_poly,
method_ext ("split", &split_poly<C>,
"@brief Splits the polygon into two or more parts\n"
"This method will break the polygon into parts. The exact breaking algorithm is unspecified, the "
"result are smaller polygons of roughly equal number of points and 'less concave' nature. "
@@ -521,6 +547,20 @@ struct simple_polygon_defs
"\n"
"This method has been introduced in version 0.25.3."
) +
method_ext ("break", &break_poly<C>, gsi::arg ("max_vertex_count"), gsi::arg ("max_area_ratio"),
"@brief Splits the polygon into parts with a maximum vertex count and area ratio\n"
"The area ratio is the ratio between the bounding box area and the polygon area. Higher values "
"mean more 'skinny' polygons.\n"
"\n"
"This method will split the input polygon into pieces having a maximum of 'max_vertex_count' vertices "
"and an area ratio less than 'max_area_ratio'. 'max_vertex_count' can be zero. In this case the "
"limit is ignored. Also 'max_area_ratio' can be zero, in which case it is ignored as well.\n"
"\n"
"The method of splitting is unspecified. The algorithm will apply 'split' recursively until the "
"parts satisfy the limits.\n"
"\n"
"This method has been introduced in version 0.29."
) +
method_ext ("area", &area,
"@brief Gets the area of the polygon\n"
"The area is correct only if the polygon is not self-overlapping and the polygon is oriented clockwise."
@@ -1098,13 +1138,6 @@ struct polygon_defs
return db::interact (*p, spoly);
}
static std::vector<C> split_spoly (const C *p)
{
std::vector<C> parts;
db::split_polygon (*p, parts);
return parts;
}
static gsi::Methods methods ()
{
return
@@ -1520,7 +1553,7 @@ struct polygon_defs
"\n"
"This method was introduced in version 0.25.\n"
) +
method_ext ("split", &split_spoly,
method_ext ("split", &split_poly<C>,
"@brief Splits the polygon into two or more parts\n"
"This method will break the polygon into parts. The exact breaking algorithm is unspecified, the "
"result are smaller polygons of roughly equal number of points and 'less concave' nature. "
@@ -1533,6 +1566,20 @@ struct polygon_defs
"\n"
"This method has been introduced in version 0.25.3."
) +
method_ext ("break", &break_poly<C>, gsi::arg ("max_vertex_count"), gsi::arg ("max_area_ratio"),
"@brief Splits the polygon into parts with a maximum vertex count and area ratio\n"
"The area ratio is the ratio between the bounding box area and the polygon area. Higher values "
"mean more 'skinny' polygons.\n"
"\n"
"This method will split the input polygon into pieces having a maximum of 'max_vertex_count' vertices "
"and an area ratio less than 'max_area_ratio'. 'max_vertex_count' can be zero. In this case the "
"limit is ignored. Also 'max_area_ratio' can be zero, in which case it is ignored as well.\n"
"\n"
"The method of splitting is unspecified. The algorithm will apply 'split' recursively until the "
"parts satisfy the limits.\n"
"\n"
"This method has been introduced in version 0.29."
) +
method_ext ("area", &area,
"@brief Gets the area of the polygon\n"
"The area is correct only if the polygon is not self-overlapping and the polygon is oriented clockwise."
+64 -5
View File
@@ -1002,6 +1002,18 @@ size_dvm (db::Region *region, const db::Vector &dv, unsigned int mode)
return *region;
}
static db::Edges
edges (const db::Region *region, db::PolygonToEdgeProcessor::EdgeMode mode)
{
if (mode != db::PolygonToEdgeProcessor::All) {
db::PolygonToEdgeProcessor proc (mode);
return region->edges (proc);
} else {
// this version is more efficient in the hierarchical case
return region->edges ();
}
}
static std::vector<std::vector<double> >
rasterize2 (const db::Region *region, const db::Point &origin, const db::Vector &pixel_distance, const db::Vector &pixel_size, unsigned int nx, unsigned int ny)
{
@@ -2493,15 +2505,20 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"If the region is not merged, this method may return false even\n"
"if the merged region would be a box.\n"
) +
method ("edges", (db::Edges (db::Region::*) () const) &db::Region::edges,
method_ext ("edges", &edges, gsi::arg ("mode", db::PolygonToEdgeProcessor::All, "All"),
"@brief Returns an edge collection representing all edges of the polygons in this region\n"
"This method will decompose the polygons into the individual edges. Edges making up the hulls "
"of the polygons are oriented clockwise while edges making up the holes are oriented counterclockwise.\n"
"\n"
"The 'mode' parameter allows selecting specific edges, such as convex or concave ones. By default, "
"all edges are selected.\n"
"\n"
"The edge collection returned can be manipulated in various ways. See \\Edges for a description of the "
"possibilities of the edge collection.\n"
"features of the edge collection.\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
"\n"
"The mode argument has been added in version 0.29."
) +
factory_ext ("decompose_convex", &decompose_convex<db::Shapes>, gsi::arg ("preferred_orientation", po_any (), "\\Polygon#PO_any"),
"@brief Decomposes the region into convex pieces.\n"
@@ -2924,7 +2941,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\n"
"The 'shielded' and 'negative' options have been introduced in version 0.27. "
"'property_constraint' has been added in version 0.28.4.\n"
"'zero_distance_mode' has been added in version 0.29."
"'zero_distance_mode' has been added in version 0.28.16."
) +
method_ext ("space_check", &space2, gsi::arg ("d"), gsi::arg ("whole_edges", false), gsi::arg ("metrics", db::metrics_type::Euclidian, "Euclidian"), gsi::arg ("ignore_angle", tl::Variant (), "default"), gsi::arg ("min_projection", tl::Variant (), "0"), gsi::arg ("max_projection", tl::Variant (), "max"), gsi::arg ("shielded", true), gsi::arg ("opposite_filter", db::NoOppositeFilter, "NoOppositeFilter"), gsi::arg ("rect_filter", db::NoRectFilter, "NoRectFilter"), gsi::arg ("negative", false), gsi::arg ("property_constraint", db::IgnoreProperties, "IgnoreProperties"), gsi::arg ("zero_distance_mode", db::IncludeZeroDistanceWhenTouching, "IncludeZeroDistanceWhenTouching"),
"@brief Performs a space check with options\n"
@@ -3577,6 +3594,48 @@ gsi::Enum<db::metrics_type> decl_Metrics ("db", "Metrics",
gsi::ClassExt<db::Region> inject_Metrics_in_Region (decl_Metrics.defs ());
gsi::ClassExt<db::Edges> inject_Metrics_in_Edges (decl_Metrics.defs ());
gsi::Enum<db::PolygonToEdgeProcessor::EdgeMode> decl_EdgeMode ("db", "EdgeMode",
gsi::enum_const ("All", db::PolygonToEdgeProcessor::All,
"@brief Selects all edges\n"
) +
gsi::enum_const ("Concave", db::PolygonToEdgeProcessor::Concave,
"@brief Selects only concave edges\n"
) +
gsi::enum_const ("NotConcave", db::PolygonToEdgeProcessor::NotConcave,
"@brief Selects only edges which are not concave\n"
) +
gsi::enum_const ("Convex", db::PolygonToEdgeProcessor::Convex,
"@brief Selects only convex edges\n"
) +
gsi::enum_const ("NotConvex", db::PolygonToEdgeProcessor::NotConvex,
"@brief Selects only edges which are not convex\n"
) +
gsi::enum_const ("Step", db::PolygonToEdgeProcessor::Step,
"@brief Selects only step edges leading inside or outside\n"
) +
gsi::enum_const ("NotStep", db::PolygonToEdgeProcessor::NotStep,
"@brief Selects only edges which are not steps\n"
) +
gsi::enum_const ("StepIn", db::PolygonToEdgeProcessor::StepIn,
"@brief Selects only step edges leading inside\n"
) +
gsi::enum_const ("NotStepIn", db::PolygonToEdgeProcessor::NotStepIn,
"@brief Selects only edges which are not steps leading inside\n"
) +
gsi::enum_const ("StepOut", db::PolygonToEdgeProcessor::StepOut,
"@brief Selects only step edges leading outside\n"
) +
gsi::enum_const ("NotStepOut", db::PolygonToEdgeProcessor::NotStepOut,
"@brief Selects only edges which are not steps leading outside\n"
),
"@brief This class represents the edge mode type for \\Region#edges.\n"
"\n"
"This enum has been introduced in version 0.29."
);
// Inject the Region::EdgeMode declarations into Region:
gsi::ClassExt<db::Region> inject_EdgeMode_in_Region (decl_EdgeMode.defs ());
gsi::Enum<db::zero_distance_mode> decl_ZeroDistanceMode ("db", "ZeroDistanceMode",
gsi::enum_const ("NeverIncludeZeroDistance", db::NeverIncludeZeroDistance,
"@brief Specifies that check functions should never include edges with zero distance.\n"
@@ -3590,7 +3649,7 @@ gsi::Enum<db::zero_distance_mode> decl_ZeroDistanceMode ("db", "ZeroDistanceMode
gsi::enum_const ("IncludeZeroDistanceWhenTouching", db::IncludeZeroDistanceWhenTouching,
"@brief Specifies that check functions should include edges when they touch\n"
"With this specification, the check functions will also check edges if they share at least one common point. "
"This is the mode that includes checking the 'kissing corner' cases. This mode is default for version 0.29 and later. "
"This is the mode that includes checking the 'kissing corner' cases. This mode is default for version 0.28.16 and later. "
) +
gsi::enum_const ("IncludeZeroDistanceWhenCollinearAndTouching", db::IncludeZeroDistanceWhenCollinearAndTouching,
"@brief Specifies that check functions should include edges when they are collinear and touch\n"
@@ -3609,7 +3668,7 @@ gsi::Enum<db::zero_distance_mode> decl_ZeroDistanceMode ("db", "ZeroDistanceMode
"if they share at least one common point (\\IncludeZeroDistanceWhenTouching). The latter mode allows activating checks for "
"the 'kissing corner' case and is the default mode in most checks."
"\n"
"This enum has been introduced in version 0.29."
"This enum has been introduced in version 0.28.16."
);
// Inject the Region::ZeroDistanceMode declarations into Region and Edges:
+218 -5
View File
@@ -133,7 +133,7 @@ TEST(3_Edge2EdgeBooleans)
db::Layout ly;
{
std::string fn (tl::testdata ());
fn += "/algo/deep_region_l1.gds";
fn += "/algo/deep_edges_l1.gds";
tl::InputStream stream (fn);
db::Reader reader (stream);
reader.read (ly);
@@ -145,15 +145,23 @@ TEST(3_Edge2EdgeBooleans)
db::DeepShapeStore dss;
unsigned int l2 = ly.get_layer (db::LayerProperties (2, 0));
unsigned int l21 = ly.get_layer (db::LayerProperties (2, 1));
unsigned int l3 = ly.get_layer (db::LayerProperties (3, 0));
unsigned int lempty = ly.insert_layer ();
db::Region r2 (db::RecursiveShapeIterator (ly, top_cell, l2), dss);
db::Region r21 (db::RecursiveShapeIterator (ly, top_cell, l21), dss);
db::Region r3 (db::RecursiveShapeIterator (ly, top_cell, l3), dss);
db::Region r2and3 = r2 & r3;
db::Edges e2 = r2.edges ();
db::Edges e21 = r21.edges ();
db::Edges e3 = r3.edges ();
db::Edges e3copy = r3.edges ();
db::Edges e2and3 = r2and3.edges ();
db::Edges eempty (db::RecursiveShapeIterator (ly, top_cell, lempty), dss);
db::Edges edots = e2and3.processed (db::EdgeSegmentSelector (-1, 0, 0));
db::Edges edotscopy = e2and3.processed (db::EdgeSegmentSelector (-1, 0, 0));
db::Layout target;
unsigned int target_top_cell_index = target.add_cell (ly.cell_name (top_cell_index));
@@ -162,11 +170,70 @@ TEST(3_Edge2EdgeBooleans)
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)), e3);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (11, 0)), e2and3);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (12, 0)), edots);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (13, 0)), edots.merged ());
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (20, 0)), e3 & e2and3);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (21, 0)), e3 - e2and3);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (22, 0)), e3 ^ e2and3);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (23, 0)), e3.intersections(e2and3));
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (24, 0)), e3.intersections(e2));
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (21, 0)), e3 & edots);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (22, 0)), e3 & eempty);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (23, 0)), e3 & e3copy);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (24, 0)), eempty & e2and3);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (25, 0)), edots & edotscopy);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (26, 0)), edots & e2);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (27, 0)), e21 & edots);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (28, 0)), edots & e21);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (30, 0)), e3 - e2and3);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (31, 0)), e3 - edots);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (32, 0)), e3 - eempty);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (33, 0)), e3 - e3copy);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (34, 0)), eempty - e2and3);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (35, 0)), edots - edotscopy);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (36, 0)), edots - e2);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (37, 0)), e21 - edots);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (38, 0)), edots - e21);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (40, 0)), e3 ^ e2and3);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (41, 0)), e3 ^ edots);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (42, 0)), e3 ^ eempty);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (43, 0)), e3 ^ e3copy);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (44, 0)), eempty ^ e2and3);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (45, 0)), edots ^ edotscopy);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (46, 0)), edots ^ e2);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (47, 0)), e21 ^ edots);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (48, 0)), edots ^ e21);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (50, 0)), e3.andnot(e2and3).first);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (51, 0)), e3.andnot(edots).first);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (52, 0)), e3.andnot(eempty).first);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (53, 0)), e3.andnot(e3copy).first);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (54, 0)), eempty.andnot(e2and3).first);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (55, 0)), edots.andnot(edotscopy).first);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (56, 0)), edots.andnot(e2).first);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (57, 0)), e21.andnot(edots).first);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (58, 0)), edots.andnot(e21).first);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (60, 0)), e3.andnot(e2and3).second);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (61, 0)), e3.andnot(edots).second);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (62, 0)), e3.andnot(eempty).second);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (63, 0)), e3.andnot(e3copy).second);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (64, 0)), eempty.andnot(e2and3).second);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (65, 0)), edots.andnot(edotscopy).second);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (66, 0)), edots.andnot(e2).second);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (67, 0)), e21.andnot(edots).second);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (68, 0)), edots.andnot(e21).second);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (70, 0)), e3.intersections(e2and3));
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (71, 0)), e3.intersections(edots));
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (72, 0)), e3.intersections(eempty));
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (73, 0)), e3.intersections(e3copy));
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (74, 0)), eempty.intersections(e2and3));
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (75, 0)), edots.intersections(edotscopy));
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (76, 0)), edots.intersections(e2));
// test, whether dots are not merged
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (77, 0)), edots.intersections(e2).select_interacting(e2));
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (78, 0)), e21.intersections(edots));
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (79, 0)), edots.intersections(e21));
CHECKPOINT();
db::compare_layouts (_this, target, tl::testdata () + "/algo/deep_edges_au3.gds");
@@ -1293,6 +1360,152 @@ TEST(20_in_and_out)
db::compare_layouts (_this, target, tl::testdata () + "/algo/deep_edges_au20.gds");
}
TEST(21_EdgeMergeWithDots)
{
db::Edges e;
e.insert (db::Edge (db::Point(0, 0), db::Point (100, 0)));
e.insert (db::Edge (db::Point(110, 0), db::Point (110, 0)));
db::Edges ee = e;
ee.insert (db::Edge (db::Point(100, 0), db::Point (110, 0)));
db::Edges eee;
eee.insert (db::Edge (db::Point(110, 0), db::Point (110, 0)));
eee.insert (db::Edge (db::Point(110, 0), db::Point (110, 0)));
// make deep
db::DeepShapeStore dss;
db::Layout ly;
ly.add_cell ("TOP");
unsigned int l1 = ly.insert_layer ();
unsigned int l2 = ly.insert_layer ();
unsigned int l3 = ly.insert_layer ();
db::cell_index_type top_cell_index = *ly.begin_top_down ();
db::Cell &top_cell = ly.cell (top_cell_index);
e.insert_into (&ly, top_cell.cell_index (), l1);
e = db::Edges (db::RecursiveShapeIterator (ly, top_cell, l1), dss);
ee.insert_into (&ly, top_cell.cell_index (), l2);
ee = db::Edges (db::RecursiveShapeIterator (ly, top_cell, l2), dss);
eee.insert_into (&ly, top_cell.cell_index (), l3);
eee = db::Edges (db::RecursiveShapeIterator (ly, top_cell, l3), dss);
EXPECT_EQ (e.merged ().to_string (), "(0,0;100,0);(110,0;110,0)");
// dots do not participate in merge
EXPECT_EQ (ee.merged ().to_string (), "(0,0;110,0)");
// dots do not participate in merge
EXPECT_EQ (eee.merged ().to_string (), "(110,0;110,0)");
}
TEST(22_InteractingWithCount)
{
db::Edges e;
e.insert (db::Edge (db::Point (0, 0), db::Point (100, 0)));
e.insert (db::Edge (db::Point (100, 0), db::Point (200, 0)));
e.insert (db::Edge (db::Point (0, 10), db::Point (200, 10)));
e.insert (db::Edge (db::Point (0, 20), db::Point (200, 20)));
e.insert (db::Edge (db::Point (0, 30), db::Point (200, 30)));
db::Edges e2;
e2.insert (db::Edge (db::Point (100, 0), db::Point (100, 10)));
e2.insert (db::Edge (db::Point (100, 0), db::Point (100, 30)));
e2.insert (db::Edge (db::Point (110, 10), db::Point (110, 30)));
e2.merge ();
e2.insert (db::Edge (db::Point (120, 20), db::Point (120, 20)));
e2.insert (db::Edge (db::Point (130, 30), db::Point (130, 30)));
e2.set_merged_semantics (false);
db::Region r2;
r2.insert (db::Box (db::Point (99, 0), db::Point (101, 10)));
r2.insert (db::Box (db::Point (99, 0), db::Point (101, 30)));
r2.insert (db::Box (db::Point (109, 10), db::Point (111, 30)));
r2.insert (db::Box (db::Point (119, 19), db::Point (121, 21)));
r2.insert (db::Box (db::Point (129, 29), db::Point (131, 31)));
// make deep
db::DeepShapeStore dss;
db::Layout ly;
ly.add_cell ("TOP");
unsigned int l1 = ly.insert_layer ();
unsigned int l2 = ly.insert_layer ();
unsigned int l3 = ly.insert_layer ();
db::cell_index_type top_cell_index = *ly.begin_top_down ();
db::Cell &top_cell = ly.cell (top_cell_index);
e.insert_into (&ly, top_cell.cell_index (), l1);
e = db::Edges (db::RecursiveShapeIterator (ly, top_cell, l1), dss);
e2.insert_into (&ly, top_cell.cell_index (), l2);
e2 = db::Edges (db::RecursiveShapeIterator (ly, top_cell, l2), dss);
// because it has dots
e2.set_merged_semantics (false);
r2.insert_into (&ly, top_cell.cell_index (), l3);
r2 = db::Region (db::RecursiveShapeIterator (ly, top_cell, l3), dss);
db::Edges edup;
EXPECT_EQ (db::compare (e.selected_interacting (e2), "(0,0;200,0);(0,10;200,10);(0,20;200,20);(0,30;200,30)"), true);
EXPECT_EQ (db::compare (e.selected_interacting (e2, size_t (2)), "(0,10;200,10);(0,20;200,20);(0,30;200,30)"), true);
EXPECT_EQ (db::compare (e.selected_interacting (e2, size_t (2), size_t(2)), "(0,10;200,10)"), true);
EXPECT_EQ (db::compare (e.selected_interacting (e2, size_t (2), size_t(3)), "(0,10;200,10);(0,20;200,20);(0,30;200,30)"), true);
EXPECT_EQ (db::compare (e.selected_interacting (e2, size_t (3)), "(0,20;200,20);(0,30;200,30)"), true);
EXPECT_EQ (db::compare (e.selected_interacting (e2, size_t (4)), ""), true);
edup = e;
edup.select_interacting (e2, size_t (2), size_t(3));
EXPECT_EQ (db::compare (edup, "(0,10;200,10);(0,20;200,20);(0,30;200,30)"), true);
EXPECT_EQ (db::compare (e.selected_not_interacting (e2), ""), true);
EXPECT_EQ (db::compare (e.selected_not_interacting (e2, size_t (2)), "(0,0;200,0)"), true);
EXPECT_EQ (db::compare (e.selected_not_interacting (e2, size_t (2), size_t(2)), "(0,0;200,0);(0,20;200,20);(0,30;200,30)"), true);
EXPECT_EQ (db::compare (e.selected_not_interacting (e2, size_t (2), size_t(3)), "(0,0;200,0)"), true);
EXPECT_EQ (db::compare (e.selected_not_interacting (e2, size_t (3)), "(0,0;200,0);(0,10;200,10)"), true);
EXPECT_EQ (db::compare (e.selected_not_interacting (e2, size_t (4)), "(0,0;200,0);(0,10;200,10);(0,20;200,20);(0,30;200,30)"), true);
edup = e;
edup.select_not_interacting (e2, size_t (2), size_t(3));
EXPECT_EQ (db::compare (edup, "(0,0;200,0)"), true);
EXPECT_EQ (db::compare (e.selected_interacting_differential (e2, size_t (2), size_t(3)).first, "(0,10;200,10);(0,20;200,20);(0,30;200,30)"), true);
EXPECT_EQ (db::compare (e.selected_interacting_differential (e2, size_t (2), size_t(3)).second, "(0,0;200,0)"), true);
EXPECT_EQ (db::compare (e.selected_interacting (r2), "(0,0;200,0);(0,10;200,10);(0,20;200,20);(0,30;200,30)"), true);
EXPECT_EQ (db::compare (e.selected_interacting (r2, size_t (2)), "(0,10;200,10);(0,20;200,20);(0,30;200,30)"), true);
EXPECT_EQ (db::compare (e.selected_interacting (r2, size_t (2), size_t(2)), "(0,10;200,10)"), true);
EXPECT_EQ (db::compare (e.selected_interacting (r2, size_t (2), size_t(3)), "(0,10;200,10);(0,20;200,20);(0,30;200,30)"), true);
EXPECT_EQ (db::compare (e.selected_interacting (r2, size_t (3)), "(0,20;200,20);(0,30;200,30)"), true);
EXPECT_EQ (db::compare (e.selected_interacting (r2, size_t (4)), ""), true);
edup = e;
edup.select_interacting (r2, size_t (2), size_t(3));
EXPECT_EQ (db::compare (edup, "(0,10;200,10);(0,20;200,20);(0,30;200,30)"), true);
EXPECT_EQ (db::compare (e.selected_not_interacting (r2), ""), true);
EXPECT_EQ (db::compare (e.selected_not_interacting (r2, size_t (2)), "(0,0;200,0)"), true);
EXPECT_EQ (db::compare (e.selected_not_interacting (r2, size_t (2), size_t(2)), "(0,0;200,0);(0,20;200,20);(0,30;200,30)"), true);
EXPECT_EQ (db::compare (e.selected_not_interacting (r2, size_t (2), size_t(3)), "(0,0;200,0)"), true);
EXPECT_EQ (db::compare (e.selected_not_interacting (r2, size_t (3)), "(0,0;200,0);(0,10;200,10)"), true);
EXPECT_EQ (db::compare (e.selected_not_interacting (r2, size_t (4)), "(0,0;200,0);(0,10;200,10);(0,20;200,20);(0,30;200,30)"), true);
edup = e;
edup.select_not_interacting (r2, size_t (2), size_t(3));
EXPECT_EQ (db::compare (edup, "(0,0;200,0)"), true);
EXPECT_EQ (db::compare (e.selected_interacting_differential (r2, size_t (2), size_t(3)).first, "(0,10;200,10);(0,20;200,20);(0,30;200,30)"), true);
EXPECT_EQ (db::compare (e.selected_interacting_differential (r2, size_t (2), size_t(3)).second, "(0,0;200,0)"), true);
}
TEST(deep_edges_and_cheats)
{
db::Layout ly;
+228 -18
View File
@@ -22,12 +22,14 @@
#include "tlUnitTest.h"
#include "tlStream.h"
#include "dbEdges.h"
#include "dbEdgesUtils.h"
#include "dbPolygonTools.h"
#include "dbRegion.h"
#include "dbTestSupport.h"
#include "dbReader.h"
#include <cstdlib>
@@ -787,27 +789,27 @@ TEST(20)
EXPECT_EQ (r2.has_valid_edges (), false);
db::Region rr1 (db::RecursiveShapeIterator (ly, ly.cell (top), lp1), db::ICplxTrans (), false);
EXPECT_EQ (rr1.has_valid_polygons (), false);
EXPECT_EQ ((r1 & r2).to_string (100), "(80,70;80,40)");
EXPECT_EQ ((r1 + r2).to_string (100), "(0,0;0,30);(0,30;30,30);(30,30;30,0);(30,0;0,0);(50,0;50,30);(50,30;80,30);(80,30;80,0);(80,0;50,0);(50,40;50,70);(50,70;80,70);(80,70;80,40);(80,40;50,40);(60,10;60,20);(60,20;70,20);(70,20;70,10);(70,10;60,10);(10,10;10,40);(10,40;40,40);(40,40;40,10);(40,10;10,10);(80,40;80,70);(80,70;110,70);(110,70;110,40);(110,40;80,40);(110,40;110,70);(110,70;140,70);(140,70;140,40);(140,40;110,40)");
EXPECT_EQ ((r1 + r2).merged ().to_string (100), "(0,0;0,30);(0,30;30,30);(30,30;30,0);(30,0;0,0);(50,0;50,30);(50,30;80,30);(80,30;80,0);(80,0;50,0);(50,40;50,70);(60,10;60,20);(60,20;70,20);(70,20;70,10);(70,10;60,10);(10,10;10,40);(10,40;40,40);(40,40;40,10);(40,10;10,10);(50,70;140,70);(140,70;140,40);(140,40;50,40)");
EXPECT_EQ ((r1 | r2).to_string (100), "(0,0;0,30);(0,30;30,30);(30,30;30,0);(30,0;0,0);(50,0;50,30);(50,30;80,30);(80,30;80,0);(80,0;50,0);(50,40;50,70);(60,10;60,20);(60,20;70,20);(70,20;70,10);(70,10;60,10);(10,10;10,40);(10,40;40,40);(40,40;40,10);(40,10;10,10);(50,70;140,70);(140,70;140,40);(140,40;50,40)");
EXPECT_EQ ((r1 ^ r2).to_string (100), "(0,0;0,30);(0,30;30,30);(30,30;30,0);(30,0;0,0);(50,0;50,30);(50,30;80,30);(80,30;80,0);(80,0;50,0);(50,40;50,70);(60,10;60,20);(60,20;70,20);(70,20;70,10);(70,10;60,10);(10,10;10,40);(10,40;40,40);(40,40;40,10);(40,10;10,10);(50,70;140,70);(140,70;140,40);(140,40;50,40)");
EXPECT_EQ ((r1 ^ r1).to_string (100), "");
EXPECT_EQ ((r1 - r2).to_string (100), "(0,0;0,30);(0,30;30,30);(30,30;30,0);(30,0;0,0);(50,0;50,30);(50,30;80,30);(80,30;80,0);(80,0;50,0);(50,40;50,70);(50,70;80,70);(80,40;50,40)");
EXPECT_EQ ((r1 - r1).to_string (100), "");
EXPECT_EQ (r2.merged ().to_string (100), "(60,10;60,20);(60,20;70,20);(70,20;70,10);(70,10;60,10);(10,10;10,40);(10,40;40,40);(40,40;40,10);(40,10;10,10);(80,40;80,70);(80,70;140,70);(140,70;140,40);(140,40;80,40)");
EXPECT_EQ (rr1.to_string (100), "(0,0;0,30;30,30;30,0);(50,0;50,30;80,30;80,0);(50,40;50,70;80,70;80,40)");
EXPECT_EQ (r2.selected_interacting (rr1).to_string (100), "(60,10;60,20);(60,20;70,20);(70,20;70,10);(70,10;60,10);(10,10;10,40);(40,10;10,10);(80,40;80,70);(80,70;140,70);(140,40;80,40)");
EXPECT_EQ (r2.selected_interacting_differential (rr1).first.to_string (100), "(60,10;60,20);(60,20;70,20);(70,20;70,10);(70,10;60,10);(10,10;10,40);(40,10;10,10);(80,40;80,70);(80,70;140,70);(140,40;80,40)");
EXPECT_EQ (r2.selected_not_interacting (rr1).to_string (100), "(10,40;40,40);(40,40;40,10);(140,70;140,40)");
EXPECT_EQ (r2.selected_interacting_differential (rr1).second.to_string (100), "(10,40;40,40);(40,40;40,10);(140,70;140,40)");
EXPECT_EQ (db::compare (r1 & r2, "(80,70;80,40)"), true);
EXPECT_EQ (db::compare (r1 + r2, "(0,0;0,30);(0,30;30,30);(30,30;30,0);(30,0;0,0);(50,0;50,30);(50,30;80,30);(80,30;80,0);(80,0;50,0);(50,40;50,70);(50,70;80,70);(80,70;80,40);(80,40;50,40);(60,10;60,20);(60,20;70,20);(70,20;70,10);(70,10;60,10);(10,10;10,40);(10,40;40,40);(40,40;40,10);(40,10;10,10);(80,40;80,70);(80,70;110,70);(110,70;110,40);(110,40;80,40);(110,40;110,70);(110,70;140,70);(140,70;140,40);(140,40;110,40)"), true);
EXPECT_EQ (db::compare ((r1 + r2).merged (), "(0,0;0,30);(0,30;30,30);(30,30;30,0);(30,0;0,0);(50,0;50,30);(50,30;80,30);(80,30;80,0);(80,0;50,0);(50,40;50,70);(60,10;60,20);(60,20;70,20);(70,20;70,10);(70,10;60,10);(10,10;10,40);(10,40;40,40);(40,40;40,10);(40,10;10,10);(50,70;140,70);(140,70;140,40);(140,40;50,40)"), true);
EXPECT_EQ (db::compare (r1 | r2, "(0,0;0,30);(0,30;30,30);(30,30;30,0);(30,0;0,0);(50,0;50,30);(50,30;80,30);(80,30;80,0);(80,0;50,0);(50,40;50,70);(60,10;60,20);(60,20;70,20);(70,20;70,10);(70,10;60,10);(10,10;10,40);(10,40;40,40);(40,40;40,10);(40,10;10,10);(50,70;140,70);(140,70;140,40);(140,40;50,40)"), true);
EXPECT_EQ (db::compare (r1 ^ r2, "(0,0;0,30);(0,30;30,30);(30,30;30,0);(30,0;0,0);(50,0;50,30);(50,30;80,30);(80,30;80,0);(80,0;50,0);(50,40;50,70);(60,10;60,20);(60,20;70,20);(70,20;70,10);(70,10;60,10);(10,10;10,40);(10,40;40,40);(40,40;40,10);(40,10;10,10);(50,70;140,70);(140,70;140,40);(140,40;50,40)"), true);
EXPECT_EQ (db::compare (r1 ^ r1, ""), true);
EXPECT_EQ (db::compare (r1 - r2, "(0,0;0,30);(0,30;30,30);(30,30;30,0);(30,0;0,0);(50,0;50,30);(50,30;80,30);(80,30;80,0);(80,0;50,0);(50,40;50,70);(50,70;80,70);(80,40;50,40)"), true);
EXPECT_EQ (db::compare (r1 - r1, ""), true);
EXPECT_EQ (db::compare (r2.merged (), "(60,10;60,20);(60,20;70,20);(70,20;70,10);(70,10;60,10);(10,10;10,40);(10,40;40,40);(40,40;40,10);(40,10;10,10);(80,40;80,70);(80,70;140,70);(140,70;140,40);(140,40;80,40)"), true);
EXPECT_EQ (db::compare (rr1, "(0,0;0,30;30,30;30,0);(50,0;50,30;80,30;80,0);(50,40;50,70;80,70;80,40)"), true);
EXPECT_EQ (db::compare (r2.selected_interacting (rr1), "(60,10;60,20);(60,20;70,20);(70,20;70,10);(70,10;60,10);(10,10;10,40);(40,10;10,10);(80,40;80,70);(80,70;140,70);(140,40;80,40)"), true);
EXPECT_EQ (db::compare (r2.selected_interacting_differential (rr1).first, "(60,10;60,20);(60,20;70,20);(70,20;70,10);(70,10;60,10);(10,10;10,40);(40,10;10,10);(80,40;80,70);(80,70;140,70);(140,40;80,40)"), true);
EXPECT_EQ (db::compare (r2.selected_not_interacting (rr1), "(10,40;40,40);(40,40;40,10);(140,70;140,40)"), true);
EXPECT_EQ (db::compare (r2.selected_interacting_differential (rr1).second, "(10,40;40,40);(40,40;40,10);(140,70;140,40)"), true);
db::Edges r2dup = r2;
r2.select_interacting (rr1);
EXPECT_EQ (db::compare (r2, "(60,10;60,20);(60,20;70,20);(70,20;70,10);(70,10;60,10);(10,10;10,40);(40,10;10,10);(80,40;80,70);(80,70;140,70);(140,40;80,40)"), true);
r2 = r2dup;
r2.select_not_interacting (rr1);
EXPECT_EQ (r2.to_string (100), "(10,40;40,40);(40,40;40,10);(140,70;140,40)");
EXPECT_EQ (db::compare (r2, "(10,40;40,40);(40,40;40,10);(140,70;140,40)"), true);
r2 = db::Edges (db::RecursiveShapeIterator (ly, ly.cell (top), l2), false);
EXPECT_EQ (r2.has_valid_edges (), false);
@@ -895,9 +897,9 @@ TEST(22)
ee.insert (db::Edge (4000,0,4000,-2000));
ee.insert (db::Edge (4000,-2000,-2000,-2000));
EXPECT_EQ (db::compare ((e & ee), "(400,0;-2000,0);(500,-174;400,0);(1000,0;900,-173);(4000,0;1000,0)"), true);
EXPECT_EQ (db::compare (e.andnot(ee).first, "(400,0;-2000,0);(500,-174;400,0);(1000,0;900,-173);(4000,0;1000,0)"), true);
EXPECT_EQ (db::compare (e.intersections (ee), "(400,0;-2000,0);(500,-174;400,0);(1000,0;900,-173);(4000,0;1000,0)"), true);
EXPECT_EQ (db::compare ((e & ee), "(400,0;-2000,0);(500,-173;400,0);(1000,0;900,-174);(4000,0;1000,0)"), true);
EXPECT_EQ (db::compare (e.andnot(ee).first, "(400,0;-2000,0);(500,-173;400,0);(1000,0;900,-174);(4000,0;1000,0)"), true);
EXPECT_EQ (db::compare (e.intersections (ee), "(400,0;-2000,0);(500,-173;400,0);(1000,0;900,-174);(4000,0;1000,0)"), true);
// Edge/edge intersections
ee.clear ();
@@ -1157,6 +1159,214 @@ TEST(28)
EXPECT_EQ (db::compare (ee.in (e, true), "(0,0;0,2000);(100,1000;0,2000)"), true);
}
// edge merge with dots -> dots are merged, but are retained
TEST(29)
{
db::Edges e;
e.insert (db::Edge (db::Point(0, 0), db::Point (100, 0)));
e.insert (db::Edge (db::Point(110, 0), db::Point (110, 0)));
EXPECT_EQ (e.merged ().to_string (), "(0,0;100,0);(110,0;110,0)");
e.insert (db::Edge (db::Point(100, 0), db::Point (110, 0)));
// dots do not participate in merge
EXPECT_EQ (e.merged ().to_string (), "(0,0;110,0)");
e.clear ();
e.insert (db::Edge (db::Point(110, 0), db::Point (110, 0)));
e.insert (db::Edge (db::Point(110, 0), db::Point (110, 0)));
// dots do not participate in merge
EXPECT_EQ (e.merged ().to_string (), "(110,0;110,0)");
}
// interacting with count
TEST(30)
{
db::Edges e;
e.insert (db::Edge (db::Point (0, 0), db::Point (100, 0)));
e.insert (db::Edge (db::Point (100, 0), db::Point (200, 0)));
e.insert (db::Edge (db::Point (0, 10), db::Point (200, 10)));
e.insert (db::Edge (db::Point (0, 20), db::Point (200, 20)));
e.insert (db::Edge (db::Point (0, 30), db::Point (200, 30)));
db::Edges e2;
e2.insert (db::Edge (db::Point (100, 0), db::Point (100, 10)));
e2.insert (db::Edge (db::Point (100, 0), db::Point (100, 30)));
e2.insert (db::Edge (db::Point (110, 10), db::Point (110, 30)));
e2.merge ();
e2.insert (db::Edge (db::Point (120, 20), db::Point (120, 20)));
e2.insert (db::Edge (db::Point (130, 30), db::Point (130, 30)));
e2.set_merged_semantics (false);
db::Edges edup;
EXPECT_EQ (e.selected_interacting (e2).to_string (), "(0,0;200,0);(0,10;200,10);(0,20;200,20);(0,30;200,30)");
EXPECT_EQ (e.selected_interacting (e2, size_t (2)).to_string (), "(0,10;200,10);(0,20;200,20);(0,30;200,30)");
EXPECT_EQ (e.selected_interacting (e2, size_t (2), size_t(2)).to_string (), "(0,10;200,10)");
EXPECT_EQ (e.selected_interacting (e2, size_t (2), size_t(3)).to_string (), "(0,10;200,10);(0,20;200,20);(0,30;200,30)");
EXPECT_EQ (e.selected_interacting (e2, size_t (3)).to_string (), "(0,20;200,20);(0,30;200,30)");
EXPECT_EQ (e.selected_interacting (e2, size_t (4)).to_string (), "");
edup = e;
edup.select_interacting (e2, size_t (2), size_t(3));
EXPECT_EQ (edup.to_string (), "(0,10;200,10);(0,20;200,20);(0,30;200,30)");
EXPECT_EQ (e.selected_not_interacting (e2).to_string (), "");
EXPECT_EQ (e.selected_not_interacting (e2, size_t (2)).to_string (), "(0,0;200,0)");
EXPECT_EQ (e.selected_not_interacting (e2, size_t (2), size_t(2)).to_string (), "(0,0;200,0);(0,20;200,20);(0,30;200,30)");
EXPECT_EQ (e.selected_not_interacting (e2, size_t (2), size_t(3)).to_string (), "(0,0;200,0)");
EXPECT_EQ (e.selected_not_interacting (e2, size_t (3)).to_string (), "(0,0;200,0);(0,10;200,10)");
EXPECT_EQ (e.selected_not_interacting (e2, size_t (4)).to_string (), "(0,0;200,0);(0,10;200,10);(0,20;200,20);(0,30;200,30)");
edup = e;
edup.select_not_interacting (e2, size_t (2), size_t(3));
EXPECT_EQ (edup.to_string (), "(0,0;200,0)");
EXPECT_EQ (e.selected_interacting_differential (e2, size_t (2), size_t(3)).first.to_string (), "(0,10;200,10);(0,20;200,20);(0,30;200,30)");
EXPECT_EQ (e.selected_interacting_differential (e2, size_t (2), size_t(3)).second.to_string (), "(0,0;200,0)");
db::Region r2;
r2.insert (db::Box (db::Point (99, 0), db::Point (101, 10)));
r2.insert (db::Box (db::Point (99, 0), db::Point (101, 30)));
r2.insert (db::Box (db::Point (109, 10), db::Point (111, 30)));
r2.insert (db::Box (db::Point (119, 19), db::Point (121, 21)));
r2.insert (db::Box (db::Point (129, 29), db::Point (131, 31)));
EXPECT_EQ (e.selected_interacting (r2).to_string (), "(0,0;200,0);(0,10;200,10);(0,20;200,20);(0,30;200,30)");
EXPECT_EQ (e.selected_interacting (r2, size_t (2)).to_string (), "(0,10;200,10);(0,20;200,20);(0,30;200,30)");
EXPECT_EQ (e.selected_interacting (r2, size_t (2), size_t(2)).to_string (), "(0,10;200,10)");
EXPECT_EQ (e.selected_interacting (r2, size_t (2), size_t(3)).to_string (), "(0,10;200,10);(0,20;200,20);(0,30;200,30)");
EXPECT_EQ (e.selected_interacting (r2, size_t (3)).to_string (), "(0,20;200,20);(0,30;200,30)");
EXPECT_EQ (e.selected_interacting (r2, size_t (4)).to_string (), "");
edup = e;
edup.select_interacting (r2, size_t (2), size_t(3));
EXPECT_EQ (edup.to_string (), "(0,10;200,10);(0,20;200,20);(0,30;200,30)");
EXPECT_EQ (e.selected_not_interacting (r2).to_string (), "");
EXPECT_EQ (e.selected_not_interacting (r2, size_t (2)).to_string (), "(0,0;200,0)");
EXPECT_EQ (e.selected_not_interacting (r2, size_t (2), size_t(2)).to_string (), "(0,0;200,0);(0,20;200,20);(0,30;200,30)");
EXPECT_EQ (e.selected_not_interacting (r2, size_t (2), size_t(3)).to_string (), "(0,0;200,0)");
EXPECT_EQ (e.selected_not_interacting (r2, size_t (3)).to_string (), "(0,0;200,0);(0,10;200,10)");
EXPECT_EQ (e.selected_not_interacting (r2, size_t (4)).to_string (), "(0,0;200,0);(0,10;200,10);(0,20;200,20);(0,30;200,30)");
edup = e;
edup.select_not_interacting (r2, size_t (2), size_t(3));
EXPECT_EQ (edup.to_string (), "(0,0;200,0)");
EXPECT_EQ (e.selected_interacting_differential (r2, size_t (2), size_t(3)).first.to_string (), "(0,10;200,10);(0,20;200,20);(0,30;200,30)");
EXPECT_EQ (e.selected_interacting_differential (r2, size_t (2), size_t(3)).second.to_string (), "(0,0;200,0)");
}
// borrowed from deep edges tests
TEST(31)
{
db::Layout ly;
{
std::string fn (tl::testdata ());
fn += "/algo/deep_edges_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);
unsigned int l2 = ly.get_layer (db::LayerProperties (2, 0));
unsigned int l21 = ly.get_layer (db::LayerProperties (2, 1));
unsigned int l3 = ly.get_layer (db::LayerProperties (3, 0));
unsigned int lempty = ly.insert_layer ();
db::Region r2 (db::RecursiveShapeIterator (ly, top_cell, l2));
db::Region r21 (db::RecursiveShapeIterator (ly, top_cell, l21));
db::Region r3 (db::RecursiveShapeIterator (ly, top_cell, l3));
db::Region r2and3 = r2 & r3;
db::Edges e2 = r2.edges ();
db::Edges e21 = r21.edges ();
db::Edges e3 = r3.edges ();
db::Edges e3copy = r3.edges ();
db::Edges e2and3 = r2and3.edges ();
db::Edges eempty (db::RecursiveShapeIterator (ly, top_cell, lempty));
db::Edges edots = e2and3.processed (db::EdgeSegmentSelector (-1, 0, 0));
db::Edges edotscopy = e2and3.processed (db::EdgeSegmentSelector (-1, 0, 0));
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)), e3);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (11, 0)), e2and3);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (12, 0)), edots);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (13, 0)), edots.merged ());
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (20, 0)), e3 & e2and3);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (21, 0)), e3 & edots);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (22, 0)), e3 & eempty);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (23, 0)), e3 & e3copy);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (24, 0)), eempty & e2and3);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (25, 0)), edots & edotscopy);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (26, 0)), edots & e2);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (27, 0)), e21 & edots);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (28, 0)), edots & e21);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (30, 0)), e3 - e2and3);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (31, 0)), e3 - edots);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (32, 0)), e3 - eempty);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (33, 0)), e3 - e3copy);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (34, 0)), eempty - e2and3);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (35, 0)), edots - edotscopy);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (36, 0)), edots - e2);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (37, 0)), e21 - edots);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (38, 0)), edots - e21);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (40, 0)), e3 ^ e2and3);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (41, 0)), e3 ^ edots);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (42, 0)), e3 ^ eempty);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (43, 0)), e3 ^ e3copy);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (44, 0)), eempty ^ e2and3);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (45, 0)), edots ^ edotscopy);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (46, 0)), edots ^ e2);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (47, 0)), e21 ^ edots);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (48, 0)), edots ^ e21);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (50, 0)), e3.andnot(e2and3).first);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (51, 0)), e3.andnot(edots).first);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (52, 0)), e3.andnot(eempty).first);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (53, 0)), e3.andnot(e3copy).first);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (54, 0)), eempty.andnot(e2and3).first);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (55, 0)), edots.andnot(edotscopy).first);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (56, 0)), edots.andnot(e2).first);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (57, 0)), e21.andnot(edots).first);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (58, 0)), edots.andnot(e21).first);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (60, 0)), e3.andnot(e2and3).second);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (61, 0)), e3.andnot(edots).second);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (62, 0)), e3.andnot(eempty).second);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (63, 0)), e3.andnot(e3copy).second);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (64, 0)), eempty.andnot(e2and3).second);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (65, 0)), edots.andnot(edotscopy).second);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (66, 0)), edots.andnot(e2).second);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (67, 0)), e21.andnot(edots).second);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (68, 0)), edots.andnot(e21).second);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (70, 0)), e3.intersections(e2and3));
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (71, 0)), e3.intersections(edots));
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (72, 0)), e3.intersections(eempty));
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (73, 0)), e3.intersections(e3copy));
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (74, 0)), eempty.intersections(e2and3));
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (75, 0)), edots.intersections(edotscopy));
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (76, 0)), edots.intersections(e2));
// test, whether dots are not merged
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (77, 0)), edots.intersections(e2).select_interacting(e2));
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (78, 0)), e21.intersections(edots));
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (79, 0)), edots.intersections(e21));
CHECKPOINT();
db::compare_layouts (_this, target, tl::testdata () + "/algo/deep_edges_au3_flat.gds");
}
// GitHub issue #72 (Edges/Region NOT issue)
TEST(100)
{
+20
View File
@@ -83,5 +83,25 @@ TEST(1)
EXPECT_EQ (db::edge_is_outside (db::Edge (db::Point (0, 11), db::Point (10, 11)), db::Polygon (db::Box (0, 0, 10, 10))), true);
EXPECT_EQ (db::edge_is_outside (db::Edge (db::Point (0, 5), db::Point (10, 5)), db::Polygon (db::Box (0, 0, 10, 10))), false);
EXPECT_EQ (db::edge_is_outside (db::Edge (db::Point (-5, 5), db::Point (15, 5)), db::Polygon (db::Box (0, 0, 10, 10))), false);
EXPECT_EQ (db::edge_is_outside (db::Edge (db::Point (-10, 5), db::Point (0, 5)), db::Polygon (db::Box (0, 0, 10, 10))), true);
EXPECT_EQ (db::edge_is_outside (db::Edge (db::Point (-10, 0), db::Point (10, 0)), db::Polygon (db::Box (0, 0, 10, 10))), true);
db::Point pts[] = {
db::Point (0, 0),
db::Point (0, 10),
db::Point (20, 10),
db::Point (20, -10),
db::Point (10, -10),
db::Point (10, 0)
};
db::Polygon poly;
poly.assign_hull (pts + 0, pts + sizeof(pts) / sizeof(pts[0]));
EXPECT_EQ (db::edge_is_outside (db::Edge (db::Point (-10, 10), db::Point (20, 10)), poly), true);
EXPECT_EQ (db::edge_is_outside (db::Edge (db::Point (-10, -10), db::Point (20, -10)), poly), true);
EXPECT_EQ (db::edge_is_outside (db::Edge (db::Point (-10, 0), db::Point (11, 0)), poly), false);
EXPECT_EQ (db::edge_is_outside (db::Edge (db::Point (-10, 0), db::Point (10, 0)), poly), true);
EXPECT_EQ (db::edge_is_outside (db::Edge (db::Point (-10, 0), db::Point (9, 0)), poly), true);
}
@@ -0,0 +1,80 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2024 Matthias Koefferlein
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "tlUnitTest.h"
#include "tlString.h"
#include "dbRegionProcessors.h"
TEST(1_RegionToEdgesProcessor)
{
db::Point hull[] = {
db::Point (0, 0),
db::Point (0, 1000),
db::Point (1000, 1000),
db::Point (1000, 2000),
db::Point (2000, 2000),
db::Point (2000, 1000),
db::Point (3000, 1000),
db::Point (3000, 0)
};
db::Point hole[] = {
db::Point (100, 100),
db::Point (2900, 100),
db::Point (2900, 900),
db::Point (100, 900)
};
db::Polygon poly;
poly.assign_hull (hull + 0, hull + sizeof (hull) / sizeof (hull[0]));
poly.insert_hole (hole + 0, hole + sizeof (hole) / sizeof (hole[0]));
std::vector<db::Edge> result;
result.clear ();
db::PolygonToEdgeProcessor ().process (poly, result);
EXPECT_EQ (tl::join (result.begin (), result.end (), ";"), "(0,0;0,1000);(0,1000;1000,1000);(1000,1000;1000,2000);(1000,2000;2000,2000);(2000,2000;2000,1000);(2000,1000;3000,1000);(3000,1000;3000,0);(3000,0;0,0);(100,100;2900,100);(2900,100;2900,900);(2900,900;100,900);(100,900;100,100)");
result.clear ();
db::PolygonToEdgeProcessor (db::PolygonToEdgeProcessor::Concave).process (poly, result);
EXPECT_EQ (tl::join (result.begin (), result.end (), ";"), "(2900,100;2900,900);(2900,900;100,900);(100,900;100,100);(100,100;2900,100)");
result.clear ();
db::PolygonToEdgeProcessor (db::PolygonToEdgeProcessor::Convex).process (poly, result);
EXPECT_EQ (tl::join (result.begin (), result.end (), ";"), "(1000,2000;2000,2000);(3000,1000;3000,0);(3000,0;0,0);(0,0;0,1000)");
result.clear ();
db::PolygonToEdgeProcessor (db::PolygonToEdgeProcessor::Step).process (poly, result);
EXPECT_EQ (tl::join (result.begin (), result.end (), ";"), "(0,1000;1000,1000);(1000,1000;1000,2000);(2000,2000;2000,1000);(2000,1000;3000,1000)");
result.clear ();
db::PolygonToEdgeProcessor (db::PolygonToEdgeProcessor::StepOut).process (poly, result);
EXPECT_EQ (tl::join (result.begin (), result.end (), ";"), "(1000,1000;1000,2000);(2000,1000;3000,1000)");
result.clear ();
db::PolygonToEdgeProcessor (db::PolygonToEdgeProcessor::StepIn).process (poly, result);
EXPECT_EQ (tl::join (result.begin (), result.end (), ";"), "(0,1000;1000,1000);(2000,2000;2000,1000)");
}
+1
View File
@@ -87,6 +87,7 @@ SOURCES = \
dbDeepTextsTests.cc \
dbNetShapeTests.cc \
dbHierNetsProcessorTests.cc \
dbRegionProcessorTests.cc \
dbAsIfFlatRegionTests.cc
INCLUDEPATH += $$TL_INC $$DB_INC $$GSI_INC
+15
View File
@@ -455,6 +455,7 @@ out = in.drc(covering(other) &gt; 2)
<p>Usage:</p>
<ul>
<li><tt>expression.edges</tt></li>
<li><tt>expression.edges(mode)</tt></li>
</ul>
<p>
Polygons will be separated into edges forming their contours. Edge pairs will be
@@ -468,6 +469,20 @@ for the edges:
<pre>
out = in.drc(primary.edges)
</pre>
</p><p>
The "mode" argument allows selecting specific edges from polygons.
Allowed values are: "convex", "concave", "step", "step_in" and "step_out".
"step" generates edges only if they provide a step between two other
edges. "step_in" creates edges that make a step towards the inside of
the polygon and "step_out" creates edges that make a step towards the
outside:
</p><p>
<pre>
out = in.drc(primary.edges(convex))
</pre>
</p><p>
The mode argument is ignored when translating other objects than
polygons.
</p>
<a name="end_segments"/><h2>"end_segments" - Returns the part at the end of each edge of the input</h2>
<keyword name="end_segments"/>
+35
View File
@@ -783,6 +783,11 @@ apply to this method.
</ul>
<a name="edges"/><h2>"edges" - Decomposes the layer into single edges</h2>
<keyword name="edges"/>
<p>Usage:</p>
<ul>
<li><tt>layer.edges</tt></li>
<li><tt>layer.edges(mode)</tt></li>
</ul>
<p>
Edge pair collections are decomposed into the individual edges that make up
the edge pairs. Polygon layers are decomposed into the edges making up the
@@ -791,6 +796,36 @@ is called on.
</p><p>
Merged semantics applies, i.e. the result reflects merged polygons rather than
individual ones unless raw mode is chosen.
</p><p>
The "mode" argument allows selecting specific edges from polygons.
Allowed values are: "convex", "concave", "step", "step_in" and "step_out".
"step" generates edges only if they provide a step between two other
edges. "step_in" creates edges that make a step towards the inside of
the polygon and "step_out" creates edges that make a step towards the
outside:
</p><p>
<pre>
out = in.edges(convex)
</pre>
</p><p>
This feature is only available for polygon layers.
</p><p>
The following images show the effect of the mode argument:
</p><p>
<table>
<tr>
<td><img src="/images/drc_edge_modes1.png"/></td>
<td><img src="/images/drc_edge_modes2.png"/></td>
</tr>
<tr>
<td><img src="/images/drc_edge_modes3.png"/></td>
<td><img src="/images/drc_edge_modes4.png"/></td>
</tr>
<tr>
<td><img src="/images/drc_edge_modes5.png"/></td>
<td><img src="/images/drc_edge_modes6.png"/></td>
</tr>
</table>
</p>
<a name="edges?"/><h2>"edges?" - Returns true, if the layer is an edge layer</h2>
<keyword name="edges?"/>
Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

+6
View File
@@ -59,6 +59,12 @@
<file alias="drc_extended2.png">doc/images/drc_extended2.png</file>
<file alias="drc_extended3.png">doc/images/drc_extended3.png</file>
<file alias="drc_extended4.png">doc/images/drc_extended4.png</file>
<file alias="drc_edge_modes1.png">doc/images/drc_edge_modes1.png</file>
<file alias="drc_edge_modes2.png">doc/images/drc_edge_modes2.png</file>
<file alias="drc_edge_modes3.png">doc/images/drc_edge_modes3.png</file>
<file alias="drc_edge_modes4.png">doc/images/drc_edge_modes4.png</file>
<file alias="drc_edge_modes5.png">doc/images/drc_edge_modes5.png</file>
<file alias="drc_edge_modes6.png">doc/images/drc_edge_modes6.png</file>
<file alias="drc_extents1.png">doc/images/drc_extents1.png</file>
<file alias="drc_extents2.png">doc/images/drc_extents2.png</file>
<file alias="drc_inside.png">doc/images/drc_inside.png</file>
@@ -991,6 +991,7 @@ CODE
# @name edges
# @brief Converts the input shapes into edges
# @synopsis expression.edges
# @synopsis expression.edges(mode)
#
# Polygons will be separated into edges forming their contours. Edge pairs will be
# decomposed into individual edges.
@@ -1003,9 +1004,38 @@ CODE
# @code
# out = in.drc(primary.edges)
# @/code
#
# The "mode" argument allows selecting specific edges from polygons.
# Allowed values are: "convex", "concave", "step", "step_in" and "step_out".
# "step" generates edges only if they provide a step between two other
# edges. "step_in" creates edges that make a step towards the inside of
# the polygon and "step_out" creates edges that make a step towards the
# outside:
#
# @code
# out = in.drc(primary.edges(convex))
# @/code
#
# In addition, "not_.." variants are available which selects edges
# not qualifying for the specific mode:
#
# @code
# out = in.drc(primary.edges(not_convex))
# @/code
#
# The mode argument is ignored when translating other objects than
# polygons.
def edges
return DRCOpNodeFilter::new(@engine, self, :new_edges, "edges")
def edges(mode = nil)
if mode
if ! mode.is_a?(DRC::DRCEdgeMode)
raise "The mode argument needs to be a mode type (convex, concave, step, step_in or step_out)"
end
mode = mode.value
else
mode = RBA::EdgeMode::All
end
return DRCOpNodeFilter::new(@engine, self, :new_edges, "edges", mode)
end
# %DRC%
@@ -255,6 +255,46 @@ module DRC
DRCJoinFlag::new(true)
end
def convex
DRCEdgeMode::new(RBA::EdgeMode::Convex)
end
def not_convex
DRCEdgeMode::new(RBA::EdgeMode::NotConvex)
end
def concave
DRCEdgeMode::new(RBA::EdgeMode::Concave)
end
def not_concave
DRCEdgeMode::new(RBA::EdgeMode::NotConcave)
end
def step_in
DRCEdgeMode::new(RBA::EdgeMode::StepIn)
end
def not_step_in
DRCEdgeMode::new(RBA::EdgeMode::NotStepIn)
end
def step_out
DRCEdgeMode::new(RBA::EdgeMode::StepOut)
end
def not_step_out
DRCEdgeMode::new(RBA::EdgeMode::NotStepOut)
end
def step
DRCEdgeMode::new(RBA::EdgeMode::Step)
end
def not_step
DRCEdgeMode::new(RBA::EdgeMode::NotStep)
end
def padding_zero
DRCDensityPadding::new(:zero)
end
+52 -2
View File
@@ -3387,6 +3387,8 @@ CODE
# %DRC%
# @name edges
# @brief Decomposes the layer into single edges
# @synopsis layer.edges
# @synopsis layer.edges(mode)
#
# Edge pair collections are decomposed into the individual edges that make up
# the edge pairs. Polygon layers are decomposed into the edges making up the
@@ -3395,13 +3397,61 @@ CODE
#
# Merged semantics applies, i.e. the result reflects merged polygons rather than
# individual ones unless raw mode is chosen.
#
# The "mode" argument allows selecting specific edges from polygons.
# Allowed values are: "convex", "concave", "step", "step_in" and "step_out".
# "step" generates edges only if they provide a step between two other
# edges. "step_in" creates edges that make a step towards the inside of
# the polygon and "step_out" creates edges that make a step towards the
# outside:
#
# @code
# out = in.edges(convex)
# @/code
#
# In addition, "not_.." variants are available which selects edges
# not qualifying for the specific mode:
#
# @code
# out = in.edges(not_convex)
# @/code
#
# The mode argument is only available for polygon layers.
#
# The following images show the effect of the mode argument:
#
# @table
# @tr
# @td @img(/images/drc_edge_modes1.png) @/td
# @td @img(/images/drc_edge_modes2.png) @/td
# @/tr
# @tr
# @td @img(/images/drc_edge_modes3.png) @/td
# @td @img(/images/drc_edge_modes4.png) @/td
# @/tr
# @tr
# @td @img(/images/drc_edge_modes5.png) @/td
# @td @img(/images/drc_edge_modes6.png) @/td
# @/tr
# @/table
%w(edges).each do |f|
eval <<"CODE"
def #{f}
def #{f}(mode = nil)
if mode
if ! mode.is_a?(DRC::DRCEdgeMode)
raise "The mode argument needs to be a mode type (convex, concave, step, step_in or step_out)"
end
if ! self.data.is_a?(RBA::Region)
raise "The mode argument is only available for polygon layers"
end
mode = mode.value
else
mode = RBA::EdgeMode::All
end
@engine._context("#{f}") do
if self.data.is_a?(RBA::Region)
DRCLayer::new(@engine, @engine._tcmd(self.data, 0, RBA::Edges, :#{f}))
DRCLayer::new(@engine, @engine._tcmd(self.data, 0, RBA::Edges, :#{f}, mode))
elsif self.data.is_a?(RBA::EdgePairs)
DRCLayer::new(@engine, @engine._cmd(self.data, :#{f}))
else
+8
View File
@@ -57,6 +57,14 @@ module DRC
end
end
# A wrapper for the edge mode value for Region#edges
class DRCEdgeMode
attr_accessor :value
def initialize(v)
self.value = v
end
end
# A wrapper for the join flag for extended
class DRCJoinFlag
attr_accessor :value
+30
View File
@@ -1672,3 +1672,33 @@ TEST(92_issue1594_dual_top)
CHECKPOINT ();
compare_netlists (_this, output, au);
}
TEST(100_edge_interaction_with_count)
{
run_test (_this, "100", false);
}
TEST(100d_edge_interaction_with_count)
{
run_test (_this, "100", true);
}
TEST(101_edge_booleans_with_dots)
{
run_test (_this, "101", false);
}
TEST(101d_edge_booleans_with_dots)
{
run_test (_this, "101", true);
}
TEST(102_edge_modes)
{
run_test (_this, "102", false);
}
TEST(102d_edge_modes)
{
run_test (_this, "102", true);
}
@@ -1080,6 +1080,12 @@ OASISReader::do_read (db::Layout &layout)
LNameJoinOp2 op2;
layer_names ().add (l1, l2 + 1, dt_map, op2);
// for singular layers, force a layer entry:
// this way we can have empty, but existing layers.
if (l1 == l2 && dt1 == dt2) {
open_dl (layout, db::LDPair (l1, dt1));
}
reset_modal_variables ();
// ignore properties attached to this name item
@@ -22,6 +22,7 @@
#include "dbOASISReader.h"
#include "dbOASISWriter.h"
#include "dbTextWriter.h"
#include "dbTestSupport.h"
#include "tlLog.h"
@@ -487,21 +488,18 @@ TEST(99)
// XGEOMTRY tests (#773)
TEST(100)
{
const char *expected =
const char *expected =
"begin_lib 0.0001\n"
"begin_cell {mask}\n"
"boundary 7 1 {13237 5356} {13210 5490} {13192 5530} {13170 5563} {13130 5586} {13090 5583} {13070 5570} {13050 5551} {13037 5530} {13021 5490} {12988 5378} {12938 5390} {12963 5530} {12977 5570} {12998 5610} {13034 5650} {13051 5663} {13090 5678} {13130 5679} {13171 5667} {13210 5638} {13232 5611} {13253 5570} {13274 5490} {13291 5365} {13237 5356}\n"
"boundary 4 0 {10772 1658} {10772 1744} {14510 1744} {14510 1658} {10772 1658}\n"
"boundary 4 0 {14510 1658} {14510 1744} {15672 1744} {15672 1658} {14510 1658}\n"
"boundary 4 0 {18157 647} {18157 676} {21642 676} {21642 647} {18157 647}\n"
"boundary 6 0 {6743 2449} {6743 4230} {9061 4230} {9061 2449} {6743 2449}\n"
"boundary 2 3 {21642 3613} {21642 4005} {19409 4005} {19409 6980} {21812 6980} {21812 4958} {21942 4958} {21942 4005} {21812 4005} {21812 3613} {21642 3613}\n"
"boundary 2 4 {21642 4005} {21642 4958} {21812 4958} {21812 4005} {21642 4005}\n"
"boundary 8 0 {21680 4106} {21640 4107} {21600 4118} {21574 4130} {21560 4138} {21520 4163} {21509 4170} {21480 4194} {21458 4210} {21440 4227} {21411 4250} {21400 4262} {21366 4290} {21360 4298} {21324 4330} {21320 4335} {21282 4370} {21280 4373} {21241 4410} {21240 4411} {21200 4450} {21160 4490} {21159 4490} {21039 4610} {21000 4650} {20960 4690} {20960 4691} {20921 4730} {20920 4732} {20896 4770} {20886 4810} {20882 4850} {20880 4930} {20880 5330} {20920 5370} {20960 5370} {21000 5340} {21013 5330} {21040 5325} {21080 5309} {21120 5291} {21121 5290} {21160 5276} {21200 5258} {21210 5250} {21240 5240} {21280 5222} {21295 5210} {21320 5202} {21360 5181} {21374 5170} {21400 5160} {21440 5136} {21447 5130} {21480 5112} {21510 5090} {21520 5086} {21560 5058} {21568 5050} {21600 5027} {21617 5010} {21640 4993} {21662 4970} {21680 4955} {21701 4930} {21720 4910} {21735 4890} {21760 4856} {21764 4850} {21786 4810} {21800 4781} {21805 4770} {21818 4730} {21828 4690} {21836 4650} {21840 4616} {21841 4610} {21845 4530} {21845 4450} {21844 4410} {21841 4370} {21840 4358} {21836 4330} {21829 4290} {21818 4250} {21803 4210} {21800 4205} {21778 4170} {21760 4148} {21738 4130} {21720 4118} {21680 4106}\n"
"boundary 1 0 {17922 6288} {17922 6510} {18150 6510} {18150 6288} {17922 6288}\n"
"boundary 1 0 {18157 647} {18157 676} {21630 676} {21630 647} {18157 647}\n"
"boundary 1 0 {21956 0} {21956 89} {22047 89} {22047 0} {21956 0}\n"
"boundary 2 3 {21642 3613} {21642 4005} {19409 4005} {19409 6980} {21812 6980} {21812 4958} {21942 4958} {21942 4005} {21812 4005} {21812 3613} {21642 3613}\n"
"boundary 2 4 {21642 4005} {21642 4958} {21812 4958} {21812 4005} {21642 4005}\n"
"boundary 3 0 {15392 1744} {15392 1774} {15672 1774} {15672 1744} {15392 1744}\n"
"boundary 4 0 {10772 1658} {10772 1744} {14510 1744} {14510 1658} {10772 1658}\n"
"boundary 4 0 {14510 1658} {14510 1744} {15672 1744} {15672 1658} {14510 1658}\n"
"boundary 4 0 {18157 647} {18157 676} {21642 676} {21642 647} {18157 647}\n"
"boundary 5 1 {15550 1658} {15550 1673} {15570 1673} {15570 1658} {15550 1658}\n"
"boundary 5 1 {15661 1657} {15641 1659} {15642 1671} {15662 1669} {15661 1657}\n"
"boundary 5 1 {18150 7440} {18150 7460} {18162 7460} {18162 7440} {18150 7440}\n"
@@ -519,6 +517,9 @@ TEST(100)
"boundary 5 1 {25710 1978} {25710 1998} {25722 1998} {25722 1978} {25710 1978}\n"
"boundary 5 1 {25710 2800} {25710 2820} {25722 2820} {25722 2800} {25710 2800}\n"
"boundary 5 2 {18074 6408} {17971 6486} {17983 6502} {18086 6424} {18074 6408}\n"
"boundary 6 0 {6743 2449} {6743 4230} {9061 4230} {9061 2449} {6743 2449}\n"
"boundary 7 1 {13237 5356} {13210 5490} {13192 5530} {13170 5563} {13130 5586} {13090 5583} {13070 5570} {13050 5551} {13037 5530} {13021 5490} {12988 5378} {12938 5390} {12963 5530} {12977 5570} {12998 5610} {13034 5650} {13051 5663} {13090 5678} {13130 5679} {13171 5667} {13210 5638} {13232 5611} {13253 5570} {13274 5490} {13291 5365} {13237 5356}\n"
"boundary 8 0 {21680 4106} {21640 4107} {21600 4118} {21574 4130} {21560 4138} {21520 4163} {21509 4170} {21480 4194} {21458 4210} {21440 4227} {21411 4250} {21400 4262} {21366 4290} {21360 4298} {21324 4330} {21320 4335} {21282 4370} {21280 4373} {21241 4410} {21240 4411} {21200 4450} {21160 4490} {21159 4490} {21039 4610} {21000 4650} {20960 4690} {20960 4691} {20921 4730} {20920 4732} {20896 4770} {20886 4810} {20882 4850} {20880 4930} {20880 5330} {20920 5370} {20960 5370} {21000 5340} {21013 5330} {21040 5325} {21080 5309} {21120 5291} {21121 5290} {21160 5276} {21200 5258} {21210 5250} {21240 5240} {21280 5222} {21295 5210} {21320 5202} {21360 5181} {21374 5170} {21400 5160} {21440 5136} {21447 5130} {21480 5112} {21510 5090} {21520 5086} {21560 5058} {21568 5050} {21600 5027} {21617 5010} {21640 4993} {21662 4970} {21680 4955} {21701 4930} {21720 4910} {21735 4890} {21760 4856} {21764 4850} {21786 4810} {21800 4781} {21805 4770} {21818 4730} {21828 4690} {21836 4650} {21840 4616} {21841 4610} {21845 4530} {21845 4450} {21844 4410} {21841 4370} {21840 4358} {21836 4330} {21829 4290} {21818 4250} {21803 4210} {21800 4205} {21778 4170} {21760 4148} {21738 4130} {21720 4118} {21680 4106}\n"
"end_cell\n"
"end_lib\n"
;
@@ -543,6 +544,41 @@ TEST(100)
EXPECT_EQ (std::string (os.string ()), std::string (expected))
}
// Empty layers through LAYERMAP
TEST(101)
{
db::Layout ly;
ly.add_cell ("TOP");
ly.insert_layer (db::LayerProperties (1, 0, "A"));
ly.insert_layer (db::LayerProperties (2, 0, ""));
ly.insert_layer (db::LayerProperties (3, 0, "C"));
std::string tmp_file = tl::TestBase::tmp_file ("tmp_OASISReader101.oas");
{
tl::OutputStream stream (tmp_file);
db::OASISWriter writer;
db::SaveLayoutOptions options;
writer.write (ly, stream, options);
}
db::Layout ly_new;
{
tl::InputStream stream (tmp_file);
db::Reader reader (stream);
reader.read (ly_new);
}
// NOTE: only named layers are written into layer table
EXPECT_EQ (ly_new.cell_by_name ("TOP").first, true);
EXPECT_EQ (int (ly_new.layers ()), 2);
if (int (ly_new.layers ()) == 2) {
EXPECT_EQ (ly_new.get_properties (0).to_string (), "A (1/0)");
EXPECT_EQ (ly_new.get_properties (1).to_string (), "C (3/0)");
}
}
TEST(Bug_121_1)
{
db::Manager m (false);
@@ -255,6 +255,13 @@ void run_test (tl::TestBase *_this, const char *file, bool scaling_test, int com
db::Reader reader (stream);
reader.read (layout);
// named layers create a mismatch between GDS and OASIS, so we unname them here
for (auto l = layout.begin_layers (); l != layout.end_layers (); ++l) {
db::LayerProperties lp = layout.get_properties ((*l).first);
lp.name.clear ();
layout.set_properties ((*l).first, lp);
}
db::SaveLayoutOptions options;
db::OASISWriterOptions oasis_options;
oasis_options.compression_level = compr;
+15 -1
View File
@@ -112,7 +112,6 @@ public:
* @brief Polling: call this function regularly to explicitly establish polling
* (in the Qt framework, this is done automatically within the event loop)
* May throw a tl::CancelException to stop.
* Returns true if a message has arrived.
*/
void tick ();
@@ -209,6 +208,21 @@ private:
InputHttpStreamCallback *mp_callback;
};
/**
* @brief A HTTP stream with .gz support
*/
class TL_PUBLIC InflatingInputHttpStream
: public inflating_input_stream<InputHttpStream>
{
public:
/**
* @brief Open a stream with the given URL
*/
InflatingInputHttpStream (const std::string &url)
: inflating_input_stream<InputHttpStream> (new InputHttpStream (url))
{ }
};
}
#endif
+143 -9
View File
@@ -140,6 +140,125 @@ public:
gzFile zs;
};
// ---------------------------------------------------------------
// inflating_input_stream implementation
/**
* @brief A wrapper that adds generic .gz support
*/
template <class Base>
inflating_input_stream<Base>::inflating_input_stream (Base *delegate)
: m_inflating_stream (delegate), m_is_compressed (false), mp_delegate (delegate)
{
enter_inflate ();
}
template <class Base>
size_t
inflating_input_stream<Base>::read (char *b, size_t n)
{
// TODO: this is somewhat inefficient, but we only use it for pipe and HTTP streams
size_t i = 0;
while (i < n) {
if (m_is_compressed || m_inflating_stream.blen () == 0) {
const char *read = m_inflating_stream.get (1);
if (! read) {
break;
}
*b++ = *read;
i += 1;
} else {
size_t nn = std::min (n - i, m_inflating_stream.blen ());
const char *read = m_inflating_stream.get (nn);
tl_assert (read != 0);
memcpy (b, read, nn);
b += nn;
i += nn;
}
}
return i;
}
template <class Base>
void
inflating_input_stream<Base>::enter_inflate ()
{
// identify and skip header for .gz file
if (auto_detect_gz ()) {
m_is_compressed = true;
m_inflating_stream.inflate (true /* stop after inflated block */);
} else {
m_inflating_stream.unget (m_inflating_stream.pos ());
}
}
template <class Base>
bool
inflating_input_stream<Base>::auto_detect_gz ()
{
std::string header = m_inflating_stream.read_all (10);
if (header.size () < 10) {
return false;
}
const unsigned char *header_data = (const unsigned char *) header.c_str ();
unsigned char flags = header_data[3];
if (header_data[0] != 0x1f || header_data[1] != 0x8b || header_data[2] != 0x08 || (flags & 0xe0) != 0) {
return false;
}
// .gz signature found
bool has_fhcrc = (flags & 0x02) != 0;
bool has_extra = (flags & 0x04) != 0;
bool has_fname = (flags & 0x08) != 0;
bool has_comment = (flags & 0x10) != 0;
if (has_extra) {
const unsigned char *xlen = (const unsigned char *) m_inflating_stream.get (2);
if (! xlen) {
throw tl::Exception (tl::to_string (tr ("Corrupt .gz header - missing XLEN field")));
}
const char *xdata = m_inflating_stream.get (size_t (xlen[0]) + (size_t (xlen[1]) << 8));
if (! xdata) {
throw tl::Exception (tl::to_string (tr ("Corrupt .gz header - missing EXTRA data")));
}
}
if (has_fname) {
const char *c;
while ((c = m_inflating_stream.get (1)) != 0 && *c)
;
if (! c) {
throw tl::Exception (tl::to_string (tr ("Corrupt .gz header - missing FNAME data trailing zero byte")));
}
}
if (has_comment) {
const char *c;
while ((c = m_inflating_stream.get (1)) != 0 && *c)
;
if (! c) {
throw tl::Exception (tl::to_string (tr ("Corrupt .gz header - missing COMMENT data trailing zero byte")));
}
}
if (has_fhcrc) {
const char *crc16 = m_inflating_stream.get (2);
if (! crc16) {
throw tl::Exception (tl::to_string (tr ("Corrupt .gz header - missing CRC16 data")));
}
}
return true;
}
// ---------------------------------------------------------------
// InputStream implementation
@@ -175,7 +294,7 @@ public:
}
InputStream::InputStream (InputStreamBase &delegate)
: m_pos (0), mp_bptr (0), mp_delegate (&delegate), m_owns_delegate (false), mp_inflate (0), m_inflate_always (false)
: m_pos (0), mp_bptr (0), mp_delegate (&delegate), m_owns_delegate (false), mp_inflate (0), m_inflate_always (false), m_stop_after_inflate (false)
{
m_bcap = 4096; // initial buffer capacity
m_blen = 0;
@@ -183,7 +302,7 @@ InputStream::InputStream (InputStreamBase &delegate)
}
InputStream::InputStream (InputStreamBase *delegate)
: m_pos (0), mp_bptr (0), mp_delegate (delegate), m_owns_delegate (true), mp_inflate (0), m_inflate_always (false)
: m_pos (0), mp_bptr (0), mp_delegate (delegate), m_owns_delegate (true), mp_inflate (0), m_inflate_always (false), m_stop_after_inflate (false)
{
m_bcap = 4096; // initial buffer capacity
m_blen = 0;
@@ -191,7 +310,7 @@ InputStream::InputStream (InputStreamBase *delegate)
}
InputStream::InputStream (const std::string &abstract_path)
: m_pos (0), mp_bptr (0), mp_delegate (0), m_owns_delegate (false), mp_inflate (0), m_inflate_always (false)
: m_pos (0), mp_bptr (0), mp_delegate (0), m_owns_delegate (false), mp_inflate (0), m_inflate_always (false), m_stop_after_inflate (false)
{
m_bcap = 4096; // initial buffer capacity
m_blen = 0;
@@ -252,7 +371,7 @@ InputStream::InputStream (const std::string &abstract_path)
} else if (ex.test ("pipe:")) {
mp_delegate = new InputPipe (ex.get ());
mp_delegate = new InflatingInputPipe (ex.get ());
} else {
@@ -260,7 +379,7 @@ InputStream::InputStream (const std::string &abstract_path)
if (uri.scheme () == "http" || uri.scheme () == "https") {
#if defined(HAVE_CURL) || defined(HAVE_QT)
mp_delegate = new InputHttpStream (abstract_path);
mp_delegate = new InflatingInputHttpStream (abstract_path);
#else
throw tl::Exception (tl::to_string (tr ("HTTP support not enabled - HTTP/HTTPS paths are not available")));
#endif
@@ -337,9 +456,16 @@ InputStream::get (size_t n, bool bypass_inflate)
tl_assert (r != 0); // since deflate did not report at_end()
return r;
} else if (m_stop_after_inflate) {
// report EOF after the inflator has finished
return 0;
} else {
delete mp_inflate;
mp_inflate = 0;
}
}
@@ -384,9 +510,16 @@ InputStream::get (size_t n, bool bypass_inflate)
void
InputStream::unget (size_t n)
{
if (n == 0) {
return;
}
if (mp_inflate) {
// TODO: this will not work if mp_inflate just got destroyed
// (no unget into previous compressed block)
mp_inflate->unget (n);
} else {
tl_assert (mp_buffer + n <= mp_bptr);
mp_bptr -= n;
m_blen += n;
m_pos -= n;
@@ -476,10 +609,11 @@ void InputStream::copy_to (tl::OutputStream &os)
}
void
InputStream::inflate ()
InputStream::inflate (bool stop_after)
{
tl_assert (mp_inflate == 0);
mp_inflate = new tl::InflateFilter (*this);
m_stop_after_inflate = stop_after;
}
void
@@ -1334,11 +1468,11 @@ OutputPipe::write (const char *b, size_t n)
// ---------------------------------------------------------------
// InputPipe delegate implementation
InputPipe::InputPipe (const std::string &path)
InputPipe::InputPipe (const std::string &source)
: m_file (NULL)
{
m_source = path;
m_file = popen (tl::string_to_system (path).c_str (), "r");
m_source = source;
m_file = popen (tl::string_to_system (source).c_str (), "r");
if (m_file == NULL) {
throw FilePOpenErrorException (m_source, errno);
}
+82 -6
View File
@@ -310,10 +310,9 @@ public:
* an error occurs - commonly if the command cannot be executed.
* This implementation is based on popen ().
*
* @param cmd The command to execute
* @param read True, if the file should be read, false on write.
* @param source The command to execute
*/
InputPipe (const std::string &path);
InputPipe (const std::string &source);
/**
* @brief Close the pipe
@@ -348,8 +347,7 @@ public:
*/
virtual std::string source () const
{
// No source (in the sense of a file name) is available ..
return std::string ();
return m_source;
}
virtual std::string absolute_path () const
@@ -474,8 +472,11 @@ public:
* the uncompressed data rather than the raw data, until the
* compressed block is finished.
* The stream must not be in inflate state yet.
*
* If "stop_after" is true, the stream will stop after the inflated
* block has finished.
*/
void inflate ();
void inflate (bool stop_after = false);
/**
* @brief Enables "inflate" right from the beginning
@@ -578,12 +579,87 @@ private:
// inflate support
InflateFilter *mp_inflate;
bool m_inflate_always;
bool m_stop_after_inflate;
// No copying currently
InputStream (const InputStream &);
InputStream &operator= (const InputStream &);
};
/**
* @brief A wrapper that adds generic .gz support
*/
template <class Base>
class TL_PUBLIC_TEMPLATE inflating_input_stream
: public InputStreamBase
{
public:
inflating_input_stream (Base *delegate);
Base *delegate ()
{
return mp_delegate;
}
virtual size_t read (char *b, size_t n);
virtual void reset ()
{
m_inflating_stream.reset ();
enter_inflate ();
}
virtual void close ()
{
m_inflating_stream.close ();
}
virtual std::string source () const
{
return m_inflating_stream.source ();
}
virtual std::string absolute_path () const
{
return m_inflating_stream.absolute_path ();
}
virtual std::string filename () const
{
return m_inflating_stream.filename ();
}
private:
tl::InputStream m_inflating_stream;
bool m_is_compressed;
Base *mp_delegate;
void enter_inflate ();
bool auto_detect_gz ();
};
/**
* @brief A pipe stream with .gz support
*/
class TL_PUBLIC InflatingInputPipe
: public inflating_input_stream<InputPipe>
{
public:
/**
* @brief Open a stream by connecting with the stdout of a given command
*
* Opening a pipe is a prerequisite for reading from the
* object. open() will throw a FilePOpenErrorException if
* an error occurs - commonly if the command cannot be executed.
* This implementation is based on popen ().
*
* @param source The command to execute
*/
InflatingInputPipe (const std::string &source)
: inflating_input_stream<InputPipe> (new InputPipe (source))
{ }
};
// ---------------------------------------------------------------------------------
/**
+28
View File
@@ -24,8 +24,10 @@
#include "tlHttpStream.h"
#include "tlUnitTest.h"
#include "tlTimer.h"
#include "tlStream.h"
static std::string test_url1 ("http://www.klayout.org/svn-public/klayout-resources/trunk/testdata/text");
static std::string test_url1_gz ("http://www.klayout.org/svn-public/klayout-resources/trunk/testdata2/text.gz");
static std::string test_url2 ("http://www.klayout.org/svn-public/klayout-resources/trunk/testdata/dir1");
TEST(1)
@@ -125,3 +127,29 @@ TEST(3)
EXPECT_EQ (res, "hello, world.\n");
}
// tl::Stream embedding
TEST(4)
{
if (! tl::InputHttpStream::is_available ()) {
throw tl::CancelException ();
}
tl::InputStream stream (test_url1);
std::string res = stream.read_all ();
EXPECT_EQ (res, "hello, world.\n");
}
// tl::Stream embedding with automatic unzip
TEST(5)
{
if (! tl::InputHttpStream::is_available ()) {
throw tl::CancelException ();
}
tl::InputStream stream (test_url1_gz);
std::string res = stream.read_all ();
EXPECT_EQ (res, "hello, world.\n");
}
+9
View File
@@ -52,6 +52,13 @@ TEST(InputPipe2)
EXPECT_NE (ret, 0);
}
TEST(InputPipe3)
{
tl::InputStream str ("pipe:echo HELLOWORLD");
tl::TextInputStream tstr (str);
EXPECT_EQ (tstr.get_line (), "HELLOWORLD");
}
TEST(OutputPipe1)
{
std::string tf = tmp_file ("pipe_out");
@@ -455,3 +462,5 @@ TEST(Backups)
}
}