diff --git a/src/db/db/dbEdgePairFilters.cc b/src/db/db/dbEdgePairFilters.cc index 541f33731..9b8d6ff9f 100644 --- a/src/db/db/dbEdgePairFilters.cc +++ b/src/db/db/dbEdgePairFilters.cc @@ -78,4 +78,41 @@ bool EdgePairFilterByDistance::selected (const db::EdgePair &edge_pair) const return m_inverted ? !sel : sel; } +// --------------------------------------------------------------------------------------------------- +// EdgePairFilterByArea implementation + +EdgePairFilterByArea::EdgePairFilterByArea (area_type min_area, area_type max_area, bool inverted) + : m_min_area (min_area), m_max_area (max_area), m_inverted (inverted) +{ + // .. nothing yet .. +} + +bool EdgePairFilterByArea::selected (const db::EdgePair &edge_pair) const +{ + area_type dist = edge_pair.to_simple_polygon (0).area (); + bool sel = (dist >= m_min_area && dist < m_max_area); + return m_inverted ? !sel : sel; +} + +// --------------------------------------------------------------------------------------------------- +// EdgePairFilterByArea implementation + +InternalAngleEdgePairFilter::InternalAngleEdgePairFilter (double a, bool inverted) + : m_inverted (inverted), m_checker (a, true, a, true) +{ + // .. nothing yet .. +} + +InternalAngleEdgePairFilter::InternalAngleEdgePairFilter (double amin, bool include_amin, double amax, bool include_amax, bool inverted) + : m_inverted (inverted), m_checker (amin, include_amin, amax, include_amax) +{ + // .. nothing yet .. +} + +bool +InternalAngleEdgePairFilter::selected (const db::EdgePair &edge_pair) const +{ + return m_checker (edge_pair.first ().d (), -edge_pair.second ().d ()) != m_inverted; +} + } diff --git a/src/db/db/dbEdgePairFilters.h b/src/db/db/dbEdgePairFilters.h index 9f25858e8..4b961a281 100644 --- a/src/db/db/dbEdgePairFilters.h +++ b/src/db/db/dbEdgePairFilters.h @@ -25,6 +25,7 @@ #define HDR_dbEdgePairFilters #include "dbEdgePairs.h" +#include "dbEdgesUtils.h" namespace db { @@ -69,12 +70,57 @@ public: EdgePairFilterByDistance (distance_type min_distance, distance_type max_distance, bool inverted); virtual bool selected (const db::EdgePair &edge_pair) const; - virtual const TransformationReducer *vars () const { return 0; } - virtual bool wants_variants () const { return false; } + virtual const TransformationReducer *vars () const { return &m_vars; } + virtual bool wants_variants () const { return true; } private: distance_type m_min_distance, m_max_distance; bool m_inverted; + db::MagnificationReducer m_vars; +}; + +/** + * @brief Filters edge pairs based on the distance of the edges. + * + * The distance is measured as the smallest distance between each of the points of the two edges. + */ +class DB_PUBLIC EdgePairFilterByArea + : public EdgePairFilterBase +{ +public: + typedef db::coord_traits::area_type area_type; + + EdgePairFilterByArea (area_type min_area, area_type max_area, bool inverted); + + virtual bool selected (const db::EdgePair &edge_pair) const; + virtual const TransformationReducer *vars () const { return &m_vars; } + virtual bool wants_variants () const { return true; } + +private: + area_type m_min_area, m_max_area; + bool m_inverted; + db::MagnificationReducer m_vars; +}; + +/** + * @brief Filters edge pairs based on the distance of the edges. + * + * The distance is measured as the smallest distance between each of the points of the two edges. + */ +class DB_PUBLIC InternalAngleEdgePairFilter + : public EdgePairFilterBase +{ +public: + InternalAngleEdgePairFilter (double a, bool inverted); + InternalAngleEdgePairFilter (double amin, bool include_amin, double amax, bool include_amax, bool inverted); + + virtual bool selected (const db::EdgePair &edge_pair) const; + virtual const TransformationReducer *vars () const { return 0; } + virtual bool wants_variants () const { return false; } + +private: + bool m_inverted; + db::EdgeAngleChecker m_checker; }; } diff --git a/src/db/db/dbEdgesUtils.h b/src/db/db/dbEdgesUtils.h index 0fd02770a..7f221025e 100644 --- a/src/db/db/dbEdgesUtils.h +++ b/src/db/db/dbEdgesUtils.h @@ -236,7 +236,6 @@ struct DB_PUBLIC EdgeOrientationFilter } private: - db::DVector m_emin, m_emax; bool m_inverse; db::MagnificationAndOrientationReducer m_vars; EdgeAngleChecker m_checker; diff --git a/src/db/db/gsiDeclDbEdgePairs.cc b/src/db/db/gsiDeclDbEdgePairs.cc index 0b220e499..f7d3073a0 100644 --- a/src/db/db/gsiDeclDbEdgePairs.cc +++ b/src/db/db/gsiDeclDbEdgePairs.cc @@ -246,6 +246,30 @@ static db::EdgePairs with_angle_both2 (const db::EdgePairs *r, double amin, doub return r->filtered (ef); } +static db::EdgePairs with_internal_angle1 (const db::EdgePairs *r, double a, bool inverse) +{ + db::InternalAngleEdgePairFilter f (a, inverse); + return r->filtered (f); +} + +static db::EdgePairs with_internal_angle2 (const db::EdgePairs *r, double amin, double amax, bool inverse, bool include_amin, bool include_amax) +{ + db::InternalAngleEdgePairFilter f (amin, include_amin, amax, include_amax, inverse); + return r->filtered (f); +} + +static db::EdgePairs with_area1 (const db::EdgePairs *r, db::EdgePair::area_type a, bool inverse) +{ + db::EdgePairFilterByArea f (a, a + 1, inverse); + return r->filtered (f); +} + +static db::EdgePairs with_area2 (const db::EdgePairs *r, db::EdgePair::area_type amin, db::EdgePair::area_type amax, bool inverse) +{ + db::EdgePairFilterByArea f (amin, amax, inverse); + return r->filtered (f); +} + extern Class decl_dbShapeCollection; Class decl_EdgePairs (decl_dbShapeCollection, "db", "EdgePairs", @@ -621,7 +645,7 @@ Class decl_EdgePairs (decl_dbShapeCollection, "db", "EdgePairs", method_ext ("with_distance", with_distance2, gsi::arg ("min_distance"), gsi::arg ("max_distance"), gsi::arg ("inverse"), "@brief Filters the edge pairs by the distance of the edges\n" "Filters the edge pairs in the edge pair collection by distance of the edges. If \"inverse\" is false, only " - "edge pairs where both edges have a distance between min_distance and max_distance (max_distance itself is excluded). If \"inverse\" is true, " + "edge pairs where both edges have a distance between min_distance and max_distance (max_distance itself is excluded) are returned. If \"inverse\" is true, " "edge pairs not fulfilling this criterion are returned.\n" "\n" "Distance is measured as the shortest distance between any of the points on the edges.\n" @@ -678,6 +702,51 @@ Class decl_EdgePairs (decl_dbShapeCollection, "db", "EdgePairs", "\n" "This method has been added in version 0.27.1.\n" ) + + method_ext ("with_area", with_area1, gsi::arg ("area"), gsi::arg ("inverse"), + "@brief Filters the edge pairs by the enclosed area\n" + "Filters the edge pairs in the edge pair collection by enclosed area. If \"inverse\" is false, only " + "edge pairs with the given area are returned. If \"inverse\" is true, " + "edge pairs not with the given area are returned.\n" + "\n" + "This method has been added in version 0.27.2.\n" + ) + + method_ext ("with_area", with_area2, gsi::arg ("min_area"), gsi::arg ("max_area"), gsi::arg ("inverse"), + "@brief Filters the edge pairs by the enclosed area\n" + "Filters the edge pairs in the edge pair collection by enclosed area. If \"inverse\" is false, only " + "edge pairs with an area between min_area and max_area (max_area itself is excluded) are returned. If \"inverse\" is true, " + "edge pairs not fulfilling this criterion are returned.\n" + "\n" + "This method has been added in version 0.27.2.\n" + ) + + method_ext ("with_internal_angle", with_internal_angle1, gsi::arg ("angle"), gsi::arg ("inverse"), + "@brief Filters the edge pairs by the angle between their edges\n" + "Filters the edge pairs in the edge pair collection by the angle between their edges. If \"inverse\" is false, only " + "edge pairs with the given angle are returned. If \"inverse\" is true, " + "edge pairs not with the given angle are returned.\n" + "\n" + "The angle is measured between the two edges. Antiparallel edges have an angle of 0, parallel ones an angle of 180 or -180 degree (whichever fits). " + "For other configurations, the angle is determined by thinking of the edges as emerging from the same point: if the second edge is rotated clockwise " + "against the first one, the angle is positive. If the second edge is rotated counterclockwise, the angle is negative. This way, the same angle " + "definition applies to edges at a corner of a polygon and the same edges appearing in an edge pair.\n" + "\n" + "This method has been added in version 0.27.2.\n" + ) + + method_ext ("with_internal_angle", with_internal_angle2, gsi::arg ("min_angle"), gsi::arg ("max_angle"), gsi::arg ("inverse"), gsi::arg ("include_min_angle", true), gsi::arg ("include_max_angle", false), + "@brief Filters the edge pairs by the angle between their edges\n" + "Filters the edge pairs in the edge pair collection by the angle between their edges. If \"inverse\" is false, only " + "edge pairs with an angle between min_angle and max_angle (max_angle itself is excluded) are returned. If \"inverse\" is true, " + "edge pairs not fulfilling this criterion are returned.\n" + "\n" + "The angle is measured between the two edges. Antiparallel edges have an angle of 0, parallel ones an angle of 180 or -180 degree (whichever fits). " + "For other configurations, the angle is determined by thinking of the edges as emerging from the same point: if the second edge is rotated clockwise " + "against the first one, the angle is positive. If the second edge is rotated counterclockwise, the angle is negative. This way, the same angle " + "definition applies to edges at a corner of a polygon and the same edges appearing in an edge pair.\n" + "\n" + "With \"include_min_angle\" set to true (the default), the minimum angle is included in the criterion while with false, the " + "minimum angle itself is not included. Same for \"include_max_angle\" where the default is false, meaning the maximum angle is not included in the range.\n" + "\n" + "This method has been added in version 0.27.2.\n" + ) + method_ext ("polygons", &polygons1, "@brief Converts the edge pairs to polygons\n" "This method creates polygons from the edge pairs. Each polygon will be a triangle or quadrangle " diff --git a/testdata/ruby/dbEdgePairsTest.rb b/testdata/ruby/dbEdgePairsTest.rb index 5a27c58fa..95ef504b5 100644 --- a/testdata/ruby/dbEdgePairsTest.rb +++ b/testdata/ruby/dbEdgePairsTest.rb @@ -225,6 +225,78 @@ class DBEdgePairs_TestClass < TestBase end + def test_5 + + # filters + + ep1 = RBA::EdgePair::new(RBA::Edge::new(0, 0, 0, 10), RBA::Edge::new(10, 20, 10, 0)) + ep2 = RBA::EdgePair::new(RBA::Edge::new(0, 0, 0, 10), RBA::Edge::new(10, 0, 10, 20)) + ep3 = RBA::EdgePair::new(RBA::Edge::new(0, 0, 0, 20), RBA::Edge::new(10, 20, 10, 0)) + ep4 = RBA::EdgePair::new(RBA::Edge::new(0, 0, 0, 10), RBA::Edge::new(10, 0, 10, 10)) + + r1 = RBA::EdgePairs::new([ ep1, ep2, ep3, ep4 ]) + + assert_equal(r1.with_distance(10, false).to_s, "(0,0;0,10)/(10,20;10,0);(0,0;0,10)/(10,0;10,20);(0,0;0,20)/(10,20;10,0);(0,0;0,10)/(10,0;10,10)") + assert_equal(r1.with_distance(5, 20, false).to_s, "(0,0;0,10)/(10,20;10,0);(0,0;0,10)/(10,0;10,20);(0,0;0,20)/(10,20;10,0);(0,0;0,10)/(10,0;10,10)") + assert_equal(r1.with_distance(15, 20, false).to_s, "") + assert_equal(r1.with_distance(15, 20, true).to_s, "(0,0;0,10)/(10,20;10,0);(0,0;0,10)/(10,0;10,20);(0,0;0,20)/(10,20;10,0);(0,0;0,10)/(10,0;10,10)") + + assert_equal(r1.with_length(10, false).to_s, "(0,0;0,10)/(10,20;10,0);(0,0;0,10)/(10,0;10,20);(0,0;0,10)/(10,0;10,10)") + assert_equal(r1.with_length(10, 20, false).to_s, "(0,0;0,10)/(10,20;10,0);(0,0;0,10)/(10,0;10,20);(0,0;0,10)/(10,0;10,10)") + assert_equal(r1.with_length(10, 21, false).to_s, "(0,0;0,10)/(10,20;10,0);(0,0;0,10)/(10,0;10,20);(0,0;0,20)/(10,20;10,0);(0,0;0,10)/(10,0;10,10)") + assert_equal(r1.with_length(10, true).to_s, "(0,0;0,10)/(10,20;10,0);(0,0;0,10)/(10,0;10,20);(0,0;0,20)/(10,20;10,0)") + assert_equal(r1.with_length_both(10, false).to_s, "(0,0;0,10)/(10,0;10,10)") + assert_equal(r1.with_length_both(10, 20, false).to_s, "(0,0;0,10)/(10,0;10,10)") + assert_equal(r1.with_length_both(10, 21, false).to_s, "(0,0;0,10)/(10,20;10,0);(0,0;0,10)/(10,0;10,20);(0,0;0,20)/(10,20;10,0);(0,0;0,10)/(10,0;10,10)") + assert_equal(r1.with_length_both(10, true).to_s, "(0,0;0,20)/(10,20;10,0)") + + assert_equal(r1.with_angle(0, false).to_s, "") + assert_equal(r1.with_angle(0, true).to_s, "(0,0;0,10)/(10,20;10,0);(0,0;0,10)/(10,0;10,20);(0,0;0,20)/(10,20;10,0);(0,0;0,10)/(10,0;10,10)") + assert_equal(r1.with_angle(90, false).to_s, "(0,0;0,10)/(10,20;10,0);(0,0;0,10)/(10,0;10,20);(0,0;0,20)/(10,20;10,0);(0,0;0,10)/(10,0;10,10)") + assert_equal(r1.with_angle(0, 90, false).to_s, "") + assert_equal(r1.with_angle(0, 90, false, true, true).to_s, "(0,0;0,10)/(10,20;10,0);(0,0;0,10)/(10,0;10,20);(0,0;0,20)/(10,20;10,0);(0,0;0,10)/(10,0;10,10)") + assert_equal(r1.with_angle_both(0, false).to_s, "") + assert_equal(r1.with_angle_both(0, true).to_s, "(0,0;0,10)/(10,20;10,0);(0,0;0,10)/(10,0;10,20);(0,0;0,20)/(10,20;10,0);(0,0;0,10)/(10,0;10,10)") + assert_equal(r1.with_angle_both(90, false).to_s, "(0,0;0,10)/(10,20;10,0);(0,0;0,10)/(10,0;10,20);(0,0;0,20)/(10,20;10,0);(0,0;0,10)/(10,0;10,10)") + assert_equal(r1.with_angle_both(0, 90, false).to_s, "") + assert_equal(r1.with_angle_both(0, 90, false, true, true).to_s, "(0,0;0,10)/(10,20;10,0);(0,0;0,10)/(10,0;10,20);(0,0;0,20)/(10,20;10,0);(0,0;0,10)/(10,0;10,10)") + + assert_equal(r1.with_area(0, false).to_s, "(0,0;0,10)/(10,0;10,10)") + assert_equal(r1.with_area(150, false).to_s, "(0,0;0,10)/(10,20;10,0)") + assert_equal(r1.with_area(0, true).to_s, "(0,0;0,10)/(10,20;10,0);(0,0;0,10)/(10,0;10,20);(0,0;0,20)/(10,20;10,0)") + assert_equal(r1.with_area(150, 151, false).to_s, "(0,0;0,10)/(10,20;10,0)") + assert_equal(r1.with_area(150, 150, false).to_s, "") + assert_equal(r1.with_area(150, 151, true).to_s, "(0,0;0,10)/(10,0;10,20);(0,0;0,20)/(10,20;10,0);(0,0;0,10)/(10,0;10,10)") + + assert_equal(r1.with_internal_angle(0, false).to_s, "(0,0;0,10)/(10,20;10,0);(0,0;0,20)/(10,20;10,0)") + assert_equal(r1.with_internal_angle(0, 0, false).to_s, "") + assert_equal(r1.with_internal_angle(0, 180, false).to_s, "(0,0;0,10)/(10,20;10,0);(0,0;0,20)/(10,20;10,0)") + assert_equal(r1.with_internal_angle(0, 180, false, true, true).to_s, "(0,0;0,10)/(10,20;10,0);(0,0;0,10)/(10,0;10,20);(0,0;0,20)/(10,20;10,0);(0,0;0,10)/(10,0;10,10)") + assert_equal(r1.with_internal_angle(180, false).to_s, "(0,0;0,10)/(10,0;10,20);(0,0;0,10)/(10,0;10,10)") + assert_equal(r1.with_internal_angle(-180, false).to_s, "(0,0;0,10)/(10,0;10,20);(0,0;0,10)/(10,0;10,10)") + assert_equal(r1.with_internal_angle(0, true).to_s, "(0,0;0,10)/(10,0;10,20);(0,0;0,10)/(10,0;10,10)") + + ep1 = RBA::EdgePair::new(RBA::Edge::new(0, 0, 0, 10), RBA::Edge::new(10, 20, 10, 0)) + ep2 = RBA::EdgePair::new(RBA::Edge::new(0, 0, 0, 10), RBA::Edge::new(20, 0, 30, 0)) + ep3 = RBA::EdgePair::new(RBA::Edge::new(0, 0, 0, 10), RBA::Edge::new(-20, 0, -30, 0)) + + r1 = RBA::EdgePairs::new([ ep1, ep2, ep3 ]) + + assert_equal(r1.with_distance(20, false).to_s, "(0,0;0,10)/(20,0;30,0);(0,0;0,10)/(-20,0;-30,0)") + assert_equal(r1.with_distance(20, true).to_s, "(0,0;0,10)/(10,20;10,0)") + + assert_equal(r1.with_internal_angle(0, false).to_s, "(0,0;0,10)/(10,20;10,0)") + assert_equal(r1.with_internal_angle(90, false).to_s, "(0,0;0,10)/(20,0;30,0)") + assert_equal(r1.with_internal_angle(-90, false).to_s, "(0,0;0,10)/(-20,0;-30,0)") + + assert_equal(r1.with_angle(90, false).to_s, "(0,0;0,10)/(10,20;10,0);(0,0;0,10)/(20,0;30,0);(0,0;0,10)/(-20,0;-30,0)") + assert_equal(r1.with_angle(0, false).to_s, "(0,0;0,10)/(20,0;30,0);(0,0;0,10)/(-20,0;-30,0)") + assert_equal(r1.with_angle(0, 90, false, true, true).to_s, "(0,0;0,10)/(10,20;10,0);(0,0;0,10)/(20,0;30,0);(0,0;0,10)/(-20,0;-30,0)") + assert_equal(r1.with_angle_both(90, false).to_s, "(0,0;0,10)/(10,20;10,0)") + assert_equal(r1.with_angle_both(0, false).to_s, "") + + end + end