| 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 | #include <geogram/delaunay/delaunay.h> | ||
| 41 | #include <geogram/delaunay/delaunay_nn.h> | ||
| 42 | #include <geogram/delaunay/delaunay_3d.h> | ||
| 43 | #include <geogram/delaunay/delaunay_2d.h> | ||
| 44 | |||
| 45 | #ifdef GEOGRAM_WITH_PDEL | ||
| 46 | #include <geogram/delaunay/parallel_delaunay_3d.h> | ||
| 47 | #endif | ||
| 48 | |||
| 49 | #ifdef GEOGRAM_WITH_TETGEN | ||
| 50 | #include <geogram/delaunay/delaunay_tetgen.h> | ||
| 51 | #endif | ||
| 52 | |||
| 53 | #ifdef GEOGRAM_WITH_TRIANGLE | ||
| 54 | #include <geogram/delaunay/delaunay_triangle.h> | ||
| 55 | #endif | ||
| 56 | |||
| 57 | #include <geogram/basic/logger.h> | ||
| 58 | #include <geogram/basic/command_line.h> | ||
| 59 | #include <geogram/basic/process.h> | ||
| 60 | #include <geogram/basic/geometry_nd.h> | ||
| 61 | #include <geogram/basic/algorithm.h> | ||
| 62 | |||
| 63 | #include <fstream> | ||
| 64 | #include <sstream> | ||
| 65 | |||
| 66 | namespace { | ||
| 67 | |||
| 68 | using namespace GEO; | ||
| 69 | |||
| 70 | /** | ||
| 71 | * \brief Builds the invalid dimension error message | ||
| 72 | * \param[in] dimension the specified dimension | ||
| 73 | * \param[in] name the name of the Delaunay implementation | ||
| 74 | * \param[in] expected the expected dimension | ||
| 75 | * \return a string that contains the error message | ||
| 76 | */ | ||
| 77 | ✗ | std::string invalid_dimension_error( | |
| 78 | coord_index_t dimension, | ||
| 79 | const char* name, | ||
| 80 | const char* expected | ||
| 81 | ) { | ||
| 82 | ✗ | std::ostringstream out; | |
| 83 | ✗ | out << "Invalid dimension: dimension " << index_t(dimension) | |
| 84 | << " is not supported by the " << name | ||
| 85 | ✗ | << " algorithm. Supported dimension(s): " << expected; | |
| 86 | ✗ | return out.str(); | |
| 87 | ✗ | } | |
| 88 | } | ||
| 89 | |||
| 90 | namespace GEO { | ||
| 91 | |||
| 92 | ✗ | Delaunay::InvalidDimension::InvalidDimension( | |
| 93 | coord_index_t dimension, | ||
| 94 | const char* name, | ||
| 95 | const char* expected | ||
| 96 | ✗ | ) : | |
| 97 | ✗ | std::logic_error(invalid_dimension_error(dimension, name, expected)) { | |
| 98 | ✗ | } | |
| 99 | |||
| 100 | ✗ | const char* Delaunay::InvalidDimension::what() const GEO_NOEXCEPT { | |
| 101 | ✗ | return std::logic_error::what(); | |
| 102 | } | ||
| 103 | |||
| 104 | |||
| 105 | ✗ | Delaunay::InvalidInput::InvalidInput(int code) : | |
| 106 | logic_error("Invalid input for Delaunay"), | ||
| 107 | ✗ | error_code(code) { | |
| 108 | ✗ | } | |
| 109 | |||
| 110 | ✗ | Delaunay::InvalidInput::InvalidInput( | |
| 111 | const InvalidInput& rhs | ||
| 112 | ✗ | ) : | |
| 113 | std::logic_error(rhs), | ||
| 114 | ✗ | error_code(rhs.error_code), | |
| 115 | ✗ | invalid_facets(rhs.invalid_facets) { | |
| 116 | ✗ | } | |
| 117 | |||
| 118 | ✗ | Delaunay::InvalidInput::~InvalidInput() GEO_NOEXCEPT { | |
| 119 | ✗ | } | |
| 120 | |||
| 121 | ✗ | const char* Delaunay::InvalidInput::what() const GEO_NOEXCEPT { | |
| 122 | ✗ | return std::logic_error::what(); | |
| 123 | } | ||
| 124 | |||
| 125 | /************************************************************************/ | ||
| 126 | |||
| 127 | 249 | void Delaunay::initialize() { | |
| 128 | |||
| 129 | #ifdef GEOGRAM_WITH_TETGEN | ||
| 130 | geo_register_Delaunay_creator(DelaunayTetgen, "tetgen"); | ||
| 131 | #endif | ||
| 132 | |||
| 133 | #ifdef GEOGRAM_WITH_TRIANGLE | ||
| 134 | geo_register_Delaunay_creator(DelaunayTriangle, "triangle"); | ||
| 135 | #endif | ||
| 136 | |||
| 137 |
3/6✓ Branch 0 taken 249 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 249 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 249 times.
✗ Branch 7 not taken.
|
747 | geo_register_Delaunay_creator(Delaunay3d, "BDEL"); |
| 138 | |||
| 139 | #ifdef GEOGRAM_WITH_PDEL | ||
| 140 |
3/6✓ Branch 0 taken 249 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 249 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 249 times.
✗ Branch 7 not taken.
|
747 | geo_register_Delaunay_creator(ParallelDelaunay3d, "PDEL"); |
| 141 | #endif | ||
| 142 |
3/6✓ Branch 0 taken 249 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 249 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 249 times.
✗ Branch 7 not taken.
|
747 | geo_register_Delaunay_creator(RegularWeightedDelaunay3d, "BPOW"); |
| 143 | |||
| 144 |
3/6✓ Branch 0 taken 249 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 249 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 249 times.
✗ Branch 7 not taken.
|
747 | geo_register_Delaunay_creator(Delaunay2d, "BDEL2d"); |
| 145 |
3/6✓ Branch 0 taken 249 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 249 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 249 times.
✗ Branch 7 not taken.
|
747 | geo_register_Delaunay_creator(RegularWeightedDelaunay2d, "BPOW2d"); |
| 146 | |||
| 147 | #ifndef GEOGRAM_PSM | ||
| 148 |
3/6✓ Branch 0 taken 249 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 249 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 249 times.
✗ Branch 7 not taken.
|
747 | geo_register_Delaunay_creator(Delaunay_NearestNeighbors, "NN"); |
| 149 | #endif | ||
| 150 | 249 | } | |
| 151 | |||
| 152 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 75 times.
|
75 | Delaunay* Delaunay::create(coord_index_t dim, const std::string& name_in) { |
| 153 | |||
| 154 | std::string name = name_in; | ||
| 155 |
2/2✓ Branch 0 taken 74 times.
✓ Branch 1 taken 1 times.
|
75 | if(name == "default") { |
| 156 |
2/4✓ Branch 1 taken 74 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 74 times.
✗ Branch 5 not taken.
|
148 | name = CmdLine::get_arg("algo:delaunay"); |
| 157 | } | ||
| 158 | |||
| 159 | try { | ||
| 160 | Delaunay* d = DelaunayFactory::create_object(name, dim); | ||
| 161 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 74 times.
|
74 | if(d != nullptr) { |
| 162 | return d; | ||
| 163 | } | ||
| 164 | |||
| 165 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
2 | Logger::warn("Delaunay") |
| 166 | << "Could not create Delaunay triangulation: " << name | ||
| 167 | << std::endl; | ||
| 168 | } | ||
| 169 | ✗ | catch(InvalidDimension& ex) { | |
| 170 | ✗ | Logger::warn("Delaunay") << ex.what() << std::endl; | |
| 171 | ✗ | } | |
| 172 | |||
| 173 | #ifdef GEOGRAM_PSM | ||
| 174 | Logger::err("Delaunay") | ||
| 175 | << "Could not create Delaunay triangulation" | ||
| 176 | << std::endl; | ||
| 177 | return nullptr; | ||
| 178 | #else | ||
| 179 |
2/6✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
1 | Logger::warn("Delaunay") |
| 180 | << "Falling back to NN mode" | ||
| 181 | << std::endl; | ||
| 182 | |||
| 183 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
1 | return new Delaunay_NearestNeighbors(dim); |
| 184 | #endif | ||
| 185 | } | ||
| 186 | |||
| 187 |
1/2✓ Branch 1 taken 75 times.
✗ Branch 2 not taken.
|
75 | Delaunay::Delaunay(coord_index_t dimension) { |
| 188 | set_dimension(dimension); | ||
| 189 | 75 | vertices_ = nullptr; | |
| 190 | 75 | nb_vertices_ = 0; | |
| 191 | 75 | nb_cells_ = 0; | |
| 192 | 75 | cell_to_v_ = nullptr; | |
| 193 | 75 | cell_to_cell_ = nullptr; | |
| 194 | 75 | is_locked_ = false; | |
| 195 | 75 | store_neighbors_ = false; | |
| 196 | 75 | default_nb_neighbors_ = 30; | |
| 197 | 75 | constraints_ = nullptr; | |
| 198 | 75 | do_reorder_ = true; | |
| 199 | 75 | refine_ = false; | |
| 200 | 75 | quality_ = 2.0; | |
| 201 | 75 | store_cicl_ = false; | |
| 202 | 75 | keep_infinite_ = false; | |
| 203 | 75 | nb_finite_cells_ = 0; | |
| 204 | 75 | keep_regions_ = false; | |
| 205 | 75 | } | |
| 206 | |||
| 207 | 150 | Delaunay::~Delaunay() { | |
| 208 | 300 | } | |
| 209 | |||
| 210 | 470 | void Delaunay::set_vertices(index_t nb_vertices, const double* vertices) { | |
| 211 | 470 | nb_vertices_ = nb_vertices; | |
| 212 | 470 | vertices_ = vertices; | |
| 213 | 470 | } | |
| 214 | |||
| 215 | ✗ | void Delaunay::set_BRIO_levels(const vector<index_t>& levels) { | |
| 216 | geo_argused(levels); | ||
| 217 | // Default implementation does nothing | ||
| 218 | ✗ | } | |
| 219 | |||
| 220 | 9 | void Delaunay::set_arrays( | |
| 221 | index_t nb_cells, | ||
| 222 | const index_t* cell_to_v, const index_t* cell_to_cell | ||
| 223 | ) { | ||
| 224 | 9 | nb_cells_ = nb_cells; | |
| 225 | 9 | cell_to_v_ = cell_to_v; | |
| 226 | 9 | cell_to_cell_ = cell_to_cell; | |
| 227 | |||
| 228 |
1/2✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
|
9 | if(cell_to_cell != nullptr) { |
| 229 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
|
9 | if(store_cicl_) { |
| 230 | ✗ | update_v_to_cell(); | |
| 231 | ✗ | update_cicl(); | |
| 232 | } | ||
| 233 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
|
9 | if(store_neighbors_) { |
| 234 | ✗ | update_neighbors(); | |
| 235 | } | ||
| 236 | } | ||
| 237 | 9 | } | |
| 238 | |||
| 239 | ✗ | bool Delaunay::supports_constraints() const { | |
| 240 | ✗ | return false; | |
| 241 | } | ||
| 242 | |||
| 243 | ✗ | index_t Delaunay::nearest_vertex(const double* p) const { | |
| 244 | // Unefficient implementation (but at least it works). | ||
| 245 | // Derived classes are supposed to overload. | ||
| 246 | ✗ | geo_assert(nb_vertices() > 0); | |
| 247 | index_t result = 0; | ||
| 248 | double d = Geom::distance2(vertex_ptr(0), p, dimension()); | ||
| 249 | ✗ | for(index_t i = 1; i < nb_vertices(); i++) { | |
| 250 | double cur_d = Geom::distance2(vertex_ptr(i), p, dimension()); | ||
| 251 | ✗ | if(cur_d < d) { | |
| 252 | d = cur_d; | ||
| 253 | result = i; | ||
| 254 | } | ||
| 255 | } | ||
| 256 | ✗ | return result; | |
| 257 | } | ||
| 258 | |||
| 259 |
2/2✓ Branch 0 taken 65 times.
✓ Branch 1 taken 396 times.
|
461 | void Delaunay::update_neighbors() { |
| 260 |
2/2✓ Branch 0 taken 65 times.
✓ Branch 1 taken 396 times.
|
461 | if(nb_vertices() != neighbors_.nb_arrays()) { |
| 261 | 65 | neighbors_.init( | |
| 262 | nb_vertices(), | ||
| 263 | default_nb_neighbors_ | ||
| 264 | ); | ||
| 265 |
2/2✓ Branch 0 taken 69081 times.
✓ Branch 1 taken 65 times.
|
69146 | for(index_t i = 0; i < nb_vertices(); i++) { |
| 266 | 69081 | neighbors_.resize_array(i, default_nb_neighbors_, false); | |
| 267 | } | ||
| 268 | } | ||
| 269 |
1/2✓ Branch 1 taken 461 times.
✗ Branch 2 not taken.
|
461 | parallel_for( |
| 270 | 0, nb_vertices(), | ||
| 271 | 1315881 | [this](index_t i) { store_neighbors_CB(i); }, | |
| 272 | 1, true | ||
| 273 | ); | ||
| 274 | 461 | } | |
| 275 | |||
| 276 | ✗ | void Delaunay::get_neighbors_internal( | |
| 277 | index_t v, vector<index_t>& neighbors | ||
| 278 | ) const { | ||
| 279 | // Step 1: traverse the incident cells list, and insert | ||
| 280 | // all neighbors (may be duplicated) | ||
| 281 | ✗ | neighbors.resize(0); | |
| 282 | ✗ | index_t vt = v_to_cell_[v]; | |
| 283 | ✗ | if(vt != NO_INDEX) { // Happens when there are duplicated vertices. | |
| 284 | index_t t = vt; | ||
| 285 | do { | ||
| 286 | ✗ | index_t lvit = index(t, v); | |
| 287 | // In the current cell, test all edges incident | ||
| 288 | // to current vertex 'it' | ||
| 289 | ✗ | for(index_t lv = 0; lv < cell_size(); lv++) { | |
| 290 | ✗ | if(lvit != lv) { | |
| 291 | ✗ | index_t neigh = cell_vertex(t, lv); | |
| 292 | geo_debug_assert(neigh != NO_INDEX); | ||
| 293 | neighbors.push_back(neigh); | ||
| 294 | } | ||
| 295 | } | ||
| 296 | ✗ | t = next_around_vertex(t, index(t, v)); | |
| 297 | ✗ | } while(t != vt); | |
| 298 | } | ||
| 299 | |||
| 300 | // Step 2: Sort the neighbors and remove all duplicates | ||
| 301 | ✗ | sort_unique(neighbors); | |
| 302 | ✗ | } | |
| 303 | |||
| 304 | ✗ | void Delaunay::store_neighbors_CB(index_t i) { | |
| 305 | // TODO: this one is not multithread-friendly | ||
| 306 | // since it does dynamic memory allocation | ||
| 307 | // (but not really a problem, since the one | ||
| 308 | // that is used is in Delaunay_ANN). | ||
| 309 | vector<index_t> neighbors; | ||
| 310 | ✗ | get_neighbors_internal(i, neighbors); | |
| 311 | ✗ | neighbors_.set_array(i, neighbors); | |
| 312 | ✗ | } | |
| 313 | |||
| 314 | ✗ | void Delaunay::update_v_to_cell() { | |
| 315 | ✗ | geo_assert(!is_locked_); // Not thread-safe | |
| 316 | ✗ | is_locked_ = true; | |
| 317 | |||
| 318 | // Note: if keeps_infinite is set, then infinite vertex | ||
| 319 | // tet chaining is at t2v_[nb_vertices]. | ||
| 320 | |||
| 321 | ✗ | if(keeps_infinite()) { | |
| 322 | ✗ | v_to_cell_.assign(nb_vertices()+1, NO_INDEX); | |
| 323 | ✗ | for(index_t c = 0; c < nb_cells(); c++) { | |
| 324 | ✗ | for(index_t lv = 0; lv < cell_size(); lv++) { | |
| 325 | index_t v = cell_vertex(c, lv); | ||
| 326 | ✗ | if(v == NO_INDEX) { | |
| 327 | v = nb_vertices(); | ||
| 328 | } | ||
| 329 | ✗ | v_to_cell_[v] = c; | |
| 330 | } | ||
| 331 | } | ||
| 332 | } else { | ||
| 333 | ✗ | v_to_cell_.assign(nb_vertices(), NO_INDEX); | |
| 334 | ✗ | for(index_t c = 0; c < nb_cells(); c++) { | |
| 335 | ✗ | for(index_t lv = 0; lv < cell_size(); lv++) { | |
| 336 | ✗ | v_to_cell_[cell_vertex(c, lv)] = c; | |
| 337 | } | ||
| 338 | } | ||
| 339 | } | ||
| 340 | ✗ | is_locked_ = false; | |
| 341 | ✗ | } | |
| 342 | |||
| 343 | ✗ | void Delaunay::update_cicl() { | |
| 344 | ✗ | geo_assert(!is_locked_); // Not thread-safe | |
| 345 | ✗ | is_locked_ = true; | |
| 346 | ✗ | cicl_.resize(cell_size() * nb_cells()); | |
| 347 | |||
| 348 | ✗ | for(index_t v = 0; v < nb_vertices(); ++v) { | |
| 349 | ✗ | index_t t = v_to_cell_[v]; | |
| 350 | ✗ | if(t != NO_INDEX) { | |
| 351 | ✗ | index_t lv = index(t, v); | |
| 352 | set_next_around_vertex(t, lv, t); | ||
| 353 | } | ||
| 354 | } | ||
| 355 | |||
| 356 | ✗ | if(keeps_infinite()) { | |
| 357 | |||
| 358 | { | ||
| 359 | // Process the infinite vertex at index nb_vertices(). | ||
| 360 | ✗ | index_t t = v_to_cell_[nb_vertices()]; | |
| 361 | ✗ | if(t != NO_INDEX) { | |
| 362 | ✗ | index_t lv = index(t, NO_INDEX); | |
| 363 | set_next_around_vertex(t, lv, t); | ||
| 364 | } | ||
| 365 | } | ||
| 366 | |||
| 367 | ✗ | for(index_t t = 0; t < nb_cells(); ++t) { | |
| 368 | ✗ | for(index_t lv = 0; lv < cell_size(); ++lv) { | |
| 369 | index_t v = cell_vertex(t, lv); | ||
| 370 | ✗ | index_t vv = (v == NO_INDEX) ? nb_vertices() : v; | |
| 371 | ✗ | if(v_to_cell_[vv] != t) { | |
| 372 | index_t t1 = v_to_cell_[vv]; | ||
| 373 | ✗ | index_t lv1 = index(t1, v); | |
| 374 | index_t t2 = next_around_vertex(t1, lv1); | ||
| 375 | set_next_around_vertex(t1, lv1, t); | ||
| 376 | set_next_around_vertex(t, lv, t2); | ||
| 377 | } | ||
| 378 | } | ||
| 379 | } | ||
| 380 | |||
| 381 | |||
| 382 | } else { | ||
| 383 | ✗ | for(index_t t = 0; t < nb_cells(); ++t) { | |
| 384 | ✗ | for(index_t lv = 0; lv < cell_size(); ++lv) { | |
| 385 | index_t v = cell_vertex(t, lv); | ||
| 386 | ✗ | if(v_to_cell_[v] != t) { | |
| 387 | index_t t1 = v_to_cell_[v]; | ||
| 388 | ✗ | index_t lv1 = index(t1, v); | |
| 389 | index_t t2 = next_around_vertex(t1, lv1); | ||
| 390 | set_next_around_vertex(t1, lv1, t); | ||
| 391 | set_next_around_vertex(t, lv, t2); | ||
| 392 | } | ||
| 393 | } | ||
| 394 | } | ||
| 395 | } | ||
| 396 | |||
| 397 | ✗ | is_locked_ = false; | |
| 398 | ✗ | } | |
| 399 | |||
| 400 | ✗ | void Delaunay::save_histogram(std::ostream& out) const { | |
| 401 | vector<index_t> histogram; | ||
| 402 | ✗ | for(index_t v = 0; v < nb_vertices(); v++) { | |
| 403 | index_t N = neighbors_.array_size(v); | ||
| 404 | ✗ | if(histogram.size() < N) { | |
| 405 | ✗ | histogram.resize(N + 1); | |
| 406 | } | ||
| 407 | ✗ | histogram[N]++; | |
| 408 | } | ||
| 409 | ✗ | for(index_t i = 0; i < histogram.size(); i++) { | |
| 410 | ✗ | out << i << " " << histogram[i] << std::endl; | |
| 411 | } | ||
| 412 | ✗ | } | |
| 413 | |||
| 414 | ✗ | bool Delaunay::cell_is_infinite(index_t c) const { | |
| 415 | geo_debug_assert(c < nb_cells()); | ||
| 416 | ✗ | for(index_t lv=0; lv < cell_size(); ++lv) { | |
| 417 | ✗ | if(cell_vertex(c,lv) == NO_INDEX) { | |
| 418 | return true; | ||
| 419 | } | ||
| 420 | } | ||
| 421 | return false; | ||
| 422 | } | ||
| 423 | |||
| 424 | ✗ | index_t Delaunay::region(index_t t) const { | |
| 425 | geo_argused(t); | ||
| 426 | geo_debug_assert(t < nb_cells()); | ||
| 427 | ✗ | return NO_INDEX; | |
| 428 | } | ||
| 429 | } | ||
| 430 |