GCC Code Coverage Report


Directory: ./
File: lib/geogram/voronoi/generic_RVD_utils.h
Date: 2026-09-07 02:36:43
Exec Total Coverage
Lines: 71 71 100.0%
Functions: 14 14 100.0%
Branches: 27 32 84.4%

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_VORONOI_GENERIC_RVD_UTILS
41 #define GEOGRAM_VORONOI_GENERIC_RVD_UTILS
42
43 #include <geogram/basic/common.h>
44 #include <geogram/voronoi/generic_RVD_vertex.h>
45 #include <geogram/voronoi/generic_RVD_polygon.h>
46 #include <geogram/voronoi/generic_RVD_cell.h>
47 #include <geogram/basic/memory.h>
48 #include <stack>
49 #include <vector>
50
51 /**
52 * \file geogram/voronoi/generic_RVD_utils.h
53 * \brief Some utilities for implementing surfacic
54 * and volumetric restricted Voronoi diagrams.
55 */
56
57 namespace GEOGen {
58
59 using GEO::NO_INDEX;
60
61 /**
62 * \brief A stack implemented in a GEO::vector.
63 * \details Used by the Android version of
64 * GEOGen::RestrictedVoronoiDiagram. The
65 * std::stack class has some problems with
66 * multithread memory protection issues (it seems that
67 * a SMP-safe global lock on memory is missing
68 * in Android libraries).
69 */
70 template <class T>
71 class VectorStack {
72 public:
73 /**
74 * \brief Pushes a new item onto the stack.
75 */
76 void push(const T& x) {
77 rep_.push_back(x);
78 }
79
80 /**
81 * \brief Pops the top of the stack.
82 * \pre !empty()
83 */
84 void pop() {
85 rep_.pop_back();
86 }
87
88 /**
89 * \brief Gets the item on the top.
90 * \return a const reference to the item on the top
91 * \pre !empty()
92 */
93 const T& top() const {
94 return *rep_.rbegin();
95 }
96
97 /**
98 * \brief Tests whether the stack is empty.
99 */
100 bool empty() const {
101 return rep_.size() == 0;
102 }
103
104 private:
105 GEO::vector<T> rep_;
106 };
107
108 /************************************************************************/
109
110 /**
111 * \brief A (facet,seed) pair.
112 * \details Used by GEOGen::RestrictedVoronoiDiagram
113 * for propagating over the facet graph and the
114 * Delaunay 1-skeleton.
115 */
116 struct FacetSeed {
117
118 /**
119 * \brief Creates a new FacetSeed
120 * \param[in] f_in index of the facet
121 * \param[in] seed_in index of the seed
122 */
123 1212413 FacetSeed(index_t f_in, index_t seed_in) :
124 1212413 f(f_in),
125 1212413 seed(seed_in) {
126 1212413 }
127
128 /**
129 * \brief Creates a new uninitialized FacetSeed
130 * \details F and seed contain random values.
131 */
132 FacetSeed() {
133 }
134
135 /**
136 * \brief Compares two facet seeds using lexicographic order.
137 * \details Makes it possible to use FacetSeed as keys for
138 * std::set and std::map.
139 */
140 bool operator< (const FacetSeed& rhs) const {
141 if(f < rhs.f) {
142 return true;
143 }
144 if(f > rhs.f) {
145 return false;
146 }
147 return seed < rhs.seed;
148 }
149
150 index_t f;
151 index_t seed;
152 };
153
154 /**
155 * \brief A (tetrahedron,seed) pair.
156 * \details Used by GEOGen::RestrictedVoronoiDiagram
157 * for propagating over the tetrahedra graph and the
158 * Delaunay 1-skeleton.
159 */
160 typedef FacetSeed TetSeed;
161 /************************************************************************/
162
163 #ifdef GEO_OS_ANDROID
164 // VectorStack uses AlignedAllocator, that is protected
165 // by a global lock under Android (needed because it
166 // seems that malloc() is not SMP-thread-safe under Android).
167
168 /**
169 * \brief A stack of FacetSeed.
170 * \details Used by GEOGen::RestrictedVoronoiDiagram.
171 */
172 typedef VectorStack<FacetSeed> FacetSeedStack;
173
174 /**
175 * \brief A stack of TetSeed.
176 * \details Used by GEOGen::RestrictedVoronoiDiagram.
177 */
178 typedef VectorStack<TetSeed> TetSeedStack;
179
180 /**
181 * \brief A stack of seed indices (index_t).
182 * \details Used by GEOGen::RestrictedVoronoiDiagram.
183 */
184 typedef VectorStack<index_t> SeedStack;
185 #else
186
187 /**
188 * \brief A stack of FacetSeed.
189 * \details Used by GEOGen::RestrictedVoronoiDiagram.
190 */
191 typedef std::stack<FacetSeed> FacetSeedStack;
192
193 /**
194 * \brief A stack of TetSeed.
195 * \details Used by GEOGen::RestrictedVoronoiDiagram.
196 */
197 typedef std::stack<TetSeed> TetSeedStack;
198
199 /**
200 * \brief A stack of seed indices (index_t).
201 * \details Used by GEOGen::RestrictedVoronoiDiagram.
202 */
203 typedef std::stack<index_t> SeedStack;
204 #endif
205
206 /************************************************************************/
207
208 /**
209 * \brief Stores associations between (facet,seed) pairs and the index of
210 * a connected component.
211 *
212 * \details Used by GEOGen::RestrictedVoronoiDiagram.
213 * The implementation uses an array of (key,value) vectors,
214 * with dynamic reallocation and linear search.
215 * Experimentally, this significantly reduces the memory
216 * footprint and execution time as compared to
217 * std::table<FacetSeed,index_t>.
218 */
219 class FacetSeedMarking {
220 public:
221 /**
222 * \brief Creates a new FacetSeedMarking
223 * \param[in] nb_seeds total number of seeds
224 */
225 10 FacetSeedMarking(index_t /* nb_facets*/, index_t nb_seeds) {
226
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 set_size(nb_seeds);
227 10 }
228
229 /**
230 * \brief Tests whether a given facet,seed couple is marked.
231 */
232 438582 bool is_marked(index_t facet, index_t seed) const {
233 438582 return (find_index(seed, facet) != NO_INDEX);
234 }
235
236 /**
237 * \brief Tests whether a fiven FacetSeed is marked.
238 */
239 325165 bool is_marked(const FacetSeed& fs) const {
240 325165 return is_marked(fs.f, fs.seed);
241 }
242
243 /**
244 * \brief Gets the index of the connected component associated
245 * with a given FacetSeed.
246 */
247 358824 index_t get_connected_component(const FacetSeed& fs) const {
248 358824 return find_value(fs.seed, fs.f);
249 }
250
251 /**
252 * \brief Marks a FacetSeed and sets the associated
253 * connected component index.
254 */
255 94552 void mark(const FacetSeed& fs, index_t conn_comp) {
256 94552 insert(fs.seed, fs.f, conn_comp);
257 94552 }
258
259 /**
260 * \brief FacetSeedMarking destructor
261 */
262 10 ~FacetSeedMarking() {
263
2/2
✓ Branch 1 taken 31200 times.
✓ Branch 2 taken 10 times.
31210 for(index_t i = 0; i < nb_arrays(); ++i) {
264 31200 free(keys_[i]);
265 }
266
2/2
✓ Branch 1 taken 31200 times.
✓ Branch 2 taken 10 times.
31210 for(index_t i = 0; i < nb_arrays(); ++i) {
267 31200 free(values_[i]);
268 }
269 10 }
270
271 protected:
272 /**
273 * \brief Gets the number of arrays used internally.
274 */
275 62420 index_t nb_arrays() const {
276 62420 return index_t(keys_.size());
277 }
278
279 /**
280 * \brief Sets the number of arrays to be used.
281 * \param[in] nb_arrays number of arrays
282 */
283 10 void set_size(index_t nb_arrays) {
284
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 keys_.assign(nb_arrays, nullptr);
285
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 values_.assign(nb_arrays, nullptr);
286
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 size_.assign(nb_arrays, 0);
287 10 }
288
289 /**
290 * \brief Gets the size of one of the arrays.
291 * \param[in] array index of the array
292 * \pre array < nb_arrays()
293 */
294 2186685 index_t array_size(index_t array) const {
295 2186685 return size_[array];
296 }
297
298 /**
299 * \brief Gets the capacity of one of the arrays.
300 * \details It corresponds with the power of two immediately
301 * greater than size. Unlike in std::vector, capacity is implicitly
302 * retrieved from size (this saves one integer
303 * per seed).
304 * \param[in] array index of the array
305 * \pre array < nb_arrays()
306 */
307 94552 index_t array_capacity(index_t array) const {
308 94552 index_t size = array_size(array);
309
2/2
✓ Branch 0 taken 31200 times.
✓ Branch 1 taken 63352 times.
94552 if(size == 0) {
310 31200 return 0;
311 }
312 63352 index_t result = 1;
313 63352 index_t mask = 1;
314
2/2
✓ Branch 0 taken 2027264 times.
✓ Branch 1 taken 63352 times.
2090616 for(index_t i = 0; i < 32; i++) {
315 2027264 mask = mask << 1;
316
2/2
✓ Branch 0 taken 58438 times.
✓ Branch 1 taken 1968826 times.
2027264 if((size & mask) != 0) {
317 58438 result = mask;
318 }
319 }
320 // If size is not already a power of two,
321
2/2
✓ Branch 0 taken 25381 times.
✓ Branch 1 taken 37971 times.
63352 if(result != size) {
322 25381 result = result << 1;
323 }
324 63352 return result;
325 }
326
327 /**
328 * \brief Finds the index of one of the keys in one of the arrays.
329 * \param[in] array index of the array
330 * \param[in] key the query key
331 * \return the index of \p key in \p array or NO_INDEX if not found
332 */
333 891958 index_t find_index(index_t array, index_t key) const {
334 891958 index_t* K = keys_[array];
335
2/2
✓ Branch 1 taken 1624335 times.
✓ Branch 2 taken 467798 times.
2092133 for(index_t i = 0; i < array_size(array); ++i) {
336
2/2
✓ Branch 0 taken 424160 times.
✓ Branch 1 taken 1200175 times.
1624335 if(K[i] == key) {
337 424160 return i;
338 }
339 }
340 467798 return NO_INDEX;
341 }
342
343 /**
344 * \brief Finds the value associated with a key in one
345 * of the arrays.
346 * \param[in] array index of the array
347 * \param[in] key the query key
348 * \return the value associated with \p key in \p array
349 * or NO_INDEX if not found.
350 */
351 358824 index_t find_value(index_t array, index_t key) const {
352 358824 index_t i = find_index(array, key);
353
2/2
✓ Branch 0 taken 179412 times.
✓ Branch 1 taken 179412 times.
358824 if(i == NO_INDEX) {
354 179412 return NO_INDEX;
355 }
356 179412 return values_[array][i];
357 }
358
359 /**
360 * \brief Inserts a (key,value) pair into one of the arrays.
361 * \param[in] array index of the array
362 * \param[in] key the key
363 * \param[in] value the value to be associated with \p key
364 */
365 94552 void insert(index_t array, index_t key, index_t value) {
366 94552 index_t i = find_index(array, key);
367
1/2
✓ Branch 0 taken 94552 times.
✗ Branch 1 not taken.
94552 if(i == NO_INDEX) {
368 // If not found, append at the end of array
369 94552 i = size_[array];
370
2/2
✓ Branch 1 taken 69171 times.
✓ Branch 2 taken 25381 times.
94552 if(i == array_capacity(array)) {
371 // If capacity is reached, grow storage
372 69171 index_t new_nb = index_t(2*i);
373
2/2
✓ Branch 0 taken 31200 times.
✓ Branch 1 taken 37971 times.
69171 if(new_nb == 0) {
374 31200 new_nb = 1;
375 }
376 138342 keys_[array] = reinterpret_cast<index_t*>(
377 69171 realloc(keys_[array], sizeof(index_t) * new_nb)
378 );
379 69171 values_[array] = reinterpret_cast<index_t*>(
380 69171 realloc(values_[array], sizeof(index_t) * new_nb)
381 );
382 }
383 94552 size_[array] = i + 1;
384 }
385 94552 keys_[array][i] = key;
386 94552 values_[array][i] = value;
387 94552 }
388
389 private:
390 std::vector<index_t*> keys_;
391 std::vector<index_t*> values_;
392 std::vector<index_t> size_;
393 };
394
395 /************************************************************************/
396
397 /**
398 * \brief Stores associations between (tet,seed) pairs and the index of
399 * a connected component.
400 */
401 typedef FacetSeedMarking TetSeedMarking;
402
403 /************************************************************************/
404 }
405
406 #endif
407