💿🐜 Antkeeper source code https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

335 lines
6.1 KiB

  1. /*
  2. * Copyright (C) 2021 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. #include "mesh.hpp"
  20. #include <stdexcept>
  21. namespace geom {
  22. mesh::~mesh()
  23. {
  24. // Deallocate vertices
  25. for (mesh::vertex* vertex: vertices)
  26. {
  27. delete vertex;
  28. }
  29. // Deallocate edges
  30. for (mesh::edge* edge: edges)
  31. {
  32. delete edge->symmetric;
  33. delete edge;
  34. }
  35. // Deallocate faces
  36. for (mesh::face* face: faces)
  37. {
  38. delete face;
  39. }
  40. }
  41. mesh::vertex* mesh::add_vertex(const float3& position)
  42. {
  43. mesh::vertex* vertex = new mesh::vertex();
  44. vertex->edge = nullptr;
  45. vertex->position = position;
  46. vertex->index = vertices.size();
  47. vertices.push_back(vertex);
  48. return vertex;
  49. }
  50. mesh::edge* mesh::add_edge(mesh::vertex* a, mesh::vertex* b)
  51. {
  52. mesh::edge* ab = new mesh::edge();
  53. mesh::edge* ba = new mesh::edge();
  54. ab->vertex = a;
  55. ab->face = nullptr;
  56. ab->previous = ba;
  57. ab->next = ba;
  58. ab->symmetric = ba;
  59. ab->index = edges.size();
  60. ba->vertex = b;
  61. ba->face = nullptr;
  62. ba->previous = ab;
  63. ba->next = ab;
  64. ba->symmetric = ab;
  65. ba->index = edges.size();
  66. if (!a->edge)
  67. {
  68. a->edge = ab;
  69. }
  70. else
  71. {
  72. mesh::edge* a_in = find_free_incident(a);
  73. mesh::edge* a_out = a_in->next;
  74. a_in->next = ab;
  75. ab->previous = a_in;
  76. ba->next = a_out;
  77. a_out->previous = ba;
  78. }
  79. if (!b->edge)
  80. {
  81. b->edge = ba;
  82. }
  83. else
  84. {
  85. mesh::edge* b_in = find_free_incident(b);
  86. mesh::edge* b_out = b_in->next;
  87. b_in->next = ba;
  88. ba->previous = b_in;
  89. ab->next = b_out;
  90. b_out->previous = ab;
  91. }
  92. // Add edge
  93. edges.push_back(ab);
  94. return ab;
  95. }
  96. mesh::face* mesh::add_face(const loop& loop)
  97. {
  98. if (loop.empty())
  99. {
  100. throw std::runtime_error("Empty edge loop");
  101. }
  102. // Validate edge loop
  103. for (std::size_t i = 0; i < loop.size(); ++i)
  104. {
  105. mesh::edge* current = loop[i];
  106. mesh::edge* next = loop[(i + 1) % loop.size()];
  107. if (current->symmetric->vertex != next->vertex)
  108. {
  109. // Disconnected edge loop
  110. throw std::runtime_error("Disconnected edge loop");
  111. }
  112. if (current->face)
  113. {
  114. // This edge already has a face
  115. throw std::runtime_error("Non-manifold mesh 1");
  116. }
  117. }
  118. // Make edges adjacent
  119. for (std::size_t i = 0; i < loop.size(); ++i)
  120. {
  121. if (!make_adjacent(loop[i], loop[(i + 1) % loop.size()]))
  122. {
  123. throw std::runtime_error("Non-manifold mesh 2");
  124. }
  125. }
  126. // Create face
  127. mesh::face* face = new mesh::face();
  128. face->edge = loop[0];
  129. face->index = faces.size();
  130. // Add face
  131. faces.push_back(face);
  132. // Connect edges to the face
  133. for (mesh::edge* edge: loop)
  134. {
  135. edge->face = face;
  136. }
  137. return face;
  138. }
  139. void mesh::remove_face(mesh::face* face)
  140. {
  141. // Nullify pointers to this face
  142. mesh::edge* edge = face->edge;
  143. do
  144. {
  145. edge->face = nullptr;
  146. edge = edge->next;
  147. }
  148. while (edge != face->edge);
  149. // Adjust indices of faces after this face
  150. for (std::size_t i = face->index + 1; i < faces.size(); ++i)
  151. {
  152. --faces[i]->index;
  153. }
  154. // Remove face from the faces vector
  155. faces.erase(faces.begin() + face->index);
  156. // Deallocate face
  157. delete face;
  158. }
  159. void mesh::remove_edge(mesh::edge* edge)
  160. {
  161. mesh::edge* ab = edge;
  162. mesh::edge* ba = edge->symmetric;
  163. mesh::vertex* a = ab->vertex;
  164. mesh::edge* a_in = ab->previous;
  165. mesh::edge* a_out = ba->next;
  166. mesh::vertex* b = ba->vertex;
  167. mesh::edge* b_in = ba->previous;
  168. mesh::edge* b_out = ab->next;
  169. // Remove dependent faces
  170. if (ab->face)
  171. remove_face(ab->face);
  172. if (ba->face)
  173. remove_face(ba->face);
  174. // Re-link edges
  175. if (a->edge == ab)
  176. a->edge = (a_out == ab) ? nullptr : a_out;
  177. if (b->edge == ba)
  178. b->edge = (b_out == ba) ? nullptr : b_out;
  179. a_in->next = a_out;
  180. a_out->previous = a_in;
  181. b_in->next = b_out;
  182. b_out->previous = b_in;
  183. // Adjust indices of edges after this edge
  184. for (std::size_t i = edge->index + 1; i < edges.size(); ++i)
  185. {
  186. --edges[i]->index;
  187. --edges[i]->symmetric->index;
  188. }
  189. // Remove edge from the edges vector
  190. edges.erase(edges.begin() + edge->index);
  191. // Deallocate edge
  192. delete edge->symmetric;
  193. delete edge;
  194. }
  195. void mesh::remove_vertex(mesh::vertex* vertex)
  196. {
  197. // Remove connected edges
  198. if (vertex->edge)
  199. {
  200. mesh::edge* current = nullptr;
  201. mesh::edge* next = vertex->edge;
  202. do
  203. {
  204. current = next;
  205. next = next->symmetric->next;
  206. if (next == current)
  207. {
  208. next = next->symmetric->next;
  209. }
  210. remove_edge(current);
  211. }
  212. while (current != next);
  213. }
  214. // Adjust indices of vertices after this vertex
  215. for (std::size_t i = vertex->index + 1; i < vertices.size(); ++i)
  216. {
  217. --vertices[i]->index;
  218. }
  219. // Remove vertex from the vertices vector
  220. vertices.erase(vertices.begin() + vertex->index);
  221. // Deallocate vertex
  222. delete vertex;
  223. }
  224. mesh::edge* mesh::find_free_incident(mesh::vertex* vertex) const
  225. {
  226. mesh::edge* begin = vertex->edge->symmetric;
  227. mesh::edge* current = begin;
  228. do
  229. {
  230. if (!current->face)
  231. {
  232. return current;
  233. }
  234. current = current->next->symmetric;
  235. }
  236. while (current != begin);
  237. return nullptr;
  238. }
  239. mesh::edge* mesh::find_free_incident(mesh::edge* start_edge, mesh::edge* end_edge) const
  240. {
  241. if (start_edge == end_edge)
  242. {
  243. return nullptr;
  244. }
  245. mesh::edge* current = start_edge;
  246. do
  247. {
  248. if (!current->face)
  249. {
  250. return current;
  251. }
  252. current = current->next->symmetric;
  253. }
  254. while (current != end_edge);
  255. return nullptr;
  256. }
  257. bool mesh::make_adjacent(mesh::edge* in, mesh::edge* out)
  258. {
  259. if (in->next == out)
  260. {
  261. return true;
  262. }
  263. mesh::edge* b = in->next;
  264. mesh::edge* d = out->previous;
  265. mesh::edge* g = find_free_incident(out->symmetric, in);
  266. if (!g)
  267. {
  268. return false;
  269. }
  270. mesh::edge* h = g->next;
  271. in->next = out;
  272. out->previous = in;
  273. g->next = b;
  274. b->previous = g;
  275. d->next = h;
  276. h->previous = d;
  277. return true;
  278. }
  279. } // namespace geom