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
commit 206e271ee3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
85 changed files with 2910 additions and 828 deletions

View File

@ -606,6 +606,35 @@ run_demo gen, "input.edges.with_length(0, 3.5)\n .extended(:out => 1.0)", "drc
run_demo gen, "input.edges.with_length(0, 3.5)\n .extended(:out => 1.0, :joined => true)", "drc_extended3.png"
run_demo gen, "input.edges.with_length(2.0)\n .extended(0.0, -0.5, 1.0, -0.5)", "drc_extended4.png"
class Gen
def produce(s1, s2)
pts = [
RBA::Point::new(1000, 0),
RBA::Point::new(1000, 5000),
RBA::Point::new(2000, 5000),
RBA::Point::new(2000, 7000),
RBA::Point::new(4000, 7000),
RBA::Point::new(4000, 5000),
RBA::Point::new(5000, 5000),
RBA::Point::new(5000, 0),
RBA::Point::new(4000, 0),
RBA::Point::new(4000, 1000),
RBA::Point::new(2000, 1000),
RBA::Point::new(2000, 0)
];
s1.insert(RBA::Polygon::new(pts))
end
end
gen = Gen::new
run_demo gen, "input.edges", "drc_edge_modes1.png"
run_demo gen, "input.edges(convex)", "drc_edge_modes2.png"
run_demo gen, "input.edges(concave)", "drc_edge_modes3.png"
run_demo gen, "input.edges(step)", "drc_edge_modes4.png"
run_demo gen, "input.edges(step_in)", "drc_edge_modes5.png"
run_demo gen, "input.edges(step_out)", "drc_edge_modes6.png"
class Gen
def produce(s1, s2)
pts = [

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 ());
}

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);

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 ();

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

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;
};
}

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));
}

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;

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 ())));
}
}
}
}

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;

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;
};
/**

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));
}
/**

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;

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"));
}
}

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

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)

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;
};
/**

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 (); }

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 ();
}

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; }

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) {

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>;

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>;

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

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);
}
/**

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) {

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;

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);
}
}
}

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;
};
/**

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"

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"

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."

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:

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;

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)
{

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);
}

View File

@ -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)");
}

View File

@ -87,6 +87,7 @@ SOURCES = \
dbDeepTextsTests.cc \
dbNetShapeTests.cc \
dbHierNetsProcessorTests.cc \
dbRegionProcessorTests.cc \
dbAsIfFlatRegionTests.cc
INCLUDEPATH += $$TL_INC $$DB_INC $$GSI_INC

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"/>

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

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>

View 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%

View File

@ -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

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

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

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);
}

View File

@ -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

View File

@ -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);

View File

@ -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;

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

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);
}

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))
{ }
};
// ---------------------------------------------------------------------------------
/**

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");
}

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)
}
}

Binary file not shown.

BIN
testdata/algo/deep_edges_au3_flat.gds vendored Normal file

Binary file not shown.

BIN
testdata/algo/deep_edges_l1.gds vendored Normal file

Binary file not shown.

89
testdata/drc/drcSimpleTests_100.drc vendored Normal file
View File

@ -0,0 +1,89 @@
source $drc_test_source
target $drc_test_target
if $drc_test_deep
deep
end
l1 = input(1, 0)
l2 = input(2, 0)
l1.output(1, 0)
l2.output(2, 0)
e1 = l1.edges
e2 = l2.edges
e1.output(10, 0)
e2.output(11, 0)
e1.interacting(l2).output(100, 0)
e1.interacting(l2, 2).output(101, 0)
e1.interacting(l2, 2, 2).output(102, 0)
e1.interacting(l2, 3).output(103, 0)
e1.split_interacting(l2)[0].output(110, 0)
e1.split_interacting(l2, 2)[0].output(111, 0)
e1.split_interacting(l2, 2, 2)[0].output(112, 0)
e1.split_interacting(l2, 3)[0].output(113, 0)
e1.interacting(e2).output(200, 0)
e1.interacting(e2, 2).output(201, 0)
e1.interacting(e2, 2, 2).output(202, 0)
e1.interacting(e2, 3).output(203, 0)
e1.interacting(e2, 3..4).output(204, 0)
e1.split_interacting(e2)[0].output(210, 0)
e1.split_interacting(e2, 2)[0].output(211, 0)
e1.split_interacting(e2, 2, 2)[0].output(212, 0)
e1.split_interacting(e2, 3)[0].output(213, 0)
e1.split_interacting(e2, 3..4)[0].output(214, 0)
e1.not_interacting(l2).output(300, 0)
e1.not_interacting(l2, 2).output(301, 0)
e1.not_interacting(l2, 2, 2).output(302, 0)
e1.not_interacting(l2, 3).output(303, 0)
e1.split_interacting(l2)[1].output(310, 0)
e1.split_interacting(l2, 2)[1].output(311, 0)
e1.split_interacting(l2, 2, 2)[1].output(312, 0)
e1.split_interacting(l2, 3)[1].output(313, 0)
e1.not_interacting(e2).output(400, 0)
e1.not_interacting(e2, 2).output(401, 0)
e1.not_interacting(e2, 2, 2).output(402, 0)
e1.not_interacting(e2, 3).output(403, 0)
e1.not_interacting(e2, 3..4).output(404, 0)
e1.split_interacting(e2)[1].output(410, 0)
e1.split_interacting(e2, 2)[1].output(411, 0)
e1.split_interacting(e2, 2, 2)[1].output(412, 0)
e1.split_interacting(e2, 3)[1].output(413, 0)
e1.split_interacting(e2, 3..4)[1].output(414, 0)
# convex detection (the initial problem)
c90 = l2.corners(as_dots, 90)
cm90 = l2.corners(as_dots, -90)
c90.output(1000, 0)
cm90.output(1001, 0)
e2.interacting(c90, 2, 2).output(1100, 0)
e2.interacting(cm90, 2, 2).output(1101, 0)
e2.interacting(c90, 1, 1).output(1102, 0)
e2.interacting(cm90, 1, 1).output(1103, 0)
c90.interacting(e1).output(1200, 0)
c90.not_interacting(e1).output(1201, 0)
c90.interacting(e2).output(1202, 0)
c90.not_interacting(e2).output(1203, 0)
c90.interacting(l1).output(1300, 0)
c90.not_interacting(l1).output(1301, 0)
c90.interacting(l2).output(1302, 0)
c90.not_interacting(l2).output(1303, 0)
c90.split_interacting(l1)[0].output(1310, 0)
c90.split_interacting(l1)[1].output(1311, 0)

BIN
testdata/drc/drcSimpleTests_100.gds vendored Normal file

Binary file not shown.

52
testdata/drc/drcSimpleTests_101.drc vendored Normal file
View File

@ -0,0 +1,52 @@
source $drc_test_source
target $drc_test_target
if $drc_test_deep
deep
end
l1 = input(1, 0)
l2 = input(2, 0)
l1.output(1, 0)
l2.output(2, 0)
e1 = l1.edges
e2 = l2.edges
e1.output(10, 0)
e2.output(11, 0)
c1 = l1.corners(as_dots)
c2 = l2.corners(as_dots)
c1.output(20, 0)
c2.output(21, 0)
(c2 & l1).output(100, 0)
(c2 - l1).output(101, 0)
c2.andnot(l1)[0].output(110, 0)
c2.andnot(l1)[1].output(111, 0)
c2.inside_part(l1).output(200, 0)
c2.outside_part(l1).output(201, 0)
c2.inside_outside_part(l1)[0].output(210, 0)
c2.inside_outside_part(l1)[1].output(211, 0)
c2.interacting(l1).output(300, 0)
c2.not_interacting(l1).output(301, 0)
c2.split_interacting(l1)[0].output(310, 0)
c2.split_interacting(l1)[1].output(311, 0)
(c2 & e1).output(400, 0)
(c2 - e1).output(401, 0)
(c2 ^ e1).output(402, 0)
(c2 | e1).output(403, 0)
c2.andnot(e1)[0].output(410, 0)
c2.andnot(e1)[1].output(411, 0)

BIN
testdata/drc/drcSimpleTests_101.gds vendored Normal file

Binary file not shown.

40
testdata/drc/drcSimpleTests_102.drc vendored Normal file
View File

@ -0,0 +1,40 @@
source $drc_test_source
target $drc_test_target
if $drc_test_deep
deep
end
l1 = input(1, 0)
l2 = input(2, 0)
l1.output(1, 0)
l2.output(2, 0)
l2.edges.output(100, 0)
l2.edges(convex).output(101, 0)
l2.edges(concave).output(102, 0)
l2.edges(step).output(103, 0)
l2.edges(step_in).output(104, 0)
l2.edges(step_out).output(105, 0)
l2.edges(not_convex).output(111, 0)
l2.edges(not_concave).output(112, 0)
l2.edges(not_step).output(113, 0)
l2.edges(not_step_in).output(114, 0)
l2.edges(not_step_out).output(115, 0)
l2.drc(primary.edges).output(200, 0)
l2.drc(primary.edges(convex)).output(201, 0)
l2.drc(primary.edges(concave)).output(202, 0)
l2.drc(primary.edges(step)).output(203, 0)
l2.drc(primary.edges(step_in)).output(204, 0)
l2.drc(primary.edges(step_out)).output(205, 0)
l2.drc(primary.edges(not_convex)).output(211, 0)
l2.drc(primary.edges(not_concave)).output(212, 0)
l2.drc(primary.edges(not_step)).output(213, 0)
l2.drc(primary.edges(not_step_in)).output(214, 0)
l2.drc(primary.edges(not_step_out)).output(215, 0)

BIN
testdata/drc/drcSimpleTests_102.gds vendored Normal file

Binary file not shown.

BIN
testdata/drc/drcSimpleTests_au100.gds vendored Normal file

Binary file not shown.

BIN
testdata/drc/drcSimpleTests_au100d.gds vendored Normal file

Binary file not shown.

BIN
testdata/drc/drcSimpleTests_au101.gds vendored Normal file

Binary file not shown.

BIN
testdata/drc/drcSimpleTests_au101d.gds vendored Normal file

Binary file not shown.

BIN
testdata/drc/drcSimpleTests_au102.gds vendored Normal file

Binary file not shown.

BIN
testdata/drc/drcSimpleTests_au102d.gds vendored Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -821,6 +821,54 @@ class DBPolygon_TestClass < TestBase
end
def test_breakPolygon
pts = []
pts << RBA::Point::new(0, 0)
pts << RBA::Point::new(0, 1000)
pts << RBA::Point::new(100, 1000)
pts << RBA::Point::new(100, 100)
pts << RBA::Point::new(1000, 100)
pts << RBA::Point::new(1000, 0)
split = RBA::Polygon::new(pts).break(4, 0)
assert_equal(split.collect { |p| p.to_s }.join(";"), "(0,0;0,100;1000,100;1000,0);(0,100;0,1000;100,1000;100,100)")
split = RBA::Polygon::new(pts).break(0, 2.0)
assert_equal(split.collect { |p| p.to_s }.join(";"), "(0,0;0,100;1000,100;1000,0);(0,100;0,1000;100,1000;100,100)")
split = RBA::Polygon::new(pts).break(0, 0)
assert_equal(split.collect { |p| p.to_s }.join(";"), "(0,0;0,1000;100,1000;100,100;1000,100;1000,0)")
split = RBA::SimplePolygon::new(pts).break(4, 0)
assert_equal(split.collect { |p| p.to_s }.join(";"), "(0,0;0,100;1000,100;1000,0);(0,100;0,1000;100,1000;100,100)")
split = RBA::SimplePolygon::new(pts).break(0, 2.0)
assert_equal(split.collect { |p| p.to_s }.join(";"), "(0,0;0,100;1000,100;1000,0);(0,100;0,1000;100,1000;100,100)")
split = RBA::SimplePolygon::new(pts).break(0, 0)
assert_equal(split.collect { |p| p.to_s }.join(";"), "(0,0;0,1000;100,1000;100,100;1000,100;1000,0)")
pts = []
pts << RBA::DPoint::new(0, 0)
pts << RBA::DPoint::new(0, 1000)
pts << RBA::DPoint::new(100, 1000)
pts << RBA::DPoint::new(100, 100)
pts << RBA::DPoint::new(1000, 100)
pts << RBA::DPoint::new(1000, 0)
split = RBA::DPolygon::new(pts).break(4, 0)
assert_equal(split.collect { |p| p.to_s }.join(";"), "(0,0;0,100;1000,100;1000,0);(0,100;0,1000;100,1000;100,100)")
split = RBA::DPolygon::new(pts).break(0, 2.0)
assert_equal(split.collect { |p| p.to_s }.join(";"), "(0,0;0,100;1000,100;1000,0);(0,100;0,1000;100,1000;100,100)")
split = RBA::DPolygon::new(pts).break(0, 0)
assert_equal(split.collect { |p| p.to_s }.join(";"), "(0,0;0,1000;100,1000;100,100;1000,100;1000,0)")
split = RBA::DSimplePolygon::new(pts).break(4, 0)
assert_equal(split.collect { |p| p.to_s }.join(";"), "(0,0;0,100;1000,100;1000,0);(0,100;0,1000;100,1000;100,100)")
split = RBA::DSimplePolygon::new(pts).break(0, 2.0)
assert_equal(split.collect { |p| p.to_s }.join(";"), "(0,0;0,100;1000,100;1000,0);(0,100;0,1000;100,1000;100,100)")
split = RBA::DSimplePolygon::new(pts).break(0, 0)
assert_equal(split.collect { |p| p.to_s }.join(";"), "(0,0;0,1000;100,1000;100,100;1000,100;1000,0)")
end
def test_voidMethodsReturnSelf
hull = [ RBA::Point::new(0, 0), RBA::Point::new(6000, 0),