diff --git a/src/db/db/dbAsIfFlatEdgePairs.cc b/src/db/db/dbAsIfFlatEdgePairs.cc index cf9c3621b..d1fb9b0cd 100644 --- a/src/db/db/dbAsIfFlatEdgePairs.cc +++ b/src/db/db/dbAsIfFlatEdgePairs.cc @@ -147,6 +147,28 @@ void AsIfFlatEdgePairs::invalidate_bbox () m_bbox_valid = false; } +EdgePairsDelegate * +AsIfFlatEdgePairs::processed (const EdgePairProcessorBase &filter) const +{ + std::unique_ptr edge_pairs (new FlatEdgePairs ()); + + if (filter.result_must_not_be_merged ()) { + edge_pairs->set_merged_semantics (false); + } + + std::vector res_edge_pairs; + + for (EdgePairsIterator e = begin (); ! e.at_end (); ++e) { + res_edge_pairs.clear (); + filter.process (*e, res_edge_pairs); + for (std::vector::const_iterator er = res_edge_pairs.begin (); er != res_edge_pairs.end (); ++er) { + edge_pairs->insert (*er); + } + } + + return edge_pairs.release (); +} + RegionDelegate * AsIfFlatEdgePairs::processed_to_polygons (const EdgePairToPolygonProcessorBase &filter) const { diff --git a/src/db/db/dbAsIfFlatEdgePairs.h b/src/db/db/dbAsIfFlatEdgePairs.h index 29f18f6f1..2a69bb035 100644 --- a/src/db/db/dbAsIfFlatEdgePairs.h +++ b/src/db/db/dbAsIfFlatEdgePairs.h @@ -53,8 +53,14 @@ public: virtual EdgePairsDelegate *filtered (const EdgePairFilterBase &) const; - virtual RegionDelegate *processed_to_polygons (const EdgePairToPolygonProcessorBase &filter) const; - virtual EdgesDelegate *processed_to_edges (const EdgePairToEdgeProcessorBase &filter) const; + virtual EdgePairsDelegate *process_in_place (const EdgePairProcessorBase &proc) + { + return processed (proc); + } + + virtual EdgePairsDelegate *processed (const EdgePairProcessorBase &proc) const; + virtual RegionDelegate *processed_to_polygons (const EdgePairToPolygonProcessorBase &proc) const; + virtual EdgesDelegate *processed_to_edges (const EdgePairToEdgeProcessorBase &proc) const; virtual EdgePairsDelegate *add_in_place (const EdgePairs &other) { diff --git a/src/db/db/dbDeepEdgePairs.cc b/src/db/db/dbDeepEdgePairs.cc index d19a08fa2..090644265 100644 --- a/src/db/db/dbDeepEdgePairs.cc +++ b/src/db/db/dbDeepEdgePairs.cc @@ -451,6 +451,18 @@ DeepEdgePairs::apply_filter (const EdgePairFilterBase &filter) const return res.release (); } +EdgePairsDelegate *DeepEdgePairs::process_in_place (const EdgePairProcessorBase &filter) +{ + // TODO: implement to be really in-place + return processed (filter); +} + +EdgePairsDelegate * +DeepEdgePairs::processed (const EdgePairProcessorBase &filter) const +{ + return shape_collection_processed_impl (deep_layer (), filter); +} + RegionDelegate * DeepEdgePairs::processed_to_polygons (const EdgePairToPolygonProcessorBase &filter) const { diff --git a/src/db/db/dbDeepEdgePairs.h b/src/db/db/dbDeepEdgePairs.h index ccc73a762..8ec686da0 100644 --- a/src/db/db/dbDeepEdgePairs.h +++ b/src/db/db/dbDeepEdgePairs.h @@ -78,6 +78,8 @@ public: virtual EdgePairsDelegate *filter_in_place (const EdgePairFilterBase &filter); virtual EdgePairsDelegate *filtered (const EdgePairFilterBase &) const; + virtual EdgePairsDelegate *process_in_place (const EdgePairProcessorBase &); + virtual EdgePairsDelegate *processed (const EdgePairProcessorBase &) const; virtual RegionDelegate *processed_to_polygons (const EdgePairToPolygonProcessorBase &filter) const; virtual EdgesDelegate *processed_to_edges (const EdgePairToEdgeProcessorBase &filter) const; diff --git a/src/db/db/dbEdgePairs.cc b/src/db/db/dbEdgePairs.cc index 0451006ef..fcfd405f9 100644 --- a/src/db/db/dbEdgePairs.cc +++ b/src/db/db/dbEdgePairs.cc @@ -169,14 +169,19 @@ EdgePairs::properties_repository () return *r; } -void EdgePairs::processed (Region &output, const EdgePairToPolygonProcessorBase &filter) const +EdgePairs EdgePairs::processed (const EdgePairProcessorBase &proc) const { - output = Region (mp_delegate->processed_to_polygons (filter)); + return EdgePairs (mp_delegate->processed (proc)); } -void EdgePairs::processed (Edges &output, const EdgePairToEdgeProcessorBase &filter) const +void EdgePairs::processed (Region &output, const EdgePairToPolygonProcessorBase &proc) const { - output = Edges (mp_delegate->processed_to_edges (filter)); + output = Region (mp_delegate->processed_to_polygons (proc)); +} + +void EdgePairs::processed (Edges &output, const EdgePairToEdgeProcessorBase &proc) const +{ + output = Edges (mp_delegate->processed_to_edges (proc)); } void EdgePairs::polygons (Region &output, db::Coord e) const diff --git a/src/db/db/dbEdgePairs.h b/src/db/db/dbEdgePairs.h index 38e32d499..9d1b1aee2 100644 --- a/src/db/db/dbEdgePairs.h +++ b/src/db/db/dbEdgePairs.h @@ -328,13 +328,31 @@ public: return EdgePairs (mp_delegate->filtered (filter)); } + /** + * @brief Processes the edge pairs in-place + * + * This method will run the processor over all edge pairs and replace the collection by the results. + */ + EdgePairs &process (const EdgePairProcessorBase &proc) + { + set_delegate (mp_delegate->process_in_place (proc)); + return *this; + } + + /** + * @brief Processes the edge pairs + * + * This method will run the processor over all edge pairs return a new edge pair collection with the results. + */ + EdgePairs processed (const EdgePairProcessorBase &proc) const; + /** * @brief Processes the edge pairs into polygons * * This method will run the processor over all edge pairs and return a region * with the outputs of the processor. */ - void processed (Region &output, const EdgePairToPolygonProcessorBase &filter) const; + void processed (Region &output, const EdgePairToPolygonProcessorBase &proc) const; /** * @brief Processes the edge pairs into edges @@ -342,7 +360,7 @@ public: * This method will run the processor over all edge pairs and return a edge collection * with the outputs of the processor. */ - void processed (Edges &output, const EdgePairToEdgeProcessorBase &filter) const; + void processed (Edges &output, const EdgePairToEdgeProcessorBase &proc) const; /** * @brief Transforms the edge pair set diff --git a/src/db/db/dbEdgePairsDelegate.h b/src/db/db/dbEdgePairsDelegate.h index 32fa03670..189ff293e 100644 --- a/src/db/db/dbEdgePairsDelegate.h +++ b/src/db/db/dbEdgePairsDelegate.h @@ -39,6 +39,7 @@ class RegionDelegate; class EdgesDelegate; class Layout; +typedef shape_collection_processor EdgePairProcessorBase; typedef shape_collection_processor EdgePairToPolygonProcessorBase; typedef shape_collection_processor EdgePairToEdgeProcessorBase; @@ -194,8 +195,10 @@ public: virtual EdgePairsDelegate *filter_in_place (const EdgePairFilterBase &filter) = 0; virtual EdgePairsDelegate *filtered (const EdgePairFilterBase &filter) const = 0; - virtual RegionDelegate *processed_to_polygons (const EdgePairToPolygonProcessorBase &filter) const = 0; - virtual EdgesDelegate *processed_to_edges (const EdgePairToEdgeProcessorBase &filter) const = 0; + virtual EdgePairsDelegate *process_in_place (const EdgePairProcessorBase &proc) = 0; + virtual EdgePairsDelegate *processed (const EdgePairProcessorBase &proc) const = 0; + virtual RegionDelegate *processed_to_polygons (const EdgePairToPolygonProcessorBase &proc) const = 0; + virtual EdgesDelegate *processed_to_edges (const EdgePairToEdgeProcessorBase &proc) const = 0; virtual RegionDelegate *polygons (db::Coord e) const = 0; virtual EdgesDelegate *edges () const = 0; diff --git a/src/db/db/dbEmptyEdgePairs.h b/src/db/db/dbEmptyEdgePairs.h index 6680ec6a3..16be5fa99 100644 --- a/src/db/db/dbEmptyEdgePairs.h +++ b/src/db/db/dbEmptyEdgePairs.h @@ -56,6 +56,8 @@ public: virtual EdgePairsDelegate *filter_in_place (const EdgePairFilterBase &) { return this; } virtual EdgePairsDelegate *filtered (const EdgePairFilterBase &) const { return new EmptyEdgePairs (); } + virtual EdgePairsDelegate *process_in_place (const EdgePairProcessorBase &) { return this; } + virtual EdgePairsDelegate *processed (const EdgePairProcessorBase &) const { return new EmptyEdgePairs (); } virtual RegionDelegate *processed_to_polygons (const EdgePairToPolygonProcessorBase &filter) const; virtual EdgesDelegate *processed_to_edges (const EdgePairToEdgeProcessorBase &filter) const; diff --git a/src/db/db/gsiDeclDbEdgePairs.cc b/src/db/db/gsiDeclDbEdgePairs.cc index 3f5639720..6f4b1d60f 100644 --- a/src/db/db/gsiDeclDbEdgePairs.cc +++ b/src/db/db/gsiDeclDbEdgePairs.cc @@ -109,6 +109,100 @@ Class decl_EdgePairFilterImpl ("db", "EdgePairFilter", "This class has been introduced in version 0.29.\n" ); +// --------------------------------------------------------------------------------- +// EdgePairProcessor binding + +Class > decl_EdgePairProcessor ("db", "EdgePairOperator", + shape_processor_impl::method_decls (false), + "@brief A generic edge-pair operator\n" + "\n" + "Edge pair processors are an efficient way to process edge pairs from an edge pair collection. To apply a processor, derive your own " + "operator class and pass an instance to the \\EdgePairs#processed or \\EdgePairs#process method.\n" + "\n" + "Conceptually, these methods take each edge pair from the edge pair collection and present it to the operator's 'process' method.\n" + "The result of this call is a list of zero to many output edge_pairs derived from the input edge pair.\n" + "The output edge pair collection is the sum over all these individual results.\n" + "\n" + "The magic happens when deep mode edge pair collections are involved. In that case, the processor will use as few calls as possible " + "and exploit the hierarchical compression if possible. It needs to know however, how the operator behaves. You " + "need to configure the operator by calling \\is_isotropic, \\is_scale_invariant or \\is_isotropic_and_scale_invariant " + "before using it.\n" + "\n" + "You can skip this step, but the processor algorithm will assume the worst case then. This usually leads to cell variant " + "formation which is not always desired and blows up the hierarchy.\n" + "\n" + "Here is some example that flips the edge pairs (swaps first and second edge):" + "\n" + "@code\n" + "class FlipEdgePairs < RBA::EdgePairOperator\n" + "\n" + " # Constructor\n" + " def initialize\n" + " self.is_isotropic_and_scale_invariant # orientation and scale do not matter\n" + " end\n" + " \n" + " # Flips the edge pair\n" + " def process(edge_pair)\n" + " return [ RBA::EdgePair::new(edge_pair.second, edge_pair.first) ]\n" + " end\n" + "\n" + "end\n" + "\n" + "edge_pairs = ... # some EdgePairs object\n" + "flipped = edge_pairs.processed(FlipEdgePairs::new)\n" + "@/code\n" + "\n" + "This class has been introduced in version 0.29.\n" +); + +Class > decl_EdgePairToPolygonProcessor ("db", "EdgePairToPolygonOperator", + shape_processor_impl::method_decls (false), + "@brief A generic edge-pair-to-polygon operator\n" + "\n" + "Edge pair processors are an efficient way to process edge pairs from an edge pair collection. To apply a processor, derive your own " + "operator class and pass an instance to the \\EdgePairs#processed method.\n" + "\n" + "Conceptually, these methods take each edge pair from the edge pair collection and present it to the operator's 'process' method.\n" + "The result of this call is a list of zero to many output polygons derived from the input edge pair.\n" + "The output region is the sum over all these individual results.\n" + "\n" + "The magic happens when deep mode edge pair collections are involved. In that case, the processor will use as few calls as possible " + "and exploit the hierarchical compression if possible. It needs to know however, how the operator behaves. You " + "need to configure the operator by calling \\is_isotropic, \\is_scale_invariant or \\is_isotropic_and_scale_invariant " + "before using it.\n" + "\n" + "You can skip this step, but the processor algorithm will assume the worst case then. This usually leads to cell variant " + "formation which is not always desired and blows up the hierarchy.\n" + "\n" + "For a basic example see the \\EdgeToPolygonOperator class, with the exception that this incarnation receives edge pairs.\n" + "\n" + "This class has been introduced in version 0.29.\n" +); + +Class > decl_EdgePairToEdgeProcessor ("db", "EdgePairToEdgeOperator", + shape_processor_impl::method_decls (false), + "@brief A generic edge-pair-to-edge operator\n" + "\n" + "Edge processors are an efficient way to process edge pairs from an edge pair collection. To apply a processor, derive your own " + "operator class and pass an instance to \\EdgePairs#processed method.\n" + "\n" + "Conceptually, these methods take each edge from the edge collection and present it to the operator's 'process' method.\n" + "The result of this call is a list of zero to many output edges derived from the input edge pair.\n" + "The output edge pair collection is the sum over all these individual results.\n" + "\n" + "The magic happens when deep mode edge pair collections are involved. In that case, the processor will use as few calls as possible " + "and exploit the hierarchical compression if possible. It needs to know however, how the operator behaves. You " + "need to configure the operator by calling \\is_isotropic, \\is_scale_invariant or \\is_isotropic_and_scale_invariant " + "before using it.\n" + "\n" + "You can skip this step, but the processor algorithm will assume the worst case then. This usually leads to cell variant " + "formation which is not always desired and blows up the hierarchy.\n" + "\n" + "For a basic example see the \\EdgeToEdgePairOperator class, with the exception that this incarnation has to deliver edges and takes edge pairs.\n" + "\n" + "This class has been introduced in version 0.29.\n" +); + // --------------------------------------------------------------------------------- // EdgePairs binding @@ -267,6 +361,30 @@ static void filter (db::EdgePairs *r, const EdgePairFilterImpl *f) r->filter (*f); } +static db::EdgePairs processed_epep (const db::EdgePairs *r, const shape_processor_impl *f) +{ + return r->processed (*f); +} + +static void process_epep (db::EdgePairs *r, const shape_processor_impl *f) +{ + r->process (*f); +} + +static db::Edges processed_epe (const db::EdgePairs *r, const shape_processor_impl *f) +{ + db::Edges out; + r->processed (out, *f); + return out; +} + +static db::Region processed_epp (const db::EdgePairs *r, const shape_processor_impl *f) +{ + db::Region out; + r->processed (out, *f); + return out; +} + static db::EdgePairs with_distance1 (const db::EdgePairs *r, db::EdgePairs::distance_type length, bool inverse) { db::EdgePairFilterByDistance ef (length, length + 1, inverse); @@ -717,6 +835,30 @@ Class decl_EdgePairs (decl_dbShapeCollection, "db", "EdgePairs", "\n" "This method has been introduced in version 0.29.\n" ) + + method_ext ("process", &process_epep, gsi::arg ("process"), + "@brief Applies a generic edge pair processor in place (replacing the edge pairs from the EdgePairs collection)\n" + "See \\EdgePairProcessor for a description of this feature.\n" + "\n" + "This method has been introduced in version 0.29.\n" + ) + + method_ext ("processed", &processed_epep, gsi::arg ("processed"), + "@brief Applies a generic edge pair processor and returns a processed copy\n" + "See \\EdgePairProcessor for a description of this feature.\n" + "\n" + "This method has been introduced in version 0.29.\n" + ) + + method_ext ("processed", &processed_epe, gsi::arg ("processed"), + "@brief Applies a generic edge-pair-to-edge processor and returns an edge collection with the results\n" + "See \\EdgePairToEdgeProcessor for a description of this feature.\n" + "\n" + "This method has been introduced in version 0.29.\n" + ) + + method_ext ("processed", &processed_epp, gsi::arg ("processed"), + "@brief Applies a generic edge-pair-to-polygon processor and returns an Region with the results\n" + "See \\EdgePairToPolygonProcessor for a description of this feature.\n" + "\n" + "This method has been introduced in version 0.29.\n" + ) + method_ext ("with_length", with_length1, gsi::arg ("length"), gsi::arg ("inverse"), "@brief Filters the edge pairs by length of one of their edges\n" "Filters the edge pairs in the edge pair collection by length of at least one of their edges. If \"inverse\" is false, only " diff --git a/src/db/db/gsiDeclDbEdges.cc b/src/db/db/gsiDeclDbEdges.cc index 881644217..ca04d5675 100644 --- a/src/db/db/gsiDeclDbEdges.cc +++ b/src/db/db/gsiDeclDbEdges.cc @@ -84,7 +84,7 @@ Class decl_EdgeFilterImpl ("db", "EdgeFilter", "@brief A generic edge filter adaptor\n" "\n" "Edge filters are an efficient way to filter edge from a Edges collection. To apply a filter, derive your own " - "filter class and pass an instance to \\Edges#filter or \\Edges#filtered method.\n" + "filter class and pass an instance to the \\Edges#filter or \\Edges#filtered method.\n" "\n" "Conceptually, these methods take each edge from the collection and present it to the filter's 'selected' method.\n" "Based on the result of this evaluation, the edge is kept or discarded.\n" @@ -131,7 +131,7 @@ Class > decl_EdgeProcessorBase ("db" "@brief A generic edge-to-polygon operator\n" "\n" "Edge processors are an efficient way to process edges from an edge collection. To apply a processor, derive your own " - "operator class and pass an instance to \\Edges#processed method.\n" + "operator class and pass an instance to the \\Edges#processed method.\n" "\n" "Conceptually, these methods take each edge from the edge collection and present it to the operator's 'process' method.\n" "The result of this call is a list of zero to many output edges derived from the input edge.\n" @@ -176,7 +176,7 @@ Class > decl_EdgeToPolygonP "@brief A generic edge-to-polygon operator\n" "\n" "Edge processors are an efficient way to process edges from an edge collection. To apply a processor, derive your own " - "operator class and pass an instance to \\Edges#processed method.\n" + "operator class and pass an instance to the \\Edges#processed method.\n" "\n" "Conceptually, these methods take each edge from the edge collection and present it to the operator's 'process' method.\n" "The result of this call is a list of zero to many output polygons derived from the input edge.\n" @@ -200,7 +200,7 @@ Class > decl_EdgeToEdgePai "@brief A generic edge-to-edge-pair operator\n" "\n" "Edge processors are an efficient way to process edges from an edge collection. To apply a processor, derive your own " - "operator class and pass an instance to \\Edges#processed method.\n" + "operator class and pass an instance to the \\Edges#processed method.\n" "\n" "Conceptually, these methods take each edge from the edge collection and present it to the operator's 'process' method.\n" "The result of this call is a list of zero to many output edge pairs derived from the input edge.\n" diff --git a/src/db/db/gsiDeclDbRegion.cc b/src/db/db/gsiDeclDbRegion.cc index a5d871e39..fb8346c2d 100644 --- a/src/db/db/gsiDeclDbRegion.cc +++ b/src/db/db/gsiDeclDbRegion.cc @@ -90,7 +90,7 @@ Class decl_PolygonFilterImpl ("db", "PolygonFilter", "@brief A generic polygon filter adaptor\n" "\n" "Polygon filters are an efficient way to filter polygons from a Region. To apply a filter, derive your own " - "filter class and pass an instance to \\Region#filter or \\Region#filtered method.\n" + "filter class and pass an instance to the \\Region#filter or \\Region#filtered method.\n" "\n" "Conceptually, these methods take each polygon from the region and present it to the filter's 'selected' method.\n" "Based on the result of this evaluation, the polygon is kept or discarded.\n" @@ -135,7 +135,7 @@ Class > decl_PolygonOperator ("db "@brief A generic polygon operator\n" "\n" "Polygon processors are an efficient way to process polygons from a Region. To apply a processor, derive your own " - "operator class and pass an instance to \\Region#process or \\Region#processed method.\n" + "operator class and pass an instance to the \\Region#process or \\Region#processed method.\n" "\n" "Conceptually, these methods take each polygon from the region and present it to the operators' 'process' method.\n" "The result of this call is a list of zero to many output polygons derived from the input polygon.\n" @@ -180,7 +180,7 @@ Class > decl_PolygonToEdgeP "@brief A generic polygon-to-edge operator\n" "\n" "Polygon processors are an efficient way to process polygons from a Region. To apply a processor, derive your own " - "operator class and pass an instance to \\Region#processed method.\n" + "operator class and pass an instance to the \\Region#processed method.\n" "\n" "Conceptually, these methods take each polygon from the region and present it to the operator's 'process' method.\n" "The result of this call is a list of zero to many output edges derived from the input polygon.\n" @@ -204,7 +204,7 @@ Class > decl_PolygonToE "@brief A generic polygon-to-edge-pair operator\n" "\n" "Polygon processors are an efficient way to process polygons from a Region. To apply a processor, derive your own " - "operator class and pass an instance to \\Region#processed method.\n" + "operator class and pass an instance to the \\Region#processed method.\n" "\n" "Conceptually, these methods take each polygon from the region and present it to the operator's 'process' method.\n" "The result of this call is a list of zero to many output edge pairs derived from the input polygon.\n" diff --git a/testdata/ruby/dbEdgePairsTest.rb b/testdata/ruby/dbEdgePairsTest.rb index b5db1f866..f9b3289be 100644 --- a/testdata/ruby/dbEdgePairsTest.rb +++ b/testdata/ruby/dbEdgePairsTest.rb @@ -44,6 +44,46 @@ class PerpendicularEdgesFilter < RBA::EdgePairFilter end +class FlipEdgePair < RBA::EdgePairOperator + + # Constructor + def initialize + self.is_isotropic_and_scale_invariant # orientation and scale do not matter + end + + # Flips the edge pair + def process(edge_pair) + return [ RBA::EdgePair::new(edge_pair.second, edge_pair.first) ] + end + +end + +class SomeEdgePairToEdgeOperator < RBA::EdgePairToEdgeOperator + + # Constructor + def initialize + self.is_isotropic_and_scale_invariant # scale or orientation do not matter + end + + def process(ep) + return [ RBA::Edge::new(ep.first.p1, ep.second.p2) ] + end + +end + +class SomeEdgePairToPolygonOperator < RBA::EdgePairToPolygonOperator + + # Constructor + def initialize + self.is_isotropic_and_scale_invariant # scale or orientation do not matter + end + + def process(ep) + return [ RBA::Polygon::new(ep.bbox) ] + end + +end + class DBEdgePairs_TestClass < TestBase # Basics @@ -374,6 +414,61 @@ class DBEdgePairs_TestClass < TestBase end + # Generic processors + def test_generic_processors_epep + + # Some basic tests for the processor class + + f = FlipEdgePair::new + assert_equal(f.wants_variants?, true) + f.wants_variants = false + assert_equal(f.wants_variants?, false) + + # Smoke test + f.is_isotropic + f.is_scale_invariant + + # Some application + + edge_pairs = RBA::EdgePairs::new + + edge_pairs.insert(RBA::EdgePair::new(RBA::Edge::new(0, 0, 100, 100), RBA::Edge::new(200, 300, 200, 500))) + + assert_equal(edge_pairs.processed(FlipEdgePair::new).to_s, "(200,300;200,500)/(0,0;100,100)") + assert_equal(edge_pairs.to_s, "(0,0;100,100)/(200,300;200,500)") + edge_pairs.process(FlipEdgePair::new) + assert_equal(edge_pairs.to_s, "(200,300;200,500)/(0,0;100,100)") + + end + + # Generic processors + def test_generic_processors_epe + + p = SomeEdgePairToEdgeOperator::new + + edge_pairs = RBA::EdgePairs::new + + edge_pairs.insert(RBA::EdgePair::new(RBA::Edge::new(0, 0, 100, 100), RBA::Edge::new(200, 300, 200, 500))) + + assert_equal(edge_pairs.processed(p).to_s, "(0,0;200,500)") + assert_equal(edge_pairs.to_s, "(0,0;100,100)/(200,300;200,500)") + + end + + # Generic processors + def test_generic_processors_epp + + p = SomeEdgePairToPolygonOperator::new + + edge_pairs = RBA::EdgePairs::new + + edge_pairs.insert(RBA::EdgePair::new(RBA::Edge::new(0, 0, 100, 100), RBA::Edge::new(200, 300, 200, 500))) + + assert_equal(edge_pairs.processed(p).to_s, "(0,0;0,500;200,500;200,0)") + assert_equal(edge_pairs.to_s, "(0,0;100,100)/(200,300;200,500)") + + end + end