1 | /**************************************************************************/ |
2 | /* quick_hull.cpp */ |
3 | /**************************************************************************/ |
4 | /* This file is part of: */ |
5 | /* GODOT ENGINE */ |
6 | /* https://godotengine.org */ |
7 | /**************************************************************************/ |
8 | /* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ |
9 | /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ |
10 | /* */ |
11 | /* Permission is hereby granted, free of charge, to any person obtaining */ |
12 | /* a copy of this software and associated documentation files (the */ |
13 | /* "Software"), to deal in the Software without restriction, including */ |
14 | /* without limitation the rights to use, copy, modify, merge, publish, */ |
15 | /* distribute, sublicense, and/or sell copies of the Software, and to */ |
16 | /* permit persons to whom the Software is furnished to do so, subject to */ |
17 | /* the following conditions: */ |
18 | /* */ |
19 | /* The above copyright notice and this permission notice shall be */ |
20 | /* included in all copies or substantial portions of the Software. */ |
21 | /* */ |
22 | /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ |
23 | /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ |
24 | /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ |
25 | /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ |
26 | /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ |
27 | /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ |
28 | /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ |
29 | /**************************************************************************/ |
30 | |
31 | #include "quick_hull.h" |
32 | |
33 | #include "core/templates/rb_map.h" |
34 | |
35 | uint32_t QuickHull::debug_stop_after = 0xFFFFFFFF; |
36 | |
37 | Error QuickHull::build(const Vector<Vector3> &p_points, Geometry3D::MeshData &r_mesh) { |
38 | /* CREATE AABB VOLUME */ |
39 | |
40 | AABB aabb; |
41 | for (int i = 0; i < p_points.size(); i++) { |
42 | if (i == 0) { |
43 | aabb.position = p_points[i]; |
44 | } else { |
45 | aabb.expand_to(p_points[i]); |
46 | } |
47 | } |
48 | |
49 | if (aabb.size == Vector3()) { |
50 | return ERR_CANT_CREATE; |
51 | } |
52 | |
53 | Vector<bool> valid_points; |
54 | valid_points.resize(p_points.size()); |
55 | HashSet<Vector3> valid_cache; |
56 | |
57 | for (int i = 0; i < p_points.size(); i++) { |
58 | Vector3 sp = p_points[i].snapped(Vector3(0.0001, 0.0001, 0.0001)); |
59 | if (valid_cache.has(sp)) { |
60 | valid_points.write[i] = false; |
61 | } else { |
62 | valid_points.write[i] = true; |
63 | valid_cache.insert(sp); |
64 | } |
65 | } |
66 | |
67 | /* CREATE INITIAL SIMPLEX */ |
68 | |
69 | int longest_axis = aabb.get_longest_axis_index(); |
70 | |
71 | //first two vertices are the most distant |
72 | int simplex[4] = { 0 }; |
73 | |
74 | { |
75 | real_t max = 0, min = 0; |
76 | |
77 | for (int i = 0; i < p_points.size(); i++) { |
78 | if (!valid_points[i]) { |
79 | continue; |
80 | } |
81 | real_t d = p_points[i][longest_axis]; |
82 | if (i == 0 || d < min) { |
83 | simplex[0] = i; |
84 | min = d; |
85 | } |
86 | |
87 | if (i == 0 || d > max) { |
88 | simplex[1] = i; |
89 | max = d; |
90 | } |
91 | } |
92 | } |
93 | |
94 | //third vertex is one most further away from the line |
95 | |
96 | { |
97 | real_t maxd = 0; |
98 | Vector3 rel12 = p_points[simplex[0]] - p_points[simplex[1]]; |
99 | |
100 | for (int i = 0; i < p_points.size(); i++) { |
101 | if (!valid_points[i]) { |
102 | continue; |
103 | } |
104 | |
105 | Vector3 n = rel12.cross(p_points[simplex[0]] - p_points[i]).cross(rel12).normalized(); |
106 | real_t d = Math::abs(n.dot(p_points[simplex[0]]) - n.dot(p_points[i])); |
107 | |
108 | if (i == 0 || d > maxd) { |
109 | maxd = d; |
110 | simplex[2] = i; |
111 | } |
112 | } |
113 | } |
114 | |
115 | //fourth vertex is the one most further away from the plane |
116 | |
117 | { |
118 | real_t maxd = 0; |
119 | Plane p(p_points[simplex[0]], p_points[simplex[1]], p_points[simplex[2]]); |
120 | |
121 | for (int i = 0; i < p_points.size(); i++) { |
122 | if (!valid_points[i]) { |
123 | continue; |
124 | } |
125 | |
126 | real_t d = Math::abs(p.distance_to(p_points[i])); |
127 | |
128 | if (i == 0 || d > maxd) { |
129 | maxd = d; |
130 | simplex[3] = i; |
131 | } |
132 | } |
133 | } |
134 | |
135 | //compute center of simplex, this is a point always warranted to be inside |
136 | Vector3 center; |
137 | |
138 | for (int i = 0; i < 4; i++) { |
139 | center += p_points[simplex[i]]; |
140 | } |
141 | |
142 | center /= 4.0; |
143 | |
144 | //add faces |
145 | |
146 | List<Face> faces; |
147 | |
148 | for (int i = 0; i < 4; i++) { |
149 | static const int face_order[4][3] = { |
150 | { 0, 1, 2 }, |
151 | { 0, 1, 3 }, |
152 | { 0, 2, 3 }, |
153 | { 1, 2, 3 } |
154 | }; |
155 | |
156 | Face f; |
157 | for (int j = 0; j < 3; j++) { |
158 | f.vertices[j] = simplex[face_order[i][j]]; |
159 | } |
160 | |
161 | Plane p(p_points[f.vertices[0]], p_points[f.vertices[1]], p_points[f.vertices[2]]); |
162 | |
163 | if (p.is_point_over(center)) { |
164 | //flip face to clockwise if facing inwards |
165 | SWAP(f.vertices[0], f.vertices[1]); |
166 | p = -p; |
167 | } |
168 | |
169 | f.plane = p; |
170 | |
171 | faces.push_back(f); |
172 | } |
173 | |
174 | real_t over_tolerance = 3 * UNIT_EPSILON * (aabb.size.x + aabb.size.y + aabb.size.z); |
175 | |
176 | /* COMPUTE AVAILABLE VERTICES */ |
177 | |
178 | for (int i = 0; i < p_points.size(); i++) { |
179 | if (i == simplex[0]) { |
180 | continue; |
181 | } |
182 | if (i == simplex[1]) { |
183 | continue; |
184 | } |
185 | if (i == simplex[2]) { |
186 | continue; |
187 | } |
188 | if (i == simplex[3]) { |
189 | continue; |
190 | } |
191 | if (!valid_points[i]) { |
192 | continue; |
193 | } |
194 | |
195 | for (Face &E : faces) { |
196 | if (E.plane.distance_to(p_points[i]) > over_tolerance) { |
197 | E.points_over.push_back(i); |
198 | break; |
199 | } |
200 | } |
201 | } |
202 | |
203 | faces.sort(); // sort them, so the ones with points are in the back |
204 | |
205 | /* BUILD HULL */ |
206 | |
207 | //poop face (while still remain) |
208 | //find further away point |
209 | //find lit faces |
210 | //determine horizon edges |
211 | //build new faces with horizon edges, them assign points side from all lit faces |
212 | //remove lit faces |
213 | |
214 | uint32_t debug_stop = debug_stop_after; |
215 | |
216 | while (debug_stop > 0 && faces.back()->get().points_over.size()) { |
217 | debug_stop--; |
218 | Face &f = faces.back()->get(); |
219 | |
220 | //find vertex most outside |
221 | int next = -1; |
222 | real_t next_d = 0; |
223 | |
224 | for (int i = 0; i < f.points_over.size(); i++) { |
225 | real_t d = f.plane.distance_to(p_points[f.points_over[i]]); |
226 | |
227 | if (d > next_d) { |
228 | next_d = d; |
229 | next = i; |
230 | } |
231 | } |
232 | |
233 | ERR_FAIL_COND_V(next == -1, ERR_BUG); |
234 | |
235 | Vector3 v = p_points[f.points_over[next]]; |
236 | |
237 | //find lit faces and lit edges |
238 | List<List<Face>::Element *> lit_faces; //lit face is a death sentence |
239 | |
240 | HashMap<Edge, FaceConnect, Edge> lit_edges; //create this on the flight, should not be that bad for performance and simplifies code a lot |
241 | |
242 | for (List<Face>::Element *E = faces.front(); E; E = E->next()) { |
243 | if (E->get().plane.distance_to(v) > 0) { |
244 | lit_faces.push_back(E); |
245 | |
246 | for (int i = 0; i < 3; i++) { |
247 | uint32_t a = E->get().vertices[i]; |
248 | uint32_t b = E->get().vertices[(i + 1) % 3]; |
249 | Edge e(a, b); |
250 | |
251 | HashMap<Edge, FaceConnect, Edge>::Iterator F = lit_edges.find(e); |
252 | if (!F) { |
253 | F = lit_edges.insert(e, FaceConnect()); |
254 | } |
255 | if (e.vertices[0] == a) { |
256 | //left |
257 | F->value.left = E; |
258 | } else { |
259 | F->value.right = E; |
260 | } |
261 | } |
262 | } |
263 | } |
264 | |
265 | //create new faces from horizon edges |
266 | List<List<Face>::Element *> new_faces; //new faces |
267 | |
268 | for (KeyValue<Edge, FaceConnect> &E : lit_edges) { |
269 | FaceConnect &fc = E.value; |
270 | if (fc.left && fc.right) { |
271 | continue; //edge is uninteresting, not on horizon |
272 | } |
273 | |
274 | //create new face! |
275 | |
276 | Face face; |
277 | face.vertices[0] = f.points_over[next]; |
278 | face.vertices[1] = E.key.vertices[0]; |
279 | face.vertices[2] = E.key.vertices[1]; |
280 | |
281 | Plane p(p_points[face.vertices[0]], p_points[face.vertices[1]], p_points[face.vertices[2]]); |
282 | |
283 | if (p.is_point_over(center)) { |
284 | //flip face to clockwise if facing inwards |
285 | SWAP(face.vertices[0], face.vertices[1]); |
286 | p = -p; |
287 | } |
288 | |
289 | face.plane = p; |
290 | new_faces.push_back(faces.push_back(face)); |
291 | } |
292 | |
293 | //distribute points into new faces |
294 | |
295 | for (List<Face>::Element *&F : lit_faces) { |
296 | Face &lf = F->get(); |
297 | |
298 | for (int i = 0; i < lf.points_over.size(); i++) { |
299 | if (lf.points_over[i] == f.points_over[next]) { //do not add current one |
300 | continue; |
301 | } |
302 | |
303 | Vector3 p = p_points[lf.points_over[i]]; |
304 | for (List<Face>::Element *&E : new_faces) { |
305 | Face &f2 = E->get(); |
306 | if (f2.plane.distance_to(p) > over_tolerance) { |
307 | f2.points_over.push_back(lf.points_over[i]); |
308 | break; |
309 | } |
310 | } |
311 | } |
312 | } |
313 | |
314 | //erase lit faces |
315 | |
316 | while (lit_faces.size()) { |
317 | faces.erase(lit_faces.front()->get()); |
318 | lit_faces.pop_front(); |
319 | } |
320 | |
321 | //put faces that contain no points on the front |
322 | |
323 | for (List<Face>::Element *&E : new_faces) { |
324 | Face &f2 = E->get(); |
325 | if (f2.points_over.size() == 0) { |
326 | faces.move_to_front(E); |
327 | } |
328 | } |
329 | |
330 | //whew, done with iteration, go next |
331 | } |
332 | |
333 | /* CREATE MESHDATA */ |
334 | |
335 | //make a map of edges again |
336 | HashMap<Edge, RetFaceConnect, Edge> ret_edges; |
337 | List<Geometry3D::MeshData::Face> ret_faces; |
338 | |
339 | for (const Face &E : faces) { |
340 | Geometry3D::MeshData::Face f; |
341 | f.plane = E.plane; |
342 | |
343 | for (int i = 0; i < 3; i++) { |
344 | f.indices.push_back(E.vertices[i]); |
345 | } |
346 | |
347 | List<Geometry3D::MeshData::Face>::Element *F = ret_faces.push_back(f); |
348 | |
349 | for (int i = 0; i < 3; i++) { |
350 | uint32_t a = E.vertices[i]; |
351 | uint32_t b = E.vertices[(i + 1) % 3]; |
352 | Edge e(a, b); |
353 | |
354 | HashMap<Edge, RetFaceConnect, Edge>::Iterator G = ret_edges.find(e); |
355 | if (!G) { |
356 | G = ret_edges.insert(e, RetFaceConnect()); |
357 | } |
358 | if (e.vertices[0] == a) { |
359 | //left |
360 | G->value.left = F; |
361 | } else { |
362 | G->value.right = F; |
363 | } |
364 | } |
365 | } |
366 | |
367 | //fill faces |
368 | |
369 | for (List<Geometry3D::MeshData::Face>::Element *E = ret_faces.front(); E; E = E->next()) { |
370 | Geometry3D::MeshData::Face &f = E->get(); |
371 | |
372 | for (uint32_t i = 0; i < f.indices.size(); i++) { |
373 | int a = E->get().indices[i]; |
374 | int b = E->get().indices[(i + 1) % f.indices.size()]; |
375 | Edge e(a, b); |
376 | |
377 | HashMap<Edge, RetFaceConnect, Edge>::Iterator F = ret_edges.find(e); |
378 | |
379 | ERR_CONTINUE(!F); |
380 | List<Geometry3D::MeshData::Face>::Element *O = F->value.left == E ? F->value.right : F->value.left; |
381 | ERR_CONTINUE(O == E); |
382 | ERR_CONTINUE(O == nullptr); |
383 | |
384 | if (O->get().plane.is_equal_approx(f.plane)) { |
385 | //merge and delete edge and contiguous face, while repointing edges (uuugh!) |
386 | int o_index_size = O->get().indices.size(); |
387 | |
388 | for (int j = 0; j < o_index_size; j++) { |
389 | //search a |
390 | if (O->get().indices[j] == a) { |
391 | //append the rest |
392 | for (int k = 0; k < o_index_size; k++) { |
393 | int idx = O->get().indices[(k + j) % o_index_size]; |
394 | int idxn = O->get().indices[(k + j + 1) % o_index_size]; |
395 | if (idx == b && idxn == a) { //already have b! |
396 | break; |
397 | } |
398 | if (idx != a) { |
399 | f.indices.insert(i + 1, idx); |
400 | i++; |
401 | } |
402 | Edge e2(idx, idxn); |
403 | |
404 | HashMap<Edge, RetFaceConnect, Edge>::Iterator F2 = ret_edges.find(e2); |
405 | ERR_CONTINUE(!F2); |
406 | //change faceconnect, point to this face instead |
407 | if (F2->value.left == O) { |
408 | F2->value.left = E; |
409 | } else if (F2->value.right == O) { |
410 | F2->value.right = E; |
411 | } |
412 | } |
413 | |
414 | break; |
415 | } |
416 | } |
417 | |
418 | // remove all edge connections to this face |
419 | for (KeyValue<Edge, RetFaceConnect> &G : ret_edges) { |
420 | if (G.value.left == O) { |
421 | G.value.left = nullptr; |
422 | } |
423 | |
424 | if (G.value.right == O) { |
425 | G.value.right = nullptr; |
426 | } |
427 | } |
428 | |
429 | ret_edges.remove(F); //remove the edge |
430 | ret_faces.erase(O); //remove the face |
431 | } |
432 | } |
433 | } |
434 | |
435 | //fill mesh |
436 | r_mesh.faces.clear(); |
437 | r_mesh.faces.resize(ret_faces.size()); |
438 | |
439 | HashMap<List<Geometry3D::MeshData::Face>::Element *, int> face_indices; |
440 | |
441 | int idx = 0; |
442 | for (List<Geometry3D::MeshData::Face>::Element *E = ret_faces.front(); E; E = E->next()) { |
443 | face_indices[E] = idx; |
444 | r_mesh.faces[idx++] = E->get(); |
445 | } |
446 | r_mesh.edges.resize(ret_edges.size()); |
447 | idx = 0; |
448 | for (const KeyValue<Edge, RetFaceConnect> &E : ret_edges) { |
449 | Geometry3D::MeshData::Edge e; |
450 | e.vertex_a = E.key.vertices[0]; |
451 | e.vertex_b = E.key.vertices[1]; |
452 | ERR_CONTINUE(!face_indices.has(E.value.left)); |
453 | ERR_CONTINUE(!face_indices.has(E.value.right)); |
454 | e.face_a = face_indices[E.value.left]; |
455 | e.face_b = face_indices[E.value.right]; |
456 | r_mesh.edges[idx++] = e; |
457 | } |
458 | |
459 | r_mesh.vertices = p_points; |
460 | |
461 | return OK; |
462 | } |
463 | |