From 576eacd0bf725eee32aefb15a3129ebc213238a3 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 13 Aug 2023 21:14:58 +0200 Subject: [PATCH] WIP --- src/db/db/dbTriangle.cc | 11 ++-- src/db/db/dbTriangle.h | 33 +++++++++++ src/db/db/dbTriangles.cc | 84 ++++++++++++--------------- src/db/db/dbTriangles.h | 1 + src/db/unit_tests/dbTrianglesTests.cc | 60 ++++++++++++++++++- 5 files changed, 134 insertions(+), 55 deletions(-) diff --git a/src/db/db/dbTriangle.cc b/src/db/db/dbTriangle.cc index 124510cfc..4833f7064 100644 --- a/src/db/db/dbTriangle.cc +++ b/src/db/db/dbTriangle.cc @@ -133,13 +133,13 @@ Vertex::in_circle (const DPoint &point, const DPoint ¢er, double radius) // TriangleEdge implementation TriangleEdge::TriangleEdge () - : mp_v1 (0), mp_v2 (0), mp_left (), mp_right (), m_level (0), m_is_segment (false) + : mp_v1 (0), mp_v2 (0), mp_left (), mp_right (), m_level (0), m_id (0), m_is_segment (false) { // .. nothing yet .. } TriangleEdge::TriangleEdge (Vertex *v1, Vertex *v2) - : mp_v1 (v1), mp_v2 (v2), mp_left (), mp_right (), m_level (0), m_is_segment (false) + : 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); @@ -148,14 +148,12 @@ TriangleEdge::TriangleEdge (Vertex *v1, Vertex *v2) void TriangleEdge::set_left (Triangle *t) { - tl_assert (t == 0 || left () == 0); mp_left = t; } void TriangleEdge::set_right (Triangle *t) { - tl_assert (t == 0 || right () == 0); mp_right = t; } @@ -305,13 +303,13 @@ TriangleEdge::has_triangle (const Triangle *t) const // Triangle implementation Triangle::Triangle () - : m_is_outside (false), mp_v1 (0), mp_v2 (0), mp_v3 (0) + : m_is_outside (false), mp_v1 (0), mp_v2 (0), mp_v3 (0), m_id (0) { // .. nothing yet .. } Triangle::Triangle (TriangleEdge *e1, TriangleEdge *e2, TriangleEdge *e3) - : m_is_outside (false), mp_e1 (e1), mp_e2 (e2), mp_e3 (e3) + : m_is_outside (false), mp_e1 (e1), mp_e2 (e2), mp_e3 (e3), m_id (0) { mp_v1 = e1->v1 (); mp_v2 = e1->other (mp_v1); @@ -348,6 +346,7 @@ Triangle::Triangle (TriangleEdge *e1, TriangleEdge *e2, TriangleEdge *e3) void Triangle::unlink () { + // @@@ Is this really needed??? for (int i = 0; i != 3; ++i) { db::TriangleEdge *e = edge (i); if (e->left () == this) { diff --git a/src/db/db/dbTriangle.h b/src/db/db/dbTriangle.h index 3459ad155..2d55e5e74 100644 --- a/src/db/db/dbTriangle.h +++ b/src/db/db/dbTriangle.h @@ -184,6 +184,9 @@ public: void set_level (size_t l) { m_level = l; } size_t level () const { return m_level; } + void set_id (size_t id) { m_id = id; } + size_t id () const { return m_id; } + void set_is_segment (bool is_seg) { m_is_segment = is_seg; } bool is_segment () const { return m_is_segment; } @@ -388,6 +391,7 @@ private: Vertex *mp_v1, *mp_v2; tl::weak_ptr mp_left, mp_right; size_t m_level; + size_t m_id; bool m_is_segment; // no copying @@ -398,6 +402,19 @@ private: void set_right (Triangle *t); }; +/** + * @brief A compare function that compares triangles by ID + * + * The ID acts as a more predicable unique ID for the object in sets and maps. + */ +struct TriangleEdgeLessFunc +{ + bool operator () (TriangleEdge *a, TriangleEdge *b) const + { + return a->id () < b->id (); + } +}; + /** * @brief A class representing a triangle */ @@ -410,6 +427,9 @@ public: void unlink (); + void set_id (size_t id) { m_id = id; } + size_t id () const { return m_id; } + bool is_outside () const { return m_is_outside; } void set_outside (bool o) { m_is_outside = o; } @@ -476,12 +496,25 @@ private: bool m_is_outside; tl::weak_ptr mp_e1, mp_e2, mp_e3; db::Vertex *mp_v1, *mp_v2, *mp_v3; + size_t m_id; // no copying Triangle &operator= (const Triangle &); Triangle (const Triangle &); }; +/** + * @brief A compare function that compares triangles by ID + * + * The ID acts as a more predicable unique ID for the object in sets and maps. + */ +struct TriangleLessFunc +{ + bool operator () (Triangle *a, Triangle *b) const + { + return a->id () < b->id (); + } +}; } diff --git a/src/db/db/dbTriangles.cc b/src/db/db/dbTriangles.cc index d58f2493b..be97c67ee 100644 --- a/src/db/db/dbTriangles.cc +++ b/src/db/db/dbTriangles.cc @@ -65,6 +65,7 @@ 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; } @@ -73,6 +74,7 @@ db::Triangle * Triangles::create_triangle (TriangleEdge *e1, TriangleEdge *e2, TriangleEdge *e3) { db::Triangle *res = new db::Triangle (e1, e2, e3); + res->set_id (++m_id); mp_triangles.push_back (res); return res; } @@ -180,6 +182,11 @@ 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); @@ -259,7 +266,9 @@ Triangles::to_layout () const } for (auto e = mp_edges.begin (); e != mp_edges.end (); ++e) { - top.shapes (l10).insert (dbu_trans * e->edge ()); + if (e->is_segment ()) { + top.shapes (l10).insert (dbu_trans * e->edge ()); + } } return layout; @@ -677,8 +686,7 @@ Triangles::remove_outside_vertex (db::Vertex *vertex, std::vector *new_triangles_out) { - std::vector triangles_to_fix; - std::set triangles_to_fix_set; + std::set triangles_to_fix; bool make_new_triangle = true; @@ -695,18 +703,16 @@ Triangles::remove_inside_vertex (db::Vertex *vertex, std::vector } // NOTE: in the "can_join" case zero-area triangles are created which we will sort out later - triangles_to_fix_set.erase (to_flip->left ()); - triangles_to_fix_set.erase (to_flip->right ()); + triangles_to_fix.erase (to_flip->left ()); + triangles_to_fix.erase (to_flip->right ()); auto pp = flip (to_flip); - triangles_to_fix.push_back (pp.first.first); - triangles_to_fix_set.insert (pp.first.first); - triangles_to_fix.push_back (pp.first.second); - triangles_to_fix_set.insert (pp.first.second); + triangles_to_fix.insert (pp.first.first); + triangles_to_fix.insert (pp.first.second); } - while (vertex->num_edges () > 3) { + if (vertex->num_edges () > 3) { tl_assert (vertex->num_edges () == 4); @@ -739,10 +745,8 @@ Triangles::remove_inside_vertex (db::Vertex *vertex, std::vector db::Triangle *t1 = create_triangle (s1, s2, new_edge); db::Triangle *t2 = create_triangle (s1opp, s2opp, new_edge); - triangles_to_fix.push_back (t1); - triangles_to_fix_set.insert (t1); - triangles_to_fix.push_back (t2); - triangles_to_fix_set.insert (t2); + triangles_to_fix.insert (t1); + triangles_to_fix.insert (t2); make_new_triangle = false; @@ -755,33 +759,28 @@ Triangles::remove_inside_vertex (db::Vertex *vertex, std::vector outer_edges.push_back ((*t)->opposite (vertex)); } - for (auto t = to_remove.begin (); t != to_remove.end (); ++t) { - triangles_to_fix_set.erase (*t); - remove (*t); - } - if (make_new_triangle) { tl_assert (outer_edges.size () == size_t (3)); db::Triangle *nt = create_triangle (outer_edges[0], outer_edges[1], outer_edges[2]); - triangles_to_fix.push_back (nt); - triangles_to_fix_set.insert (nt); + triangles_to_fix.insert (nt); } - std::vector::iterator wp = triangles_to_fix.begin (); - for (auto t = triangles_to_fix.begin (); t != triangles_to_fix.end (); ++t) { - if (triangles_to_fix_set.find (*t) != triangles_to_fix_set.end ()) { - *wp++ = *t; - if (new_triangles_out) { - new_triangles_out->push_back (*t); - } + for (auto t = to_remove.begin (); t != to_remove.end (); ++t) { + triangles_to_fix.erase (*t); + remove (*t); + } + + if (new_triangles_out) { + for (auto t = triangles_to_fix.begin (); t != triangles_to_fix.end (); ++t) { + new_triangles_out->push_back (*t); } } - triangles_to_fix.erase (wp, triangles_to_fix.end ()); - fix_triangles (triangles_to_fix, std::vector (), new_triangles_out); + std::vector to_fix_a (triangles_to_fix.begin (), triangles_to_fix.end ()); + fix_triangles (to_fix_a, std::vector (), new_triangles_out); } int @@ -794,13 +793,13 @@ Triangles::fix_triangles (const std::vector &tris, const std::ve (*e)->set_level (m_level); } - std::vector queue, todo; + std::set queue, todo; for (auto t = tris.begin (); t != tris.end (); ++t) { for (int i = 0; i < 3; ++i) { db::TriangleEdge *e = (*t)->edge (i); if (e->level () < m_level && ! e->is_segment ()) { - queue.push_back (e); + queue.insert (e); } } } @@ -809,7 +808,6 @@ Triangles::fix_triangles (const std::vector &tris, const std::ve todo.clear (); todo.swap (queue); - std::set queued; // NOTE: we cannot be sure that already treated edges will not become // illegal by neighbor edges flipping .. @@ -820,7 +818,7 @@ Triangles::fix_triangles (const std::vector &tris, const std::ve if (is_illegal_edge (*e)) { - queued.erase (*e); + queue.erase (*e); auto pp = flip (*e); auto t1 = pp.first.first; @@ -837,17 +835,15 @@ Triangles::fix_triangles (const std::vector &tris, const std::ve for (int i = 0; i < 3; ++i) { db::TriangleEdge *s1 = t1->edge (i); - if (s1->level () < m_level && ! s1->is_segment () && queued.find (s1) == queued.end ()) { - queue.push_back (s1); - queued.insert (s1); + if (s1->level () < m_level && ! s1->is_segment ()) { + queue.insert (s1); } } for (int i = 0; i < 3; ++i) { db::TriangleEdge *s2 = t2->edge (i); - if (s2->level () < m_level && ! s2->is_segment () && queued.find (s2) == queued.end ()) { - queue.push_back (s2); - queued.insert (s2); + if (s2->level () < m_level && ! s2->is_segment ()) { + queue.insert (s2); } } @@ -855,14 +851,6 @@ Triangles::fix_triangles (const std::vector &tris, const std::ve } - std::vector::iterator wp = queue.begin (); - for (auto e = queue.begin (); e != queue.end (); ++e) { - if (queued.find (*e) != queued.end ()) { - *wp++ = *e; - } - } - queue.erase (wp, queue.end ()); - } return flips; diff --git a/src/db/db/dbTriangles.h b/src/db/db/dbTriangles.h index b27d08bc1..20a86d7ef 100644 --- a/src/db/db/dbTriangles.h +++ b/src/db/db/dbTriangles.h @@ -156,6 +156,7 @@ private: std::list m_vertex_heap; bool m_is_constrained; size_t m_level; + size_t m_id; db::Vertex *create_vertex (double x, double y); db::Vertex *create_vertex (const db::DPoint &pt); diff --git a/src/db/unit_tests/dbTrianglesTests.cc b/src/db/unit_tests/dbTrianglesTests.cc index d3aa07cb9..614623b20 100644 --- a/src/db/unit_tests/dbTrianglesTests.cc +++ b/src/db/unit_tests/dbTrianglesTests.cc @@ -24,6 +24,8 @@ #include "dbTriangles.h" #include "tlUnitTest.h" +#include +#include #include #include @@ -187,7 +189,7 @@ TEST(Triangle_test_heavy_insert) } // not strictly true, but very likely with at least 10 vertexes: - EXPECT_EQ (tris.num_triangles () >= 1, true); + EXPECT_EQ (tris.num_triangles () > 0, true); EXPECT_EQ (tris.bbox ().to_string (), bbox.to_string ()); bool ok = true; @@ -216,3 +218,59 @@ TEST(Triangle_test_heavy_insert) tl::info << tl::endl << "done."; } + +TEST(Triangle_test_heavy_remove) +{ + tl::info << "Running test_heavy_remove " << tl::noendl; + + for (unsigned int l = 0; l < 100; ++l) { + + srand (l); + tl::info << "." << tl::noendl; + + db::Triangles tris; + double res = 128.0; + + unsigned int n = rand () % 190 + 10; + + for (unsigned int i = 0; i < n; ++i) { + double x = round (flt_rand () * res) * (1.0 / res); + double y = round (flt_rand () * res) * (1.0 / res); + tris.insert_point (x, y); + } + + EXPECT_EQ (tris.check(), true); + + std::set vset; + std::vector vertexes; + for (auto t = tris.begin (); t != tris.end (); ++t) { + for (int i = 0; i < 3; ++i) { + db::Vertex *v = t->vertex (i); + if (vset.insert (v).second) { + vertexes.push_back (v); + } + } + } + + int loop = 0; // @@@ + while (! vertexes.empty ()) { + ++loop; printf("@@@ %d\n", loop); fflush(stdout); + if (loop == 38) { + printf("@@@BANG!\n"); // @@@ + } + + unsigned int n = rand () % (unsigned int) vertexes.size (); + db::Vertex *v = vertexes [n]; + tris.remove (v); + vertexes.erase (vertexes.begin () + n); + + EXPECT_EQ (tris.check (), true); + + } + + EXPECT_EQ (tris.num_triangles (), size_t (0)); + + } + + tl::info << tl::endl << "done."; +}