From fe0d3e28bab5862b0f73a7929346a01fbf565ad5 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 26 Jan 2019 23:59:22 +0100 Subject: [PATCH] Fixed issue #228 Reason for the problem: the interaction test has to keep separate "inside" records for both below and above the scanline, not just once. With the single record, the step in the left polygon erased the "inside" condition. --- src/db/db/dbEdgeProcessor.cc | 28 ++++++++++++++++++++-------- src/db/db/dbEdgeProcessor.h | 4 ++-- src/db/unit_tests/dbRegion.cc | 24 ++++++++++++++++++++++++ 3 files changed, 46 insertions(+), 10 deletions(-) diff --git a/src/db/db/dbEdgeProcessor.cc b/src/db/db/dbEdgeProcessor.cc index 0a1481cd1..756f6af72 100644 --- a/src/db/db/dbEdgeProcessor.cc +++ b/src/db/db/dbEdgeProcessor.cc @@ -639,7 +639,8 @@ InteractionDetector::reset () { m_wcv_n.clear (); m_wcv_s.clear (); - m_inside.clear (); + m_inside_n.clear (); + m_inside_s.clear (); } void @@ -649,7 +650,8 @@ InteractionDetector::reserve (size_t n) m_wcv_s.clear (); m_wcv_n.resize (n, 0); m_wcv_s.resize (n, 0); - m_inside.clear (); + m_inside_n.clear (); + m_inside_s.clear (); } int @@ -667,9 +669,11 @@ InteractionDetector::edge (bool north, bool enter, property_type p) // we have to catch interactions between objects north and south to the scanline if (north || (m_mode == 0 && m_include_touching)) { + std::set *inside = north ? &m_inside_n : &m_inside_s; + if (inside_after < inside_before) { - m_inside.erase (p); + inside->erase (p); if (m_mode != 0) { @@ -677,7 +681,7 @@ InteractionDetector::edge (bool north, bool enter, property_type p) // (due to prefer_touch == true and the sorting of coincident edges by property id) // hence every remaining parts count as non-interacting (outside) if (p == m_container_id) { - for (std::set ::const_iterator i = m_inside.begin (); i != m_inside.end (); ++i) { + for (std::set ::const_iterator i = inside->begin (); i != inside->end (); ++i) { if (*i != m_container_id) { m_non_interactions.insert (*i); } @@ -695,13 +699,13 @@ InteractionDetector::edge (bool north, bool enter, property_type p) // note that the container parts will be delivered first of all coincident // edges hence we can check whether the container is present even for coincident // edges - if (m_inside.find (m_container_id) != m_inside.end ()) { + if (inside->find (m_container_id) != inside->end ()) { m_interactions.insert (std::make_pair (m_container_id, p)); } else { m_non_interactions.insert (p); } } else { - for (std::set ::const_iterator i = m_inside.begin (); i != m_inside.end (); ++i) { + for (std::set ::const_iterator i = inside->begin (); i != inside->end (); ++i) { if (*i != m_container_id) { m_interactions.insert (std::make_pair (m_container_id, *i)); } @@ -710,7 +714,15 @@ InteractionDetector::edge (bool north, bool enter, property_type p) } else { - for (std::set ::const_iterator i = m_inside.begin (); i != m_inside.end (); ++i) { + for (std::set ::const_iterator i = m_inside_n.begin (); i != m_inside_n.end (); ++i) { + if (*i < p) { + m_interactions.insert (std::make_pair (*i, p)); + } else if (*i > p) { + m_interactions.insert (std::make_pair (p, *i)); + } + } + + for (std::set ::const_iterator i = m_inside_s.begin (); i != m_inside_s.end (); ++i) { if (*i < p) { m_interactions.insert (std::make_pair (*i, p)); } else if (*i > p) { @@ -720,7 +732,7 @@ InteractionDetector::edge (bool north, bool enter, property_type p) } - m_inside.insert (p); + inside->insert (p); } diff --git a/src/db/db/dbEdgeProcessor.h b/src/db/db/dbEdgeProcessor.h index bca103bc2..9cca1308a 100644 --- a/src/db/db/dbEdgeProcessor.h +++ b/src/db/db/dbEdgeProcessor.h @@ -299,7 +299,7 @@ public: virtual void reserve (size_t n); virtual int edge (bool north, bool enter, property_type p); virtual int compare_ns () const; - virtual bool is_reset () const { return m_inside.empty (); } + virtual bool is_reset () const { return m_inside_s.empty () && m_inside_n.empty (); } virtual bool prefer_touch () const { return m_include_touching; } private: @@ -307,7 +307,7 @@ private: bool m_include_touching; property_type m_container_id; std::vector m_wcv_n, m_wcv_s; - std::set m_inside; + std::set m_inside_n, m_inside_s; std::set > m_interactions; std::set m_non_interactions; }; diff --git a/src/db/unit_tests/dbRegion.cc b/src/db/unit_tests/dbRegion.cc index 686ec4062..55f61df92 100644 --- a/src/db/unit_tests/dbRegion.cc +++ b/src/db/unit_tests/dbRegion.cc @@ -1329,3 +1329,27 @@ TEST(30c) EXPECT_EQ (r.to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)"); } +TEST(issue_228) +{ + db::Region r; + db::Point pts[] = { + db::Point (0, 10), + db::Point (0, 290), + db::Point (280, 290), + db::Point (280, 230), + db::Point (360, 230), + db::Point (360, 70), + db::Point (280,70), + db::Point (280,10) + }; + + db::Polygon poly; + poly.assign_hull (pts, pts + sizeof (pts) / sizeof (pts [0])); + r.insert (poly); + + db::Region rr; + rr.insert (db::Box (360, 70, 480, 230)); + + EXPECT_EQ (r.selected_interacting (rr).to_string (), r.to_string ()); + EXPECT_EQ (rr.selected_interacting (r).to_string (), rr.to_string ()); +}