GCC Code Coverage Report


Directory: ./
File: basic/vechg.h
Date: 2026-10-17 02:51: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 863330 vec2Hg(const T& x_in, const T& y_in, const T& w_in) :
68 863330 x(x_in),
69
1/2
✓ Branch 1 taken 863330 times.
✗ Branch 2 not taken.
863330 y(y_in),
70
1/2
✓ Branch 1 taken 863330 times.
✗ Branch 2 not taken.
863330 w(w_in) {
71 863330 }
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 2118834 vec2Hg(T&& x_in, T&& y_in, T&& w_in) :
80 2118834 x(x_in),
81
1/2
✓ Branch 1 taken 33099 times.
✗ Branch 2 not taken.
2118834 y(y_in),
82
1/2
✓ Branch 1 taken 33099 times.
✗ Branch 2 not taken.
2118834 w(w_in) {
83 2118834 }
84
85
2/4
✓ Branch 2 taken 90800 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 90800 times.
✗ Branch 6 not taken.
90800 vec2Hg(const vec2Hg& rhs) = default;
86
87 vec2Hg(vec2Hg&& rhs) = default;
88
89 32688 template <class T2> explicit vec2Hg(const vecng<2,T2>& rhs) :
90 32688 x(rhs.x),
91
1/2
✓ Branch 1 taken 32688 times.
✗ Branch 2 not taken.
32688 y(rhs.y),
92
1/2
✓ Branch 1 taken 32688 times.
✗ Branch 2 not taken.
32688 w(1.0) {
93 32688 }
94
95 1368424 template <class T2> explicit vec2Hg(const vec2Hg<T2>& rhs) :
96 1368424 x(rhs.x),
97 1368424 y(rhs.y),
98 1368424 w(rhs.w) {
99 1368424 }
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 108255 void optimize() {
128 108255 Numeric::optimize_number_representation(x);
129 108255 Numeric::optimize_number_representation(y);
130 108255 Numeric::optimize_number_representation(w);
131 108255 }
132
133 T x;
134 T y;
135 T w;
136 };
137
138 /************************************************************************/
139
140 108417 template <class T> inline vec2Hg<T> operator-(
141 const vec2Hg<T>& p1, const vec2Hg<T>& p2
142 ) {
143
2/2
✓ Branch 1 taken 75399 times.
✓ Branch 2 taken 33018 times.
108417 if(p2.w == p1.w) {
144 return vec2Hg<T>(
145
1/2
✓ Branch 1 taken 75399 times.
✗ Branch 2 not taken.
150798 p1.x-p2.x,
146 75399 p1.y-p2.y,
147
1/2
✓ Branch 1 taken 75399 times.
✗ Branch 2 not taken.
75399 p1.w
148
1/2
✓ Branch 1 taken 75399 times.
✗ Branch 2 not taken.
75399 );
149 }
150 return vec2Hg<T>(
151
1/2
✓ Branch 1 taken 33018 times.
✗ Branch 2 not taken.
66036 det2x2(p1.x,p1.w,p2.x,p2.w),
152
1/2
✓ Branch 1 taken 33018 times.
✗ Branch 2 not taken.
66036 det2x2(p1.y,p1.w,p2.y,p2.w),
153
1/2
✓ Branch 1 taken 33018 times.
✗ Branch 2 not taken.
66036 p1.w*p2.w
154
1/2
✓ Branch 1 taken 33018 times.
✗ Branch 2 not taken.
33018 );
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 84857 bool operator()(const vec2Hg<T>& v1, const vec2Hg<T>& v2) const {
173 84857 Sign s = Numeric::ratio_compare(v2.x, v2.w, v1.x, v1.w);
174
2/2
✓ Branch 0 taken 22370 times.
✓ Branch 1 taken 62487 times.
84857 if(s == POSITIVE) {
175 22370 return true;
176 }
177
2/2
✓ Branch 0 taken 38935 times.
✓ Branch 1 taken 23552 times.
62487 if(s == NEGATIVE) {
178 38935 return false;
179 }
180 23552 s = Numeric::ratio_compare(v2.y, v2.w, v1.y, v1.w);
181 23552 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 298027 vec3Hg() = default;
196
197 427504 vec3Hg(const T& x_in, const T& y_in, const T& z_in, const T& w_in) :
198 427504 x(x_in),
199
1/2
✓ Branch 1 taken 427504 times.
✗ Branch 2 not taken.
427504 y(y_in),
200
1/2
✓ Branch 1 taken 427504 times.
✗ Branch 2 not taken.
427504 z(z_in),
201
1/2
✓ Branch 1 taken 427504 times.
✗ Branch 2 not taken.
427504 w(w_in) {
202 427504 }
203
204 766122 vec3Hg(T&& x_in, T&& y_in, T&& z_in, T&& w_in) :
205 766122 x(x_in),
206
1/2
✓ Branch 1 taken 312108 times.
✗ Branch 2 not taken.
766122 y(y_in),
207
1/2
✓ Branch 1 taken 312108 times.
✗ Branch 2 not taken.
766122 z(z_in),
208
1/2
✓ Branch 1 taken 312108 times.
✗ Branch 2 not taken.
766122 w(w_in) {
209 766122 }
210
211 785597 vec3Hg(double x_in, double y_in, double z_in, double w_in) :
212 785597 x(x_in),
213
1/2
✓ Branch 1 taken 785597 times.
✗ Branch 2 not taken.
785597 y(y_in),
214
1/2
✓ Branch 1 taken 785597 times.
✗ Branch 2 not taken.
785597 z(z_in),
215
1/2
✓ Branch 1 taken 785597 times.
✗ Branch 2 not taken.
785597 w(w_in) {
216 785597 }
217
218
3/6
✓ Branch 2 taken 248572 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 248572 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 248572 times.
✗ Branch 9 not taken.
248572 vec3Hg(const vec3Hg& rhs) = default;
219
220 24898 vec3Hg(vec3Hg&& rhs) = default;
221
222 68173 template <class T2> explicit vec3Hg(const vecng<3,T2>& rhs) :
223 68173 x(rhs.x),
224
1/2
✓ Branch 1 taken 68173 times.
✗ Branch 2 not taken.
68173 y(rhs.y),
225
1/2
✓ Branch 1 taken 68173 times.
✗ Branch 2 not taken.
68173 z(rhs.z),
226
1/2
✓ Branch 1 taken 68173 times.
✗ Branch 2 not taken.
68173 w(1.0) {
227 68173 }
228
229 94604 template <class T2> explicit vec3Hg(const vec3Hg<T2>& rhs) :
230 94604 x(rhs.x),
231 94604 y(rhs.y),
232 94604 z(rhs.z),
233 94604 w(rhs.w) {
234 94604 }
235
236 292343 vec3Hg& operator=(const vec3Hg& rhs) = default;
237 4310 vec3Hg& operator=(vec3Hg&& rhs) = default;
238
239 86934 T* data() {
240 86934 return &x;
241 }
242
243 44131688 const T* data() const {
244 44131688 return &x;
245 }
246
247 86934 T& operator[](coord_index_t i) {
248
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 86934 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
86934 geo_debug_assert(i <= 3);
249 86934 return data()[i];
250 }
251
252 44131688 const T& operator[](coord_index_t i) const {
253
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 44131688 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
44131688 geo_debug_assert(i <= 3);
254 44131688 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 292343 void optimize() {
263 292343 Numeric::optimize_number_representation(x);
264 292343 Numeric::optimize_number_representation(y);
265 292343 Numeric::optimize_number_representation(z);
266 292343 Numeric::optimize_number_representation(w);
267 292343 }
268
269 T x;
270 T y;
271 T z;
272 T w;
273 };
274
275 /************************************************************************/
276
277 516816 template <class T> inline vec3Hg<T> operator-(
278 const vec3Hg<T>& p1, const vec3Hg<T>& p2
279 ) {
280
2/2
✓ Branch 1 taken 427504 times.
✓ Branch 2 taken 89312 times.
516816 if(p1.w == p2.w) {
281 return vec3Hg<T>(
282
1/2
✓ Branch 1 taken 427504 times.
✗ Branch 2 not taken.
855008 p1.x - p2.x,
283
1/2
✓ Branch 1 taken 427504 times.
✗ Branch 2 not taken.
855008 p1.y - p2.y,
284 427504 p1.z - p2.z,
285
1/2
✓ Branch 1 taken 427504 times.
✗ Branch 2 not taken.
427504 p1.w
286
1/2
✓ Branch 1 taken 427504 times.
✗ Branch 2 not taken.
427504 );
287 }
288 return vec3Hg<T>(
289
1/2
✓ Branch 1 taken 89312 times.
✗ Branch 2 not taken.
178624 det2x2(p1.x,p1.w,p2.x,p2.w),
290
1/2
✓ Branch 1 taken 89312 times.
✗ Branch 2 not taken.
178624 det2x2(p1.y,p1.w,p2.y,p2.w),
291
1/2
✓ Branch 1 taken 89312 times.
✗ Branch 2 not taken.
178624 det2x2(p1.z,p1.w,p2.z,p2.w),
292
1/2
✓ Branch 1 taken 89312 times.
✗ Branch 2 not taken.
178624 p1.w * p2.w
293
1/2
✓ Branch 1 taken 89312 times.
✗ Branch 2 not taken.
89312 );
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 1659270 bool operator()(const vec3Hg<T>& v1, const vec3Hg<T>& v2) const {
312 1659270 Sign s = Numeric::ratio_compare(v2.x, v2.w, v1.x, v1.w);
313
2/2
✓ Branch 0 taken 722679 times.
✓ Branch 1 taken 936591 times.
1659270 if(s == POSITIVE) {
314 722679 return true;
315 }
316
2/2
✓ Branch 0 taken 640187 times.
✓ Branch 1 taken 296404 times.
936591 if(s == NEGATIVE) {
317 640187 return false;
318 }
319
320 296404 s = Numeric::ratio_compare(v2.y, v2.w, v1.y, v1.w);
321
2/2
✓ Branch 0 taken 78377 times.
✓ Branch 1 taken 218027 times.
296404 if(s == POSITIVE) {
322 78377 return true;
323 }
324
2/2
✓ Branch 0 taken 53133 times.
✓ Branch 1 taken 164894 times.
218027 if(s == NEGATIVE) {
325 53133 return false;
326 }
327
328 164894 s = Numeric::ratio_compare(v2.z, v2.w, v1.z, v1.w);
329 164894 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 292343 inline void optimize_number_representation(vec3Hg<T>& v) {
423 292343 v.optimize();
424 292343 }
425
426 }
427
428 /************************************************************************/
429 }
430
431
432 #endif
433