diff --git a/src/db/dbEdges.cc b/src/db/dbEdges.cc index 1a4983b84..1235c6f51 100644 --- a/src/db/dbEdges.cc +++ b/src/db/dbEdges.cc @@ -27,6 +27,7 @@ #include "dbLayoutUtils.h" #include "dbBoxConvert.h" #include "dbBoxScanner.h" +#include "dbPolygonTools.h" #include "tlIntervalMap.h" #include "tlVariant.h" @@ -667,25 +668,10 @@ public: } if (e && p && m_seen.find (e) == m_seen.end ()) { - - // A polygon and an edge interact if the edge is either inside completely - // of at least one edge of the polygon intersects with the edge - bool interacts = false; - if (p->box ().contains (e->p1 ()) && db::inside_poly (p->begin_edge (), e->p1 ()) >= 0) { - interacts = true; - } else { - for (db::Polygon::polygon_edge_iterator pe = p->begin_edge (); ! pe.at_end () && ! interacts; ++pe) { - if ((*pe).intersect (*e)) { - interacts = true; - } - } - } - - if (interacts) { + if (db::interact (*p, *e)) { m_seen.insert (e); mp_output->insert (*e); } - } } diff --git a/src/db/dbPolygonTools.h b/src/db/dbPolygonTools.h index 17bc5421d..5d466e584 100644 --- a/src/db/dbPolygonTools.h +++ b/src/db/dbPolygonTools.h @@ -325,6 +325,27 @@ bool interact_pp (const Polygon1 &poly1, const Polygon2 &poly2) return false; } +/** + * @brief Determines whether a polygon and an edge share at least one common point. + */ +template +bool interact_pe (const Polygon &poly, const Edge &edge) +{ + // A polygon and an edge interact if the edge is either inside completely + // of at least one edge of the polygon intersects with the edge + if (poly.box ().contains (edge.p1 ()) && db::inside_poly (poly.begin_edge (), edge.p1 ()) >= 0) { + return true; + } else { + for (typename Polygon::polygon_edge_iterator pe = poly.begin_edge (); ! pe.at_end (); ++pe) { + if ((*pe).intersect (edge)) { + return true; + } + } + } + + return false; +} + // Some specializations that map all combinations to template versions inline bool interact (const db::Box &box1, const db::Box &box2) { return box1.touches (box2); } inline bool interact (const db::DBox &box1, const db::DBox &box2) { return box1.touches (box2); } @@ -332,6 +353,10 @@ inline bool interact (const db::Polygon &poly, const db::Box &box) inline bool interact (const db::SimplePolygon &poly, const db::Box &box) { return interact_pb (poly, box); } inline bool interact (const db::DPolygon &poly, const db::DBox &box) { return interact_pb (poly, box); } inline bool interact (const db::DSimplePolygon &poly, const db::DBox &box) { return interact_pb (poly, box); } +inline bool interact (const db::Polygon &poly, const db::Edge &edge) { return interact_pe (poly, edge); } +inline bool interact (const db::SimplePolygon &poly, const db::Edge &edge) { return interact_pe (poly, edge); } +inline bool interact (const db::DPolygon &poly, const db::DEdge &edge) { return interact_pe (poly, edge); } +inline bool interact (const db::DSimplePolygon &poly, const db::DEdge &edge) { return interact_pe (poly, edge); } inline bool interact (const db::Polygon &poly1, const db::Polygon &poly2) { return interact_pp (poly1, poly2); } inline bool interact (const db::SimplePolygon &poly1, const db::Polygon &poly2) { return interact_pp (poly1, poly2); } inline bool interact (const db::Polygon &poly1, const db::SimplePolygon &poly2) { return interact_pp (poly1, poly2); } diff --git a/src/db/dbTrans.h b/src/db/dbTrans.h index 87f0f3bbf..07b49bc5c 100644 --- a/src/db/dbTrans.h +++ b/src/db/dbTrans.h @@ -1770,8 +1770,7 @@ public: if (fabs (m_cos - 1.0) > eps_f ()) { return false; } - return fabs (m_u.x ()) <= db::epsilon_f () && - fabs (m_u.y ()) <= db::epsilon_f (); + return disp ().equal (displacement_type ()); } /** diff --git a/src/unit_tests/dbEdges.cc b/src/unit_tests/dbEdges.cc index 26cab1982..7a1345651 100644 --- a/src/unit_tests/dbEdges.cc +++ b/src/unit_tests/dbEdges.cc @@ -24,6 +24,7 @@ #include "utHead.h" #include "dbEdges.h" +#include "dbPolygonTools.h" #include "dbRegion.h" #include @@ -378,57 +379,64 @@ TEST(8) TEST(9) { - for (int pass = 0; pass < 10; ++pass) { + for (unsigned int seed = 1; seed < 20; ++seed) { - int d = pass >= 5 ? 10 : 1000; + srand(seed); - db::Edges e; - for (int i = 0; i < 100; ++i) { - e.insert (db::Edge (db::Point (abs (rand ()) % d, abs (rand ()) % d), db::Point (abs (rand ()) % d, abs (rand ()) % d))); - db::Point p (abs (rand ()) % d, abs (rand ()) % d); - e.insert (db::Edge (p, p)); - } + for (int pass = 0; pass < 10; ++pass) { - db::Edges e2; - for (int i = 0; i < 2; ++i) { - e2.insert (db::Edge (db::Point (abs (rand ()) % d, abs (rand ()) % d), db::Point (abs (rand ()) % d, abs (rand ()) % d))); - db::Point p (abs (rand ()) % d, abs (rand ()) % d); - e2.insert (db::Edge (p, p)); - } + int d = pass >= 5 ? 10 : 1000; - std::set ea, eb; + db::Edges e; + for (int i = 0; i < 100; ++i) { + e.insert (db::Edge (db::Point (abs (rand ()) % d, abs (rand ()) % d), db::Point (abs (rand ()) % d, abs (rand ()) % d))); + db::Point p (abs (rand ()) % d, abs (rand ()) % d); + e.insert (db::Edge (p, p)); + } - e.set_merged_semantics (false); - db::Edges ia = e.selected_interacting (e2); - for (db::Edges::const_iterator i = ia.begin (); ! i.at_end (); ++i) { - ea.insert (*i); - } + db::Edges e2; + for (int i = 0; i < 2; ++i) { + e2.insert (db::Edge (db::Point (abs (rand ()) % d, abs (rand ()) % d), db::Point (abs (rand ()) % d, abs (rand ()) % d))); + db::Point p (abs (rand ()) % d, abs (rand ()) % d); + e2.insert (db::Edge (p, p)); + } - EXPECT_NE (ea.size (), size_t (0)); + std::set ea, eb; - // brute force - for (db::Edges::const_iterator i = e.begin (); ! i.at_end (); ++i) { - for (db::Edges::const_iterator j = e2.begin (); ! j.at_end (); ++j) { - if (i->intersect (*j)) { - eb.insert (*i); + e.set_merged_semantics (false); + db::Edges ia = e.selected_interacting (e2); + for (db::Edges::const_iterator i = ia.begin (); ! i.at_end (); ++i) { + ea.insert (*i); + } + + EXPECT_NE (ea.size (), size_t (0)); + + // brute force + for (db::Edges::const_iterator i = e.begin (); ! i.at_end (); ++i) { + for (db::Edges::const_iterator j = e2.begin (); ! j.at_end (); ++j) { + if (i->intersect (*j)) { + eb.insert (*i); + } } } - } - if (ea != eb) { - tl::info << "In implementation but not in brute-force:"; - for (std::set::const_iterator i = ea.begin (); i != ea.end (); ++i) { - if (eb.find (*i) == eb.end ()) { - tl::info << " " << i->to_string (); + if (ea != eb) { + tl::info << "Seed = " << seed; + tl::info << "In implementation but not in brute-force:"; + for (std::set::const_iterator i = ea.begin (); i != ea.end (); ++i) { + if (eb.find (*i) == eb.end ()) { + tl::info << " " << i->to_string (); + } } - } - tl::info << "In brute-force but not in implementation:"; - for (std::set::const_iterator i = eb.begin (); i != eb.end (); ++i) { - if (ea.find (*i) == ea.end ()) { - tl::info << " " << i->to_string (); + tl::info << "In brute-force but not in implementation:"; + for (std::set::const_iterator i = eb.begin (); i != eb.end (); ++i) { + if (ea.find (*i) == ea.end ()) { + tl::info << " " << i->to_string (); + } } + EXPECT_EQ (true, false); } - EXPECT_EQ (true, false); + } } @@ -436,64 +444,70 @@ TEST(9) TEST(10) { - for (int pass = 0; pass < 10; ++pass) { + for (unsigned int seed = 1; seed < 20; ++seed) { - int d = pass >= 5 ? 10 : 1000; + srand(seed); - db::Edges e; - for (int i = 0; i < 100; ++i) { - e.insert (db::Edge (db::Point (abs (rand ()) % d, abs (rand ()) % d), db::Point (abs (rand ()) % d, abs (rand ()) % d))); - db::Point p (abs (rand ()) % d, abs (rand ()) % d); - e.insert (db::Edge (p, p)); - } + for (int pass = 0; pass < 10; ++pass) { - db::Region r; - for (int i = 0; i < 2; ++i) { - db::Box b; - do { - b = db::Box (db::Point (abs (rand ()) % d, abs (rand ()) % d), db::Point (abs (rand ()) % d, abs (rand ()) % d)); - } while (b.width () == 0 || b.height () == 0); - r.insert (b); - } + int d = pass >= 5 ? 10 : 1000; - std::set ea, eb; + db::Edges e; + for (int i = 0; i < 100; ++i) { + e.insert (db::Edge (db::Point (abs (rand ()) % d, abs (rand ()) % d), db::Point (abs (rand ()) % d, abs (rand ()) % d))); + db::Point p (abs (rand ()) % d, abs (rand ()) % d); + e.insert (db::Edge (p, p)); + } - e.set_merged_semantics (false); - db::Edges ia = e.selected_interacting (r); - for (db::Edges::const_iterator i = ia.begin (); ! i.at_end (); ++i) { - ea.insert (*i); - } + db::Region r; + for (int i = 0; i < 2; ++i) { + db::Box b; + do { + b = db::Box (db::Point (abs (rand ()) % d, abs (rand ()) % d), db::Point (abs (rand ()) % d, abs (rand ()) % d)); + } while (b.width () == 0 || b.height () == 0); + r.insert (b); + } - EXPECT_NE (ea.size (), size_t (0)); + std::set ea, eb; - // brute force - for (db::Edges::const_iterator i = e.begin (); ! i.at_end (); ++i) { - for (db::Region::const_iterator j = r.begin (); ! j.at_end (); ++j) { - // Use the enlarged edges and box to avoid rounding issues - if (i->transformed (db::ICplxTrans (10.0)).clipped (j->box ().transformed (db::ICplxTrans (10.0))).first) { - eb.insert (*i); + e.set_merged_semantics (false); + db::Edges ia = e.selected_interacting (r); + for (db::Edges::const_iterator i = ia.begin (); ! i.at_end (); ++i) { + ea.insert (*i); + } + + EXPECT_NE (ea.size (), size_t (0)); + + // brute force + for (db::Edges::const_iterator i = e.begin (); ! i.at_end (); ++i) { + for (db::Region::const_iterator j = r.begin (); ! j.at_end (); ++j) { + if (db::interact (*j, *i)) { + eb.insert (*i); + } } } - } - if (ea != eb) { - tl::info << "Boxes:"; - for (db::Region::const_iterator j = r.begin (); ! j.at_end (); ++j) { - tl::info << " " << j->to_string (); - } - tl::info << "In implementation but not in brute-force:"; - for (std::set::const_iterator i = ea.begin (); i != ea.end (); ++i) { - if (eb.find (*i) == eb.end ()) { - tl::info << " " << i->to_string (); + if (ea != eb) { + tl::info << "Seed = " << seed; + tl::info << "Boxes:"; + for (db::Region::const_iterator j = r.begin (); ! j.at_end (); ++j) { + tl::info << " " << j->to_string (); } - } - tl::info << "In brute-force but not in implementation:"; - for (std::set::const_iterator i = eb.begin (); i != eb.end (); ++i) { - if (ea.find (*i) == ea.end ()) { - tl::info << " " << i->to_string (); + tl::info << "In implementation but not in brute-force:"; + for (std::set::const_iterator i = ea.begin (); i != ea.end (); ++i) { + if (eb.find (*i) == eb.end ()) { + tl::info << " " << i->to_string (); + } } + tl::info << "In brute-force but not in implementation:"; + for (std::set::const_iterator i = eb.begin (); i != eb.end (); ++i) { + if (ea.find (*i) == ea.end ()) { + tl::info << " " << i->to_string (); + } + } + EXPECT_EQ (true, false); } - EXPECT_EQ (true, false); + } } diff --git a/src/unit_tests/dbPolygonTools.cc b/src/unit_tests/dbPolygonTools.cc index 481fab086..a8a144586 100644 --- a/src/unit_tests/dbPolygonTools.cc +++ b/src/unit_tests/dbPolygonTools.cc @@ -604,7 +604,7 @@ TEST(9d) TEST(10) { - // Simple test for polygon-box interaction (integer coordinates) + // Simple test for polygon-box/edge interaction (integer coordinates) db::Polygon poly; db::Point p[] = { db::Point (0, 100), @@ -613,6 +613,21 @@ TEST(10) }; poly.assign_hull (p, p + sizeof (p) / sizeof (p[0])); + EXPECT_EQ (interact (poly, db::Edge (-10, -10, -1, -1)), false); + EXPECT_EQ (interact (poly, db::Edge (-10, -10, 0, 0)), true); + EXPECT_EQ (interact (poly, db::Edge (-10, -10, 1, 1)), true); + EXPECT_EQ (interact (poly, db::Edge (-10, -10, 20, 10)), false); + EXPECT_EQ (interact (poly, db::Edge (-10, -10, 10, 20)), true); + EXPECT_EQ (interact (poly, db::Edge (10, 20, 20, 30)), true); + EXPECT_EQ (interact (poly, db::Edge (10, 20, 15, 25)), true); + EXPECT_EQ (interact (poly, db::Edge (30, 10, 40, 20)), false); + EXPECT_EQ (interact (poly, db::Edge (30, 20, 40, 50)), true); + EXPECT_EQ (interact (poly, db::Edge (-10, 20, 0, 30)), true); + EXPECT_EQ (interact (poly, db::Edge (-10, 20, -5, 30)), false); + EXPECT_EQ (interact (poly, db::Edge (-10, 100, -5, 110)), false); + EXPECT_EQ (interact (poly, db::Edge (-10, 100, 0, 110)), false); + EXPECT_EQ (interact (poly, db::Edge (-10, 100, 5, 100)), true); + EXPECT_EQ (interact (db::Box (0, 0, 100, 100), db::Box (-10, 100, 5, 110)), true); EXPECT_EQ (interact (db::Box (0, 0, 100, 100), db::Box (-10, -10, 110, 110)), true); EXPECT_EQ (interact (db::Box (0, 0, 100, 100), db::Box (-10, -10, 50, 110)), true); @@ -677,7 +692,7 @@ TEST(10) TEST(11) { - // Simple test for polygon-box interaction (integer coordinates) + // Simple test for polygon-box interaction (double coordinates) db::DPolygon poly; db::DPoint p[] = { db::DPoint (0, 100), @@ -686,6 +701,21 @@ TEST(11) }; poly.assign_hull (p, p + sizeof (p) / sizeof (p[0])); + EXPECT_EQ (interact (poly, db::DEdge (-1.0, -1.0, -0.1, -0.1)), false); + EXPECT_EQ (interact (poly, db::DEdge (-10, -10, 0, 0)), true); + EXPECT_EQ (interact (poly, db::DEdge (-0.01, -0.01, 0.001, 0.001)), true); + EXPECT_EQ (interact (poly, db::DEdge (-10, -10, 20, 10)), false); + EXPECT_EQ (interact (poly, db::DEdge (-10, -10, 10, 20)), true); + EXPECT_EQ (interact (poly, db::DEdge (10, 20, 20, 30)), true); + EXPECT_EQ (interact (poly, db::DEdge (10, 20, 15, 25)), true); + EXPECT_EQ (interact (poly, db::DEdge (30, 10, 40, 20)), false); + EXPECT_EQ (interact (poly, db::DEdge (30, 20, 40, 50)), true); + EXPECT_EQ (interact (poly, db::DEdge (-10, 20, 0, 30)), true); + EXPECT_EQ (interact (poly, db::DEdge (-10, 20, -5, 30)), false); + EXPECT_EQ (interact (poly, db::DEdge (-10, 100, -5, 110)), false); + EXPECT_EQ (interact (poly, db::DEdge (-10.0, 100.0, 0.0, 100.5)), false); + EXPECT_EQ (interact (poly, db::DEdge (-10, 100, 5, 100)), true); + EXPECT_EQ (interact (db::DBox (0, 0, 100, 100), db::DBox (-10, 100, 5, 110)), true); EXPECT_EQ (interact (db::DBox (0, 0, 100, 100), db::DBox (-10, -10, 110, 110)), true); EXPECT_EQ (interact (db::DBox (0, 0, 100, 100), db::DBox (-10, -10, 50, 110)), true); diff --git a/src/unit_tests/dbTilingProcessor.cc b/src/unit_tests/dbTilingProcessor.cc index 2b506497f..362905144 100644 --- a/src/unit_tests/dbTilingProcessor.cc +++ b/src/unit_tests/dbTilingProcessor.cc @@ -274,9 +274,9 @@ TEST(3) } EXPECT_EQ (or2.has_valid_polygons (), true); - EXPECT_EQ (or2.size () / 1000, size_t (100)); // because we use rand () the value may vary - it's only accurate to 1% + EXPECT_EQ (or2.size () / 2000, size_t (50)); // because we use rand () the value may vary - it's only accurate to 2% EXPECT_EQ (or2_copy.has_valid_polygons (), true); - EXPECT_EQ (or2_copy.size () / 1000, size_t (81)); // because we use rand () the value may vary - it's only accurate to 1% + EXPECT_EQ (or2_copy.size () / 2000, size_t (40)); // because we use rand () the value may vary - it's only accurate to 2% EXPECT_EQ ((or2 ^ or2_copy).empty (), true); #if 0 diff --git a/src/unit_tests/tlFileSystemWatcher.cc b/src/unit_tests/tlFileSystemWatcher.cc index 7ddd21a41..b63697330 100644 --- a/src/unit_tests/tlFileSystemWatcher.cc +++ b/src/unit_tests/tlFileSystemWatcher.cc @@ -182,7 +182,7 @@ TEST(3) } // make sure the events get processed - wait_for_ms (1100); + wait_for_ms (5000); // should have modified the file EXPECT_EQ (changed_spy.count (), 0); @@ -204,7 +204,7 @@ TEST(3) } // make sure the events get processed - wait_for_ms (1100); + wait_for_ms (5000); // should have modified the file EXPECT_EQ (changed_spy.count (), 50);