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