Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/core/math/convex_hull.cpp
9903 views
1
/**************************************************************************/
2
/* convex_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
/*
32
* Based on Godot's patched VHACD-version of Bullet's btConvexHullComputer.
33
* See /thirdparty/vhacd/btConvexHullComputer.cpp at 64403ddcab9f1dca2408f0a412a22d899708bbb1
34
* In turn, based on /src/LinearMath/btConvexHullComputer.cpp in <https://github.com/bulletphysics/bullet3>
35
* at 73b217fb07e7e3ce126caeb28ab3c9ddd0718467
36
*
37
* Changes:
38
* - int32_t is consistently used instead of int in some cases
39
* - integrated patch db0d6c92927f5a1358b887f2645c11f3014f0e8a from Bullet (CWE-190 integer overflow in btConvexHullComputer)
40
* - adapted to Godot's code style
41
* - replaced Bullet's types (e.g. vectors) with Godot's
42
* - replaced custom Pool implementation with PagedAllocator
43
*/
44
45
/*
46
Copyright (c) 2011 Ole Kniemeyer, MAXON, www.maxon.net
47
48
This software is provided 'as-is', without any express or implied warranty.
49
In no event will the authors be held liable for any damages arising from the use of this software.
50
Permission is granted to anyone to use this software for any purpose,
51
including commercial applications, and to alter it and redistribute it freely,
52
subject to the following restrictions:
53
54
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
55
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
56
3. This notice may not be removed or altered from any source distribution.
57
*/
58
59
#include "convex_hull.h"
60
61
#include "core/error/error_macros.h"
62
#include "core/math/aabb.h"
63
#include "core/math/math_defs.h"
64
#include "core/templates/a_hash_map.h"
65
#include "core/templates/paged_allocator.h"
66
67
//#define DEBUG_CONVEX_HULL
68
//#define SHOW_ITERATIONS
69
70
// -- GODOT start --
71
// Assembly optimizations are not used at the moment.
72
//#define USE_X86_64_ASM
73
// -- GODOT end --
74
75
#ifdef DEBUG_ENABLED
76
#define CHULL_ASSERT(m_cond) \
77
if constexpr (true) { \
78
if (unlikely(!(m_cond))) { \
79
ERR_PRINT("Assertion \"" _STR(m_cond) "\" failed."); \
80
} \
81
} else \
82
((void)0)
83
#else
84
#define CHULL_ASSERT(m_cond) \
85
if constexpr (true) { \
86
} else \
87
((void)0)
88
#endif
89
90
#if defined(DEBUG_CONVEX_HULL) || defined(SHOW_ITERATIONS)
91
#include <cstdio>
92
#endif
93
94
// Convex hull implementation based on Preparata and Hong
95
// Ole Kniemeyer, MAXON Computer GmbH
96
class ConvexHullInternal {
97
public:
98
class Point64 {
99
public:
100
int64_t x;
101
int64_t y;
102
int64_t z;
103
104
Point64(int64_t p_x, int64_t p_y, int64_t p_z) {
105
x = p_x;
106
y = p_y;
107
z = p_z;
108
}
109
110
bool is_zero() {
111
return (x == 0) && (y == 0) && (z == 0);
112
}
113
114
int64_t dot(const Point64 &b) const {
115
return x * b.x + y * b.y + z * b.z;
116
}
117
};
118
119
class Point32 {
120
public:
121
int32_t x = 0;
122
int32_t y = 0;
123
int32_t z = 0;
124
int32_t index = -1;
125
126
Point32() {
127
}
128
129
Point32(int32_t p_x, int32_t p_y, int32_t p_z) {
130
x = p_x;
131
y = p_y;
132
z = p_z;
133
}
134
135
bool operator==(const Point32 &b) const {
136
return (x == b.x) && (y == b.y) && (z == b.z);
137
}
138
139
bool operator!=(const Point32 &b) const {
140
return (x != b.x) || (y != b.y) || (z != b.z);
141
}
142
143
bool is_zero() {
144
return (x == 0) && (y == 0) && (z == 0);
145
}
146
147
Point64 cross(const Point32 &b) const {
148
return Point64((int64_t)y * b.z - (int64_t)z * b.y, (int64_t)z * b.x - (int64_t)x * b.z, (int64_t)x * b.y - (int64_t)y * b.x);
149
}
150
151
Point64 cross(const Point64 &b) const {
152
return Point64(y * b.z - z * b.y, z * b.x - x * b.z, x * b.y - y * b.x);
153
}
154
155
int64_t dot(const Point32 &b) const {
156
return (int64_t)x * b.x + (int64_t)y * b.y + (int64_t)z * b.z;
157
}
158
159
int64_t dot(const Point64 &b) const {
160
return x * b.x + y * b.y + z * b.z;
161
}
162
163
Point32 operator+(const Point32 &b) const {
164
return Point32(x + b.x, y + b.y, z + b.z);
165
}
166
167
Point32 operator-(const Point32 &b) const {
168
return Point32(x - b.x, y - b.y, z - b.z);
169
}
170
};
171
172
class Int128 {
173
public:
174
uint64_t low = 0;
175
uint64_t high = 0;
176
177
Int128() {
178
}
179
180
Int128(uint64_t p_low, uint64_t p_high) {
181
low = p_low;
182
high = p_high;
183
}
184
185
Int128(uint64_t p_low) {
186
low = p_low;
187
high = 0;
188
}
189
190
Int128(int64_t p_value) {
191
low = p_value;
192
if (p_value >= 0) {
193
high = 0;
194
} else {
195
high = (uint64_t)-1LL;
196
}
197
}
198
199
static Int128 mul(int64_t a, int64_t b);
200
201
static Int128 mul(uint64_t a, uint64_t b);
202
203
Int128 operator-() const {
204
return Int128(uint64_t(-int64_t(low)), ~high + (low == 0));
205
}
206
207
Int128 operator+(const Int128 &b) const {
208
#ifdef USE_X86_64_ASM
209
Int128 result;
210
__asm__("addq %[bl], %[rl]\n\t"
211
"adcq %[bh], %[rh]\n\t"
212
: [rl] "=r"(result.low), [rh] "=r"(result.high)
213
: "0"(low), "1"(high), [bl] "g"(b.low), [bh] "g"(b.high)
214
: "cc");
215
return result;
216
#else
217
uint64_t lo = low + b.low;
218
return Int128(lo, high + b.high + (lo < low));
219
#endif
220
}
221
222
Int128 operator-(const Int128 &b) const {
223
#ifdef USE_X86_64_ASM
224
Int128 result;
225
__asm__("subq %[bl], %[rl]\n\t"
226
"sbbq %[bh], %[rh]\n\t"
227
: [rl] "=r"(result.low), [rh] "=r"(result.high)
228
: "0"(low), "1"(high), [bl] "g"(b.low), [bh] "g"(b.high)
229
: "cc");
230
return result;
231
#else
232
return *this + -b;
233
#endif
234
}
235
236
Int128 &operator+=(const Int128 &b) {
237
#ifdef USE_X86_64_ASM
238
__asm__("addq %[bl], %[rl]\n\t"
239
"adcq %[bh], %[rh]\n\t"
240
: [rl] "=r"(low), [rh] "=r"(high)
241
: "0"(low), "1"(high), [bl] "g"(b.low), [bh] "g"(b.high)
242
: "cc");
243
#else
244
uint64_t lo = low + b.low;
245
if (lo < low) {
246
++high;
247
}
248
low = lo;
249
high += b.high;
250
#endif
251
return *this;
252
}
253
254
Int128 &operator++() {
255
if (++low == 0) {
256
++high;
257
}
258
return *this;
259
}
260
261
Int128 operator*(int64_t b) const;
262
263
real_t to_scalar() const {
264
return ((int64_t)high >= 0) ? real_t(high) * (real_t(0x100000000LL) * real_t(0x100000000LL)) + real_t(low) : -(-*this).to_scalar();
265
}
266
267
int32_t get_sign() const {
268
return ((int64_t)high < 0) ? -1 : ((high || low) ? 1 : 0);
269
}
270
271
bool operator<(const Int128 &b) const {
272
return (high < b.high) || ((high == b.high) && (low < b.low));
273
}
274
275
int32_t ucmp(const Int128 &b) const {
276
if (high < b.high) {
277
return -1;
278
}
279
if (high > b.high) {
280
return 1;
281
}
282
if (low < b.low) {
283
return -1;
284
}
285
if (low > b.low) {
286
return 1;
287
}
288
return 0;
289
}
290
};
291
292
class Rational64 {
293
private:
294
uint64_t numerator;
295
uint64_t denominator;
296
int32_t sign;
297
298
public:
299
Rational64(int64_t p_numerator, int64_t p_denominator) {
300
if (p_numerator > 0) {
301
sign = 1;
302
numerator = (uint64_t)p_numerator;
303
} else if (p_numerator < 0) {
304
sign = -1;
305
numerator = (uint64_t)-p_numerator;
306
} else {
307
sign = 0;
308
numerator = 0;
309
}
310
if (p_denominator > 0) {
311
denominator = (uint64_t)p_denominator;
312
} else if (p_denominator < 0) {
313
sign = -sign;
314
denominator = (uint64_t)-p_denominator;
315
} else {
316
denominator = 0;
317
}
318
}
319
320
bool is_negative_infinity() const {
321
return (sign < 0) && (denominator == 0);
322
}
323
324
bool is_nan() const {
325
return (sign == 0) && (denominator == 0);
326
}
327
328
int32_t compare(const Rational64 &b) const;
329
330
real_t to_scalar() const {
331
return sign * ((denominator == 0) ? FLT_MAX : (real_t)numerator / denominator);
332
}
333
};
334
335
class Rational128 {
336
private:
337
Int128 numerator;
338
Int128 denominator;
339
int32_t sign;
340
bool is_int_64;
341
342
public:
343
Rational128(int64_t p_value) {
344
if (p_value > 0) {
345
sign = 1;
346
numerator = p_value;
347
} else if (p_value < 0) {
348
sign = -1;
349
numerator = -p_value;
350
} else {
351
sign = 0;
352
numerator = (uint64_t)0;
353
}
354
denominator = (uint64_t)1;
355
is_int_64 = true;
356
}
357
358
Rational128(const Int128 &p_numerator, const Int128 &p_denominator) {
359
sign = p_numerator.get_sign();
360
if (sign >= 0) {
361
numerator = p_numerator;
362
} else {
363
numerator = -p_numerator;
364
}
365
int32_t dsign = p_denominator.get_sign();
366
if (dsign >= 0) {
367
denominator = p_denominator;
368
} else {
369
sign = -sign;
370
denominator = -p_denominator;
371
}
372
is_int_64 = false;
373
}
374
375
int32_t compare(const Rational128 &b) const;
376
377
int32_t compare(int64_t b) const;
378
379
real_t to_scalar() const {
380
return sign * ((denominator.get_sign() == 0) ? FLT_MAX : numerator.to_scalar() / denominator.to_scalar());
381
}
382
};
383
384
class PointR128 {
385
public:
386
Int128 x;
387
Int128 y;
388
Int128 z;
389
Int128 denominator;
390
391
PointR128() {
392
}
393
394
PointR128(Int128 p_x, Int128 p_y, Int128 p_z, Int128 p_denominator) {
395
x = p_x;
396
y = p_y;
397
z = p_z;
398
denominator = p_denominator;
399
}
400
401
real_t xvalue() const {
402
return x.to_scalar() / denominator.to_scalar();
403
}
404
405
real_t yvalue() const {
406
return y.to_scalar() / denominator.to_scalar();
407
}
408
409
real_t zvalue() const {
410
return z.to_scalar() / denominator.to_scalar();
411
}
412
};
413
414
class Edge;
415
class Face;
416
417
class Vertex {
418
public:
419
Vertex *next = nullptr;
420
Vertex *prev = nullptr;
421
Edge *edges = nullptr;
422
Face *first_nearby_face = nullptr;
423
Face *last_nearby_face = nullptr;
424
PointR128 point128;
425
Point32 point;
426
int32_t copy = -1;
427
428
Vertex() {
429
}
430
431
#ifdef DEBUG_CONVEX_HULL
432
void print() {
433
printf("V%d (%d, %d, %d)", point.index, point.x, point.y, point.z);
434
}
435
436
void print_graph();
437
#endif
438
439
Point32 operator-(const Vertex &b) const {
440
return point - b.point;
441
}
442
443
Rational128 dot(const Point64 &b) const {
444
return (point.index >= 0) ? Rational128(point.dot(b)) : Rational128(point128.x * b.x + point128.y * b.y + point128.z * b.z, point128.denominator);
445
}
446
447
real_t xvalue() const {
448
return (point.index >= 0) ? real_t(point.x) : point128.xvalue();
449
}
450
451
real_t yvalue() const {
452
return (point.index >= 0) ? real_t(point.y) : point128.yvalue();
453
}
454
455
real_t zvalue() const {
456
return (point.index >= 0) ? real_t(point.z) : point128.zvalue();
457
}
458
459
void receive_nearby_faces(Vertex *p_src) {
460
if (last_nearby_face) {
461
last_nearby_face->next_with_same_nearby_vertex = p_src->first_nearby_face;
462
} else {
463
first_nearby_face = p_src->first_nearby_face;
464
}
465
if (p_src->last_nearby_face) {
466
last_nearby_face = p_src->last_nearby_face;
467
}
468
for (Face *f = p_src->first_nearby_face; f; f = f->next_with_same_nearby_vertex) {
469
CHULL_ASSERT(f->nearby_vertex == p_src);
470
f->nearby_vertex = this;
471
}
472
p_src->first_nearby_face = nullptr;
473
p_src->last_nearby_face = nullptr;
474
}
475
};
476
477
class Edge {
478
public:
479
Edge *next = nullptr;
480
Edge *prev = nullptr;
481
Edge *reverse = nullptr;
482
Vertex *target = nullptr;
483
Face *face = nullptr;
484
int32_t copy = -1;
485
486
void link(Edge *n) {
487
CHULL_ASSERT(reverse->target == n->reverse->target);
488
next = n;
489
n->prev = this;
490
}
491
492
#ifdef DEBUG_CONVEX_HULL
493
void print() {
494
printf("E%p : %d -> %d, n=%p p=%p (0 %d\t%d\t%d) -> (%d %d %d)", this, reverse->target->point.index, target->point.index, next, prev,
495
reverse->target->point.x, reverse->target->point.y, reverse->target->point.z, target->point.x, target->point.y, target->point.z);
496
}
497
#endif
498
};
499
500
class Face {
501
public:
502
Face *next = nullptr;
503
Vertex *nearby_vertex = nullptr;
504
Face *next_with_same_nearby_vertex = nullptr;
505
Point32 origin;
506
Point32 dir0;
507
Point32 dir1;
508
509
Face() {
510
}
511
512
void init(Vertex *p_a, const Vertex *p_b, const Vertex *p_c) {
513
nearby_vertex = p_a;
514
origin = p_a->point;
515
dir0 = *p_b - *p_a;
516
dir1 = *p_c - *p_a;
517
if (p_a->last_nearby_face) {
518
p_a->last_nearby_face->next_with_same_nearby_vertex = this;
519
} else {
520
p_a->first_nearby_face = this;
521
}
522
p_a->last_nearby_face = this;
523
}
524
525
Point64 get_normal() {
526
return dir0.cross(dir1);
527
}
528
};
529
530
template <typename UWord, typename UHWord>
531
class DMul {
532
private:
533
static uint32_t high(uint64_t p_value) {
534
return (uint32_t)(p_value >> 32);
535
}
536
537
static uint32_t low(uint64_t p_value) {
538
return (uint32_t)p_value;
539
}
540
541
static uint64_t mul(uint32_t a, uint32_t b) {
542
return (uint64_t)a * (uint64_t)b;
543
}
544
545
static void shl_half(uint64_t &p_value) {
546
p_value <<= 32;
547
}
548
549
static uint64_t high(Int128 p_value) {
550
return p_value.high;
551
}
552
553
static uint64_t low(Int128 p_value) {
554
return p_value.low;
555
}
556
557
static Int128 mul(uint64_t a, uint64_t b) {
558
return Int128::mul(a, b);
559
}
560
561
static void shl_half(Int128 &p_value) {
562
p_value.high = p_value.low;
563
p_value.low = 0;
564
}
565
566
public:
567
static void mul(UWord p_a, UWord p_b, UWord &r_low, UWord &r_high) {
568
UWord p00 = mul(low(p_a), low(p_b));
569
UWord p01 = mul(low(p_a), high(p_b));
570
UWord p10 = mul(high(p_a), low(p_b));
571
UWord p11 = mul(high(p_a), high(p_b));
572
UWord p0110 = UWord(low(p01)) + UWord(low(p10));
573
p11 += high(p01);
574
p11 += high(p10);
575
p11 += high(p0110);
576
shl_half(p0110);
577
p00 += p0110;
578
if (p00 < p0110) {
579
++p11;
580
}
581
r_low = p00;
582
r_high = p11;
583
}
584
};
585
586
private:
587
class IntermediateHull {
588
public:
589
Vertex *min_xy = nullptr;
590
Vertex *max_xy = nullptr;
591
Vertex *min_yx = nullptr;
592
Vertex *max_yx = nullptr;
593
594
IntermediateHull() {
595
}
596
};
597
598
enum Orientation { ORIENTATION_NONE,
599
ORIENTATION_CLOCKWISE,
600
ORIENTATION_COUNTER_CLOCKWISE };
601
602
Vector3 scaling;
603
Vector3 center;
604
PagedAllocator<Vertex> vertex_pool;
605
PagedAllocator<Edge> edge_pool;
606
PagedAllocator<Face> face_pool;
607
LocalVector<Vertex *> original_vertices;
608
int32_t merge_stamp = 0;
609
Vector3::Axis min_axis = Vector3::Axis::AXIS_X;
610
Vector3::Axis med_axis = Vector3::Axis::AXIS_X;
611
Vector3::Axis max_axis = Vector3::Axis::AXIS_X;
612
int32_t used_edge_pairs = 0;
613
int32_t max_used_edge_pairs = 0;
614
615
static Orientation get_orientation(const Edge *p_prev, const Edge *p_next, const Point32 &p_s, const Point32 &p_t);
616
Edge *find_max_angle(bool p_ccw, const Vertex *p_start, const Point32 &p_s, const Point64 &p_rxs, const Point64 &p_ssxrxs, Rational64 &p_min_cot);
617
void find_edge_for_coplanar_faces(Vertex *p_c0, Vertex *p_c1, Edge *&p_e0, Edge *&p_e1, const Vertex *p_stop0, const Vertex *p_stop1);
618
619
Edge *new_edge_pair(Vertex *p_from, Vertex *p_to);
620
621
void remove_edge_pair(Edge *p_edge) {
622
Edge *n = p_edge->next;
623
Edge *r = p_edge->reverse;
624
625
CHULL_ASSERT(p_edge->target && r->target);
626
627
if (n != p_edge) {
628
n->prev = p_edge->prev;
629
p_edge->prev->next = n;
630
r->target->edges = n;
631
} else {
632
r->target->edges = nullptr;
633
}
634
635
n = r->next;
636
637
if (n != r) {
638
n->prev = r->prev;
639
r->prev->next = n;
640
p_edge->target->edges = n;
641
} else {
642
p_edge->target->edges = nullptr;
643
}
644
645
edge_pool.free(p_edge);
646
edge_pool.free(r);
647
used_edge_pairs--;
648
}
649
650
void compute_internal(int32_t p_start, int32_t p_end, IntermediateHull &r_result);
651
652
bool merge_projection(IntermediateHull &p_h0, IntermediateHull &p_h1, Vertex *&r_c0, Vertex *&r_c1);
653
654
void merge(IntermediateHull &p_h0, IntermediateHull &p_h1);
655
656
Vector3 to_gd_vector(const Point32 &p_v);
657
658
Vector3 get_gd_normal(Face *p_face);
659
660
bool shift_face(Face *p_face, real_t p_amount, LocalVector<Vertex *> &p_stack);
661
662
public:
663
~ConvexHullInternal() {
664
vertex_pool.reset(true);
665
edge_pool.reset(true);
666
face_pool.reset(true);
667
}
668
669
Vertex *vertex_list = nullptr;
670
671
void compute(const Vector3 *p_coords, int32_t p_count);
672
673
Vector3 get_coordinates(const Vertex *p_v);
674
675
real_t shrink(real_t amount, real_t p_clamp_amount);
676
};
677
678
ConvexHullInternal::Int128 ConvexHullInternal::Int128::operator*(int64_t b) const {
679
bool negative = (int64_t)high < 0;
680
Int128 a = negative ? -*this : *this;
681
if (b < 0) {
682
negative = !negative;
683
b = -b;
684
}
685
Int128 result = mul(a.low, (uint64_t)b);
686
result.high += a.high * (uint64_t)b;
687
return negative ? -result : result;
688
}
689
690
ConvexHullInternal::Int128 ConvexHullInternal::Int128::mul(int64_t a, int64_t b) {
691
Int128 result;
692
693
#ifdef USE_X86_64_ASM
694
__asm__("imulq %[b]"
695
: "=a"(result.low), "=d"(result.high)
696
: "0"(a), [b] "r"(b)
697
: "cc");
698
return result;
699
700
#else
701
bool negative = a < 0;
702
if (negative) {
703
a = -a;
704
}
705
if (b < 0) {
706
negative = !negative;
707
b = -b;
708
}
709
DMul<uint64_t, uint32_t>::mul((uint64_t)a, (uint64_t)b, result.low, result.high);
710
return negative ? -result : result;
711
#endif
712
}
713
714
ConvexHullInternal::Int128 ConvexHullInternal::Int128::mul(uint64_t a, uint64_t b) {
715
Int128 result;
716
717
#ifdef USE_X86_64_ASM
718
__asm__("mulq %[b]"
719
: "=a"(result.low), "=d"(result.high)
720
: "0"(a), [b] "r"(b)
721
: "cc");
722
723
#else
724
DMul<uint64_t, uint32_t>::mul(a, b, result.low, result.high);
725
#endif
726
727
return result;
728
}
729
730
int32_t ConvexHullInternal::Rational64::compare(const Rational64 &b) const {
731
if (sign != b.sign) {
732
return sign - b.sign;
733
} else if (sign == 0) {
734
return 0;
735
}
736
737
#ifdef USE_X86_64_ASM
738
739
int32_t result;
740
int64_t tmp;
741
int64_t dummy;
742
__asm__("mulq %[bn]\n\t"
743
"movq %%rax, %[tmp]\n\t"
744
"movq %%rdx, %%rbx\n\t"
745
"movq %[tn], %%rax\n\t"
746
"mulq %[bd]\n\t"
747
"subq %[tmp], %%rax\n\t"
748
"sbbq %%rbx, %%rdx\n\t" // rdx:rax contains 128-bit-difference "numerator*b.denominator - b.numerator*denominator"
749
"setnsb %%bh\n\t" // bh=1 if difference is non-negative, bh=0 otherwise
750
"orq %%rdx, %%rax\n\t"
751
"setnzb %%bl\n\t" // bl=1 if difference if non-zero, bl=0 if it is zero
752
"decb %%bh\n\t" // now bx=0x0000 if difference is zero, 0xff01 if it is negative, 0x0001 if it is positive (i.e., same sign as difference)
753
"shll $16, %%ebx\n\t" // ebx has same sign as difference
754
: "=&b"(result), [tmp] "=&r"(tmp), "=a"(dummy)
755
: "a"(denominator), [bn] "g"(b.numerator), [tn] "g"(numerator), [bd] "g"(b.denominator)
756
: "%rdx", "cc");
757
// if sign is +1, only bit 0 of result is inverted, which does not change the sign of result (and cannot result in zero)
758
// if sign is -1, all bits of result are inverted, which changes the sign of result (and again cannot result in zero)
759
return result ? result ^ sign : 0;
760
761
#else
762
763
return sign * Int128::mul(numerator, b.denominator).ucmp(Int128::mul(denominator, b.numerator));
764
765
#endif
766
}
767
768
int32_t ConvexHullInternal::Rational128::compare(const Rational128 &b) const {
769
if (sign != b.sign) {
770
return sign - b.sign;
771
} else if (sign == 0) {
772
return 0;
773
}
774
if (is_int_64) {
775
return -b.compare(sign * (int64_t)numerator.low);
776
}
777
778
Int128 nbd_low, nbd_high, dbn_low, dbn_high;
779
DMul<Int128, uint64_t>::mul(numerator, b.denominator, nbd_low, nbd_high);
780
DMul<Int128, uint64_t>::mul(denominator, b.numerator, dbn_low, dbn_high);
781
782
int32_t cmp = nbd_high.ucmp(dbn_high);
783
if (cmp) {
784
return cmp * sign;
785
}
786
return nbd_low.ucmp(dbn_low) * sign;
787
}
788
789
int32_t ConvexHullInternal::Rational128::compare(int64_t b) const {
790
if (is_int_64) {
791
int64_t a = sign * (int64_t)numerator.low;
792
return (a > b) ? 1 : ((a < b) ? -1 : 0);
793
}
794
if (b > 0) {
795
if (sign <= 0) {
796
return -1;
797
}
798
} else if (b < 0) {
799
if (sign >= 0) {
800
return 1;
801
}
802
b = -b;
803
} else {
804
return sign;
805
}
806
807
return numerator.ucmp(denominator * b) * sign;
808
}
809
810
ConvexHullInternal::Edge *ConvexHullInternal::new_edge_pair(Vertex *p_from, Vertex *p_to) {
811
CHULL_ASSERT(p_from && p_to);
812
Edge *e = edge_pool.alloc();
813
Edge *r = edge_pool.alloc();
814
e->reverse = r;
815
r->reverse = e;
816
e->copy = merge_stamp;
817
r->copy = merge_stamp;
818
e->target = p_to;
819
r->target = p_from;
820
e->face = nullptr;
821
r->face = nullptr;
822
used_edge_pairs++;
823
if (used_edge_pairs > max_used_edge_pairs) {
824
max_used_edge_pairs = used_edge_pairs;
825
}
826
return e;
827
}
828
829
bool ConvexHullInternal::merge_projection(IntermediateHull &r_h0, IntermediateHull &r_h1, Vertex *&r_c0, Vertex *&r_c1) {
830
Vertex *v0 = r_h0.max_yx;
831
Vertex *v1 = r_h1.min_yx;
832
if ((v0->point.x == v1->point.x) && (v0->point.y == v1->point.y)) {
833
CHULL_ASSERT(v0->point.z < v1->point.z);
834
Vertex *v1p = v1->prev;
835
if (v1p == v1) {
836
r_c0 = v0;
837
if (v1->edges) {
838
CHULL_ASSERT(v1->edges->next == v1->edges);
839
v1 = v1->edges->target;
840
CHULL_ASSERT(v1->edges->next == v1->edges);
841
}
842
r_c1 = v1;
843
return false;
844
}
845
Vertex *v1n = v1->next;
846
v1p->next = v1n;
847
v1n->prev = v1p;
848
if (v1 == r_h1.min_xy) {
849
if ((v1n->point.x < v1p->point.x) || ((v1n->point.x == v1p->point.x) && (v1n->point.y < v1p->point.y))) {
850
r_h1.min_xy = v1n;
851
} else {
852
r_h1.min_xy = v1p;
853
}
854
}
855
if (v1 == r_h1.max_xy) {
856
if ((v1n->point.x > v1p->point.x) || ((v1n->point.x == v1p->point.x) && (v1n->point.y > v1p->point.y))) {
857
r_h1.max_xy = v1n;
858
} else {
859
r_h1.max_xy = v1p;
860
}
861
}
862
}
863
864
v0 = r_h0.max_xy;
865
v1 = r_h1.max_xy;
866
Vertex *v00 = nullptr;
867
Vertex *v10 = nullptr;
868
int32_t sign = 1;
869
870
for (int32_t side = 0; side <= 1; side++) {
871
int32_t dx = (v1->point.x - v0->point.x) * sign;
872
if (dx > 0) {
873
while (true) {
874
int32_t dy = v1->point.y - v0->point.y;
875
876
Vertex *w0 = side ? v0->next : v0->prev;
877
if (w0 != v0) {
878
int32_t dx0 = (w0->point.x - v0->point.x) * sign;
879
int32_t dy0 = w0->point.y - v0->point.y;
880
if ((dy0 <= 0) && ((dx0 == 0) || ((dx0 < 0) && (dy0 * dx <= dy * dx0)))) {
881
v0 = w0;
882
dx = (v1->point.x - v0->point.x) * sign;
883
continue;
884
}
885
}
886
887
Vertex *w1 = side ? v1->next : v1->prev;
888
if (w1 != v1) {
889
int32_t dx1 = (w1->point.x - v1->point.x) * sign;
890
int32_t dy1 = w1->point.y - v1->point.y;
891
int32_t dxn = (w1->point.x - v0->point.x) * sign;
892
if ((dxn > 0) && (dy1 < 0) && ((dx1 == 0) || ((dx1 < 0) && (dy1 * dx < dy * dx1)))) {
893
v1 = w1;
894
dx = dxn;
895
continue;
896
}
897
}
898
899
break;
900
}
901
} else if (dx < 0) {
902
while (true) {
903
int32_t dy = v1->point.y - v0->point.y;
904
905
Vertex *w1 = side ? v1->prev : v1->next;
906
if (w1 != v1) {
907
int32_t dx1 = (w1->point.x - v1->point.x) * sign;
908
int32_t dy1 = w1->point.y - v1->point.y;
909
if ((dy1 >= 0) && ((dx1 == 0) || ((dx1 < 0) && (dy1 * dx <= dy * dx1)))) {
910
v1 = w1;
911
dx = (v1->point.x - v0->point.x) * sign;
912
continue;
913
}
914
}
915
916
Vertex *w0 = side ? v0->prev : v0->next;
917
if (w0 != v0) {
918
int32_t dx0 = (w0->point.x - v0->point.x) * sign;
919
int32_t dy0 = w0->point.y - v0->point.y;
920
int32_t dxn = (v1->point.x - w0->point.x) * sign;
921
if ((dxn < 0) && (dy0 > 0) && ((dx0 == 0) || ((dx0 < 0) && (dy0 * dx < dy * dx0)))) {
922
v0 = w0;
923
dx = dxn;
924
continue;
925
}
926
}
927
928
break;
929
}
930
} else {
931
int32_t x = v0->point.x;
932
int32_t y0 = v0->point.y;
933
Vertex *w0 = v0;
934
Vertex *t;
935
while (((t = side ? w0->next : w0->prev) != v0) && (t->point.x == x) && (t->point.y <= y0)) {
936
w0 = t;
937
y0 = t->point.y;
938
}
939
v0 = w0;
940
941
int32_t y1 = v1->point.y;
942
Vertex *w1 = v1;
943
while (((t = side ? w1->prev : w1->next) != v1) && (t->point.x == x) && (t->point.y >= y1)) {
944
w1 = t;
945
y1 = t->point.y;
946
}
947
v1 = w1;
948
}
949
950
if (side == 0) {
951
v00 = v0;
952
v10 = v1;
953
954
v0 = r_h0.min_xy;
955
v1 = r_h1.min_xy;
956
sign = -1;
957
}
958
}
959
960
v0->prev = v1;
961
v1->next = v0;
962
963
v00->next = v10;
964
v10->prev = v00;
965
966
if (r_h1.min_xy->point.x < r_h0.min_xy->point.x) {
967
r_h0.min_xy = r_h1.min_xy;
968
}
969
if (r_h1.max_xy->point.x >= r_h0.max_xy->point.x) {
970
r_h0.max_xy = r_h1.max_xy;
971
}
972
973
r_h0.max_yx = r_h1.max_yx;
974
975
r_c0 = v00;
976
r_c1 = v10;
977
978
return true;
979
}
980
981
void ConvexHullInternal::compute_internal(int32_t p_start, int32_t p_end, IntermediateHull &r_result) {
982
int32_t n = p_end - p_start;
983
switch (n) {
984
case 0:
985
r_result.min_xy = nullptr;
986
r_result.max_xy = nullptr;
987
r_result.min_yx = nullptr;
988
r_result.max_yx = nullptr;
989
return;
990
case 2: {
991
Vertex *v = original_vertices[p_start];
992
Vertex *w = original_vertices[p_start + 1];
993
if (v->point != w->point) {
994
int32_t dx = v->point.x - w->point.x;
995
int32_t dy = v->point.y - w->point.y;
996
997
if ((dx == 0) && (dy == 0)) {
998
if (v->point.z > w->point.z) {
999
Vertex *t = w;
1000
w = v;
1001
v = t;
1002
}
1003
CHULL_ASSERT(v->point.z < w->point.z);
1004
v->next = v;
1005
v->prev = v;
1006
r_result.min_xy = v;
1007
r_result.max_xy = v;
1008
r_result.min_yx = v;
1009
r_result.max_yx = v;
1010
} else {
1011
v->next = w;
1012
v->prev = w;
1013
w->next = v;
1014
w->prev = v;
1015
1016
if ((dx < 0) || ((dx == 0) && (dy < 0))) {
1017
r_result.min_xy = v;
1018
r_result.max_xy = w;
1019
} else {
1020
r_result.min_xy = w;
1021
r_result.max_xy = v;
1022
}
1023
1024
if ((dy < 0) || ((dy == 0) && (dx < 0))) {
1025
r_result.min_yx = v;
1026
r_result.max_yx = w;
1027
} else {
1028
r_result.min_yx = w;
1029
r_result.max_yx = v;
1030
}
1031
}
1032
1033
Edge *e = new_edge_pair(v, w);
1034
e->link(e);
1035
v->edges = e;
1036
1037
e = e->reverse;
1038
e->link(e);
1039
w->edges = e;
1040
1041
return;
1042
}
1043
[[fallthrough]];
1044
}
1045
case 1: {
1046
Vertex *v = original_vertices[p_start];
1047
v->edges = nullptr;
1048
v->next = v;
1049
v->prev = v;
1050
1051
r_result.min_xy = v;
1052
r_result.max_xy = v;
1053
r_result.min_yx = v;
1054
r_result.max_yx = v;
1055
1056
return;
1057
}
1058
}
1059
1060
int32_t split0 = p_start + n / 2;
1061
Point32 p = original_vertices[split0 - 1]->point;
1062
int32_t split1 = split0;
1063
while ((split1 < p_end) && (original_vertices[split1]->point == p)) {
1064
split1++;
1065
}
1066
compute_internal(p_start, split0, r_result);
1067
IntermediateHull hull1;
1068
compute_internal(split1, p_end, hull1);
1069
#ifdef DEBUG_CONVEX_HULL
1070
printf("\n\nMerge\n");
1071
r_result.print();
1072
hull1.print();
1073
#endif
1074
merge(r_result, hull1);
1075
#ifdef DEBUG_CONVEX_HULL
1076
printf("\n Result\n");
1077
r_result.print();
1078
#endif
1079
}
1080
1081
#ifdef DEBUG_CONVEX_HULL
1082
void ConvexHullInternal::IntermediateHull::print() {
1083
printf(" Hull\n");
1084
for (Vertex *v = min_xy; v;) {
1085
printf(" ");
1086
v->print();
1087
if (v == max_xy) {
1088
printf(" max_xy");
1089
}
1090
if (v == min_yx) {
1091
printf(" min_yx");
1092
}
1093
if (v == max_yx) {
1094
printf(" max_yx");
1095
}
1096
if (v->next->prev != v) {
1097
printf(" Inconsistency");
1098
}
1099
printf("\n");
1100
v = v->next;
1101
if (v == min_xy) {
1102
break;
1103
}
1104
}
1105
if (min_xy) {
1106
min_xy->copy = (min_xy->copy == -1) ? -2 : -1;
1107
min_xy->print_graph();
1108
}
1109
}
1110
1111
void ConvexHullInternal::Vertex::print_graph() {
1112
print();
1113
printf("\nEdges\n");
1114
Edge *e = edges;
1115
if (e) {
1116
do {
1117
e->print();
1118
printf("\n");
1119
e = e->next;
1120
} while (e != edges);
1121
do {
1122
Vertex *v = e->target;
1123
if (v->copy != copy) {
1124
v->copy = copy;
1125
v->print_graph();
1126
}
1127
e = e->next;
1128
} while (e != edges);
1129
}
1130
}
1131
#endif
1132
1133
ConvexHullInternal::Orientation ConvexHullInternal::get_orientation(const Edge *p_prev, const Edge *p_next, const Point32 &p_s, const Point32 &p_t) {
1134
CHULL_ASSERT(p_prev->reverse->target == p_next->reverse->target);
1135
if (p_prev->next == p_next) {
1136
if (p_prev->prev == p_next) {
1137
Point64 n = p_t.cross(p_s);
1138
Point64 m = (*p_prev->target - *p_next->reverse->target).cross(*p_next->target - *p_next->reverse->target);
1139
CHULL_ASSERT(!m.is_zero());
1140
int64_t dot = n.dot(m);
1141
CHULL_ASSERT(dot != 0);
1142
return (dot > 0) ? ORIENTATION_COUNTER_CLOCKWISE : ORIENTATION_CLOCKWISE;
1143
}
1144
return ORIENTATION_COUNTER_CLOCKWISE;
1145
} else if (p_prev->prev == p_next) {
1146
return ORIENTATION_CLOCKWISE;
1147
} else {
1148
return ORIENTATION_NONE;
1149
}
1150
}
1151
1152
ConvexHullInternal::Edge *ConvexHullInternal::find_max_angle(bool p_ccw, const Vertex *p_start, const Point32 &p_s, const Point64 &p_rxs, const Point64 &p_sxrxs, Rational64 &p_min_cot) {
1153
Edge *min_edge = nullptr;
1154
1155
#ifdef DEBUG_CONVEX_HULL
1156
printf("find max edge for %d\n", p_start->point.index);
1157
#endif
1158
Edge *e = p_start->edges;
1159
if (e) {
1160
do {
1161
if (e->copy > merge_stamp) {
1162
Point32 t = *e->target - *p_start;
1163
Rational64 cot(t.dot(p_sxrxs), t.dot(p_rxs));
1164
#ifdef DEBUG_CONVEX_HULL
1165
printf(" Angle is %f (%d) for ", Math::atan(cot.to_scalar()), (int32_t)cot.is_nan());
1166
e->print();
1167
#endif
1168
if (cot.is_nan()) {
1169
CHULL_ASSERT(p_ccw ? (t.dot(p_s) < 0) : (t.dot(p_s) > 0));
1170
} else {
1171
int32_t cmp;
1172
if (min_edge == nullptr) {
1173
p_min_cot = cot;
1174
min_edge = e;
1175
} else if ((cmp = cot.compare(p_min_cot)) < 0) {
1176
p_min_cot = cot;
1177
min_edge = e;
1178
} else if ((cmp == 0) && (p_ccw == (get_orientation(min_edge, e, p_s, t) == ORIENTATION_COUNTER_CLOCKWISE))) {
1179
min_edge = e;
1180
}
1181
}
1182
#ifdef DEBUG_CONVEX_HULL
1183
printf("\n");
1184
#endif
1185
}
1186
e = e->next;
1187
} while (e != p_start->edges);
1188
}
1189
return min_edge;
1190
}
1191
1192
void ConvexHullInternal::find_edge_for_coplanar_faces(Vertex *p_c0, Vertex *p_c1, Edge *&p_e0, Edge *&p_e1, const Vertex *p_stop0, const Vertex *p_stop1) {
1193
Edge *start0 = p_e0;
1194
Edge *start1 = p_e1;
1195
Point32 et0 = start0 ? start0->target->point : p_c0->point;
1196
Point32 et1 = start1 ? start1->target->point : p_c1->point;
1197
Point32 s = p_c1->point - p_c0->point;
1198
Point64 normal = ((start0 ? start0 : start1)->target->point - p_c0->point).cross(s);
1199
int64_t dist = p_c0->point.dot(normal);
1200
CHULL_ASSERT(!start1 || (start1->target->point.dot(normal) == dist));
1201
Point64 perp = s.cross(normal);
1202
CHULL_ASSERT(!perp.is_zero());
1203
1204
#ifdef DEBUG_CONVEX_HULL
1205
printf(" Advancing %d %d (%p %p, %d %d)\n", p_c0->point.index, p_c1->point.index, start0, start1, start0 ? start0->target->point.index : -1, start1 ? start1->target->point.index : -1);
1206
#endif
1207
1208
int64_t max_dot0 = et0.dot(perp);
1209
if (p_e0) {
1210
while (p_e0->target != p_stop0) {
1211
Edge *e = p_e0->reverse->prev;
1212
if (e->target->point.dot(normal) < dist) {
1213
break;
1214
}
1215
CHULL_ASSERT(e->target->point.dot(normal) == dist);
1216
if (e->copy == merge_stamp) {
1217
break;
1218
}
1219
int64_t dot = e->target->point.dot(perp);
1220
if (dot <= max_dot0) {
1221
break;
1222
}
1223
max_dot0 = dot;
1224
p_e0 = e;
1225
et0 = e->target->point;
1226
}
1227
}
1228
1229
int64_t max_dot1 = et1.dot(perp);
1230
if (p_e1) {
1231
while (p_e1->target != p_stop1) {
1232
Edge *e = p_e1->reverse->next;
1233
if (e->target->point.dot(normal) < dist) {
1234
break;
1235
}
1236
CHULL_ASSERT(e->target->point.dot(normal) == dist);
1237
if (e->copy == merge_stamp) {
1238
break;
1239
}
1240
int64_t dot = e->target->point.dot(perp);
1241
if (dot <= max_dot1) {
1242
break;
1243
}
1244
max_dot1 = dot;
1245
p_e1 = e;
1246
et1 = e->target->point;
1247
}
1248
}
1249
1250
#ifdef DEBUG_CONVEX_HULL
1251
printf(" Starting at %d %d\n", et0.index, et1.index);
1252
#endif
1253
1254
int64_t dx = max_dot1 - max_dot0;
1255
if (dx > 0) {
1256
while (true) {
1257
int64_t dy = (et1 - et0).dot(s);
1258
1259
if (p_e0 && (p_e0->target != p_stop0)) {
1260
Edge *f0 = p_e0->next->reverse;
1261
if (f0->copy > merge_stamp) {
1262
int64_t dx0 = (f0->target->point - et0).dot(perp);
1263
int64_t dy0 = (f0->target->point - et0).dot(s);
1264
if ((dx0 == 0) ? (dy0 < 0) : ((dx0 < 0) && (Rational64(dy0, dx0).compare(Rational64(dy, dx)) >= 0))) {
1265
et0 = f0->target->point;
1266
dx = (et1 - et0).dot(perp);
1267
p_e0 = (p_e0 == start0) ? nullptr : f0;
1268
continue;
1269
}
1270
}
1271
}
1272
1273
if (p_e1 && (p_e1->target != p_stop1)) {
1274
Edge *f1 = p_e1->reverse->next;
1275
if (f1->copy > merge_stamp) {
1276
Point32 d1 = f1->target->point - et1;
1277
if (d1.dot(normal) == 0) {
1278
int64_t dx1 = d1.dot(perp);
1279
int64_t dy1 = d1.dot(s);
1280
int64_t dxn = (f1->target->point - et0).dot(perp);
1281
if ((dxn > 0) && ((dx1 == 0) ? (dy1 < 0) : ((dx1 < 0) && (Rational64(dy1, dx1).compare(Rational64(dy, dx)) > 0)))) {
1282
p_e1 = f1;
1283
et1 = p_e1->target->point;
1284
dx = dxn;
1285
continue;
1286
}
1287
} else {
1288
CHULL_ASSERT((p_e1 == start1) && (d1.dot(normal) < 0));
1289
}
1290
}
1291
}
1292
1293
break;
1294
}
1295
} else if (dx < 0) {
1296
while (true) {
1297
int64_t dy = (et1 - et0).dot(s);
1298
1299
if (p_e1 && (p_e1->target != p_stop1)) {
1300
Edge *f1 = p_e1->prev->reverse;
1301
if (f1->copy > merge_stamp) {
1302
int64_t dx1 = (f1->target->point - et1).dot(perp);
1303
int64_t dy1 = (f1->target->point - et1).dot(s);
1304
if ((dx1 == 0) ? (dy1 > 0) : ((dx1 < 0) && (Rational64(dy1, dx1).compare(Rational64(dy, dx)) <= 0))) {
1305
et1 = f1->target->point;
1306
dx = (et1 - et0).dot(perp);
1307
p_e1 = (p_e1 == start1) ? nullptr : f1;
1308
continue;
1309
}
1310
}
1311
}
1312
1313
if (p_e0 && (p_e0->target != p_stop0)) {
1314
Edge *f0 = p_e0->reverse->prev;
1315
if (f0->copy > merge_stamp) {
1316
Point32 d0 = f0->target->point - et0;
1317
if (d0.dot(normal) == 0) {
1318
int64_t dx0 = d0.dot(perp);
1319
int64_t dy0 = d0.dot(s);
1320
int64_t dxn = (et1 - f0->target->point).dot(perp);
1321
if ((dxn < 0) && ((dx0 == 0) ? (dy0 > 0) : ((dx0 < 0) && (Rational64(dy0, dx0).compare(Rational64(dy, dx)) < 0)))) {
1322
p_e0 = f0;
1323
et0 = p_e0->target->point;
1324
dx = dxn;
1325
continue;
1326
}
1327
} else {
1328
CHULL_ASSERT((p_e0 == start0) && (d0.dot(normal) < 0));
1329
}
1330
}
1331
}
1332
1333
break;
1334
}
1335
}
1336
#ifdef DEBUG_CONVEX_HULL
1337
printf(" Advanced edges to %d %d\n", et0.index, et1.index);
1338
#endif
1339
}
1340
1341
void ConvexHullInternal::merge(IntermediateHull &p_h0, IntermediateHull &p_h1) {
1342
if (!p_h1.max_xy) {
1343
return;
1344
}
1345
if (!p_h0.max_xy) {
1346
p_h0 = p_h1;
1347
return;
1348
}
1349
1350
merge_stamp--;
1351
1352
Vertex *c0 = nullptr;
1353
Edge *to_prev0 = nullptr;
1354
Edge *first_new0 = nullptr;
1355
Edge *pending_head0 = nullptr;
1356
Edge *pending_tail0 = nullptr;
1357
Vertex *c1 = nullptr;
1358
Edge *to_prev1 = nullptr;
1359
Edge *first_new1 = nullptr;
1360
Edge *pending_head1 = nullptr;
1361
Edge *pending_tail1 = nullptr;
1362
Point32 prev_point;
1363
1364
if (merge_projection(p_h0, p_h1, c0, c1)) {
1365
Point32 s = *c1 - *c0;
1366
Point64 normal = Point32(0, 0, -1).cross(s);
1367
Point64 t = s.cross(normal);
1368
CHULL_ASSERT(!t.is_zero());
1369
1370
Edge *e = c0->edges;
1371
Edge *start0 = nullptr;
1372
if (e) {
1373
do {
1374
int64_t dot = (*e->target - *c0).dot(normal);
1375
CHULL_ASSERT(dot <= 0);
1376
if ((dot == 0) && ((*e->target - *c0).dot(t) > 0)) {
1377
if (!start0 || (get_orientation(start0, e, s, Point32(0, 0, -1)) == ORIENTATION_CLOCKWISE)) {
1378
start0 = e;
1379
}
1380
}
1381
e = e->next;
1382
} while (e != c0->edges);
1383
}
1384
1385
e = c1->edges;
1386
Edge *start1 = nullptr;
1387
if (e) {
1388
do {
1389
int64_t dot = (*e->target - *c1).dot(normal);
1390
CHULL_ASSERT(dot <= 0);
1391
if ((dot == 0) && ((*e->target - *c1).dot(t) > 0)) {
1392
if (!start1 || (get_orientation(start1, e, s, Point32(0, 0, -1)) == ORIENTATION_COUNTER_CLOCKWISE)) {
1393
start1 = e;
1394
}
1395
}
1396
e = e->next;
1397
} while (e != c1->edges);
1398
}
1399
1400
if (start0 || start1) {
1401
find_edge_for_coplanar_faces(c0, c1, start0, start1, nullptr, nullptr);
1402
if (start0) {
1403
c0 = start0->target;
1404
}
1405
if (start1) {
1406
c1 = start1->target;
1407
}
1408
}
1409
1410
prev_point = c1->point;
1411
prev_point.z++;
1412
} else {
1413
prev_point = c1->point;
1414
prev_point.x++;
1415
}
1416
1417
Vertex *first0 = c0;
1418
Vertex *first1 = c1;
1419
bool first_run = true;
1420
1421
while (true) {
1422
Point32 s = *c1 - *c0;
1423
Point32 r = prev_point - c0->point;
1424
Point64 rxs = r.cross(s);
1425
Point64 sxrxs = s.cross(rxs);
1426
1427
#ifdef DEBUG_CONVEX_HULL
1428
printf("\n Checking %d %d\n", c0->point.index, c1->point.index);
1429
#endif
1430
Rational64 min_cot0(0, 0);
1431
Edge *min0 = find_max_angle(false, c0, s, rxs, sxrxs, min_cot0);
1432
Rational64 min_cot1(0, 0);
1433
Edge *min1 = find_max_angle(true, c1, s, rxs, sxrxs, min_cot1);
1434
if (!min0 && !min1) {
1435
Edge *e = new_edge_pair(c0, c1);
1436
e->link(e);
1437
c0->edges = e;
1438
1439
e = e->reverse;
1440
e->link(e);
1441
c1->edges = e;
1442
return;
1443
} else {
1444
int32_t cmp = !min0 ? 1 : (!min1 ? -1 : min_cot0.compare(min_cot1));
1445
#ifdef DEBUG_CONVEX_HULL
1446
printf(" -> Result %d\n", cmp);
1447
#endif
1448
if (first_run || ((cmp >= 0) ? !min_cot1.is_negative_infinity() : !min_cot0.is_negative_infinity())) {
1449
Edge *e = new_edge_pair(c0, c1);
1450
if (pending_tail0) {
1451
pending_tail0->prev = e;
1452
} else {
1453
pending_head0 = e;
1454
}
1455
e->next = pending_tail0;
1456
pending_tail0 = e;
1457
1458
e = e->reverse;
1459
if (pending_tail1) {
1460
pending_tail1->next = e;
1461
} else {
1462
pending_head1 = e;
1463
}
1464
e->prev = pending_tail1;
1465
pending_tail1 = e;
1466
}
1467
1468
Edge *e0 = min0;
1469
Edge *e1 = min1;
1470
1471
#ifdef DEBUG_CONVEX_HULL
1472
printf(" Found min edges to %d %d\n", e0 ? e0->target->point.index : -1, e1 ? e1->target->point.index : -1);
1473
#endif
1474
1475
if (cmp == 0) {
1476
find_edge_for_coplanar_faces(c0, c1, e0, e1, nullptr, nullptr);
1477
}
1478
1479
if ((cmp >= 0) && e1) {
1480
if (to_prev1) {
1481
for (Edge *e = to_prev1->next, *n = nullptr; e != min1; e = n) {
1482
n = e->next;
1483
remove_edge_pair(e);
1484
}
1485
}
1486
1487
if (pending_tail1) {
1488
if (to_prev1) {
1489
to_prev1->link(pending_head1);
1490
} else {
1491
min1->prev->link(pending_head1);
1492
first_new1 = pending_head1;
1493
}
1494
pending_tail1->link(min1);
1495
pending_head1 = nullptr;
1496
pending_tail1 = nullptr;
1497
} else if (!to_prev1) {
1498
first_new1 = min1;
1499
}
1500
1501
prev_point = c1->point;
1502
c1 = e1->target;
1503
to_prev1 = e1->reverse;
1504
}
1505
1506
if ((cmp <= 0) && e0) {
1507
if (to_prev0) {
1508
for (Edge *e = to_prev0->prev, *n = nullptr; e != min0; e = n) {
1509
n = e->prev;
1510
remove_edge_pair(e);
1511
}
1512
}
1513
1514
if (pending_tail0) {
1515
if (to_prev0) {
1516
pending_head0->link(to_prev0);
1517
} else {
1518
pending_head0->link(min0->next);
1519
first_new0 = pending_head0;
1520
}
1521
min0->link(pending_tail0);
1522
pending_head0 = nullptr;
1523
pending_tail0 = nullptr;
1524
} else if (!to_prev0) {
1525
first_new0 = min0;
1526
}
1527
1528
prev_point = c0->point;
1529
c0 = e0->target;
1530
to_prev0 = e0->reverse;
1531
}
1532
}
1533
1534
if ((c0 == first0) && (c1 == first1)) {
1535
if (to_prev0 == nullptr) {
1536
pending_head0->link(pending_tail0);
1537
c0->edges = pending_tail0;
1538
} else {
1539
for (Edge *e = to_prev0->prev, *n = nullptr; e != first_new0; e = n) {
1540
n = e->prev;
1541
remove_edge_pair(e);
1542
}
1543
if (pending_tail0) {
1544
pending_head0->link(to_prev0);
1545
first_new0->link(pending_tail0);
1546
}
1547
}
1548
1549
if (to_prev1 == nullptr) {
1550
pending_tail1->link(pending_head1);
1551
c1->edges = pending_tail1;
1552
} else {
1553
for (Edge *e = to_prev1->next, *n = nullptr; e != first_new1; e = n) {
1554
n = e->next;
1555
remove_edge_pair(e);
1556
}
1557
if (pending_tail1) {
1558
to_prev1->link(pending_head1);
1559
pending_tail1->link(first_new1);
1560
}
1561
}
1562
1563
return;
1564
}
1565
1566
first_run = false;
1567
}
1568
}
1569
1570
struct PointComparator {
1571
_FORCE_INLINE_ bool operator()(const ConvexHullInternal::Point32 &p, const ConvexHullInternal::Point32 &q) const {
1572
return (p.y < q.y) || ((p.y == q.y) && ((p.x < q.x) || ((p.x == q.x) && (p.z < q.z))));
1573
}
1574
};
1575
1576
void ConvexHullInternal::compute(const Vector3 *p_coords, int32_t p_count) {
1577
AABB aabb;
1578
for (int32_t i = 0; i < p_count; i++) {
1579
Vector3 p = p_coords[i];
1580
if (i == 0) {
1581
aabb.position = p;
1582
} else {
1583
aabb.expand_to(p);
1584
}
1585
}
1586
1587
Vector3 s = aabb.size;
1588
max_axis = s.max_axis_index();
1589
min_axis = s.min_axis_index();
1590
if (min_axis == max_axis) {
1591
min_axis = Vector3::Axis((max_axis + 1) % 3);
1592
}
1593
med_axis = Vector3::Axis(3 - max_axis - min_axis);
1594
1595
s /= real_t(10216);
1596
if (((med_axis + 1) % 3) != max_axis) {
1597
s *= -1;
1598
}
1599
scaling = s;
1600
1601
if (s[0] != 0) {
1602
s[0] = real_t(1) / s[0];
1603
}
1604
if (s[1] != 0) {
1605
s[1] = real_t(1) / s[1];
1606
}
1607
if (s[2] != 0) {
1608
s[2] = real_t(1) / s[2];
1609
}
1610
1611
center = aabb.position;
1612
1613
LocalVector<Point32> points;
1614
points.resize(p_count);
1615
for (int32_t i = 0; i < p_count; i++) {
1616
Vector3 p = p_coords[i];
1617
p = (p - center) * s;
1618
points[i].x = (int32_t)p[med_axis];
1619
points[i].y = (int32_t)p[max_axis];
1620
points[i].z = (int32_t)p[min_axis];
1621
points[i].index = i;
1622
}
1623
1624
points.sort_custom<PointComparator>();
1625
1626
vertex_pool.reset(true);
1627
original_vertices.resize(p_count);
1628
for (int32_t i = 0; i < p_count; i++) {
1629
Vertex *v = vertex_pool.alloc();
1630
v->edges = nullptr;
1631
v->point = points[i];
1632
v->copy = -1;
1633
original_vertices[i] = v;
1634
}
1635
1636
points.clear();
1637
1638
edge_pool.reset(true);
1639
1640
used_edge_pairs = 0;
1641
max_used_edge_pairs = 0;
1642
1643
merge_stamp = -3;
1644
1645
IntermediateHull hull;
1646
compute_internal(0, p_count, hull);
1647
vertex_list = hull.min_xy;
1648
#ifdef DEBUG_CONVEX_HULL
1649
printf("max. edges %d (3v = %d)", max_used_edge_pairs, 3 * p_count);
1650
#endif
1651
}
1652
1653
Vector3 ConvexHullInternal::to_gd_vector(const Point32 &p_v) {
1654
Vector3 p;
1655
p[med_axis] = real_t(p_v.x);
1656
p[max_axis] = real_t(p_v.y);
1657
p[min_axis] = real_t(p_v.z);
1658
return p * scaling;
1659
}
1660
1661
Vector3 ConvexHullInternal::get_gd_normal(Face *p_face) {
1662
return to_gd_vector(p_face->dir0).cross(to_gd_vector(p_face->dir1)).normalized();
1663
}
1664
1665
Vector3 ConvexHullInternal::get_coordinates(const Vertex *p_v) {
1666
Vector3 p;
1667
p[med_axis] = p_v->xvalue();
1668
p[max_axis] = p_v->yvalue();
1669
p[min_axis] = p_v->zvalue();
1670
return p * scaling + center;
1671
}
1672
1673
real_t ConvexHullInternal::shrink(real_t p_amount, real_t p_clamp_amount) {
1674
if (!vertex_list) {
1675
return 0;
1676
}
1677
int32_t stamp = --merge_stamp;
1678
LocalVector<Vertex *> stack;
1679
vertex_list->copy = stamp;
1680
stack.push_back(vertex_list);
1681
LocalVector<Face *> faces;
1682
1683
Point32 ref = vertex_list->point;
1684
Int128 hull_center_x(0, 0);
1685
Int128 hull_center_y(0, 0);
1686
Int128 hull_center_z(0, 0);
1687
Int128 volume(0, 0);
1688
1689
while (stack.size() > 0) {
1690
Vertex *v = stack[stack.size() - 1];
1691
stack.remove_at(stack.size() - 1);
1692
Edge *e = v->edges;
1693
if (e) {
1694
do {
1695
if (e->target->copy != stamp) {
1696
e->target->copy = stamp;
1697
stack.push_back(e->target);
1698
}
1699
if (e->copy != stamp) {
1700
Face *face = face_pool.alloc();
1701
face->init(e->target, e->reverse->prev->target, v);
1702
faces.push_back(face);
1703
Edge *f = e;
1704
1705
Vertex *a = nullptr;
1706
Vertex *b = nullptr;
1707
do {
1708
if (a && b) {
1709
int64_t vol = (v->point - ref).dot((a->point - ref).cross(b->point - ref));
1710
CHULL_ASSERT(vol >= 0);
1711
Point32 c = v->point + a->point + b->point + ref;
1712
hull_center_x += vol * c.x;
1713
hull_center_y += vol * c.y;
1714
hull_center_z += vol * c.z;
1715
volume += vol;
1716
}
1717
1718
CHULL_ASSERT(f->copy != stamp);
1719
f->copy = stamp;
1720
f->face = face;
1721
1722
a = b;
1723
b = f->target;
1724
1725
f = f->reverse->prev;
1726
} while (f != e);
1727
}
1728
e = e->next;
1729
} while (e != v->edges);
1730
}
1731
}
1732
1733
if (volume.get_sign() <= 0) {
1734
return 0;
1735
}
1736
1737
Vector3 hull_center;
1738
hull_center[med_axis] = hull_center_x.to_scalar();
1739
hull_center[max_axis] = hull_center_y.to_scalar();
1740
hull_center[min_axis] = hull_center_z.to_scalar();
1741
hull_center /= 4 * volume.to_scalar();
1742
hull_center *= scaling;
1743
1744
int32_t face_count = faces.size();
1745
1746
if (p_clamp_amount > 0) {
1747
real_t min_dist = FLT_MAX;
1748
for (int32_t i = 0; i < face_count; i++) {
1749
Vector3 normal = get_gd_normal(faces[i]);
1750
real_t dist = normal.dot(to_gd_vector(faces[i]->origin) - hull_center);
1751
if (dist < min_dist) {
1752
min_dist = dist;
1753
}
1754
}
1755
1756
if (min_dist <= 0) {
1757
return 0;
1758
}
1759
1760
p_amount = MIN(p_amount, min_dist * p_clamp_amount);
1761
}
1762
1763
uint32_t seed = 243703;
1764
for (int32_t i = 0; i < face_count; i++, seed = 1664525 * seed + 1013904223) {
1765
SWAP(faces[i], faces[seed % face_count]);
1766
}
1767
1768
for (int32_t i = 0; i < face_count; i++) {
1769
if (!shift_face(faces[i], p_amount, stack)) {
1770
return -p_amount;
1771
}
1772
}
1773
1774
return p_amount;
1775
}
1776
1777
bool ConvexHullInternal::shift_face(Face *p_face, real_t p_amount, LocalVector<Vertex *> &p_stack) {
1778
Vector3 orig_shift = get_gd_normal(p_face) * -p_amount;
1779
if (scaling[0] != 0) {
1780
orig_shift[0] /= scaling[0];
1781
}
1782
if (scaling[1] != 0) {
1783
orig_shift[1] /= scaling[1];
1784
}
1785
if (scaling[2] != 0) {
1786
orig_shift[2] /= scaling[2];
1787
}
1788
Point32 shift((int32_t)orig_shift[med_axis], (int32_t)orig_shift[max_axis], (int32_t)orig_shift[min_axis]);
1789
if (shift.is_zero()) {
1790
return true;
1791
}
1792
Point64 normal = p_face->get_normal();
1793
#ifdef DEBUG_CONVEX_HULL
1794
printf("\nShrinking p_face (%d %d %d) (%d %d %d) (%d %d %d) by (%d %d %d)\n",
1795
p_face->origin.x, p_face->origin.y, p_face->origin.z, p_face->dir0.x, p_face->dir0.y, p_face->dir0.z, p_face->dir1.x, p_face->dir1.y, p_face->dir1.z, shift.x, shift.y, shift.z);
1796
#endif
1797
int64_t orig_dot = p_face->origin.dot(normal);
1798
Point32 shifted_origin = p_face->origin + shift;
1799
int64_t shifted_dot = shifted_origin.dot(normal);
1800
CHULL_ASSERT(shifted_dot <= orig_dot);
1801
if (shifted_dot >= orig_dot) {
1802
return false;
1803
}
1804
1805
Edge *intersection = nullptr;
1806
1807
Edge *start_edge = p_face->nearby_vertex->edges;
1808
#ifdef DEBUG_CONVEX_HULL
1809
printf("Start edge is ");
1810
start_edge->print();
1811
printf(", normal is (%lld %lld %lld), shifted dot is %lld\n", normal.x, normal.y, normal.z, shifted_dot);
1812
#endif
1813
Rational128 opt_dot = p_face->nearby_vertex->dot(normal);
1814
int32_t cmp = opt_dot.compare(shifted_dot);
1815
#ifdef SHOW_ITERATIONS
1816
int32_t n = 0;
1817
#endif
1818
if (cmp >= 0) {
1819
Edge *e = start_edge;
1820
do {
1821
#ifdef SHOW_ITERATIONS
1822
n++;
1823
#endif
1824
Rational128 dot = e->target->dot(normal);
1825
CHULL_ASSERT(dot.compare(orig_dot) <= 0);
1826
#ifdef DEBUG_CONVEX_HULL
1827
printf("Moving downwards, edge is ");
1828
e->print();
1829
printf(", dot is %f (%f %lld)\n", (float)dot.to_scalar(), (float)opt_dot.to_scalar(), shifted_dot);
1830
#endif
1831
if (dot.compare(opt_dot) < 0) {
1832
int32_t c = dot.compare(shifted_dot);
1833
opt_dot = dot;
1834
e = e->reverse;
1835
start_edge = e;
1836
if (c < 0) {
1837
intersection = e;
1838
break;
1839
}
1840
cmp = c;
1841
}
1842
e = e->prev;
1843
} while (e != start_edge);
1844
1845
if (!intersection) {
1846
return false;
1847
}
1848
} else {
1849
Edge *e = start_edge;
1850
do {
1851
#ifdef SHOW_ITERATIONS
1852
n++;
1853
#endif
1854
Rational128 dot = e->target->dot(normal);
1855
CHULL_ASSERT(dot.compare(orig_dot) <= 0);
1856
#ifdef DEBUG_CONVEX_HULL
1857
printf("Moving upwards, edge is ");
1858
e->print();
1859
printf(", dot is %f (%f %lld)\n", (float)dot.to_scalar(), (float)opt_dot.to_scalar(), shifted_dot);
1860
#endif
1861
if (dot.compare(opt_dot) > 0) {
1862
cmp = dot.compare(shifted_dot);
1863
if (cmp >= 0) {
1864
intersection = e;
1865
break;
1866
}
1867
opt_dot = dot;
1868
e = e->reverse;
1869
start_edge = e;
1870
}
1871
e = e->prev;
1872
} while (e != start_edge);
1873
1874
if (!intersection) {
1875
return true;
1876
}
1877
}
1878
1879
#ifdef SHOW_ITERATIONS
1880
printf("Needed %d iterations to find initial intersection\n", n);
1881
#endif
1882
1883
if (cmp == 0) {
1884
Edge *e = intersection->reverse->next;
1885
#ifdef SHOW_ITERATIONS
1886
n = 0;
1887
#endif
1888
while (e->target->dot(normal).compare(shifted_dot) <= 0) {
1889
#ifdef SHOW_ITERATIONS
1890
n++;
1891
#endif
1892
e = e->next;
1893
if (e == intersection->reverse) {
1894
return true;
1895
}
1896
#ifdef DEBUG_CONVEX_HULL
1897
printf("Checking for outwards edge, current edge is ");
1898
e->print();
1899
printf("\n");
1900
#endif
1901
}
1902
#ifdef SHOW_ITERATIONS
1903
printf("Needed %d iterations to check for complete containment\n", n);
1904
#endif
1905
}
1906
1907
Edge *first_intersection = nullptr;
1908
Edge *face_edge = nullptr;
1909
Edge *first_face_edge = nullptr;
1910
1911
#ifdef SHOW_ITERATIONS
1912
int32_t m = 0;
1913
#endif
1914
while (true) {
1915
#ifdef SHOW_ITERATIONS
1916
m++;
1917
#endif
1918
#ifdef DEBUG_CONVEX_HULL
1919
printf("Intersecting edge is ");
1920
intersection->print();
1921
printf("\n");
1922
#endif
1923
if (cmp == 0) {
1924
Edge *e = intersection->reverse->next;
1925
start_edge = e;
1926
#ifdef SHOW_ITERATIONS
1927
n = 0;
1928
#endif
1929
while (true) {
1930
#ifdef SHOW_ITERATIONS
1931
n++;
1932
#endif
1933
if (e->target->dot(normal).compare(shifted_dot) >= 0) {
1934
break;
1935
}
1936
intersection = e->reverse;
1937
e = e->next;
1938
if (e == start_edge) {
1939
return true;
1940
}
1941
}
1942
#ifdef SHOW_ITERATIONS
1943
printf("Needed %d iterations to advance intersection\n", n);
1944
#endif
1945
}
1946
1947
#ifdef DEBUG_CONVEX_HULL
1948
printf("Advanced intersecting edge to ");
1949
intersection->print();
1950
printf(", cmp = %d\n", cmp);
1951
#endif
1952
1953
if (!first_intersection) {
1954
first_intersection = intersection;
1955
} else if (intersection == first_intersection) {
1956
break;
1957
}
1958
1959
int32_t prev_cmp = cmp;
1960
Edge *prev_intersection = intersection;
1961
Edge *prev_face_edge = face_edge;
1962
1963
Edge *e = intersection->reverse;
1964
#ifdef SHOW_ITERATIONS
1965
n = 0;
1966
#endif
1967
while (true) {
1968
#ifdef SHOW_ITERATIONS
1969
n++;
1970
#endif
1971
e = e->reverse->prev;
1972
CHULL_ASSERT(e != intersection->reverse);
1973
cmp = e->target->dot(normal).compare(shifted_dot);
1974
#ifdef DEBUG_CONVEX_HULL
1975
printf("Testing edge ");
1976
e->print();
1977
printf(" -> cmp = %d\n", cmp);
1978
#endif
1979
if (cmp >= 0) {
1980
intersection = e;
1981
break;
1982
}
1983
}
1984
#ifdef SHOW_ITERATIONS
1985
printf("Needed %d iterations to find other intersection of p_face\n", n);
1986
#endif
1987
1988
if (cmp > 0) {
1989
Vertex *removed = intersection->target;
1990
e = intersection->reverse;
1991
if (e->prev == e) {
1992
removed->edges = nullptr;
1993
} else {
1994
removed->edges = e->prev;
1995
e->prev->link(e->next);
1996
e->link(e);
1997
}
1998
#ifdef DEBUG_CONVEX_HULL
1999
printf("1: Removed part contains (%d %d %d)\n", removed->point.x, removed->point.y, removed->point.z);
2000
#endif
2001
2002
Point64 n0 = intersection->face->get_normal();
2003
Point64 n1 = intersection->reverse->face->get_normal();
2004
int64_t m00 = p_face->dir0.dot(n0);
2005
int64_t m01 = p_face->dir1.dot(n0);
2006
int64_t m10 = p_face->dir0.dot(n1);
2007
int64_t m11 = p_face->dir1.dot(n1);
2008
int64_t r0 = (intersection->face->origin - shifted_origin).dot(n0);
2009
int64_t r1 = (intersection->reverse->face->origin - shifted_origin).dot(n1);
2010
Int128 det = Int128::mul(m00, m11) - Int128::mul(m01, m10);
2011
CHULL_ASSERT(det.get_sign() != 0);
2012
Vertex *v = vertex_pool.alloc();
2013
v->point.index = -1;
2014
v->copy = -1;
2015
v->point128 = PointR128(Int128::mul(p_face->dir0.x * r0, m11) - Int128::mul(p_face->dir0.x * r1, m01) + Int128::mul(p_face->dir1.x * r1, m00) - Int128::mul(p_face->dir1.x * r0, m10) + det * shifted_origin.x,
2016
Int128::mul(p_face->dir0.y * r0, m11) - Int128::mul(p_face->dir0.y * r1, m01) + Int128::mul(p_face->dir1.y * r1, m00) - Int128::mul(p_face->dir1.y * r0, m10) + det * shifted_origin.y,
2017
Int128::mul(p_face->dir0.z * r0, m11) - Int128::mul(p_face->dir0.z * r1, m01) + Int128::mul(p_face->dir1.z * r1, m00) - Int128::mul(p_face->dir1.z * r0, m10) + det * shifted_origin.z,
2018
det);
2019
v->point.x = (int32_t)v->point128.xvalue();
2020
v->point.y = (int32_t)v->point128.yvalue();
2021
v->point.z = (int32_t)v->point128.zvalue();
2022
intersection->target = v;
2023
v->edges = e;
2024
2025
p_stack.push_back(v);
2026
p_stack.push_back(removed);
2027
p_stack.push_back(nullptr);
2028
}
2029
2030
if (cmp || prev_cmp || (prev_intersection->reverse->next->target != intersection->target)) {
2031
face_edge = new_edge_pair(prev_intersection->target, intersection->target);
2032
if (prev_cmp == 0) {
2033
face_edge->link(prev_intersection->reverse->next);
2034
}
2035
if ((prev_cmp == 0) || prev_face_edge) {
2036
prev_intersection->reverse->link(face_edge);
2037
}
2038
if (cmp == 0) {
2039
intersection->reverse->prev->link(face_edge->reverse);
2040
}
2041
face_edge->reverse->link(intersection->reverse);
2042
} else {
2043
face_edge = prev_intersection->reverse->next;
2044
}
2045
2046
if (prev_face_edge) {
2047
if (prev_cmp > 0) {
2048
face_edge->link(prev_face_edge->reverse);
2049
} else if (face_edge != prev_face_edge->reverse) {
2050
p_stack.push_back(prev_face_edge->target);
2051
while (face_edge->next != prev_face_edge->reverse) {
2052
Vertex *removed = face_edge->next->target;
2053
remove_edge_pair(face_edge->next);
2054
p_stack.push_back(removed);
2055
#ifdef DEBUG_CONVEX_HULL
2056
printf("2: Removed part contains (%d %d %d)\n", removed->point.x, removed->point.y, removed->point.z);
2057
#endif
2058
}
2059
p_stack.push_back(nullptr);
2060
}
2061
}
2062
face_edge->face = p_face;
2063
face_edge->reverse->face = intersection->face;
2064
2065
if (!first_face_edge) {
2066
first_face_edge = face_edge;
2067
}
2068
}
2069
#ifdef SHOW_ITERATIONS
2070
printf("Needed %d iterations to process all intersections\n", m);
2071
#endif
2072
2073
if (cmp > 0) {
2074
first_face_edge->reverse->target = face_edge->target;
2075
first_intersection->reverse->link(first_face_edge);
2076
first_face_edge->link(face_edge->reverse);
2077
} else if (first_face_edge != face_edge->reverse) {
2078
p_stack.push_back(face_edge->target);
2079
while (first_face_edge->next != face_edge->reverse) {
2080
Vertex *removed = first_face_edge->next->target;
2081
remove_edge_pair(first_face_edge->next);
2082
p_stack.push_back(removed);
2083
#ifdef DEBUG_CONVEX_HULL
2084
printf("3: Removed part contains (%d %d %d)\n", removed->point.x, removed->point.y, removed->point.z);
2085
#endif
2086
}
2087
p_stack.push_back(nullptr);
2088
}
2089
2090
CHULL_ASSERT(p_stack.size() > 0);
2091
vertex_list = p_stack[0];
2092
2093
#ifdef DEBUG_CONVEX_HULL
2094
printf("Removing part\n");
2095
#endif
2096
#ifdef SHOW_ITERATIONS
2097
n = 0;
2098
#endif
2099
uint32_t pos = 0;
2100
while (pos < p_stack.size()) {
2101
uint32_t end = p_stack.size();
2102
while (pos < end) {
2103
Vertex *kept = p_stack[pos++];
2104
#ifdef DEBUG_CONVEX_HULL
2105
kept->print();
2106
#endif
2107
bool deeper = false;
2108
Vertex *removed;
2109
while ((removed = p_stack[pos++]) != nullptr) {
2110
#ifdef SHOW_ITERATIONS
2111
n++;
2112
#endif
2113
kept->receive_nearby_faces(removed);
2114
while (removed->edges) {
2115
if (!deeper) {
2116
deeper = true;
2117
p_stack.push_back(kept);
2118
}
2119
p_stack.push_back(removed->edges->target);
2120
remove_edge_pair(removed->edges);
2121
}
2122
}
2123
if (deeper) {
2124
p_stack.push_back(nullptr);
2125
}
2126
}
2127
}
2128
#ifdef SHOW_ITERATIONS
2129
printf("Needed %d iterations to remove part\n", n);
2130
#endif
2131
2132
p_stack.clear();
2133
p_face->origin = shifted_origin;
2134
2135
return true;
2136
}
2137
2138
static int32_t get_vertex_copy(ConvexHullInternal::Vertex *p_vertex, LocalVector<ConvexHullInternal::Vertex *> &p_vertices) {
2139
int32_t index = p_vertex->copy;
2140
if (index < 0) {
2141
index = p_vertices.size();
2142
p_vertex->copy = index;
2143
p_vertices.push_back(p_vertex);
2144
#ifdef DEBUG_CONVEX_HULL
2145
printf("Vertex %d gets index *%d\n", p_vertex->point.index, index);
2146
#endif
2147
}
2148
return index;
2149
}
2150
2151
real_t ConvexHullComputer::compute(const Vector3 *p_coords, int32_t p_count, real_t p_shrink, real_t p_shrink_clamp) {
2152
vertices.clear();
2153
edges.clear();
2154
faces.clear();
2155
2156
if (p_count <= 0) {
2157
return 0;
2158
}
2159
2160
ConvexHullInternal hull;
2161
hull.compute(p_coords, p_count);
2162
2163
real_t shift = 0;
2164
if ((p_shrink > 0) && ((shift = hull.shrink(p_shrink, p_shrink_clamp)) < 0)) {
2165
return shift;
2166
}
2167
2168
LocalVector<ConvexHullInternal::Vertex *> old_vertices;
2169
get_vertex_copy(hull.vertex_list, old_vertices);
2170
int32_t copied = 0;
2171
while (copied < (int32_t)old_vertices.size()) {
2172
ConvexHullInternal::Vertex *v = old_vertices[copied];
2173
vertices.push_back(hull.get_coordinates(v));
2174
ConvexHullInternal::Edge *first_edge = v->edges;
2175
if (first_edge) {
2176
int32_t first_copy = -1;
2177
int32_t prev_copy = -1;
2178
ConvexHullInternal::Edge *e = first_edge;
2179
do {
2180
if (e->copy < 0) {
2181
int32_t s = edges.size();
2182
edges.push_back(Edge());
2183
edges.push_back(Edge());
2184
Edge *c = &edges[s];
2185
Edge *r = &edges[s + 1];
2186
e->copy = s;
2187
e->reverse->copy = s + 1;
2188
c->reverse = 1;
2189
r->reverse = -1;
2190
c->target_vertex = get_vertex_copy(e->target, old_vertices);
2191
r->target_vertex = copied;
2192
#ifdef DEBUG_CONVEX_HULL
2193
printf(" CREATE: Vertex *%d has edge to *%d\n", copied, c->get_target_vertex());
2194
#endif
2195
}
2196
if (prev_copy >= 0) {
2197
edges[e->copy].next = prev_copy - e->copy;
2198
} else {
2199
first_copy = e->copy;
2200
}
2201
prev_copy = e->copy;
2202
e = e->next;
2203
} while (e != first_edge);
2204
edges[first_copy].next = prev_copy - first_copy;
2205
}
2206
copied++;
2207
}
2208
2209
for (int32_t i = 0; i < copied; i++) {
2210
ConvexHullInternal::Vertex *v = old_vertices[i];
2211
ConvexHullInternal::Edge *first_edge = v->edges;
2212
if (first_edge) {
2213
ConvexHullInternal::Edge *e = first_edge;
2214
do {
2215
if (e->copy >= 0) {
2216
#ifdef DEBUG_CONVEX_HULL
2217
printf("Vertex *%d has edge to *%d\n", i, edges[e->copy].get_target_vertex());
2218
#endif
2219
faces.push_back(e->copy);
2220
ConvexHullInternal::Edge *f = e;
2221
do {
2222
#ifdef DEBUG_CONVEX_HULL
2223
printf(" Face *%d\n", edges[f->copy].get_target_vertex());
2224
#endif
2225
f->copy = -1;
2226
f = f->reverse->prev;
2227
} while (f != e);
2228
}
2229
e = e->next;
2230
} while (e != first_edge);
2231
}
2232
}
2233
2234
return shift;
2235
}
2236
2237
Error ConvexHullComputer::convex_hull(const Vector<Vector3> &p_points, Geometry3D::MeshData &r_mesh) {
2238
r_mesh = Geometry3D::MeshData(); // clear
2239
2240
if (p_points.is_empty()) {
2241
return FAILED; // matches QuickHull
2242
}
2243
2244
ConvexHullComputer ch;
2245
ch.compute(p_points.ptr(), p_points.size(), -1.0, -1.0);
2246
2247
r_mesh.vertices = ch.vertices;
2248
2249
// Tag which face each edge belongs to
2250
LocalVector<int32_t> edge_faces;
2251
edge_faces.resize(ch.edges.size());
2252
2253
for (uint32_t i = 0; i < ch.edges.size(); i++) {
2254
edge_faces[i] = -1;
2255
}
2256
2257
for (uint32_t i = 0; i < ch.faces.size(); i++) {
2258
const Edge *e_start = &ch.edges[ch.faces[i]];
2259
const Edge *e = e_start;
2260
do {
2261
int64_t ofs = e - ch.edges.ptr();
2262
edge_faces[ofs] = i;
2263
2264
e = e->get_next_edge_of_face();
2265
} while (e != e_start);
2266
}
2267
2268
// Copy the edges over. There's two "half-edges" for every edge, so we pick only one of them.
2269
r_mesh.edges.resize(ch.edges.size() / 2);
2270
AHashMap<uint64_t, int32_t> edge_map(ch.edges.size() * 4); // The higher the capacity, the faster the insert
2271
2272
uint32_t edges_copied = 0;
2273
for (uint32_t i = 0; i < ch.edges.size(); i++) {
2274
ERR_CONTINUE(edge_faces[i] == -1); // Safety check.
2275
2276
uint32_t a = (&ch.edges[i])->get_source_vertex();
2277
uint32_t b = (&ch.edges[i])->get_target_vertex();
2278
if (a < b) { // Copy only the "canonical" edge. For the reverse edge, this will be false.
2279
ERR_BREAK(edges_copied >= (uint32_t)r_mesh.edges.size());
2280
r_mesh.edges[edges_copied].vertex_a = a;
2281
r_mesh.edges[edges_copied].vertex_b = b;
2282
r_mesh.edges[edges_copied].face_a = edge_faces[i];
2283
r_mesh.edges[edges_copied].face_b = -1;
2284
2285
uint64_t key = a;
2286
key <<= 32;
2287
key |= b;
2288
edge_map.insert(key, edges_copied);
2289
2290
edges_copied++;
2291
} else {
2292
uint64_t key = b;
2293
key <<= 32;
2294
key |= a;
2295
int32_t *index_ptr = edge_map.getptr(key);
2296
if (!index_ptr) {
2297
ERR_PRINT("Invalid edge");
2298
} else {
2299
r_mesh.edges[*index_ptr].face_b = edge_faces[i];
2300
}
2301
}
2302
}
2303
2304
if (edges_copied != (uint32_t)r_mesh.edges.size()) {
2305
ERR_PRINT("Invalid edge count.");
2306
}
2307
2308
r_mesh.faces.resize(ch.faces.size());
2309
for (uint32_t i = 0; i < ch.faces.size(); i++) {
2310
const Edge *e_start = &ch.edges[ch.faces[i]];
2311
const Edge *e = e_start;
2312
Geometry3D::MeshData::Face &face = r_mesh.faces[i];
2313
2314
do {
2315
face.indices.push_back(e->get_target_vertex());
2316
2317
e = e->get_next_edge_of_face();
2318
} while (e != e_start);
2319
2320
// reverse indices: Godot wants clockwise, but this is counter-clockwise
2321
if (face.indices.size() > 2) {
2322
// reverse all but the first index.
2323
int *indices = face.indices.ptr();
2324
for (uint32_t c = 0; c < (face.indices.size() - 1) / 2; c++) {
2325
SWAP(indices[c + 1], indices[face.indices.size() - 1 - c]);
2326
}
2327
}
2328
2329
// compute normal
2330
if (face.indices.size() >= 3) {
2331
face.plane = Plane(r_mesh.vertices[face.indices[0]], r_mesh.vertices[face.indices[1]], r_mesh.vertices[face.indices[2]]);
2332
} else {
2333
WARN_PRINT("Too few vertices per face.");
2334
}
2335
}
2336
2337
return OK;
2338
}
2339
2340