GCC Code Coverage Report


Directory: ./
File: lib/geogram/basic/geometry.h
Date: 2026-09-07 02:37:58
Exec Total Coverage
Lines: 64 118 54.2%
Functions: 14 29 48.3%
Branches: 14 34 41.2%

Line Branch Exec Source
1 /*
2 * Copyright (c) 2000-2022 Inria
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * * Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * * Neither the name of the ALICE Project-Team nor the names of its
14 * contributors may be used to endorse or promote products derived from this
15 * software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
28 *
29 * Contact: Bruno Levy
30 *
31 * https://www.inria.fr/fr/bruno-levy
32 *
33 * Inria,
34 * Domaine de Voluceau,
35 * 78150 Le Chesnay - Rocquencourt
36 * FRANCE
37 *
38 */
39
40 #ifndef GEOGRAM_BASIC_GEOMETRY
41 #define GEOGRAM_BASIC_GEOMETRY
42
43 #include <geogram/basic/common.h>
44 #include <geogram/basic/matrix.h>
45
46 /**
47 * \file geogram/basic/geometry.h
48 * \brief Geometric functions in 2d and 3d
49 */
50
51 namespace GEO {
52
53 /************************************************************************/
54
55 /**
56 * \brief Represents points and vectors in 2d.
57 * \details Syntax is (mostly) compatible with GLSL.
58 */
59 typedef vecng<2, Numeric::float64> vec2;
60
61 /**
62 * \brief Represents points and vectors in 3d.
63 * \details Syntax is (mostly) compatible with GLSL.
64 */
65 typedef vecng<3, Numeric::float64> vec3;
66
67 /**
68 * \brief Represents points and vectors in 4d.
69 * \details Syntax is (mostly) compatible with GLSL.
70 */
71 typedef vecng<4, Numeric::float64> vec4;
72
73 /**
74 * \brief Represents points and vectors in 2d with
75 * single-precision coordinates.
76 * \details Syntax is (mostly) compatible with GLSL.
77 */
78 typedef vecng<2, Numeric::float32> vec2f;
79
80 /**
81 * \brief Represents points and vectors in 3d with
82 * single-precision coordinates.
83 * \details Syntax is (mostly) compatible with GLSL.
84 */
85 typedef vecng<3, Numeric::float32> vec3f;
86
87 /**
88 * \brief Represents points and vectors in 4d with
89 * single-precision coordinates.
90 * \details Syntax is (mostly) compatible with GLSL.
91 */
92 typedef vecng<4, Numeric::float32> vec4f;
93
94
95 /**
96 * \brief Represents points and vectors in 2d with
97 * integer coordinates.
98 * \details Syntax is (mostly) compatible with GLSL.
99 */
100 typedef vecng<2, Numeric::int32> vec2i;
101
102 /**
103 * \brief Represents points and vectors in 3d with
104 * integer coordinates.
105 * \details Syntax is (mostly) compatible with GLSL.
106 */
107 typedef vecng<3, Numeric::int32> vec3i;
108
109 /**
110 * \brief Represents points and vectors in 4d with
111 * integer coordinates.
112 * \details Syntax is (mostly) compatible with GLSL.
113 */
114 typedef vecng<4, Numeric::int32> vec4i;
115
116 /**
117 * \brief Represents points and vectors in 2d with
118 * unsigned integer coordinates.
119 * \details Syntax is (mostly) compatible with GLSL.
120 */
121 typedef vecng<2, Numeric::uint32> vec2u;
122
123 /**
124 * \brief Represents points and vectors in 3d with
125 * unsigned integer coordinates.
126 * \details Syntax is (mostly) compatible with GLSL.
127 */
128 typedef vecng<3, Numeric::uint32> vec3u;
129
130 /**
131 * \brief Represents points and vectors in 4d with
132 * unsigned integer coordinates.
133 * \details Syntax is (mostly) compatible with GLSL.
134 */
135 typedef vecng<4, Numeric::uint32> vec4u;
136
137 /**
138 * \brief Represents a 2x2 matrix.
139 * \details Syntax is (mostly) compatible with GLSL.
140 */
141 typedef Matrix<2, Numeric::float64> mat2;
142
143 /**
144 * \brief Represents a 3x3 matrix.
145 * \details Syntax is (mostly) compatible with GLSL.
146 */
147 typedef Matrix<3, Numeric::float64> mat3;
148
149 /**
150 * \brief Represents a 4x4 matrix.
151 * \details Syntax is (mostly) compatible with GLSL.
152 */
153 typedef Matrix<4, Numeric::float64> mat4;
154
155 /************************************************************************/
156
157 /**
158 * \brief Computes the determinant of a 2x2 matrix
159 * \param[in] M a const reference to the matrix
160 * \return the determinant
161 */
162 inline double det(const mat2& M) {
163 return det2x2(
164 M(0,0), M(0,1),
165 M(1,0), M(1,1)
166 );
167 }
168
169 /**
170 * \brief Computes the determinant of a 3x3 matrix
171 * \param[in] M a const reference to the matrix
172 * \return the determinant
173 */
174 inline double det(const mat3& M) {
175 return det3x3(
176 M(0,0), M(0,1), M(0,2),
177 M(1,0), M(1,1), M(1,2),
178 M(2,0), M(2,1), M(2,2)
179 );
180 }
181
182 /**
183 * \brief Computes the determinant of a 4x4 matrix
184 * \param[in] M a const reference to the matrix
185 * \return the determinant
186 */
187 258 inline double det(const mat4& M) {
188 258 return det4x4(
189 M(0,0), M(0,1), M(0,2), M(0,3),
190 M(1,0), M(1,1), M(1,2), M(1,3),
191 M(2,0), M(2,1), M(2,2), M(2,3),
192 M(3,0), M(3,1), M(3,2), M(3,3)
193 258 );
194 }
195
196 /************************************************************************/
197
198 /**
199 * \brief Geometric functions and utilities.
200 */
201 namespace Geom {
202
203 /**
204 * \brief Computes the barycenter of two points in 3d.
205 * \param[in] p1 first point
206 * \param[in] p2 second point
207 * \return the barycenter of \p p1 and \p p2
208 */
209 inline vec3 barycenter(const vec3& p1, const vec3& p2) {
210 return vec3(
211 0.5 * (p1.x + p2.x),
212 0.5 * (p1.y + p2.y),
213 0.5 * (p1.z + p2.z)
214 );
215 }
216
217 /**
218 * \brief Computes the barycenter of two points in 2d.
219 * \param[in] p1 first point
220 * \param[in] p2 second point
221 * \return the barycenter of \p p1 and \p p2
222 */
223 inline vec2 barycenter(const vec2& p1, const vec2& p2) {
224 return vec2(
225 0.5 * (p1.x + p2.x),
226 0.5 * (p1.y + p2.y)
227 );
228 }
229
230 /**
231 * \brief Computes the barycenter of three points in 3d.
232 * \param[in] p1 first point
233 * \param[in] p2 second point
234 * \param[in] p3 third point
235 * \return the barycenter of \p p1, \p p2 and \p p3
236 */
237 inline vec3 barycenter(
238 const vec3& p1, const vec3& p2, const vec3& p3
239 ) {
240 return vec3(
241 (p1.x + p2.x + p3.x) / 3.0,
242 (p1.y + p2.y + p3.y) / 3.0,
243 (p1.z + p2.z + p3.z) / 3.0
244 );
245 }
246
247 /**
248 * \brief Computes the barycenter of three points in 2d.
249 * \param[in] p1 first point
250 * \param[in] p2 second point
251 * \param[in] p3 third point
252 * \return the barycenter of \p p1, \p p2 and \p p3
253 */
254 inline vec2 barycenter(
255 const vec2& p1, const vec2& p2, const vec2& p3
256 ) {
257 return vec2(
258 (p1.x + p2.x + p3.x) / 3.0,
259 (p1.y + p2.y + p3.y) / 3.0
260 );
261 }
262
263 /**
264 * \brief Computes the cosine of the angle between two 3d vectors.
265 * \param[in] a first vector
266 * \param[in] b second vector
267 * \return the cosine of the angle between \p a and \p b
268 */
269 inline double cos_angle(const vec3& a, const vec3& b) {
270 double lab = ::sqrt(length2(a)*length2(b));
271 double result = (lab > 1e-50) ? (dot(a, b) / lab) : 1.0;
272 // Numerical precision problem may occur, and generate
273 // normalized dot products that are outside the valid
274 // range of acos.
275 geo_clamp(result, -1.0, 1.0);
276 return result;
277 }
278
279 /**
280 * \brief Computes the angle between two 3d vectors.
281 * \param[in] a first vector
282 * \param[in] b second vector
283 * \return the angle between \p a and \p b in radians, in
284 * the interval \f$ [ 0 \ldots \pi ] \f$.
285 */
286 inline double angle(const vec3& a, const vec3& b) {
287 return ::acos(cos_angle(a, b));
288 }
289
290 /**
291 * \brief Computes the cosine of the angle between two 2d vectors.
292 * \param[in] a first vector
293 * \param[in] b second vector
294 * \return the cosine of the angle between \p a and \p b
295 */
296 inline double cos_angle(const vec2& a, const vec2& b) {
297 double lab = ::sqrt(length2(a)*length2(b));
298 double result = (lab > 1e-20) ? (dot(a, b) / lab) : 1.0;
299 // Numerical precision problem may occur, and generate
300 // normalized dot products that are outside the valid
301 // range of acos.
302 geo_clamp(result, -1.0, 1.0);
303 return result;
304 }
305
306 /**
307 * \brief Computes the determinant of two vectors.
308 * \param[in] a first vector
309 * \param[in] b second vector
310 * \return the determinant of \p a and \p b
311 */
312 inline double det(const vec2& a, const vec2& b) {
313 return a.x * b.y - a.y * b.x;
314 }
315
316 /**
317 * \brief Computes the angle between two 2d vectors.
318 * \param[in] a first vector
319 * \param[in] b second vector
320 * \return the angle between \a and \b in radians,
321 * in the interval \f$ [-\pi \ldots \pi] \f$
322 */
323 inline double angle(const vec2& a, const vec2& b) {
324 return det(a, b) > 0 ?
325 ::acos(cos_angle(a, b)) :
326 -::acos(cos_angle(a, b));
327 }
328
329 /**
330 * \brief Computes the normal of a 3d triangle
331 * \param[in] p1 , p2 , p3 the three vertices of the
332 * triangle
333 * \return the normal of the triangle (\p p1, \p p2, \p p3).
334 */
335 inline vec3 triangle_normal(
336 const vec3& p1, const vec3& p2, const vec3& p3
337 ) {
338 return cross(p2 - p1, p3 - p1);
339 }
340
341 /**
342 * \brief Computes the area of a 3d triangle
343 * \param[in] p1 , p2 , p3 the three vertices of the triangle
344 * \return the area of the triangle (\p p1, \p p2, \p p3).
345 */
346 295855 inline double triangle_area_3d(
347 const double* p1, const double* p2, const double* p3
348 ) {
349 295855 double Ux = p2[0] - p1[0];
350 295855 double Uy = p2[1] - p1[1];
351 295855 double Uz = p2[2] - p1[2];
352
353 295855 double Vx = p3[0] - p1[0];
354 295855 double Vy = p3[1] - p1[1];
355 295855 double Vz = p3[2] - p1[2];
356
357 295855 double Nx = Uy*Vz - Uz*Vy;
358 295855 double Ny = Uz*Vx - Ux*Vz;
359 295855 double Nz = Ux*Vy - Uy*Vx;
360 295855 return 0.5 * ::sqrt(Nx*Nx+Ny*Ny+Nz*Nz);
361 }
362
363 /**
364 * \brief Computes the area of a 3d triangle
365 * \param[in] p1 , p2 , p3 the three vertices of the triangle
366 * \return the area of the triangle (\p p1, \p p2, \p p3).
367 */
368 295855 inline double triangle_area(
369 const vec3& p1, const vec3& p2, const vec3& p3
370 ) {
371 295855 return triangle_area_3d(p1.data(), p2.data(), p3.data());
372 }
373
374 /**
375 * \brief Computes the area of a 2d triangle
376 * \param[in] p1 first vertex of the triangle
377 * \param[in] p2 second vertex of the triangle
378 * \param[in] p3 third vertex of the triangle
379 * \return the signed area of the 2D triangle (\p p1, \p p2, \p p3),
380 * positive if the triangle is oriented clockwise, negative otherwise.
381 */
382 inline double triangle_signed_area_2d(
383 const double* p1, const double* p2, const double* p3
384 ) {
385 double a = p2[0]-p1[0];
386 double b = p3[0]-p1[0];
387 double c = p2[1]-p1[1];
388 double d = p3[1]-p1[1];
389 return 0.5*(a*d-b*c);
390 }
391
392 /**
393 * \brief Computes the area of a 2d triangle
394 * \param[in] p1 first vertex of the triangle
395 * \param[in] p2 second vertex of the triangle
396 * \param[in] p3 third vertex of the triangle
397 * \return the signed area of the triangle (\p p1, \p p2, \p p3),
398 * positive if the triangle is oriented clockwise, negative otherwise.
399 */
400 inline double triangle_signed_area(
401 const vec2& p1, const vec2& p2, const vec2& p3
402 ) {
403 return 0.5 * det(p2 - p1, p3 - p1);
404 }
405
406 /**
407 * \brief Computes the area of a 2d triangle
408 * \param[in] p1 first vertex of the triangle
409 * \param[in] p2 second vertex of the triangle
410 * \param[in] p3 third vertex of the triangle
411 * \return the area of the triangle (\p p1, \p p2, \p p3).
412 */
413 inline double triangle_area(
414 const vec2& p1, const vec2& p2, const vec2& p3
415 ) {
416 return ::fabs(triangle_signed_area(p1, p2, p3));
417 }
418
419 /**
420 * \brief Computes the area of a 2d triangle
421 * \param[in] p1 first vertex of the triangle
422 * \param[in] p2 second vertex of the triangle
423 * \param[in] p3 third vertex of the triangle
424 * \return the area of the triangle (\p p1, \p p2, \p p3).
425 */
426 inline double triangle_area_2d(
427 const double* p1, const double* p2, const double* p3
428 ) {
429 return ::fabs(triangle_signed_area_2d(p1,p2,p3));
430 }
431
432 /**
433 * \brief Computes the center of the circumscribed circle of
434 * a 2d triangle.
435 * \param[in] p1 first vertex of the triangle
436 * \param[in] p2 second vertex of the triangle
437 * \param[in] p3 third vertex of the triangle
438 * \return the circumcenter of the triangle (\p p1, \p p2, \p p3).
439 */
440 vec2 GEOGRAM_API triangle_circumcenter(
441 const vec2& p1, const vec2& p2, const vec2& p3
442 );
443
444 /**
445 * \brief Tests whether a 3d vector has a NaN (not a number) coordinate.
446 * \param[in] v a 3d vector
447 * \return true if one of the coordinates is a NaN, false otherwise
448 */
449 inline bool has_nan(const vec3& v) {
450 return
451 Numeric::is_nan(v.x) ||
452 Numeric::is_nan(v.y) ||
453 Numeric::is_nan(v.z);
454 }
455
456 /**
457 * \brief Tests whether a 2d vector has a NaN (not a number) coordinate.
458 * \param[in] v a 2d vector
459 * \return true if one of the coordinates is a NaN, false otherwise
460 */
461 inline bool has_nan(const vec2& v) {
462 return
463 Numeric::is_nan(v.x) ||
464 Numeric::is_nan(v.y);
465 }
466
467 /**
468 * \brief Computes a 3d vector orthogonal to another one.
469 * \param[in] V a 3d vector
470 * \return a 3d vector orthogonal to \p V
471 */
472 vec3 GEOGRAM_API perpendicular(const vec3& V);
473
474 /**
475 * \brief Computes the signed volume of a 3d tetrahedron
476 * \param[in] p1 first vertex of the tetrahedron
477 * \param[in] p2 second vertex of the tetrahedron
478 * \param[in] p3 third vertex of the tetrahedron
479 * \param[in] p4 fourth vertex of the tetrahedron
480 * \return the signed volume of the tetrahedron
481 * (\p p1, \p p2, \p p3, \p p4)
482 */
483 1224497 inline double tetra_signed_volume(
484 const vec3& p1, const vec3& p2,
485 const vec3& p3, const vec3& p4
486 ) {
487 1224497 return dot(p2 - p1, cross(p3 - p1, p4 - p1)) / 6.0;
488 }
489
490 /**
491 * \brief Computes the signed volume of a 3d tetrahedron
492 * \param[in] p1 first vertex of the tetrahedron
493 * \param[in] p2 second vertex of the tetrahedron
494 * \param[in] p3 third vertex of the tetrahedron
495 * \param[in] p4 fourth vertex of the tetrahedron
496 * \return the signed volume of the tetrahedron
497 * (\p p1, \p p2, \p p3, \p p4)
498 */
499 inline double tetra_signed_volume(
500 const double* p1, const double* p2,
501 const double* p3, const double* p4
502 ) {
503 return tetra_signed_volume(
504 *reinterpret_cast<const vec3*>(p1),
505 *reinterpret_cast<const vec3*>(p2),
506 *reinterpret_cast<const vec3*>(p3),
507 *reinterpret_cast<const vec3*>(p4)
508 );
509 }
510
511 /**
512 * \brief Computes the volume of a 3d tetrahedron
513 * \param[in] p1 first vertex of the tetrahedron
514 * \param[in] p2 second vertex of the tetrahedron
515 * \param[in] p3 third vertex of the tetrahedron
516 * \param[in] p4 fourth vertex of the tetrahedron
517 * \return the volume of the tetrahedron
518 * (\p p1, \p p2, \p p3, \p p4)
519 */
520 1175935 inline double tetra_volume(
521 const vec3& p1, const vec3& p2,
522 const vec3& p3, const vec3& p4
523 ) {
524 1175935 return ::fabs(tetra_signed_volume(p1, p2, p3, p4));
525 }
526
527 /**
528 * \brief Computes the center of the circumscribed sphere
529 * of 3d tetrahedron
530 * \param[in] p1 first vertex of the tetrahedron
531 * \param[in] p2 second vertex of the tetrahedron
532 * \param[in] p3 third vertex of the tetrahedron
533 * \param[in] p4 fourth vertex of the tetrahedron
534 * \return the circumcenter of the tetrahedron
535 * (\p p1, \p p2, \p p3, \p p4)
536 */
537 vec3 GEOGRAM_API tetra_circum_center(
538 const vec3& p1, const vec3& p2,
539 const vec3& p3, const vec3& p4
540 );
541
542 /**
543 * \brief Computes the centroid of a 3d triangle with weighted points.
544 * \details The integrated weight varies linearly in the triangle.
545 * \param[in] p first vertex of the triangle
546 * \param[in] q second vertex of the triangle
547 * \param[in] r third vertex of the triangle
548 * \param[in] a the weight associated with vertex \p p
549 * \param[in] b the weight associated with vertex \p q
550 * \param[in] c the weight associated with vertex \p r
551 * \param[out] Vg the total weight times the centroid
552 * \param[out] V the total weight
553 */
554 inline void triangle_centroid(
555 const vec3& p, const vec3& q, const vec3& r,
556 double a, double b, double c,
557 vec3& Vg, double& V
558 ) {
559 double abc = a + b + c;
560 double area = Geom::triangle_area(p, q, r);
561 V = area / 3.0 * abc;
562 double wp = a + abc;
563 double wq = b + abc;
564 double wr = c + abc;
565 double s = area / 12.0;
566 Vg.x = s * (wp * p.x + wq * q.x + wr * r.x);
567 Vg.y = s * (wp * p.y + wq * q.y + wr * r.y);
568 Vg.z = s * (wp * p.z + wq * q.z + wr * r.z);
569 }
570
571 /**
572 * \brief Computes the mass of a 3d triangle with weighted points.
573 * \details The integrated weight varies linearly in the triangle.
574 * \param[in] p first vertex of the triangle
575 * \param[in] q second vertex of the triangle
576 * \param[in] r third vertex of the triangle
577 * \param[in] a the weight associated with vertex \p p
578 * \param[in] b the weight associated with vertex \p q
579 * \param[in] c the weight associated with vertex \p r
580 * \return the mass of the weighted triangle ( \p p, \p a),
581 * ( \p q, \p b), ( \p r, \p c)
582 */
583 inline double triangle_mass(
584 const vec3& p, const vec3& q, const vec3& r,
585 double a, double b, double c
586 ) {
587 return Geom::triangle_area(p, q, r) / 3.0 * (
588 sqrt(::fabs(a)) + sqrt(::fabs(b)) + sqrt(::fabs(c))
589 );
590 }
591
592 /**
593 * \brief Generates a random point in a 3d triangle.
594 * \details Uses Greg Turk's second method.
595 * Reference: Greg Turk, Generating Random Points
596 * in Triangles, Graphics Gems, p. 24-28, code: p. 649-650.
597 * \param[in] p1 first vertex of the triangle
598 * \param[in] p2 second vertex of the triangle
599 * \param[in] p3 third vertex of the triangle
600 * \return a random point in triangle ( \p p1, \p p2, \p p3 )
601 */
602 876296 inline vec3 random_point_in_triangle(
603 const vec3& p1,
604 const vec3& p2,
605 const vec3& p3
606 ) {
607 876296 double s = Numeric::random_float64();
608 876296 double t = Numeric::random_float64();
609
2/2
✓ Branch 0 taken 438007 times.
✓ Branch 1 taken 438289 times.
876296 if(s + t > 1) {
610 438007 s = 1.0 - s;
611 438007 t = 1.0 - t;
612 }
613 876296 double u = 1.0 - s - t;
614 return vec3(
615 1752592 u * p1.x + s * p2.x + t * p3.x,
616 1752592 u * p1.y + s * p2.y + t * p3.y,
617 876296 u * p1.z + s * p2.z + t * p3.z
618 876296 );
619 }
620 }
621
622 /**
623 * \brief A 3D Plane.
624 * \details The plane is represented by the coefficients
625 * a,b,c,d of its equation \f$ ax + by + cz + d = 0 \f$.
626 */
627 struct Plane {
628
629 /**
630 * \brief Constructs the plane passing through three points.
631 * \param[in] p1 first point
632 * \param[in] p2 second point
633 * \param[in] p3 third point
634 */
635 Plane(const vec3& p1, const vec3& p2, const vec3& p3) {
636 vec3 n = cross(p2 - p1, p3 - p1);
637 a = n.x;
638 b = n.y;
639 c = n.z;
640 d = -(a * p1.x + b * p1.y + c * p1.z);
641 }
642
643 /**
644 * \brief Constructs a plane passign through a point and orthogonal
645 * to a vector.
646 * \param[in] p the point
647 * \param[in] n the vector
648 */
649 Plane(const vec3& p, const vec3& n) {
650 a = n.x;
651 b = n.y;
652 c = n.z;
653 d = -(a * p.x + b * p.y + c * p.z);
654 }
655
656 /**
657 * \brief Constructs a plane from the coefficients of its equation.
658 */
659 Plane(
660 double a_in, double b_in, double c_in, double d_in
661 ) :
662 a(a_in),
663 b(b_in),
664 c(c_in),
665 d(d_in) {
666 }
667
668 /**
669 * \brief Constructs an uninitialized plane.
670 */
671 Plane() {
672 }
673
674 /**
675 * \brief Gets the normal vector of the plane.
676 */
677 vec3 normal() const {
678 return vec3(a, b, c);
679 }
680
681 double a, b, c, d;
682 };
683
684 /*******************************************************************/
685
686 /**
687 * \brief Axis-aligned bounding box.
688 */
689 class Box {
690 public:
691 double xyz_min[3];
692 double xyz_max[3];
693
694 /**
695 * \brief Constructs an uninitialized box
696 */
697 645624 Box() {
698 645624 }
699
700 /**
701 * \brief Constructs a box from lower and upper bounds
702 * \param[in] x1 , y1 , z1 the lower bounds
703 * \param[in] x2 , y2 , z2 the upper bounds
704 */
705 170132 Box(double x1, double y1, double z1, double x2, double y2, double z2) {
706 170132 xyz_min[0] = x1;
707 170132 xyz_min[1] = y1;
708 170132 xyz_min[2] = z1;
709 170132 xyz_max[0] = x2;
710 170132 xyz_max[1] = y2;
711 170132 xyz_max[2] = z2;
712 170132 }
713
714 /**
715 * \brief Constructs a box from lower and upper bounds
716 * \param[in] lo the lower bound as a vec3
717 * \param[in] hi the upper bound as a vec3
718 */
719 Box(const vec3& lo, const vec3& hi) {
720 xyz_min[0] = lo.x;
721 xyz_min[1] = lo.y;
722 xyz_min[2] = lo.z;
723 xyz_max[0] = hi.x;
724 xyz_max[1] = hi.y;
725 xyz_max[2] = hi.z;
726 }
727
728 /**
729 * \brief Gets the lower bounds
730 * \return the lower bounds as a vec3
731 */
732 4 vec3 lo() const {
733 4 return vec3(xyz_min);
734 }
735
736 /**
737 * \brief Gets the higher bounds
738 * \return the higher bounds as a vec3
739 */
740 4 vec3 hi() const {
741 4 return vec3(xyz_max);
742 }
743
744 /**
745 * \brief Tests whether a box contains a point.
746 * \param[in] b the point
747 * \return true if this box contains \p b, false otherwise
748 */
749 15261388 bool contains(const vec3& b) const {
750
2/2
✓ Branch 0 taken 45784164 times.
✓ Branch 1 taken 15261388 times.
61045552 for(coord_index_t c = 0; c < 3; ++c) {
751
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 45784164 times.
45784164 if(b[c] < xyz_min[c]) {
752 return false;
753 }
754
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 45784164 times.
45784164 if(b[c] > xyz_max[c]) {
755 return false;
756 }
757 }
758 15261388 return true;
759 }
760
761 /**
762 * \brief Enlarges the box
763 * \param[in] d the amount that should be subtracted from the lower
764 * bounds and added to the upper bounds
765 */
766 void enlarge(double d) {
767 xyz_min[0] -= d;
768 xyz_min[1] -= d;
769 xyz_min[2] -= d;
770 xyz_max[0] += d;
771 xyz_max[1] += d;
772 xyz_max[2] += d;
773 }
774
775 };
776
777 typedef Box Box3d;
778
779 /**
780 * \brief Tests whether two Boxes have a non-empty intersection.
781 * \param[in] B1 first box
782 * \param[in] B2 second box
783 * \return true if \p B1 and \p B2 have a non-empty intersection,
784 * false otherwise.
785 */
786 5390487 inline bool bboxes_overlap(const Box& B1, const Box& B2) {
787
2/2
✓ Branch 0 taken 13944550 times.
✓ Branch 1 taken 3762467 times.
17707017 for(coord_index_t c = 0; c < 3; ++c) {
788
2/2
✓ Branch 0 taken 1138864 times.
✓ Branch 1 taken 12805686 times.
13944550 if(B1.xyz_max[c] < B2.xyz_min[c]) {
789 1138864 return false;
790 }
791
2/2
✓ Branch 0 taken 489156 times.
✓ Branch 1 taken 12316530 times.
12805686 if(B1.xyz_min[c] > B2.xyz_max[c]) {
792 489156 return false;
793 }
794 }
795 3762467 return true;
796 }
797
798 /**
799 * \brief Computes the smallest Box that encloses two Boxes.
800 * \param[out] target the smallest axis-aligned box
801 * that encloses \p B1 and \p B2
802 * \param[in] B1 first box
803 * \param[in] B2 second box
804 */
805 204648 inline void bbox_union(Box& target, const Box& B1, const Box& B2) {
806
2/2
✓ Branch 0 taken 613944 times.
✓ Branch 1 taken 204648 times.
818592 for(coord_index_t c = 0; c < 3; ++c) {
807 613944 target.xyz_min[c] = std::min(B1.xyz_min[c], B2.xyz_min[c]);
808 613944 target.xyz_max[c] = std::max(B1.xyz_max[c], B2.xyz_max[c]);
809 }
810 204648 }
811
812 /*******************************************************************/
813
814 /**
815 * \brief Axis-aligned bounding box.
816 */
817 class Box2d {
818 public:
819 double xy_min[2];
820 double xy_max[2];
821
822 /**
823 * \brief Constructs an uninitialized Box2d
824 */
825 Box2d() {
826 }
827
828 /**
829 * \brief Constructs a box from lower and upper bounds
830 * \param[in] x1 , y1 the lower bounds
831 * \param[in] x2 , y2 the upper bounds
832 */
833 Box2d(double x1, double y1, double x2, double y2) {
834 xy_min[0] = x1;
835 xy_min[1] = y1;
836 xy_max[0] = x2;
837 xy_max[1] = y2;
838 }
839
840 /**
841 * \brief Constructs a box from lower and upper bounds
842 * \param[in] lo the lower bound as a vec2
843 * \param[in] hi the upper bound as a vec2
844 */
845 Box2d(const vec2& lo, const vec2& hi) {
846 xy_min[0] = lo.x;
847 xy_min[1] = lo.y;
848 xy_max[0] = hi.x;
849 xy_max[1] = hi.y;
850 }
851
852 /**
853 * \brief Gets the lower bounds
854 * \return the lower bounds as a vec2
855 */
856 vec2 lo() const {
857 return vec2(xy_min);
858 }
859
860 /**
861 * \brief Gets the higher bounds
862 * \return the higher bounds as a vec2
863 */
864 vec2 hi() const {
865 return vec2(xy_max);
866 }
867
868 /**
869 * \brief Tests whether a box contains a point.
870 * \param[in] b the point
871 * \return true if this box contains \p b, false otherwise
872 */
873 bool contains(const vec2& b) const {
874 for(coord_index_t c = 0; c < 2; ++c) {
875 if(b[c] < xy_min[c]) {
876 return false;
877 }
878 if(b[c] > xy_max[c]) {
879 return false;
880 }
881 }
882 return true;
883 }
884
885 /**
886 * \brief Enlarges the box
887 * \param[in] d the amount that should be subtracted from the lower
888 * bounds and added to the upper bounds
889 */
890 void enlarge(double d) {
891 xy_min[0] -= d;
892 xy_min[1] -= d;
893 xy_max[0] += d;
894 xy_max[1] += d;
895 }
896 };
897
898
899 /**
900 * \brief Tests whether two Box2d have a non-empty intersection.
901 * \param[in] B1 first box
902 * \param[in] B2 second box
903 * \return true if \p B1 and \p B2 have a non-empty intersection,
904 * false otherwise.
905 */
906 inline bool bboxes_overlap(const Box2d& B1, const Box2d& B2) {
907 for(coord_index_t c = 0; c < 2; ++c) {
908 if(B1.xy_max[c] < B2.xy_min[c]) {
909 return false;
910 }
911 if(B1.xy_min[c] > B2.xy_max[c]) {
912 return false;
913 }
914 }
915 return true;
916 }
917
918 /**
919 * \brief Computes the smallest Box2d that encloses two Box2d.
920 * \param[out] target the smallest axis-aligned box
921 * that encloses \p B1 and \p B2
922 * \param[in] B1 first box
923 * \param[in] B2 second box
924 */
925 inline void bbox_union(Box2d& target, const Box2d& B1, const Box2d& B2) {
926 for(coord_index_t c = 0; c < 2; ++c) {
927 target.xy_min[c] = std::min(B1.xy_min[c], B2.xy_min[c]);
928 target.xy_max[c] = std::max(B1.xy_max[c], B2.xy_max[c]);
929 }
930 }
931
932 /*******************************************************************/
933
934 #ifndef GOMGEN
935
936 /**
937 * \brief Applies a 3d transform to a 3d vector.
938 * \details Convention is the same as in OpenGL, i.e.
939 * vector is a row vector, multiplied on the left
940 * of the transform.
941 * Internally, the vector is converted into
942 * a 4d vector, with w coordinate set to zero.
943 * \param[in] v the input 3d vector to be transformed
944 * \param[in] M the transform, as a 4x4 matrix, using
945 * homogeneous coordinates
946 * \tparam FT type of the coordinates
947 * \return the transformed 3d vector
948 */
949 template <class FT> [[deprecated("use operators and vec3/4 conversions")]]
950 inline vecng<3,FT> transform_vector(
951 const vecng<3,FT>& v, const Matrix<4,FT>& M
952 ) {
953 return vecng<3,FT>( vecng<4,FT>(v,FT(0.0)) * M );
954 }
955
956 /**
957 * \brief Applies a 3d transform to a 3d point.
958 * \details Convention is the same as in OpenGL, i.e.
959 * vector is a row vector, multiplied on the left
960 * of the transform.
961 * Internally, the point is converted into
962 * a 4d vector, with w coordinate set to one. Transformed
963 * coordinates are divided by the transformed w to form
964 * a 3d point.
965 * \param[in] p the input 3d point to be transformed
966 * \param[in] M the transform, as a 4x4 matrix, using
967 * homogeneous coordinates
968 * \tparam FT type of the coordinates
969 * \return the transformed 3d point
970 */
971 template <class FT> [[deprecated("use operators and vec3/4 conversions")]]
972 inline vecng<3,FT> transform_point(
973 const vecng<3,FT>& p, const Matrix<4,FT>& M
974 ) {
975 vecng<4,FT> q = vecng<4,FT>(p,FT(1.0)) * M;
976 return vecng<3,FT>(q.x/q.w, q.y/q.w, q.z/q.w);
977 }
978
979
980 /**
981 * \brief Applies a 3d transform to a 3d point.
982 * \details Convention is the same as in math, i.e.
983 * vector is a column vector, multiplied on the right
984 * of the transform.
985 * Internally, the point is converted into
986 * a 4d vector, with w coordinate set to one. Transformed
987 * coordinates are divided by the transformed w to form
988 * a 3d point.
989 * \param[in] p the input 3d point to be transformed
990 * \param[in] M the transform, as a 4x4 matrix, using
991 * homogeneous coordinates
992 * \tparam FT type of the coordinates
993 * \return the transformed 3d point
994 */
995 template <class FT> [[deprecated("use operators and vec3/4 conversions")]]
996 inline vecng<3,FT> transform_point(
997 const Matrix<4,FT>& M, const vecng<3,FT>& p
998 ) {
999 vecng<4,FT> q = M * vecng<4,FT>(p,FT(1.0));
1000 return vecng<3,FT>(q.x/q.w, q.y/q.w, q.z/q.w);
1001 }
1002
1003 /**
1004 * \brief Applies a 4d transform to a 4d vector.
1005 * \details Convention is the same as in OpenGL, i.e.
1006 * vector is a row vector, multiplied on the left
1007 * of the transform.
1008 * \param[in] v the input 4d vector to be transformed
1009 * \param[in] M the transform, as a 4x4 matrix
1010 * \tparam FT type of the coordinates
1011 * \return the transformed 4d vector
1012 */
1013 template <class FT> [[deprecated("use operators and vec3/4 conversions")]]
1014 inline vecng<4,FT> transform_vector(
1015 const vecng<4,FT>& v, const Matrix<4,FT>& M
1016 ) {
1017 return v*M;
1018 }
1019
1020 #endif
1021
1022 /******************************************************************/
1023
1024 /**
1025 * \brief Creates a translation matrix from a vector.
1026 * \details The translation matrix is in homogeneous coordinates,
1027 * with the same convention as OpenGL (transforms row vectors
1028 * mutliplied on the left).
1029 * \param[in] T a const reference to the translation vector
1030 * \return the translation matrix
1031 */
1032 inline mat4 create_translation_matrix(const vec3& T) {
1033 mat4 result;
1034 result.load_identity();
1035 result(3,0) = T.x;
1036 result(3,1) = T.y;
1037 result(3,2) = T.z;
1038 return result;
1039 }
1040
1041 /**
1042 * \brief Creates a scaling matrix.
1043 * \details The scaling matrix is in homogeneous coordinates,
1044 * with the same convention as OpenGL (transforms row vectors
1045 * mutliplied on the left).
1046 * \param[in] s the scaling coefficient
1047 * \return the scaling matrix
1048 */
1049 inline mat4 create_scaling_matrix(double s) {
1050 mat4 result;
1051 result.load_identity();
1052 result(0,0) = s;
1053 result(1,1) = s;
1054 result(2,2) = s;
1055 return result;
1056 }
1057
1058 /******************************************************************/
1059
1060 /**
1061 * \brief A Ray, in parametric form.
1062 */
1063 struct Ray {
1064 /**
1065 * \brief Ray constructor.
1066 * \param[in] O the origin of the ray.
1067 * \param[in] D the direction of the ray.
1068 */
1069 179996 Ray(vec3 O, vec3 D) : origin(O), direction(D) {
1070 179996 }
1071 /**
1072 * \brief Ray constructor.
1073 */
1074 Ray() {
1075 }
1076 vec3 origin;
1077 vec3 direction;
1078 };
1079
1080 /******************************************************************/
1081
1082 }
1083
1084 #endif
1085