GCC Code Coverage Report


Directory: ./
File: lib/geogram/basic/vechg.h
Date: 2026-09-07 02:25:23
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 863647 vec2Hg(const T& x_in, const T& y_in, const T& w_in) :
68 863647 x(x_in),
69 863647 y(y_in),
70 863647 w(w_in) {
71 863647 }
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 1058885 vec2Hg(T&& x_in, T&& y_in, T&& w_in) :
80 33089 x(x_in),
81 33089 y(y_in),
82 33089 w(w_in) {
83 33089 }
84
85 90810 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 1367728 template <class T2> explicit vec2Hg(const vec2Hg<T2>& rhs) :
96 1367728 x(rhs.x),
97 1367728 y(rhs.y),
98 1367728 w(rhs.w) {
99 1367728 }
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 108192 void optimize() {
128 Numeric::optimize_number_representation(x);
129 Numeric::optimize_number_representation(y);
130 Numeric::optimize_number_representation(w);
131 108192 }
132
133 T x;
134 T y;
135 T w;
136 };
137
138 /************************************************************************/
139
140 108354 template <class T> inline vec2Hg<T> operator-(
141 const vec2Hg<T>& p1, const vec2Hg<T>& p2
142 ) {
143
2/2
✓ Branch 0 taken 75346 times.
✓ Branch 1 taken 33008 times.
108354 if(p2.w == p1.w) {
144 return vec2Hg<T>(
145
2/6
✓ Branch 1 taken 75346 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 75346 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
150692 p1.x-p2.x,
146 75346 p1.y-p2.y,
147 75346 p1.w
148 75346 );
149 }
150 return vec2Hg<T>(
151
2/6
✓ Branch 1 taken 33008 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 33008 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
66016 det2x2(p1.x,p1.w,p2.x,p2.w),
152
2/6
✓ Branch 1 taken 33008 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 33008 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
66016 det2x2(p1.y,p1.w,p2.y,p2.w),
153 66016 p1.w*p2.w
154 33008 );
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 83904 bool operator()(const vec2Hg<T>& v1, const vec2Hg<T>& v2) const {
173 83904 Sign s = Numeric::ratio_compare(v2.x, v2.w, v1.x, v1.w);
174
2/2
✓ Branch 0 taken 61869 times.
✓ Branch 1 taken 22035 times.
83904 if(s == POSITIVE) {
175 return true;
176 }
177
2/2
✓ Branch 0 taken 23395 times.
✓ Branch 1 taken 38474 times.
61869 if(s == NEGATIVE) {
178 return false;
179 }
180 23395 s = Numeric::ratio_compare(v2.y, v2.w, v1.y, v1.w);
181 23395 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 427168 vec3Hg(const T& x_in, const T& y_in, const T& z_in, const T& w_in) :
198 427168 x(x_in),
199 427168 y(y_in),
200 427168 z(z_in),
201 427168 w(w_in) {
202 427168 }
203
204 382775 vec3Hg(T&& x_in, T&& y_in, T&& z_in, T&& w_in) :
205 312032 x(x_in),
206 312032 y(y_in),
207 312032 z(z_in),
208 312032 w(w_in) {
209 312032 }
210
211 785393 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 785393 }
217
218 540812 vec3Hg(const vec3Hg& rhs) = default;
219
220 24897 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 94324 template <class T2> explicit vec3Hg(const vec3Hg<T2>& rhs) :
230 94324 x(rhs.x),
231 94324 y(rhs.y),
232 94324 z(rhs.z),
233 94324 w(rhs.w) {
234 94324 }
235
236 292336 vec3Hg& operator=(const vec3Hg& rhs) = default;
237
4/8
✓ Branch 0 taken 4358 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4358 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4358 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 4358 times.
✗ Branch 7 not taken.
17432 vec3Hg& operator=(vec3Hg&& rhs) = default;
238
239 T* data() {
240 return &x;
241 }
242
243 const T* data() const {
244 13542454 return &x;
245 }
246
247 T& operator[](coord_index_t i) {
248 geo_debug_assert(i <= 3);
249 43473 return data()[i];
250 }
251
252 const T& operator[](coord_index_t i) const {
253 geo_debug_assert(i <= 3);
254 13276169 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 516360 template <class T> inline vec3Hg<T> operator-(
278 const vec3Hg<T>& p1, const vec3Hg<T>& p2
279 ) {
280
2/2
✓ Branch 0 taken 427168 times.
✓ Branch 1 taken 89192 times.
516360 if(p1.w == p2.w) {
281 return vec3Hg<T>(
282
2/6
✓ Branch 1 taken 427168 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 427168 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
854336 p1.x - p2.x,
283
2/6
✓ Branch 1 taken 427168 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 427168 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
854336 p1.y - p2.y,
284 427168 p1.z - p2.z,
285 427168 p1.w
286 427168 );
287 }
288 return vec3Hg<T>(
289
2/6
✓ Branch 1 taken 89192 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 89192 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
178384 det2x2(p1.x,p1.w,p2.x,p2.w),
290
2/6
✓ Branch 1 taken 89192 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 89192 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
178384 det2x2(p1.y,p1.w,p2.y,p2.w),
291
2/6
✓ Branch 1 taken 89192 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 89192 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
178384 det2x2(p1.z,p1.w,p2.z,p2.w),
292 178384 p1.w * p2.w
293 89192 );
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 1660920 bool operator()(const vec3Hg<T>& v1, const vec3Hg<T>& v2) const {
312 1660920 Sign s = Numeric::ratio_compare(v2.x, v2.w, v1.x, v1.w);
313
2/2
✓ Branch 0 taken 729338 times.
✓ Branch 1 taken 931582 times.
1660920 if(s == POSITIVE) {
314 return true;
315 }
316
2/2
✓ Branch 0 taken 635326 times.
✓ Branch 1 taken 296256 times.
931582 if(s == NEGATIVE) {
317 return false;
318 }
319
320 296256 s = Numeric::ratio_compare(v2.y, v2.w, v1.y, v1.w);
321
2/2
✓ Branch 0 taken 78187 times.
✓ Branch 1 taken 218069 times.
296256 if(s == POSITIVE) {
322 return true;
323 }
324
2/2
✓ Branch 0 taken 53037 times.
✓ Branch 1 taken 165032 times.
218069 if(s == NEGATIVE) {
325 return false;
326 }
327
328 165032 s = Numeric::ratio_compare(v2.z, v2.w, v1.z, v1.w);
329 165032 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