1 /* 2 GNU Octave level-set package. 3 Copyright (C) 2013-2014 Daniel Kraft <d@domob.eu> 4 5 This program is free software: you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published by 7 the Free Software Foundation, either version 3 of the License, or 8 (at your option) any later version. 9 10 This program is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with this program. If not, see <http://www.gnu.org/licenses/>. 17 */ 18 19 #ifndef FASTMARCHING_HPP 20 #define FASTMARCHING_HPP 21 22 /* 23 24 Implementation of the fast marching method to numerically solve the 25 Eikonal equation: 26 27 | grad u | = f 28 29 f is assumed to be positive, and also assumed to include the grid spacing 30 already (so that 1 is used as unit distance between grid points). 31 For solving problems with changing sign of f, 32 the domain has to be split into parts with constant sign of f, and if f 33 is negative, a corresponding transformation on f and u has to be performed 34 to make f positive. 35 36 The base grid is rectangular and assumed to "hold all" of the domain, 37 but it is not necessary to set F on the full grid to meaningful values. 38 Only for cells which are not initially marked as "alive" are the 39 neighbours actually ever accessed, and points outside the domain of 40 interest can be set NULL. Those will be assumed to be always 41 too far away to influence interior points, so in particular if f -> infinity 42 towards the boundary we can really ignore those points. 43 44 Each grid cell is represented by a pointed-to object, so that we can easily 45 store pointers to those objects in the grid to access them by indices and 46 find their neighbours, and also in the heap structure used to find the 47 next "narrow band" point to operate on. 48 49 Additionally, it is possible to extend a function g known on the domain boundary 50 "along" the normal direction, such that 51 52 grad u * grad g = 0. 53 54 */ 55 56 #include "Heap.hpp" 57 58 #include <cassert> 59 #include <limits> 60 #include <map> 61 #include <vector> 62 63 namespace fastMarching 64 { 65 66 class Entry; 67 class Grid; 68 69 /** Type used for real numbers. */ 70 typedef double realT; 71 72 /** Define value used to represent "very large" values. */ 73 static const realT LARGE_DIST = std::numeric_limits<realT>::max (); 74 75 /** 76 * Type used to number entries. Signed values are allowed in order to allow 77 * -1 to be a "valid" index. The grid takes care of out-of-range values. 78 */ 79 typedef int indexT; 80 81 /** 82 * Full set of indices. To be precise, this contains N indexT grouped 83 * together, where N is the space dimension we solve the equation in. 84 */ 85 typedef std::vector<indexT> IndexTuple; 86 87 /** Type used to number the dimensions. */ 88 typedef IndexTuple::size_type dimensionT; 89 90 /** Type used for the heap. */ 91 typedef Heap<Entry*, bool (*)(const Entry*, const Entry*)> heapT; 92 93 /** 94 * Method to issue warnings. This is not implemented in FastMarching.cpp 95 * but must be provided by the caller. That way, it can use Octave's 96 * warning infrastructure but still make the FastMarching code itself 97 * independent of Octave. 98 * @param id An ID for the warning. 99 * @param fmt The (printf-like) message template. 100 * @param ... Other arguments for printf-like formatting. 101 */ 102 void issueWarning (const std::string& id, const std::string& fmt, ...); 103 104 /* ************************************************************************** */ 105 /* Update equation class. */ 106 107 /** 108 * Represent and solve the quadratic equation necessary in the fast marching 109 * step for updating the distance of a point from given neighbours. This 110 * is also useful for initialising the narrow-band entries from the level-set 111 * function, and thus available as global class. 112 */ 113 class UpdateEquation 114 { 115 116 private: 117 118 class EqnEntry; 119 120 /** 121 * Map space dimensions to the currently best entry along the given 122 * dimension. It may be null if there's not yet an acceptable entry 123 * there, and there may be multiple entries added for the same dimension 124 * (on both sides of our point). In this case, only the closer one is 125 * relevant, and will be kept in the map. 126 */ 127 typedef std::map<dimensionT, EqnEntry*> entryMapT; 128 129 /** The actual map. */ 130 entryMapT entries; 131 132 /** 133 * Remember whether one of the g values was being absent. If that's 134 * the case, we can't calculate g from the equation. This is enforced. 135 */ 136 bool gMissing; 137 138 /** 139 * When solving, keep track of the actually used and sorted neighbours 140 * for calculating g later on. 141 */ 142 mutable std::vector<const EqnEntry*> sortedEntries; 143 144 /** Store calculated distance value here. */ 145 mutable realT u; 146 147 public: 148 149 /** 150 * Construct it empty. 151 */ UpdateEquation()152 inline UpdateEquation () 153 : entries (), gMissing(false), sortedEntries(), u(0.0) 154 {} 155 156 /** 157 * Destruct and free all memory held in the entries map. 158 */ 159 ~UpdateEquation (); 160 161 // No copying. 162 UpdateEquation (const UpdateEquation&) = delete; 163 UpdateEquation& operator= (const UpdateEquation&) = delete; 164 165 /** 166 * Add a new entry. The entry is characterised by the dimension along 167 * which it neighbours the cell being calculated, the distance (grid spacing) 168 * to it and the distance value at the neighbour. Using this function 169 * without a parameter for g flags the equation as missing g values, 170 * which means that getExtendedFunction does not work. 171 * @param d Dimension along which the point neighbours the centre. 172 * @param h Grid spacing to the neighbour. 173 * @param u Value of the distance function at the neighbour. 174 */ 175 inline void add(dimensionT d,realT h,realT u)176 add (dimensionT d, realT h, realT u) 177 { 178 add (d, h, u, 0.0); 179 gMissing = true; 180 } 181 182 /** 183 * Add a new entry together with g. 184 * @param d Dimension along which the point neighbours the centre. 185 * @param h Grid spacing to the neighbour. 186 * @param u Value of the distance function at the neighbour. 187 * @param g Value of the extended function at the neighbour. 188 */ 189 void add (dimensionT d, realT h, realT u, realT g); 190 191 /** 192 * Calculate the new distance value solving the quadratic equation. 193 * @param f Speed value at the current cell. 194 * @return Distance value at the centre cell. 195 */ 196 realT solve (realT f) const; 197 198 /** 199 * Calculate the value of the extended function at the centre. This 200 * can only be used if all g values were given for all entries, and 201 * if solve() was already called. 202 * @return The value of the extended function at the centre. 203 * @throws std::logic_error if the equation was built without all g's. 204 * @throws std::logic_error if solve() was not yet called. 205 */ 206 realT getExtendedFunction () const; 207 208 }; 209 210 /** 211 * The equation entry class. This simply holds some data. 212 */ 213 class UpdateEquation::EqnEntry 214 { 215 216 public: 217 218 /** The neighbour's distance on the grid. */ 219 realT h; 220 221 /** The neighbour's distance value. */ 222 realT u; 223 224 /** The neighbour's extended function value. */ 225 realT g; 226 227 /* Note that we don't need the dimension, since this is already part 228 of the map in UpdateEquation anyway. */ 229 230 /** 231 * Construct it given all the data. 232 * @param mh Grid distance. 233 * @param mu Distance value. 234 * @param mg Extended function value. 235 */ EqnEntry(realT mh,realT mu,realT mg)236 inline EqnEntry (realT mh, realT mu, realT mg) 237 : h(mh), u(mu), g(mg) 238 {} 239 240 // No copying or default constructor, since it is not needed. 241 EqnEntry () = delete; 242 EqnEntry (const EqnEntry&) = delete; 243 EqnEntry& operator= (const EqnEntry&) = delete; 244 245 /** 246 * Get the "effective distance" that this point would imply for the 247 * centre, which is the distance if only this point would be there. It 248 * is used for deciding which one of two neighbours along a single dimension 249 * is the one to use, and also for sorting later on. 250 * @return The effective distance, which is u + h. 251 */ 252 inline realT getEffDistance() const253 getEffDistance () const 254 { 255 /* Note: The roles of u and h in the quadratic equation being solved 256 are not entirely the same, so it is not clear whether this 257 "effective distance" is really the right criterion to decide upon which 258 point to use. However, in the cases actually used, either h is the 259 same along a dimension (grid spacing) or u is zero everywhere (initial 260 distances from the level-set function). For those, this concept should 261 work at least. */ 262 263 return u + h; 264 } 265 266 /** 267 * Compare two entry pointers for sorting by distance. If the distances 268 * are equal, we compare the pointers just to get a criterion to avoid 269 * false classification as being equal (which might confuse the sorting 270 * algorithm). 271 * @param a First pointer. 272 * @param b Second pointer. 273 * @return True iff a < b. 274 */ 275 static inline bool compare(const EqnEntry * a,const EqnEntry * b)276 compare (const EqnEntry* a, const EqnEntry* b) 277 { 278 const realT diff = a->getEffDistance () - b->getEffDistance (); 279 if (diff != 0.0) 280 return (diff < 0.0); 281 282 return (a < b); 283 } 284 285 }; 286 287 /* ************************************************************************** */ 288 /* Single cell entry. */ 289 290 /** 291 * This class represents all data stored for a single grid point. It also 292 * has the ability to do cell-related calculations, and update itself solving 293 * the respective quadratic equation. 294 */ 295 class Entry 296 { 297 298 public: 299 300 /** Possible states of a cell during processing. */ 301 enum State 302 { 303 ALIVE, 304 NARROW_BAND, 305 FAR_AWAY 306 }; 307 308 private: 309 310 /** Value of f at the given point. */ 311 const realT f; 312 313 /** Current value of u. */ 314 realT u; 315 /** Current value of the extended function g. */ 316 realT g; 317 318 /** Current state. */ 319 State state; 320 321 /** 322 * Index of this grid cell. This is used to find the neighbours 323 * in the updating calculation. 324 */ 325 const IndexTuple coord; 326 327 /** Entry into the heap in case we're in narrow band. */ 328 heapT::Entry heapEntry; 329 330 /** 331 * Construct the cell entry given the data. 332 * @param s Initial state. 333 * @param c Coordinate in the grid. 334 * @param mf Value of f at this position. 335 * @param mu Distance value. 336 * @param mg Value for extended function. 337 */ Entry(State s,const IndexTuple & c,realT mf,realT mu,realT mg)338 inline Entry (State s, const IndexTuple& c, realT mf, realT mu, realT mg) 339 : f(mf), u(mu), g(mg), state(s), coord(c), heapEntry(nullptr) 340 { 341 assert (s == ALIVE || s == FAR_AWAY); 342 } 343 344 public: 345 346 /* No copying or default constructor. */ 347 Entry () = delete; 348 Entry (const Entry& o) = delete; 349 Entry& operator= (const Entry& o) = delete; 350 351 /** 352 * Construct the entry for an initially alive cell. 353 * @param c Coordinate for it. 354 * @param u Initial distance. 355 * @param g Initial function value. 356 */ 357 static inline newAlive(const IndexTuple & c,realT u,realT g)358 Entry* newAlive (const IndexTuple& c, realT u, realT g) 359 { 360 /* f is not necessary, set to dummy value. */ 361 return new Entry (ALIVE, c, 0.0, u, g); 362 } 363 364 /** 365 * Construct the entry for an initially far away cell. 366 * @param c Coordinate for it. 367 * @param f Value of f. 368 */ 369 static inline newFarAway(const IndexTuple & c,realT f)370 Entry* newFarAway (const IndexTuple& c, realT f) 371 { 372 /* g0 is not necessary (will be overwritten), set to dummy value. */ 373 return new Entry (FAR_AWAY, c, f, LARGE_DIST, 0.0); 374 } 375 376 /** 377 * Get current value of u. 378 * @return Current value of u for this cell. 379 */ 380 inline realT getDistance() const381 getDistance () const 382 { 383 return u; 384 } 385 386 /** 387 * Get value of extended function g. 388 * @return Current value of g for this cell. 389 */ 390 inline realT getFunction() const391 getFunction () const 392 { 393 return g; 394 } 395 396 /** 397 * Get index coordinate. This is used by the grid to put the cell into 398 * the correct place when initialising. 399 * @return This entry's coordinate. 400 */ 401 inline const IndexTuple& getCoordinate() const402 getCoordinate () const 403 { 404 return coord; 405 } 406 407 /** 408 * Get the current state. 409 * @return The current state. 410 */ 411 inline State getState() const412 getState () const 413 { 414 return state; 415 } 416 417 /** 418 * Set state to alive. 419 * @see setNarrowBand 420 */ 421 void setAlive (); 422 423 /** 424 * Set state to narrow band, adding also the heap entry. 425 * @param e Heap entry. 426 * @see setState 427 */ 428 void setNarrowBand (const heapT::Entry& e); 429 430 /** 431 * Update distance value from the neighbours. They are found 432 * using our coordinates and the given grid, and the heap is 433 * automatically bubbled for the change to take place. 434 * This may raise assertion failures under certain conditions. 435 * @param grid The grid to use to access neighbours. 436 */ 437 void update (const Grid& grid); 438 439 /** 440 * Compare two elements as they should be compared for the heap 441 * data structure. Since the heap has the largest element first and 442 * that should correspond to smallest distance, return ordering 443 * induced by ">" on u. Because the heap 444 * will be based on pointers to entries, this function also works on them. 445 * @param a First entry. 446 * @param b Second entry. 447 * @return True iff a should be accessed later than b, which is equivalent 448 * to a.u > b.u. 449 */ 450 static inline bool compareForHeap(const Entry * a,const Entry * b)451 compareForHeap (const Entry* a, const Entry* b) 452 { 453 assert (a && b); 454 return a->u > b->u; 455 } 456 457 }; 458 459 /* ************************************************************************** */ 460 /* Full grid. */ 461 462 /** 463 * This class represents a full grid, which also keeps track of the high-level 464 * data structures during the solve. 465 */ 466 class Grid 467 { 468 469 private: 470 471 /** Size of the grid. */ 472 const IndexTuple size; 473 474 /** 475 * Store pointers to the grid entries "by index" here. This is the 476 * multi-dimensional array mapped to a single dimension. Some entries 477 * may be NULL, which means that those are outside of the domain 478 * we're interested in. 479 */ 480 std::vector<Entry*> entries; 481 482 /** Keep track of points currently in "narrow band" state. */ 483 heapT narrowBand; 484 485 /** 486 * Calculate index into entries for given coordinates. 487 * @param c Coordinates in indices. 488 * @return Single index into entries or -1 if c is out of range. 489 */ 490 indexT lineariseIndex (const IndexTuple& c) const; 491 492 /** 493 * Perform a single update step on the currently best next narrow-band 494 * entry. It is removed and set alive, and its neighbours are then 495 * added into the narrow-band if not yet there and updated. 496 */ 497 void update (); 498 499 /** 500 * Recalculate neighbours of a given entry. This is used both for 501 * update and initialisation of narrow band. 502 * @param center Recalculate this entry's neighbours. 503 */ 504 void recalculateNeighbours (const Entry& center); 505 506 /** 507 * Get grid cell by index, mutable version for internal use. 508 * @param c Index coordinate tuple. 509 * @return The corresponding entry pointer. 510 * @see get (const IndexTuple&) 511 */ 512 inline Entry* get(const IndexTuple & c)513 get (const IndexTuple& c) 514 { 515 const indexT ind = lineariseIndex (c); 516 if (ind < 0) 517 return nullptr; 518 return entries[ind]; 519 } 520 521 /** 522 * Internal routine used for iterate(), that is called recursively 523 * to perform the required number of nested loops. 524 * @param cur Current index tuple, will be built up recursively. 525 * @param depth Current depth in the recursion. 526 * @param f The call-back to call for each cell index. 527 */ 528 template<typename F> 529 void iterate (IndexTuple& cur, dimensionT depth, const F& f) const; 530 531 public: 532 533 /* No copying or default constructor. */ 534 Grid () = delete; 535 Grid (const Grid& o) = delete; 536 Grid& operator= (const Grid& o) = delete; 537 538 /** 539 * Construct the grid with a given size. The entries will be empty 540 * and will still have to be filled in. 541 * @param s Size to use. 542 */ 543 Grid (const IndexTuple& s); 544 545 /** 546 * Destructor, freeing all memory. 547 */ 548 ~Grid (); 549 550 /** 551 * Initialise a given grid cell by the given entry. The coordinate 552 * where to put the entry is taken from the object itself, and an 553 * error is raised if that entry is already filled in. The entries 554 * state must be either "alive" or "far away", narrow band is 555 * automatically initialised later on. 556 * @param e The new entry. Ownership is taken over. 557 * @throws std::invalid_argument if something is wrong with e. 558 */ 559 void setInitial (Entry* e); 560 561 /** 562 * Get grid cell by index. Returned is the pointer, which may be NULL 563 * in case this cell is outside the domain or even the index range given 564 * outside the size. 565 * @param c Index coordinate tuple. 566 * @return The corresponding entry pointer. 567 */ 568 inline const Entry* get(const IndexTuple & c) const569 get (const IndexTuple& c) const 570 { 571 const indexT ind = lineariseIndex (c); 572 if (ind < 0) 573 return nullptr; 574 return entries[ind]; 575 } 576 577 /** 578 * Perform the calculation, updating all narrow-band entries until 579 * all of them are alive. It is necessary to have narrow-band already 580 * filled in, meaning that far-away entries not reached by the propagation 581 * from any narrow-band will not be updated! 582 */ 583 void perform (); 584 585 /** 586 * Iterate over all cells of the given grid and call the provided 587 * call-back routine with the coordinate as IndexTuple. 588 * @param f The call-back to call for each cell index. 589 */ 590 template<typename F> 591 inline void iterate(const F & f) const592 iterate (const F& f) const 593 { 594 IndexTuple cur(size.size ()); 595 iterate (cur, 0, f); 596 } 597 598 /** 599 * Iterate over all neighbours of a given index. For each neighbour that 600 * is still on the grid, call the provided function with its index. 601 * @param c The centre coordinate. 602 * @param f The call-back to call for each neighbour. 603 */ 604 template<typename F> 605 void iterateNeighbours (const IndexTuple& c, const F& f) const; 606 607 }; 608 609 /* ************************************************************************** */ 610 611 } // Namespace fastMarching. 612 613 /* Include template implementations. */ 614 #include "FastMarching.tpp" 615 616 #endif /* Header guard. */ 617