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