Blender V4.3
math_geom.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include "BLI_array.hh"
10#include "BLI_math_base.h"
11#include "BLI_math_base.hh"
12#include "BLI_math_geom.h"
13
14#include "BLI_math_bits.h"
15#include "BLI_math_matrix.h"
16#include "BLI_math_rotation.h"
17#include "BLI_math_vector.h"
18#include "BLI_utildefines.h"
19
20#include "BLI_strict_flags.h" /* Keep last. */
21
22/********************************** Polygons *********************************/
23
24void cross_tri_v3(float n[3], const float v1[3], const float v2[3], const float v3[3])
25{
26 float n1[3], n2[3];
27
28 n1[0] = v1[0] - v2[0];
29 n2[0] = v2[0] - v3[0];
30 n1[1] = v1[1] - v2[1];
31 n2[1] = v2[1] - v3[1];
32 n1[2] = v1[2] - v2[2];
33 n2[2] = v2[2] - v3[2];
34 n[0] = n1[1] * n2[2] - n1[2] * n2[1];
35 n[1] = n1[2] * n2[0] - n1[0] * n2[2];
36 n[2] = n1[0] * n2[1] - n1[1] * n2[0];
37}
38
39float normal_tri_v3(float n[3], const float v1[3], const float v2[3], const float v3[3])
40{
41 float n1[3], n2[3];
42
43 n1[0] = v1[0] - v2[0];
44 n2[0] = v2[0] - v3[0];
45 n1[1] = v1[1] - v2[1];
46 n2[1] = v2[1] - v3[1];
47 n1[2] = v1[2] - v2[2];
48 n2[2] = v2[2] - v3[2];
49 n[0] = n1[1] * n2[2] - n1[2] * n2[1];
50 n[1] = n1[2] * n2[0] - n1[0] * n2[2];
51 n[2] = n1[0] * n2[1] - n1[1] * n2[0];
52
53 return normalize_v3(n);
54}
55
57 float n[3], const float v1[3], const float v2[3], const float v3[3], const float v4[3])
58{
59 /* real cross! */
60 float n1[3], n2[3];
61
62 n1[0] = v1[0] - v3[0];
63 n1[1] = v1[1] - v3[1];
64 n1[2] = v1[2] - v3[2];
65
66 n2[0] = v2[0] - v4[0];
67 n2[1] = v2[1] - v4[1];
68 n2[2] = v2[2] - v4[2];
69
70 n[0] = n1[1] * n2[2] - n1[2] * n2[1];
71 n[1] = n1[2] * n2[0] - n1[0] * n2[2];
72 n[2] = n1[0] * n2[1] - n1[1] * n2[0];
73
74 return normalize_v3(n);
75}
76
77float normal_poly_v3(float n[3], const float verts[][3], uint nr)
78{
79 cross_poly_v3(n, verts, nr);
80 return normalize_v3(n);
81}
82
83float area_quad_v3(const float v1[3], const float v2[3], const float v3[3], const float v4[3])
84{
85 const float verts[4][3] = {{UNPACK3(v1)}, {UNPACK3(v2)}, {UNPACK3(v3)}, {UNPACK3(v4)}};
86 return area_poly_v3(verts, 4);
87}
88
89float area_squared_quad_v3(const float v1[3],
90 const float v2[3],
91 const float v3[3],
92 const float v4[3])
93{
94 const float verts[4][3] = {{UNPACK3(v1)}, {UNPACK3(v2)}, {UNPACK3(v3)}, {UNPACK3(v4)}};
95 return area_squared_poly_v3(verts, 4);
96}
97
98float area_tri_v3(const float v1[3], const float v2[3], const float v3[3])
99{
100 float n[3];
101 cross_tri_v3(n, v1, v2, v3);
102 return len_v3(n) * 0.5f;
103}
104
105float area_squared_tri_v3(const float v1[3], const float v2[3], const float v3[3])
106{
107 float n[3];
108 cross_tri_v3(n, v1, v2, v3);
109 mul_v3_fl(n, 0.5f);
110 return len_squared_v3(n);
111}
112
113float area_tri_signed_v3(const float v1[3],
114 const float v2[3],
115 const float v3[3],
116 const float normal[3])
117{
118 float area, n[3];
119
120 cross_tri_v3(n, v1, v2, v3);
121 area = len_v3(n) * 0.5f;
122
123 /* negate area for flipped triangles */
124 if (dot_v3v3(n, normal) < 0.0f) {
125 area = -area;
126 }
127
128 return area;
129}
130
131float area_poly_v3(const float verts[][3], uint nr)
132{
133 float n[3];
134 cross_poly_v3(n, verts, nr);
135 return len_v3(n) * 0.5f;
136}
137
138float area_squared_poly_v3(const float verts[][3], uint nr)
139{
140 float n[3];
141
142 cross_poly_v3(n, verts, nr);
143 mul_v3_fl(n, 0.5f);
144 return len_squared_v3(n);
145}
146
147float cross_poly_v2(const float verts[][2], uint nr)
148{
149 uint a;
150 float cross;
151 const float *co_curr, *co_prev;
152
153 /* The Trapezium Area Rule */
154 co_prev = verts[nr - 1];
155 co_curr = verts[0];
156 cross = 0.0f;
157 for (a = 0; a < nr; a++) {
158 cross += (co_prev[0] - co_curr[0]) * (co_curr[1] + co_prev[1]);
159 co_prev = co_curr;
160 co_curr += 2;
161 }
162
163 return cross;
164}
165
166void cross_poly_v3(float n[3], const float verts[][3], uint nr)
167{
168 const float *v_prev = verts[nr - 1];
169 const float *v_curr = verts[0];
170 uint i;
171
172 zero_v3(n);
173
174 /* Newell's Method */
175 for (i = 0; i < nr; v_prev = v_curr, v_curr = verts[++i]) {
176 add_newell_cross_v3_v3v3(n, v_prev, v_curr);
177 }
178}
179
180float area_poly_v2(const float verts[][2], uint nr)
181{
182 return fabsf(0.5f * cross_poly_v2(verts, nr));
183}
184
185float area_poly_signed_v2(const float verts[][2], uint nr)
186{
187 return (0.5f * cross_poly_v2(verts, nr));
188}
189
190float area_squared_poly_v2(const float verts[][2], uint nr)
191{
192 float area = area_poly_signed_v2(verts, nr);
193 return area * area;
194}
195
196float cotangent_tri_weight_v3(const float v1[3], const float v2[3], const float v3[3])
197{
198 float a[3], b[3], c[3], c_len;
199
200 sub_v3_v3v3(a, v2, v1);
201 sub_v3_v3v3(b, v3, v1);
202 cross_v3_v3v3(c, a, b);
203
204 c_len = len_v3(c);
205
206 if (c_len > FLT_EPSILON) {
207 return dot_v3v3(a, b) / c_len;
208 }
209
210 return 0.0f;
211}
212
213/********************************* Planes **********************************/
214
215void plane_from_point_normal_v3(float r_plane[4], const float plane_co[3], const float plane_no[3])
216{
217 copy_v3_v3(r_plane, plane_no);
218 r_plane[3] = -dot_v3v3(r_plane, plane_co);
219}
220
221void plane_to_point_vector_v3(const float plane[4], float r_plane_co[3], float r_plane_no[3])
222{
223 mul_v3_v3fl(r_plane_co, plane, (-plane[3] / len_squared_v3(plane)));
224 copy_v3_v3(r_plane_no, plane);
225}
226
227void plane_to_point_vector_v3_normalized(const float plane[4],
228 float r_plane_co[3],
229 float r_plane_no[3])
230{
231 const float length = normalize_v3_v3(r_plane_no, plane);
232 mul_v3_v3fl(r_plane_co, r_plane_no, (-plane[3] / length));
233}
234
235/********************************* Volume **********************************/
236
237float volume_tetrahedron_v3(const float v1[3],
238 const float v2[3],
239 const float v3[3],
240 const float v4[3])
241{
242 float m[3][3];
243 sub_v3_v3v3(m[0], v1, v2);
244 sub_v3_v3v3(m[1], v2, v3);
245 sub_v3_v3v3(m[2], v3, v4);
246 return fabsf(determinant_m3_array(m)) / 6.0f;
247}
248
249float volume_tetrahedron_signed_v3(const float v1[3],
250 const float v2[3],
251 const float v3[3],
252 const float v4[3])
253{
254 float m[3][3];
255 sub_v3_v3v3(m[0], v1, v2);
256 sub_v3_v3v3(m[1], v2, v3);
257 sub_v3_v3v3(m[2], v3, v4);
258 return determinant_m3_array(m) / 6.0f;
259}
260
261float volume_tri_tetrahedron_signed_v3_6x(const float v1[3], const float v2[3], const float v3[3])
262{
263 float v_cross[3];
264 cross_v3_v3v3(v_cross, v1, v2);
265 float tetra_volume = dot_v3v3(v_cross, v3);
266 return tetra_volume;
267}
268
269float volume_tri_tetrahedron_signed_v3(const float v1[3], const float v2[3], const float v3[3])
270{
271 return volume_tri_tetrahedron_signed_v3_6x(v1, v2, v3) / 6.0f;
272}
273
274/********************************* Distance **********************************/
275
276float dist_squared_to_line_v2(const float p[2], const float l1[2], const float l2[2])
277{
278 float closest[2];
279
280 closest_to_line_v2(closest, p, l1, l2);
281
282 return len_squared_v2v2(closest, p);
283}
284float dist_to_line_v2(const float p[2], const float l1[2], const float l2[2])
285{
286 return sqrtf(dist_squared_to_line_v2(p, l1, l2));
287}
288
289float dist_squared_to_line_segment_v2(const float p[2], const float l1[2], const float l2[2])
290{
291 float closest[2];
292
294
295 return len_squared_v2v2(closest, p);
296}
297
298float dist_to_line_segment_v2(const float p[2], const float l1[2], const float l2[2])
299{
300 return sqrtf(dist_squared_to_line_segment_v2(p, l1, l2));
301}
302
303float closest_seg_seg_v2(float r_closest_a[2],
304 float r_closest_b[2],
305 float *r_lambda_a,
306 float *r_lambda_b,
307 const float a1[2],
308 const float a2[2],
309 const float b1[2],
310 const float b2[2])
311{
312 if (isect_seg_seg_v2_simple(a1, a2, b1, b2)) {
313 float intersection[2];
314 isect_line_line_v2_point(a1, a2, b1, b2, intersection);
315 copy_v2_v2(r_closest_a, intersection);
316 copy_v2_v2(r_closest_b, intersection);
317 float tmp[2];
318 *r_lambda_a = closest_to_line_v2(tmp, intersection, a1, a2);
319 *r_lambda_b = closest_to_line_v2(tmp, intersection, b1, b2);
320 const float min_dist_sq = len_squared_v2v2(r_closest_a, r_closest_b);
321 return min_dist_sq;
322 }
323
324 float p1[2], p2[2], p3[2], p4[2];
325 const float lambda1 = closest_to_line_segment_v2(p1, a1, b1, b2);
326 const float lambda2 = closest_to_line_segment_v2(p2, a2, b1, b2);
327 const float lambda3 = closest_to_line_segment_v2(p3, b1, a1, a2);
328 const float lambda4 = closest_to_line_segment_v2(p4, b2, a1, a2);
329 const float dist_sq1 = len_squared_v2v2(p1, a1);
330 const float dist_sq2 = len_squared_v2v2(p2, a2);
331 const float dist_sq3 = len_squared_v2v2(p3, b1);
332 const float dist_sq4 = len_squared_v2v2(p4, b2);
333
334 const float min_dist_sq = min_ffff(dist_sq1, dist_sq2, dist_sq3, dist_sq4);
335 if (min_dist_sq == dist_sq1) {
336 copy_v2_v2(r_closest_a, a1);
337 copy_v2_v2(r_closest_b, p1);
338 *r_lambda_a = 0.0f;
339 *r_lambda_b = lambda1;
340 }
341 else if (min_dist_sq == dist_sq2) {
342 copy_v2_v2(r_closest_a, a2);
343 copy_v2_v2(r_closest_b, p2);
344 *r_lambda_a = 1.0f;
345 *r_lambda_b = lambda2;
346 }
347 else if (min_dist_sq == dist_sq3) {
348 copy_v2_v2(r_closest_a, p3);
349 copy_v2_v2(r_closest_b, b1);
350 *r_lambda_a = lambda3;
351 *r_lambda_b = 0.0f;
352 }
353 else {
354 BLI_assert(min_dist_sq == dist_sq4);
355 copy_v2_v2(r_closest_a, p4);
356 copy_v2_v2(r_closest_b, b2);
357 *r_lambda_a = lambda4;
358 *r_lambda_b = 1.0f;
359 }
360 return min_dist_sq;
361}
362
363float closest_to_line_segment_v2(float r_close[2],
364 const float p[2],
365 const float l1[2],
366 const float l2[2])
367{
368 float lambda, cp[2];
369
370 lambda = closest_to_line_v2(cp, p, l1, l2);
371
372 /* flip checks for !finite case (when segment is a point) */
373 if (lambda <= 0.0f) {
374 copy_v2_v2(r_close, l1);
375 return 0.0f;
376 }
377 if (lambda >= 1.0f) {
378 copy_v2_v2(r_close, l2);
379 return 1.0f;
380 }
381 copy_v2_v2(r_close, cp);
382 return lambda;
383}
384
385float closest_to_line_segment_v3(float r_close[3],
386 const float p[3],
387 const float l1[3],
388 const float l2[3])
389{
390 float lambda, cp[3];
391
392 lambda = closest_to_line_v3(cp, p, l1, l2);
393
394 /* flip checks for !finite case (when segment is a point) */
395 if (lambda <= 0.0f) {
396 copy_v3_v3(r_close, l1);
397 return 0.0f;
398 }
399 if (lambda >= 1.0f) {
400 copy_v3_v3(r_close, l2);
401 return 1.0f;
402 }
403 copy_v3_v3(r_close, cp);
404 return lambda;
405}
406
407float closest_ray_to_segment_v3(const float ray_origin[3],
408 const float ray_direction[3],
409 const float v0[3],
410 const float v1[3],
411 float r_close[3])
412{
413 float lambda;
414 if (!isect_ray_line_v3(ray_origin, ray_direction, v0, v1, &lambda)) {
415 copy_v3_v3(r_close, v0);
416 return 0.0f;
417 }
418
419 if (lambda <= 0.0f) {
420 copy_v3_v3(r_close, v0);
421 return 0.0f;
422 }
423
424 if (lambda >= 1.0f) {
425 copy_v3_v3(r_close, v1);
426 return 1.0f;
427 }
428
429 interp_v3_v3v3(r_close, v0, v1, lambda);
430 return lambda;
431}
432
433void closest_to_plane_v3(float r_close[3], const float plane[4], const float pt[3])
434{
435 const float len_sq = len_squared_v3(plane);
436 const float side = plane_point_side_v3(plane, pt);
437 madd_v3_v3v3fl(r_close, pt, plane, -side / len_sq);
438}
439
440void closest_to_plane_normalized_v3(float r_close[3], const float plane[4], const float pt[3])
441{
442 const float side = plane_point_side_v3(plane, pt);
443 BLI_ASSERT_UNIT_V3(plane);
444 madd_v3_v3v3fl(r_close, pt, plane, -side);
445}
446
447void closest_to_plane3_v3(float r_close[3], const float plane[3], const float pt[3])
448{
449 const float len_sq = len_squared_v3(plane);
450 const float side = dot_v3v3(plane, pt);
451 madd_v3_v3v3fl(r_close, pt, plane, -side / len_sq);
452}
453
454void closest_to_plane3_normalized_v3(float r_close[3], const float plane[3], const float pt[3])
455{
456 const float side = dot_v3v3(plane, pt);
457 BLI_ASSERT_UNIT_V3(plane);
458 madd_v3_v3v3fl(r_close, pt, plane, -side);
459}
460
461float dist_signed_squared_to_plane_v3(const float p[3], const float plane[4])
462{
463 const float len_sq = len_squared_v3(plane);
464 const float side = plane_point_side_v3(plane, p);
465 const float fac = side / len_sq;
466 return copysignf(len_sq * (fac * fac), side);
467}
468float dist_squared_to_plane_v3(const float p[3], const float plane[4])
469{
470 const float len_sq = len_squared_v3(plane);
471 const float side = plane_point_side_v3(plane, p);
472 const float fac = side / len_sq;
473 /* only difference to code above - no 'copysignf' */
474 return len_sq * (fac * fac);
475}
476
477float dist_signed_squared_to_plane3_v3(const float p[3], const float plane[3])
478{
479 const float len_sq = len_squared_v3(plane);
480 const float side = dot_v3v3(plane, p); /* only difference with 'plane[4]' version */
481 const float fac = side / len_sq;
482 return copysignf(len_sq * (fac * fac), side);
483}
484float dist_squared_to_plane3_v3(const float p[3], const float plane[3])
485{
486 const float len_sq = len_squared_v3(plane);
487 const float side = dot_v3v3(plane, p); /* only difference with 'plane[4]' version */
488 const float fac = side / len_sq;
489 /* only difference to code above - no 'copysignf' */
490 return len_sq * (fac * fac);
491}
492
493float dist_signed_to_plane_v3(const float p[3], const float plane[4])
494{
495 const float len_sq = len_squared_v3(plane);
496 const float side = plane_point_side_v3(plane, p);
497 const float fac = side / len_sq;
498 return sqrtf(len_sq) * fac;
499}
500float dist_to_plane_v3(const float p[3], const float plane[4])
501{
502 return fabsf(dist_signed_to_plane_v3(p, plane));
503}
504
505float dist_signed_to_plane3_v3(const float p[3], const float plane[3])
506{
507 const float len_sq = len_squared_v3(plane);
508 const float side = dot_v3v3(plane, p); /* only difference with 'plane[4]' version */
509 const float fac = side / len_sq;
510 return sqrtf(len_sq) * fac;
511}
512float dist_to_plane3_v3(const float p[3], const float plane[3])
513{
514 return fabsf(dist_signed_to_plane3_v3(p, plane));
515}
516
517float dist_squared_to_line_segment_v3(const float p[3], const float l1[3], const float l2[3])
518{
519 float closest[3];
520
522
523 return len_squared_v3v3(closest, p);
524}
525
526float dist_to_line_segment_v3(const float p[3], const float l1[3], const float l2[3])
527{
528 return sqrtf(dist_squared_to_line_segment_v3(p, l1, l2));
529}
530
531float dist_squared_to_line_v3(const float p[3], const float l1[3], const float l2[3])
532{
533 float closest[3];
534
535 closest_to_line_v3(closest, p, l1, l2);
536
537 return len_squared_v3v3(closest, p);
538}
539float dist_to_line_v3(const float p[3], const float l1[3], const float l2[3])
540{
541 return sqrtf(dist_squared_to_line_v3(p, l1, l2));
542}
543
545 const float v1[3],
546 const float v2[3],
547 const float v3[3],
548 const float axis_ref[3])
549{
550 float dir_a[3], dir_b[3];
551 float plane_a[3], plane_b[3];
552 float dist_a, dist_b;
553 float axis[3];
554 float s_p_v2[3];
555 bool flip = false;
556
557 sub_v3_v3v3(dir_a, v1, v2);
558 sub_v3_v3v3(dir_b, v3, v2);
559
560 cross_v3_v3v3(axis, dir_a, dir_b);
561
562 if (len_squared_v3(axis) < FLT_EPSILON) {
563 copy_v3_v3(axis, axis_ref);
564 }
565 else if (dot_v3v3(axis, axis_ref) < 0.0f) {
566 /* concave */
567 flip = true;
568 negate_v3(axis);
569 }
570
571 cross_v3_v3v3(plane_a, dir_a, axis);
572 cross_v3_v3v3(plane_b, axis, dir_b);
573
574#if 0
575 plane_from_point_normal_v3(plane_a, v2, plane_a);
576 plane_from_point_normal_v3(plane_b, v2, plane_b);
577
578 dist_a = dist_signed_squared_to_plane_v3(p, plane_a);
579 dist_b = dist_signed_squared_to_plane_v3(p, plane_b);
580#else
581 /* calculate without the planes 4th component to avoid float precision issues */
582 sub_v3_v3v3(s_p_v2, p, v2);
583
584 dist_a = dist_signed_squared_to_plane3_v3(s_p_v2, plane_a);
585 dist_b = dist_signed_squared_to_plane3_v3(s_p_v2, plane_b);
586#endif
587
588 if (flip) {
589 return min_ff(dist_a, dist_b);
590 }
591
592 return max_ff(dist_a, dist_b);
593}
594
595float dist_squared_to_ray_v3_normalized(const float ray_origin[3],
596 const float ray_direction[3],
597 const float co[3])
598{
599 float origin_to_co[3];
600 sub_v3_v3v3(origin_to_co, co, ray_origin);
601
602 float origin_to_proj[3];
603 project_v3_v3v3_normalized(origin_to_proj, origin_to_co, ray_direction);
604
605 float co_projected_on_ray[3];
606 add_v3_v3v3(co_projected_on_ray, ray_origin, origin_to_proj);
607
608 return len_squared_v3v3(co, co_projected_on_ray);
609}
610
611float dist_squared_ray_to_seg_v3(const float ray_origin[3],
612 const float ray_direction[3],
613 const float v0[3],
614 const float v1[3],
615 float r_point[3],
616 float *r_depth)
617{
618 float lambda, depth;
619 if (isect_ray_line_v3(ray_origin, ray_direction, v0, v1, &lambda)) {
620 if (lambda <= 0.0f) {
621 copy_v3_v3(r_point, v0);
622 }
623 else if (lambda >= 1.0f) {
624 copy_v3_v3(r_point, v1);
625 }
626 else {
627 interp_v3_v3v3(r_point, v0, v1, lambda);
628 }
629 }
630 else {
631 /* has no nearest point, only distance squared. */
632 /* Calculate the distance to the point v0 then */
633 copy_v3_v3(r_point, v0);
634 }
635
636 float dvec[3];
637 sub_v3_v3v3(dvec, r_point, ray_origin);
638 depth = dot_v3v3(dvec, ray_direction);
639
640 if (r_depth) {
641 *r_depth = depth;
642 }
643
644 return len_squared_v3(dvec) - square_f(depth);
645}
646
647void aabb_get_near_far_from_plane(const float plane_no[3],
648 const float bbmin[3],
649 const float bbmax[3],
650 float bb_near[3],
651 float bb_afar[3])
652{
653 if (plane_no[0] < 0.0f) {
654 bb_near[0] = bbmax[0];
655 bb_afar[0] = bbmin[0];
656 }
657 else {
658 bb_near[0] = bbmin[0];
659 bb_afar[0] = bbmax[0];
660 }
661 if (plane_no[1] < 0.0f) {
662 bb_near[1] = bbmax[1];
663 bb_afar[1] = bbmin[1];
664 }
665 else {
666 bb_near[1] = bbmin[1];
667 bb_afar[1] = bbmax[1];
668 }
669 if (plane_no[2] < 0.0f) {
670 bb_near[2] = bbmax[2];
671 bb_afar[2] = bbmin[2];
672 }
673 else {
674 bb_near[2] = bbmin[2];
675 bb_afar[2] = bbmax[2];
676 }
677}
678
679/* -------------------------------------------------------------------- */
682
684 const float ray_direction[3])
685{
686 DistRayAABB_Precalc nearest_precalc{};
687 copy_v3_v3(nearest_precalc.ray_origin, ray_origin);
688 copy_v3_v3(nearest_precalc.ray_direction, ray_direction);
689
690 for (int i = 0; i < 3; i++) {
691 nearest_precalc.ray_inv_dir[i] = (nearest_precalc.ray_direction[i] != 0.0f) ?
692 (1.0f / nearest_precalc.ray_direction[i]) :
693 FLT_MAX;
694 }
695 return nearest_precalc;
696}
697
699 const float bb_min[3],
700 const float bb_max[3],
701 float r_point[3],
702 float *r_depth)
703{
704 // bool r_axis_closest[3];
705 float local_bvmin[3], local_bvmax[3];
706 aabb_get_near_far_from_plane(data->ray_direction, bb_min, bb_max, local_bvmin, local_bvmax);
707
708 const float tmin[3] = {
709 (local_bvmin[0] - data->ray_origin[0]) * data->ray_inv_dir[0],
710 (local_bvmin[1] - data->ray_origin[1]) * data->ray_inv_dir[1],
711 (local_bvmin[2] - data->ray_origin[2]) * data->ray_inv_dir[2],
712 };
713 const float tmax[3] = {
714 (local_bvmax[0] - data->ray_origin[0]) * data->ray_inv_dir[0],
715 (local_bvmax[1] - data->ray_origin[1]) * data->ray_inv_dir[1],
716 (local_bvmax[2] - data->ray_origin[2]) * data->ray_inv_dir[2],
717 };
718 /* `va` and `vb` are the coordinates of the AABB edge closest to the ray */
719 float va[3], vb[3];
720 /* `rtmin` and `rtmax` are the minimum and maximum distances of the ray hits on the AABB */
721 float rtmin, rtmax;
722 int main_axis;
723
724 if ((tmax[0] <= tmax[1]) && (tmax[0] <= tmax[2])) {
725 rtmax = tmax[0];
726 va[0] = vb[0] = local_bvmax[0];
727 main_axis = 3;
728 // r_axis_closest[0] = neasrest_precalc->ray_direction[0] < 0.0f;
729 }
730 else if ((tmax[1] <= tmax[0]) && (tmax[1] <= tmax[2])) {
731 rtmax = tmax[1];
732 va[1] = vb[1] = local_bvmax[1];
733 main_axis = 2;
734 // r_axis_closest[1] = neasrest_precalc->ray_direction[1] < 0.0f;
735 }
736 else {
737 rtmax = tmax[2];
738 va[2] = vb[2] = local_bvmax[2];
739 main_axis = 1;
740 // r_axis_closest[2] = neasrest_precalc->ray_direction[2] < 0.0f;
741 }
742
743 if ((tmin[0] >= tmin[1]) && (tmin[0] >= tmin[2])) {
744 rtmin = tmin[0];
745 va[0] = vb[0] = local_bvmin[0];
746 main_axis -= 3;
747 // r_axis_closest[0] = neasrest_precalc->ray_direction[0] >= 0.0f;
748 }
749 else if ((tmin[1] >= tmin[0]) && (tmin[1] >= tmin[2])) {
750 rtmin = tmin[1];
751 va[1] = vb[1] = local_bvmin[1];
752 main_axis -= 1;
753 // r_axis_closest[1] = neasrest_precalc->ray_direction[1] >= 0.0f;
754 }
755 else {
756 rtmin = tmin[2];
757 va[2] = vb[2] = local_bvmin[2];
758 main_axis -= 2;
759 // r_axis_closest[2] = neasrest_precalc->ray_direction[2] >= 0.0f;
760 }
761 if (main_axis < 0) {
762 main_axis += 3;
763 }
764
765 /* if rtmin <= rtmax, ray intersect `AABB` */
766 if (rtmin <= rtmax) {
767 float dvec[3];
768 copy_v3_v3(r_point, local_bvmax);
769 sub_v3_v3v3(dvec, local_bvmax, data->ray_origin);
770 *r_depth = dot_v3v3(dvec, data->ray_direction);
771 return 0.0f;
772 }
773
774 if (data->ray_direction[main_axis] >= 0.0f) {
775 va[main_axis] = local_bvmin[main_axis];
776 vb[main_axis] = local_bvmax[main_axis];
777 }
778 else {
779 va[main_axis] = local_bvmax[main_axis];
780 vb[main_axis] = local_bvmin[main_axis];
781 }
782
784 data->ray_origin, data->ray_direction, va, vb, r_point, r_depth);
785}
786
787float dist_squared_ray_to_aabb_v3_simple(const float ray_origin[3],
788 const float ray_direction[3],
789 const float bb_min[3],
790 const float bb_max[3],
791 float r_point[3],
792 float *r_depth)
793{
794 const DistRayAABB_Precalc data = dist_squared_ray_to_aabb_v3_precalc(ray_origin, ray_direction);
795 return dist_squared_ray_to_aabb_v3(&data, bb_min, bb_max, r_point, r_depth);
796}
797
799
800/* -------------------------------------------------------------------- */
803
805 const float projmat[4][4],
806 const float winsize[2],
807 const float mval[2])
808{
809 float win_half[2], relative_mval[2], px[4], py[4];
810
811 mul_v2_v2fl(win_half, winsize, 0.5f);
812 sub_v2_v2v2(precalc->mval, mval, win_half);
813
814 relative_mval[0] = precalc->mval[0] / win_half[0];
815 relative_mval[1] = precalc->mval[1] / win_half[1];
816
817 copy_m4_m4(precalc->pmat, projmat);
818 for (int i = 0; i < 4; i++) {
819 px[i] = precalc->pmat[i][0] - precalc->pmat[i][3] * relative_mval[0];
820 py[i] = precalc->pmat[i][1] - precalc->pmat[i][3] * relative_mval[1];
821
822 precalc->pmat[i][0] *= win_half[0];
823 precalc->pmat[i][1] *= win_half[1];
824 }
825#if 0
826 float projmat_trans[4][4];
827 transpose_m4_m4(projmat_trans, projmat);
829 projmat_trans[0], projmat_trans[1], projmat_trans[3], precalc->ray_origin))
830 {
831 /* Orthographic projection. */
832 isect_plane_plane_v3(px, py, precalc->ray_origin, precalc->ray_direction);
833 }
834 else {
835 /* Perspective projection. */
836 cross_v3_v3v3(precalc->ray_direction, py, px);
837 // normalize_v3(precalc->ray_direction);
838 }
839#else
840 if (!isect_plane_plane_v3(px, py, precalc->ray_origin, precalc->ray_direction)) {
841 /* Matrix with weird co-planar planes. Undetermined origin. */
842 zero_v3(precalc->ray_origin);
843 precalc->ray_direction[0] = precalc->pmat[0][3];
844 precalc->ray_direction[1] = precalc->pmat[1][3];
845 precalc->ray_direction[2] = precalc->pmat[2][3];
846 }
847#endif
848
849 for (int i = 0; i < 3; i++) {
850 precalc->ray_inv_dir[i] = (precalc->ray_direction[i] != 0.0f) ?
851 (1.0f / precalc->ray_direction[i]) :
852 FLT_MAX;
853 }
854}
855
857 const float bbmin[3],
858 const float bbmax[3],
859 bool r_axis_closest[3])
860{
861 float local_bvmin[3], local_bvmax[3];
862 aabb_get_near_far_from_plane(data->ray_direction, bbmin, bbmax, local_bvmin, local_bvmax);
863
864 const float tmin[3] = {
865 (local_bvmin[0] - data->ray_origin[0]) * data->ray_inv_dir[0],
866 (local_bvmin[1] - data->ray_origin[1]) * data->ray_inv_dir[1],
867 (local_bvmin[2] - data->ray_origin[2]) * data->ray_inv_dir[2],
868 };
869 const float tmax[3] = {
870 (local_bvmax[0] - data->ray_origin[0]) * data->ray_inv_dir[0],
871 (local_bvmax[1] - data->ray_origin[1]) * data->ray_inv_dir[1],
872 (local_bvmax[2] - data->ray_origin[2]) * data->ray_inv_dir[2],
873 };
874 /* `va` and `vb` are the coordinates of the AABB edge closest to the ray */
875 float va[3], vb[3];
876 /* `rtmin` and `rtmax` are the minimum and maximum distances of the ray hits on the AABB */
877 float rtmin, rtmax;
878 int main_axis;
879
880 r_axis_closest[0] = false;
881 r_axis_closest[1] = false;
882 r_axis_closest[2] = false;
883
884 if ((tmax[0] <= tmax[1]) && (tmax[0] <= tmax[2])) {
885 rtmax = tmax[0];
886 va[0] = vb[0] = local_bvmax[0];
887 main_axis = 3;
888 r_axis_closest[0] = data->ray_direction[0] < 0.0f;
889 }
890 else if ((tmax[1] <= tmax[0]) && (tmax[1] <= tmax[2])) {
891 rtmax = tmax[1];
892 va[1] = vb[1] = local_bvmax[1];
893 main_axis = 2;
894 r_axis_closest[1] = data->ray_direction[1] < 0.0f;
895 }
896 else {
897 rtmax = tmax[2];
898 va[2] = vb[2] = local_bvmax[2];
899 main_axis = 1;
900 r_axis_closest[2] = data->ray_direction[2] < 0.0f;
901 }
902
903 if ((tmin[0] >= tmin[1]) && (tmin[0] >= tmin[2])) {
904 rtmin = tmin[0];
905 va[0] = vb[0] = local_bvmin[0];
906 main_axis -= 3;
907 r_axis_closest[0] = data->ray_direction[0] >= 0.0f;
908 }
909 else if ((tmin[1] >= tmin[0]) && (tmin[1] >= tmin[2])) {
910 rtmin = tmin[1];
911 va[1] = vb[1] = local_bvmin[1];
912 main_axis -= 1;
913 r_axis_closest[1] = data->ray_direction[1] >= 0.0f;
914 }
915 else {
916 rtmin = tmin[2];
917 va[2] = vb[2] = local_bvmin[2];
918 main_axis -= 2;
919 r_axis_closest[2] = data->ray_direction[2] >= 0.0f;
920 }
921 if (main_axis < 0) {
922 main_axis += 3;
923 }
924
925 /* if rtmin <= rtmax, ray intersect `AABB` */
926 if (rtmin <= rtmax) {
927 return 0;
928 }
929
930 if (data->ray_direction[main_axis] >= 0.0f) {
931 va[main_axis] = local_bvmin[main_axis];
932 vb[main_axis] = local_bvmax[main_axis];
933 }
934 else {
935 va[main_axis] = local_bvmax[main_axis];
936 vb[main_axis] = local_bvmin[main_axis];
937 }
938 float scale = fabsf(local_bvmax[main_axis] - local_bvmin[main_axis]);
939
940 float va2d[2] = {
941 (dot_m4_v3_row_x(data->pmat, va) + data->pmat[3][0]),
942 (dot_m4_v3_row_y(data->pmat, va) + data->pmat[3][1]),
943 };
944 float vb2d[2] = {
945 (va2d[0] + data->pmat[main_axis][0] * scale),
946 (va2d[1] + data->pmat[main_axis][1] * scale),
947 };
948
949 float w_a = mul_project_m4_v3_zfac(data->pmat, va);
950 if (w_a != 1.0f) {
951 /* Perspective Projection. */
952 float w_b = w_a + data->pmat[main_axis][3] * scale;
953 va2d[0] /= w_a;
954 va2d[1] /= w_a;
955 vb2d[0] /= w_b;
956 vb2d[1] /= w_b;
957 }
958
959 float dvec[2], edge[2], lambda, rdist_sq;
960 sub_v2_v2v2(dvec, data->mval, va2d);
961 sub_v2_v2v2(edge, vb2d, va2d);
962 lambda = dot_v2v2(dvec, edge);
963 if (lambda != 0.0f) {
964 lambda /= len_squared_v2(edge);
965 if (lambda <= 0.0f) {
966 rdist_sq = len_squared_v2v2(data->mval, va2d);
967 r_axis_closest[main_axis] = true;
968 }
969 else if (lambda >= 1.0f) {
970 rdist_sq = len_squared_v2v2(data->mval, vb2d);
971 r_axis_closest[main_axis] = false;
972 }
973 else {
974 madd_v2_v2fl(va2d, edge, lambda);
975 rdist_sq = len_squared_v2v2(data->mval, va2d);
976 r_axis_closest[main_axis] = lambda < 0.5f;
977 }
978 }
979 else {
980 rdist_sq = len_squared_v2v2(data->mval, va2d);
981 }
982
983 return rdist_sq;
984}
985
986float dist_squared_to_projected_aabb_simple(const float projmat[4][4],
987 const float winsize[2],
988 const float mval[2],
989 const float bbmin[3],
990 const float bbmax[3])
991{
993 dist_squared_to_projected_aabb_precalc(&data, projmat, winsize, mval);
994
995 bool dummy[3] = {true, true, true};
996 return dist_squared_to_projected_aabb(&data, bbmin, bbmax, dummy);
997}
998
1000
1001float dist_seg_seg_v2(const float a1[3], const float a2[3], const float b1[3], const float b2[3])
1002{
1003 if (isect_seg_seg_v2_simple(a1, a2, b1, b2)) {
1004 return 0.0f;
1005 }
1006 const float d1 = dist_squared_to_line_segment_v2(a1, b1, b2);
1007 const float d2 = dist_squared_to_line_segment_v2(a2, b1, b2);
1008 const float d3 = dist_squared_to_line_segment_v2(b1, a1, a2);
1009 const float d4 = dist_squared_to_line_segment_v2(b2, a1, a2);
1010 return sqrtf(min_ffff(d1, d2, d3, d4));
1011}
1012
1014 float r[3], const float p[3], const float v1[3], const float v2[3], const float v3[3])
1015{
1016 /* Adapted from "Real-Time Collision Detection" by Christer Ericson,
1017 * published by Morgan Kaufmann Publishers, copyright 2005 Elsevier Inc. */
1018
1019 float ab[3], ac[3], ap[3], d1, d2;
1020 float bp[3], d3, d4, vc, cp[3], d5, d6, vb, va;
1021 float denom, v, w;
1022
1023 /* Check if P in vertex region outside A */
1024 sub_v3_v3v3(ab, v2, v1);
1025 sub_v3_v3v3(ac, v3, v1);
1026 sub_v3_v3v3(ap, p, v1);
1027 d1 = dot_v3v3(ab, ap);
1028 d2 = dot_v3v3(ac, ap);
1029 if (d1 <= 0.0f && d2 <= 0.0f) {
1030 /* barycentric coordinates (1,0,0) */
1031 copy_v3_v3(r, v1);
1032 return;
1033 }
1034
1035 /* Check if P in vertex region outside B */
1036 sub_v3_v3v3(bp, p, v2);
1037 d3 = dot_v3v3(ab, bp);
1038 d4 = dot_v3v3(ac, bp);
1039 if (d3 >= 0.0f && d4 <= d3) {
1040 /* barycentric coordinates (0,1,0) */
1041 copy_v3_v3(r, v2);
1042 return;
1043 }
1044 /* Check if P in edge region of AB, if so return projection of P onto AB */
1045 vc = d1 * d4 - d3 * d2;
1046 if (vc <= 0.0f && d1 >= 0.0f && d3 <= 0.0f) {
1047 v = d1 / (d1 - d3);
1048 /* barycentric coordinates (1-v,v,0) */
1049 madd_v3_v3v3fl(r, v1, ab, v);
1050 return;
1051 }
1052 /* Check if P in vertex region outside C */
1053 sub_v3_v3v3(cp, p, v3);
1054 d5 = dot_v3v3(ab, cp);
1055 d6 = dot_v3v3(ac, cp);
1056 if (d6 >= 0.0f && d5 <= d6) {
1057 /* barycentric coordinates (0,0,1) */
1058 copy_v3_v3(r, v3);
1059 return;
1060 }
1061 /* Check if P in edge region of AC, if so return projection of P onto AC */
1062 vb = d5 * d2 - d1 * d6;
1063 if (vb <= 0.0f && d2 >= 0.0f && d6 <= 0.0f) {
1064 w = d2 / (d2 - d6);
1065 /* barycentric coordinates (1-w,0,w) */
1066 madd_v3_v3v3fl(r, v1, ac, w);
1067 return;
1068 }
1069 /* Check if P in edge region of BC, if so return projection of P onto BC */
1070 va = d3 * d6 - d5 * d4;
1071 if (va <= 0.0f && (d4 - d3) >= 0.0f && (d5 - d6) >= 0.0f) {
1072 w = (d4 - d3) / ((d4 - d3) + (d5 - d6));
1073 /* barycentric coordinates (0,1-w,w) */
1074 sub_v3_v3v3(r, v3, v2);
1075 mul_v3_fl(r, w);
1076 add_v3_v3(r, v2);
1077 return;
1078 }
1079
1080 /* P inside face region. Compute Q through its barycentric coordinates (u,v,w) */
1081 denom = 1.0f / (va + vb + vc);
1082 v = vb * denom;
1083 w = vc * denom;
1084
1085 /* = u*a + v*b + w*c, u = va * denom = 1.0f - v - w */
1086 /* ac * w */
1087 mul_v3_fl(ac, w);
1088 /* a + ab * v */
1089 madd_v3_v3v3fl(r, v1, ab, v);
1090 /* a + ab * v + ac * w */
1091 add_v3_v3(r, ac);
1092}
1093
1094/******************************* Intersection ********************************/
1095
1096int isect_seg_seg_v2_int(const int v1[2], const int v2[2], const int v3[2], const int v4[2])
1097{
1098 float div, lambda, mu;
1099
1100 div = float((v2[0] - v1[0]) * (v4[1] - v3[1]) - (v2[1] - v1[1]) * (v4[0] - v3[0]));
1101 if (div == 0.0f) {
1103 }
1104
1105 lambda = float((v1[1] - v3[1]) * (v4[0] - v3[0]) - (v1[0] - v3[0]) * (v4[1] - v3[1])) / div;
1106
1107 mu = float((v1[1] - v3[1]) * (v2[0] - v1[0]) - (v1[0] - v3[0]) * (v2[1] - v1[1])) / div;
1108
1109 if (lambda >= 0.0f && lambda <= 1.0f && mu >= 0.0f && mu <= 1.0f) {
1110 if (lambda == 0.0f || lambda == 1.0f || mu == 0.0f || mu == 1.0f) {
1111 return ISECT_LINE_LINE_EXACT;
1112 }
1113 return ISECT_LINE_LINE_CROSS;
1114 }
1115 return ISECT_LINE_LINE_NONE;
1116}
1117
1119 const float v0[2], const float v1[2], const float v2[2], const float v3[2], float r_vi[2])
1120{
1121 float s10[2], s32[2];
1122 float div;
1123
1124 sub_v2_v2v2(s10, v1, v0);
1125 sub_v2_v2v2(s32, v3, v2);
1126
1127 div = cross_v2v2(s10, s32);
1128 if (div != 0.0f) {
1129 const float u = cross_v2v2(v1, v0);
1130 const float v = cross_v2v2(v3, v2);
1131
1132 r_vi[0] = ((s32[0] * u) - (s10[0] * v)) / div;
1133 r_vi[1] = ((s32[1] * u) - (s10[1] * v)) / div;
1134
1135 return ISECT_LINE_LINE_CROSS;
1136 }
1137
1139}
1140
1141int isect_seg_seg_v2(const float v1[2], const float v2[2], const float v3[2], const float v4[2])
1142{
1143 float div, lambda, mu;
1144
1145 div = (v2[0] - v1[0]) * (v4[1] - v3[1]) - (v2[1] - v1[1]) * (v4[0] - v3[0]);
1146 if (div == 0.0f) {
1148 }
1149
1150 lambda = (float(v1[1] - v3[1]) * (v4[0] - v3[0]) - (v1[0] - v3[0]) * (v4[1] - v3[1])) / div;
1151
1152 mu = (float(v1[1] - v3[1]) * (v2[0] - v1[0]) - (v1[0] - v3[0]) * (v2[1] - v1[1])) / div;
1153
1154 if (lambda >= 0.0f && lambda <= 1.0f && mu >= 0.0f && mu <= 1.0f) {
1155 if (lambda == 0.0f || lambda == 1.0f || mu == 0.0f || mu == 1.0f) {
1156 return ISECT_LINE_LINE_EXACT;
1157 }
1158 return ISECT_LINE_LINE_CROSS;
1159 }
1160 return ISECT_LINE_LINE_NONE;
1161}
1162
1163void isect_seg_seg_v3(const float a0[3],
1164 const float a1[3],
1165 const float b0[3],
1166 const float b1[3],
1167 float r_a[3],
1168 float r_b[3])
1169{
1170 float fac_a, fac_b;
1171 float a_dir[3], b_dir[3], a0b0[3], crs_ab[3];
1172 sub_v3_v3v3(a_dir, a1, a0);
1173 sub_v3_v3v3(b_dir, b1, b0);
1174 sub_v3_v3v3(a0b0, b0, a0);
1175 cross_v3_v3v3(crs_ab, b_dir, a_dir);
1176 const float nlen = len_squared_v3(crs_ab);
1177
1178 if (nlen == 0.0f) {
1179 /* Parallel Lines */
1180 /* In this case return any point that
1181 * is between the closest segments. */
1182 float a0b1[3], a1b0[3], len_a, len_b, fac1, fac2;
1183 sub_v3_v3v3(a0b1, b1, a0);
1184 sub_v3_v3v3(a1b0, b0, a1);
1185 len_a = len_squared_v3(a_dir);
1186 len_b = len_squared_v3(b_dir);
1187
1188 if (len_a) {
1189 fac1 = dot_v3v3(a0b0, a_dir);
1190 fac2 = dot_v3v3(a0b1, a_dir);
1191 CLAMP(fac1, 0.0f, len_a);
1192 CLAMP(fac2, 0.0f, len_a);
1193 fac_a = (fac1 + fac2) / (2 * len_a);
1194 }
1195 else {
1196 fac_a = 0.0f;
1197 }
1198
1199 if (len_b) {
1200 fac1 = -dot_v3v3(a0b0, b_dir);
1201 fac2 = -dot_v3v3(a1b0, b_dir);
1202 CLAMP(fac1, 0.0f, len_b);
1203 CLAMP(fac2, 0.0f, len_b);
1204 fac_b = (fac1 + fac2) / (2 * len_b);
1205 }
1206 else {
1207 fac_b = 0.0f;
1208 }
1209 }
1210 else {
1211 float c[3], cray[3];
1212 sub_v3_v3v3(c, crs_ab, a0b0);
1213
1214 cross_v3_v3v3(cray, c, b_dir);
1215 fac_a = dot_v3v3(cray, crs_ab) / nlen;
1216
1217 cross_v3_v3v3(cray, c, a_dir);
1218 fac_b = dot_v3v3(cray, crs_ab) / nlen;
1219
1220 CLAMP(fac_a, 0.0f, 1.0f);
1221 CLAMP(fac_b, 0.0f, 1.0f);
1222 }
1223
1224 madd_v3_v3v3fl(r_a, a0, a_dir, fac_a);
1225 madd_v3_v3v3fl(r_b, b0, b_dir, fac_b);
1226}
1227
1228int isect_seg_seg_v2_point_ex(const float v0[2],
1229 const float v1[2],
1230 const float v2[2],
1231 const float v3[2],
1232 const float endpoint_bias,
1233 float r_vi[2])
1234{
1235 float s10[2], s32[2], s30[2], d;
1236 const float eps = 1e-6f;
1237 const float endpoint_min = -endpoint_bias;
1238 const float endpoint_max = endpoint_bias + 1.0f;
1239
1240 sub_v2_v2v2(s10, v1, v0);
1241 sub_v2_v2v2(s32, v3, v2);
1242 sub_v2_v2v2(s30, v3, v0);
1243
1244 d = cross_v2v2(s10, s32);
1245
1246 if (d != 0) {
1247 float u, v;
1248
1249 u = cross_v2v2(s30, s32) / d;
1250 v = cross_v2v2(s10, s30) / d;
1251
1252 if ((u >= endpoint_min && u <= endpoint_max) && (v >= endpoint_min && v <= endpoint_max)) {
1253 /* intersection */
1254 float vi_test[2];
1255 float s_vi_v2[2];
1256
1257 madd_v2_v2v2fl(vi_test, v0, s10, u);
1258
1259 /* When 'd' approaches zero, float precision lets non-overlapping co-linear segments
1260 * detect as an intersection. So re-calculate 'v' to ensure the point overlaps both.
1261 * see #45123 */
1262
1263 /* inline since we have most vars already */
1264#if 0
1265 v = line_point_factor_v2(ix_test, v2, v3);
1266#else
1267 sub_v2_v2v2(s_vi_v2, vi_test, v2);
1268 v = (dot_v2v2(s32, s_vi_v2) / dot_v2v2(s32, s32));
1269#endif
1270 if (v >= endpoint_min && v <= endpoint_max) {
1271 copy_v2_v2(r_vi, vi_test);
1272 return 1;
1273 }
1274 }
1275
1276 /* out of segment intersection */
1277 return -1;
1278 }
1279
1280 if ((cross_v2v2(s10, s30) == 0.0f) && (cross_v2v2(s32, s30) == 0.0f)) {
1281 /* equal lines */
1282 float s20[2];
1283 float u_a, u_b;
1284
1285 if (equals_v2v2(v0, v1)) {
1286 if (len_squared_v2v2(v2, v3) > square_f(eps)) {
1287 /* use non-point segment as basis */
1288 std::swap(v0, v2);
1289 std::swap(v1, v3);
1290
1291 sub_v2_v2v2(s10, v1, v0);
1292 sub_v2_v2v2(s30, v3, v0);
1293 }
1294 else { /* both of segments are points */
1295 if (equals_v2v2(v0, v2)) { /* points are equal */
1296 copy_v2_v2(r_vi, v0);
1297 return 1;
1298 }
1299
1300 /* two different points */
1301 return -1;
1302 }
1303 }
1304
1305 sub_v2_v2v2(s20, v2, v0);
1306
1307 u_a = dot_v2v2(s20, s10) / dot_v2v2(s10, s10);
1308 u_b = dot_v2v2(s30, s10) / dot_v2v2(s10, s10);
1309
1310 if (u_a > u_b) {
1311 std::swap(u_a, u_b);
1312 }
1313
1314 if (u_a > endpoint_max || u_b < endpoint_min) {
1315 /* non-overlapping segments */
1316 return -1;
1317 }
1318 if (max_ff(0.0f, u_a) == min_ff(1.0f, u_b)) {
1319 /* one common point: can return result */
1320 madd_v2_v2v2fl(r_vi, v0, s10, max_ff(0, u_a));
1321 return 1;
1322 }
1323 }
1324
1325 /* lines are collinear */
1326 return -1;
1327}
1328
1330 const float v0[2], const float v1[2], const float v2[2], const float v3[2], float r_vi[2])
1331{
1332 const float endpoint_bias = 1e-6f;
1333 return isect_seg_seg_v2_point_ex(v0, v1, v2, v3, endpoint_bias, r_vi);
1334}
1335
1336bool isect_seg_seg_v2_simple(const float v1[2],
1337 const float v2[2],
1338 const float v3[2],
1339 const float v4[2])
1340{
1341#define CCW(A, B, C) ((C[1] - A[1]) * (B[0] - A[0]) > (B[1] - A[1]) * (C[0] - A[0]))
1342
1343 return CCW(v1, v3, v4) != CCW(v2, v3, v4) && CCW(v1, v2, v3) != CCW(v1, v2, v4);
1344
1345#undef CCW
1346}
1347
1348int isect_seg_seg_v2_lambda_mu_db(const double v1[2],
1349 const double v2[2],
1350 const double v3[2],
1351 const double v4[2],
1352 double *r_lambda,
1353 double *r_mu)
1354{
1355 double div, lambda, mu;
1356
1357 div = (v2[0] - v1[0]) * (v4[1] - v3[1]) - (v2[1] - v1[1]) * (v4[0] - v3[0]);
1358 if (fabs(div) < DBL_EPSILON) {
1360 }
1361
1362 lambda = ((v1[1] - v3[1]) * (v4[0] - v3[0]) - (v1[0] - v3[0]) * (v4[1] - v3[1])) / div;
1363
1364 mu = ((v1[1] - v3[1]) * (v2[0] - v1[0]) - (v1[0] - v3[0]) * (v2[1] - v1[1])) / div;
1365
1366 if (r_lambda) {
1367 *r_lambda = lambda;
1368 }
1369 if (r_mu) {
1370 *r_mu = mu;
1371 }
1372
1373 if (lambda >= 0.0 && lambda <= 1.0 && mu >= 0.0 && mu <= 1.0) {
1374 if (lambda == 0.0 || lambda == 1.0 || mu == 0.0 || mu == 1.0) {
1375 return ISECT_LINE_LINE_EXACT;
1376 }
1377 return ISECT_LINE_LINE_CROSS;
1378 }
1379 return ISECT_LINE_LINE_NONE;
1380}
1381
1382int isect_line_sphere_v3(const float l1[3],
1383 const float l2[3],
1384 const float sp[3],
1385 const float r,
1386 float r_p1[3],
1387 float r_p2[3])
1388{
1389 /* Adapted for use in blender by Campbell Barton, 2011.
1390 *
1391 * http://www.iebele.nl
1392 * `Atelier Iebele Abel <atelier@iebele.nl>` - 2001.
1393 *
1394 * sphere_line_intersection function adapted from:
1395 * http://astronomy.swin.edu.au/pbourke/geometry/sphereline
1396 * `Paul Bourke <pbourke@swin.edu.au>`. */
1397
1398 const float ldir[3] = {
1399 l2[0] - l1[0],
1400 l2[1] - l1[1],
1401 l2[2] - l1[2],
1402 };
1403
1404 const float a = len_squared_v3(ldir);
1405
1406 const float b = 2.0f * (ldir[0] * (l1[0] - sp[0]) + ldir[1] * (l1[1] - sp[1]) +
1407 ldir[2] * (l1[2] - sp[2]));
1408
1409 const float c = len_squared_v3(sp) + len_squared_v3(l1) - (2.0f * dot_v3v3(sp, l1)) - (r * r);
1410
1411 const float i = b * b - 4.0f * a * c;
1412
1413 float mu;
1414
1415 if (i < 0.0f) {
1416 /* no intersections */
1417 return 0;
1418 }
1419 if (i == 0.0f) {
1420 /* one intersection */
1421 mu = -b / (2.0f * a);
1422 madd_v3_v3v3fl(r_p1, l1, ldir, mu);
1423 return 1;
1424 }
1425 if (i > 0.0f) {
1426 const float i_sqrt = sqrtf(i); /* avoid calc twice */
1427
1428 /* first intersection */
1429 mu = (-b + i_sqrt) / (2.0f * a);
1430 madd_v3_v3v3fl(r_p1, l1, ldir, mu);
1431
1432 /* second intersection */
1433 mu = (-b - i_sqrt) / (2.0f * a);
1434 madd_v3_v3v3fl(r_p2, l1, ldir, mu);
1435 return 2;
1436 }
1437
1438 /* math domain error - nan */
1439 return -1;
1440}
1441
1442int isect_line_sphere_v2(const float l1[2],
1443 const float l2[2],
1444 const float sp[2],
1445 const float r,
1446 float r_p1[2],
1447 float r_p2[2])
1448{
1449 /* Keep in sync with #isect_line_sphere_v3. */
1450
1451 const float ldir[2] = {l2[0] - l1[0], l2[1] - l1[1]};
1452
1453 const float a = dot_v2v2(ldir, ldir);
1454
1455 const float b = 2.0f * (ldir[0] * (l1[0] - sp[0]) + ldir[1] * (l1[1] - sp[1]));
1456
1457 const float c = dot_v2v2(sp, sp) + dot_v2v2(l1, l1) - (2.0f * dot_v2v2(sp, l1)) - (r * r);
1458
1459 const float i = b * b - 4.0f * a * c;
1460
1461 float mu;
1462
1463 if (i < 0.0f) {
1464 /* no intersections */
1465 return 0;
1466 }
1467 if (i == 0.0f) {
1468 /* one intersection */
1469 mu = -b / (2.0f * a);
1470 madd_v2_v2v2fl(r_p1, l1, ldir, mu);
1471 return 1;
1472 }
1473 if (i > 0.0f) {
1474 const float i_sqrt = sqrtf(i); /* avoid calc twice */
1475
1476 /* first intersection */
1477 mu = (-b + i_sqrt) / (2.0f * a);
1478 madd_v2_v2v2fl(r_p1, l1, ldir, mu);
1479
1480 /* second intersection */
1481 mu = (-b - i_sqrt) / (2.0f * a);
1482 madd_v2_v2v2fl(r_p2, l1, ldir, mu);
1483 return 2;
1484 }
1485
1486 /* math domain error - nan */
1487 return -1;
1488}
1489
1490bool isect_point_poly_v2(const float pt[2], const float verts[][2], const uint nr)
1491{
1492 /* Keep in sync with #isect_point_poly_v2_int. */
1493
1494 uint i, j;
1495 bool isect = false;
1496 for (i = 0, j = nr - 1; i < nr; j = i++) {
1497 if (((verts[i][1] > pt[1]) != (verts[j][1] > pt[1])) &&
1498 (pt[0] <
1499 (verts[j][0] - verts[i][0]) * (pt[1] - verts[i][1]) / (verts[j][1] - verts[i][1]) +
1500 verts[i][0]))
1501 {
1502 isect = !isect;
1503 }
1504 }
1505 return isect;
1506}
1507bool isect_point_poly_v2_int(const int pt[2], const int verts[][2], const uint nr)
1508{
1509 /* Keep in sync with #isect_point_poly_v2. */
1510
1511 uint i, j;
1512 bool isect = false;
1513 for (i = 0, j = nr - 1; i < nr; j = i++) {
1514 if (((verts[i][1] > pt[1]) != (verts[j][1] > pt[1])) &&
1515 (pt[0] <
1516 (verts[j][0] - verts[i][0]) * (pt[1] - verts[i][1]) / (verts[j][1] - verts[i][1]) +
1517 verts[i][0]))
1518 {
1519 isect = !isect;
1520 }
1521 }
1522 return isect;
1523}
1524
1525/* point in tri */
1526
1527bool isect_point_tri_v2_cw(const float pt[2],
1528 const float v1[2],
1529 const float v2[2],
1530 const float v3[2])
1531{
1532 if (line_point_side_v2(v1, v2, pt) >= 0.0f) {
1533 if (line_point_side_v2(v2, v3, pt) >= 0.0f) {
1534 if (line_point_side_v2(v3, v1, pt) >= 0.0f) {
1535 return true;
1536 }
1537 }
1538 }
1539
1540 return false;
1541}
1542
1543int isect_point_tri_v2(const float pt[2], const float v1[2], const float v2[2], const float v3[2])
1544{
1545 float side12 = line_point_side_v2(v1, v2, pt);
1546 float side23 = line_point_side_v2(v2, v3, pt);
1547 float side31 = line_point_side_v2(v3, v1, pt);
1548 if (side12 >= 0.0f && side23 >= 0.0f && side31 >= 0.0f) {
1549 return 1;
1550 }
1551 if (side12 <= 0.0f && side23 <= 0.0f && side31 <= 0.0f) {
1552 return -1;
1553 }
1554
1555 return 0;
1556}
1557
1559 const float p[2], const float v1[2], const float v2[2], const float v3[2], const float v4[2])
1560{
1561 float side12 = line_point_side_v2(v1, v2, p);
1562 float side23 = line_point_side_v2(v2, v3, p);
1563 float side34 = line_point_side_v2(v3, v4, p);
1564 float side41 = line_point_side_v2(v4, v1, p);
1565 if (side12 >= 0.0f && side23 >= 0.0f && side34 >= 0.0f && side41 >= 0.0f) {
1566 return 1;
1567 }
1568 if (side12 <= 0.0f && side23 <= 0.0f && side34 <= 0.0f && side41 <= 0.0f) {
1569 return -1;
1570 }
1571 return 0;
1572}
1573
1574bool isect_line_segment_tri_v3(const float p1[3],
1575 const float p2[3],
1576 const float v0[3],
1577 const float v1[3],
1578 const float v2[3],
1579 float *r_lambda,
1580 float r_uv[2])
1581{
1582
1583 float p[3], s[3], d[3], e1[3], e2[3], q[3];
1584 float a, f, u, v;
1585
1586 sub_v3_v3v3(e1, v1, v0);
1587 sub_v3_v3v3(e2, v2, v0);
1588 sub_v3_v3v3(d, p2, p1);
1589
1590 cross_v3_v3v3(p, d, e2);
1591 a = dot_v3v3(e1, p);
1592 if (a == 0.0f) {
1593 return false;
1594 }
1595 f = 1.0f / a;
1596
1597 sub_v3_v3v3(s, p1, v0);
1598
1599 u = f * dot_v3v3(s, p);
1600 if ((u < 0.0f) || (u > 1.0f)) {
1601 return false;
1602 }
1603
1604 cross_v3_v3v3(q, s, e1);
1605
1606 v = f * dot_v3v3(d, q);
1607 if ((v < 0.0f) || ((u + v) > 1.0f)) {
1608 return false;
1609 }
1610
1611 *r_lambda = f * dot_v3v3(e2, q);
1612 if ((*r_lambda < 0.0f) || (*r_lambda > 1.0f)) {
1613 return false;
1614 }
1615
1616 if (r_uv) {
1617 r_uv[0] = u;
1618 r_uv[1] = v;
1619 }
1620
1621 return true;
1622}
1623
1625 const float p2[3],
1626 const float v0[3],
1627 const float v1[3],
1628 const float v2[3],
1629 float *r_lambda,
1630 float r_uv[2],
1631 const float epsilon)
1632{
1633
1634 float p[3], s[3], d[3], e1[3], e2[3], q[3];
1635 float a, f, u, v;
1636
1637 sub_v3_v3v3(e1, v1, v0);
1638 sub_v3_v3v3(e2, v2, v0);
1639 sub_v3_v3v3(d, p2, p1);
1640
1641 cross_v3_v3v3(p, d, e2);
1642 a = dot_v3v3(e1, p);
1643 if (a == 0.0f) {
1644 return false;
1645 }
1646 f = 1.0f / a;
1647
1648 sub_v3_v3v3(s, p1, v0);
1649
1650 u = f * dot_v3v3(s, p);
1651 if ((u < -epsilon) || (u > 1.0f + epsilon)) {
1652 return false;
1653 }
1654
1655 cross_v3_v3v3(q, s, e1);
1656
1657 v = f * dot_v3v3(d, q);
1658 if ((v < -epsilon) || ((u + v) > 1.0f + epsilon)) {
1659 return false;
1660 }
1661
1662 *r_lambda = f * dot_v3v3(e2, q);
1663 if ((*r_lambda < 0.0f) || (*r_lambda > 1.0f)) {
1664 return false;
1665 }
1666
1667 if (r_uv) {
1668 r_uv[0] = u;
1669 r_uv[1] = v;
1670 }
1671
1672 return true;
1673}
1674
1675bool isect_ray_tri_v3(const float ray_origin[3],
1676 const float ray_direction[3],
1677 const float v0[3],
1678 const float v1[3],
1679 const float v2[3],
1680 float *r_lambda,
1681 float r_uv[2])
1682{
1683 /* NOTE(@ideasman42): these values were 0.000001 in 2.4x but for projection snapping on
1684 * a human head `(1BU == 1m)`, subdivision-surface level 2, this gave many errors. */
1685 const float epsilon = 0.00000001f;
1686 float p[3], s[3], e1[3], e2[3], q[3];
1687 float a, f, u, v;
1688
1689 sub_v3_v3v3(e1, v1, v0);
1690 sub_v3_v3v3(e2, v2, v0);
1691
1692 cross_v3_v3v3(p, ray_direction, e2);
1693 a = dot_v3v3(e1, p);
1694 if ((a > -epsilon) && (a < epsilon)) {
1695 return false;
1696 }
1697 f = 1.0f / a;
1698
1699 sub_v3_v3v3(s, ray_origin, v0);
1700
1701 u = f * dot_v3v3(s, p);
1702 if ((u < 0.0f) || (u > 1.0f)) {
1703 return false;
1704 }
1705
1706 cross_v3_v3v3(q, s, e1);
1707
1708 v = f * dot_v3v3(ray_direction, q);
1709 if ((v < 0.0f) || ((u + v) > 1.0f)) {
1710 return false;
1711 }
1712
1713 *r_lambda = f * dot_v3v3(e2, q);
1714 if (*r_lambda < 0.0f) {
1715 return false;
1716 }
1717
1718 if (r_uv) {
1719 r_uv[0] = u;
1720 r_uv[1] = v;
1721 }
1722
1723 return true;
1724}
1725
1726bool isect_ray_plane_v3_factor(const float ray_origin[3],
1727 const float ray_direction[3],
1728 const float plane_co[3],
1729 const float plane_no[3],
1730 float *r_lambda)
1731{
1732 float h[3];
1733 float dot = dot_v3v3(plane_no, ray_direction);
1734 if (dot == 0.0f) {
1735 return false;
1736 }
1737 sub_v3_v3v3(h, ray_origin, plane_co);
1738 *r_lambda = -dot_v3v3(plane_no, h) / dot;
1739 return true;
1740}
1741
1742bool isect_ray_plane_v3(const float ray_origin[3],
1743 const float ray_direction[3],
1744 const float plane[4],
1745 float *r_lambda,
1746 const bool clip)
1747{
1748 float plane_co[3], plane_no[3];
1749 plane_to_point_vector_v3(plane, plane_co, plane_no);
1750 if (!isect_ray_plane_v3_factor(ray_origin, ray_direction, plane_co, plane_no, r_lambda)) {
1751 return false;
1752 }
1753 if (clip && (*r_lambda < 0.0f)) {
1754 return false;
1755 }
1756 return true;
1757}
1758
1759bool isect_ray_tri_epsilon_v3(const float ray_origin[3],
1760 const float ray_direction[3],
1761 const float v0[3],
1762 const float v1[3],
1763 const float v2[3],
1764 float *r_lambda,
1765 float r_uv[2],
1766 const float epsilon)
1767{
1768 float p[3], s[3], e1[3], e2[3], q[3];
1769 float a, f, u, v;
1770
1771 sub_v3_v3v3(e1, v1, v0);
1772 sub_v3_v3v3(e2, v2, v0);
1773
1774 cross_v3_v3v3(p, ray_direction, e2);
1775 a = dot_v3v3(e1, p);
1776 if (a == 0.0f) {
1777 return false;
1778 }
1779 f = 1.0f / a;
1780
1781 sub_v3_v3v3(s, ray_origin, v0);
1782
1783 u = f * dot_v3v3(s, p);
1784 if ((u < -epsilon) || (u > 1.0f + epsilon)) {
1785 return false;
1786 }
1787
1788 cross_v3_v3v3(q, s, e1);
1789
1790 v = f * dot_v3v3(ray_direction, q);
1791 if ((v < -epsilon) || ((u + v) > 1.0f + epsilon)) {
1792 return false;
1793 }
1794
1795 *r_lambda = f * dot_v3v3(e2, q);
1796 if (*r_lambda < 0.0f) {
1797 return false;
1798 }
1799
1800 if (r_uv) {
1801 r_uv[0] = u;
1802 r_uv[1] = v;
1803 }
1804
1805 return true;
1806}
1807
1809 const float ray_direction[3])
1810{
1811 float inv_dir_z;
1812
1813 /* Calculate dimension where the ray direction is maximal. */
1814 int kz = axis_dominant_v3_single(ray_direction);
1815 int kx = (kz != 2) ? (kz + 1) : 0;
1816 int ky = (kx != 2) ? (kx + 1) : 0;
1817
1818 /* Swap kx and ky dimensions to preserve winding direction of triangles. */
1819 if (ray_direction[kz] < 0.0f) {
1820 std::swap(kx, ky);
1821 }
1822
1823 /* Calculate the shear constants. */
1824 inv_dir_z = 1.0f / ray_direction[kz];
1825 isect_precalc->sx = ray_direction[kx] * inv_dir_z;
1826 isect_precalc->sy = ray_direction[ky] * inv_dir_z;
1827 isect_precalc->sz = inv_dir_z;
1828
1829 /* Store the dimensions. */
1830 isect_precalc->kx = kx;
1831 isect_precalc->ky = ky;
1832 isect_precalc->kz = kz;
1833}
1834
1835bool isect_ray_tri_watertight_v3(const float ray_origin[3],
1836 const IsectRayPrecalc *isect_precalc,
1837 const float v0[3],
1838 const float v1[3],
1839 const float v2[3],
1840 float *r_lambda,
1841 float r_uv[2])
1842{
1843 const int kx = isect_precalc->kx;
1844 const int ky = isect_precalc->ky;
1845 const int kz = isect_precalc->kz;
1846 const float sx = isect_precalc->sx;
1847 const float sy = isect_precalc->sy;
1848 const float sz = isect_precalc->sz;
1849
1850 /* Calculate vertices relative to ray origin. */
1851 const float a[3] = {v0[0] - ray_origin[0], v0[1] - ray_origin[1], v0[2] - ray_origin[2]};
1852 const float b[3] = {v1[0] - ray_origin[0], v1[1] - ray_origin[1], v1[2] - ray_origin[2]};
1853 const float c[3] = {v2[0] - ray_origin[0], v2[1] - ray_origin[1], v2[2] - ray_origin[2]};
1854
1855 const float a_kx = a[kx], a_ky = a[ky], a_kz = a[kz];
1856 const float b_kx = b[kx], b_ky = b[ky], b_kz = b[kz];
1857 const float c_kx = c[kx], c_ky = c[ky], c_kz = c[kz];
1858
1859 /* Perform shear and scale of vertices. */
1860 const float ax = a_kx - sx * a_kz;
1861 const float ay = a_ky - sy * a_kz;
1862 const float bx = b_kx - sx * b_kz;
1863 const float by = b_ky - sy * b_kz;
1864 const float cx = c_kx - sx * c_kz;
1865 const float cy = c_ky - sy * c_kz;
1866
1867 /* Calculate scaled barycentric coordinates. */
1868 const float u = cx * by - cy * bx;
1869 const float v = ax * cy - ay * cx;
1870 const float w = bx * ay - by * ax;
1871 float det;
1872
1873 if ((u < 0.0f || v < 0.0f || w < 0.0f) && (u > 0.0f || v > 0.0f || w > 0.0f)) {
1874 return false;
1875 }
1876
1877 /* Calculate determinant. */
1878 det = u + v + w;
1879 if (UNLIKELY(det == 0.0f || !isfinite(det))) {
1880 return false;
1881 }
1882
1883 /* Calculate scaled z-coordinates of vertices and use them to calculate
1884 * the hit distance.
1885 */
1886 const int sign_det = (float_as_int(det) & int(0x80000000));
1887 const float t = (u * a_kz + v * b_kz + w * c_kz) * sz;
1888 const float sign_t = xor_fl(t, sign_det);
1889 if ((sign_t < 0.0f)
1890 /* Differ from Cycles, don't read r_lambda's original value
1891 * otherwise we won't match any of the other intersect functions here...
1892 * which would be confusing. */
1893#if 0
1894 || (sign_T > *r_lambda * xor_signmask(det, sign_mask))
1895#endif
1896 )
1897 {
1898 return false;
1899 }
1900
1901 /* Normalize u, v and t. */
1902 const float inv_det = 1.0f / det;
1903 if (r_uv) {
1904 r_uv[0] = u * inv_det;
1905 r_uv[1] = v * inv_det;
1906 }
1907 *r_lambda = t * inv_det;
1908 return true;
1909}
1910
1911bool isect_ray_tri_watertight_v3_simple(const float ray_origin[3],
1912 const float ray_direction[3],
1913 const float v0[3],
1914 const float v1[3],
1915 const float v2[3],
1916 float *r_lambda,
1917 float r_uv[2])
1918{
1919 IsectRayPrecalc isect_precalc;
1920 isect_ray_tri_watertight_v3_precalc(&isect_precalc, ray_direction);
1921 return isect_ray_tri_watertight_v3(ray_origin, &isect_precalc, v0, v1, v2, r_lambda, r_uv);
1922}
1923
1924#if 0 /* UNUSED */
1929bool isect_ray_tri_threshold_v3(const float ray_origin[3],
1930 const float ray_direction[3],
1931 const float v0[3],
1932 const float v1[3],
1933 const float v2[3],
1934 float *r_lambda,
1935 float r_uv[2],
1936 const float threshold)
1937{
1938 const float epsilon = 0.00000001f;
1939 float p[3], s[3], e1[3], e2[3], q[3];
1940 float a, f, u, v;
1941 float du, dv;
1942
1943 sub_v3_v3v3(e1, v1, v0);
1944 sub_v3_v3v3(e2, v2, v0);
1945
1946 cross_v3_v3v3(p, ray_direction, e2);
1947 a = dot_v3v3(e1, p);
1948 if ((a > -epsilon) && (a < epsilon)) {
1949 return false;
1950 }
1951 f = 1.0f / a;
1952
1953 sub_v3_v3v3(s, ray_origin, v0);
1954
1955 cross_v3_v3v3(q, s, e1);
1956 *r_lambda = f * dot_v3v3(e2, q);
1957 if (*r_lambda < 0.0f) {
1958 return false;
1959 }
1960
1961 u = f * dot_v3v3(s, p);
1962 v = f * dot_v3v3(ray_direction, q);
1963
1964 if (u > 0 && v > 0 && u + v > 1) {
1965 float t = (u + v - 1) / 2;
1966 du = u - t;
1967 dv = v - t;
1968 }
1969 else {
1970 if (u < 0) {
1971 du = u;
1972 }
1973 else if (u > 1) {
1974 du = u - 1;
1975 }
1976 else {
1977 du = 0.0f;
1978 }
1979
1980 if (v < 0) {
1981 dv = v;
1982 }
1983 else if (v > 1) {
1984 dv = v - 1;
1985 }
1986 else {
1987 dv = 0.0f;
1988 }
1989 }
1990
1991 mul_v3_fl(e1, du);
1992 mul_v3_fl(e2, dv);
1993
1994 if (len_squared_v3(e1) + len_squared_v3(e2) > threshold * threshold) {
1995 return false;
1996 }
1997
1998 if (r_uv) {
1999 r_uv[0] = u;
2000 r_uv[1] = v;
2001 }
2002
2003 return true;
2004}
2005#endif
2006
2007bool isect_ray_seg_v2(const float ray_origin[2],
2008 const float ray_direction[2],
2009 const float v0[2],
2010 const float v1[2],
2011 float *r_lambda,
2012 float *r_u)
2013{
2014 float v0_local[2], v1_local[2];
2015 sub_v2_v2v2(v0_local, v0, ray_origin);
2016 sub_v2_v2v2(v1_local, v1, ray_origin);
2017
2018 float s10[2];
2019 float det;
2020
2021 sub_v2_v2v2(s10, v1_local, v0_local);
2022
2023 det = cross_v2v2(ray_direction, s10);
2024 if (det != 0.0f) {
2025 const float v = cross_v2v2(v0_local, v1_local);
2026 const float p[2] = {(ray_direction[0] * v) / det, (ray_direction[1] * v) / det};
2027
2028 const float t = (dot_v2v2(p, ray_direction) / dot_v2v2(ray_direction, ray_direction));
2029 if ((t >= 0.0f) == 0) {
2030 return false;
2031 }
2032
2033 float h[2];
2034 sub_v2_v2v2(h, v1_local, p);
2035 const float u = (dot_v2v2(s10, h) / dot_v2v2(s10, s10));
2036 if ((u >= 0.0f && u <= 1.0f) == 0) {
2037 return false;
2038 }
2039
2040 if (r_lambda) {
2041 *r_lambda = t;
2042 }
2043 if (r_u) {
2044 *r_u = u;
2045 }
2046
2047 return true;
2048 }
2049
2050 return false;
2051}
2052
2053bool isect_ray_line_v3(const float ray_origin[3],
2054 const float ray_direction[3],
2055 const float v0[3],
2056 const float v1[3],
2057 float *r_lambda)
2058{
2059 float a[3], t[3], n[3];
2060 sub_v3_v3v3(a, v1, v0);
2061 sub_v3_v3v3(t, v0, ray_origin);
2062 cross_v3_v3v3(n, a, ray_direction);
2063 const float nlen = len_squared_v3(n);
2064
2065 if (nlen == 0.0f) {
2066 /* The lines are parallel. */
2067 return false;
2068 }
2069
2070 float c[3], cray[3];
2071 sub_v3_v3v3(c, n, t);
2072 cross_v3_v3v3(cray, c, ray_direction);
2073
2074 *r_lambda = dot_v3v3(cray, n) / nlen;
2075
2076 return true;
2077}
2078
2079bool isect_point_planes_v3(const float (*planes)[4], int totplane, const float p[3])
2080{
2081 int i;
2082
2083 for (i = 0; i < totplane; i++) {
2084 if (plane_point_side_v3(planes[i], p) > 0.0f) {
2085 return false;
2086 }
2087 }
2088
2089 return true;
2090}
2091
2092bool isect_point_planes_v3_negated(const float (*planes)[4], const int totplane, const float p[3])
2093{
2094 for (int i = 0; i < totplane; i++) {
2095 if (plane_point_side_v3(planes[i], p) <= 0.0f) {
2096 return false;
2097 }
2098 }
2099
2100 return true;
2101}
2102
2103bool isect_line_plane_v3(float r_isect_co[3],
2104 const float l1[3],
2105 const float l2[3],
2106 const float plane_co[3],
2107 const float plane_no[3])
2108{
2109 float u[3], h[3];
2110 float dot;
2111
2112 sub_v3_v3v3(u, l2, l1);
2113 sub_v3_v3v3(h, l1, plane_co);
2114 dot = dot_v3v3(plane_no, u);
2115
2116 if (fabsf(dot) > FLT_EPSILON) {
2117 float lambda = -dot_v3v3(plane_no, h) / dot;
2118 madd_v3_v3v3fl(r_isect_co, l1, u, lambda);
2119 return true;
2120 }
2121
2122 /* The segment is parallel to plane */
2123 return false;
2124}
2125
2126bool isect_plane_plane_plane_v3(const float plane_a[4],
2127 const float plane_b[4],
2128 const float plane_c[4],
2129 float r_isect_co[3])
2130{
2131 float det;
2132
2133 det = determinant_m3(UNPACK3(plane_a), UNPACK3(plane_b), UNPACK3(plane_c));
2134
2135 if (det != 0.0f) {
2136 float tmp[3];
2137
2138 /* (plane_b.xyz.cross(plane_c.xyz) * -plane_a[3] +
2139 * plane_c.xyz.cross(plane_a.xyz) * -plane_b[3] +
2140 * plane_a.xyz.cross(plane_b.xyz) * -plane_c[3]) / det; */
2141
2142 cross_v3_v3v3(tmp, plane_c, plane_b);
2143 mul_v3_v3fl(r_isect_co, tmp, plane_a[3]);
2144
2145 cross_v3_v3v3(tmp, plane_a, plane_c);
2146 madd_v3_v3fl(r_isect_co, tmp, plane_b[3]);
2147
2148 cross_v3_v3v3(tmp, plane_b, plane_a);
2149 madd_v3_v3fl(r_isect_co, tmp, plane_c[3]);
2150
2151 mul_v3_fl(r_isect_co, 1.0f / det);
2152
2153 return true;
2154 }
2155
2156 return false;
2157}
2158
2159bool isect_plane_plane_v3(const float plane_a[4],
2160 const float plane_b[4],
2161 float r_isect_co[3],
2162 float r_isect_no[3])
2163{
2164 float det, plane_c[3];
2165
2166 /* direction is simply the cross product */
2167 cross_v3_v3v3(plane_c, plane_a, plane_b);
2168
2169 /* in this case we don't need to use 'determinant_m3' */
2170 det = len_squared_v3(plane_c);
2171
2172 if (det != 0.0f) {
2173 float tmp[3];
2174
2175 /* (plane_b.xyz.cross(plane_c.xyz) * -plane_a[3] +
2176 * plane_c.xyz.cross(plane_a.xyz) * -plane_b[3]) / det; */
2177 cross_v3_v3v3(tmp, plane_c, plane_b);
2178 mul_v3_v3fl(r_isect_co, tmp, plane_a[3]);
2179
2180 cross_v3_v3v3(tmp, plane_a, plane_c);
2181 madd_v3_v3fl(r_isect_co, tmp, plane_b[3]);
2182
2183 mul_v3_fl(r_isect_co, 1.0f / det);
2184
2185 copy_v3_v3(r_isect_no, plane_c);
2186
2187 return true;
2188 }
2189
2190 return false;
2191}
2192
2194 const float planes[][4],
2195 const int planes_len,
2196 const float eps_coplanar,
2197 const float eps_isect,
2198 void (*callback_fn)(const float co[3], int i, int j, int k, void *user_data),
2199 void *user_data)
2200{
2201 bool found = false;
2202
2203 float n1n2[3], n2n3[3], n3n1[3];
2204
2205 for (int i = 0; i < planes_len; i++) {
2206 const float *n1 = planes[i];
2207 for (int j = i + 1; j < planes_len; j++) {
2208 const float *n2 = planes[j];
2209 cross_v3_v3v3(n1n2, n1, n2);
2210 if (len_squared_v3(n1n2) <= eps_coplanar) {
2211 continue;
2212 }
2213 for (int k = j + 1; k < planes_len; k++) {
2214 const float *n3 = planes[k];
2215 cross_v3_v3v3(n2n3, n2, n3);
2216 if (len_squared_v3(n2n3) <= eps_coplanar) {
2217 continue;
2218 }
2219
2220 cross_v3_v3v3(n3n1, n3, n1);
2221 if (len_squared_v3(n3n1) <= eps_coplanar) {
2222 continue;
2223 }
2224 const float quotient = -dot_v3v3(n1, n2n3);
2225 if (fabsf(quotient) < eps_coplanar) {
2226 continue;
2227 }
2228 const float co_test[3] = {
2229 ((n2n3[0] * n1[3]) + (n3n1[0] * n2[3]) + (n1n2[0] * n3[3])) / quotient,
2230 ((n2n3[1] * n1[3]) + (n3n1[1] * n2[3]) + (n1n2[1] * n3[3])) / quotient,
2231 ((n2n3[2] * n1[3]) + (n3n1[2] * n2[3]) + (n1n2[2] * n3[3])) / quotient,
2232 };
2233 int i_test;
2234 for (i_test = 0; i_test < planes_len; i_test++) {
2235 const float *np_test = planes[i_test];
2236 if ((dot_v3v3(np_test, co_test) + np_test[3]) > eps_isect) {
2237 /* For low epsilon values the point could intersect its own plane. */
2238 if (!ELEM(i_test, i, j, k)) {
2239 break;
2240 }
2241 }
2242 }
2243
2244 if (i_test == planes_len) { /* ok */
2245 callback_fn(co_test, i, j, k, user_data);
2246 found = true;
2247 }
2248 }
2249 }
2250 }
2251
2252 return found;
2253}
2254
2255bool isect_tri_tri_v3_ex(const float tri_a[3][3],
2256 const float tri_b[3][3],
2257 float r_i1[3],
2258 float r_i2[3],
2259 int *r_tri_a_edge_isect_count)
2260{
2261 struct {
2262 /* Factor that indicates the position of the intersection point on the line
2263 * that intersects the planes of the triangles. */
2264 float min, max;
2265 /* Intersection point location. */
2266 float loc[2][3];
2267 } range[2];
2268
2269 float side[2][3];
2270 double ba[3], bc[3], plane_a[4], plane_b[4];
2271 *r_tri_a_edge_isect_count = 0;
2272
2273 sub_v3db_v3fl_v3fl(ba, tri_a[0], tri_a[1]);
2274 sub_v3db_v3fl_v3fl(bc, tri_a[2], tri_a[1]);
2275 cross_v3_v3v3_db(plane_a, ba, bc);
2276 plane_a[3] = -dot_v3db_v3fl(plane_a, tri_a[1]);
2277 side[1][0] = float(dot_v3db_v3fl(plane_a, tri_b[0]) + plane_a[3]);
2278 side[1][1] = float(dot_v3db_v3fl(plane_a, tri_b[1]) + plane_a[3]);
2279 side[1][2] = float(dot_v3db_v3fl(plane_a, tri_b[2]) + plane_a[3]);
2280
2281 if (!side[1][0] && !side[1][1] && !side[1][2]) {
2282 /* Coplanar case is not supported. */
2283 return false;
2284 }
2285
2286 if ((side[1][0] && side[1][1] && side[1][2]) && (side[1][0] < 0.0f) == (side[1][1] < 0.0f) &&
2287 (side[1][0] < 0.0f) == (side[1][2] < 0.0f))
2288 {
2289 /* All vertices of the 2nd triangle are positioned on the same side to the
2290 * plane defined by the 1st triangle. */
2291 return false;
2292 }
2293
2294 sub_v3db_v3fl_v3fl(ba, tri_b[0], tri_b[1]);
2295 sub_v3db_v3fl_v3fl(bc, tri_b[2], tri_b[1]);
2296 cross_v3_v3v3_db(plane_b, ba, bc);
2297 plane_b[3] = -dot_v3db_v3fl(plane_b, tri_b[1]);
2298 side[0][0] = float(dot_v3db_v3fl(plane_b, tri_a[0]) + plane_b[3]);
2299 side[0][1] = float(dot_v3db_v3fl(plane_b, tri_a[1]) + plane_b[3]);
2300 side[0][2] = float(dot_v3db_v3fl(plane_b, tri_a[2]) + plane_b[3]);
2301
2302 if ((side[0][0] && side[0][1] && side[0][2]) && (side[0][0] < 0.0f) == (side[0][1] < 0.0f) &&
2303 (side[0][0] < 0.0f) == (side[0][2] < 0.0f))
2304 {
2305 /* All vertices of the 1st triangle are positioned on the same side to the
2306 * plane defined by the 2nd triangle. */
2307 return false;
2308 }
2309
2310 /* Direction of the line that intersects the planes of the triangles. */
2311 double isect_dir[3];
2312 cross_v3_v3v3_db(isect_dir, plane_a, plane_b);
2313 for (int i = 0; i < 2; i++) {
2314 const float(*tri)[3] = i == 0 ? tri_a : tri_b;
2315 /* Rearrange the triangle so that the vertex that is alone on one side
2316 * of the plane is located at index 1. */
2317 int tri_i[3];
2318 if ((side[i][0] && side[i][1]) && (side[i][0] < 0.0f) == (side[i][1] < 0.0f)) {
2319 tri_i[0] = 1;
2320 tri_i[1] = 2;
2321 tri_i[2] = 0;
2322 }
2323 else if ((side[i][1] && side[i][2]) && (side[i][1] < 0.0f) == (side[i][2] < 0.0f)) {
2324 tri_i[0] = 2;
2325 tri_i[1] = 0;
2326 tri_i[2] = 1;
2327 }
2328 else {
2329 tri_i[0] = 0;
2330 tri_i[1] = 1;
2331 tri_i[2] = 2;
2332 }
2333
2334 double dot_b = dot_v3db_v3fl(isect_dir, tri[tri_i[1]]);
2335 float sidec = side[i][tri_i[1]];
2336 if (sidec) {
2337 double dot_a = dot_v3db_v3fl(isect_dir, tri[tri_i[0]]);
2338 double dot_c = dot_v3db_v3fl(isect_dir, tri[tri_i[2]]);
2339 float fac0 = sidec / (sidec - side[i][tri_i[0]]);
2340 float fac1 = sidec / (sidec - side[i][tri_i[2]]);
2341 double offset0 = fac0 * (dot_a - dot_b);
2342 double offset1 = fac1 * (dot_c - dot_b);
2343 if (offset0 > offset1) {
2344 /* Sort min max. */
2345 std::swap(offset0, offset1);
2346 std::swap(fac0, fac1);
2347 std::swap(tri_i[0], tri_i[2]);
2348 }
2349
2350 range[i].min = float(dot_b + offset0);
2351 range[i].max = float(dot_b + offset1);
2352 interp_v3_v3v3(range[i].loc[0], tri[tri_i[1]], tri[tri_i[0]], fac0);
2353 interp_v3_v3v3(range[i].loc[1], tri[tri_i[1]], tri[tri_i[2]], fac1);
2354 }
2355 else {
2356 range[i].min = range[i].max = float(dot_b);
2357 copy_v3_v3(range[i].loc[0], tri[tri_i[1]]);
2358 copy_v3_v3(range[i].loc[1], tri[tri_i[1]]);
2359 }
2360 }
2361
2362 if ((range[0].max > range[1].min) && (range[0].min < range[1].max)) {
2363 /* The triangles intersect because they overlap on the intersection line.
2364 * Now identify the two points of intersection that are in the middle to get the actual
2365 * intersection between the triangles. (B--C from A--B--C--D) */
2366 if (range[0].min >= range[1].min) {
2367 copy_v3_v3(r_i1, range[0].loc[0]);
2368 if (range[0].max <= range[1].max) {
2369 copy_v3_v3(r_i2, range[0].loc[1]);
2370 *r_tri_a_edge_isect_count = 2;
2371 }
2372 else {
2373 copy_v3_v3(r_i2, range[1].loc[1]);
2374 *r_tri_a_edge_isect_count = 1;
2375 }
2376 }
2377 else {
2378 if (range[0].max <= range[1].max) {
2379 copy_v3_v3(r_i1, range[0].loc[1]);
2380 copy_v3_v3(r_i2, range[1].loc[0]);
2381 *r_tri_a_edge_isect_count = 1;
2382 }
2383 else {
2384 copy_v3_v3(r_i1, range[1].loc[0]);
2385 copy_v3_v3(r_i2, range[1].loc[1]);
2386 }
2387 }
2388 return true;
2389 }
2390
2391 return false;
2392}
2393
2394bool isect_tri_tri_v3(const float t_a0[3],
2395 const float t_a1[3],
2396 const float t_a2[3],
2397 const float t_b0[3],
2398 const float t_b1[3],
2399 const float t_b2[3],
2400 float r_i1[3],
2401 float r_i2[3])
2402{
2403 float tri_a[3][3], tri_b[3][3];
2404 int dummy;
2405 copy_v3_v3(tri_a[0], t_a0);
2406 copy_v3_v3(tri_a[1], t_a1);
2407 copy_v3_v3(tri_a[2], t_a2);
2408 copy_v3_v3(tri_b[0], t_b0);
2409 copy_v3_v3(tri_b[1], t_b1);
2410 copy_v3_v3(tri_b[2], t_b2);
2411 return isect_tri_tri_v3_ex(tri_a, tri_b, r_i1, r_i2, &dummy);
2412}
2413
2414/* -------------------------------------------------------------------- */
2422
2423static bool isect_tri_tri_v2_impl_vert(const float t_a0[2],
2424 const float t_a1[2],
2425 const float t_a2[2],
2426 const float t_b0[2],
2427 const float t_b1[2],
2428 const float t_b2[2])
2429{
2430 if (line_point_side_v2(t_b2, t_b0, t_a1) >= 0.0f) {
2431 if (line_point_side_v2(t_b2, t_b1, t_a1) <= 0.0f) {
2432 if (line_point_side_v2(t_a0, t_b0, t_a1) > 0.0f) {
2433 if (line_point_side_v2(t_a0, t_b1, t_a1) <= 0.0f) {
2434 return true;
2435 }
2436
2437 return false;
2438 }
2439
2440 if (line_point_side_v2(t_a0, t_b0, t_a2) >= 0.0f) {
2441 if (line_point_side_v2(t_a1, t_a2, t_b0) >= 0.0f) {
2442 return true;
2443 }
2444
2445 return false;
2446 }
2447
2448 return false;
2449 }
2450 if (line_point_side_v2(t_a0, t_b1, t_a1) <= 0.0f) {
2451 if (line_point_side_v2(t_b2, t_b1, t_a2) <= 0.0f) {
2452 if (line_point_side_v2(t_a1, t_a2, t_b1) >= 0.0f) {
2453 return true;
2454 }
2455
2456 return false;
2457 }
2458
2459 return false;
2460 }
2461
2462 return false;
2463 }
2464 if (line_point_side_v2(t_b2, t_b0, t_a2) >= 0.0f) {
2465 if (line_point_side_v2(t_a1, t_a2, t_b2) >= 0.0f) {
2466 if (line_point_side_v2(t_a0, t_b0, t_a2) >= 0.0f) {
2467 return true;
2468 }
2469
2470 return false;
2471 }
2472 if (line_point_side_v2(t_a1, t_a2, t_b1) >= 0.0f) {
2473 if (line_point_side_v2(t_b2, t_a2, t_b1) >= 0.0f) {
2474 return true;
2475 }
2476
2477 return false;
2478 }
2479
2480 return false;
2481 }
2482
2483 return false;
2484}
2485
2486static bool isect_tri_tri_v2_impl_edge(const float t_a0[2],
2487 const float t_a1[2],
2488 const float t_a2[2],
2489 const float t_b0[2],
2490 const float t_b1[2],
2491 const float t_b2[2])
2492{
2493 UNUSED_VARS(t_b1);
2494
2495 if (line_point_side_v2(t_b2, t_b0, t_a1) >= 0.0f) {
2496 if (line_point_side_v2(t_a0, t_b0, t_a1) >= 0.0f) {
2497 if (line_point_side_v2(t_a0, t_a1, t_b2) >= 0.0f) {
2498 return true;
2499 }
2500
2501 return false;
2502 }
2503
2504 if (line_point_side_v2(t_a1, t_a2, t_b0) >= 0.0f) {
2505 if (line_point_side_v2(t_a2, t_a0, t_b0) >= 0.0f) {
2506 return true;
2507 }
2508
2509 return false;
2510 }
2511
2512 return false;
2513 }
2514
2515 if (line_point_side_v2(t_b2, t_b0, t_a2) >= 0.0f) {
2516 if (line_point_side_v2(t_a0, t_b0, t_a2) >= 0.0f) {
2517 if (line_point_side_v2(t_a0, t_a2, t_b2) >= 0.0f) {
2518 return true;
2519 }
2520
2521 if (line_point_side_v2(t_a1, t_a2, t_b2) >= 0.0f) {
2522 return true;
2523 }
2524
2525 return false;
2526 }
2527
2528 return false;
2529 }
2530
2531 return false;
2532}
2533
2534static int isect_tri_tri_impl_ccw_v2(const float t_a0[2],
2535 const float t_a1[2],
2536 const float t_a2[2],
2537 const float t_b0[2],
2538 const float t_b1[2],
2539 const float t_b2[2])
2540{
2541 if (line_point_side_v2(t_b0, t_b1, t_a0) >= 0.0f) {
2542 if (line_point_side_v2(t_b1, t_b2, t_a0) >= 0.0f) {
2543 if (line_point_side_v2(t_b2, t_b0, t_a0) >= 0.0f) {
2544 return 1;
2545 }
2546
2547 return isect_tri_tri_v2_impl_edge(t_a0, t_a1, t_a2, t_b0, t_b1, t_b2);
2548 }
2549
2550 if (line_point_side_v2(t_b2, t_b0, t_a0) >= 0.0f) {
2551 return isect_tri_tri_v2_impl_edge(t_a0, t_a1, t_a2, t_b2, t_b0, t_b1);
2552 }
2553
2554 return isect_tri_tri_v2_impl_vert(t_a0, t_a1, t_a2, t_b0, t_b1, t_b2);
2555 }
2556
2557 if (line_point_side_v2(t_b1, t_b2, t_a0) >= 0.0f) {
2558 if (line_point_side_v2(t_b2, t_b0, t_a0) >= 0.0f) {
2559 return isect_tri_tri_v2_impl_edge(t_a0, t_a1, t_a2, t_b1, t_b2, t_b0);
2560 }
2561
2562 return isect_tri_tri_v2_impl_vert(t_a0, t_a1, t_a2, t_b1, t_b2, t_b0);
2563 }
2564
2565 return isect_tri_tri_v2_impl_vert(t_a0, t_a1, t_a2, t_b2, t_b0, t_b1);
2566}
2567
2568bool isect_tri_tri_v2(const float t_a0[2],
2569 const float t_a1[2],
2570 const float t_a2[2],
2571 const float t_b0[2],
2572 const float t_b1[2],
2573 const float t_b2[2])
2574{
2575 if (line_point_side_v2(t_a0, t_a1, t_a2) < 0.0f) {
2576 if (line_point_side_v2(t_b0, t_b1, t_b2) < 0.0f) {
2577 return isect_tri_tri_impl_ccw_v2(t_a0, t_a2, t_a1, t_b0, t_b2, t_b1);
2578 }
2579
2580 return isect_tri_tri_impl_ccw_v2(t_a0, t_a2, t_a1, t_b0, t_b1, t_b2);
2581 }
2582
2583 if (line_point_side_v2(t_b0, t_b1, t_b2) < 0.0f) {
2584 return isect_tri_tri_impl_ccw_v2(t_a0, t_a1, t_a2, t_b0, t_b2, t_b1);
2585 }
2586
2587 return isect_tri_tri_impl_ccw_v2(t_a0, t_a1, t_a2, t_b0, t_b1, t_b2);
2588}
2589
2591
2592/* Adapted from the paper by Kasper Fauerby */
2593
2594/* "Improved Collision detection and Response" */
2595static bool getLowestRoot(
2596 const float a, const float b, const float c, const float maxR, float *root)
2597{
2598 /* Check if a solution exists */
2599 const float determinant = b * b - 4.0f * a * c;
2600
2601 /* If determinant is negative it means no solutions. */
2602 if (determinant >= 0.0f) {
2603 /* calculate the two roots: (if determinant == 0 then
2604 * x1==x2 but lets disregard that slight optimization) */
2605 const float sqrtD = sqrtf(determinant);
2606 float r1 = (-b - sqrtD) / (2.0f * a);
2607 float r2 = (-b + sqrtD) / (2.0f * a);
2608
2609 /* Sort so x1 <= x2 */
2610 if (r1 > r2) {
2611 std::swap(r1, r2);
2612 }
2613
2614 /* Get lowest root: */
2615 if (r1 > 0.0f && r1 < maxR) {
2616 *root = r1;
2617 return true;
2618 }
2619
2620 /* It is possible that we want x2 - this can happen */
2621 /* if x1 < 0 */
2622 if (r2 > 0.0f && r2 < maxR) {
2623 *root = r2;
2624 return true;
2625 }
2626 }
2627 /* No (valid) solutions */
2628 return false;
2629}
2630
2631int isect_aabb_planes_v3(const float (*planes)[4],
2632 const int totplane,
2633 const float bbmin[3],
2634 const float bbmax[3])
2635{
2637
2638 float bb_near[3], bb_far[3];
2639 for (int i = 0; i < totplane; i++) {
2640 aabb_get_near_far_from_plane(planes[i], bbmin, bbmax, bb_near, bb_far);
2641
2642 if (plane_point_side_v3(planes[i], bb_far) < 0.0f) {
2644 }
2645 if ((ret != ISECT_AABB_PLANE_CROSS_ANY) && (plane_point_side_v3(planes[i], bb_near) < 0.0f)) {
2647 }
2648 }
2649
2650 return ret;
2651}
2652
2653bool isect_sweeping_sphere_tri_v3(const float p1[3],
2654 const float p2[3],
2655 const float radius,
2656 const float v0[3],
2657 const float v1[3],
2658 const float v2[3],
2659 float *r_lambda,
2660 float ipoint[3])
2661{
2662 float e1[3], e2[3], e3[3], point[3], vel[3], /*dist[3],*/ nor[3], temp[3], bv[3];
2663 float a, b, c, d, e, x, y, z, radius2 = radius * radius;
2664 float elen2, edotv, edotbv, nordotv;
2665 float newLambda;
2666 bool found_by_sweep = false;
2667
2668 sub_v3_v3v3(e1, v1, v0);
2669 sub_v3_v3v3(e2, v2, v0);
2670 sub_v3_v3v3(vel, p2, p1);
2671
2672 /*---test plane of tri---*/
2673 cross_v3_v3v3(nor, e1, e2);
2675
2676 /* flip normal */
2677 if (dot_v3v3(nor, vel) > 0.0f) {
2678 negate_v3(nor);
2679 }
2680
2681 a = dot_v3v3(p1, nor) - dot_v3v3(v0, nor);
2682 nordotv = dot_v3v3(nor, vel);
2683
2684 if (fabsf(nordotv) < 0.000001f) {
2685 if (fabsf(a) >= radius) {
2686 return false;
2687 }
2688 }
2689 else {
2690 float t0 = (-a + radius) / nordotv;
2691 float t1 = (-a - radius) / nordotv;
2692
2693 if (t0 > t1) {
2694 std::swap(t0, t1);
2695 }
2696
2697 if (t0 > 1.0f || t1 < 0.0f) {
2698 return false;
2699 }
2700
2701 /* clamp to [0, 1] */
2702 CLAMP(t0, 0.0f, 1.0f);
2703 // CLAMP(t1, 0.0f, 1.0f); /* UNUSED. */
2704
2705 /*---test inside of tri---*/
2706 /* plane intersection point */
2707
2708 point[0] = p1[0] + vel[0] * t0 - nor[0] * radius;
2709 point[1] = p1[1] + vel[1] * t0 - nor[1] * radius;
2710 point[2] = p1[2] + vel[2] * t0 - nor[2] * radius;
2711
2712 /* is the point in the tri? */
2713 a = dot_v3v3(e1, e1);
2714 b = dot_v3v3(e1, e2);
2715 c = dot_v3v3(e2, e2);
2716
2717 sub_v3_v3v3(temp, point, v0);
2718 d = dot_v3v3(temp, e1);
2719 e = dot_v3v3(temp, e2);
2720
2721 x = d * c - e * b;
2722 y = e * a - d * b;
2723 z = x + y - (a * c - b * b);
2724
2725 if (z <= 0.0f && (x >= 0.0f && y >= 0.0f)) {
2726 // ((uint32_t(z) & ~(uint32_t(x) | uint32_t(y))) & 0x80000000)
2727 *r_lambda = t0;
2728 copy_v3_v3(ipoint, point);
2729 return true;
2730 }
2731 }
2732
2733 *r_lambda = 1.0f;
2734
2735 /*---test points---*/
2736 a = dot_v3v3(vel, vel);
2737
2738 /*v0*/
2739 sub_v3_v3v3(temp, p1, v0);
2740 b = 2.0f * dot_v3v3(vel, temp);
2741 c = dot_v3v3(temp, temp) - radius2;
2742
2743 if (getLowestRoot(a, b, c, *r_lambda, r_lambda)) {
2744 copy_v3_v3(ipoint, v0);
2745 found_by_sweep = true;
2746 }
2747
2748 /*v1*/
2749 sub_v3_v3v3(temp, p1, v1);
2750 b = 2.0f * dot_v3v3(vel, temp);
2751 c = dot_v3v3(temp, temp) - radius2;
2752
2753 if (getLowestRoot(a, b, c, *r_lambda, r_lambda)) {
2754 copy_v3_v3(ipoint, v1);
2755 found_by_sweep = true;
2756 }
2757
2758 /*v2*/
2759 sub_v3_v3v3(temp, p1, v2);
2760 b = 2.0f * dot_v3v3(vel, temp);
2761 c = dot_v3v3(temp, temp) - radius2;
2762
2763 if (getLowestRoot(a, b, c, *r_lambda, r_lambda)) {
2764 copy_v3_v3(ipoint, v2);
2765 found_by_sweep = true;
2766 }
2767
2768 /*---test edges---*/
2769 sub_v3_v3v3(e3, v2, v1); /* wasn't yet calculated */
2770
2771 /* `e1` */
2772 sub_v3_v3v3(bv, v0, p1);
2773
2774 elen2 = dot_v3v3(e1, e1);
2775 edotv = dot_v3v3(e1, vel);
2776 edotbv = dot_v3v3(e1, bv);
2777
2778 a = elen2 * -dot_v3v3(vel, vel) + edotv * edotv;
2779 b = 2.0f * (elen2 * dot_v3v3(vel, bv) - edotv * edotbv);
2780 c = elen2 * (radius2 - dot_v3v3(bv, bv)) + edotbv * edotbv;
2781
2782 if (getLowestRoot(a, b, c, *r_lambda, &newLambda)) {
2783 e = (edotv * newLambda - edotbv) / elen2;
2784
2785 if (e >= 0.0f && e <= 1.0f) {
2786 *r_lambda = newLambda;
2787 copy_v3_v3(ipoint, e1);
2788 mul_v3_fl(ipoint, e);
2789 add_v3_v3(ipoint, v0);
2790 found_by_sweep = true;
2791 }
2792 }
2793
2794 /* `e2` */
2795 /* `bv` is same. */
2796 elen2 = dot_v3v3(e2, e2);
2797 edotv = dot_v3v3(e2, vel);
2798 edotbv = dot_v3v3(e2, bv);
2799
2800 a = elen2 * -dot_v3v3(vel, vel) + edotv * edotv;
2801 b = 2.0f * (elen2 * dot_v3v3(vel, bv) - edotv * edotbv);
2802 c = elen2 * (radius2 - dot_v3v3(bv, bv)) + edotbv * edotbv;
2803
2804 if (getLowestRoot(a, b, c, *r_lambda, &newLambda)) {
2805 e = (edotv * newLambda - edotbv) / elen2;
2806
2807 if (e >= 0.0f && e <= 1.0f) {
2808 *r_lambda = newLambda;
2809 copy_v3_v3(ipoint, e2);
2810 mul_v3_fl(ipoint, e);
2811 add_v3_v3(ipoint, v0);
2812 found_by_sweep = true;
2813 }
2814 }
2815
2816 /* `e3` */
2817 // sub_v3_v3v3(bv, v0, p1); /* UNUSED */
2818 // elen2 = dot_v3v3(e1, e1); /* UNUSED */
2819 // edotv = dot_v3v3(e1, vel); /* UNUSED */
2820 // edotbv = dot_v3v3(e1, bv); /* UNUSED */
2821
2822 sub_v3_v3v3(bv, v1, p1);
2823 elen2 = dot_v3v3(e3, e3);
2824 edotv = dot_v3v3(e3, vel);
2825 edotbv = dot_v3v3(e3, bv);
2826
2827 a = elen2 * -dot_v3v3(vel, vel) + edotv * edotv;
2828 b = 2.0f * (elen2 * dot_v3v3(vel, bv) - edotv * edotbv);
2829 c = elen2 * (radius2 - dot_v3v3(bv, bv)) + edotbv * edotbv;
2830
2831 if (getLowestRoot(a, b, c, *r_lambda, &newLambda)) {
2832 e = (edotv * newLambda - edotbv) / elen2;
2833
2834 if (e >= 0.0f && e <= 1.0f) {
2835 *r_lambda = newLambda;
2836 copy_v3_v3(ipoint, e3);
2837 mul_v3_fl(ipoint, e);
2838 add_v3_v3(ipoint, v1);
2839 found_by_sweep = true;
2840 }
2841 }
2842
2843 return found_by_sweep;
2844}
2845
2847 const float p1[3],
2848 const float p2[3],
2849 const float v0[3],
2850 const float v1[3],
2851 const float v2[3],
2852 float *r_lambda)
2853{
2854 const float epsilon = 0.000001f;
2855 float p[3], e1[3], e2[3];
2856 float u, v, f;
2857 int a0 = axis, a1 = (axis + 1) % 3, a2 = (axis + 2) % 3;
2858
2859 sub_v3_v3v3(e1, v1, v0);
2860 sub_v3_v3v3(e2, v2, v0);
2861 sub_v3_v3v3(p, v0, p1);
2862
2863 f = (e2[a1] * e1[a2] - e2[a2] * e1[a1]);
2864 if ((f > -epsilon) && (f < epsilon)) {
2865 return false;
2866 }
2867
2868 v = (p[a2] * e1[a1] - p[a1] * e1[a2]) / f;
2869 if ((v < 0.0f) || (v > 1.0f)) {
2870 return false;
2871 }
2872
2873 f = e1[a1];
2874 if ((f > -epsilon) && (f < epsilon)) {
2875 f = e1[a2];
2876 if ((f > -epsilon) && (f < epsilon)) {
2877 return false;
2878 }
2879 u = (-p[a2] - v * e2[a2]) / f;
2880 }
2881 else {
2882 u = (-p[a1] - v * e2[a1]) / f;
2883 }
2884
2885 if ((u < 0.0f) || ((u + v) > 1.0f)) {
2886 return false;
2887 }
2888
2889 *r_lambda = (p[a0] + u * e1[a0] + v * e2[a0]) / (p2[a0] - p1[a0]);
2890
2891 if ((*r_lambda < 0.0f) || (*r_lambda > 1.0f)) {
2892 return false;
2893 }
2894
2895 return true;
2896}
2897
2898int isect_line_line_epsilon_v3(const float v1[3],
2899 const float v2[3],
2900 const float v3[3],
2901 const float v4[3],
2902 float r_i1[3],
2903 float r_i2[3],
2904 const float epsilon)
2905{
2906 float a[3], b[3], c[3], ab[3], cb[3];
2907 float d, div;
2908
2909 sub_v3_v3v3(c, v3, v1);
2910 sub_v3_v3v3(a, v2, v1);
2911 sub_v3_v3v3(b, v4, v3);
2912
2913 cross_v3_v3v3(ab, a, b);
2914 d = dot_v3v3(c, ab);
2915 div = dot_v3v3(ab, ab);
2916
2917 /* important not to use an epsilon here, see: #45919 */
2918 /* test zero length line */
2919 if (UNLIKELY(div == 0.0f)) {
2920 return 0;
2921 }
2922 /* test if the two lines are coplanar */
2923 if (UNLIKELY(fabsf(d) <= epsilon)) {
2924 cross_v3_v3v3(cb, c, b);
2925
2926 mul_v3_fl(a, dot_v3v3(cb, ab) / div);
2927 add_v3_v3v3(r_i1, v1, a);
2928 copy_v3_v3(r_i2, r_i1);
2929
2930 return 1; /* one intersection only */
2931 }
2932 /* if not */
2933
2934 float n[3], t[3];
2935 float v3t[3], v4t[3];
2936 sub_v3_v3v3(t, v1, v3);
2937
2938 /* offset between both plane where the lines lies */
2939 cross_v3_v3v3(n, a, b);
2940 project_v3_v3v3(t, t, n);
2941
2942 /* for the first line, offset the second line until it is coplanar */
2943 add_v3_v3v3(v3t, v3, t);
2944 add_v3_v3v3(v4t, v4, t);
2945
2946 sub_v3_v3v3(c, v3t, v1);
2947 sub_v3_v3v3(a, v2, v1);
2948 sub_v3_v3v3(b, v4t, v3t);
2949
2950 cross_v3_v3v3(ab, a, b);
2951 cross_v3_v3v3(cb, c, b);
2952
2953 mul_v3_fl(a, dot_v3v3(cb, ab) / dot_v3v3(ab, ab));
2954 add_v3_v3v3(r_i1, v1, a);
2955
2956 /* for the second line, just subtract the offset from the first intersection point */
2957 sub_v3_v3v3(r_i2, r_i1, t);
2958
2959 return 2; /* two nearest points */
2960}
2961
2962int isect_line_line_v3(const float v1[3],
2963 const float v2[3],
2964 const float v3[3],
2965 const float v4[3],
2966 float r_i1[3],
2967 float r_i2[3])
2968{
2969 const float epsilon = 0.000001f;
2970 return isect_line_line_epsilon_v3(v1, v2, v3, v4, r_i1, r_i2, epsilon);
2971}
2972
2973bool isect_line_line_strict_v3(const float v1[3],
2974 const float v2[3],
2975 const float v3[3],
2976 const float v4[3],
2977 float vi[3],
2978 float *r_lambda)
2979{
2980 const float epsilon = 0.000001f;
2981 float a[3], b[3], c[3], ab[3], cb[3], ca[3];
2982 float d, div;
2983
2984 sub_v3_v3v3(c, v3, v1);
2985 sub_v3_v3v3(a, v2, v1);
2986 sub_v3_v3v3(b, v4, v3);
2987
2988 cross_v3_v3v3(ab, a, b);
2989 d = dot_v3v3(c, ab);
2990 div = dot_v3v3(ab, ab);
2991
2992 /* important not to use an epsilon here, see: #45919 */
2993 /* test zero length line */
2994 if (UNLIKELY(div == 0.0f)) {
2995 return false;
2996 }
2997 /* test if the two lines are coplanar */
2998 if (UNLIKELY(fabsf(d) < epsilon)) {
2999 return false;
3000 }
3001
3002 float f1, f2;
3003 cross_v3_v3v3(cb, c, b);
3004 cross_v3_v3v3(ca, c, a);
3005
3006 f1 = dot_v3v3(cb, ab) / div;
3007 f2 = dot_v3v3(ca, ab) / div;
3008
3009 if (f1 >= 0 && f1 <= 1 && f2 >= 0 && f2 <= 1) {
3010 mul_v3_fl(a, f1);
3011 add_v3_v3v3(vi, v1, a);
3012
3013 if (r_lambda) {
3014 *r_lambda = f1;
3015 }
3016
3017 return true; /* intersection found */
3018 }
3019
3020 return false;
3021}
3022
3023bool isect_ray_ray_epsilon_v3(const float ray_origin_a[3],
3024 const float ray_direction_a[3],
3025 const float ray_origin_b[3],
3026 const float ray_direction_b[3],
3027 const float epsilon,
3028 float *r_lambda_a,
3029 float *r_lambda_b)
3030{
3031 BLI_assert(r_lambda_a || r_lambda_b);
3032 float n[3];
3033 cross_v3_v3v3(n, ray_direction_b, ray_direction_a);
3034 const float nlen = len_squared_v3(n);
3035
3036 /* `nlen` is the square of the area formed by the two vectors. */
3037 if (UNLIKELY(nlen < epsilon)) {
3038 /* The lines are parallel. */
3039 return false;
3040 }
3041
3042 float t[3], c[3], cray[3];
3043 sub_v3_v3v3(t, ray_origin_b, ray_origin_a);
3044 sub_v3_v3v3(c, n, t);
3045
3046 if (r_lambda_a != nullptr) {
3047 cross_v3_v3v3(cray, c, ray_direction_b);
3048 *r_lambda_a = dot_v3v3(cray, n) / nlen;
3049 }
3050
3051 if (r_lambda_b != nullptr) {
3052 cross_v3_v3v3(cray, c, ray_direction_a);
3053 *r_lambda_b = dot_v3v3(cray, n) / nlen;
3054 }
3055
3056 return true;
3057}
3058
3059bool isect_ray_ray_v3(const float ray_origin_a[3],
3060 const float ray_direction_a[3],
3061 const float ray_origin_b[3],
3062 const float ray_direction_b[3],
3063 float *r_lambda_a,
3064 float *r_lambda_b)
3065{
3066 return isect_ray_ray_epsilon_v3(ray_origin_a,
3067 ray_direction_a,
3068 ray_origin_b,
3069 ray_direction_b,
3070 FLT_MIN,
3071 r_lambda_a,
3072 r_lambda_b);
3073}
3074
3075bool isect_aabb_aabb_v3(const float min1[3],
3076 const float max1[3],
3077 const float min2[3],
3078 const float max2[3])
3079{
3080 return (min1[0] < max2[0] && min1[1] < max2[1] && min1[2] < max2[2] && min2[0] < max1[0] &&
3081 min2[1] < max1[1] && min2[2] < max1[2]);
3082}
3083
3085 const float ray_origin[3],
3086 const float ray_direction[3])
3087{
3088 copy_v3_v3(data->ray_origin, ray_origin);
3089
3090 data->ray_inv_dir[0] = 1.0f / ray_direction[0];
3091 data->ray_inv_dir[1] = 1.0f / ray_direction[1];
3092 data->ray_inv_dir[2] = 1.0f / ray_direction[2];
3093
3094 data->sign[0] = data->ray_inv_dir[0] < 0.0f;
3095 data->sign[1] = data->ray_inv_dir[1] < 0.0f;
3096 data->sign[2] = data->ray_inv_dir[2] < 0.0f;
3097}
3098
3100 const float bb_min[3],
3101 const float bb_max[3],
3102 float *r_tmin)
3103{
3104 /* Adapted from http://www.gamedev.net/community/forums/topic.asp?topic_id=459973 */
3105
3106 float bbox[2][3];
3107
3108 copy_v3_v3(bbox[0], bb_min);
3109 copy_v3_v3(bbox[1], bb_max);
3110
3111 float tmin = (bbox[data->sign[0]][0] - data->ray_origin[0]) * data->ray_inv_dir[0];
3112 float tmax = (bbox[1 - data->sign[0]][0] - data->ray_origin[0]) * data->ray_inv_dir[0];
3113
3114 const float tymin = (bbox[data->sign[1]][1] - data->ray_origin[1]) * data->ray_inv_dir[1];
3115 const float tymax = (bbox[1 - data->sign[1]][1] - data->ray_origin[1]) * data->ray_inv_dir[1];
3116
3117 if ((tmin > tymax) || (tymin > tmax)) {
3118 return false;
3119 }
3120
3121 if (tymin > tmin) {
3122 tmin = tymin;
3123 }
3124
3125 if (tymax < tmax) {
3126 tmax = tymax;
3127 }
3128
3129 const float tzmin = (bbox[data->sign[2]][2] - data->ray_origin[2]) * data->ray_inv_dir[2];
3130 const float tzmax = (bbox[1 - data->sign[2]][2] - data->ray_origin[2]) * data->ray_inv_dir[2];
3131
3132 if ((tmin > tzmax) || (tzmin > tmax)) {
3133 return false;
3134 }
3135
3136 if (tzmin > tmin) {
3137 tmin = tzmin;
3138 }
3139
3140 /* NOTE(jwilkins): tmax does not need to be updated since we don't use it
3141 * keeping this here for future reference. */
3142 // if (tzmax < tmax) tmax = tzmax;
3143
3144 if (r_tmin) {
3145 (*r_tmin) = tmin;
3146 }
3147
3148 return true;
3149}
3150
3151bool isect_ray_aabb_v3_simple(const float orig[3],
3152 const float dir[3],
3153 const float bb_min[3],
3154 const float bb_max[3],
3155 float *tmin,
3156 float *tmax)
3157{
3158 double t[6];
3159 float hit_dist[2];
3160 const double invdirx = (dir[0] > 1e-35f || dir[0] < -1e-35f) ? 1.0 / double(dir[0]) : DBL_MAX;
3161 const double invdiry = (dir[1] > 1e-35f || dir[1] < -1e-35f) ? 1.0 / double(dir[1]) : DBL_MAX;
3162 const double invdirz = (dir[2] > 1e-35f || dir[2] < -1e-35f) ? 1.0 / double(dir[2]) : DBL_MAX;
3163 t[0] = double(bb_min[0] - orig[0]) * invdirx;
3164 t[1] = double(bb_max[0] - orig[0]) * invdirx;
3165 t[2] = double(bb_min[1] - orig[1]) * invdiry;
3166 t[3] = double(bb_max[1] - orig[1]) * invdiry;
3167 t[4] = double(bb_min[2] - orig[2]) * invdirz;
3168 t[5] = double(bb_max[2] - orig[2]) * invdirz;
3169 hit_dist[0] = float(fmax(fmax(fmin(t[0], t[1]), fmin(t[2], t[3])), fmin(t[4], t[5])));
3170 hit_dist[1] = float(fmin(fmin(fmax(t[0], t[1]), fmax(t[2], t[3])), fmax(t[4], t[5])));
3171 if ((hit_dist[1] < 0.0f) || (hit_dist[0] > hit_dist[1])) {
3172 return false;
3173 }
3174
3175 if (tmin) {
3176 *tmin = hit_dist[0];
3177 }
3178 if (tmax) {
3179 *tmax = hit_dist[1];
3180 }
3181 return true;
3182}
3183
3184float closest_to_ray_v3(float r_close[3],
3185 const float p[3],
3186 const float ray_orig[3],
3187 const float ray_dir[3])
3188{
3189 float h[3], lambda;
3190
3191 if (UNLIKELY(is_zero_v3(ray_dir))) {
3192 lambda = 0.0f;
3193 copy_v3_v3(r_close, ray_orig);
3194 return lambda;
3195 }
3196
3197 sub_v3_v3v3(h, p, ray_orig);
3198 lambda = dot_v3v3(ray_dir, h) / dot_v3v3(ray_dir, ray_dir);
3199 madd_v3_v3v3fl(r_close, ray_orig, ray_dir, lambda);
3200 return lambda;
3201}
3202
3203float closest_to_line_v3(float r_close[3], const float p[3], const float l1[3], const float l2[3])
3204{
3205 float u[3];
3206 sub_v3_v3v3(u, l2, l1);
3207 return closest_to_ray_v3(r_close, p, l1, u);
3208}
3209
3210float closest_to_line_v2(float r_close[2], const float p[2], const float l1[2], const float l2[2])
3211{
3212 float h[2], u[2], lambda, denom;
3213 sub_v2_v2v2(u, l2, l1);
3214 sub_v2_v2v2(h, p, l1);
3215 denom = dot_v2v2(u, u);
3216 if (denom == 0.0f) {
3217 r_close[0] = l1[0];
3218 r_close[1] = l1[1];
3219 return 0.0f;
3220 }
3221 lambda = dot_v2v2(u, h) / denom;
3222 r_close[0] = l1[0] + u[0] * lambda;
3223 r_close[1] = l1[1] + u[1] * lambda;
3224 return lambda;
3225}
3226
3227double closest_to_line_v2_db(double r_close[2],
3228 const double p[2],
3229 const double l1[2],
3230 const double l2[2])
3231{
3232 double h[2], u[2], lambda, denom;
3233 sub_v2_v2v2_db(u, l2, l1);
3234 sub_v2_v2v2_db(h, p, l1);
3235 denom = dot_v2v2_db(u, u);
3236 if (denom == 0.0) {
3237 r_close[0] = l1[0];
3238 r_close[1] = l1[1];
3239 return 0.0;
3240 }
3241 lambda = dot_v2v2_db(u, h) / denom;
3242 r_close[0] = l1[0] + u[0] * lambda;
3243 r_close[1] = l1[1] + u[1] * lambda;
3244 return lambda;
3245}
3246
3247float ray_point_factor_v3_ex(const float p[3],
3248 const float ray_origin[3],
3249 const float ray_direction[3],
3250 const float epsilon,
3251 const float fallback)
3252{
3253 float p_relative[3];
3254 sub_v3_v3v3(p_relative, p, ray_origin);
3255 const float dot = len_squared_v3(ray_direction);
3256 return (dot > epsilon) ? (dot_v3v3(ray_direction, p_relative) / dot) : fallback;
3257}
3258
3259float ray_point_factor_v3(const float p[3],
3260 const float ray_origin[3],
3261 const float ray_direction[3])
3262{
3263 return ray_point_factor_v3_ex(p, ray_origin, ray_direction, 0.0f, 0.0f);
3264}
3265
3266float line_point_factor_v3_ex(const float p[3],
3267 const float l1[3],
3268 const float l2[3],
3269 const float epsilon,
3270 const float fallback)
3271{
3272 float h[3], u[3];
3273 float dot;
3274 sub_v3_v3v3(u, l2, l1);
3275 sub_v3_v3v3(h, p, l1);
3276
3277 /* better check for zero */
3278 dot = len_squared_v3(u);
3279 return (dot > epsilon) ? (dot_v3v3(u, h) / dot) : fallback;
3280}
3281float line_point_factor_v3(const float p[3], const float l1[3], const float l2[3])
3282{
3283 return line_point_factor_v3_ex(p, l1, l2, 0.0f, 0.0f);
3284}
3285
3286float line_point_factor_v2_ex(const float p[2],
3287 const float l1[2],
3288 const float l2[2],
3289 const float epsilon,
3290 const float fallback)
3291{
3292 float h[2], u[2];
3293 float dot;
3294 sub_v2_v2v2(u, l2, l1);
3295 sub_v2_v2v2(h, p, l1);
3296 /* better check for zero */
3297 dot = len_squared_v2(u);
3298 return (dot > epsilon) ? (dot_v2v2(u, h) / dot) : fallback;
3299}
3300
3301float line_point_factor_v2(const float p[2], const float l1[2], const float l2[2])
3302{
3303 return line_point_factor_v2_ex(p, l1, l2, 0.0f, 0.0f);
3304}
3305
3306float line_plane_factor_v3(const float plane_co[3],
3307 const float plane_no[3],
3308 const float l1[3],
3309 const float l2[3])
3310{
3311 float u[3], h[3];
3312 float dot;
3313 sub_v3_v3v3(u, l2, l1);
3314 sub_v3_v3v3(h, l1, plane_co);
3315 dot = dot_v3v3(plane_no, u);
3316 return (dot != 0.0f) ? -dot_v3v3(plane_no, h) / dot : 0.0f;
3317}
3318
3319void limit_dist_v3(float v1[3], float v2[3], const float dist)
3320{
3321 const float dist_old = len_v3v3(v1, v2);
3322
3323 if (dist_old > dist) {
3324 float v1_old[3];
3325 float v2_old[3];
3326 float fac = (dist / dist_old) * 0.5f;
3327
3328 copy_v3_v3(v1_old, v1);
3329 copy_v3_v3(v2_old, v2);
3330
3331 interp_v3_v3v3(v1, v1_old, v2_old, 0.5f - fac);
3332 interp_v3_v3v3(v2, v1_old, v2_old, 0.5f + fac);
3333 }
3334}
3335
3337 const int x1, const int y1, const int x2, const int y2, const int a, const int b)
3338{
3339 float v1[2], v2[2], v3[2], p[2];
3340
3341 v1[0] = float(x1);
3342 v1[1] = float(y1);
3343
3344 v2[0] = float(x1);
3345 v2[1] = float(y2);
3346
3347 v3[0] = float(x2);
3348 v3[1] = float(y1);
3349
3350 p[0] = float(a);
3351 p[1] = float(b);
3352
3353 return isect_point_tri_v2(p, v1, v2, v3);
3354}
3355
3356static bool point_in_slice(const float p[3],
3357 const float v1[3],
3358 const float l1[3],
3359 const float l2[3])
3360{
3361 /* What is a slice?
3362 * Some math:
3363 * a line including (l1, l2) and a point not on the line
3364 * define a subset of R3 delimited by planes parallel to the line and orthogonal
3365 * to the (point --> line) distance vector, one plane on the line one on the point,
3366 * the room inside usually is rather small compared to R3 though still infinite
3367 * useful for restricting (speeding up) searches
3368 * e.g. all points of triangular prism are within the intersection of 3 "slices"
3369 * Another trivial case is a cube, but see a "spat" which is a deformed cube
3370 * with paired parallel planes needs only 3 slices too. */
3371 float h, rp[3], cp[3], q[3];
3372
3373 closest_to_line_v3(cp, v1, l1, l2);
3374 sub_v3_v3v3(q, cp, v1);
3375
3376 sub_v3_v3v3(rp, p, v1);
3377 h = dot_v3v3(q, rp) / dot_v3v3(q, q);
3378 /* NOTE: when 'h' is nan/-nan, this check returns false
3379 * without explicit check - covering the degenerate case */
3380 return (h >= 0.0f && h <= 1.0f);
3381}
3382
3383/* Adult sister defining the slice planes by the origin and the normal.
3384 * NOTE: |normal| may not be 1 but defining the thickness of the slice. */
3385static bool point_in_slice_as(const float p[3], const float origin[3], const float normal[3])
3386{
3387 float h, rp[3];
3388 sub_v3_v3v3(rp, p, origin);
3389 h = dot_v3v3(normal, rp) / dot_v3v3(normal, normal);
3390 if (h < 0.0f || h > 1.0f) {
3391 return false;
3392 }
3393 return true;
3394}
3395
3396bool point_in_slice_seg(float p[3], float l1[3], float l2[3])
3397{
3398 float normal[3];
3399
3400 sub_v3_v3v3(normal, l2, l1);
3401
3402 return point_in_slice_as(p, l1, normal);
3403}
3404
3405bool isect_point_tri_prism_v3(const float p[3],
3406 const float v1[3],
3407 const float v2[3],
3408 const float v3[3])
3409{
3410 if (!point_in_slice(p, v1, v2, v3)) {
3411 return false;
3412 }
3413 if (!point_in_slice(p, v2, v3, v1)) {
3414 return false;
3415 }
3416 if (!point_in_slice(p, v3, v1, v2)) {
3417 return false;
3418 }
3419 return true;
3420}
3421
3423 const float p[3], const float v1[3], const float v2[3], const float v3[3], float r_isect_co[3])
3424{
3425 if (isect_point_tri_prism_v3(p, v1, v2, v3)) {
3426 float plane[4];
3427 float no[3];
3428
3429 /* Could use normal_tri_v3, but doesn't have to be unit-length */
3430 cross_tri_v3(no, v1, v2, v3);
3431 BLI_assert(len_squared_v3(no) != 0.0f);
3432
3433 plane_from_point_normal_v3(plane, v1, no);
3434 closest_to_plane_v3(r_isect_co, plane, p);
3435
3436 return true;
3437 }
3438
3439 return false;
3440}
3441
3443 const float p1[3], const float p2[3], const float plane[4], float r_p1[3], float r_p2[3])
3444{
3445 float dp[3], div;
3446
3447 sub_v3_v3v3(dp, p2, p1);
3448 div = dot_v3v3(dp, plane);
3449
3450 if (div == 0.0f) {
3451 /* parallel */
3452 return true;
3453 }
3454
3455 float t = -plane_point_side_v3(plane, p1);
3456
3457 if (div > 0.0f) {
3458 /* behind plane, completely clipped */
3459 if (t >= div) {
3460 return false;
3461 }
3462 if (t > 0.0f) {
3463 const float p1_copy[3] = {UNPACK3(p1)};
3464 copy_v3_v3(r_p2, p2);
3465 madd_v3_v3v3fl(r_p1, p1_copy, dp, t / div);
3466 return true;
3467 }
3468 }
3469 else {
3470 /* behind plane, completely clipped */
3471 if (t >= 0.0f) {
3472 return false;
3473 }
3474 if (t > div) {
3475 const float p1_copy[3] = {UNPACK3(p1)};
3476 copy_v3_v3(r_p1, p1);
3477 madd_v3_v3v3fl(r_p2, p1_copy, dp, t / div);
3478 return true;
3479 }
3480 }
3481
3482 /* In case input/output values match (above also). */
3483 const float p1_copy[3] = {UNPACK3(p1)};
3484 copy_v3_v3(r_p2, p2);
3485 copy_v3_v3(r_p1, p1_copy);
3486 return true;
3487}
3488
3489bool clip_segment_v3_plane_n(const float p1[3],
3490 const float p2[3],
3491 const float plane_array[][4],
3492 const int plane_num,
3493 float r_p1[3],
3494 float r_p2[3])
3495{
3496 /* intersect from both directions */
3497 float p1_fac = 0.0f, p2_fac = 1.0f;
3498
3499 float dp[3];
3500 sub_v3_v3v3(dp, p2, p1);
3501
3502 for (int i = 0; i < plane_num; i++) {
3503 const float *plane = plane_array[i];
3504 const float div = dot_v3v3(dp, plane);
3505
3506 if (div != 0.0f) {
3507 float t = -plane_point_side_v3(plane, p1);
3508 if (div > 0.0f) {
3509 /* clip p1 lower bounds */
3510 if (t >= div) {
3511 return false;
3512 }
3513 if (t > 0.0f) {
3514 t /= div;
3515 if (t > p1_fac) {
3516 p1_fac = t;
3517 if (p1_fac > p2_fac) {
3518 return false;
3519 }
3520 }
3521 }
3522 }
3523 else if (div < 0.0f) {
3524 /* clip p2 upper bounds */
3525 if (t >= 0.0f) {
3526 return false;
3527 }
3528 if (t > div) {
3529 t /= div;
3530 if (t < p2_fac) {
3531 p2_fac = t;
3532 if (p1_fac > p2_fac) {
3533 return false;
3534 }
3535 }
3536 }
3537 }
3538 }
3539 }
3540
3541 /* In case input/output values match. */
3542 const float p1_copy[3] = {UNPACK3(p1)};
3543
3544 madd_v3_v3v3fl(r_p1, p1_copy, dp, p1_fac);
3545 madd_v3_v3v3fl(r_p2, p1_copy, dp, p2_fac);
3546
3547 return true;
3548}
3549
3550/****************************** Axis Utils ********************************/
3551
3552void axis_dominant_v3_to_m3(float r_mat[3][3], const float normal[3])
3553{
3554 BLI_ASSERT_UNIT_V3(normal);
3555
3556 copy_v3_v3(r_mat[2], normal);
3557 ortho_basis_v3v3_v3(r_mat[0], r_mat[1], r_mat[2]);
3558
3559 BLI_ASSERT_UNIT_V3(r_mat[0]);
3560 BLI_ASSERT_UNIT_V3(r_mat[1]);
3561
3562 transpose_m3(r_mat);
3563
3564 BLI_assert(!is_negative_m3(r_mat));
3565 BLI_assert((fabsf(dot_m3_v3_row_z(r_mat, normal) - 1.0f) < BLI_ASSERT_UNIT_EPSILON) ||
3566 is_zero_v3(normal));
3567}
3568
3569void axis_dominant_v3_to_m3_negate(float r_mat[3][3], const float normal[3])
3570{
3571 BLI_ASSERT_UNIT_V3(normal);
3572
3573 negate_v3_v3(r_mat[2], normal);
3574 ortho_basis_v3v3_v3(r_mat[0], r_mat[1], r_mat[2]);
3575
3576 BLI_ASSERT_UNIT_V3(r_mat[0]);
3577 BLI_ASSERT_UNIT_V3(r_mat[1]);
3578
3579 transpose_m3(r_mat);
3580
3581 BLI_assert(!is_negative_m3(r_mat));
3582 BLI_assert((dot_m3_v3_row_z(r_mat, normal) < BLI_ASSERT_UNIT_EPSILON) || is_zero_v3(normal));
3583}
3584
3585/****************************** Interpolation ********************************/
3586
3587static float tri_signed_area(
3588 const float v1[3], const float v2[3], const float v3[3], const int i, const int j)
3589{
3590 return 0.5f * ((v1[i] - v2[i]) * (v2[j] - v3[j]) + (v1[j] - v2[j]) * (v3[i] - v2[i]));
3591}
3592
3596static bool barycentric_weights(const float v1[3],
3597 const float v2[3],
3598 const float v3[3],
3599 const float co[3],
3600 const float n[3],
3601 float w[3])
3602{
3603 float wtot;
3604 int i, j;
3605
3606 axis_dominant_v3(&i, &j, n);
3607
3608 w[0] = tri_signed_area(v2, v3, co, i, j);
3609 w[1] = tri_signed_area(v3, v1, co, i, j);
3610 w[2] = tri_signed_area(v1, v2, co, i, j);
3611
3612 wtot = w[0] + w[1] + w[2];
3613
3614#ifndef NDEBUG /* Avoid floating point exception when debugging. */
3615 if (wtot != 0.0f)
3616#endif
3617 {
3618 mul_v3_fl(w, 1.0f / wtot);
3619 if (is_finite_v3(w)) {
3620 return true;
3621 }
3622 }
3623 /* Zero area triangle. */
3624 copy_v3_fl(w, 1.0f / 3.0f);
3625 return false;
3626}
3627
3629 float w[3], const float v1[3], const float v2[3], const float v3[3], const float co[3])
3630{
3631 float n[3];
3632
3633 normal_tri_v3(n, v1, v2, v3);
3634 barycentric_weights(v1, v2, v3, co, n, w);
3635}
3636
3638 const float v1[3],
3639 const float v2[3],
3640 const float v3[3],
3641 const float v4[3],
3642 const float co[3])
3643{
3644 float w2[3];
3645
3646 zero_v4(w);
3647
3648 /* first check for exact match */
3649 if (equals_v3v3(co, v1)) {
3650 w[0] = 1.0f;
3651 }
3652 else if (equals_v3v3(co, v2)) {
3653 w[1] = 1.0f;
3654 }
3655 else if (equals_v3v3(co, v3)) {
3656 w[2] = 1.0f;
3657 }
3658 else if (equals_v3v3(co, v4)) {
3659 w[3] = 1.0f;
3660 }
3661 else {
3662 /* otherwise compute barycentric interpolation weights */
3663 float n1[3], n2[3], n[3];
3664 bool ok;
3665
3666 sub_v3_v3v3(n1, v1, v3);
3667 sub_v3_v3v3(n2, v2, v4);
3668 cross_v3_v3v3(n, n1, n2);
3669
3670 ok = barycentric_weights(v1, v2, v4, co, n, w);
3671 std::swap(w[2], w[3]);
3672
3673 if (!ok || (w[0] < 0.0f)) {
3674 /* if w[1] is negative, co is on the other side of the v1-v3 edge,
3675 * so we interpolate using the other triangle */
3676 ok = barycentric_weights(v2, v3, v4, co, n, w2);
3677
3678 if (ok) {
3679 w[0] = 0.0f;
3680 w[1] = w2[0];
3681 w[2] = w2[1];
3682 w[3] = w2[2];
3683 }
3684 }
3685 }
3686}
3687
3689{
3690 if (IN_RANGE(w[0], 0.0f, 1.0f) && IN_RANGE(w[1], 0.0f, 1.0f) && IN_RANGE(w[2], 0.0f, 1.0f)) {
3691 return 1;
3692 }
3693 if (IN_RANGE_INCL(w[0], 0.0f, 1.0f) && IN_RANGE_INCL(w[1], 0.0f, 1.0f) &&
3694 IN_RANGE_INCL(w[2], 0.0f, 1.0f))
3695 {
3696 return 2;
3697 }
3698
3699 return 0;
3700}
3701
3703 const float v1[2], const float v2[2], const float v3[2], const float co[2], float w[3])
3704{
3705 const float x = co[0], y = co[1];
3706 const float x1 = v1[0], y1 = v1[1];
3707 const float x2 = v2[0], y2 = v2[1];
3708 const float x3 = v3[0], y3 = v3[1];
3709 const float det = (y2 - y3) * (x1 - x3) + (x3 - x2) * (y1 - y3);
3710
3711#ifndef NDEBUG /* Avoid floating point exception when debugging. */
3712 if (det != 0.0f)
3713#endif
3714 {
3715 w[0] = ((y2 - y3) * (x - x3) + (x3 - x2) * (y - y3)) / det;
3716 w[1] = ((y3 - y1) * (x - x3) + (x1 - x3) * (y - y3)) / det;
3717 w[2] = 1.0f - w[0] - w[1];
3718 if (is_finite_v3(w)) {
3719 return true;
3720 }
3721 }
3722
3723 return false;
3724}
3725
3727 const float v1[2], const float v2[2], const float v3[2], const float co[2], float w[3])
3728{
3729 float wtot;
3730
3731 w[0] = cross_tri_v2(v2, v3, co);
3732 w[1] = cross_tri_v2(v3, v1, co);
3733 w[2] = cross_tri_v2(v1, v2, co);
3734 wtot = w[0] + w[1] + w[2];
3735
3736#ifndef NDEBUG /* Avoid floating point exception when debugging. */
3737 if (wtot != 0.0f)
3738#endif
3739 {
3740 mul_v3_fl(w, 1.0f / wtot);
3741 if (is_finite_v3(w)) {
3742 return;
3743 }
3744 }
3745 /* Dummy values for zero area face. */
3746 copy_v3_fl(w, 1.0f / 3.0f);
3747}
3748
3750 const float v1[2], const float v2[2], const float v3[2], const float co[2], float w[3])
3751{
3752 float wtot;
3753
3754 w[0] = max_ff(cross_tri_v2(v2, v3, co), 0.0f);
3755 w[1] = max_ff(cross_tri_v2(v3, v1, co), 0.0f);
3756 w[2] = max_ff(cross_tri_v2(v1, v2, co), 0.0f);
3757 wtot = w[0] + w[1] + w[2];
3758
3759#ifndef NDEBUG /* Avoid floating point exception when debugging. */
3760 if (wtot != 0.0f)
3761#endif
3762 {
3763 mul_v3_fl(w, 1.0f / wtot);
3764 if (is_finite_v3(w)) {
3765 return;
3766 }
3767 }
3768 /* Dummy values for zero area face. */
3769 copy_v3_fl(w, 1.0f / 3.0f);
3770}
3771
3773 const float v1[4], const float v2[4], const float v3[4], const float co[2], float w[3])
3774{
3775 float wtot;
3776
3777 w[0] = cross_tri_v2(v2, v3, co) / v1[3];
3778 w[1] = cross_tri_v2(v3, v1, co) / v2[3];
3779 w[2] = cross_tri_v2(v1, v2, co) / v3[3];
3780 wtot = w[0] + w[1] + w[2];
3781
3782#ifndef NDEBUG /* Avoid floating point exception when debugging. */
3783 if (wtot != 0.0f)
3784#endif
3785 {
3786 mul_v3_fl(w, 1.0f / wtot);
3787 if (is_finite_v3(w)) {
3788 return;
3789 }
3790 }
3791 /* Dummy values for zero area face. */
3792 copy_v3_fl(w, 1.0f / 3.0f);
3793}
3794
3795void barycentric_weights_v2_quad(const float v1[2],
3796 const float v2[2],
3797 const float v3[2],
3798 const float v4[2],
3799 const float co[2],
3800 float w[4])
3801{
3802 /* NOTE(@ideasman42): fabsf() here is not needed for convex quads
3803 * (and not used in #interp_weights_poly_v2).
3804 * But in the case of concave/bow-tie quads for the mask rasterizer it
3805 * gives unreliable results without adding `absf()`. If this becomes an issue for more general
3806 * usage we could have this optional or use a different function. */
3807#define MEAN_VALUE_HALF_TAN_V2(_area, i1, i2) \
3808 ((_area = cross_v2v2(dirs[i1], dirs[i2])) != 0.0f ? \
3809 fabsf(((lens[i1] * lens[i2]) - dot_v2v2(dirs[i1], dirs[i2])) / _area) : \
3810 0.0f)
3811
3812 const float dirs[4][2] = {
3813 {v1[0] - co[0], v1[1] - co[1]},
3814 {v2[0] - co[0], v2[1] - co[1]},
3815 {v3[0] - co[0], v3[1] - co[1]},
3816 {v4[0] - co[0], v4[1] - co[1]},
3817 };
3818
3819 const float lens[4] = {
3820 len_v2(dirs[0]),
3821 len_v2(dirs[1]),
3822 len_v2(dirs[2]),
3823 len_v2(dirs[3]),
3824 };
3825
3826 /* avoid divide by zero */
3827 if (UNLIKELY(lens[0] < FLT_EPSILON)) {
3828 w[0] = 1.0f;
3829 w[1] = w[2] = w[3] = 0.0f;
3830 }
3831 else if (UNLIKELY(lens[1] < FLT_EPSILON)) {
3832 w[1] = 1.0f;
3833 w[0] = w[2] = w[3] = 0.0f;
3834 }
3835 else if (UNLIKELY(lens[2] < FLT_EPSILON)) {
3836 w[2] = 1.0f;
3837 w[0] = w[1] = w[3] = 0.0f;
3838 }
3839 else if (UNLIKELY(lens[3] < FLT_EPSILON)) {
3840 w[3] = 1.0f;
3841 w[0] = w[1] = w[2] = 0.0f;
3842 }
3843 else {
3844 float wtot, area;
3845
3846 /* variable 'area' is just for storage,
3847 * the order its initialized doesn't matter */
3848#ifdef __clang__
3849# pragma clang diagnostic push
3850# pragma clang diagnostic ignored "-Wunsequenced"
3851#endif
3852
3853 /* inline mean_value_half_tan four times here */
3854 const float t[4] = {
3855 MEAN_VALUE_HALF_TAN_V2(area, 0, 1),
3856 MEAN_VALUE_HALF_TAN_V2(area, 1, 2),
3857 MEAN_VALUE_HALF_TAN_V2(area, 2, 3),
3858 MEAN_VALUE_HALF_TAN_V2(area, 3, 0),
3859 };
3860
3861#ifdef __clang__
3862# pragma clang diagnostic pop
3863#endif
3864
3865#undef MEAN_VALUE_HALF_TAN_V2
3866
3867 w[0] = (t[3] + t[0]) / lens[0];
3868 w[1] = (t[0] + t[1]) / lens[1];
3869 w[2] = (t[1] + t[2]) / lens[2];
3870 w[3] = (t[2] + t[3]) / lens[3];
3871
3872 wtot = w[0] + w[1] + w[2] + w[3];
3873
3874#ifndef NDEBUG /* Avoid floating point exception when debugging. */
3875 if (wtot != 0.0f)
3876#endif
3877 {
3878 mul_v4_fl(w, 1.0f / wtot);
3879 if (is_finite_v4(w)) {
3880 return;
3881 }
3882 }
3883 /* Dummy values for zero area face. */
3884 copy_v4_fl(w, 1.0f / 4.0f);
3885 }
3886}
3887
3888void transform_point_by_tri_v3(float pt_tar[3],
3889 float const pt_src[3],
3890 const float tri_tar_p1[3],
3891 const float tri_tar_p2[3],
3892 const float tri_tar_p3[3],
3893 const float tri_src_p1[3],
3894 const float tri_src_p2[3],
3895 const float tri_src_p3[3])
3896{
3897 /* this works by moving the source triangle so its normal is pointing on the Z
3898 * axis where its barycentric weights can be calculated in 2D and its Z offset can
3899 * be re-applied. The weights are applied directly to the targets 3D points and the
3900 * z-depth is used to scale the targets normal as an offset.
3901 * This saves transforming the target into its Z-Up orientation and back
3902 * (which could also work) */
3903 float no_tar[3], no_src[3];
3904 float mat_src[3][3];
3905 float pt_src_xy[3];
3906 float tri_xy_src[3][3];
3907 float w_src[3];
3908 float area_tar, area_src;
3909 float z_ofs_src;
3910
3911 normal_tri_v3(no_tar, tri_tar_p1, tri_tar_p2, tri_tar_p3);
3912 normal_tri_v3(no_src, tri_src_p1, tri_src_p2, tri_src_p3);
3913
3914 axis_dominant_v3_to_m3(mat_src, no_src);
3915
3916 /* make the source tri xy space */
3917 mul_v3_m3v3(pt_src_xy, mat_src, pt_src);
3918 mul_v3_m3v3(tri_xy_src[0], mat_src, tri_src_p1);
3919 mul_v3_m3v3(tri_xy_src[1], mat_src, tri_src_p2);
3920 mul_v3_m3v3(tri_xy_src[2], mat_src, tri_src_p3);
3921
3922 barycentric_weights_v2(tri_xy_src[0], tri_xy_src[1], tri_xy_src[2], pt_src_xy, w_src);
3923 interp_v3_v3v3v3(pt_tar, tri_tar_p1, tri_tar_p2, tri_tar_p3, w_src);
3924
3925 area_tar = sqrtf(area_tri_v3(tri_tar_p1, tri_tar_p2, tri_tar_p3));
3926 area_src = sqrtf(area_tri_v2(tri_xy_src[0], tri_xy_src[1], tri_xy_src[2]));
3927
3928 z_ofs_src = pt_src_xy[2] - tri_xy_src[0][2];
3929 madd_v3_v3v3fl(pt_tar, pt_tar, no_tar, (z_ofs_src / area_src) * area_tar);
3930}
3931
3932void transform_point_by_seg_v3(float p_dst[3],
3933 const float p_src[3],
3934 const float l_dst_p1[3],
3935 const float l_dst_p2[3],
3936 const float l_src_p1[3],
3937 const float l_src_p2[3])
3938{
3939 float t = line_point_factor_v3(p_src, l_src_p1, l_src_p2);
3940 interp_v3_v3v3(p_dst, l_dst_p1, l_dst_p2, t);
3941}
3942
3943int interp_sparse_array(float *array, const int list_size, const float skipval)
3944{
3945 int found_invalid = 0;
3946 int found_valid = 0;
3947 int i;
3948
3949 for (i = 0; i < list_size; i++) {
3950 if (array[i] == skipval) {
3951 found_invalid = 1;
3952 }
3953 else {
3954 found_valid = 1;
3955 }
3956 }
3957
3958 if (found_valid == 0) {
3959 return -1;
3960 }
3961 if (found_invalid == 0) {
3962 return 0;
3963 }
3964
3965 /* found invalid depths, interpolate */
3966 float valid_last = skipval;
3967 int valid_ofs = 0;
3968
3969 blender::Array<float> array_up(list_size);
3970 blender::Array<float> array_down(list_size);
3971
3972 blender::Array<int> ofs_tot_up(list_size);
3973 blender::Array<int> ofs_tot_down(list_size);
3974
3975 for (i = 0; i < list_size; i++) {
3976 if (array[i] == skipval) {
3977 array_up[i] = valid_last;
3978 ofs_tot_up[i] = ++valid_ofs;
3979 }
3980 else {
3981 valid_last = array[i];
3982 valid_ofs = 0;
3983 }
3984 }
3985
3986 valid_last = skipval;
3987 valid_ofs = 0;
3988
3989 for (i = list_size - 1; i >= 0; i--) {
3990 if (array[i] == skipval) {
3991 array_down[i] = valid_last;
3992 ofs_tot_down[i] = ++valid_ofs;
3993 }
3994 else {
3995 valid_last = array[i];
3996 valid_ofs = 0;
3997 }
3998 }
3999
4000 /* now blend */
4001 for (i = 0; i < list_size; i++) {
4002 if (array[i] == skipval) {
4003 if (array_up[i] != skipval && array_down[i] != skipval) {
4004 array[i] = ((array_up[i] * float(ofs_tot_down[i])) +
4005 (array_down[i] * float(ofs_tot_up[i]))) /
4006 float(ofs_tot_down[i] + ofs_tot_up[i]);
4007 }
4008 else if (array_up[i] != skipval) {
4009 array[i] = array_up[i];
4010 }
4011 else if (array_down[i] != skipval) {
4012 array[i] = array_down[i];
4013 }
4014 }
4015 }
4016
4017 return 1;
4018}
4019
4020/* -------------------------------------------------------------------- */
4023
4024#define IS_POINT_IX (1 << 0)
4025#define IS_SEGMENT_IX (1 << 1)
4026
4027#define DIR_V3_SET(d_len, va, vb) \
4028 { \
4029 sub_v3_v3v3((d_len)->dir, va, vb); \
4030 (d_len)->len = len_v3((d_len)->dir); \
4031 } \
4032 (void)0
4033
4034#define DIR_V2_SET(d_len, va, vb) \
4035 { \
4036 sub_v2db_v2fl_v2fl((d_len)->dir, va, vb); \
4037 (d_len)->len = len_v2_db((d_len)->dir); \
4038 } \
4039 (void)0
4040
4042 float dir[3], len;
4043};
4044
4046 double dir[2], len;
4047};
4048
4049/* Mean value weights - smooth interpolation weights for polygons with
4050 * more than 3 vertices */
4051static float mean_value_half_tan_v3(const Float3_Len *d_curr, const Float3_Len *d_next)
4052{
4053 float cross[3];
4054 cross_v3_v3v3(cross, d_curr->dir, d_next->dir);
4055 const float area = len_v3(cross);
4056 /* Compare against zero since 'FLT_EPSILON' can be too large, see: #73348. */
4057 if (LIKELY(area != 0.0f)) {
4058 const float dot = dot_v3v3(d_curr->dir, d_next->dir);
4059 const float len = d_curr->len * d_next->len;
4060 const float result = (len - dot) / area;
4061 if (isfinite(result)) {
4062 return result;
4063 }
4064 }
4065 return 0.0f;
4066}
4067
4077static double mean_value_half_tan_v2_db(const Double2_Len *d_curr, const Double2_Len *d_next)
4078{
4079 /* Different from the 3d version but still correct. */
4080 const double area = cross_v2v2_db(d_curr->dir, d_next->dir);
4081 /* Compare against zero since 'FLT_EPSILON' can be too large, see: #73348. */
4082 if (LIKELY(area != 0.0)) {
4083 const double dot = dot_v2v2_db(d_curr->dir, d_next->dir);
4084 const double len = d_curr->len * d_next->len;
4085 const double result = (len - dot) / area;
4086 if (isfinite(result)) {
4087 return result;
4088 }
4089 }
4090 return 0.0;
4091}
4092
4093void interp_weights_poly_v3(float *w, float v[][3], const int n, const float co[3])
4094{
4095 /* Before starting to calculate the weight, we need to figure out the floating point precision we
4096 * can expect from the supplied data. */
4097 float max_value = 0;
4098
4099 for (int i = 0; i < n; i++) {
4100 max_value = max_ff(max_value, fabsf(v[i][0] - co[0]));
4101 max_value = max_ff(max_value, fabsf(v[i][1] - co[1]));
4102 max_value = max_ff(max_value, fabsf(v[i][2] - co[2]));
4103 }
4104
4105 /* These to values we derived by empirically testing different values that works for the test
4106 * files in D7772. */
4107 const float eps = 16.0f * FLT_EPSILON * max_value;
4108 const float eps_sq = eps * eps;
4109 const float *v_curr, *v_next;
4110 float ht_prev, ht; /* half tangents */
4111 float totweight = 0.0f;
4112 int i_curr, i_next;
4113 char ix_flag = 0;
4114 Float3_Len d_curr, d_next;
4115
4116 /* loop over 'i_next' */
4117 i_curr = n - 1;
4118 i_next = 0;
4119
4120 v_curr = v[i_curr];
4121 v_next = v[i_next];
4122
4123 DIR_V3_SET(&d_curr, v_curr - 3 /* v[n - 2] */, co);
4124 DIR_V3_SET(&d_next, v_curr /* v[n - 1] */, co);
4125 ht_prev = mean_value_half_tan_v3(&d_curr, &d_next);
4126
4127 while (i_next < n) {
4128 /* Mark Mayer et al algorithm that is used here does not operate well if vertex is close
4129 * to borders of face.
4130 * In that case, do simple linear interpolation between the two edge vertices */
4131
4132 /* 'd_next.len' is in fact 'd_curr.len', just avoid copy to begin with */
4133 if (UNLIKELY(d_next.len < eps)) {
4134 ix_flag = IS_POINT_IX;
4135 break;
4136 }
4137 if (UNLIKELY(dist_squared_to_line_segment_v3(co, v_curr, v_next) < eps_sq)) {
4138 ix_flag = IS_SEGMENT_IX;
4139 break;
4140 }
4141
4142 d_curr = d_next;
4143 DIR_V3_SET(&d_next, v_next, co);
4144 ht = mean_value_half_tan_v3(&d_curr, &d_next);
4145 w[i_curr] = (ht_prev + ht) / d_curr.len;
4146 totweight += w[i_curr];
4147
4148 /* step */
4149 i_curr = i_next++;
4150 v_curr = v_next;
4151 v_next = v[i_next];
4152
4153 ht_prev = ht;
4154 }
4155
4156 if (ix_flag) {
4157 memset(w, 0, sizeof(*w) * size_t(n));
4158
4159 if (ix_flag & IS_POINT_IX) {
4160 w[i_curr] = 1.0f;
4161 }
4162 else {
4163 float fac = line_point_factor_v3(co, v_curr, v_next);
4164 CLAMP(fac, 0.0f, 1.0f);
4165 w[i_curr] = 1.0f - fac;
4166 w[i_next] = fac;
4167 }
4168 }
4169 else {
4170 if (totweight != 0.0f) {
4171 for (i_curr = 0; i_curr < n; i_curr++) {
4172 w[i_curr] /= totweight;
4173 }
4174 }
4175 }
4176}
4177
4178void interp_weights_poly_v2(float *w, float v[][2], const int n, const float co[2])
4179{
4180 /* Before starting to calculate the weight, we need to figure out the floating point precision we
4181 * can expect from the supplied data. */
4182 float max_value = 0;
4183
4184 for (int i = 0; i < n; i++) {
4185 max_value = max_ff(max_value, fabsf(v[i][0] - co[0]));
4186 max_value = max_ff(max_value, fabsf(v[i][1] - co[1]));
4187 }
4188
4189 /* These to values we derived by empirically testing different values that works for the test
4190 * files in D7772. */
4191 const float eps = 16.0f * FLT_EPSILON * max_value;
4192 const float eps_sq = eps * eps;
4193
4194 const float *v_curr, *v_next;
4195 double ht_prev, ht; /* half tangents */
4196 float totweight = 0.0f;
4197 int i_curr, i_next;
4198 char ix_flag = 0;
4199 Double2_Len d_curr, d_next;
4200
4201 /* loop over 'i_next' */
4202 i_curr = n - 1;
4203 i_next = 0;
4204
4205 v_curr = v[i_curr];
4206 v_next = v[i_next];
4207
4208 DIR_V2_SET(&d_curr, v_curr - 2 /* v[n - 2] */, co);
4209 DIR_V2_SET(&d_next, v_curr /* v[n - 1] */, co);
4210 ht_prev = mean_value_half_tan_v2_db(&d_curr, &d_next);
4211
4212 while (i_next < n) {
4213 /* Mark Mayer et al algorithm that is used here does not operate well if vertex is close
4214 * to borders of face. In that case,
4215 * do simple linear interpolation between the two edge vertices */
4216
4217 /* 'd_next.len' is in fact 'd_curr.len', just avoid copy to begin with */
4218 if (UNLIKELY(d_next.len < eps)) {
4219 ix_flag = IS_POINT_IX;
4220 break;
4221 }
4222 if (UNLIKELY(dist_squared_to_line_segment_v2(co, v_curr, v_next) < eps_sq)) {
4223 ix_flag = IS_SEGMENT_IX;
4224 break;
4225 }
4226
4227 d_curr = d_next;
4228 DIR_V2_SET(&d_next, v_next, co);
4229 ht = mean_value_half_tan_v2_db(&d_curr, &d_next);
4230 w[i_curr] = (d_curr.len == 0.0) ? 0.0f : float((ht_prev + ht) / d_curr.len);
4231 totweight += w[i_curr];
4232
4233 /* step */
4234 i_curr = i_next++;
4235 v_curr = v_next;
4236 v_next = v[i_next];
4237
4238 ht_prev = ht;
4239 }
4240
4241 if (ix_flag) {
4242 memset(w, 0, sizeof(*w) * size_t(n));
4243
4244 if (ix_flag & IS_POINT_IX) {
4245 w[i_curr] = 1.0f;
4246 }
4247 else {
4248 float fac = line_point_factor_v2(co, v_curr, v_next);
4249 CLAMP(fac, 0.0f, 1.0f);
4250 w[i_curr] = 1.0f - fac;
4251 w[i_next] = fac;
4252 }
4253 }
4254 else {
4255 if (totweight != 0.0f) {
4256 for (i_curr = 0; i_curr < n; i_curr++) {
4257 w[i_curr] /= totweight;
4258 }
4259 }
4260 }
4261}
4262
4263#undef IS_POINT_IX
4264#undef IS_SEGMENT_IX
4265
4266#undef DIR_V3_SET
4267#undef DIR_V2_SET
4268
4270
4271void interp_cubic_v3(float x[3],
4272 float v[3],
4273 const float x1[3],
4274 const float v1[3],
4275 const float x2[3],
4276 const float v2[3],
4277 const float t)
4278{
4279 float a[3], b[3];
4280 const float t2 = t * t;
4281 const float t3 = t2 * t;
4282
4283 /* cubic interpolation */
4284 a[0] = v1[0] + v2[0] + 2 * (x1[0] - x2[0]);
4285 a[1] = v1[1] + v2[1] + 2 * (x1[1] - x2[1]);
4286 a[2] = v1[2] + v2[2] + 2 * (x1[2] - x2[2]);
4287
4288 b[0] = -2 * v1[0] - v2[0] - 3 * (x1[0] - x2[0]);
4289 b[1] = -2 * v1[1] - v2[1] - 3 * (x1[1] - x2[1]);
4290 b[2] = -2 * v1[2] - v2[2] - 3 * (x1[2] - x2[2]);
4291
4292 x[0] = a[0] * t3 + b[0] * t2 + v1[0] * t + x1[0];
4293 x[1] = a[1] * t3 + b[1] * t2 + v1[1] * t + x1[1];
4294 x[2] = a[2] * t3 + b[2] * t2 + v1[2] * t + x1[2];
4295
4296 v[0] = 3 * a[0] * t2 + 2 * b[0] * t + v1[0];
4297 v[1] = 3 * a[1] * t2 + 2 * b[1] * t + v1[1];
4298 v[2] = 3 * a[2] * t2 + 2 * b[2] * t + v1[2];
4299}
4300
4301/* unfortunately internal calculations have to be done at double precision
4302 * to achieve correct/stable results. */
4303
4304#define IS_ZERO(x) ((x > (-DBL_EPSILON) && x < DBL_EPSILON) ? 1 : 0)
4305
4307 float r_uv[2], const float st[2], const float st0[2], const float st1[2], const float st2[2])
4308{
4309 /* find UV such that
4310 * t = u * t0 + v * t1 + (1 - u - v) * t2
4311 * u * (t0 - t2) + v * (t1 - t2) = t - t2 */
4312 const double a = st0[0] - st2[0], b = st1[0] - st2[0];
4313 const double c = st0[1] - st2[1], d = st1[1] - st2[1];
4314 const double det = a * d - c * b;
4315
4316 /* det should never be zero since the determinant is the signed ST area of the triangle. */
4317 if (IS_ZERO(det) == 0) {
4318 const double x[2] = {st[0] - st2[0], st[1] - st2[1]};
4319
4320 r_uv[0] = float((d * x[0] - b * x[1]) / det);
4321 r_uv[1] = float(((-c) * x[0] + a * x[1]) / det);
4322 }
4323 else {
4324 zero_v2(r_uv);
4325 }
4326}
4327
4329 float r_uv[2], const float st[3], const float st0[3], const float st1[3], const float st2[3])
4330{
4331 float v0[3], v1[3], v2[3];
4332 double d00, d01, d11, d20, d21, det;
4333
4334 sub_v3_v3v3(v0, st1, st0);
4335 sub_v3_v3v3(v1, st2, st0);
4336 sub_v3_v3v3(v2, st, st0);
4337
4338 d00 = dot_v3v3(v0, v0);
4339 d01 = dot_v3v3(v0, v1);
4340 d11 = dot_v3v3(v1, v1);
4341 d20 = dot_v3v3(v2, v0);
4342 d21 = dot_v3v3(v2, v1);
4343
4344 det = d00 * d11 - d01 * d01;
4345
4346 /* det should never be zero since the determinant is the signed ST area of the triangle. */
4347 if (IS_ZERO(det) == 0) {
4348 float w;
4349
4350 w = float((d00 * d21 - d01 * d20) / det);
4351 r_uv[1] = float((d11 * d20 - d01 * d21) / det);
4352 r_uv[0] = 1.0f - r_uv[1] - w;
4353 }
4354 else {
4355 zero_v2(r_uv);
4356 }
4357}
4358
4359void resolve_quad_uv_v2(float r_uv[2],
4360 const float st[2],
4361 const float st0[2],
4362 const float st1[2],
4363 const float st2[2],
4364 const float st3[2])
4365{
4366 resolve_quad_uv_v2_deriv(r_uv, nullptr, st, st0, st1, st2, st3);
4367}
4368
4369void resolve_quad_uv_v2_deriv(float r_uv[2],
4370 float r_deriv[2][2],
4371 const float st[2],
4372 const float st0[2],
4373 const float st1[2],
4374 const float st2[2],
4375 const float st3[2])
4376{
4377 const double signed_area = (st0[0] * st1[1] - st0[1] * st1[0]) +
4378 (st1[0] * st2[1] - st1[1] * st2[0]) +
4379 (st2[0] * st3[1] - st2[1] * st3[0]) +
4380 (st3[0] * st0[1] - st3[1] * st0[0]);
4381
4382 /* X is 2D cross product (determinant)
4383 * A = (p0 - p) X (p0 - p3) */
4384 const double a = (st0[0] - st[0]) * (st0[1] - st3[1]) - (st0[1] - st[1]) * (st0[0] - st3[0]);
4385
4386 /* B = ( (p0 - p) X (p1 - p2) + (p1 - p) X (p0 - p3) ) / 2 */
4387 const double b =
4388 0.5 * double(((st0[0] - st[0]) * (st1[1] - st2[1]) - (st0[1] - st[1]) * (st1[0] - st2[0])) +
4389 ((st1[0] - st[0]) * (st0[1] - st3[1]) - (st1[1] - st[1]) * (st0[0] - st3[0])));
4390
4391 /* C = (p1-p) X (p1-p2) */
4392 const double fC = (st1[0] - st[0]) * (st1[1] - st2[1]) - (st1[1] - st[1]) * (st1[0] - st2[0]);
4393 double denom = a - 2 * b + fC;
4394
4395 /* clear outputs */
4396 zero_v2(r_uv);
4397
4398 if (IS_ZERO(denom) != 0) {
4399 const double fDen = a - fC;
4400 if (IS_ZERO(fDen) == 0) {
4401 r_uv[0] = float(a / fDen);
4402 }
4403 }
4404 else {
4405 const double desc_sq = b * b - a * fC;
4406 const double desc = sqrt(desc_sq < 0.0 ? 0.0 : desc_sq);
4407 const double s = signed_area > 0 ? (-1.0) : 1.0;
4408
4409 r_uv[0] = float(((a - b) + s * desc) / denom);
4410 }
4411
4412 /* find UV such that
4413 * fST = (1-u)(1-v) * ST0 + u * (1-v) * ST1 + u * v * ST2 + (1-u) * v * ST3 */
4414 {
4415 const double denom_s = (1 - r_uv[0]) * (st0[0] - st3[0]) + r_uv[0] * (st1[0] - st2[0]);
4416 const double denom_t = (1 - r_uv[0]) * (st0[1] - st3[1]) + r_uv[0] * (st1[1] - st2[1]);
4417 int i = 0;
4418 denom = denom_s;
4419
4420 if (fabs(denom_s) < fabs(denom_t)) {
4421 i = 1;
4422 denom = denom_t;
4423 }
4424
4425 if (IS_ZERO(denom) == 0) {
4426 r_uv[1] = float(double((1.0f - r_uv[0]) * (st0[i] - st[i]) + r_uv[0] * (st1[i] - st[i])) /
4427 denom);
4428 }
4429 }
4430
4431 if (r_deriv) {
4432 float tmp1[2], tmp2[2], s[2], t[2];
4433
4434 /* clear outputs */
4435 zero_v2(r_deriv[0]);
4436 zero_v2(r_deriv[1]);
4437
4438 sub_v2_v2v2(tmp1, st1, st0);
4439 sub_v2_v2v2(tmp2, st2, st3);
4440 interp_v2_v2v2(s, tmp1, tmp2, r_uv[1]);
4441 sub_v2_v2v2(tmp1, st3, st0);
4442 sub_v2_v2v2(tmp2, st2, st1);
4443 interp_v2_v2v2(t, tmp1, tmp2, r_uv[0]);
4444
4445 denom = t[0] * s[1] - t[1] * s[0];
4446
4447 if (!IS_ZERO(denom)) {
4448 double inv_denom = 1.0 / denom;
4449 r_deriv[0][0] = float(double(-t[1]) * inv_denom);
4450 r_deriv[0][1] = float(double(t[0]) * inv_denom);
4451 r_deriv[1][0] = float(double(s[1]) * inv_denom);
4452 r_deriv[1][1] = float(double(-s[0]) * inv_denom);
4453 }
4454 }
4455}
4456
4457float resolve_quad_u_v2(const float st[2],
4458 const float st0[2],
4459 const float st1[2],
4460 const float st2[2],
4461 const float st3[2])
4462{
4463 const double signed_area = (st0[0] * st1[1] - st0[1] * st1[0]) +
4464 (st1[0] * st2[1] - st1[1] * st2[0]) +
4465 (st2[0] * st3[1] - st2[1] * st3[0]) +
4466 (st3[0] * st0[1] - st3[1] * st0[0]);
4467
4468 /* X is 2D cross product (determinant)
4469 * A = (p0 - p) X (p0 - p3) */
4470 const double a = (st0[0] - st[0]) * (st0[1] - st3[1]) - (st0[1] - st[1]) * (st0[0] - st3[0]);
4471
4472 /* B = ( (p0 - p) X (p1 - p2) + (p1 - p) X (p0 - p3) ) / 2 */
4473 const double b =
4474 0.5 * double(((st0[0] - st[0]) * (st1[1] - st2[1]) - (st0[1] - st[1]) * (st1[0] - st2[0])) +
4475 ((st1[0] - st[0]) * (st0[1] - st3[1]) - (st1[1] - st[1]) * (st0[0] - st3[0])));
4476
4477 /* C = (p1-p) X (p1-p2) */
4478 const double fC = (st1[0] - st[0]) * (st1[1] - st2[1]) - (st1[1] - st[1]) * (st1[0] - st2[0]);
4479 double denom = a - 2 * b + fC;
4480
4481 if (IS_ZERO(denom) != 0) {
4482 const double fDen = a - fC;
4483 if (IS_ZERO(fDen) == 0) {
4484 return float(a / fDen);
4485 }
4486
4487 return 0.0f;
4488 }
4489
4490 const double desc_sq = b * b - a * fC;
4491 const double desc = sqrt(desc_sq < 0.0 ? 0.0 : desc_sq);
4492 const double s = signed_area > 0 ? (-1.0) : 1.0;
4493
4494 return float(((a - b) + s * desc) / denom);
4495}
4496
4497#undef IS_ZERO
4498
4499void interp_bilinear_quad_v3(float data[4][3], float u, float v, float res[3])
4500{
4501 float vec[3];
4502
4503 copy_v3_v3(res, data[0]);
4504 mul_v3_fl(res, (1 - u) * (1 - v));
4505 copy_v3_v3(vec, data[1]);
4506 mul_v3_fl(vec, u * (1 - v));
4507 add_v3_v3(res, vec);
4508 copy_v3_v3(vec, data[2]);
4509 mul_v3_fl(vec, u * v);
4510 add_v3_v3(res, vec);
4511 copy_v3_v3(vec, data[3]);
4512 mul_v3_fl(vec, (1 - u) * v);
4513 add_v3_v3(res, vec);
4514}
4515
4516void interp_barycentric_tri_v3(float data[3][3], float u, float v, float res[3])
4517{
4518 float vec[3];
4519
4520 copy_v3_v3(res, data[0]);
4521 mul_v3_fl(res, u);
4522 copy_v3_v3(vec, data[1]);
4523 mul_v3_fl(vec, v);
4524 add_v3_v3(res, vec);
4525 copy_v3_v3(vec, data[2]);
4526 mul_v3_fl(vec, 1.0f - u - v);
4527 add_v3_v3(res, vec);
4528}
4529
4530/***************************** View & Projection *****************************/
4531
4532void orthographic_m4(float mat[4][4],
4533 const float left,
4534 const float right,
4535 const float bottom,
4536 const float top,
4537 const float nearClip,
4538 const float farClip)
4539{
4540 float Xdelta, Ydelta, Zdelta;
4541
4542 Xdelta = right - left;
4543 Ydelta = top - bottom;
4544 Zdelta = farClip - nearClip;
4545 if (Xdelta == 0.0f || Ydelta == 0.0f || Zdelta == 0.0f) {
4546 return;
4547 }
4548 unit_m4(mat);
4549 mat[0][0] = 2.0f / Xdelta;
4550 mat[3][0] = -(right + left) / Xdelta;
4551 mat[1][1] = 2.0f / Ydelta;
4552 mat[3][1] = -(top + bottom) / Ydelta;
4553 mat[2][2] = -2.0f / Zdelta; /* NOTE: negate Z. */
4554 mat[3][2] = -(farClip + nearClip) / Zdelta;
4555}
4556
4557void perspective_m4(float mat[4][4],
4558 const float left,
4559 const float right,
4560 const float bottom,
4561 const float top,
4562 const float nearClip,
4563 const float farClip)
4564{
4565 const float Xdelta = right - left;
4566 const float Ydelta = top - bottom;
4567 const float Zdelta = farClip - nearClip;
4568
4569 if (Xdelta == 0.0f || Ydelta == 0.0f || Zdelta == 0.0f) {
4570 return;
4571 }
4572 mat[0][0] = nearClip * 2.0f / Xdelta;
4573 mat[1][1] = nearClip * 2.0f / Ydelta;
4574 mat[2][0] = (right + left) / Xdelta; /* NOTE: negate Z. */
4575 mat[2][1] = (top + bottom) / Ydelta;
4576 mat[2][2] = -(farClip + nearClip) / Zdelta;
4577 mat[2][3] = -1.0f;
4578 mat[3][2] = (-2.0f * nearClip * farClip) / Zdelta;
4579 mat[0][1] = mat[0][2] = mat[0][3] = mat[1][0] = mat[1][2] = mat[1][3] = mat[3][0] = mat[3][1] =
4580 mat[3][3] = 0.0f;
4581}
4582
4583void perspective_m4_fov(float mat[4][4],
4584 const float angle_left,
4585 const float angle_right,
4586 const float angle_up,
4587 const float angle_down,
4588 const float nearClip,
4589 const float farClip)
4590{
4591 const float tan_angle_left = tanf(angle_left);
4592 const float tan_angle_right = tanf(angle_right);
4593 const float tan_angle_bottom = tanf(angle_up);
4594 const float tan_angle_top = tanf(angle_down);
4595
4597 mat, tan_angle_left, tan_angle_right, tan_angle_top, tan_angle_bottom, nearClip, farClip);
4598 mat[0][0] /= nearClip;
4599 mat[1][1] /= nearClip;
4600}
4601
4602void window_translate_m4(float winmat[4][4], float perspmat[4][4], const float x, const float y)
4603{
4604 if (winmat[2][3] == -1.0f) {
4605 /* in the case of a win-matrix, this means perspective always */
4606 float v1[3];
4607 float v2[3];
4608 float len1, len2;
4609
4610 v1[0] = perspmat[0][0];
4611 v1[1] = perspmat[1][0];
4612 v1[2] = perspmat[2][0];
4613
4614 v2[0] = perspmat[0][1];
4615 v2[1] = perspmat[1][1];
4616 v2[2] = perspmat[2][1];
4617
4618 len1 = (1.0f / len_v3(v1));
4619 len2 = (1.0f / len_v3(v2));
4620
4621 winmat[2][0] -= len1 * winmat[0][0] * x;
4622 winmat[2][1] -= len2 * winmat[1][1] * y;
4623 }
4624 else {
4625 winmat[3][0] += x;
4626 winmat[3][1] += y;
4627 }
4628}
4629
4630void planes_from_projmat(const float mat[4][4],
4631 float left[4],
4632 float right[4],
4633 float bottom[4],
4634 float top[4],
4635 float near[4],
4636 float far[4])
4637{
4638 /* References:
4639 *
4640 * https://fgiesen.wordpress.com/2012/08/31/frustum-planes-from-the-projection-matrix/
4641 * http://www8.cs.umu.se/kurser/5DV051/HT12/lab/plane_extraction.pdf
4642 */
4643
4644 int i;
4645
4646 if (left) {
4647 for (i = 4; i--;) {
4648 left[i] = mat[i][3] + mat[i][0];
4649 }
4650 }
4651
4652 if (right) {
4653 for (i = 4; i--;) {
4654 right[i] = mat[i][3] - mat[i][0];
4655 }
4656 }
4657
4658 if (bottom) {
4659 for (i = 4; i--;) {
4660 bottom[i] = mat[i][3] + mat[i][1];
4661 }
4662 }
4663
4664 if (top) {
4665 for (i = 4; i--;) {
4666 top[i] = mat[i][3] - mat[i][1];
4667 }
4668 }
4669
4670 if (near) {
4671 for (i = 4; i--;) {
4672 near[i] = mat[i][3] + mat[i][2];
4673 }
4674 }
4675
4676 if (far) {
4677 for (i = 4; i--;) {
4678 far[i] = mat[i][3] - mat[i][2];
4679 }
4680 }
4681}
4682
4683void projmat_dimensions(const float winmat[4][4],
4684 float *r_left,
4685 float *r_right,
4686 float *r_bottom,
4687 float *r_top,
4688 float *r_near,
4689 float *r_far)
4690{
4691 const bool is_persp = winmat[3][3] == 0.0f;
4692 if (is_persp) {
4693 const float near = winmat[3][2] / (winmat[2][2] - 1.0f);
4694 *r_left = near * ((winmat[2][0] - 1.0f) / winmat[0][0]);
4695 *r_right = near * ((winmat[2][0] + 1.0f) / winmat[0][0]);
4696 *r_bottom = near * ((winmat[2][1] - 1.0f) / winmat[1][1]);
4697 *r_top = near * ((winmat[2][1] + 1.0f) / winmat[1][1]);
4698 *r_near = near;
4699 *r_far = winmat[3][2] / (winmat[2][2] + 1.0f);
4700 }
4701 else {
4702 *r_left = (-winmat[3][0] - 1.0f) / winmat[0][0];
4703 *r_right = (-winmat[3][0] + 1.0f) / winmat[0][0];
4704 *r_bottom = (-winmat[3][1] - 1.0f) / winmat[1][1];
4705 *r_top = (-winmat[3][1] + 1.0f) / winmat[1][1];
4706 *r_near = (winmat[3][2] + 1.0f) / winmat[2][2];
4707 *r_far = (winmat[3][2] - 1.0f) / winmat[2][2];
4708 }
4709}
4710
4711void projmat_dimensions_db(const float winmat_fl[4][4],
4712 double *r_left,
4713 double *r_right,
4714 double *r_bottom,
4715 double *r_top,
4716 double *r_near,
4717 double *r_far)
4718{
4719 double winmat[4][4];
4720 copy_m4d_m4(winmat, winmat_fl);
4721
4722 const bool is_persp = winmat[3][3] == 0.0f;
4723 if (is_persp) {
4724 const double near = winmat[3][2] / (winmat[2][2] - 1.0);
4725 *r_left = near * ((winmat[2][0] - 1.0) / winmat[0][0]);
4726 *r_right = near * ((winmat[2][0] + 1.0) / winmat[0][0]);
4727 *r_bottom = near * ((winmat[2][1] - 1.0) / winmat[1][1]);
4728 *r_top = near * ((winmat[2][1] + 1.0) / winmat[1][1]);
4729 *r_near = near;
4730 *r_far = winmat[3][2] / (winmat[2][2] + 1.0);
4731 }
4732 else {
4733 *r_left = (-winmat[3][0] - 1.0) / winmat[0][0];
4734 *r_right = (-winmat[3][0] + 1.0) / winmat[0][0];
4735 *r_bottom = (-winmat[3][1] - 1.0) / winmat[1][1];
4736 *r_top = (-winmat[3][1] + 1.0) / winmat[1][1];
4737 *r_near = (winmat[3][2] + 1.0) / winmat[2][2];
4738 *r_far = (winmat[3][2] - 1.0) / winmat[2][2];
4739 }
4740}
4741
4742void projmat_from_subregion(const float projmat[4][4],
4743 const int win_size[2],
4744 const int x_min,
4745 const int x_max,
4746 const int y_min,
4747 const int y_max,
4748 float r_projmat[4][4])
4749{
4750 float rect_width = float(x_max - x_min);
4751 float rect_height = float(y_max - y_min);
4752
4753 float x_sca = float(win_size[0]) / rect_width;
4754 float y_sca = float(win_size[1]) / rect_height;
4755
4756 float x_fac = float((x_min + x_max) - win_size[0]) / rect_width;
4757 float y_fac = float((y_min + y_max) - win_size[1]) / rect_height;
4758
4759 copy_m4_m4(r_projmat, projmat);
4760 r_projmat[0][0] *= x_sca;
4761 r_projmat[1][1] *= y_sca;
4762
4763 if (projmat[3][3] == 0.0f) {
4764 r_projmat[2][0] = r_projmat[2][0] * x_sca + x_fac;
4765 r_projmat[2][1] = r_projmat[2][1] * y_sca + y_fac;
4766 }
4767 else {
4768 r_projmat[3][0] = r_projmat[3][0] * x_sca - x_fac;
4769 r_projmat[3][1] = r_projmat[3][1] * y_sca - y_fac;
4770 }
4771}
4772
4773static void i_multmatrix(const float icand[4][4], float mat[4][4])
4774{
4775 int row, col;
4776 float temp[4][4];
4777
4778 for (row = 0; row < 4; row++) {
4779 for (col = 0; col < 4; col++) {
4780 temp[row][col] = (icand[row][0] * mat[0][col] + icand[row][1] * mat[1][col] +
4781 icand[row][2] * mat[2][col] + icand[row][3] * mat[3][col]);
4782 }
4783 }
4784 copy_m4_m4(mat, temp);
4785}
4786
4787void polarview_m4(float mat[4][4], float dist, float azimuth, float incidence, float twist)
4788{
4789 unit_m4(mat);
4790
4791 translate_m4(mat, 0.0, 0.0, -dist);
4792 rotate_m4(mat, 'Z', -twist);
4793 rotate_m4(mat, 'X', -incidence);
4794 rotate_m4(mat, 'Z', -azimuth);
4795}
4796
4798 float mat[4][4], float vx, float vy, float vz, float px, float py, float pz, float twist)
4799{
4800 float sine, cosine, hyp, hyp1, dx, dy, dz;
4801 float mat1[4][4];
4802
4803 unit_m4(mat1);
4804
4805 axis_angle_to_mat4_single(mat, 'Z', -twist);
4806
4807 dx = px - vx;
4808 dy = py - vy;
4809 dz = pz - vz;
4810 hyp = dx * dx + dz * dz; /* hyp squared */
4811 hyp1 = sqrtf(dy * dy + hyp);
4812 hyp = sqrtf(hyp); /* the real hyp */
4813
4814 if (hyp1 != 0.0f) { /* rotate X */
4815 sine = -dy / hyp1;
4816 cosine = hyp / hyp1;
4817 }
4818 else {
4819 sine = 0.0f;
4820 cosine = 1.0f;
4821 }
4822 mat1[1][1] = cosine;
4823 mat1[1][2] = sine;
4824 mat1[2][1] = -sine;
4825 mat1[2][2] = cosine;
4826
4827 i_multmatrix(mat1, mat);
4828
4829 /* Be careful here to reinitialize those modified by the last. */
4830 mat1[1][1] = mat1[2][2] = 1.0f;
4831 mat1[1][2] = mat1[2][1] = 0.0f;
4832
4833 /* paragraph */
4834 if (hyp != 0.0f) { /* rotate Y */
4835 sine = dx / hyp;
4836 cosine = -dz / hyp;
4837 }
4838 else {
4839 sine = 0.0f;
4840 cosine = 1.0f;
4841 }
4842 mat1[0][0] = cosine;
4843 mat1[0][2] = -sine;
4844 mat1[2][0] = sine;
4845 mat1[2][2] = cosine;
4846
4847 i_multmatrix(mat1, mat);
4848 translate_m4(mat, -vx, -vy, -vz); /* translate viewpoint to origin */
4849}
4850
4851int box_clip_bounds_m4(float boundbox[2][3], const float bounds[4], float winmat[4][4])
4852{
4853 float mat[4][4], vec[4];
4854 int a, fl, flag = -1;
4855
4856 copy_m4_m4(mat, winmat);
4857
4858 for (a = 0; a < 8; a++) {
4859 vec[0] = (a & 1) ? boundbox[0][0] : boundbox[1][0];
4860 vec[1] = (a & 2) ? boundbox[0][1] : boundbox[1][1];
4861 vec[2] = (a & 4) ? boundbox[0][2] : boundbox[1][2];
4862 vec[3] = 1.0;
4863 mul_m4_v4(mat, vec);
4864
4865 fl = 0;
4866 if (bounds) {
4867 if (vec[0] > bounds[1] * vec[3]) {
4868 fl |= 1;
4869 }
4870 if (vec[0] < bounds[0] * vec[3]) {
4871 fl |= 2;
4872 }
4873 if (vec[1] > bounds[3] * vec[3]) {
4874 fl |= 4;
4875 }
4876 if (vec[1] < bounds[2] * vec[3]) {
4877 fl |= 8;
4878 }
4879 }
4880 else {
4881 if (vec[0] < -vec[3]) {
4882 fl |= 1;
4883 }
4884 if (vec[0] > vec[3]) {
4885 fl |= 2;
4886 }
4887 if (vec[1] < -vec[3]) {
4888 fl |= 4;
4889 }
4890 if (vec[1] > vec[3]) {
4891 fl |= 8;
4892 }
4893 }
4894 if (vec[2] < -vec[3]) {
4895 fl |= 16;
4896 }
4897 if (vec[2] > vec[3]) {
4898 fl |= 32;
4899 }
4900
4901 flag &= fl;
4902 if (flag == 0) {
4903 return 0;
4904 }
4905 }
4906
4907 return flag;
4908}
4909
4910void box_minmax_bounds_m4(float min[3], float max[3], float boundbox[2][3], float mat[4][4])
4911{
4912 float mn[3], mx[3], vec[3];
4913 int a;
4914
4915 copy_v3_v3(mn, min);
4916 copy_v3_v3(mx, max);
4917
4918 for (a = 0; a < 8; a++) {
4919 vec[0] = (a & 1) ? boundbox[0][0] : boundbox[1][0];
4920 vec[1] = (a & 2) ? boundbox[0][1] : boundbox[1][1];
4921 vec[2] = (a & 4) ? boundbox[0][2] : boundbox[1][2];
4922
4923 mul_m4_v3(mat, vec);
4924 minmax_v3v3_v3(mn, mx, vec);
4925 }
4926
4927 copy_v3_v3(min, mn);
4928 copy_v3_v3(max, mx);
4929}
4930
4931/********************************** Mapping **********************************/
4932
4933static float snap_coordinate(float u)
4934{
4935 /* Adjust a coordinate value `u` to obtain a value inside the (closed) unit interval.
4936 * i.e. 0.0 <= snap_coordinate(u) <= 1.0.
4937 * Due to round-off errors, it is possible that the value of `u` may be close to the boundary of
4938 * the unit interval, but not exactly on it. In order to handle these cases, `snap_coordinate`
4939 * checks whether `u` is within `epsilon` of the boundary, and if so, it snaps the return value
4940 * to the boundary. */
4941 if (u < 0.0f) {
4942 u += 1.0f; /* Get back into the unit interval. */
4943 }
4944 BLI_assert(0.0f <= u);
4945 BLI_assert(u <= 1.0f);
4946 const float epsilon = 0.25f / 65536.0f; /* i.e. Quarter of a texel on a 65536 x 65536 texture. */
4947 if (u < epsilon) {
4948 return 0.0f; /* `u` is close to 0, just return 0. */
4949 }
4950 if (1.0f - epsilon < u) {
4951 return 1.0f; /* `u` is close to 1, just return 1. */
4952 }
4953 return u;
4954}
4955
4956bool map_to_tube(float *r_u, float *r_v, const float x, const float y, const float z)
4957{
4958 bool regular = true;
4959 if (x * x + y * y < 1e-6f * 1e-6f) {
4960 regular = false; /* We're too close to the cylinder's axis. */
4961 *r_u = 0.5f;
4962 }
4963 else {
4964 /* The "Regular" case, just compute the coordinate. */
4965 *r_u = snap_coordinate(atan2f(x, -y) / float(2.0f * M_PI));
4966 }
4967 *r_v = (z + 1.0f) / 2.0f;
4968 return regular;
4969}
4970
4971bool map_to_sphere(float *r_u, float *r_v, const float x, const float y, const float z)
4972{
4973 bool regular = true;
4974 const float epsilon = 0.25f / 65536.0f; /* i.e. Quarter of a texel on a 65536 x 65536 texture. */
4975 const float len_xy = sqrtf(x * x + y * y);
4976 if (len_xy <= fabsf(z) * epsilon) {
4977 regular = false; /* We're on the line that runs through the north and south poles. */
4978 *r_u = 0.5f;
4979 }
4980 else {
4981 /* The "Regular" case, just compute the coordinate. */
4982 *r_u = snap_coordinate(atan2f(x, -y) / float(2.0f * M_PI));
4983 }
4984 *r_v = snap_coordinate(atan2f(len_xy, -z) / float(M_PI));
4985 return regular;
4986}
4987
4988void map_to_plane_v2_v3v3(float r_co[2], const float co[3], const float no[3])
4989{
4990 const float target[3] = {0.0f, 0.0f, 1.0f};
4991 float axis[3];
4992
4993 cross_v3_v3v3(axis, no, target);
4994 normalize_v3(axis);
4995
4996 map_to_plane_axis_angle_v2_v3v3fl(r_co, co, axis, angle_normalized_v3v3(no, target));
4997}
4998
5000 const float co[3],
5001 const float axis[3],
5002 const float angle)
5003{
5004 float tmp[3];
5005
5006 rotate_normalized_v3_v3v3fl(tmp, co, axis, angle);
5007
5008 copy_v2_v2(r_co, tmp);
5009}
5010
5011/********************************* Normals **********************************/
5012
5014 float n2[3],
5015 float n3[3],
5016 const float f_no[3],
5017 const float co1[3],
5018 const float co2[3],
5019 const float co3[3])
5020{
5021 float vdiffs[3][3];
5022 const int nverts = 3;
5023
5024 /* compute normalized edge vectors */
5025 sub_v3_v3v3(vdiffs[0], co2, co1);
5026 sub_v3_v3v3(vdiffs[1], co3, co2);
5027 sub_v3_v3v3(vdiffs[2], co1, co3);
5028
5029 normalize_v3(vdiffs[0]);
5030 normalize_v3(vdiffs[1]);
5031 normalize_v3(vdiffs[2]);
5032
5033 /* accumulate angle weighted face normal */
5034 {
5035 float *vn[] = {n1, n2, n3};
5036 const float *prev_edge = vdiffs[nverts - 1];
5037 int i;
5038
5039 for (i = 0; i < nverts; i++) {
5040 const float *cur_edge = vdiffs[i];
5041 const float fac = blender::math::safe_acos_approx(-dot_v3v3(cur_edge, prev_edge));
5042
5043 /* accumulate */
5044 madd_v3_v3fl(vn[i], f_no, fac);
5045 prev_edge = cur_edge;
5046 }
5047 }
5048}
5049
5051 float n2[3],
5052 float n3[3],
5053 float n4[3],
5054 const float f_no[3],
5055 const float co1[3],
5056 const float co2[3],
5057 const float co3[3],
5058 const float co4[3])
5059{
5060 float vdiffs[4][3];
5061 const int nverts = (n4 != nullptr && co4 != nullptr) ? 4 : 3;
5062
5063 /* compute normalized edge vectors */
5064 sub_v3_v3v3(vdiffs[0], co2, co1);
5065 sub_v3_v3v3(vdiffs[1], co3, co2);
5066
5067 if (nverts == 3) {
5068 sub_v3_v3v3(vdiffs[2], co1, co3);
5069 }
5070 else {
5071 sub_v3_v3v3(vdiffs[2], co4, co3);
5072 sub_v3_v3v3(vdiffs[3], co1, co4);
5073 normalize_v3(vdiffs[3]);
5074 }
5075
5076 normalize_v3(vdiffs[0]);
5077 normalize_v3(vdiffs[1]);
5078 normalize_v3(vdiffs[2]);
5079
5080 /* accumulate angle weighted face normal */
5081 {
5082 float *vn[] = {n1, n2, n3, n4};
5083 const float *prev_edge = vdiffs[nverts - 1];
5084 int i;
5085
5086 for (i = 0; i < nverts; i++) {
5087 const float *cur_edge = vdiffs[i];
5088 const float fac = blender::math::safe_acos_approx(-dot_v3v3(cur_edge, prev_edge));
5089
5090 /* accumulate */
5091 madd_v3_v3fl(vn[i], f_no, fac);
5092 prev_edge = cur_edge;
5093 }
5094 }
5095}
5096
5098 const float polyno[3],
5099 const float **vertcos,
5100 float vdiffs[][3],
5101 const int nverts)
5102{
5103 int i;
5104
5105 /* calculate normalized edge directions for each edge in the poly */
5106 for (i = 0; i < nverts; i++) {
5107 sub_v3_v3v3(vdiffs[i], vertcos[(i + 1) % nverts], vertcos[i]);
5108 normalize_v3(vdiffs[i]);
5109 }
5110
5111 /* accumulate angle weighted face normal */
5112 {
5113 const float *prev_edge = vdiffs[nverts - 1];
5114
5115 for (i = 0; i < nverts; i++) {
5116 const float *cur_edge = vdiffs[i];
5117
5118 /* calculate angle between the two poly edges incident on
5119 * this vertex */
5120 const float fac = blender::math::safe_acos_approx(-dot_v3v3(cur_edge, prev_edge));
5121
5122 /* accumulate */
5123 madd_v3_v3fl(vertnos[i], polyno, fac);
5124 prev_edge = cur_edge;
5125 }
5126 }
5127}
5128
5129/********************************* Tangents **********************************/
5130
5131void tangent_from_uv_v3(const float uv1[2],
5132 const float uv2[2],
5133 const float uv3[2],
5134 const float co1[3],
5135 const float co2[3],
5136 const float co3[3],
5137 const float n[3],
5138 float r_tang[3])
5139{
5140 const float s1 = uv2[0] - uv1[0];
5141 const float s2 = uv3[0] - uv1[0];
5142 const float t1 = uv2[1] - uv1[1];
5143 const float t2 = uv3[1] - uv1[1];
5144 float det = (s1 * t2 - s2 * t1);
5145
5146 /* otherwise 'r_tang' becomes nan */
5147 if (det != 0.0f) {
5148 float tangv[3], ct[3], e1[3], e2[3];
5149
5150 det = 1.0f / det;
5151
5152 /* normals in render are inversed... */
5153 sub_v3_v3v3(e1, co1, co2);
5154 sub_v3_v3v3(e2, co1, co3);
5155 r_tang[0] = (t2 * e1[0] - t1 * e2[0]) * det;
5156 r_tang[1] = (t2 * e1[1] - t1 * e2[1]) * det;
5157 r_tang[2] = (t2 * e1[2] - t1 * e2[2]) * det;
5158 tangv[0] = (s1 * e2[0] - s2 * e1[0]) * det;
5159 tangv[1] = (s1 * e2[1] - s2 * e1[1]) * det;
5160 tangv[2] = (s1 * e2[2] - s2 * e1[2]) * det;
5161 cross_v3_v3v3(ct, r_tang, tangv);
5162
5163 /* check flip */
5164 if (dot_v3v3(ct, n) < 0.0f) {
5165 negate_v3(r_tang);
5166 }
5167 }
5168 else {
5169 zero_v3(r_tang);
5170 }
5171}
5172
5173/****************************** Vector Clouds ********************************/
5174
5175/* vector clouds */
5176
5177void vcloud_estimate_transform_v3(const int list_size,
5178 const float (*pos)[3],
5179 const float *weight,
5180 const float (*rpos)[3],
5181 const float *rweight,
5182 float lloc[3],
5183 float rloc[3],
5184 float lrot[3][3],
5185 float lscale[3][3])
5186{
5187 float accu_com[3] = {0.0f, 0.0f, 0.0f}, accu_rcom[3] = {0.0f, 0.0f, 0.0f};
5188 float accu_weight = 0.0f, accu_rweight = 0.0f;
5189 const float eps = 1e-6f;
5190
5191 int a;
5192 /* first set up a nice default response */
5193 if (lloc) {
5194 zero_v3(lloc);
5195 }
5196 if (rloc) {
5197 zero_v3(rloc);
5198 }
5199 if (lrot) {
5200 unit_m3(lrot);
5201 }
5202 if (lscale) {
5203 unit_m3(lscale);
5204 }
5205 /* do com for both clouds */
5206 if (pos && rpos && (list_size > 0)) { /* paranoia check */
5207 /* do com for both clouds */
5208 for (a = 0; a < list_size; a++) {
5209 if (weight) {
5210 float v[3];
5211 copy_v3_v3(v, pos[a]);
5212 mul_v3_fl(v, weight[a]);
5213 add_v3_v3(accu_com, v);
5214 accu_weight += weight[a];
5215 }
5216 else {
5217 add_v3_v3(accu_com, pos[a]);
5218 }
5219
5220 if (rweight) {
5221 float v[3];
5222 copy_v3_v3(v, rpos[a]);
5223 mul_v3_fl(v, rweight[a]);
5224 add_v3_v3(accu_rcom, v);
5225 accu_rweight += rweight[a];
5226 }
5227 else {
5228 add_v3_v3(accu_rcom, rpos[a]);
5229 }
5230 }
5231 if (!weight || !rweight) {
5232 accu_weight = accu_rweight = float(list_size);
5233 }
5234
5235 mul_v3_fl(accu_com, 1.0f / accu_weight);
5236 mul_v3_fl(accu_rcom, 1.0f / accu_rweight);
5237 if (lloc) {
5238 copy_v3_v3(lloc, accu_com);
5239 }
5240 if (rloc) {
5241 copy_v3_v3(rloc, accu_rcom);
5242 }
5243 if (lrot || lscale) { /* caller does not want rot nor scale, strange but legal */
5244 /* so now do some reverse engineering and see if we can
5245 * split rotation from scale -> Polar-decompose. */
5246 /* build 'projection' matrix */
5247 float m[3][3], mr[3][3], q[3][3], qi[3][3];
5248 float va[3], vb[3], stunt[3];
5249 float odet, ndet;
5250 int i = 0, imax = 15;
5251 zero_m3(m);
5252 zero_m3(mr);
5253
5254 /* build 'projection' matrix */
5255 for (a = 0; a < list_size; a++) {
5256 sub_v3_v3v3(va, rpos[a], accu_rcom);
5257 // mul_v3_fl(va, bp->mass); /* Mass needs re-normalization here? */
5258 sub_v3_v3v3(vb, pos[a], accu_com);
5259 // mul_v3_fl(va, rp->mass);
5260 m[0][0] += va[0] * vb[0];
5261 m[0][1] += va[0] * vb[1];
5262 m[0][2] += va[0] * vb[2];
5263
5264 m[1][0] += va[1] * vb[0];
5265 m[1][1] += va[1] * vb[1];
5266 m[1][2] += va[1] * vb[2];
5267
5268 m[2][0] += va[2] * vb[0];
5269 m[2][1] += va[2] * vb[1];
5270 m[2][2] += va[2] * vb[2];
5271
5272 /* building the reference matrix on the fly
5273 * needed to scale properly later */
5274
5275 mr[0][0] += va[0] * va[0];
5276 mr[0][1] += va[0] * va[1];
5277 mr[0][2] += va[0] * va[2];
5278
5279 mr[1][0] += va[1] * va[0];
5280 mr[1][1] += va[1] * va[1];
5281 mr[1][2] += va[1] * va[2];
5282
5283 mr[2][0] += va[2] * va[0];
5284 mr[2][1] += va[2] * va[1];
5285 mr[2][2] += va[2] * va[2];
5286 }
5287 copy_m3_m3(q, m);
5288 stunt[0] = q[0][0];
5289 stunt[1] = q[1][1];
5290 stunt[2] = q[2][2];
5291 /* Re-normalizing for numeric stability. */
5292 mul_m3_fl(q, 1.0f / len_v3(stunt));
5293
5294 /* This is pretty much Polar-decompose 'inline' the algorithm based on Higham's thesis
5295 * without the far case ... but seems to work here pretty neat. */
5296 odet = 0.0f;
5297 ndet = determinant_m3_array(q);
5298 while ((odet - ndet) * (odet - ndet) > eps && i < imax) {
5299 invert_m3_m3(qi, q);
5300 transpose_m3(qi);
5301 add_m3_m3m3(q, q, qi);
5302 mul_m3_fl(q, 0.5f);
5303 odet = ndet;
5304 ndet = determinant_m3_array(q);
5305 i++;
5306 }
5307
5308 if (i) {
5309 float scale[3][3];
5310 float irot[3][3];
5311 if (lrot) {
5312 copy_m3_m3(lrot, q);
5313 }
5314 invert_m3_m3(irot, q);
5315 invert_m3_m3(qi, mr);
5316 mul_m3_m3m3(q, m, qi);
5317 mul_m3_m3m3(scale, irot, q);
5318 if (lscale) {
5319 copy_m3_m3(lscale, scale);
5320 }
5321 }
5322 }
5323 }
5324}
5325
5326bool is_edge_convex_v3(const float v1[3],
5327 const float v2[3],
5328 const float f1_no[3],
5329 const float f2_no[3])
5330{
5331 if (!equals_v3v3(f1_no, f2_no)) {
5332 float cross[3];
5333 float l_dir[3];
5334 cross_v3_v3v3(cross, f1_no, f2_no);
5335 /* we assume contiguous normals, otherwise the result isn't meaningful */
5336 sub_v3_v3v3(l_dir, v2, v1);
5337 return (dot_v3v3(l_dir, cross) > 0.0f);
5338 }
5339 return false;
5340}
5341
5342bool is_quad_convex_v3(const float v1[3], const float v2[3], const float v3[3], const float v4[3])
5343{
5352
5353 /* non-unit length normal, used as a projection plane */
5354 float plane[3];
5355
5356 {
5357 float v13[3], v24[3];
5358
5359 sub_v3_v3v3(v13, v1, v3);
5360 sub_v3_v3v3(v24, v2, v4);
5361
5362 cross_v3_v3v3(plane, v13, v24);
5363
5364 if (len_squared_v3(plane) < FLT_EPSILON) {
5365 return false;
5366 }
5367 }
5368
5369 const float *quad_coords[4] = {v1, v2, v3, v4};
5370 float quad_proj[4][3];
5371
5372 for (int i = 0; i < 4; i++) {
5373 project_plane_v3_v3v3(quad_proj[i], quad_coords[i], plane);
5374 }
5375
5376 float quad_dirs[4][3];
5377 for (int i = 0, j = 3; i < 4; j = i++) {
5378 sub_v3_v3v3(quad_dirs[i], quad_proj[i], quad_proj[j]);
5379 }
5380
5381 float test_dir[3];
5382
5383#define CROSS_SIGN(dir_a, dir_b) \
5384 ((void)cross_v3_v3v3(test_dir, dir_a, dir_b), (dot_v3v3(plane, test_dir) > 0.0f))
5385
5386 return (CROSS_SIGN(quad_dirs[0], quad_dirs[1]) && CROSS_SIGN(quad_dirs[1], quad_dirs[2]) &&
5387 CROSS_SIGN(quad_dirs[2], quad_dirs[3]) && CROSS_SIGN(quad_dirs[3], quad_dirs[0]));
5388
5389#undef CROSS_SIGN
5390}
5391
5392bool is_quad_convex_v2(const float v1[2], const float v2[2], const float v3[2], const float v4[2])
5393{
5394 /* Line-tests, the 2 diagonals have to intersect to be convex. */
5395 return (isect_seg_seg_v2(v1, v3, v2, v4) > 0);
5396}
5397
5398bool is_poly_convex_v2(const float verts[][2], uint nr)
5399{
5400 uint sign_flag = 0;
5401 uint a;
5402 const float *co_curr, *co_prev;
5403 float dir_curr[2], dir_prev[2];
5404
5405 co_prev = verts[nr - 1];
5406 co_curr = verts[0];
5407
5408 sub_v2_v2v2(dir_prev, verts[nr - 2], co_prev);
5409
5410 for (a = 0; a < nr; a++) {
5411 float cross;
5412
5413 sub_v2_v2v2(dir_curr, co_prev, co_curr);
5414
5415 cross = cross_v2v2(dir_prev, dir_curr);
5416
5417 if (cross < 0.0f) {
5418 sign_flag |= 1;
5419 }
5420 else if (cross > 0.0f) {
5421 sign_flag |= 2;
5422 }
5423
5424 if (sign_flag == (1 | 2)) {
5425 return false;
5426 }
5427
5428 copy_v2_v2(dir_prev, dir_curr);
5429
5430 co_prev = co_curr;
5431 co_curr += 2;
5432 }
5433
5434 return true;
5435}
5436
5437int is_quad_flip_v3(const float v1[3], const float v2[3], const float v3[3], const float v4[3])
5438{
5439 float d_12[3], d_23[3], d_34[3], d_41[3];
5440 float cross_a[3], cross_b[3];
5441 int ret = 0;
5442
5443 sub_v3_v3v3(d_12, v1, v2);
5444 sub_v3_v3v3(d_23, v2, v3);
5445 sub_v3_v3v3(d_34, v3, v4);
5446 sub_v3_v3v3(d_41, v4, v1);
5447
5448 cross_v3_v3v3(cross_a, d_12, d_23);
5449 cross_v3_v3v3(cross_b, d_34, d_41);
5450 ret |= ((dot_v3v3(cross_a, cross_b) < 0.0f) << 0);
5451
5452 cross_v3_v3v3(cross_a, d_23, d_34);
5453 cross_v3_v3v3(cross_b, d_41, d_12);
5454 ret |= ((dot_v3v3(cross_a, cross_b) < 0.0f) << 1);
5455
5456 return ret;
5457}
5458
5460 const float v2[3],
5461 const float v3[3],
5462 const float v4[3])
5463{
5464 /* NOTE: if the faces normal has been calculated it's possible to simplify the following checks,
5465 * however this means the solution may be different depending on the existence of normals
5466 * causing tessellation to be "unstable" depending on the existence of normals, see #106469. */
5467 float d_12[3], d_13[3], d_14[3];
5468 float cross_a[3], cross_b[3];
5469 sub_v3_v3v3(d_12, v2, v1);
5470 sub_v3_v3v3(d_13, v3, v1);
5471 sub_v3_v3v3(d_14, v4, v1);
5472 cross_v3_v3v3(cross_a, d_12, d_13);
5473 cross_v3_v3v3(cross_b, d_14, d_13);
5474 return dot_v3v3(cross_a, cross_b) > 0.0f;
5475}
5476
5477float cubic_tangent_factor_circle_v3(const float tan_l[3], const float tan_r[3])
5478{
5479 BLI_ASSERT_UNIT_V3(tan_l);
5480 BLI_ASSERT_UNIT_V3(tan_r);
5481
5482 /* -7f causes instability/glitches with Bendy Bones + Custom Refs. */
5483 const float eps = 1e-5f;
5484
5485 const float tan_dot = dot_v3v3(tan_l, tan_r);
5486 if (tan_dot > 1.0f - eps) {
5487 /* no angle difference (use fallback, length won't make any difference) */
5488 return (1.0f / 3.0f) * 0.75f;
5489 }
5490 if (tan_dot < -1.0f + eps) {
5491 /* Parallel tangents (half-circle). */
5492 return (1.0f / 2.0f);
5493 }
5494
5495 /* non-aligned tangents, calculate handle length */
5496 const float angle = acosf(tan_dot) / 2.0f;
5497
5498 /* could also use 'angle_sin = len_vnvn(tan_l, tan_r, dims) / 2.0' */
5499 const float angle_sin = sinf(angle);
5500 const float angle_cos = cosf(angle);
5501 return ((1.0f - angle_cos) / (angle_sin * 2.0f)) / angle_sin;
5502}
5503
5505 const float v0[3], const float v1[3], const float v2[3], const float dist1, const float dist2)
5506{
5507 /* Vectors along triangle edges. */
5508 float v10[3], v12[3];
5509 sub_v3_v3v3(v10, v0, v1);
5510 sub_v3_v3v3(v12, v2, v1);
5511
5512 if (dist1 != 0.0f && dist2 != 0.0f) {
5513 /* Local coordinate system in the triangle plane. */
5514 float u[3], v[3], n[3];
5515 const float d12 = normalize_v3_v3(u, v12);
5516
5517 if (d12 * d12 > 0.0f) {
5518 cross_v3_v3v3(n, v12, v10);
5519 normalize_v3(n);
5520 cross_v3_v3v3(v, n, u);
5521
5522 /* v0 in local coordinates */
5523 const float v0_[2] = {dot_v3v3(v10, u), fabsf(dot_v3v3(v10, v))};
5524
5525 /* Compute virtual source point in local coordinates, that we estimate the geodesic
5526 * distance is being computed from. See figure 9 in the paper for the derivation. */
5527 const float a = 0.5f * (1.0f + (dist1 * dist1 - dist2 * dist2) / (d12 * d12));
5528 const float hh = dist1 * dist1 - a * a * d12 * d12;
5529
5530 if (hh > 0.0f) {
5531 const float h = sqrtf(hh);
5532 const float S_[2] = {a * d12, -h};
5533
5534 /* Only valid if the line between the source point and v0 crosses
5535 * the edge between v1 and v2. */
5536 const float x_intercept = S_[0] + h * (v0_[0] - S_[0]) / (v0_[1] + h);
5537 if (x_intercept >= 0.0f && x_intercept <= d12) {
5538 return len_v2v2(S_, v0_);
5539 }
5540 }
5541 }
5542 }
5543
5544 /* Fall back to Dijsktra approximation in trivial case, or if no valid source
5545 * point found that connects to v0 across the triangle. */
5546 return min_ff(dist1 + len_v3(v10), dist2 + len_v3v3(v0, v2));
5547}
#define BLI_assert(a)
Definition BLI_assert.h:50
sqrt(x)+1/max(0
MINLINE float max_ff(float a, float b)
MINLINE float min_ffff(float a, float b, float c, float d)
#define BLI_ASSERT_UNIT_EPSILON
MINLINE float min_ff(float a, float b)
MINLINE float square_f(float a)
#define BLI_ASSERT_UNIT_V3(v)
#define M_PI
MINLINE int float_as_int(float f)
MINLINE float xor_fl(float x, int y)
bool isect_ray_tri_threshold_v3(const float ray_origin[3], const float ray_direction[3], const float v0[3], const float v1[3], const float v2[3], float *r_lambda, float r_uv[2], float threshold)
MINLINE float area_tri_v2(const float v1[2], const float v2[2], const float v3[2])
#define ISECT_AABB_PLANE_IN_FRONT_ALL
MINLINE int axis_dominant_v3_single(const float vec[3])
MINLINE float cross_tri_v2(const float v1[2], const float v2[2], const float v3[2])
#define ISECT_LINE_LINE_NONE
MINLINE float plane_point_side_v3(const float plane[4], const float co[3])
#define ISECT_AABB_PLANE_CROSS_ANY
#define ISECT_AABB_PLANE_BEHIND_ANY
#define ISECT_LINE_LINE_COLINEAR
#define ISECT_LINE_LINE_EXACT
MINLINE void axis_dominant_v3(int *r_axis_a, int *r_axis_b, const float axis[3])
#define ISECT_LINE_LINE_CROSS
bool is_negative_m3(const float mat[3][3])
void copy_m3_m3(float m1[3][3], const float m2[3][3])
void unit_m3(float m[3][3])
void transpose_m4_m4(float R[4][4], const float M[4][4])
void mul_m3_fl(float R[3][3], float f)
bool invert_m3_m3(float inverse[3][3], const float mat[3][3])
void unit_m4(float m[4][4])
Definition rct.c:1127
void add_m3_m3m3(float R[3][3], const float A[3][3], const float B[3][3])
void zero_m3(float m[3][3])
void translate_m4(float mat[4][4], float Tx, float Ty, float Tz)
void copy_m4d_m4(double m1[4][4], const float m2[4][4])
void mul_m4_v3(const float M[4][4], float r[3])
void copy_m4_m4(float m1[4][4], const float m2[4][4])
float determinant_m3_array(const float m[3][3])
void mul_m4_v4(const float mat[4][4], float r[4])
void rotate_m4(float mat[4][4], char axis, float angle)
void mul_v3_m3v3(float r[3], const float M[3][3], const float a[3])
void transpose_m3(float R[3][3])
float determinant_m3(float a1, float a2, float a3, float b1, float b2, float b3, float c1, float c2, float c3)
void mul_m3_m3m3(float R[3][3], const float A[3][3], const float B[3][3])
void axis_angle_to_mat4_single(float R[4][4], char axis, float angle)
MINLINE void sub_v3db_v3fl_v3fl(double r[3], const float a[3], const float b[3])
MINLINE void mul_v4_fl(float r[4], float f)
MINLINE float len_squared_v2(const float v[2]) ATTR_WARN_UNUSED_RESULT
MINLINE float len_v2(const float v[2]) ATTR_WARN_UNUSED_RESULT
MINLINE float len_squared_v3(const float v[3]) ATTR_WARN_UNUSED_RESULT
MINLINE float len_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
void minmax_v3v3_v3(float min[3], float max[3], const float vec[3])
MINLINE void madd_v3_v3fl(float r[3], const float a[3], float f)
MINLINE float len_squared_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT
MINLINE double dot_v2v2_db(const double a[2], const double b[2]) ATTR_WARN_UNUSED_RESULT
MINLINE void madd_v2_v2fl(float r[2], const float a[2], float f)
MINLINE void madd_v2_v2v2fl(float r[2], const float a[2], const float b[2], float f)
MINLINE bool equals_v3v3(const float v1[3], const float v2[3]) ATTR_WARN_UNUSED_RESULT
void interp_v3_v3v3v3(float p[3], const float v1[3], const float v2[3], const float v3[3], const float w[3])
MINLINE float len_squared_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE double dot_v3db_v3fl(const double a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void add_newell_cross_v3_v3v3(float n[3], const float v_prev[3], const float v_curr[3])
bool is_finite_v4(const float v[4]) ATTR_WARN_UNUSED_RESULT
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE float len_v2v2(const float v1[2], const float v2[2]) ATTR_WARN_UNUSED_RESULT
void interp_v2_v2v2(float r[2], const float a[2], const float b[2], float t)
Definition math_vector.c:21
MINLINE void copy_v2_v2(float r[2], const float a[2])
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void negate_v3_v3(float r[3], const float a[3])
void project_v3_v3v3_normalized(float out[3], const float p[3], const float v_proj[3])
void project_v3_v3v3(float out[3], const float p[3], const float v_proj[3])
void project_plane_v3_v3v3(float out[3], const float p[3], const float v_plane[3])
MINLINE float dot_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
void interp_v3_v3v3(float r[3], const float a[3], const float b[3], float t)
Definition math_vector.c:36
MINLINE void add_v3_v3v3(float r[3], const float a[3], const float b[3])
void rotate_normalized_v3_v3v3fl(float out[3], const float p[3], const float axis[3], float angle)
MINLINE void cross_v3_v3v3(float r[3], const float a[3], const float b[3])
bool is_finite_v3(const float v[3]) ATTR_WARN_UNUSED_RESULT
MINLINE bool equals_v2v2(const float v1[2], const float v2[2]) ATTR_WARN_UNUSED_RESULT
MINLINE void negate_v3(float r[3])
MINLINE float dot_m3_v3_row_z(const float M[3][3], const float a[3]) ATTR_WARN_UNUSED_RESULT
MINLINE float cross_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT
MINLINE void zero_v4(float r[4])
MINLINE float normalize_v3_v3(float r[3], const float a[3])
MINLINE void sub_v2_v2v2(float r[2], const float a[2], const float b[2])
MINLINE float line_point_side_v2(const float l1[2], const float l2[2], const float pt[2]) ATTR_WARN_UNUSED_RESULT
MINLINE bool is_zero_v3(const float v[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void zero_v2(float r[2])
MINLINE float mul_project_m4_v3_zfac(const float mat[4][4], const float co[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void cross_v3_v3v3_db(double r[3], const double a[3], const double b[3])
MINLINE float dot_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT
void ortho_basis_v3v3_v3(float r_n1[3], float r_n2[3], const float n[3])
MINLINE void copy_v3_fl(float r[3], float f)
MINLINE void madd_v3_v3v3fl(float r[3], const float a[3], const float b[3], float f)
MINLINE void zero_v3(float r[3])
MINLINE void mul_v3_v3fl(float r[3], const float a[3], float f)
MINLINE void mul_v2_v2fl(float r[2], const float a[2], float f)
float angle_normalized_v3v3(const float v1[3], const float v2[3]) ATTR_WARN_UNUSED_RESULT
MINLINE float dot_m4_v3_row_x(const float M[4][4], const float a[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void add_v3_v3(float r[3], const float a[3])
MINLINE void copy_v4_fl(float r[4], float f)
MINLINE float dot_m4_v3_row_y(const float M[4][4], const float a[3]) ATTR_WARN_UNUSED_RESULT
MINLINE float normalize_v3(float n[3])
MINLINE double cross_v2v2_db(const double a[2], const double b[2]) ATTR_WARN_UNUSED_RESULT
MINLINE float len_v3(const float a[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void sub_v2_v2v2_db(double r[2], const double a[2], const double b[2])
unsigned int uint
#define CLAMP(a, b, c)
#define UNUSED_VARS(...)
#define IN_RANGE(a, b, c)
#define UNPACK3(a)
#define UNLIKELY(x)
#define ELEM(...)
#define IN_RANGE_INCL(a, b, c)
#define LIKELY(x)
int rect_width(int rect[2][2])
Definition Basic.c:43
int rect_height(int rect[2][2])
Definition Basic.c:47
typedef double(DMatrix)[4][4]
static double angle(const Eigen::Vector3d &v1, const Eigen::Vector3d &v2)
Definition IK_Math.h:125
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Generate a perturbed normal from an RGB normal map image Typically used for faking highly detailed surfaces Generate an OSL shader from a file or text data block Image Sample an image file as a texture Gabor Generate Gabor noise Gradient Generate interpolated color and intensity values based on the input vector Magic Generate a psychedelic color texture Voronoi Generate Worley noise based on the distance to random points Typically used to generate textures such as or biological cells Brick Generate a procedural texture producing bricks Texture Retrieve multiple types of texture coordinates nTypically used as inputs for texture nodes Vector Convert a point
ATTR_WARN_UNUSED_RESULT const BMVert * v2
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMVert * v
static btDbvtVolume bounds(btDbvtNode **leaves, int count)
Definition btDbvt.cpp:299
btScalar determinant() const
Return the determinant of the matrix.
SIMD_FORCE_INLINE const btScalar & z() const
Return the z value.
Definition btQuadWord.h:117
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition btQuadWord.h:119
SIMD_FORCE_INLINE btScalar length(const btQuaternion &q)
Return the length of a quaternion.
bool closest(btVector3 &v)
local_group_size(16, 16) .push_constant(Type b
#define sinf(x)
#define cosf(x)
#define tanf(x)
#define atan2f(x, y)
#define acosf(x)
#define copysignf(x, y)
#define fabsf(x)
#define sqrtf(x)
int len
draw_view in_light_buf[] float
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
static float verts[][3]
uint col
uint top
ccl_device_inline float cross(const float2 a, const float2 b)
ccl_device_inline float2 fabs(const float2 a)
float area_poly_v2(const float verts[][2], uint nr)
Definition math_geom.cc:180
int isect_seg_seg_v2(const float v1[2], const float v2[2], const float v3[2], const float v4[2])
bool isect_point_planes_v3(const float(*planes)[4], int totplane, const float p[3])
static double mean_value_half_tan_v2_db(const Double2_Len *d_curr, const Double2_Len *d_next)
bool map_to_sphere(float *r_u, float *r_v, const float x, const float y, const float z)
bool isect_ray_aabb_v3(const IsectRayAABB_Precalc *data, const float bb_min[3], const float bb_max[3], float *r_tmin)
void plane_from_point_normal_v3(float r_plane[4], const float plane_co[3], const float plane_no[3])
Definition math_geom.cc:215
bool isect_ray_ray_v3(const float ray_origin_a[3], const float ray_direction_a[3], const float ray_origin_b[3], const float ray_direction_b[3], float *r_lambda_a, float *r_lambda_b)
#define IS_ZERO(x)
float dist_signed_to_plane3_v3(const float p[3], const float plane[3])
Definition math_geom.cc:505
int isect_point_quad_v2(const float p[2], const float v1[2], const float v2[2], const float v3[2], const float v4[2])
float cross_poly_v2(const float verts[][2], uint nr)
Definition math_geom.cc:147
float closest_to_ray_v3(float r_close[3], const float p[3], const float ray_orig[3], const float ray_dir[3])
void window_translate_m4(float winmat[4][4], float perspmat[4][4], const float x, const float y)
float closest_seg_seg_v2(float r_closest_a[2], float r_closest_b[2], float *r_lambda_a, float *r_lambda_b, const float a1[2], const float a2[2], const float b1[2], const float b2[2])
Definition math_geom.cc:303
float dist_squared_to_line_v3(const float p[3], const float l1[3], const float l2[3])
Definition math_geom.cc:531
float dist_squared_to_line_segment_v3(const float p[3], const float l1[3], const float l2[3])
Definition math_geom.cc:517
float normal_quad_v3(float n[3], const float v1[3], const float v2[3], const float v3[3], const float v4[3])
Definition math_geom.cc:56
int isect_line_line_v3(const float v1[3], const float v2[3], const float v3[3], const float v4[3], float r_i1[3], float r_i2[3])
float line_point_factor_v2_ex(const float p[2], const float l1[2], const float l2[2], const float epsilon, const float fallback)
static bool getLowestRoot(const float a, const float b, const float c, const float maxR, float *root)
float dist_squared_to_plane_v3(const float p[3], const float plane[4])
Definition math_geom.cc:468
bool isect_ray_line_v3(const float ray_origin[3], const float ray_direction[3], const float v0[3], const float v1[3], float *r_lambda)
int barycentric_inside_triangle_v2(const float w[3])
int is_quad_flip_v3(const float v1[3], const float v2[3], const float v3[3], const float v4[3])
float dist_squared_to_plane3_v3(const float p[3], const float plane[3])
Definition math_geom.cc:484
bool is_poly_convex_v2(const float verts[][2], uint nr)
void transform_point_by_seg_v3(float p_dst[3], const float p_src[3], const float l_dst_p1[3], const float l_dst_p2[3], const float l_src_p1[3], const float l_src_p2[3])
bool isect_sweeping_sphere_tri_v3(const float p1[3], const float p2[3], const float radius, const float v0[3], const float v1[3], const float v2[3], float *r_lambda, float ipoint[3])
float area_poly_v3(const float verts[][3], uint nr)
Definition math_geom.cc:131
bool isect_ray_tri_v3(const float ray_origin[3], const float ray_direction[3], const float v0[3], const float v1[3], const float v2[3], float *r_lambda, float r_uv[2])
float dist_to_plane3_v3(const float p[3], const float plane[3])
Definition math_geom.cc:512
void barycentric_weights_v2(const float v1[2], const float v2[2], const float v3[2], const float co[2], float w[3])
void accumulate_vertex_normals_tri_v3(float n1[3], float n2[3], float n3[3], const float f_no[3], const float co1[3], const float co2[3], const float co3[3])
float closest_to_line_segment_v3(float r_close[3], const float p[3], const float l1[3], const float l2[3])
Definition math_geom.cc:385
float ray_point_factor_v3(const float p[3], const float ray_origin[3], const float ray_direction[3])
void barycentric_weights_v2_clamped(const float v1[2], const float v2[2], const float v3[2], const float co[2], float w[3])
#define IS_POINT_IX
void isect_seg_seg_v3(const float a0[3], const float a1[3], const float b0[3], const float b1[3], float r_a[3], float r_b[3])
double closest_to_line_v2_db(double r_close[2], const double p[2], const double l1[2], const double l2[2])
bool isect_line_segment_tri_epsilon_v3(const float p1[3], const float p2[3], const float v0[3], const float v1[3], const float v2[3], float *r_lambda, float r_uv[2], const float epsilon)
void cross_tri_v3(float n[3], const float v1[3], const float v2[3], const float v3[3])
Definition math_geom.cc:24
bool point_in_slice_seg(float p[3], float l1[3], float l2[3])
static float mean_value_half_tan_v3(const Float3_Len *d_curr, const Float3_Len *d_next)
float dist_to_plane_v3(const float p[3], const float plane[4])
Definition math_geom.cc:500
bool isect_tri_tri_v2(const float t_a0[2], const float t_a1[2], const float t_a2[2], const float t_b0[2], const float t_b1[2], const float t_b2[2])
void transform_point_by_tri_v3(float pt_tar[3], float const pt_src[3], const float tri_tar_p1[3], const float tri_tar_p2[3], const float tri_tar_p3[3], const float tri_src_p1[3], const float tri_src_p2[3], const float tri_src_p3[3])
void polarview_m4(float mat[4][4], float dist, float azimuth, float incidence, float twist)
int isect_seg_seg_v2_lambda_mu_db(const double v1[2], const double v2[2], const double v3[2], const double v4[2], double *r_lambda, double *r_mu)
void interp_weights_quad_v3(float w[4], const float v1[3], const float v2[3], const float v3[3], const float v4[3], const float co[3])
float area_tri_signed_v3(const float v1[3], const float v2[3], const float v3[3], const float normal[3])
Definition math_geom.cc:113
float area_poly_signed_v2(const float verts[][2], uint nr)
Definition math_geom.cc:185
float volume_tri_tetrahedron_signed_v3_6x(const float v1[3], const float v2[3], const float v3[3])
Definition math_geom.cc:261
void closest_to_plane3_normalized_v3(float r_close[3], const float plane[3], const float pt[3])
Definition math_geom.cc:454
bool isect_seg_seg_v2_simple(const float v1[2], const float v2[2], const float v3[2], const float v4[2])
#define DIR_V3_SET(d_len, va, vb)
void closest_to_plane_normalized_v3(float r_close[3], const float plane[4], const float pt[3])
Definition math_geom.cc:440
int isect_point_tri_v2_int(const int x1, const int y1, const int x2, const int y2, const int a, const int b)
bool isect_ray_plane_v3_factor(const float ray_origin[3], const float ray_direction[3], const float plane_co[3], const float plane_no[3], float *r_lambda)
bool isect_point_tri_v3(const float p[3], const float v1[3], const float v2[3], const float v3[3], float r_isect_co[3])
void interp_weights_tri_v3(float w[3], const float v1[3], const float v2[3], const float v3[3], const float co[3])
void resolve_tri_uv_v2(float r_uv[2], const float st[2], const float st0[2], const float st1[2], const float st2[2])
float closest_ray_to_segment_v3(const float ray_origin[3], const float ray_direction[3], const float v0[3], const float v1[3], float r_close[3])
Definition math_geom.cc:407
float line_point_factor_v3_ex(const float p[3], const float l1[3], const float l2[3], const float epsilon, const float fallback)
void cross_poly_v3(float n[3], const float verts[][3], uint nr)
Definition math_geom.cc:166
bool isect_ray_aabb_v3_simple(const float orig[3], const float dir[3], const float bb_min[3], const float bb_max[3], float *tmin, float *tmax)
float dist_to_line_segment_v3(const float p[3], const float l1[3], const float l2[3])
Definition math_geom.cc:526
bool isect_aabb_aabb_v3(const float min1[3], const float max1[3], const float min2[3], const float max2[3])
void vcloud_estimate_transform_v3(const int list_size, const float(*pos)[3], const float *weight, const float(*rpos)[3], const float *rweight, float lloc[3], float rloc[3], float lrot[3][3], float lscale[3][3])
static void i_multmatrix(const float icand[4][4], float mat[4][4])
void projmat_from_subregion(const float projmat[4][4], const int win_size[2], const int x_min, const int x_max, const int y_min, const int y_max, float r_projmat[4][4])
float volume_tri_tetrahedron_signed_v3(const float v1[3], const float v2[3], const float v3[3])
Definition math_geom.cc:269
#define CCW(A, B, C)
bool isect_line_plane_v3(float r_isect_co[3], const float l1[3], const float l2[3], const float plane_co[3], const float plane_no[3])
bool isect_ray_seg_v2(const float ray_origin[2], const float ray_direction[2], const float v0[2], const float v1[2], float *r_lambda, float *r_u)
float dist_squared_to_projected_aabb_simple(const float projmat[4][4], const float winsize[2], const float mval[2], const float bbmin[3], const float bbmax[3])
Definition math_geom.cc:986
void accumulate_vertex_normals_poly_v3(float **vertnos, const float polyno[3], const float **vertcos, float vdiffs[][3], const int nverts)
float normal_poly_v3(float n[3], const float verts[][3], uint nr)
Definition math_geom.cc:77
float dist_squared_ray_to_aabb_v3_simple(const float ray_origin[3], const float ray_direction[3], const float bb_min[3], const float bb_max[3], float r_point[3], float *r_depth)
Definition math_geom.cc:787
static bool point_in_slice(const float p[3], const float v1[3], const float l1[3], const float l2[3])
bool is_quad_flip_v3_first_third_fast(const float v1[3], const float v2[3], const float v3[3], const float v4[3])
#define DIR_V2_SET(d_len, va, vb)
#define MEAN_VALUE_HALF_TAN_V2(_area, i1, i2)
bool clip_segment_v3_plane(const float p1[3], const float p2[3], const float plane[4], float r_p1[3], float r_p2[3])
void closest_to_plane3_v3(float r_close[3], const float plane[3], const float pt[3])
Definition math_geom.cc:447
bool isect_plane_plane_plane_v3(const float plane_a[4], const float plane_b[4], const float plane_c[4], float r_isect_co[3])
void interp_weights_poly_v2(float *w, float v[][2], const int n, const float co[2])
void resolve_quad_uv_v2(float r_uv[2], const float st[2], const float st0[2], const float st1[2], const float st2[2], const float st3[2])
float line_point_factor_v2(const float p[2], const float l1[2], const float l2[2])
void projmat_dimensions_db(const float winmat_fl[4][4], double *r_left, double *r_right, double *r_bottom, double *r_top, double *r_near, double *r_far)
bool isect_ray_tri_watertight_v3_simple(const float ray_origin[3], const float ray_direction[3], const float v0[3], const float v1[3], const float v2[3], float *r_lambda, float r_uv[2])
void closest_on_tri_to_point_v3(float r[3], const float p[3], const float v1[3], const float v2[3], const float v3[3])
void tangent_from_uv_v3(const float uv1[2], const float uv2[2], const float uv3[2], const float co1[3], const float co2[3], const float co3[3], const float n[3], float r_tang[3])
bool map_to_tube(float *r_u, float *r_v, const float x, const float y, const float z)
void perspective_m4(float mat[4][4], const float left, const float right, const float bottom, const float top, const float nearClip, const float farClip)
static bool isect_tri_tri_v2_impl_vert(const float t_a0[2], const float t_a1[2], const float t_a2[2], const float t_b0[2], const float t_b1[2], const float t_b2[2])
void lookat_m4(float mat[4][4], float vx, float vy, float vz, float px, float py, float pz, float twist)
void axis_dominant_v3_to_m3_negate(float r_mat[3][3], const float normal[3])
static bool barycentric_weights(const float v1[3], const float v2[3], const float v3[3], const float co[3], const float n[3], float w[3])
void accumulate_vertex_normals_v3(float n1[3], float n2[3], float n3[3], float n4[3], const float f_no[3], const float co1[3], const float co2[3], const float co3[3], const float co4[3])
bool isect_tri_tri_v3(const float t_a0[3], const float t_a1[3], const float t_a2[3], const float t_b0[3], const float t_b1[3], const float t_b2[3], float r_i1[3], float r_i2[3])
float line_plane_factor_v3(const float plane_co[3], const float plane_no[3], const float l1[3], const float l2[3])
static int isect_tri_tri_impl_ccw_v2(const float t_a0[2], const float t_a1[2], const float t_a2[2], const float t_b0[2], const float t_b1[2], const float t_b2[2])
#define IS_SEGMENT_IX
float dist_signed_to_plane_v3(const float p[3], const float plane[4])
Definition math_geom.cc:493
void aabb_get_near_far_from_plane(const float plane_no[3], const float bbmin[3], const float bbmax[3], float bb_near[3], float bb_afar[3])
Definition math_geom.cc:647
bool isect_ray_tri_watertight_v3(const float ray_origin[3], const IsectRayPrecalc *isect_precalc, const float v0[3], const float v1[3], const float v2[3], float *r_lambda, float r_uv[2])
void isect_ray_aabb_v3_precalc(IsectRayAABB_Precalc *data, const float ray_origin[3], const float ray_direction[3])
float dist_seg_seg_v2(const float a1[3], const float a2[3], const float b1[3], const float b2[3])
void resolve_tri_uv_v3(float r_uv[2], const float st[3], const float st0[3], const float st1[3], const float st2[3])
bool isect_point_poly_v2_int(const int pt[2], const int verts[][2], const uint nr)
bool isect_point_poly_v2(const float pt[2], const float verts[][2], const uint nr)
bool isect_plane_plane_v3(const float plane_a[4], const float plane_b[4], float r_isect_co[3], float r_isect_no[3])
float area_tri_v3(const float v1[3], const float v2[3], const float v3[3])
Definition math_geom.cc:98
bool isect_point_tri_v2_cw(const float pt[2], const float v1[2], const float v2[2], const float v3[2])
DistRayAABB_Precalc dist_squared_ray_to_aabb_v3_precalc(const float ray_origin[3], const float ray_direction[3])
Definition math_geom.cc:683
int isect_line_sphere_v3(const float l1[3], const float l2[3], const float sp[3], const float r, float r_p1[3], float r_p2[3])
bool is_quad_convex_v3(const float v1[3], const float v2[3], const float v3[3], const float v4[3])
void dist_squared_to_projected_aabb_precalc(DistProjectedAABBPrecalc *precalc, const float projmat[4][4], const float winsize[2], const float mval[2])
Definition math_geom.cc:804
bool is_edge_convex_v3(const float v1[3], const float v2[3], const float f1_no[3], const float f2_no[3])
float resolve_quad_u_v2(const float st[2], const float st0[2], const float st1[2], const float st2[2], const float st3[2])
void axis_dominant_v3_to_m3(float r_mat[3][3], const float normal[3])
Normal to x,y matrix.
void interp_barycentric_tri_v3(float data[3][3], float u, float v, float res[3])
float volume_tetrahedron_signed_v3(const float v1[3], const float v2[3], const float v3[3], const float v4[3])
Definition math_geom.cc:249
void perspective_m4_fov(float mat[4][4], const float angle_left, const float angle_right, const float angle_up, const float angle_down, const float nearClip, const float farClip)
float closest_to_line_segment_v2(float r_close[2], const float p[2], const float l1[2], const float l2[2])
Definition math_geom.cc:363
static bool point_in_slice_as(const float p[3], const float origin[3], const float normal[3])
bool isect_line_line_strict_v3(const float v1[3], const float v2[3], const float v3[3], const float v4[3], float vi[3], float *r_lambda)
float dist_squared_to_projected_aabb(DistProjectedAABBPrecalc *data, const float bbmin[3], const float bbmax[3], bool r_axis_closest[3])
Definition math_geom.cc:856
void interp_cubic_v3(float x[3], float v[3], const float x1[3], const float v1[3], const float x2[3], const float v2[3], const float t)
static bool isect_tri_tri_v2_impl_edge(const float t_a0[2], const float t_a1[2], const float t_a2[2], const float t_b0[2], const float t_b1[2], const float t_b2[2])
float area_squared_tri_v3(const float v1[3], const float v2[3], const float v3[3])
Definition math_geom.cc:105
bool isect_tri_tri_v3_ex(const float tri_a[3][3], const float tri_b[3][3], float r_i1[3], float r_i2[3], int *r_tri_a_edge_isect_count)
float dist_squared_ray_to_seg_v3(const float ray_origin[3], const float ray_direction[3], const float v0[3], const float v1[3], float r_point[3], float *r_depth)
Definition math_geom.cc:611
float area_squared_poly_v3(const float verts[][3], uint nr)
Definition math_geom.cc:138
void barycentric_weights_v2_quad(const float v1[2], const float v2[2], const float v3[2], const float v4[2], const float co[2], float w[4])
int isect_line_sphere_v2(const float l1[2], const float l2[2], const float sp[2], const float r, float r_p1[2], float r_p2[2])
float geodesic_distance_propagate_across_triangle(const float v0[3], const float v1[3], const float v2[3], const float dist1, const float dist2)
int box_clip_bounds_m4(float boundbox[2][3], const float bounds[4], float winmat[4][4])
bool isect_planes_v3_fn(const float planes[][4], const int planes_len, const float eps_coplanar, const float eps_isect, void(*callback_fn)(const float co[3], int i, int j, int k, void *user_data), void *user_data)
float cubic_tangent_factor_circle_v3(const float tan_l[3], const float tan_r[3])
float dist_squared_ray_to_aabb_v3(const DistRayAABB_Precalc *data, const float bb_min[3], const float bb_max[3], float r_point[3], float *r_depth)
Definition math_geom.cc:698
float line_point_factor_v3(const float p[3], const float l1[3], const float l2[3])
float dist_squared_to_ray_v3_normalized(const float ray_origin[3], const float ray_direction[3], const float co[3])
Definition math_geom.cc:595
float area_squared_quad_v3(const float v1[3], const float v2[3], const float v3[3], const float v4[3])
Definition math_geom.cc:89
void limit_dist_v3(float v1[3], float v2[3], const float dist)
bool barycentric_coords_v2(const float v1[2], const float v2[2], const float v3[2], const float co[2], float w[3])
bool clip_segment_v3_plane_n(const float p1[3], const float p2[3], const float plane_array[][4], const int plane_num, float r_p1[3], float r_p2[3])
int isect_line_line_v2_point(const float v0[2], const float v1[2], const float v2[2], const float v3[2], float r_vi[2])
void closest_to_plane_v3(float r_close[3], const float plane[4], const float pt[3])
Definition math_geom.cc:433
void plane_to_point_vector_v3(const float plane[4], float r_plane_co[3], float r_plane_no[3])
Definition math_geom.cc:221
int isect_seg_seg_v2_point_ex(const float v0[2], const float v1[2], const float v2[2], const float v3[2], const float endpoint_bias, float r_vi[2])
float closest_to_line_v2(float r_close[2], const float p[2], const float l1[2], const float l2[2])
void isect_ray_tri_watertight_v3_precalc(IsectRayPrecalc *isect_precalc, const float ray_direction[3])
float area_squared_poly_v2(const float verts[][2], uint nr)
Definition math_geom.cc:190
float dist_to_line_segment_v2(const float p[2], const float l1[2], const float l2[2])
Definition math_geom.cc:298
#define CROSS_SIGN(dir_a, dir_b)
float closest_to_line_v3(float r_close[3], const float p[3], const float l1[3], const float l2[3])
void projmat_dimensions(const float winmat[4][4], float *r_left, float *r_right, float *r_bottom, float *r_top, float *r_near, float *r_far)
void map_to_plane_v2_v3v3(float r_co[2], const float co[3], const float no[3])
bool is_quad_convex_v2(const float v1[2], const float v2[2], const float v3[2], const float v4[2])
float cotangent_tri_weight_v3(const float v1[3], const float v2[3], const float v3[3])
Definition math_geom.cc:196
void resolve_quad_uv_v2_deriv(float r_uv[2], float r_deriv[2][2], const float st[2], const float st0[2], const float st1[2], const float st2[2], const float st3[2])
bool isect_ray_ray_epsilon_v3(const float ray_origin_a[3], const float ray_direction_a[3], const float ray_origin_b[3], const float ray_direction_b[3], const float epsilon, float *r_lambda_a, float *r_lambda_b)
void barycentric_weights_v2_persp(const float v1[4], const float v2[4], const float v3[4], const float co[2], float w[3])
float dist_to_line_v3(const float p[3], const float l1[3], const float l2[3])
Definition math_geom.cc:539
float ray_point_factor_v3_ex(const float p[3], const float ray_origin[3], const float ray_direction[3], const float epsilon, const float fallback)
static float tri_signed_area(const float v1[3], const float v2[3], const float v3[3], const int i, const int j)
float dist_signed_squared_to_plane_v3(const float p[3], const float plane[4])
Definition math_geom.cc:461
int interp_sparse_array(float *array, const int list_size, const float skipval)
void orthographic_m4(float mat[4][4], const float left, const float right, const float bottom, const float top, const float nearClip, const float farClip)
bool isect_ray_tri_epsilon_v3(const float ray_origin[3], const float ray_direction[3], const float v0[3], const float v1[3], const float v2[3], float *r_lambda, float r_uv[2], const float epsilon)
float dist_squared_to_line_v2(const float p[2], const float l1[2], const float l2[2])
Definition math_geom.cc:276
int isect_line_line_epsilon_v3(const float v1[3], const float v2[3], const float v3[3], const float v4[3], float r_i1[3], float r_i2[3], const float epsilon)
int isect_seg_seg_v2_int(const int v1[2], const int v2[2], const int v3[2], const int v4[2])
int isect_point_tri_v2(const float pt[2], const float v1[2], const float v2[2], const float v3[2])
int isect_seg_seg_v2_point(const float v0[2], const float v1[2], const float v2[2], const float v3[2], float r_vi[2])
float normal_tri_v3(float n[3], const float v1[3], const float v2[3], const float v3[3])
Definition math_geom.cc:39
bool isect_axial_line_segment_tri_v3(const int axis, const float p1[3], const float p2[3], const float v0[3], const float v1[3], const float v2[3], float *r_lambda)
bool isect_line_segment_tri_v3(const float p1[3], const float p2[3], const float v0[3], const float v1[3], const float v2[3], float *r_lambda, float r_uv[2])
float area_quad_v3(const float v1[3], const float v2[3], const float v3[3], const float v4[3])
Definition math_geom.cc:83
float dist_signed_squared_to_plane3_v3(const float p[3], const float plane[3])
Definition math_geom.cc:477
void interp_weights_poly_v3(float *w, float v[][3], const int n, const float co[3])
float dist_to_line_v2(const float p[2], const float l1[2], const float l2[2])
Definition math_geom.cc:284
void plane_to_point_vector_v3_normalized(const float plane[4], float r_plane_co[3], float r_plane_no[3])
Definition math_geom.cc:227
int isect_aabb_planes_v3(const float(*planes)[4], const int totplane, const float bbmin[3], const float bbmax[3])
void interp_bilinear_quad_v3(float data[4][3], float u, float v, float res[3])
bool isect_point_planes_v3_negated(const float(*planes)[4], const int totplane, const float p[3])
void planes_from_projmat(const float mat[4][4], float left[4], float right[4], float bottom[4], float top[4], float near[4], float far[4])
bool isect_point_tri_prism_v3(const float p[3], const float v1[3], const float v2[3], const float v3[3])
void map_to_plane_axis_angle_v2_v3v3fl(float r_co[2], const float co[3], const float axis[3], const float angle)
bool isect_ray_plane_v3(const float ray_origin[3], const float ray_direction[3], const float plane[4], float *r_lambda, const bool clip)
float volume_tetrahedron_v3(const float v1[3], const float v2[3], const float v3[3], const float v4[3])
Definition math_geom.cc:237
float dist_squared_to_line_segment_v2(const float p[2], const float l1[2], const float l2[2])
Definition math_geom.cc:289
void box_minmax_bounds_m4(float min[3], float max[3], float boundbox[2][3], float mat[4][4])
static float snap_coordinate(float u)
float dist_signed_squared_to_corner_v3v3v3(const float p[3], const float v1[3], const float v2[3], const float v3[3], const float axis_ref[3])
Definition math_geom.cc:544
static int left
double epsilon
default precision while comparing with Equal(..,..) functions. Initialized at 0.0000001.
Definition utility.cpp:22
float safe_acos_approx(float x)
Frequency::GEOMETRY nor[]
const btScalar eps
Definition poly34.cpp:11
return ret
#define min(a, b)
Definition sort.c:32
#define FLT_MAX
Definition stdcycles.h:14
double dir[2]
float dir[3]
float max
ccl_device_inline float xor_signmask(float x, int y)
Definition util/math.h:838
uint8_t flag
Definition wm_window.cc:138