mirror of https://github.com/KLayout/klayout.git
commit
206e271ee3
|
|
@ -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 = [
|
||||
|
|
|
|||
|
|
@ -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 ®ion, 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 ®ion, 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 ());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 ®ion) 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 ®ion, EdgeInteractionMode mode, bool inverse) const;
|
||||
virtual std::pair<EdgesDelegate *, EdgesDelegate *> selected_interacting_pair_generic (const Region ®ion, 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 ®ion, EdgeInteractionMode mode, bool inverse, size_t min_count, size_t max_count) const;
|
||||
virtual std::pair<EdgesDelegate *, EdgesDelegate *> selected_interacting_pair_generic (const Region ®ion, EdgeInteractionMode mode, size_t min_count, size_t max_count) const;
|
||||
AsIfFlatEdges &operator= (const AsIfFlatEdges &other);
|
||||
AsIfFlatEdges (const AsIfFlatEdges &other);
|
||||
|
||||
|
|
|
|||
|
|
@ -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 ();
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 ®ion) 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 ®ion, EdgeInteractionMode mode, bool inverse) const;
|
||||
virtual std::pair<EdgesDelegate *, EdgesDelegate *> selected_interacting_pair_generic (const Region ®ion, 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 ®ion, EdgeInteractionMode mode, bool inverse, size_t min_count, size_t max_count) const;
|
||||
virtual std::pair<EdgesDelegate *, EdgesDelegate *> selected_interacting_pair_generic (const Region ®ion, 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;
|
||||
|
|
|
|||
|
|
@ -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 ())));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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 (); }
|
||||
|
|
|
|||
|
|
@ -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 ();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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>;
|
||||
|
|
|
|||
|
|
@ -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>;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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."
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -83,5 +83,25 @@ TEST(1)
|
|||
EXPECT_EQ (db::edge_is_outside (db::Edge (db::Point (0, 11), db::Point (10, 11)), db::Polygon (db::Box (0, 0, 10, 10))), true);
|
||||
EXPECT_EQ (db::edge_is_outside (db::Edge (db::Point (0, 5), db::Point (10, 5)), db::Polygon (db::Box (0, 0, 10, 10))), false);
|
||||
EXPECT_EQ (db::edge_is_outside (db::Edge (db::Point (-5, 5), db::Point (15, 5)), db::Polygon (db::Box (0, 0, 10, 10))), false);
|
||||
EXPECT_EQ (db::edge_is_outside (db::Edge (db::Point (-10, 5), db::Point (0, 5)), db::Polygon (db::Box (0, 0, 10, 10))), true);
|
||||
EXPECT_EQ (db::edge_is_outside (db::Edge (db::Point (-10, 0), db::Point (10, 0)), db::Polygon (db::Box (0, 0, 10, 10))), true);
|
||||
|
||||
db::Point pts[] = {
|
||||
db::Point (0, 0),
|
||||
db::Point (0, 10),
|
||||
db::Point (20, 10),
|
||||
db::Point (20, -10),
|
||||
db::Point (10, -10),
|
||||
db::Point (10, 0)
|
||||
};
|
||||
|
||||
db::Polygon poly;
|
||||
poly.assign_hull (pts + 0, pts + sizeof(pts) / sizeof(pts[0]));
|
||||
|
||||
EXPECT_EQ (db::edge_is_outside (db::Edge (db::Point (-10, 10), db::Point (20, 10)), poly), true);
|
||||
EXPECT_EQ (db::edge_is_outside (db::Edge (db::Point (-10, -10), db::Point (20, -10)), poly), true);
|
||||
EXPECT_EQ (db::edge_is_outside (db::Edge (db::Point (-10, 0), db::Point (11, 0)), poly), false);
|
||||
EXPECT_EQ (db::edge_is_outside (db::Edge (db::Point (-10, 0), db::Point (10, 0)), poly), true);
|
||||
EXPECT_EQ (db::edge_is_outside (db::Edge (db::Point (-10, 0), db::Point (9, 0)), poly), true);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,80 @@
|
|||
|
||||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2024 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#include "tlUnitTest.h"
|
||||
#include "tlString.h"
|
||||
|
||||
#include "dbRegionProcessors.h"
|
||||
|
||||
|
||||
TEST(1_RegionToEdgesProcessor)
|
||||
{
|
||||
db::Point hull[] = {
|
||||
db::Point (0, 0),
|
||||
db::Point (0, 1000),
|
||||
db::Point (1000, 1000),
|
||||
db::Point (1000, 2000),
|
||||
db::Point (2000, 2000),
|
||||
db::Point (2000, 1000),
|
||||
db::Point (3000, 1000),
|
||||
db::Point (3000, 0)
|
||||
};
|
||||
|
||||
db::Point hole[] = {
|
||||
db::Point (100, 100),
|
||||
db::Point (2900, 100),
|
||||
db::Point (2900, 900),
|
||||
db::Point (100, 900)
|
||||
};
|
||||
|
||||
db::Polygon poly;
|
||||
poly.assign_hull (hull + 0, hull + sizeof (hull) / sizeof (hull[0]));
|
||||
poly.insert_hole (hole + 0, hole + sizeof (hole) / sizeof (hole[0]));
|
||||
|
||||
std::vector<db::Edge> result;
|
||||
|
||||
result.clear ();
|
||||
db::PolygonToEdgeProcessor ().process (poly, result);
|
||||
EXPECT_EQ (tl::join (result.begin (), result.end (), ";"), "(0,0;0,1000);(0,1000;1000,1000);(1000,1000;1000,2000);(1000,2000;2000,2000);(2000,2000;2000,1000);(2000,1000;3000,1000);(3000,1000;3000,0);(3000,0;0,0);(100,100;2900,100);(2900,100;2900,900);(2900,900;100,900);(100,900;100,100)");
|
||||
|
||||
result.clear ();
|
||||
db::PolygonToEdgeProcessor (db::PolygonToEdgeProcessor::Concave).process (poly, result);
|
||||
EXPECT_EQ (tl::join (result.begin (), result.end (), ";"), "(2900,100;2900,900);(2900,900;100,900);(100,900;100,100);(100,100;2900,100)");
|
||||
|
||||
result.clear ();
|
||||
db::PolygonToEdgeProcessor (db::PolygonToEdgeProcessor::Convex).process (poly, result);
|
||||
EXPECT_EQ (tl::join (result.begin (), result.end (), ";"), "(1000,2000;2000,2000);(3000,1000;3000,0);(3000,0;0,0);(0,0;0,1000)");
|
||||
|
||||
result.clear ();
|
||||
db::PolygonToEdgeProcessor (db::PolygonToEdgeProcessor::Step).process (poly, result);
|
||||
EXPECT_EQ (tl::join (result.begin (), result.end (), ";"), "(0,1000;1000,1000);(1000,1000;1000,2000);(2000,2000;2000,1000);(2000,1000;3000,1000)");
|
||||
|
||||
result.clear ();
|
||||
db::PolygonToEdgeProcessor (db::PolygonToEdgeProcessor::StepOut).process (poly, result);
|
||||
EXPECT_EQ (tl::join (result.begin (), result.end (), ";"), "(1000,1000;1000,2000);(2000,1000;3000,1000)");
|
||||
|
||||
result.clear ();
|
||||
db::PolygonToEdgeProcessor (db::PolygonToEdgeProcessor::StepIn).process (poly, result);
|
||||
EXPECT_EQ (tl::join (result.begin (), result.end (), ";"), "(0,1000;1000,1000);(2000,2000;2000,1000)");
|
||||
}
|
||||
|
|
@ -87,6 +87,7 @@ SOURCES = \
|
|||
dbDeepTextsTests.cc \
|
||||
dbNetShapeTests.cc \
|
||||
dbHierNetsProcessorTests.cc \
|
||||
dbRegionProcessorTests.cc \
|
||||
dbAsIfFlatRegionTests.cc
|
||||
|
||||
INCLUDEPATH += $$TL_INC $$DB_INC $$GSI_INC
|
||||
|
|
|
|||
|
|
@ -455,6 +455,7 @@ out = in.drc(covering(other) > 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"/>
|
||||
|
|
|
|||
|
|
@ -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 |
|
|
@ -59,6 +59,12 @@
|
|||
<file alias="drc_extended2.png">doc/images/drc_extended2.png</file>
|
||||
<file alias="drc_extended3.png">doc/images/drc_extended3.png</file>
|
||||
<file alias="drc_extended4.png">doc/images/drc_extended4.png</file>
|
||||
<file alias="drc_edge_modes1.png">doc/images/drc_edge_modes1.png</file>
|
||||
<file alias="drc_edge_modes2.png">doc/images/drc_edge_modes2.png</file>
|
||||
<file alias="drc_edge_modes3.png">doc/images/drc_edge_modes3.png</file>
|
||||
<file alias="drc_edge_modes4.png">doc/images/drc_edge_modes4.png</file>
|
||||
<file alias="drc_edge_modes5.png">doc/images/drc_edge_modes5.png</file>
|
||||
<file alias="drc_edge_modes6.png">doc/images/drc_edge_modes6.png</file>
|
||||
<file alias="drc_extents1.png">doc/images/drc_extents1.png</file>
|
||||
<file alias="drc_extents2.png">doc/images/drc_extents2.png</file>
|
||||
<file alias="drc_inside.png">doc/images/drc_inside.png</file>
|
||||
|
|
|
|||
|
|
@ -991,6 +991,7 @@ CODE
|
|||
# @name edges
|
||||
# @brief Converts the input shapes into edges
|
||||
# @synopsis expression.edges
|
||||
# @synopsis expression.edges(mode)
|
||||
#
|
||||
# Polygons will be separated into edges forming their contours. Edge pairs will be
|
||||
# decomposed into individual edges.
|
||||
|
|
@ -1003,9 +1004,38 @@ CODE
|
|||
# @code
|
||||
# out = in.drc(primary.edges)
|
||||
# @/code
|
||||
#
|
||||
# The "mode" argument allows selecting specific edges from polygons.
|
||||
# Allowed values are: "convex", "concave", "step", "step_in" and "step_out".
|
||||
# "step" generates edges only if they provide a step between two other
|
||||
# edges. "step_in" creates edges that make a step towards the inside of
|
||||
# the polygon and "step_out" creates edges that make a step towards the
|
||||
# outside:
|
||||
#
|
||||
# @code
|
||||
# out = in.drc(primary.edges(convex))
|
||||
# @/code
|
||||
#
|
||||
# In addition, "not_.." variants are available which selects edges
|
||||
# not qualifying for the specific mode:
|
||||
#
|
||||
# @code
|
||||
# out = in.drc(primary.edges(not_convex))
|
||||
# @/code
|
||||
#
|
||||
# The mode argument is ignored when translating other objects than
|
||||
# polygons.
|
||||
|
||||
def edges
|
||||
return DRCOpNodeFilter::new(@engine, self, :new_edges, "edges")
|
||||
def edges(mode = nil)
|
||||
if mode
|
||||
if ! mode.is_a?(DRC::DRCEdgeMode)
|
||||
raise "The mode argument needs to be a mode type (convex, concave, step, step_in or step_out)"
|
||||
end
|
||||
mode = mode.value
|
||||
else
|
||||
mode = RBA::EdgeMode::All
|
||||
end
|
||||
return DRCOpNodeFilter::new(@engine, self, :new_edges, "edges", mode)
|
||||
end
|
||||
|
||||
# %DRC%
|
||||
|
|
|
|||
|
|
@ -255,6 +255,46 @@ module DRC
|
|||
DRCJoinFlag::new(true)
|
||||
end
|
||||
|
||||
def convex
|
||||
DRCEdgeMode::new(RBA::EdgeMode::Convex)
|
||||
end
|
||||
|
||||
def not_convex
|
||||
DRCEdgeMode::new(RBA::EdgeMode::NotConvex)
|
||||
end
|
||||
|
||||
def concave
|
||||
DRCEdgeMode::new(RBA::EdgeMode::Concave)
|
||||
end
|
||||
|
||||
def not_concave
|
||||
DRCEdgeMode::new(RBA::EdgeMode::NotConcave)
|
||||
end
|
||||
|
||||
def step_in
|
||||
DRCEdgeMode::new(RBA::EdgeMode::StepIn)
|
||||
end
|
||||
|
||||
def not_step_in
|
||||
DRCEdgeMode::new(RBA::EdgeMode::NotStepIn)
|
||||
end
|
||||
|
||||
def step_out
|
||||
DRCEdgeMode::new(RBA::EdgeMode::StepOut)
|
||||
end
|
||||
|
||||
def not_step_out
|
||||
DRCEdgeMode::new(RBA::EdgeMode::NotStepOut)
|
||||
end
|
||||
|
||||
def step
|
||||
DRCEdgeMode::new(RBA::EdgeMode::Step)
|
||||
end
|
||||
|
||||
def not_step
|
||||
DRCEdgeMode::new(RBA::EdgeMode::NotStep)
|
||||
end
|
||||
|
||||
def padding_zero
|
||||
DRCDensityPadding::new(:zero)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -1672,3 +1672,33 @@ TEST(92_issue1594_dual_top)
|
|||
CHECKPOINT ();
|
||||
compare_netlists (_this, output, au);
|
||||
}
|
||||
|
||||
TEST(100_edge_interaction_with_count)
|
||||
{
|
||||
run_test (_this, "100", false);
|
||||
}
|
||||
|
||||
TEST(100d_edge_interaction_with_count)
|
||||
{
|
||||
run_test (_this, "100", true);
|
||||
}
|
||||
|
||||
TEST(101_edge_booleans_with_dots)
|
||||
{
|
||||
run_test (_this, "101", false);
|
||||
}
|
||||
|
||||
TEST(101d_edge_booleans_with_dots)
|
||||
{
|
||||
run_test (_this, "101", true);
|
||||
}
|
||||
|
||||
TEST(102_edge_modes)
|
||||
{
|
||||
run_test (_this, "102", false);
|
||||
}
|
||||
|
||||
TEST(102d_edge_modes)
|
||||
{
|
||||
run_test (_this, "102", true);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1080,6 +1080,12 @@ OASISReader::do_read (db::Layout &layout)
|
|||
LNameJoinOp2 op2;
|
||||
layer_names ().add (l1, l2 + 1, dt_map, op2);
|
||||
|
||||
// for singular layers, force a layer entry:
|
||||
// this way we can have empty, but existing layers.
|
||||
if (l1 == l2 && dt1 == dt2) {
|
||||
open_dl (layout, db::LDPair (l1, dt1));
|
||||
}
|
||||
|
||||
reset_modal_variables ();
|
||||
|
||||
// ignore properties attached to this name item
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
|
||||
|
||||
#include "dbOASISReader.h"
|
||||
#include "dbOASISWriter.h"
|
||||
#include "dbTextWriter.h"
|
||||
#include "dbTestSupport.h"
|
||||
#include "tlLog.h"
|
||||
|
|
@ -487,21 +488,18 @@ TEST(99)
|
|||
// XGEOMTRY tests (#773)
|
||||
TEST(100)
|
||||
{
|
||||
const char *expected =
|
||||
const char *expected =
|
||||
"begin_lib 0.0001\n"
|
||||
"begin_cell {mask}\n"
|
||||
"boundary 7 1 {13237 5356} {13210 5490} {13192 5530} {13170 5563} {13130 5586} {13090 5583} {13070 5570} {13050 5551} {13037 5530} {13021 5490} {12988 5378} {12938 5390} {12963 5530} {12977 5570} {12998 5610} {13034 5650} {13051 5663} {13090 5678} {13130 5679} {13171 5667} {13210 5638} {13232 5611} {13253 5570} {13274 5490} {13291 5365} {13237 5356}\n"
|
||||
"boundary 4 0 {10772 1658} {10772 1744} {14510 1744} {14510 1658} {10772 1658}\n"
|
||||
"boundary 4 0 {14510 1658} {14510 1744} {15672 1744} {15672 1658} {14510 1658}\n"
|
||||
"boundary 4 0 {18157 647} {18157 676} {21642 676} {21642 647} {18157 647}\n"
|
||||
"boundary 6 0 {6743 2449} {6743 4230} {9061 4230} {9061 2449} {6743 2449}\n"
|
||||
"boundary 2 3 {21642 3613} {21642 4005} {19409 4005} {19409 6980} {21812 6980} {21812 4958} {21942 4958} {21942 4005} {21812 4005} {21812 3613} {21642 3613}\n"
|
||||
"boundary 2 4 {21642 4005} {21642 4958} {21812 4958} {21812 4005} {21642 4005}\n"
|
||||
"boundary 8 0 {21680 4106} {21640 4107} {21600 4118} {21574 4130} {21560 4138} {21520 4163} {21509 4170} {21480 4194} {21458 4210} {21440 4227} {21411 4250} {21400 4262} {21366 4290} {21360 4298} {21324 4330} {21320 4335} {21282 4370} {21280 4373} {21241 4410} {21240 4411} {21200 4450} {21160 4490} {21159 4490} {21039 4610} {21000 4650} {20960 4690} {20960 4691} {20921 4730} {20920 4732} {20896 4770} {20886 4810} {20882 4850} {20880 4930} {20880 5330} {20920 5370} {20960 5370} {21000 5340} {21013 5330} {21040 5325} {21080 5309} {21120 5291} {21121 5290} {21160 5276} {21200 5258} {21210 5250} {21240 5240} {21280 5222} {21295 5210} {21320 5202} {21360 5181} {21374 5170} {21400 5160} {21440 5136} {21447 5130} {21480 5112} {21510 5090} {21520 5086} {21560 5058} {21568 5050} {21600 5027} {21617 5010} {21640 4993} {21662 4970} {21680 4955} {21701 4930} {21720 4910} {21735 4890} {21760 4856} {21764 4850} {21786 4810} {21800 4781} {21805 4770} {21818 4730} {21828 4690} {21836 4650} {21840 4616} {21841 4610} {21845 4530} {21845 4450} {21844 4410} {21841 4370} {21840 4358} {21836 4330} {21829 4290} {21818 4250} {21803 4210} {21800 4205} {21778 4170} {21760 4148} {21738 4130} {21720 4118} {21680 4106}\n"
|
||||
"boundary 1 0 {17922 6288} {17922 6510} {18150 6510} {18150 6288} {17922 6288}\n"
|
||||
"boundary 1 0 {18157 647} {18157 676} {21630 676} {21630 647} {18157 647}\n"
|
||||
"boundary 1 0 {21956 0} {21956 89} {22047 89} {22047 0} {21956 0}\n"
|
||||
"boundary 2 3 {21642 3613} {21642 4005} {19409 4005} {19409 6980} {21812 6980} {21812 4958} {21942 4958} {21942 4005} {21812 4005} {21812 3613} {21642 3613}\n"
|
||||
"boundary 2 4 {21642 4005} {21642 4958} {21812 4958} {21812 4005} {21642 4005}\n"
|
||||
"boundary 3 0 {15392 1744} {15392 1774} {15672 1774} {15672 1744} {15392 1744}\n"
|
||||
"boundary 4 0 {10772 1658} {10772 1744} {14510 1744} {14510 1658} {10772 1658}\n"
|
||||
"boundary 4 0 {14510 1658} {14510 1744} {15672 1744} {15672 1658} {14510 1658}\n"
|
||||
"boundary 4 0 {18157 647} {18157 676} {21642 676} {21642 647} {18157 647}\n"
|
||||
"boundary 5 1 {15550 1658} {15550 1673} {15570 1673} {15570 1658} {15550 1658}\n"
|
||||
"boundary 5 1 {15661 1657} {15641 1659} {15642 1671} {15662 1669} {15661 1657}\n"
|
||||
"boundary 5 1 {18150 7440} {18150 7460} {18162 7460} {18162 7440} {18150 7440}\n"
|
||||
|
|
@ -519,6 +517,9 @@ TEST(100)
|
|||
"boundary 5 1 {25710 1978} {25710 1998} {25722 1998} {25722 1978} {25710 1978}\n"
|
||||
"boundary 5 1 {25710 2800} {25710 2820} {25722 2820} {25722 2800} {25710 2800}\n"
|
||||
"boundary 5 2 {18074 6408} {17971 6486} {17983 6502} {18086 6424} {18074 6408}\n"
|
||||
"boundary 6 0 {6743 2449} {6743 4230} {9061 4230} {9061 2449} {6743 2449}\n"
|
||||
"boundary 7 1 {13237 5356} {13210 5490} {13192 5530} {13170 5563} {13130 5586} {13090 5583} {13070 5570} {13050 5551} {13037 5530} {13021 5490} {12988 5378} {12938 5390} {12963 5530} {12977 5570} {12998 5610} {13034 5650} {13051 5663} {13090 5678} {13130 5679} {13171 5667} {13210 5638} {13232 5611} {13253 5570} {13274 5490} {13291 5365} {13237 5356}\n"
|
||||
"boundary 8 0 {21680 4106} {21640 4107} {21600 4118} {21574 4130} {21560 4138} {21520 4163} {21509 4170} {21480 4194} {21458 4210} {21440 4227} {21411 4250} {21400 4262} {21366 4290} {21360 4298} {21324 4330} {21320 4335} {21282 4370} {21280 4373} {21241 4410} {21240 4411} {21200 4450} {21160 4490} {21159 4490} {21039 4610} {21000 4650} {20960 4690} {20960 4691} {20921 4730} {20920 4732} {20896 4770} {20886 4810} {20882 4850} {20880 4930} {20880 5330} {20920 5370} {20960 5370} {21000 5340} {21013 5330} {21040 5325} {21080 5309} {21120 5291} {21121 5290} {21160 5276} {21200 5258} {21210 5250} {21240 5240} {21280 5222} {21295 5210} {21320 5202} {21360 5181} {21374 5170} {21400 5160} {21440 5136} {21447 5130} {21480 5112} {21510 5090} {21520 5086} {21560 5058} {21568 5050} {21600 5027} {21617 5010} {21640 4993} {21662 4970} {21680 4955} {21701 4930} {21720 4910} {21735 4890} {21760 4856} {21764 4850} {21786 4810} {21800 4781} {21805 4770} {21818 4730} {21828 4690} {21836 4650} {21840 4616} {21841 4610} {21845 4530} {21845 4450} {21844 4410} {21841 4370} {21840 4358} {21836 4330} {21829 4290} {21818 4250} {21803 4210} {21800 4205} {21778 4170} {21760 4148} {21738 4130} {21720 4118} {21680 4106}\n"
|
||||
"end_cell\n"
|
||||
"end_lib\n"
|
||||
;
|
||||
|
|
@ -543,6 +544,41 @@ TEST(100)
|
|||
EXPECT_EQ (std::string (os.string ()), std::string (expected))
|
||||
}
|
||||
|
||||
// Empty layers through LAYERMAP
|
||||
TEST(101)
|
||||
{
|
||||
db::Layout ly;
|
||||
ly.add_cell ("TOP");
|
||||
ly.insert_layer (db::LayerProperties (1, 0, "A"));
|
||||
ly.insert_layer (db::LayerProperties (2, 0, ""));
|
||||
ly.insert_layer (db::LayerProperties (3, 0, "C"));
|
||||
|
||||
std::string tmp_file = tl::TestBase::tmp_file ("tmp_OASISReader101.oas");
|
||||
|
||||
{
|
||||
tl::OutputStream stream (tmp_file);
|
||||
db::OASISWriter writer;
|
||||
db::SaveLayoutOptions options;
|
||||
writer.write (ly, stream, options);
|
||||
}
|
||||
|
||||
db::Layout ly_new;
|
||||
|
||||
{
|
||||
tl::InputStream stream (tmp_file);
|
||||
db::Reader reader (stream);
|
||||
reader.read (ly_new);
|
||||
}
|
||||
|
||||
// NOTE: only named layers are written into layer table
|
||||
EXPECT_EQ (ly_new.cell_by_name ("TOP").first, true);
|
||||
EXPECT_EQ (int (ly_new.layers ()), 2);
|
||||
if (int (ly_new.layers ()) == 2) {
|
||||
EXPECT_EQ (ly_new.get_properties (0).to_string (), "A (1/0)");
|
||||
EXPECT_EQ (ly_new.get_properties (1).to_string (), "C (3/0)");
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Bug_121_1)
|
||||
{
|
||||
db::Manager m (false);
|
||||
|
|
|
|||
|
|
@ -255,6 +255,13 @@ void run_test (tl::TestBase *_this, const char *file, bool scaling_test, int com
|
|||
db::Reader reader (stream);
|
||||
reader.read (layout);
|
||||
|
||||
// named layers create a mismatch between GDS and OASIS, so we unname them here
|
||||
for (auto l = layout.begin_layers (); l != layout.end_layers (); ++l) {
|
||||
db::LayerProperties lp = layout.get_properties ((*l).first);
|
||||
lp.name.clear ();
|
||||
layout.set_properties ((*l).first, lp);
|
||||
}
|
||||
|
||||
db::SaveLayoutOptions options;
|
||||
db::OASISWriterOptions oasis_options;
|
||||
oasis_options.compression_level = compr;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
{ }
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
Binary file not shown.
Binary file not shown.
|
|
@ -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)
|
||||
|
||||
Binary file not shown.
|
|
@ -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)
|
||||
|
||||
Binary file not shown.
|
|
@ -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)
|
||||
|
||||
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.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -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),
|
||||
|
|
|
|||
Loading…
Reference in New Issue