Antkeeper  0.0.1
mesh.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2023 Christopher J. Howard
3  *
4  * This file is part of Antkeeper source code.
5  *
6  * Antkeeper source code is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * Antkeeper source code is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include <engine/geom/mesh.hpp>
21 #include <stdexcept>
22 
23 namespace geom {
24 
25 mesh::mesh(const mesh& other)
26 {
27  *this = other;
28 }
29 
31 {
32  clear();
33 }
34 
35 mesh& mesh::operator=(const mesh& other)
36 {
37  // Clear the mesh
38  clear();
39 
40  // Resize vertices, edges, and faces
41  vertices.resize(other.vertices.size());
42  edges.resize(other.edges.size());
43  faces.resize(other.faces.size());
44 
45  // Allocate vertices
46  for (std::size_t i = 0; i < vertices.size(); ++i)
47  vertices[i] = new vertex();
48 
49  // Allocate edges
50  for (std::size_t i = 0; i < edges.size(); ++i)
51  {
52  edges[i] = new edge();
53  edges[i]->symmetric = new edge();
54  edges[i]->symmetric->symmetric = edges[i];
55  }
56 
57  // Allocate faces
58  for (std::size_t i = 0; i < faces.size(); ++i)
59  faces[i] = new face();
60 
61  // Copy vertices
62  for (std::size_t i = 0; i < vertices.size(); ++i)
63  {
64  vertex* va = vertices[i];
65  const vertex* vb = other.vertices[i];
66 
67  va->index = vb->index;
68  va->position = vb->position;
69  va->edge = nullptr;
70 
71  if (vb->edge)
72  {
73  va->edge = edges[vb->edge->index];
74  if (vb->edge != other.edges[vb->edge->index])
75  va->edge = va->edge->symmetric;
76  }
77  }
78 
79  // Copy edges
80  for (std::size_t i = 0; i < edges.size(); ++i)
81  {
82  edge* ea = edges[i];
83  const edge* eb = other.edges[i];
84 
85  for (std::size_t j = 0; j < 2; ++j)
86  {
87  ea->index = eb->index;
88  ea->vertex = vertices[eb->vertex->index];
89 
90  ea->face = nullptr;
91  if (eb->face)
92  ea->face = faces[eb->face->index];
93 
94  ea->previous = edges[eb->previous->index];
95  if (eb->previous != other.edges[eb->previous->index])
96  ea->previous = ea->previous->symmetric;
97 
98  ea->next = edges[eb->next->index];
99  if (eb->next != other.edges[eb->next->index])
100  ea->next = ea->next->symmetric;
101 
102  ea = ea->symmetric;
103  eb = eb->symmetric;
104  }
105  }
106 
107  // Copy faces
108  for (std::size_t i = 0; i < faces.size(); ++i)
109  {
110  face* fa = faces[i];
111  const face* fb = other.faces[i];
112 
113  fa->index = fb->index;
114 
115  fa->edge = edges[fb->edge->index];
116  if (fb->edge != other.edges[fb->edge->index])
117  fa->edge = fa->edge->symmetric;
118  }
119 
120  return *this;
121 }
122 
123 void mesh::clear() noexcept
124 {
125  // Deallocate vertices
126  for (mesh::vertex* vertex: vertices)
127  delete vertex;
128 
129  // Deallocate edges
130  for (mesh::edge* edge: edges)
131  {
132  delete edge->symmetric;
133  delete edge;
134  }
135 
136  // Deallocate faces
137  for (mesh::face* face: faces)
138  delete face;
139 
140  vertices.clear();
141  edges.clear();
142  faces.clear();
143 }
144 
146 {
148  {
149  vertices.size(),
150  nullptr,
151  position
152  };
153 
154  vertices.push_back(vertex);
155 
156  return vertex;
157 }
158 
160 {
161  mesh::edge* ab = new mesh::edge();
162  mesh::edge* ba = new mesh::edge();
163 
164  ab->index = edges.size();
165  ab->vertex = a;
166  ab->face = nullptr;
167  ab->previous = ba;
168  ab->next = ba;
169  ab->symmetric = ba;
170 
171  ba->index = edges.size();
172  ba->vertex = b;
173  ba->face = nullptr;
174  ba->previous = ab;
175  ba->next = ab;
176  ba->symmetric = ab;
177 
178  if (!a->edge)
179  {
180  a->edge = ab;
181  }
182  else
183  {
184  mesh::edge* a_in = find_free_incident(a);
185  mesh::edge* a_out = a_in->next;
186  a_in->next = ab;
187  ab->previous = a_in;
188  ba->next = a_out;
189  a_out->previous = ba;
190  }
191 
192  if (!b->edge)
193  {
194  b->edge = ba;
195  }
196  else
197  {
198  mesh::edge* b_in = find_free_incident(b);
199  mesh::edge* b_out = b_in->next;
200  b_in->next = ba;
201  ba->previous = b_in;
202  ab->next = b_out;
203  b_out->previous = ab;
204  }
205 
206  // Add edge
207  edges.push_back(ab);
208 
209  return ab;
210 }
211 
213 {
214  if (loop.empty())
215  {
216  throw std::runtime_error("Empty edge loop");
217  }
218 
219  // Validate edge loop
220  for (std::size_t i = 0; i < loop.size(); ++i)
221  {
222  mesh::edge* current = loop[i];
223  mesh::edge* next = loop[(i + 1) % loop.size()];
224 
225  if (current->symmetric->vertex != next->vertex)
226  {
227  // Disconnected edge loop
228  throw std::runtime_error("Disconnected edge loop");
229  }
230 
231  if (current->face)
232  {
233  // This edge already has a face
234  throw std::runtime_error("Non-manifold mesh 1");
235  }
236  }
237 
238  // Make edges adjacent
239  for (std::size_t i = 0; i < loop.size(); ++i)
240  {
241  if (!make_adjacent(loop[i], loop[(i + 1) % loop.size()]))
242  {
243  throw std::runtime_error("Non-manifold mesh 2");
244  }
245  }
246 
247  // Create face
248  mesh::face* face = new mesh::face();
249  face->edge = loop[0];
250  face->index = faces.size();
251 
252  // Add face
253  faces.push_back(face);
254 
255  // Connect edges to the face
256  for (mesh::edge* edge: loop)
257  {
258  edge->face = face;
259  }
260 
261  return face;
262 }
263 
265 {
266  // Nullify pointers to this face
267  mesh::edge* edge = face->edge;
268  do
269  {
270  edge->face = nullptr;
271  edge = edge->next;
272  }
273  while (edge != face->edge);
274 
275  // Adjust indices of faces after this face
276  for (std::size_t i = face->index + 1; i < faces.size(); ++i)
277  {
278  --faces[i]->index;
279  }
280 
281  // Remove face from the faces vector
282  faces.erase(faces.begin() + face->index);
283 
284  // Deallocate face
285  delete face;
286 }
287 
289 {
290  mesh::edge* ab = edge;
291  mesh::edge* ba = edge->symmetric;
292  mesh::vertex* a = ab->vertex;
293  mesh::edge* a_in = ab->previous;
294  mesh::edge* a_out = ba->next;
295  mesh::vertex* b = ba->vertex;
296  mesh::edge* b_in = ba->previous;
297  mesh::edge* b_out = ab->next;
298 
299  // Remove dependent faces
300  if (ab->face)
301  remove_face(ab->face);
302  if (ba->face)
303  remove_face(ba->face);
304 
305  // Re-link edges
306  if (a->edge == ab)
307  a->edge = (a_out == ab) ? nullptr : a_out;
308  if (b->edge == ba)
309  b->edge = (b_out == ba) ? nullptr : b_out;
310  a_in->next = a_out;
311  a_out->previous = a_in;
312  b_in->next = b_out;
313  b_out->previous = b_in;
314 
315  // Adjust indices of edges after this edge
316  for (std::size_t i = edge->index + 1; i < edges.size(); ++i)
317  {
318  --edges[i]->index;
319  --edges[i]->symmetric->index;
320  }
321 
322  // Remove edge from the edges vector
323  edges.erase(edges.begin() + edge->index);
324 
325  // Deallocate edge
326  delete edge->symmetric;
327  delete edge;
328 }
329 
331 {
332  // Remove connected edges
333  if (vertex->edge)
334  {
335  mesh::edge* current = nullptr;
336  mesh::edge* next = vertex->edge;
337 
338  do
339  {
340  current = next;
341 
342  next = next->symmetric->next;
343  if (next == current)
344  {
345  next = next->symmetric->next;
346  }
347 
348  remove_edge(current);
349  }
350  while (current != next);
351  }
352 
353  // Adjust indices of vertices after this vertex
354  for (std::size_t i = vertex->index + 1; i < vertices.size(); ++i)
355  {
356  --vertices[i]->index;
357  }
358 
359  // Remove vertex from the vertices vector
360  vertices.erase(vertices.begin() + vertex->index);
361 
362  // Deallocate vertex
363  delete vertex;
364 }
365 
366 mesh::edge* mesh::find_free_incident(mesh::vertex* vertex) const
367 {
368  mesh::edge* begin = vertex->edge->symmetric;
369  mesh::edge* current = begin;
370 
371  do
372  {
373  if (!current->face)
374  {
375  return current;
376  }
377 
378  current = current->next->symmetric;
379  }
380  while (current != begin);
381 
382  return nullptr;
383 }
384 
385 mesh::edge* mesh::find_free_incident(mesh::edge* start_edge, mesh::edge* end_edge) const
386 {
387  if (start_edge == end_edge)
388  {
389  return nullptr;
390  }
391 
392  mesh::edge* current = start_edge;
393  do
394  {
395  if (!current->face)
396  {
397  return current;
398  }
399 
400  current = current->next->symmetric;
401  }
402  while (current != end_edge);
403 
404  return nullptr;
405 }
406 
407 bool mesh::make_adjacent(mesh::edge* in, mesh::edge* out)
408 {
409  if (in->next == out)
410  {
411  return true;
412  }
413 
414  mesh::edge* b = in->next;
415  mesh::edge* d = out->previous;
416  mesh::edge* g = find_free_incident(out->symmetric, in);
417  if (!g)
418  {
419  return false;
420  }
421 
422  mesh::edge* h = g->next;
423 
424  in->next = out;
425  out->previous = in;
426 
427  g->next = b;
428  b->previous = g;
429 
430  d->next = h;
431  h->previous = d;
432 
433  return true;
434 }
435 
436 } // namespace geom
Half-edge mesh.
Definition: mesh.hpp:34
void remove_vertex(mesh::vertex *vertex)
Removes a vertex, all dependent edges, and all dependent faces from the mesh.
Definition: mesh.cpp:330
mesh & operator=(const mesh &other)
Copies another mesh into this mesh.
Definition: mesh.cpp:35
void remove_face(mesh::face *face)
Removes a face from the mesh.
Definition: mesh.cpp:264
mesh::face * add_face(const loop &loop)
Adds a face to the mesh.
Definition: mesh.cpp:212
~mesh() noexcept
Destructs a mesh.
Definition: mesh.cpp:30
mesh::vertex * add_vertex(const float3 &position)
Adds a vertex to the mesh.
Definition: mesh.cpp:145
void clear() noexcept
Removes all vertices, edges, and faces from the mesh.
Definition: mesh.cpp:123
std::vector< edge * > loop
List of edges which form a face.
Definition: mesh.hpp:94
constexpr mesh() noexcept=default
Constructs a mesh.
mesh::edge * add_edge(mesh::vertex *a, mesh::vertex *b)
Adds two half edges to the mesh.
Definition: mesh.cpp:159
void remove_edge(mesh::edge *edge)
Removes an edge and all dependent faces from the mesh.
Definition: mesh.cpp:288
constexpr math::vector2< T > b
Definition: illuminant.hpp:40
Geometric algorithms.
Definition: cartesian.hpp:26
@ position
Vertex position (vec3)
Half-edge mesh edge, containing its index and pointers to its starting vertex, parent face,...
Definition: mesh.hpp:59
mesh::face * face
Pointer to the face on the left of this edge.
Definition: mesh.hpp:67
std::size_t index
Index of this edge.
Definition: mesh.hpp:61
mesh::edge * next
Pointer to the next edge in the parent face.
Definition: mesh.hpp:73
mesh::vertex * vertex
Pointer to the vertex at which the edge starts.
Definition: mesh.hpp:64
mesh::edge * symmetric
Pointer to the symmetric edge.
Definition: mesh.hpp:76
mesh::edge * previous
Pointer to the previous edge in the parent face.
Definition: mesh.hpp:70
Half-edge mesh face, containing its index and a pointer to its first edge.
Definition: mesh.hpp:83
mesh::edge * edge
Pointer to the first edge in this face.
Definition: mesh.hpp:88
std::size_t index
Index of this face.
Definition: mesh.hpp:85
Half-edge mesh vertex, containing its index, a pointer to its parent edge, and its position vector.
Definition: mesh.hpp:44
float3 position
Vertex position.
Definition: mesh.hpp:52
mesh::edge * edge
Pointer to the edge to which this vertex belongs.
Definition: mesh.hpp:49
std::size_t index
Index of this vertex.
Definition: mesh.hpp:46