GCC Code Coverage Report


Directory: ./
File: lib/geogram/basic/vechg.h
Date: 2026-09-07 02:28:19
Exec Total Coverage
Lines: 105 111 94.6%
Functions: 21 21 100.0%
Branches: 50 150 33.3%

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_VECHG
41 #define GEOGRAM_BASIC_VECHG
42
43 #include <geogram/basic/common.h>
44 #include <geogram/basic/vecg.h>
45 #include <geogram/basic/rationalg.h>
46
47 /**
48 * \file geogram/basic/vechg.h
49 * \brief Generic implementation of geometric vectors in homogeneous coordinates
50 */
51
52 namespace GEO {
53
54
55 /************************************************************************/
56
57 /**
58 * \brief 2d vector with homogeneous coordinates
59 */
60 template <class T> class vec2Hg {
61 public:
62 /** \brief The type of the vector coordinates */
63 typedef T value_type;
64
65 vec2Hg() = default;
66
67 869193 vec2Hg(const T& x_in, const T& y_in, const T& w_in) :
68 869193 x(x_in),
69 869193 y(y_in),
70 869193 w(w_in) {
71 869193 }
72
73 3127 vec2Hg(double x_in, double y_in, double w_in) :
74 x(x_in),
75 y(y_in),
76 w(w_in) {
77 3127 }
78
79 1063830 vec2Hg(T&& x_in, T&& y_in, T&& w_in) :
80 32568 x(x_in),
81 32568 y(y_in),
82 32568 w(w_in) {
83 32568 }
84
85 90781 vec2Hg(const vec2Hg& rhs) = default;
86
87 vec2Hg(vec2Hg&& rhs) = default;
88
89 32692 template <class T2> explicit vec2Hg(const vecng<2,T2>& rhs) :
90 32692 x(rhs.x),
91 32692 y(rhs.y),
92 w(1.0) {
93 32692 }
94
95 1375016 template <class T2> explicit vec2Hg(const vec2Hg<T2>& rhs) :
96 1375016 x(rhs.x),
97 1375016 y(rhs.y),
98 1375016 w(rhs.w) {
99 1375016 }
100
101 vec2Hg& operator=(const vec2Hg& rhs) = default;
102 vec2Hg& operator=(vec2Hg&& rhs) = default;
103
104 T* data() {
105 return &x;
106 }
107
108 const T* data() const {
109 return &x;
110 }
111
112 T& operator[](coord_index_t i) {
113 geo_debug_assert(i <= 2);
114 return data()[i];
115 }
116
117 const T& operator[](coord_index_t i) const {
118 geo_debug_assert(i <= 2);
119 return data()[i];
120 }
121
122 rationalg<T> cartesian(coord_index_t i) const {
123 geo_debug_assert(i < 2);
124 return rationalg<T>(data()[i], data()[2]);
125 }
126
127 108270 void optimize() {
128 Numeric::optimize_number_representation(x);
129 Numeric::optimize_number_representation(y);
130 Numeric::optimize_number_representation(w);
131 108270 }
132
133 T x;
134 T y;
135 T w;
136 };
137
138 /************************************************************************/
139
140 108432 template <class T> inline vec2Hg<T> operator-(
141 const vec2Hg<T>& p1, const vec2Hg<T>& p2
142 ) {
143
2/2
✓ Branch 0 taken 75945 times.
✓ Branch 1 taken 32487 times.
108432 if(p2.w == p1.w) {
144 return vec2Hg<T>(
145
2/6
✓ Branch 1 taken 75945 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 75945 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
151890 p1.x-p2.x,
146 75945 p1.y-p2.y,
147 75945 p1.w
148 75945 );
149 }
150 return vec2Hg<T>(
151
2/6
✓ Branch 1 taken 32487 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 32487 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
64974 det2x2(p1.x,p1.w,p2.x,p2.w),
152
2/6
✓ Branch 1 taken 32487 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 32487 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
64974 det2x2(p1.y,p1.w,p2.y,p2.w),
153 64974 p1.w*p2.w
154 32487 );
155 }
156
157 /************************************************************************/
158
159 /**
160 * \brief Comparator class for vec2Hg
161 * \detail Used to create maps indexed by vec2Hg or
162 * SOS symbolic perturbation
163 */
164 template <class T> class vec2HgLexicoCompare {
165 public:
166 /**
167 * \brief Compares two vec2Hg
168 * \retval true if \p v1 is before \p v2 in the lexicographic
169 * order
170 * \retval false otherwise
171 */
172 84379 bool operator()(const vec2Hg<T>& v1, const vec2Hg<T>& v2) const {
173 84379 Sign s = Numeric::ratio_compare(v2.x, v2.w, v1.x, v1.w);
174
2/2
✓ Branch 0 taken 62195 times.
✓ Branch 1 taken 22184 times.
84379 if(s == POSITIVE) {
175 return true;
176 }
177
2/2
✓ Branch 0 taken 23401 times.
✓ Branch 1 taken 38794 times.
62195 if(s == NEGATIVE) {
178 return false;
179 }
180 23401 s = Numeric::ratio_compare(v2.y, v2.w, v1.y, v1.w);
181 23401 return (s == POSITIVE);
182 }
183 };
184
185 /************************************************************************/
186
187 /**
188 * \brief 3d vector with homogeneous coordinates
189 */
190 template <class T> class vec3Hg {
191 public:
192 /** \brief The type of the vector coordinates */
193 typedef T value_type;
194
195 vec3Hg() = default;
196
197 427318 vec3Hg(const T& x_in, const T& y_in, const T& z_in, const T& w_in) :
198 427318 x(x_in),
199 427318 y(y_in),
200 427318 z(z_in),
201 427318 w(w_in) {
202 427318 }
203
204 382577 vec3Hg(T&& x_in, T&& y_in, T&& z_in, T&& w_in) :
205 311804 x(x_in),
206 311804 y(y_in),
207 311804 z(z_in),
208 311804 w(w_in) {
209 311804 }
210
211 787440 vec3Hg(double x_in, double y_in, double z_in, double w_in) :
212 x(x_in),
213 y(y_in),
214 z(z_in),
215 w(w_in) {
216 787440 }
217
218 540830 vec3Hg(const vec3Hg& rhs) = default;
219
220 24896 vec3Hg(vec3Hg&& rhs) = default;
221
222 68170 template <class T2> explicit vec3Hg(const vecng<3,T2>& rhs) :
223 68170 x(rhs.x),
224 68170 y(rhs.y),
225 68170 z(rhs.z),
226 w(1.0) {
227 68170 }
228
229 94364 template <class T2> explicit vec3Hg(const vec3Hg<T2>& rhs) :
230 94364 x(rhs.x),
231 94364 y(rhs.y),
232 94364 z(rhs.z),
233 94364 w(rhs.w) {
234 94364 }
235
236 292336 vec3Hg& operator=(const vec3Hg& rhs) = default;
237
4/8
✓ Branch 0 taken 4319 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4319 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4319 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 4319 times.
✗ Branch 7 not taken.
17276 vec3Hg& operator=(vec3Hg&& rhs) = default;
238
239 T* data() {
240 return &x;
241 }
242
243 const T* data() const {
244 13584469 return &x;
245 }
246
247 T& operator[](coord_index_t i) {
248 geo_debug_assert(i <= 3);
249 43476 return data()[i];
250 }
251
252 const T& operator[](coord_index_t i) const {
253 geo_debug_assert(i <= 3);
254 13314476 return data()[i];
255 }
256
257 rationalg<T> cartesian(coord_index_t i) const {
258 geo_debug_assert(i < 3);
259 return rationalg<T>(data()[i], data()[3]);
260 }
261
262 292336 void optimize() {
263 Numeric::optimize_number_representation(x);
264 Numeric::optimize_number_representation(y);
265 Numeric::optimize_number_representation(z);
266 Numeric::optimize_number_representation(w);
267 292336 }
268
269 T x;
270 T y;
271 T z;
272 T w;
273 };
274
275 /************************************************************************/
276
277 516321 template <class T> inline vec3Hg<T> operator-(
278 const vec3Hg<T>& p1, const vec3Hg<T>& p2
279 ) {
280
2/2
✓ Branch 0 taken 427318 times.
✓ Branch 1 taken 89003 times.
516321 if(p1.w == p2.w) {
281 return vec3Hg<T>(
282
2/6
✓ Branch 1 taken 427318 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 427318 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
854636 p1.x - p2.x,
283
2/6
✓ Branch 1 taken 427318 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 427318 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
854636 p1.y - p2.y,
284 427318 p1.z - p2.z,
285 427318 p1.w
286 427318 );
287 }
288 return vec3Hg<T>(
289
2/6
✓ Branch 1 taken 89003 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 89003 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
178006 det2x2(p1.x,p1.w,p2.x,p2.w),
290
2/6
✓ Branch 1 taken 89003 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 89003 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
178006 det2x2(p1.y,p1.w,p2.y,p2.w),
291
2/6
✓ Branch 1 taken 89003 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 89003 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
178006 det2x2(p1.z,p1.w,p2.z,p2.w),
292 178006 p1.w * p2.w
293 89003 );
294 }
295
296 /************************************************************************/
297
298 /**
299 * \brief Comparator class for vec3Hg
300 * \detail Used to create maps indexed by vec3Hg or
301 * SOS symbolic perturbation
302 */
303 template <class T> class vec3HgLexicoCompare {
304 public:
305 /**
306 * \brief Compares two vec3Hg
307 * \retval true if \p v1 is before \p v2 in the lexicographic
308 * order
309 * \retval false otherwise
310 */
311 1666609 bool operator()(const vec3Hg<T>& v1, const vec3Hg<T>& v2) const {
312 1666609 Sign s = Numeric::ratio_compare(v2.x, v2.w, v1.x, v1.w);
313
2/2
✓ Branch 0 taken 729101 times.
✓ Branch 1 taken 937508 times.
1666609 if(s == POSITIVE) {
314 return true;
315 }
316
2/2
✓ Branch 0 taken 641629 times.
✓ Branch 1 taken 295879 times.
937508 if(s == NEGATIVE) {
317 return false;
318 }
319
320 295879 s = Numeric::ratio_compare(v2.y, v2.w, v1.y, v1.w);
321
2/2
✓ Branch 0 taken 77912 times.
✓ Branch 1 taken 217967 times.
295879 if(s == POSITIVE) {
322 return true;
323 }
324
2/2
✓ Branch 0 taken 53188 times.
✓ Branch 1 taken 164779 times.
217967 if(s == NEGATIVE) {
325 return false;
326 }
327
328 164779 s = Numeric::ratio_compare(v2.z, v2.w, v1.z, v1.w);
329 164779 return (s == POSITIVE);
330 }
331 };
332
333 /************************************************************************/
334
335 template <class T> inline vec2Hg<T> mix(
336 const rationalg<T>& t,
337 const vecng<2,double>& p1, const vecng<2,double>& p2
338 ) {
339 const T& st_d = t.denom();
340 const T& t_n = t.num();
341 T s_n = st_d - t_n;
342 return vec2Hg<T>(
343 s_n * T(p1.x) + t_n * T(p2.x),
344 s_n * T(p1.y) + t_n * T(p2.y),
345 st_d
346 );
347 }
348
349 template <class T> inline vec3Hg<T> mix(
350 const rationalg<T>& t,
351 const vecng<3,double>& p1, const vecng<3,double>& p2
352 ) {
353 const T& st_d = t.denom();
354 const T& t_n = t.num();
355 T s_n = st_d - t_n;
356 return vec3Hg<T>(
357 s_n * T(p1.x) + t_n * T(p2.x),
358 s_n * T(p1.y) + t_n * T(p2.y),
359 s_n * T(p1.z) + t_n * T(p2.z),
360 st_d
361 );
362 }
363
364
365 81 template <class T> inline vec2Hg<T> mix(
366 const rationalg<T>& t, const vec2Hg<T>& p1, const vec2Hg<T>& p2
367 ) {
368
1/2
✓ Branch 0 taken 81 times.
✗ Branch 1 not taken.
81 if(p1.w == p2.w) {
369 81 T sn = t.denom() - t.num();
370 T tn = t.num();
371 return vec2Hg<T>(
372
5/14
✓ Branch 1 taken 81 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 81 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 81 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 81 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 81 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
243 sn * p1.x + tn * p2.x,
373
5/14
✓ Branch 1 taken 81 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 81 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 81 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 81 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 81 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
243 sn * p1.y + tn * p2.y,
374
2/6
✓ Branch 1 taken 81 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 81 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
162 t.denom() * p1.w
375 81 );
376 } else {
377 T sn = p2.w*(t.denom() - t.num());
378 T tn = p1.w*t.num();
379 return vec2Hg<T>(
380 sn * p1.x + tn * p2.x,
381 sn * p1.y + tn * p2.y,
382 t.denom() * p1.w * p2.w
383 );
384 }
385 }
386
387 template <class T> inline vec3Hg<T> mix(
388 const rationalg<T>& t, const vec3Hg<T>& p1, const vec3Hg<T>& p2
389 ) {
390 if(p1.w == p2.w) {
391 T sn = t.denom() - t.num();
392 T tn = t.num();
393 return vec3Hg<T>(
394 sn * p1.x + tn * p2.x,
395 sn * p1.y + tn * p2.y,
396 sn * p1.z + tn * p2.z,
397 t.denom() * p1.w
398 );
399 } else {
400 T sn = p2.w*(t.denom() - t.num());
401 T tn = p1.w*t.num();
402 return vec3Hg<T>(
403 sn * p1.x + tn * p2.x,
404 sn * p1.y + tn * p2.y,
405 sn * p1.z + tn * p2.z,
406 t.denom() * p1.w * p2.w
407 );
408 }
409 }
410
411
412 /************************************************************************/
413
414 namespace Numeric {
415
416 template<class T>
417 inline void optimize_number_representation(vec2Hg<T>& v) {
418
1/2
✓ Branch 1 taken 81 times.
✗ Branch 2 not taken.
81 v.optimize();
419 81 }
420
421 template<class T>
422 inline void optimize_number_representation(vec3Hg<T>& v) {
423 292336 v.optimize();
424 }
425
426 }
427
428 /************************************************************************/
429 }
430
431
432 #endif
433