From b710b32fbe901fdd1cca35e36ee1c1ef6e8b136c Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 12 Aug 2023 21:23:00 +0200 Subject: [PATCH] WIP --- src/db/db/dbTriangles.cc | 285 +++++++++++++++++++++++++++++++++++---- src/db/db/dbTriangles.h | 14 +- 2 files changed, 268 insertions(+), 31 deletions(-) diff --git a/src/db/db/dbTriangles.cc b/src/db/db/dbTriangles.cc index 615a11b12..a47eec737 100644 --- a/src/db/db/dbTriangles.cc +++ b/src/db/db/dbTriangles.cc @@ -315,9 +315,264 @@ Triangles::insert_point (const db::DPoint &point, std::vector *n db::Vertex * Triangles::insert (db::Vertex *vertex, std::vector *new_triangles) { + std::vector tris = find_triangle_for_point (*vertex); - // @@@ + // the new vertex is outside the domain + if (tris.empty ()) { + tl_assert (! m_is_constrained); + insert_new_vertex (vertex, new_triangles); + return vertex; + } + // the new vertex is on the edge between two triangles + std::vector on_edges; + for (int i = 0; i < 3; ++i) { + db::TriangleEdge *e = tris.front ()->edge (i); + if (e->side_of (*vertex) == 0) { + on_edges.push_back (e); + } + } + + if (! on_edges.empty ()) { + if (on_edges.size () == size_t (1)) { + split_triangles_on_edge (tris, vertex, on_edges.front (), new_triangles); + return vertex; + } else { + // the vertex is already present + tl_assert (on_edges.size () == size_t (2)); + return on_edges.front ()->common_vertex (on_edges [1]); + } + } else if (tris.size () == size_t (1)) { + // the new vertex is inside one triangle + split_triangle (tris.front (), vertex, new_triangles); + return vertex; + } + + tl_assert (false); +} + +std::vector +Triangles::find_triangle_for_point (const db::DPoint &point) +{ + db::TriangleEdge *edge = find_closest_edge (point); + + std::vector res; + if (edge) { + for (auto t = edge->begin_triangles (); t != edge->end_triangles (); ++t) { + if (t->contains (point) >= 0) { + res.push_back (t.operator-> ()); + } + } + } + return res; +} + +db::TriangleEdge * +Triangles::find_closest_edge (const db::DPoint &p, db::Vertex *vstart, bool inside_only) +{ + if (!vstart) { + if (! mp_triangles.empty ()) { + vstart = mp_triangles.front ()->vertex (0); + } else { + return 0; + } + } + + db::DEdge line (*vstart, p); + + double d = -1.0; + db::TriangleEdge *edge = 0; + db::Vertex *v = vstart; + + while (v) { + + db::Vertex *vnext = 0; + + for (auto e = v->begin_edges (); e != v->end_edges (); ++e) { + + 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 ()) { + continue; + } + if (! e->crosses_including (line)) { + continue; + } + } + + double ds = e->distance (p); + + if (d < 0.0 || ds < d) { + + d = ds; + edge = const_cast (e.operator-> ()); + vnext = edge->other (v); + + } else if (fabs (ds - d) < std::max (1.0, fabs (ds) + fabs (d)) * db::epsilon) { + + // 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-> ()); + if (cv) { + db::DVector edge_d = *edge->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-> ()); + vnext = edge->other (v); + } + } + + } + + } + + v = vnext; + + } + + return edge; +} + +void +Triangles::insert_new_vertex (db::Vertex *vertex, std::vector *new_triangles_out) +{ +#if 0 + if len(self.vertexes) <= 3: + if len(self.vertexes) == 3: + # form the first triangle + s1 = TriangleEdge(self.vertexes[0], self.vertexes[1]) + s2 = TriangleEdge(self.vertexes[1], self.vertexes[2]) + s3 = TriangleEdge(self.vertexes[2], self.vertexes[0]) + # avoid degenerate Triangles to happen here @@@ + if vprod_sign(s1.d(), s2.d()) == 0: + self.vertexes = [] # reject some points? + else: + t = Triangle(s1, s2, s3) + if new_triangles_out is not None: + new_triangles_out.append(t) + self.triangles.append(t) + return 0 + + new_triangles = [] + + # Find closest edge + closest_edge = self.find_closest_edge(vertex) + assert(closest_edge is not None) + + s1 = TriangleEdge(vertex, closest_edge.p1) + s2 = TriangleEdge(vertex, closest_edge.p2) + + t = Triangle(s1, closest_edge, s2) + self.triangles.append(t) + new_triangles.append(t) + + self._add_more_triangles(new_triangles, closest_edge, closest_edge.p1, vertex, s1) + self._add_more_triangles(new_triangles, closest_edge, closest_edge.p2, vertex, s2) + + if new_triangles_out is not None: + new_triangles_out += new_triangles + + return self._fix_triangles(new_triangles, [], new_triangles_out) +#endif +} + +void +Triangles::add_more_triangles (const std::vector &new_triangles, + db::TriangleEdge *incoming_edge, + db::Vertex *from_vertex, db::Vertex *to_vertex, + db::TriangleEdge *conn_edge) +{ +#if 0 + while True: + + next_edge = None + for s in from_vertex.edges: + if not s.has_vertex(to_vertex) and s.is_outside(): + # TODO: remove and break + assert(next_edge is None) + next_edge = s + + assert (next_edge is not None) + next_vertex = next_edge.other_vertex(from_vertex) + + d_from_to = sub(to_vertex, from_vertex) + incoming_vertex = incoming_edge.other_vertex(from_vertex) + if vprod_sign(sub(from_vertex, incoming_vertex), d_from_to) * vprod_sign(sub(from_vertex, next_vertex), d_from_to) >= 0: + return + + next_conn_edge = TriangleEdge(next_vertex, to_vertex) + t = Triangle(next_conn_edge, next_edge, conn_edge) + self.triangles.append(t) + new_triangles.append(t) + + incoming_edge = next_edge + conn_edge = next_conn_edge + from_vertex = next_vertex +#endif +} + +void +Triangles::split_triangle (db::Triangle *t, db::Vertex *vertex, std::vector *new_triangles_out) +{ +#if 0 + # TODO: this is not quite efficient + self.triangles.remove(t) + t.unlink() + + new_edges = {} + for v in t.vertexes: + new_edges[v] = TriangleEdge(v, vertex) + + new_triangles = [] + for s in t.edges(): + new_triangle = Triangle(s, new_edges[s.p1], new_edges[s.p2]) + if new_triangles_out is not None: + new_triangles_out.append(new_triangle) + new_triangle.is_outside = t.is_outside + new_triangles.append(new_triangle) + self.triangles.append(new_triangle) + + return self._fix_triangles(new_triangles, new_edges.values(), new_triangles_out) +#endif +} + +void +Triangles::split_triangles_on_edge (const std::vector &tris, db::Vertex *vertex, db::TriangleEdge *split_edge, std::vector *new_triangles_out) +{ +#if 0 + split_edge.unlink() + + s1 = TriangleEdge(split_edge.p1, vertex) + s2 = TriangleEdge(split_edge.p2, vertex) + s1.is_segment = split_edge.is_segment + s2.is_segment = split_edge.is_segment + + new_triangles = [] + + for t in tris: + + self.triangles.remove(t) + + ext_vertex = t.ext_vertex(split_edge) + new_edge = TriangleEdge(ext_vertex, vertex) + + for s in t.edges(): + if s.has_vertex(ext_vertex): + partial = s1 if s.has_vertex(split_edge.p1) else s2 + new_triangle = Triangle(new_edge, partial, s) + if new_triangles_out is not None: + new_triangles_out.append(new_triangle) + new_triangle.is_outside = t.is_outside + new_triangles.append(new_triangle) + self.triangles.append(new_triangle) + + return self._fix_triangles(new_triangles, [s1, s2], new_triangles_out) +#endif } std::vector @@ -766,34 +1021,6 @@ class Triangles(object): def insert(self, vertex, new_triangles: [Vertex] = None): - self.flips = 0 - - tris = self.find_triangle_for_vertex(vertex) - if len(tris) == 0: - assert(not self.is_constrained) - self.vertexes.append(vertex) - self.flips += self._insert_new_vertex(vertex, new_triangles) - return vertex - - # the new vertex is on the edge between two triangles - on_edges = [s for s in tris[0].edges() if s.side_of(vertex) == 0] - - if len(on_edges) > 0: - if len(on_edges) == 1: - self.vertexes.append(vertex) - self.flips += self._split_triangles_on_edge(tris, vertex, on_edges[0], new_triangles) - return vertex - else: - # the vertex is already present - assert (len(on_edges) == 2) - return on_edges[0].common_vertex(on_edges[1]) - elif len(tris) == 1: - # the new vertex is inside one triangle - self.vertexes.append(vertex) - self.flips += self._split_triangle(tris[0], vertex, new_triangles) - return vertex - - assert(False) def find_triangle_for_vertex(self, p: Point) -> [Triangle]: diff --git a/src/db/db/dbTriangles.h b/src/db/db/dbTriangles.h index 14208c076..7f6a44dd0 100644 --- a/src/db/db/dbTriangles.h +++ b/src/db/db/dbTriangles.h @@ -50,6 +50,9 @@ public: bool check (bool check_delaunay = true) const; void dump (const std::string &path) const; + db::Vertex *create_vertex (double x, double y); + db::Vertex *create_vertex (const db::DPoint &pt); + /** * @brief Finds the points within (not "on") a circle of radius "radius" around the given vertex. */ @@ -66,8 +69,6 @@ private: bool m_is_constrained; size_t m_level; - db::Vertex *create_vertex (double x, double y); - db::Vertex *create_vertex (const db::DPoint &pt); db::TriangleEdge *create_edge (db::Vertex *v1, db::Vertex *v2); db::Triangle *create_triangle (db::TriangleEdge *e1, db::TriangleEdge *e2, db::TriangleEdge *e3); void remove (db::Triangle *tri); @@ -83,6 +84,15 @@ private: int fix_triangles(const std::vector &tris, const std::vector &fixed_edges, std::vector *new_triangles); std::pair, db::TriangleEdge *> flip (TriangleEdge *edge); static bool is_illegal_edge (db::TriangleEdge *edge); + std::vector find_triangle_for_point (const db::DPoint &point); + db::TriangleEdge *find_closest_edge (const db::DPoint &p, db::Vertex *vstart = 0, bool inside_only = false); + void split_triangle (db::Triangle *t, db::Vertex *vertex, std::vector *new_triangles_out); + void split_triangles_on_edge (const std::vector &tris, db::Vertex *vertex, db::TriangleEdge *split_edge, std::vector *new_triangles_out); + void add_more_triangles (const std::vector &new_triangles, + db::TriangleEdge *incoming_edge, + db::Vertex *from_vertex, db::Vertex *to_vertex, + db::TriangleEdge *conn_edge); + void insert_new_vertex (db::Vertex *vertex, std::vector *new_triangles_out); }; }