diff --git a/src/db/db/dbTriangle.cc b/src/db/db/dbTriangle.cc index 26dbc4789..9f4f49fa3 100644 --- a/src/db/db/dbTriangle.cc +++ b/src/db/db/dbTriangle.cc @@ -68,8 +68,8 @@ Vertex::Vertex (db::DCoord x, db::DCoord y) bool Vertex::is_outside () const { - for (auto e = m_edges.begin (); e != m_edges.end (); ++e) { - if (e->is_outside ()) { + for (auto e = mp_edges.begin (); e != mp_edges.end (); ++e) { + if ((*e)->is_outside ()) { return true; } } @@ -81,8 +81,8 @@ Vertex::triangles () const { std::set seen; std::vector res; - for (auto e = m_edges.begin (); e != m_edges.end (); ++e) { - for (auto t = e->begin_triangles (); t != e->end_triangles (); ++t) { + for (auto e = mp_edges.begin (); e != mp_edges.end (); ++e) { + for (auto t = (*e)->begin_triangles (); t != (*e)->end_triangles (); ++t) { if (seen.insert (t.operator-> ()).second) { res.push_back (t.operator-> ()); } @@ -94,8 +94,8 @@ Vertex::triangles () const bool Vertex::has_edge (const TriangleEdge *edge) const { - for (auto e = m_edges.begin (); e != m_edges.end (); ++e) { - if (e.operator-> () == edge) { + for (auto e = mp_edges.begin (); e != mp_edges.end (); ++e) { + if (*e == edge) { return true; } } @@ -107,11 +107,23 @@ Vertex::to_string (bool with_id) const { std::string res = tl::sprintf ("(%.12g, %.12g)", x (), y()); if (with_id) { - res += tl::sprintf ("[%p]", (void *)this); + res += tl::sprintf ("[%x]", (size_t)this); } return res; } +void +Vertex::remove_edge (db::TriangleEdge *edge) +{ + for (auto e = mp_edges.begin (); e != mp_edges.end (); ++e) { + if (*e == edge) { + mp_edges.erase (e); + return; + } + } + tl_assert (false); +} + int Vertex::in_circle (const DPoint &point, const DPoint ¢er, double radius) { @@ -141,8 +153,7 @@ TriangleEdge::TriangleEdge () TriangleEdge::TriangleEdge (Vertex *v1, Vertex *v2) : mp_v1 (v1), mp_v2 (v2), mp_left (), mp_right (), m_level (0), m_id (0), m_is_segment (false) { - v1->m_edges.push_back (this); - v2->m_edges.push_back (this); + // .. nothing yet .. } void @@ -157,14 +168,33 @@ TriangleEdge::set_right (Triangle *t) mp_right = t; } +void +TriangleEdge::link () +{ + mp_v1->mp_edges.push_back (this); + mp_v2->mp_edges.push_back (this); +} + +void +TriangleEdge::unlink () +{ + if (mp_v1) { + mp_v1->remove_edge (this); + } + if (mp_v2) { + mp_v2->remove_edge (this); + } + mp_v1 = mp_v2 = 0; +} + Triangle * TriangleEdge::other (const Triangle *t) const { - if (t == mp_left.get ()) { - return const_cast (mp_right.get ()); + if (t == mp_left) { + return mp_right; } - if (t == mp_right.get ()) { - return const_cast (mp_left.get ()); + if (t == mp_right) { + return mp_left; } tl_assert (false); return 0; @@ -206,7 +236,7 @@ TriangleEdge::to_string (bool with_id) const { std::string res = std::string ("(") + mp_v1->to_string (with_id) + ", " + mp_v2->to_string (with_id) + ")"; if (with_id) { - res += tl::sprintf ("[%p]", (void *)this); + res += tl::sprintf ("[%x]", (size_t)this); } return res; } @@ -341,6 +371,11 @@ Triangle::Triangle (TriangleEdge *e1, TriangleEdge *e2, TriangleEdge *e3) } } +Triangle::~Triangle () +{ + unlink (); +} + void Triangle::unlink () { @@ -376,7 +411,6 @@ Triangle::to_string (bool with_id) const Vertex * Triangle::vertex (int n) const { - tl_assert (mp_e1 && mp_e2 && mp_e3); n = (n + 3) % 3; if (n == 0) { return mp_v1; @@ -392,11 +426,11 @@ Triangle::edge (int n) const { n = (n + 3) % 3; if (n == 0) { - return const_cast (mp_e1.get ()); + return mp_e1; } else if (n == 1) { - return const_cast (mp_e2.get ()); + return mp_e2; } else { - return const_cast (mp_e3.get ()); + return mp_e3; } } diff --git a/src/db/db/dbTriangle.h b/src/db/db/dbTriangle.h index ae050b19a..4d5bc4931 100644 --- a/src/db/db/dbTriangle.h +++ b/src/db/db/dbTriangle.h @@ -48,7 +48,7 @@ class DB_PUBLIC Vertex : public db::DPoint { public: - typedef tl::weak_collection edges_type; + typedef std::vector edges_type; typedef edges_type::const_iterator edges_iterator; Vertex (); @@ -61,9 +61,9 @@ public: bool is_outside () const; std::vector triangles () const; - edges_iterator begin_edges () const { return m_edges.begin (); } - edges_iterator end_edges () const { return m_edges.end (); } - size_t num_edges () const { return m_edges.size (); } + edges_iterator begin_edges () const { return mp_edges.begin (); } + edges_iterator end_edges () const { return mp_edges.end (); } + size_t num_edges () const { return mp_edges.size (); } bool has_edge (const TriangleEdge *edge) const; @@ -88,8 +88,9 @@ public: private: friend class TriangleEdge; + void remove_edge (db::TriangleEdge *edge); - edges_type m_edges; + edges_type mp_edges; size_t m_level; }; @@ -97,7 +98,6 @@ private: * @brief A class representing an edge in the Delaunay triangulation graph */ class DB_PUBLIC TriangleEdge - : public tl::Object { public: class TriangleIterator @@ -153,7 +153,6 @@ public: }; TriangleEdge (); - TriangleEdge (Vertex *v1, Vertex *v2); Vertex *v1 () const { return mp_v1; } Vertex *v2 () const { return mp_v2; } @@ -162,14 +161,14 @@ public: { std::swap (mp_v1, mp_v2); - Triangle *l = mp_left.get (); - Triangle *r = mp_right.get (); + Triangle *l = mp_left; + Triangle *r = mp_right; mp_left = r; mp_right = l; } - Triangle *left () const { return const_cast (mp_left.get ()); } - Triangle *right () const { return const_cast (mp_right.get ()); } + Triangle *left () const { return mp_left; } + Triangle *right () const { return mp_right; } TriangleIterator begin_triangles () const { @@ -385,19 +384,23 @@ public: */ bool has_triangle (const Triangle *t) const; + // --- exposed for test purposes only --- + + TriangleEdge (Vertex *v1, Vertex *v2); + + void unlink (); + void link (); + private: friend class Triangle; + friend class Triangles; Vertex *mp_v1, *mp_v2; - tl::weak_ptr mp_left, mp_right; + Triangle *mp_left, *mp_right; size_t m_level; size_t m_id; bool m_is_segment; - // no copying - // @@@ TriangleEdge &operator= (const TriangleEdge &); - // @@@ TriangleEdge (const TriangleEdge &); - void set_left (Triangle *t); void set_right (Triangle *t); }; @@ -425,6 +428,8 @@ public: Triangle (); Triangle (TriangleEdge *e1, TriangleEdge *e2, TriangleEdge *e3); + ~Triangle (); + void unlink (); void set_id (size_t id) { m_id = id; } @@ -499,7 +504,7 @@ public: */ bool has_edge (const db::TriangleEdge *e) const { - return mp_e1.get () == e || mp_e2.get () == e || mp_e3.get () == e; + return mp_e1 == e || mp_e2 == e || mp_e3 == e; } /** @@ -524,7 +529,7 @@ public: private: bool m_is_outside; - tl::weak_ptr mp_e1, mp_e2, mp_e3; + TriangleEdge *mp_e1, *mp_e2, *mp_e3; db::Vertex *mp_v1, *mp_v2, *mp_v3; size_t m_id; diff --git a/src/db/db/dbTriangles.cc b/src/db/db/dbTriangles.cc index 419600709..6a6c9c373 100644 --- a/src/db/db/dbTriangles.cc +++ b/src/db/db/dbTriangles.cc @@ -44,8 +44,6 @@ Triangles::~Triangles () while (! mp_triangles.empty ()) { remove (mp_triangles.front ()); } - - tl_assert (mp_edges.empty ()); } db::Vertex * @@ -65,10 +63,10 @@ Triangles::create_vertex (const db::DPoint &pt) db::TriangleEdge * Triangles::create_edge (db::Vertex *v1, db::Vertex *v2) { - db::TriangleEdge *res = new db::TriangleEdge (v1, v2); - res->set_id (++m_id); - mp_edges.push_back (res); - return res; + m_edges_heap.push_back (db::TriangleEdge (v1, v2)); + m_edges_heap.back ().link (); + m_edges_heap.back ().set_id (++m_id); + return &m_edges_heap.back (); } db::Triangle * @@ -93,7 +91,7 @@ Triangles::remove (db::Triangle *tri) // clean up edges we do no longer need for (int i = 0; i < 3; ++i) { if (edges [i] && edges [i]->left () == 0 && edges [i]->right () == 0) { - delete edges [i]; + edges [i]->unlink (); } } } @@ -172,7 +170,11 @@ Triangles::check (bool check_delaunay) const } } - for (auto e = mp_edges.begin (); e != mp_edges.end (); ++e) { + for (auto e = m_edges_heap.begin (); e != m_edges_heap.end (); ++e) { + + if (!e->left () && !e->right ()) { + continue; + } if (e->left () && e->right ()) { if (e->left ()->is_outside () != e->right ()->is_outside () && ! e->is_segment ()) { @@ -181,11 +183,6 @@ Triangles::check (bool check_delaunay) const } } - if (!e->left () && !e->right ()) { - tl::error << "(check error) found orphan edge " << e->to_string (true); - res = false; - } - for (auto t = e->begin_triangles (); t != e->end_triangles (); ++t) { if (! t->has_edge (e.operator-> ())) { tl::error << "(check error) edge " << e->to_string (true) << " not found in adjacent triangle " << t->to_string (true); @@ -223,7 +220,7 @@ Triangles::check (bool check_delaunay) const for (auto v = m_vertex_heap.begin (); v != m_vertex_heap.end (); ++v) { unsigned int num_outside_edges = 0; for (auto e = v->begin_edges (); e != v->end_edges (); ++e) { - if (e->is_outside ()) { + if ((*e)->is_outside ()) { ++num_outside_edges; } } @@ -231,8 +228,8 @@ Triangles::check (bool check_delaunay) const tl::error << "(check error) vertex " << v->to_string (true) << " has " << num_outside_edges << " outside edges (can only be 2)"; res = false; for (auto e = v->begin_edges (); e != v->end_edges (); ++e) { - if (e->is_outside ()) { - tl::error << " Outside edge is " << e->to_string (true); + if ((*e)->is_outside ()) { + tl::error << " Outside edge is " << (*e)->to_string (true); } } } @@ -264,8 +261,8 @@ Triangles::to_layout () const top.shapes (t->is_outside () ? l2 : l1).insert (dbu_trans * poly); } - for (auto e = mp_edges.begin (); e != mp_edges.end (); ++e) { - if (e->is_segment ()) { + for (auto e = m_edges_heap.begin (); e != m_edges_heap.end (); ++e) { + if ((e->left () || e->right ()) && e->is_segment ()) { top.shapes (l10).insert (dbu_trans * e->edge ()); } } @@ -301,7 +298,7 @@ Triangles::find_points_around (db::Vertex *vertex, double radius) next_vertexes.clear (); for (auto v = new_vertexes.begin (); v != new_vertexes.end (); ++v) { for (auto e = (*v)->begin_edges (); e != (*v)->end_edges (); ++e) { - db::Vertex *ov = e->other (*v); + db::Vertex *ov = (*e)->other (*v); if (ov->in_circle (*vertex, radius) == 1 && seen.insert (ov).second) { next_vertexes.push_back (ov); res.push_back (ov); @@ -386,7 +383,7 @@ Triangles::find_closest_edge (const db::DPoint &p, db::Vertex *vstart, bool insi { if (!vstart) { - if (! mp_edges.empty ()) { + if (! mp_triangles.empty ()) { unsigned int ls = 0; size_t n = m_vertex_heap.size (); @@ -395,13 +392,14 @@ Triangles::find_closest_edge (const db::DPoint &p, db::Vertex *vstart, bool insi // A sample heuristics that takes a sqrt(N) sample from the // vertexes to find a good starting point - vstart = mp_edges.front ()->v1 (); + vstart = mp_triangles.front ()->vertex (0); double dmin = vstart->distance (p); while (ls * ls < m) { m /= 2; for (size_t i = m / 2; i < n; i += m) { ++ls; + // NOTE: this assumes the heap is not too loaded with orphan vertexes db::Vertex *v = (m_vertex_heap.begin () + i).operator-> (); if (v->begin_edges () != v->end_edges ()) { double d = v->distance (p); @@ -435,20 +433,20 @@ Triangles::find_closest_edge (const db::DPoint &p, db::Vertex *vstart, bool insi if (inside_only) { // NOTE: in inside mode we stay on the line of sight as we don't // want to walk around outside pockets. - if (! e->is_segment () && e->is_for_outside_triangles ()) { + if (! (*e)->is_segment () && (*e)->is_for_outside_triangles ()) { continue; } - if (! e->crosses_including (line)) { + if (! (*e)->crosses_including (line)) { continue; } } - double ds = e->distance (p); + double ds = (*e)->distance (p); if (d < 0.0 || ds < d) { d = ds; - edge = const_cast (e.operator-> ()); + edge = *e; vnext = edge->other (v); } else if (fabs (ds - d) < std::max (1.0, fabs (ds) + fabs (d)) * db::epsilon) { @@ -456,15 +454,15 @@ Triangles::find_closest_edge (const db::DPoint &p, db::Vertex *vstart, bool insi // this differentiation selects the edge which bends further towards // the target point if both edges share a common point and that // is the one the determines the distance. - db::Vertex *cv = edge->common_vertex (e.operator-> ()); + db::Vertex *cv = edge->common_vertex (*e); if (cv) { db::DVector edge_d = *edge->other (cv) - *cv; - db::DVector e_d = *e->other(cv) - *cv; + db::DVector e_d = *(*e)->other(cv) - *cv; db::DVector r = p - *cv; double edge_sp = db::sprod (r, edge_d) / edge_d.length (); double s_sp = db::sprod (r, e_d) / e_d.length (); if (s_sp > edge_sp) { - edge = const_cast (e.operator-> ()); + edge = *e; vnext = edge->other (v); } } @@ -550,10 +548,10 @@ Triangles::add_more_triangles (std::vector &new_triangles, db::TriangleEdge *next_edge = 0; for (auto e = from_vertex->begin_edges (); e != from_vertex->end_edges (); ++e) { - if (! e->has_vertex (to_vertex) && e->is_outside ()) { + if (! (*e)->has_vertex (to_vertex) && (*e)->is_outside ()) { // TODO: remove and break tl_assert (next_edge == 0); - next_edge = const_cast (e.operator-> ()); + next_edge = *e; } } @@ -730,8 +728,8 @@ Triangles::remove_inside_vertex (db::Vertex *vertex, std::listbegin_edges (); e != vertex->end_edges () && to_flip == 0; ++e) { - if (e->can_flip ()) { - to_flip = const_cast (e.operator-> ()); + if ((*e)->can_flip ()) { + to_flip = *e; } } if (! to_flip) { @@ -756,8 +754,8 @@ Triangles::remove_inside_vertex (db::Vertex *vertex, std::listbegin_edges (); e != vertex->end_edges () && !jseg; ++e) { - if (e->can_join_via (vertex)) { - jseg = const_cast (e.operator-> ()); + if ((*e)->can_join_via (vertex)) { + jseg = *e; } } tl_assert (jseg != 0); @@ -769,8 +767,8 @@ Triangles::remove_inside_vertex (db::Vertex *vertex, std::listbegin_edges (); e != vertex->end_edges () && !jseg_opp; ++e) { - if (!e->has_triangle (jseg->left ()) && !e->has_triangle (jseg->right ())) { - jseg_opp = const_cast (e.operator-> ()); + if (!(*e)->has_triangle (jseg->left ()) && !(*e)->has_triangle (jseg->right ())) { + jseg_opp = *e; } } @@ -1084,7 +1082,7 @@ Triangles::search_edges_crossing (Vertex *from, Vertex *to) std::vector result; for (auto e = v->begin_edges (); e != v->end_edges () && ! next_edge; ++e) { - for (auto t = e->begin_triangles (); t != e->end_triangles (); ++t) { + for (auto t = (*e)->begin_triangles (); t != (*e)->end_triangles (); ++t) { db::TriangleEdge *os = t->opposite (v); if (os->has_vertex (vv)) { return result; @@ -1152,8 +1150,8 @@ Triangles::find_edge_for_points (const db::DPoint &p1, const db::DPoint &p2) return 0; } for (auto e = v->begin_edges (); e != v->end_edges (); ++e) { - if (e->other (v)->equal (p2)) { - return const_cast (e.operator-> ()); + if ((*e)->other (v)->equal (p2)) { + return *e; } } return 0; @@ -1240,9 +1238,9 @@ Triangles::join_edges (std::vector &edges) std::vector join_edges; for (auto e = cp->begin_edges (); e != cp->end_edges (); ++e) { - if (e.operator-> () != s1 && e.operator-> () != s2) { - if (e->can_join_via (cp)) { - join_edges.push_back (const_cast (e.operator-> ())); + if (*e != s1 && *e != s2) { + if ((*e)->can_join_via (cp)) { + join_edges.push_back (*e); } else { join_edges.clear (); break; @@ -1380,7 +1378,7 @@ Triangles::remove_outside_triangles () void Triangles::clear () { - mp_edges.clear (); + m_edges_heap.clear (); mp_triangles.clear (); m_vertex_heap.clear (); m_is_constrained = false; @@ -1549,7 +1547,7 @@ Triangles::triangulate (const db::Region ®ion, const TriangulateParameters &p for (auto v = vertexes_in_diametral_circle.begin (); v != vertexes_in_diametral_circle.end (); ++v) { bool has_segment = false; for (auto e = (*v)->begin_edges (); e != (*v)->end_edges () && ! has_segment; ++e) { - has_segment = e->is_segment (); + has_segment = (*e)->is_segment (); } if (! has_segment) { to_delete.push_back (*v); diff --git a/src/db/db/dbTriangles.h b/src/db/db/dbTriangles.h index ec0c0b269..bb085fbd8 100644 --- a/src/db/db/dbTriangles.h +++ b/src/db/db/dbTriangles.h @@ -253,7 +253,7 @@ public: private: tl::shared_collection mp_triangles; - tl::weak_collection mp_edges; + tl::stable_vector m_edges_heap; tl::stable_vector m_vertex_heap; bool m_is_constrained; size_t m_level; diff --git a/src/db/unit_tests/dbTriangleTests.cc b/src/db/unit_tests/dbTriangleTests.cc index 0b326e9b7..263d9ca07 100644 --- a/src/db/unit_tests/dbTriangleTests.cc +++ b/src/db/unit_tests/dbTriangleTests.cc @@ -52,7 +52,7 @@ static std::string edges_from_vertex (const db::Vertex &v) if (! res.empty ()) { res += ", "; } - res += e->to_string (); + res += (*e)->to_string (); } return res; } @@ -77,20 +77,24 @@ TEST(Vertex_edge_registration) db::Vertex v3 (2, 1); std::unique_ptr e1 (new db::TriangleEdge (&v1, &v2)); + e1->link (); EXPECT_EQ (edges_from_vertex (v1), "((0, 0), (1, 2))"); EXPECT_EQ (edges_from_vertex (v2), "((0, 0), (1, 2))"); EXPECT_EQ (edges_from_vertex (v3), ""); std::unique_ptr e2 (new db::TriangleEdge (&v2, &v3)); + e2->link (); EXPECT_EQ (edges_from_vertex (v1), "((0, 0), (1, 2))"); EXPECT_EQ (edges_from_vertex (v2), "((0, 0), (1, 2)), ((1, 2), (2, 1))"); EXPECT_EQ (edges_from_vertex (v3), "((1, 2), (2, 1))"); + e2->unlink (); e2.reset (0); EXPECT_EQ (edges_from_vertex (v1), "((0, 0), (1, 2))"); EXPECT_EQ (edges_from_vertex (v2), "((0, 0), (1, 2))"); EXPECT_EQ (edges_from_vertex (v3), ""); + e1->unlink (); e1.reset (0); EXPECT_EQ (edges_from_vertex (v1), ""); EXPECT_EQ (edges_from_vertex (v2), ""); @@ -106,8 +110,11 @@ TEST(Vertex_triangles) EXPECT_EQ (triangles_from_vertex (v1), ""); std::unique_ptr e1 (new db::TriangleEdge (&v1, &v2)); + e1->link (); std::unique_ptr e2 (new db::TriangleEdge (&v2, &v3)); + e2->link (); std::unique_ptr e3 (new db::TriangleEdge (&v3, &v1)); + e3->link (); std::unique_ptr tri (new db::Triangle (e1.get (), e2.get (), e3.get ())); EXPECT_EQ (triangles_from_vertex (v1), "((0, 0), (1, 2), (2, 1))"); @@ -115,12 +122,20 @@ TEST(Vertex_triangles) EXPECT_EQ (triangles_from_vertex (v3), "((0, 0), (1, 2), (2, 1))"); std::unique_ptr e4 (new db::TriangleEdge (&v1, &v4)); + e4->link (); std::unique_ptr e5 (new db::TriangleEdge (&v2, &v4)); + e5->link (); std::unique_ptr tri2 (new db::Triangle (e1.get (), e4.get (), e5.get ())); EXPECT_EQ (triangles_from_vertex (v1), "((0, 0), (-1, 2), (1, 2)), ((0, 0), (1, 2), (2, 1))"); EXPECT_EQ (triangles_from_vertex (v2), "((0, 0), (-1, 2), (1, 2)), ((0, 0), (1, 2), (2, 1))"); EXPECT_EQ (triangles_from_vertex (v3), "((0, 0), (1, 2), (2, 1))"); EXPECT_EQ (triangles_from_vertex (v4), "((0, 0), (-1, 2), (1, 2))"); + + tri->unlink (); + EXPECT_EQ (triangles_from_vertex (v1), "((0, 0), (-1, 2), (1, 2))"); + + tri2->unlink (); + EXPECT_EQ (triangles_from_vertex (v1), ""); } // Tests for Triangle class diff --git a/src/db/unit_tests/dbTrianglesTests.cc b/src/db/unit_tests/dbTrianglesTests.cc index 412a12ce5..8c404f86f 100644 --- a/src/db/unit_tests/dbTrianglesTests.cc +++ b/src/db/unit_tests/dbTrianglesTests.cc @@ -643,8 +643,6 @@ TEST(create_constrained_delaunay) TEST(triangulate) { - tl::equals(1.0, 2.0); - return; // @@@ db::Region r; r.insert (db::Box (0, 0, 10000, 10000)); @@ -669,7 +667,6 @@ TEST(triangulate) EXPECT_GT (tri.num_triangles (), size_t (100)); EXPECT_LT (tri.num_triangles (), size_t (150)); - tl::info << tri.num_triangles (); param.min_b = 1.0; param.max_area = 0.1;