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
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
293 closest_to_line_segment_v2(closest, p, l1, l2);
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
521 closest_to_line_segment_v3(closest, p, l1, l2);
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/* -------------------------------------------------------------------- */
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
800/* -------------------------------------------------------------------- */
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
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/* -------------------------------------------------------------------- */
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
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/* -------------------------------------------------------------------- */
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
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{
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]
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
local_group_size(16, 16) .push_constant(Type b
additional_info("compositor_sum_squared_difference_float_shared") .push_constant(Type output_img float dot(value.rgb, luminance_coefficients)") .define("LOAD(value)"
#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
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