💿🐜 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.

332 lines
6.1 KiB

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