GCC Code Coverage Report


Directory: ./
File: lib/geogram/basic/vechg.h
Date: 2026-09-07 02:37:58
Exec Total Coverage
Lines: 140 148 94.6%
Functions: 31 32 96.9%
Branches: 70 156 44.9%

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 863923 vec2Hg(const T& x_in, const T& y_in, const T& w_in) :
68 863923 x(x_in),
69
1/2
✓ Branch 1 taken 863923 times.
✗ Branch 2 not taken.
863923 y(y_in),
70
1/2
✓ Branch 1 taken 863923 times.
✗ Branch 2 not taken.
863923 w(w_in) {
71 863923 }
72
73 3127 vec2Hg(double x_in, double y_in, double w_in) :
74 3127 x(x_in),
75
1/2
✓ Branch 1 taken 3127 times.
✗ Branch 2 not taken.
3127 y(y_in),
76
1/2
✓ Branch 1 taken 3127 times.
✗ Branch 2 not taken.
3127 w(w_in) {
77 3127 }
78
79 2114368 vec2Hg(T&& x_in, T&& y_in, T&& w_in) :
80 2114368 x(x_in),
81
1/2
✓ Branch 1 taken 32591 times.
✗ Branch 2 not taken.
2114368 y(y_in),
82
1/2
✓ Branch 1 taken 32591 times.
✗ Branch 2 not taken.
2114368 w(w_in) {
83 2114368 }
84
85
2/4
✓ Branch 2 taken 90802 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 90802 times.
✗ Branch 6 not taken.
90802 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
1/2
✓ Branch 1 taken 32692 times.
✗ Branch 2 not taken.
32692 y(rhs.y),
92
1/2
✓ Branch 1 taken 32692 times.
✗ Branch 2 not taken.
32692 w(1.0) {
93 32692 }
94
95 1366124 template <class T2> explicit vec2Hg(const vec2Hg<T2>& rhs) :
96 1366124 x(rhs.x),
97 1366124 y(rhs.y),
98 1366124 w(rhs.w) {
99 1366124 }
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 108102 void optimize() {
128 108102 Numeric::optimize_number_representation(x);
129 108102 Numeric::optimize_number_representation(y);
130 108102 Numeric::optimize_number_representation(w);
131 108102 }
132
133 T x;
134 T y;
135 T w;
136 };
137
138 /************************************************************************/
139
140 108264 template <class T> inline vec2Hg<T> operator-(
141 const vec2Hg<T>& p1, const vec2Hg<T>& p2
142 ) {
143
2/2
✓ Branch 1 taken 75754 times.
✓ Branch 2 taken 32510 times.
108264 if(p2.w == p1.w) {
144 return vec2Hg<T>(
145
1/2
✓ Branch 1 taken 75754 times.
✗ Branch 2 not taken.
151508 p1.x-p2.x,
146 75754 p1.y-p2.y,
147
1/2
✓ Branch 1 taken 75754 times.
✗ Branch 2 not taken.
75754 p1.w
148
1/2
✓ Branch 1 taken 75754 times.
✗ Branch 2 not taken.
75754 );
149 }
150 return vec2Hg<T>(
151
1/2
✓ Branch 1 taken 32510 times.
✗ Branch 2 not taken.
65020 det2x2(p1.x,p1.w,p2.x,p2.w),
152
1/2
✓ Branch 1 taken 32510 times.
✗ Branch 2 not taken.
65020 det2x2(p1.y,p1.w,p2.y,p2.w),
153
1/2
✓ Branch 1 taken 32510 times.
✗ Branch 2 not taken.
65020 p1.w*p2.w
154
1/2
✓ Branch 1 taken 32510 times.
✗ Branch 2 not taken.
32510 );
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 84418 bool operator()(const vec2Hg<T>& v1, const vec2Hg<T>& v2) const {
173 84418 Sign s = Numeric::ratio_compare(v2.x, v2.w, v1.x, v1.w);
174
2/2
✓ Branch 0 taken 22201 times.
✓ Branch 1 taken 62217 times.
84418 if(s == POSITIVE) {
175 22201 return true;
176 }
177
2/2
✓ Branch 0 taken 38795 times.
✓ Branch 1 taken 23422 times.
62217 if(s == NEGATIVE) {
178 38795 return false;
179 }
180 23422 s = Numeric::ratio_compare(v2.y, v2.w, v1.y, v1.w);
181 23422 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 298020 vec3Hg() = default;
196
197 427326 vec3Hg(const T& x_in, const T& y_in, const T& z_in, const T& w_in) :
198 427326 x(x_in),
199
1/2
✓ Branch 1 taken 427326 times.
✗ Branch 2 not taken.
427326 y(y_in),
200
1/2
✓ Branch 1 taken 427326 times.
✗ Branch 2 not taken.
427326 z(z_in),
201
1/2
✓ Branch 1 taken 427326 times.
✗ Branch 2 not taken.
427326 w(w_in) {
202 427326 }
203
204 765942 vec3Hg(T&& x_in, T&& y_in, T&& z_in, T&& w_in) :
205 765942 x(x_in),
206
1/2
✓ Branch 1 taken 312072 times.
✗ Branch 2 not taken.
765942 y(y_in),
207
1/2
✓ Branch 1 taken 312072 times.
✗ Branch 2 not taken.
765942 z(z_in),
208
1/2
✓ Branch 1 taken 312072 times.
✗ Branch 2 not taken.
765942 w(w_in) {
209 765942 }
210
211 787569 vec3Hg(double x_in, double y_in, double z_in, double w_in) :
212 787569 x(x_in),
213
1/2
✓ Branch 1 taken 787569 times.
✗ Branch 2 not taken.
787569 y(y_in),
214
1/2
✓ Branch 1 taken 787569 times.
✗ Branch 2 not taken.
787569 z(z_in),
215
1/2
✓ Branch 1 taken 787569 times.
✗ Branch 2 not taken.
787569 w(w_in) {
216 787569 }
217
218
3/6
✓ Branch 2 taken 540856 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 540856 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 540856 times.
✗ Branch 9 not taken.
540856 vec3Hg(const vec3Hg& rhs) = default;
219
220 24895 vec3Hg(vec3Hg&& rhs) = default;
221
222 68170 template <class T2> explicit vec3Hg(const vecng<3,T2>& rhs) :
223 68170 x(rhs.x),
224
1/2
✓ Branch 1 taken 68170 times.
✗ Branch 2 not taken.
68170 y(rhs.y),
225
1/2
✓ Branch 1 taken 68170 times.
✗ Branch 2 not taken.
68170 z(rhs.z),
226
1/2
✓ Branch 1 taken 68170 times.
✗ Branch 2 not taken.
68170 w(1.0) {
227 68170 }
228
229 94532 template <class T2> explicit vec3Hg(const vec3Hg<T2>& rhs) :
230 94532 x(rhs.x),
231 94532 y(rhs.y),
232 94532 z(rhs.z),
233 94532 w(rhs.w) {
234 94532 }
235
236 292336 vec3Hg& operator=(const vec3Hg& rhs) = default;
237 4343 vec3Hg& operator=(vec3Hg&& rhs) = default;
238
239 86946 T* data() {
240 86946 return &x;
241 }
242
243 44248220 const T* data() const {
244 44248220 return &x;
245 }
246
247 86946 T& operator[](coord_index_t i) {
248
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 86946 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
86946 geo_debug_assert(i <= 3);
249 86946 return data()[i];
250 }
251
252 44248220 const T& operator[](coord_index_t i) const {
253
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 44248220 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
44248220 geo_debug_assert(i <= 3);
254 44248220 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 292336 Numeric::optimize_number_representation(x);
264 292336 Numeric::optimize_number_representation(y);
265 292336 Numeric::optimize_number_representation(z);
266 292336 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 516573 template <class T> inline vec3Hg<T> operator-(
278 const vec3Hg<T>& p1, const vec3Hg<T>& p2
279 ) {
280
2/2
✓ Branch 1 taken 427326 times.
✓ Branch 2 taken 89247 times.
516573 if(p1.w == p2.w) {
281 return vec3Hg<T>(
282
1/2
✓ Branch 1 taken 427326 times.
✗ Branch 2 not taken.
854652 p1.x - p2.x,
283
1/2
✓ Branch 1 taken 427326 times.
✗ Branch 2 not taken.
854652 p1.y - p2.y,
284 427326 p1.z - p2.z,
285
1/2
✓ Branch 1 taken 427326 times.
✗ Branch 2 not taken.
427326 p1.w
286
1/2
✓ Branch 1 taken 427326 times.
✗ Branch 2 not taken.
427326 );
287 }
288 return vec3Hg<T>(
289
1/2
✓ Branch 1 taken 89247 times.
✗ Branch 2 not taken.
178494 det2x2(p1.x,p1.w,p2.x,p2.w),
290
1/2
✓ Branch 1 taken 89247 times.
✗ Branch 2 not taken.
178494 det2x2(p1.y,p1.w,p2.y,p2.w),
291
1/2
✓ Branch 1 taken 89247 times.
✗ Branch 2 not taken.
178494 det2x2(p1.z,p1.w,p2.z,p2.w),
292
1/2
✓ Branch 1 taken 89247 times.
✗ Branch 2 not taken.
178494 p1.w * p2.w
293
1/2
✓ Branch 1 taken 89247 times.
✗ Branch 2 not taken.
89247 );
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 1658492 bool operator()(const vec3Hg<T>& v1, const vec3Hg<T>& v2) const {
312 1658492 Sign s = Numeric::ratio_compare(v2.x, v2.w, v1.x, v1.w);
313
2/2
✓ Branch 0 taken 735683 times.
✓ Branch 1 taken 922809 times.
1658492 if(s == POSITIVE) {
314 735683 return true;
315 }
316
2/2
✓ Branch 0 taken 627118 times.
✓ Branch 1 taken 295691 times.
922809 if(s == NEGATIVE) {
317 627118 return false;
318 }
319
320 295691 s = Numeric::ratio_compare(v2.y, v2.w, v1.y, v1.w);
321
2/2
✓ Branch 0 taken 78312 times.
✓ Branch 1 taken 217379 times.
295691 if(s == POSITIVE) {
322 78312 return true;
323 }
324
2/2
✓ Branch 0 taken 52395 times.
✓ Branch 1 taken 164984 times.
217379 if(s == NEGATIVE) {
325 52395 return false;
326 }
327
328 164984 s = Numeric::ratio_compare(v2.z, v2.w, v1.z, v1.w);
329 164984 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 1 taken 81 times.
✗ Branch 2 not taken.
81 if(p1.w == p2.w) {
369
1/2
✓ Branch 3 taken 81 times.
✗ Branch 4 not taken.
81 T sn = t.denom() - t.num();
370
1/2
✓ Branch 2 taken 81 times.
✗ Branch 3 not taken.
81 T tn = t.num();
371 return vec2Hg<T>(
372
3/6
✓ 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.
162 sn * p1.x + tn * p2.x,
373
3/6
✓ 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.
162 sn * p1.y + tn * p2.y,
374
1/2
✓ Branch 2 taken 81 times.
✗ Branch 3 not taken.
162 t.denom() * p1.w
375
1/2
✓ Branch 1 taken 81 times.
✗ Branch 2 not taken.
81 );
376 81 } 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 81 inline void optimize_number_representation(vec2Hg<T>& v) {
418 81 v.optimize();
419 81 }
420
421 template<class T>
422 292336 inline void optimize_number_representation(vec3Hg<T>& v) {
423 292336 v.optimize();
424 292336 }
425
426 }
427
428 /************************************************************************/
429 }
430
431
432 #endif
433