Ocean
SpatialDistribution.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) Meta Platforms, Inc. and affiliates.
3  *
4  * This source code is licensed under the MIT license found in the
5  * LICENSE file in the root directory of this source tree.
6  */
7 
8 #ifndef META_OCEAN_GEOMETRY_SPATIAL_DISTRIBUTION_H
9 #define META_OCEAN_GEOMETRY_SPATIAL_DISTRIBUTION_H
10 
12 
13 #include "ocean/base/Utilities.h"
14 
15 #include "ocean/math/Box2.h"
16 
17 #include <algorithm>
18 
19 namespace Ocean
20 {
21 
22 namespace Geometry
23 {
24 
25 /**
26  * This class implements spatial distribution function for 2D geometric data.
27  * @ingroup geometry
28  */
29 class OCEAN_GEOMETRY_EXPORT SpatialDistribution
30 {
31  public:
32 
33  /**
34  * This class implements a base class for data arrays.
35  */
36  class OCEAN_GEOMETRY_EXPORT Array
37  {
38  public:
39 
40  /**
41  * Returns the left position of the distribution area.
42  * @return Left position
43  */
44  inline Scalar left() const;
45 
46  /**
47  * Returns the top position of the distribution area.
48  * @return Top position
49  */
50  inline Scalar top() const;
51 
52  /**
53  * Returns the width of the distribution area.
54  * @return Area width
55  */
56  inline Scalar width() const;
57 
58  /**
59  * Returns the height of the distribution area.
60  * @return Area height
61  */
62  inline Scalar height() const;
63 
64  /**
65  * Returns the number of horizontal distribution bins.
66  * @return Number of bins
67  */
68  inline unsigned int horizontalBins() const;
69 
70  /**
71  * Returns the number of vertical distribution bins.
72  * @return Number of bins
73  */
74  inline unsigned int verticalBins() const;
75 
76  /**
77  * Returns the number of bins this distribution holds.
78  * @return Bin number
79  */
80  inline unsigned int bins() const;
81 
82  /**
83  * Returns the bin index for a given position.
84  * Beware: Make sure that the given position is inside the specified range!
85  * @param x Horizontal position, with range [0, width())
86  * @param y Vertical position, with range [0, height())
87  * @return Resulting bin index
88  */
89  inline unsigned int index(const Scalar x, const Scalar y) const;
90 
91  /**
92  * Returns the horizontal bin of a given horizontal position.
93  * Beware: The resulting bin can exceed the bin-ranges of the array.<br>
94  * @param x Horizontal position, with range (-infinity, infinity)
95  * @return Horizontal bin, with range (-infinity, infinity)
96  * @see clampedHorizontalBin().
97  */
98  inline int horizontalBin(const Scalar x) const;
99 
100  /**
101  * Returns the vertical bin of a given vertical position.
102  * Beware: The resulting bin can exceed the bin-ranges of the array.<br>
103  * @param y Vertical position, with range (-infinity, infinity)
104  * @return Vertical bin, with range (-infinity, infinity)
105  * @see clampedVerticalBin().
106  */
107  inline int verticalBin(const Scalar y) const;
108 
109  /**
110  * Returns the horizontal bin of a given horizontal position.
111  * Beware: The resulting bin is clamped into the range [0, number of bins - 1).<br>
112  * @param x Horizontal position, with range (-infinity, infinity)
113  * @return Horizontal bin, with range [0, horizontalBins() - 1]
114  * @see horizontalBin().
115  */
116  inline int clampedHorizontalBin(const Scalar x) const;
117 
118  /**
119  * Returns the vertical bin of a given vertical position.
120  * Beware: The resulting bin is clamped into the range [0, number of bins - 1).<br>
121  * @param y Vertical position, with range (-infinity, infinity)
122  * @return Vertical bin, with range [0, verticalBins() - 1]
123  * @see clampedVerticalBin().
124  */
125  inline int clampedVerticalBin(const Scalar y) const;
126 
127  /**
128  * Returns whether this object holds a valid distribution.
129  * @return True, if so
130  */
131  inline bool isValid() const;
132 
133  /**
134  * Returns whether two Array objects are identical.
135  * @param right The second array object to compare
136  * @return True, if so
137  */
138  inline bool operator==(const Array& right) const;
139 
140  /**
141  * Returns whether two Array objects are not identical.
142  * @param right The second array object to compare
143  * @return True, if so
144  */
145  inline bool operator!=(const Array& right) const;
146 
147  /**
148  * Returns whether this object holds a valid distribution.
149  * @return True, if so
150  */
151  explicit inline operator bool() const;
152 
153  protected:
154 
155  /**
156  * Creates an empty array object.
157  */
158  Array() = default;
159 
160  /**
161  * Copy constructor.
162  * @param object The array object to be copied
163  */
164  Array(const Array& object) = default;
165 
166  /**
167  * Move constructor.
168  * @param object The array object to be moved
169  */
170  inline Array(Array&& object) noexcept;
171 
172  /**
173  * Creates a new array object.
174  * @param left The left area position, with range (-infinity, infinity)
175  * @param top The top area position, with range (-infinity, infinity)
176  * @param width The width of the distribution area, with range (0, infinity)
177  * @param height The height of the distribution area, with range (0, infinity)
178  * @param horizontalBins Number of horizontal distribution bins, with range [1, infinity)
179  * @param verticalBins Number of vertical distribution bins, with range [1, infinity)
180  */
181  inline Array(const Scalar left, const Scalar top, const Scalar width, const Scalar height, const unsigned int horizontalBins, const unsigned int verticalBins);
182 
183  /**
184  * Assign operator.
185  * @param object The object to be assigned
186  * @return Reference to this object
187  */
188  inline Array& operator=(const Array& object);
189 
190  /**
191  * Move operator.
192  * @param object The object to be moved
193  * @return Reference to this object
194  */
195  inline Array& operator=(Array&& object) noexcept;
196 
197  protected:
198 
199  /// Left position of the distribution area.
200  Scalar areaLeft_ = Scalar(0);
201 
202  /// Top position of the distribution area.
203  Scalar areaTop_ = Scalar(0);
204 
205  /// Width of the distribution area.
206  Scalar areaWidth_ = Scalar(0);
207 
208  /// Height of the distribution area.
209  Scalar areaHeight_ = Scalar(0);
210 
211  /// Number of horizontal distribution bins.
212  unsigned int horizontalBins_ = 0u;
213 
214  /// Number of vertical distribution bins.
215  unsigned int verticalBins_ = 0u;
216 
217  /// Horizontal position to bin factor.
218  Scalar horizontalPoint2Bin_ = Scalar(0);
219 
220  /// Vertical position to bin factor.
221  Scalar verticalPoint2Bin_ = Scalar(0);
222  };
223 
224  /**
225  * This class implements a distribution array.
226  */
227  class OCEAN_GEOMETRY_EXPORT DistributionArray : public Array
228  {
229  public:
230 
231  /**
232  * Creates an empty distribution array object.
233  */
234  DistributionArray() = default;
235 
236  /**
237  * Copy constructor.
238  * @param object The object to be copied
239  */
240  DistributionArray(const DistributionArray& object) = default;
241 
242  /**
243  * Move constructor.
244  * @param object The object to be copied
245  */
246  inline DistributionArray(DistributionArray&& object) noexcept;
247 
248  /**
249  * Creates a new distribution array object.
250  * @param left The left area position, with range (-infinity, infinity)
251  * @param top The top area position, with range (-infinity, infinity)
252  * @param width The width of the distribution area, with range (0, infinity)
253  * @param height The height of the distribution area, with range (0, infinity)
254  * @param horizontalBins Number of horizontal distribution bins, with range [1, infinity)
255  * @param verticalBins Number of vertical distribution bins, with range [1, infinity)
256  */
257  inline DistributionArray(const Scalar left, const Scalar top, const Scalar width, const Scalar height, const unsigned int horizontalBins, const unsigned int verticalBins);
258 
259  /**
260  * Copies a given distribution array and optional copies the indices from the 8-neighborhood of each individual bin to the bin in the center of the neighborhood.
261  * The resulting distribution array can be used to speed-up the search for nearest neighbors if the distribution array is reused several times.<br>
262  * Instead of gathering neighboring indices via indicesNeighborhood9(), each bin contains all indices of the 9 neighborhood already.
263  * @param distributionArray The distribution array to be copied
264  * @param copyNeighborhood8 True, to copy the 8-neighborhood of each individual bin to the bin in the center of the neighborhood; False to create a simple copy of the distribution array
265  * @see hasCopiedNeighborhood8().
266  */
267  DistributionArray(const DistributionArray& distributionArray, const bool copyNeighborhood8);
268 
269  /**
270  * Returns the indices of the 8-neighborhood and the specified bin itself.
271  * @param horizontal The horizontal distribution bin, with range [0, horizontalBins() - 1]
272  * @param vertical The vertical distribution bin, with range [0, verticalBins() - 1]
273  * @return Indices of the 9 neighboring bins
274  * @see hasCopiedNeighborhood8().
275  */
276  Indices32 indicesNeighborhood9(const unsigned int horizontal, const unsigned int vertical) const;
277 
278  /**
279  * Returns the indices of the 8-neighborhood and the specified bin itself.
280  * @param horizontal The horizontal distribution bin, with range [0, horizontalBins() - 1]
281  * @param vertical The vertical distribution bin, with range [0, verticalBins() - 1]
282  * @param indices Resulting indices of the 9 neighboring bins
283  * @see hasCopiedNeighborhood8().
284  */
285  void indicesNeighborhood9(const unsigned int horizontal, const unsigned int vertical, Indices32& indices) const;
286 
287  /**
288  * Returns whether this distribution array contains copies of indices within the 8-neighborhood of each individual bin.
289  * @return True, if so
290  */
291  inline bool hasCopiedNeighborhood8() const;
292 
293  /**
294  * Removes all elements form this array.
295  */
296  void clear();
297 
298  /**
299  * Returns the distribution indices of a specified bin.
300  * @param horizontal The horizontal distribution bin, with range [0, horizontalBins() - 1]
301  * @param vertical The vertical distribution bin, with range [0, verticalBins() - 1]
302  * @return Specified distribution indices
303  */
304  inline const Indices32& operator()(const unsigned int horizontal, const unsigned int vertical) const;
305 
306  /**
307  * Returns the distribution indices of a specified bin.
308  * @param horizontal The horizontal distribution bin, with range [0, horizontalBins() - 1]
309  * @param vertical The vertical distribution bin, with range [0, verticalBins() - 1]
310  * @return Specified distribution indices
311  */
312  inline Indices32& operator()(const unsigned int horizontal, const unsigned int vertical);
313 
314  /**
315  * Returns the distribution indices of a specified bin.
316  * The bins are stored in a row aligned order.
317  * @param index The index of the specified bin, with range [0, horizontalBins() * verticalBins() - 1]
318  * @return Specified distribution indices
319  */
320  inline const Indices32& operator[](const unsigned int index) const;
321 
322  /**
323  * Returns the distribution indices of a specified bin.
324  * The bins are stored in a row aligned order.
325  * @param index The index of the specified bin, with range [0, horizontalBins() * verticalBins() - 1]
326  * @return Specified distribution indices
327  */
328  inline Indices32& operator[](const unsigned int index);
329 
330  /**
331  * Assign operator.
332  * @param object The object to be assigned
333  * @return Reference to this object
334  */
335  inline DistributionArray& operator=(const DistributionArray& object);
336 
337  /**
338  * Move operator.
339  * @param object The object to be moved
340  */
341  inline DistributionArray& operator=(DistributionArray&& object) noexcept;
342 
343  /**
344  * Returns whether two DistributionArray objects are identical.
345  * @param distributionArray The second array object to compare
346  * @return True, if so
347  */
348  inline bool operator==(const DistributionArray& distributionArray) const;
349 
350  /**
351  * Returns whether two DistributionArray objects are not identical.
352  * @param distributionArray The second array object to compare
353  * @return True, if so
354  */
355  inline bool operator!=(const DistributionArray& distributionArray) const;
356 
357  private:
358 
359  /// Distribution array with point indices.
361 
362  /// True, if the array contains copies of indices within the 8-neighborhood of each individual bin; False, if each bin contains the indices of the actual bin only
363  bool hasCopiedNeighborhood8_ = false;
364  };
365 
366  /**
367  * This class implements an occupancy array.
368  */
369  class OCEAN_GEOMETRY_EXPORT OccupancyArray : public Array
370  {
371  public:
372 
373  /**
374  * Creates an empty distribution array object.
375  */
376  OccupancyArray() = default;
377 
378  /**
379  * Copy constructor.
380  * @param object Occupancy array object to be copied
381  */
382  OccupancyArray(const OccupancyArray& object) = default;
383 
384  /**
385  * Move constructor.
386  * @param object Occupancy array object to be move
387  */
388  inline OccupancyArray(OccupancyArray&& object) noexcept;
389 
390  /**
391  * Creates a new distribution array object.
392  * @param boundingBox The bounding box defining the position and dimension of the area, must be valid
393  * @param horizontalBins Number of horizontal distribution bins, with range [1, infinity)
394  * @param verticalBins Number of vertical distribution bins, with range [1, infinity)
395  * @param allFree True, to set all bins as free; False, to set all bins as occupied
396  */
397  inline OccupancyArray(const Box2& boundingBox, const unsigned int horizontalBins, const unsigned int verticalBins, const bool allFree = true);
398 
399  /**
400  * Creates a new distribution array object.
401  * @param left The left area position, with range (-infinity, infinity)
402  * @param top The top area position, with range (-infinity, infinity)
403  * @param width The width of the distribution area, with range (0, infinity)
404  * @param height The height of the distribution area, with range (0, infinity)
405  * @param horizontalBins Number of horizontal distribution bins, with range [1, infinity)
406  * @param verticalBins Number of vertical distribution bins, with range [1, infinity)
407  * @param allFree True, to set all bins as free; False, to set all bins as occupied
408  */
409  inline OccupancyArray(const Scalar left, const Scalar top, const Scalar width, const Scalar height, const unsigned int horizontalBins, const unsigned int verticalBins, const bool allFree = true);
410 
411  /**
412  * Returns whether at least one bin in the 8-neighborhood or the specified bin itself is occupied.
413  * @param horizontal The horizontal distribution bin, with range [0, horizontalBins() - 1]
414  * @param vertical The vertical distribution bin, with range [0, verticalBins() - 1]
415  * @return True, if so
416  */
417  inline bool isOccupiedNeighborhood9(const unsigned int horizontal, const unsigned int vertical) const;
418 
419  /**
420  * Returns whether at least one bin in the 8-neighborhood or the specified bin itself is occupied.
421  * @param point The point for that the 9-neighborhood bins have to be checked, with range (-infinity, infinity)x(-infinity, infinity)
422  * @return True, if so
423  */
424  inline bool isOccupiedNeighborhood9(const Vector2& point) const;
425 
426  /**
427  * Returns whether at least one bin in the 8-neighborhood or the specified bin itself is not occupied.
428  * @param horizontal The horizontal distribution bin, with range [0, horizontalBins() - 1]
429  * @param vertical The vertical distribution bin, with range [0, verticalBins() - 1]
430  * @return True, if so
431  */
432  inline bool isNotOccupiedNeighborhood9(const unsigned int horizontal, const unsigned int vertical) const;
433 
434  /**
435  * Returns whether at least one bin in the 8-neighborhood or the specified bin itself is not occupied.
436  * @param point The point for that the 9-neighborhood bins have to be checked, with range (-infinity, infinity)x(-infinity, infinity)
437  * @return True, if so
438  */
439  inline bool isNotOccupiedNeighborhood9(const Vector2& point) const;
440 
441  /**
442  * Returns the number of occupied bins in the 9-neighborhood (so the specified bin is included).
443  * @param horizontal The horizontal distribution bin, with range [0, horizontalBins() - 1]
444  * @param vertical The vertical distribution bin, with range [0, verticalBins() - 1]
445  * @return The number of occupied bins
446  */
447  inline unsigned int countOccupiedNeighborhood9(const unsigned int horizontal, const unsigned int vertical) const;
448 
449  /**
450  * Returns the number of occupied bins.
451  * @return Bin number
452  */
453  inline unsigned int occupiedBins() const;
454 
455  /**
456  * Returns the number of free bins.
457  * @return Bin number
458  */
459  inline unsigned int freeBins() const;
460 
461  /**
462  * Adds an image point and returns whether the corresponding bin was not occupied before (was free before).
463  * If the point lies outside the array False is returned.<br>
464  * The bin (if valid) which belongs to the given point is occupied after the function returns.
465  * @param point The point to be added, with range (-infinity, infinity)x(-infinity, infinity)
466  * @return True, if so
467  */
468  inline bool addPoint(const Vector2& point);
469 
470  /**
471  * Adds an image point and returns whether the occupancy counter of the corresponding bin was equal or below a specified value.
472  * If the point lies outside the array False is returned.<br>
473  * The occupancy counter of the bin (if valid) to which the given point belongs will be incremented.<br>
474  * Beware: This function should not be used in conjunction with any other addPoint(), removePoint() function not leveraging a occupancy counter.
475  * @param point The point to be added, with range (-infinity, infinity)x(-infinity, infinity)
476  * @param maximalOccupancyCounter The maximal occupancy counter the corresponding bin may have to add the point.
477  * @return True, if so
478  */
479  inline bool addPointWithCounter(const Vector2& point, const unsigned int maximalOccupancyCounter);
480 
481  /**
482  * Removes an image point and returns whether the corresponding bin was occupied before.
483  * If the point lies outside the array False is returned.<br>
484  * The bin (if valid) which belongs to the given point is free (not occupied) after the function returns.
485  * @param point The point to be removed, with range (-infinity, infinity)x(-infinity, infinity)
486  * @return True, if so
487  */
488  inline bool removePoint(const Vector2& point);
489 
490  /**
491  * Resets all occupied bins so that all bins a free afterwards.
492  */
493  inline void reset();
494 
495  /**
496  * Adds an image point to this occupancy array.
497  * The bin (if valid) which belongs to the given point is occupied after the function returns.
498  * @param point The point to be added, with range (-infinity, infinity)x(-infinity, infinity)
499  * @return Reference to this object
500  */
501  inline OccupancyArray& operator+=(const Vector2& point);
502 
503  /**
504  * Removes an image point from this occupancy array.
505  * The bin (if valid) which belongs to the given point is free (not occupied) after the function returns.
506  * @return Reference to this object
507  */
508  inline OccupancyArray& operator-=(const Vector2& point);
509 
510  /**
511  * Returns whether a specified bin is occupied.
512  * @param horizontal The horizontal distribution bin, with range [0, horizontalBins() - 1]
513  * @param vertical The vertical distribution bin, with range [0, verticalBins() - 1]
514  * @return True, if so
515  */
516  inline bool operator()(const unsigned int horizontal, const unsigned int vertical) const;
517 
518  /**
519  * Returns whether the bin corresponding to a given point is occupied.
520  * @param point The point for which the bin has to be checked, with range (-infinity, infinity)x(-infinity, infinity)
521  * @return True, if so
522  */
523  inline bool operator()(const Vector2& point) const;
524 
525  /**
526  * Returns whether a specified bin is occupied.
527  * @param horizontal The horizontal distribution bin, with range [0, horizontalBins() - 1]
528  * @param vertical The vertical distribution bin, with range [0, verticalBins() - 1]
529  * @return Non-zero, if so
530  */
531  inline unsigned int& operator()(const unsigned int horizontal, const unsigned int vertical);
532 
533  /**
534  * Returns whether a specified bin is occupied.
535  * @param index The index of the specified bin, with range [0, horizontalBins() * verticalBins() - 1]
536  * @return True, if so
537  */
538  inline bool operator[](const unsigned int index) const;
539 
540  /**
541  * Returns whether a specified bin is occupied.
542  * @param index The index of the specified bin, with range [0, horizontalBins() * verticalBins() - 1]
543  * @return Non-zero, if so
544  */
545  inline unsigned int& operator[](const unsigned int index);
546 
547  /**
548  * Assign operator.
549  * @param object Occupancy array object to be assigned
550  * @return Reference to this object
551  */
552  inline OccupancyArray& operator=(const OccupancyArray& object);
553 
554  /**
555  * Move operator.
556  * @param object Occupancy array object to be moved
557  * @return Reference to this object
558  */
559  inline OccupancyArray& operator=(OccupancyArray&& object) noexcept;
560 
561  /**
562  * Returns whether two OccupancyArray objects are identical.
563  * @param occupancyArray The second array object to compare
564  * @return True, if so
565  */
566  inline bool operator==(const OccupancyArray& occupancyArray) const;
567 
568  /**
569  * Returns whether two OccupancyArray objects are not identical.
570  * @param occupancyArray The second array object to compare
571  * @return True, if so
572  */
573  inline bool operator!=(const OccupancyArray& occupancyArray) const;
574 
575  private:
576 
577  /// Occupancy array.
579  };
580 
581  /**
582  * Definition of a class holding an index and a distance.
583  */
584  class OCEAN_GEOMETRY_EXPORT DistanceElement
585  {
586  public:
587 
588  /**
589  * Creates a new distance element.
590  * @param index Interest index to be stored
591  * @param candidateIndex Index of the candidate to be stored
592  * @param distance The distance to be stored
593  */
594  inline DistanceElement(const unsigned int index, const unsigned int candidateIndex, const Scalar distance);
595 
596  /**
597  * Returns the interest index of this element.
598  * @return Stored index
599  */
600  inline unsigned int index() const;
601 
602  /**
603  * Returns the candidate index of this element.
604  * @return Stored candidate index
605  */
606  inline unsigned int candidateIndex() const;
607 
608  /**
609  * Returns the distance of this element.
610  * @return Stored distance
611  */
612  inline Scalar distance() const;
613 
614  /**
615  * Compares two distance elements.
616  * @param left The left element to compare
617  * @param right The right element to compare
618  * @return True, if the left element has a smaller distance value than the right one
619  */
620  static inline bool compareLeftSmaller(const DistanceElement& left, const DistanceElement& right);
621 
622  /**
623  * Compares two distance elements.
624  * @param left The left element to compare
625  * @param right The right element to compare
626  * @return True, if the left element has a higher distance value than the right one
627  */
628  static inline bool compareLeftHigher(const DistanceElement& left, const DistanceElement& right);
629 
630  /**
631  * Returns whether the left element holds a higher distance than the right one.
632  * @return True, if so
633  */
634  inline bool operator<(const DistanceElement& element) const;
635 
636  private:
637 
638  /// Interest index.
639  unsigned int index_ = 0u;
640 
641  /// Candidate index.
642  unsigned int candidateIndex_ = 0u;
643 
644  /// Distance value.
645  Scalar distance_ = Scalar(-1);
646  };
647 
648  /**
649  * Definition of a vector holding distance elements.
650  */
651  typedef std::vector<DistanceElement> DistanceElements;
652 
653  public:
654 
655  /**
656  * Calculates the ideal number of horizontal and vertical bins for an array if the overall number of bins is known.
657  * This function tries to get bins with almost identical horizontal and vertical size.
658  * @param width The width of the area the array covers, with range [1, infinity)
659  * @param height The height of the area the array covers, with range [1, infinity)
660  * @param numberBins The number of bins that would be perfect, with range [1, infinity)
661  * @param horizontalBins The resulting number of horizontal bins that fit best with the given parameters, with range [minimalHorizontalBins, width]
662  * @param verticalBins The resulting number of vertical bins that fit best with the given parameters, with range [minimalVerticalBins, height]
663  * @param minimalHorizontalBins The minimal number of horizontal bins, with range [1, width]
664  * @param minimalVerticalBins The minimal number of vertical bins, with range [1, height]
665  */
666  static void idealBins(const unsigned int width, const unsigned int height, const size_t numberBins, unsigned int& horizontalBins, unsigned int& verticalBins, const unsigned int minimalHorizontalBins = 2u, const unsigned int minimalVerticalBins = 2u);
667 
668  /**
669  * Calculates the ideal number of horizontal and vertical bins for an array if bin elements within a certain distance should be guaranteed to be located in the 9 neighborhood of that bin
670  * This function tries to get bins with almost identical horizontal and vertical size.
671  * @param width The width of the area the array covers, with range [1, infinity)
672  * @param height The height of the area the array covers, with range [1, infinity)
673  * @param distance The distance to other bin elements that should be guaranteed to be located in the 9 neighborhood, with range [1, infinity)
674  * @param horizontalBins The resulting number of horizontal bins that fit best with the given parameters, with range [minimalHorizontalBins, width]
675  * @param verticalBins The resulting number of vertical bins that fit best with the given parameters, with range [minimalVerticalBins, height]
676  * @param minimalHorizontalBins The minimal number of horizontal bins, with range [1, maximalHorizontalBins]
677  * @param minimalVerticalBins The minimal number of vertical bins, with range [1, maximalVerticalBins]
678  * @param maximalHorizontalBins The maximal number of horizontal bins, with range [minimalHorizontalBins, width]
679  * @param maximalVerticalBins The maximal number of vertical bins, with range [minimalVerticalBins, height]
680  */
681  static void idealBinsNeighborhood9(const unsigned int width, const unsigned int height, const Scalar distance, unsigned int& horizontalBins, unsigned int& verticalBins, const unsigned int minimalHorizontalBins = 2u, const unsigned int minimalVerticalBins = 2u, const unsigned int maximalHorizontalBins = 20u, const unsigned int maximalVerticalBins = 20u);
682 
683  /**
684  * Distributes the given 2D image points into a spatial array.
685  * The number of used horizontal and vertical bins are calculated automatically.
686  * Instead of creating a 2D array a 1D array is returned with the first n elements for the top bins and the second n elements for the second top bins and so on.<br>
687  * Image points not fitting into the array bins are discarded.<br>
688  * @param imagePoints Image points to be distributed, may be nullptr if number==0
689  * @param number The number of given image points, with range [0, infinity)
690  * @param left Horizontal position of the area, may be 0 for e.g. an entire image, with range (-infinity, infinity)
691  * @param top Vertical position of the area, may be 0 for e.g. an entire image, with range (-infinity, infinity)
692  * @param width The width of the area holding the elements, with range (0, infinity)
693  * @param height The height of the area holding the elements, with range (0, infinity)
694  * @param averagePointsPerBin Average number of points per bin, with range [1, infinity)
695  * @param maxHorizontalBins Maximal number of horizontal bins, with range [1, infinity)
696  * @param maxVerticalBins Maximal number of vertical bins, with range [1, infinity)
697  * @param horizontalBins Resulting horizontal bins, with range [1, infinity)
698  * @param verticalBins Resulting vertical bins, with range [1, infinity)
699  * @return Resulting array holding the indices of the distributed image points, will be cleared before usage
700  */
701  static inline DistributionArray distributeToArray(const ImagePoint* imagePoints, const size_t number, const Scalar left, const Scalar top, const Scalar width, const Scalar height, const unsigned int averagePointsPerBin, const unsigned int maxHorizontalBins, const unsigned int maxVerticalBins, unsigned int& horizontalBins, unsigned int& verticalBins);
702 
703  /**
704  * Distributes a set of given 2D image points into a spatial array.
705  * Image points not fitting into the array bins are discarded.
706  * @param imagePoints Image points to be distributed, with range (-infinity, infinity)x(-infinity, infinity), may be nullptr if number==0
707  * @param number The number of given image points, with range [0, infinity)
708  * @param left Horizontal position of the area, may be 0 for e.g. an entire image, with range (-infinity, infinity)
709  * @param top Vertical position of the area, may be 0 for e.g. an entire image, with range (-infinity, infinity)
710  * @param width The width of the area holding the points, with range (0, infinity)
711  * @param height The height of the area holding the points, with range (0, infinity)
712  * @param horizontalBins Number of horizontal bins to distribute the image points into, with range [1, infinity)
713  * @param verticalBins Number of vertical bins to distribute the image points into, with range [1, infinity)
714  * @return Resulting array holding the indices of the distributed image points
715  */
716  static DistributionArray distributeToArray(const ImagePoint* imagePoints, const size_t number, const Scalar left, const Scalar top, const Scalar width, const Scalar height, const unsigned int horizontalBins, const unsigned int verticalBins);
717 
718  /**
719  * Distributes the given elements into a spatial array.
720  * Elements not fitting into the array bins are discarded.
721  * @param elements The elements (e.g. holding image points) to be distributed
722  * @param number The number of given image points
723  * @param left Horizontal position of the area, may be 0 for e.g. an entire image, with range (-infinity, infinity)
724  * @param top Vertical position of the area, may be 0 for e.g. an entire image, with range (-infinity, infinity)
725  * @param width The width of the area holding the elements, with range (0, infinity)
726  * @param height The height of the area holding the elements, with range (0, infinity)
727  * @param horizontalBins Number of horizontal bins to distribute the image points into, with range [1, width]
728  * @param verticalBins Number of vertical bins to distribute the image points into, with range [1, height]
729  * @return Resulting array holding the indices of the distributed elements
730  * @tparam T Data type of the given elements
731  * @tparam tFunction Function pointer type of a function returning the 2D position of any element
732  */
733  template <typename T, const Vector2& (*tFunction)(const T&)>
734  static DistributionArray distributeToArray(const T* elements, const size_t number, const Scalar left, const Scalar top, const Scalar width, const Scalar height, const unsigned int horizontalBins, const unsigned int verticalBins);
735 
736  /**
737  * Distributes the given 2D image points into a spatial array.
738  * Instead of creating a 2D array a 1D array is returned with the first n elements for the top bins and the second n elements for the second top bins and so on.
739  * Image points not fitting into the array bins are discarded.<br>
740  * @param imagePoints Image points to be distributed
741  * @param number The number of given image points
742  * @param left Horizontal position of the area, may be 0 for e.g. an entire image, with range (-infinity, infinity)
743  * @param top Vertical position of the area, may be 0 for e.g. an entire image, with range (-infinity, infinity)
744  * @param width The width of the area holding the points, with range (0, infinity)
745  * @param height The height of the area holding the points, with range (0, infinity)
746  * @param searchDistance Search distance that will be applied (minimal size of each bin)
747  * @return Resulting array holding the indices of the distributed image points
748  * @tparam tMaximalBins Number of maximal bins in each direction (horizontal and vertical), width range [1, infinity)
749  */
750  template <unsigned int tMaximalBins>
751  static inline DistributionArray distributeToArray(const ImagePoint* imagePoints, const size_t number, const Scalar left, const Scalar top, const Scalar width, const Scalar height, const Scalar searchDistance);
752 
753  /**
754  * Distributes the given 2D image points into a spatial array.
755  * Instead of creating a 2D array a 1D array is returned with the first n elements for the top bins and the second n elements for the second top bins and so on.
756  * Image points not fitting into the array bins are discarded.<br>
757  * @param imagePoints Image points to be distributed, must be valid if the specified number is not zero
758  * @param number The number of given image points, with range [0, infinity)
759  * @param left Horizontal position of the area, may be 0 for e.g. an entire image, with range (-infinity, infinity)
760  * @param top Vertical position of the area, may be 0 for e.g. an entire image, with range (-infinity, infinity)
761  * @param width The width of the area holding the points, with range (0, infinity)
762  * @param height The height of the area holding the points, with range (0, infinity)
763  * @param horizontalBins Number of horizontal bins to distribute the image points into, with range [1, width]
764  * @param verticalBins Number of vertical bins to distribute the image points into, with range [1, height]
765  * @return Resulting array holding the indices of the distributed image points
766  */
767  static OccupancyArray createOccupancyArray(const ImagePoint* imagePoints, const size_t number, const Scalar left, const Scalar top, const Scalar width, const Scalar height, const unsigned int horizontalBins, const unsigned int verticalBins);
768 
769  /**
770  * Filters the given 2D image points according to their distance to neighboring image points.
771  * @param imagePoints Image points (e.g. holding image points) to be filtered
772  * @param number The number of given image points
773  * @param width The width of the area holding the points in pixel, with range [1, infinity)
774  * @param height The height of the area holding the points in pixel, with range [1, infinity)
775  * @param distance The distance threshold to be used for filtering
776  * @return Resulting vector holding the indices of the found image points
777  */
778  static Indices32 filterAccordingDistance(const ImagePoint* imagePoints, const size_t number, const unsigned int width, const unsigned int height, const Scalar distance);
779 
780  /**
781  * Filters the given 2D candidate points according to the distance to the given image points.
782  * @param imagePoints Image points for that the filtered candidate points have to be found
783  * @param numberImagePoints Number of image points
784  * @param candidatePoints Candidate points that will be filtered
785  * @param numberCandidatePoints Number of candidate points
786  * @param width The width of the area holding the image points, with range [1, infinity)
787  * @param height The height of the area holding the image points, with range [1, infinity)
788  * @param filterDistance Distance threshold that define whether a candidate point belongs to one image point
789  * @param filterSize Number of candidate points that can belong to one image point
790  * @param filteredIndices Resulting indices of the filtered candidate points, if defined
791  * @param filteredCandidates Resulting filtered candidate points, if defined
792  */
793  static void filterCandidatePoint(const ImagePoint* imagePoints, const size_t numberImagePoints, const ImagePoint* candidatePoints, const size_t numberCandidatePoints, const unsigned int width, const unsigned int height, const Scalar filterDistance, const unsigned int filterSize, Indices32* filteredIndices = nullptr, ImagePoints* filteredCandidates = nullptr);
794 
795  /**
796  * Sorts the given 2D image points according to their minimal distance to neighboring image points.
797  * Points with higher distances will be returned before points with lower distances.
798  * @param imagePoints Image points (e.g. holding image points) to be sorted
799  * @param number The number of given image points
800  * @param minimalDistanceFirst True, to sort minimal distance to the front
801  * @return Resulting vector holding the indices and distances of the sorted image points
802  */
803  static DistanceElements sortAccordingDistance(const ImagePoint* imagePoints, const size_t number, const bool minimalDistanceFirst);
804 
805  /**
806  * Sorts the given 2D image points according to their minimal distance to neighboring image points.
807  * Points with higher distances will be returned before points with lower distances.
808  * This function first distributes all points to array bins to speed up the computation.<br>
809  * @param imagePoints Image points (e.g. holding image points) to be sorted
810  * @param number The number of given image points
811  * @param width The width of the area holding the image points in pixel, with range [1, infinity)
812  * @param height The height of the area holding the image points in pixel, with range [1, infinity)
813  * @param bins Number of bins in each direction used for image point distribution
814  * @param minimalDistanceFirst True, to sort minimal distance to the front
815  * @return Resulting vector holding the indices and distances of the sorted image points
816  */
817  static DistanceElements sortAccordingDistance(const ImagePoint* imagePoints, const size_t number, const unsigned int width, const unsigned int height, const unsigned int bins, const bool minimalDistanceFirst);
818 
819  /**
820  * Determines the minimal square distance for one given 2D image point to all other points in the same set.
821  * This function uses an already create point distribution to speed up the computation.<br>
822  * Candidates for nearest neighbors are all points lying in the 9-bin-neighborhood of a point, thus the result technically is an approximation and not correct in any case.
823  * @param imagePoints Image points to calculate the distances for
824  * @param numberImagePoints Number of given image points
825  * @param index The index of the image point to find the minimal square distance for, with range [0, numberImagePoints)
826  * @param distributionImagePoints Already created distribution array of the image points
827  * @return Resulting square distances calculated for the given image point
828  */
829  static Scalar determineMinimalSqrDistance(const ImagePoint* imagePoints, const size_t numberImagePoints, const unsigned int index, const DistributionArray& distributionImagePoints);
830 
831  /**
832  * Determines the minimal square distances for each given 2D image point to all other points in the same set.
833  * This function first distributes all points to array bins to speed up the computation.<br>
834  * Candidates for nearest neighbors are all points lying in the 9-bin-neighborhood of a point, thus the result technically is an approximation and not correct in any case.
835  * @param imagePoints Image points to calculate the distances for, may be nullptr if numberImagePoints==0
836  * @param numberImagePoints Number of given image points, with range [0, infinity)
837  * @param width The width of the area holding the image points in pixel, with range [1, infinity)
838  * @param height The height of the area holding the image points in pixel, with range [1, infinity)
839  * @param bins Number of bins in each direction used for image point distribution, with range [1, infinity)
840  * @param sqrDistances Resulting square distances calculated for each given image point, make sure that this buffer holds enough space
841  */
842  static void determineMinimalSqrDistances(const ImagePoint* imagePoints, const size_t numberImagePoints, const unsigned int width, const unsigned int height, const unsigned int bins, Scalar* sqrDistances);
843 
844  /**
845  * Determines the minimal square distances for each given 2D image point to another given set of 2D image points.
846  * This function first distributes all points to array bins to speed up the computation.<br>
847  * Candidates for nearest neighbors are all points lying in the 9-bin-neighborhood of a point, thus the result technically is an approximation and not correct in any case.
848  * @param imagePoints Image points to calculate the distances for, may be nullptr if numberImagePoints==0
849  * @param numberImagePoints Number of given image points, with range [0, infinity)
850  * @param candidates Image points being candidates as nearest neighbors for the given image points
851  * @param numberCandidates Number of given candidates
852  * @param width The width of the area holding the image points in pixel, with range [1, infinity)
853  * @param height The height of the area holding the image points in pixel, with range [1, infinity)
854  * @param bins Number of bins in each direction used for image point distribution
855  * @param sqrDistances Resulting square distances calculated for each given image point, make sure that this buffer holds enough space
856  */
857  static void determineMinimalSqrDistances(const ImagePoint* imagePoints, const size_t numberImagePoints, const ImagePoint* candidates, const size_t numberCandidates, const unsigned int width, const unsigned int height, const unsigned int bins, Scalar* sqrDistances);
858 
859  /**
860  * Determines the minimal square distances for each given image point to another given set of image points.
861  * Candidates for nearest neighbors are all points lying in the 9-bin-neighborhood of a point, thus the result technically is an approximation and not correct in any case.
862  * @param imagePoints Image points to calculate the distances for, may be nullptr if numberImagePoints==0
863  * @param numberImagePoints Number of given image points, with range [0, infinity)
864  * @param candidates Image points being candidates as nearest neighbors for the given image points
865  * @param numberCandidates Number of given candidates
866  * @param distributionCandidates Already created distribution array of the candidates
867  * @param sqrDistances Resulting square distances calculated for each given element, make sure that this buffer holds enough space
868  * @param candidateIndices Optional resulting indices of the candidate with minimal distance, make sure that this buffer holds enough space (if defined)
869  */
870  static void determineMinimalSqrDistances(const ImagePoint* imagePoints, const size_t numberImagePoints, const ImagePoint* candidates, const size_t numberCandidates, const DistributionArray& distributionCandidates, Scalar* sqrDistances, unsigned int* candidateIndices = nullptr);
871 
872  /**
873  * Determines the minimal square distances for each specified image point inside their neighborhood.
874  * This function first distributes all image points to array bins to speed up the computation.<br>
875  * Candidates for nearest neighbors are all points lying in the 9-bin-neighborhood of a point, thus the result technically is an approximation and not correct in any case.
876  * @param imagePoints Image points holding the entire set, may be nullptr if numberImagePoints==0
877  * @param numberImagePoints Number of given image points, with range [0, infinity)
878  * @param interestIndices Indices of all interest image points to calculate the minimal distance for
879  * @param numberInterestIndices Number of given interest indices
880  * @param width The width of the area holding the elements in pixel, with range [1, infinity)
881  * @param height The height of the area holding the elements in pixel, with range [1, infinity)
882  * @param bins Number of bins in each direction used for element distribution
883  * @param sqrDistances Resulting square distances calculated for each given interest index, make sure that this buffer holds enough space
884  */
885  static void determineMinimalSqrDistances(const ImagePoint* imagePoints, const size_t numberImagePoints, const unsigned int* interestIndices, const size_t numberInterestIndices, const unsigned int width, const unsigned int height, const unsigned int bins, Scalar* sqrDistances);
886 
887  /**
888  * Determines all candidate points for a given image point (interest point) lying inside a specified circle around the interest point.
889  * @param imagePoint The interest image point to find the neighboring candidate points for, with range (-infinity, infinity)x(-infinity, infinity)
890  * @param candidatePoints Candidate points to find the neighbors in
891  * @param numberCandidatePoints Number of given candidate points
892  * @param radius The radius specifying the circle around the interest point, with range [0, infinity)
893  * @param distributionCandidatePoints Already created distribution array of the candidate points
894  * @return Resulting indices of all neighbors out the candidate set lying within the specified circle.
895  */
896  static Indices32 determineNeighbors(const ImagePoint& imagePoint, const ImagePoint* candidatePoints, const size_t numberCandidatePoints, const Scalar radius, const DistributionArray& distributionCandidatePoints);
897 
898  /**
899  * Determines the nearest image point between an interest point and a set of given image point lying inside a specified circle around the interest point.
900  * @param interestPoint The interest image point for which the nearest neighbor will be determined, with range (-infinity, infinity)x(-infinity, infinity)
901  * @param imagePoints The set of image points from which the nearest neighbor will be determined
902  * @param numberImagePoints Number of given image points, with range [0, infinity)
903  * @param radius The radius specifying the circle around the interest point, with range [0, infinity)
904  * @param distributionImagePoints Already created distribution array of the image points
905  * @param sqrDistance Optional resulting square distance of the nearest image point, if any
906  * @return Resulting index of the nearest neighbor image point, -1 if no image point lies within the specified radius
907  */
908  static Index32 determineNearestNeighbor(const ImagePoint& interestPoint, const ImagePoint* imagePoints, const size_t numberImagePoints, const Scalar radius, const DistributionArray& distributionImagePoints, Scalar* sqrDistance = nullptr);
909 
910  /**
911  * Distributes the given image points into an array of specified size and returns (at most) one point from each bin.
912  * @param imagePoints Image points to be distributed and filtered, may be nullptr if numberImagePoints==0
913  * @param numberImagePoints Number of given image points, with range [0, infinity)
914  * @param left Horizontal position of the area, may be 0 for e.g. an entire image, with range (-infinity, infinity)
915  * @param top Vertical position of the area, may be 0 for e.g. an entire image, with range (-infinity, infinity)
916  * @param width The width of the area holding the elements, with range (0, infinity)
917  * @param height The height of the area holding the elements, with range (0, infinity)
918  * @param horizontalBins Number of horizontal bins to be used for distribution, with range [1, infinity)
919  * @param verticalBins Number of vertical bins to be used for distribution, with range [1, infinity)
920  * @return Resulting filtered elements
921  */
922  static inline ImagePoints distributeAndFilter(const ImagePoint* imagePoints, const size_t numberImagePoints, const Scalar left, const Scalar top, const Scalar width, const Scalar height, const unsigned int horizontalBins, const unsigned int verticalBins);
923 
924  /**
925  * Distributes the given image points into an array of specified size and returns as much points as requested by first selecting the first point from each bin, then the second point from each bin, and so on.
926  * @param imagePoints Image points to be distributed and filtered, may be nullptr if numberImagePoints==0
927  * @param numberImagePoints Number of given image points, with range [0, infinity)
928  * @param left Horizontal position of the area, may be 0 for e.g. an entire image, with range (-infinity, infinity)
929  * @param top Vertical position of the area, may be 0 for e.g. an entire image, with range (-infinity, infinity)
930  * @param width The width of the area holding the elements, with range (0, infinity)
931  * @param height The height of the area holding the elements, with range (0, infinity)
932  * @param horizontalBins Number of horizontal bins to be used for distribution, with range [1, infinity)
933  * @param verticalBins Number of vertical bins to be used for distribution, with range [1, infinity)
934  * @param size The number of requested feature points, with range [0, numberImagePoints]
935  * @return Resulting filtered elements
936  */
937  static ImagePoints distributeAndFilter(const ImagePoint* imagePoints, const size_t numberImagePoints, const Scalar left, const Scalar top, const Scalar width, const Scalar height, const unsigned int horizontalBins, const unsigned int verticalBins, const size_t size);
938 
939  /**
940  * Distributes the given image points into an array of specified size and returns (at most) one point index from each bin.
941  * The resulting indices can be used to filter the actual set of image points.<br>
942  * @param imagePoints Image points to be distributed and filtered, may be nullptr if numberImagePoints==0
943  * @param numberImagePoints Number of given image points, with range [0, infinity)
944  * @param left Horizontal position of the area, may be 0 for e.g. an entire image, with range (-infinity, infinity)
945  * @param top Vertical position of the area, may be 0 for e.g. an entire image, with range (-infinity, infinity)
946  * @param width The width of the area holding the elements, with range (0, infinity)
947  * @param height The height of the area holding the elements, with range (0, infinity)
948  * @param horizontalBins Number of horizontal bins to be used for distribution, with range [1, infinity)
949  * @param verticalBins Number of vertical bins to be used for distribution, with range [1, infinity)
950  * @return Resulting indices of the filtered elements
951  * @tparam TIndex The data type of the indices (e.g., may be Index32 or Index64)
952  */
953  template <typename TIndex>
954  static inline std::vector<TIndex> distributeAndFilterIndices(const ImagePoint* imagePoints, const size_t numberImagePoints, const Scalar left, const Scalar top, const Scalar width, const Scalar height, const unsigned int horizontalBins, const unsigned int verticalBins);
955 
956  /**
957  * Distributes the given elements into an array of specified size and returns (at most) one element from each bin.
958  * @param elements The elements to be distributed and filtered, may be nullptr if numberImagePoints==0
959  * @param numberElements Number of given elements, with range [0, infinity)
960  * @param left Horizontal position of the area, may be 0 for e.g. an entire image, with range (-infinity, infinity)
961  * @param top Vertical position of the area, may be 0 for e.g. an entire image, with range (-infinity, infinity)
962  * @param width The width of the area holding the elements, with range (0, infinity)
963  * @param height The height of the area holding the elements, with range (0, infinity)
964  * @param horizontalBins Number of horizontal bins to be used for distribution, with range [1, infinity)
965  * @param verticalBins Number of vertical bins to be used for distribution, with range [1, infinity)
966  * @return Resulting filtered elements
967  * @tparam T The data type of the elements to be distributed
968  * @tparam tFunction The function pointer that returns the 2D position of each element
969  */
970  template <typename T, Vector2 (*tFunction)(const T&)>
971  static std::vector<T> distributeAndFilter(const T* elements, const size_t numberElements, const Scalar left, const Scalar top, const Scalar width, const Scalar height, const unsigned int horizontalBins, const unsigned int verticalBins);
972 
973  /**
974  * Distributes the given elements into an array of specified size but returns as much elements per bin necessary to reach the specified amount of desired elements.
975  * This function should be used whenever the given elements are not distributed equally while a specified amount of feature points is desired.
976  * The function applies several filter iterations until the desired number of elements is reached.<br>
977  * After the first iteration each bin will contain at most one element, after the second iteration at most two elements, and so on.
978  * @param elements The elements to be distributed and filtered, may be nullptr if numberImagePoints==0
979  * @param numberElements Number of given elements, with range [0, infinity)
980  * @param left Horizontal position of the area, may be 0 for e.g. an entire image, with range (-infinity, infinity)
981  * @param top Vertical position of the area, may be 0 for e.g. an entire image, with range (-infinity, infinity)
982  * @param width The width of the area holding the elements, with range (0, infinity)
983  * @param height The height of the area holding the elements, with range (0, infinity)
984  * @param horizontalBins Number of horizontal bins to be used for distribution, with range [1, infinity)
985  * @param verticalBins Number of vertical bins to be used for distribution, with range [1, infinity)
986  * @param numberDesiredFilteredElements The desired number of filtered elements, with range [1, numberElements]
987  * @param indices Optional resulting indices of the selected keypoints, if defined indices will be pushed at the back.
988  * @return Resulting filtered elements
989  * @tparam T The data type of the elements to be distributed
990  * @tparam tFunction The function pointer that returns the 2D position of each element
991  */
992  template <typename T, Vector2 (*tFunction)(const T&)>
993  static std::vector<T> distributeAndFilter(const T* elements, const size_t numberElements, const Scalar left, const Scalar top, const Scalar width, const Scalar height, const unsigned int horizontalBins, const unsigned int verticalBins, const size_t numberDesiredFilteredElements, Indices32 *indices = nullptr);
994 
995  /**
996  * Distributes the given elements into an array of specified size and returns (at most) one point index from each bin.
997  * The resulting indices can be used to filter the actual set of image points.<br>
998  * @param elements The elements to be distributed and filtered, may be nullptr if numberImagePoints==0
999  * @param numberElements Number of given elements, with range [0, infinity)
1000  * @param left Horizontal position of the area, may be 0 for e.g. an entire image, with range (-infinity, infinity)
1001  * @param top Vertical position of the area, may be 0 for e.g. an entire image, with range (-infinity, infinity)
1002  * @param width The width of the area holding the elements, with range (0, infinity)
1003  * @param height The height of the area holding the elements, with range (0, infinity)
1004  * @param horizontalBins Number of horizontal bins to be used for distribution, with range [1, infinity)
1005  * @param verticalBins Number of vertical bins to be used for distribution, with range [1, infinity)
1006  * @return Resulting indices of the filtered elements
1007  * @tparam T The data type of the elements to be distributed
1008  * @tparam TIndex The data type of the indices (e.g., may be Index32 or Index64)
1009  * @tparam tFunction The function pointer that returns the 2D position of each element
1010  */
1011  template <typename T, typename TIndex, Vector2 (*tFunction)(const T&)>
1012  static std::vector<TIndex> distributeAndFilterIndices(const T* elements, const size_t numberElements, const Scalar left, const Scalar top, const Scalar width, const Scalar height, const unsigned int horizontalBins, const unsigned int verticalBins);
1013 
1014  protected:
1015 
1016  /**
1017  * This function simply returns the given object (actually a copy of the object).
1018  * @param value The value to be returned
1019  * @return The given value
1020  * @tparam T The data type of the value
1021  */
1022  template <typename T>
1023  static inline T identity(const T& value);
1024 };
1025 
1026 inline SpatialDistribution::Array::Array(Array&& object) noexcept :
1027  areaLeft_(object.areaLeft_),
1028  areaTop_(object.areaTop_),
1029  areaWidth_(object.areaWidth_),
1030  areaHeight_(object.areaHeight_),
1031  horizontalBins_(object.horizontalBins_),
1032  verticalBins_(object.verticalBins_),
1033  horizontalPoint2Bin_(object.horizontalPoint2Bin_),
1034  verticalPoint2Bin_(object.verticalPoint2Bin_)
1035 {
1036  object.areaLeft_ = Scalar(0);
1037  object.areaTop_ = Scalar(0);
1038  object.areaWidth_ = Scalar(0);
1039  object.areaHeight_ = Scalar(0);
1040  object.horizontalBins_ = 0u;
1041  object.verticalBins_ = 0u;
1042  object.horizontalPoint2Bin_ = Scalar(0);
1043  object.verticalPoint2Bin_ = Scalar(0);
1044 }
1045 
1046 inline SpatialDistribution::Array::Array(const Scalar left, const Scalar top, const Scalar width, const Scalar height, const unsigned int horizontalBins, const unsigned int verticalBins) :
1047  areaLeft_(left),
1048  areaTop_(top),
1049  areaWidth_(width),
1050  areaHeight_(height),
1051  horizontalBins_(horizontalBins),
1052  verticalBins_(verticalBins),
1053  horizontalPoint2Bin_(width > Numeric::eps() ? (Scalar(horizontalBins) / (Scalar(width) + Numeric::eps())) : Scalar(0)),
1054  verticalPoint2Bin_(height > Numeric::eps() ? (Scalar(verticalBins) / (Scalar(height) + Numeric::eps())) : Scalar(0))
1055 {
1056  ocean_assert(width > Numeric::eps() && height > Numeric::eps());
1057 }
1058 
1060 {
1061  return areaLeft_;
1062 }
1063 
1065 {
1066  return areaTop_;
1067 }
1068 
1070 {
1071  return areaWidth_;
1072 }
1073 
1075 {
1076  return areaHeight_;
1077 }
1078 
1080 {
1081  return horizontalBins_;
1082 }
1083 
1084 inline unsigned int SpatialDistribution::Array::verticalBins() const
1085 {
1086  return verticalBins_;
1087 }
1088 
1089 inline unsigned int SpatialDistribution::Array::bins() const
1090 {
1091  return horizontalBins_ * verticalBins_;
1092 }
1093 
1094 inline unsigned int SpatialDistribution::Array::index(const Scalar x, const Scalar y) const
1095 {
1096  const int xBin = horizontalBin(x);
1097  const int yBin = verticalBin(y);
1098 
1099  ocean_assert(xBin >= 0 && xBin < int(horizontalBins_));
1100  ocean_assert(yBin >= 0 && yBin < int(verticalBins_));
1101 
1102  return yBin * horizontalBins_ + xBin;
1103 }
1104 
1106 {
1107  // for positive values we could avoid to use floor(), however for negative values we e.g., need -0.2 to be -1
1108  return int(Numeric::floor((x - areaLeft_) * horizontalPoint2Bin_));
1109 }
1110 
1112 {
1113  // for positive values we could avoid to use floor(), however for negative values we e.g., need -0.2 to be -1
1114  return int(Numeric::floor((y - areaTop_) * verticalPoint2Bin_));
1115 }
1116 
1118 {
1119  ocean_assert(isValid());
1120  return minmax<int>(0, horizontalBin(x), horizontalBins_ - 1);
1121 }
1122 
1124 {
1125  ocean_assert(isValid());
1126  return minmax<int>(0, verticalBin(y), verticalBins_ - 1);
1127 }
1128 
1130 {
1131  return horizontalBins_ != 0u && verticalBins_ != 0u;
1132 }
1133 
1134 inline bool SpatialDistribution::Array::operator==(const Array& right) const
1135 {
1136  return areaLeft_ == right.areaLeft_
1137  && areaTop_ == right.areaTop_
1138  && areaWidth_ == right.areaWidth_
1139  && areaHeight_ == right.areaHeight_
1140  && horizontalBins_ == right.horizontalBins_
1141  && verticalBins_ == right.verticalBins_
1142  && horizontalPoint2Bin_ == right.horizontalPoint2Bin_
1143  && verticalPoint2Bin_ == right.verticalPoint2Bin_;
1144 }
1145 
1146 inline bool SpatialDistribution::Array::operator!=(const Array& right) const
1147 {
1148  return !(*this == right);
1149 }
1150 
1151 inline SpatialDistribution::Array::operator bool() const
1152 {
1153  return isValid();
1154 }
1155 
1157 {
1158  if (this != &object)
1159  {
1160  areaLeft_ = object.areaLeft_;
1161  areaTop_ = object.areaTop_;
1162  areaWidth_ = object.areaWidth_;
1163  areaHeight_ = object.areaHeight_;
1164  horizontalBins_ = object.horizontalBins_;
1165  verticalBins_ = object.verticalBins_;
1166  horizontalPoint2Bin_ = object.horizontalPoint2Bin_;
1167  verticalPoint2Bin_ = object.verticalPoint2Bin_;
1168  }
1169 
1170  return *this;
1171 }
1172 
1174 {
1175  if (this != &object)
1176  {
1177  areaLeft_ = object.areaLeft_;
1178  areaTop_ = object.areaTop_;
1179  areaWidth_ = object.areaWidth_;
1180  areaHeight_ = object.areaHeight_;
1181  horizontalBins_ = object.horizontalBins_;
1182  verticalBins_ = object.verticalBins_;
1183  horizontalPoint2Bin_ = object.horizontalPoint2Bin_;
1184  verticalPoint2Bin_ = object.verticalPoint2Bin_;
1185 
1186  object.areaLeft_ = Scalar(0);
1187  object.areaTop_ = Scalar(0);
1188  object.areaWidth_ = Scalar(0);
1189  object.areaHeight_ = Scalar(0);
1190  object.horizontalBins_ = 0u;
1191  object.verticalBins_ = 0u;
1192  object.horizontalPoint2Bin_ = Scalar(0);
1193  object.verticalPoint2Bin_ = Scalar(0);
1194  }
1195 
1196  return *this;
1197 }
1198 
1200  Array(object),
1201  indexGroups_(std::move(object.indexGroups_)),
1202  hasCopiedNeighborhood8_(object.hasCopiedNeighborhood8_)
1203 {
1204  object = DistributionArray();
1205 }
1206 
1207 inline SpatialDistribution::DistributionArray::DistributionArray(const Scalar left, const Scalar top, const Scalar width, const Scalar height, const unsigned int horizontalBins, const unsigned int verticalBins) :
1208  Array(left, top, width, height, horizontalBins, verticalBins),
1209  indexGroups_(horizontalBins * verticalBins),
1210  hasCopiedNeighborhood8_(false)
1211 {
1212  // nothing to do here
1213 }
1214 
1216 {
1217  return hasCopiedNeighborhood8_;
1218 }
1219 
1220 inline const Indices32& SpatialDistribution::DistributionArray::operator()(const unsigned int horizontal, const unsigned int vertical) const
1221 {
1222  ocean_assert(horizontal < horizontalBins_);
1223  ocean_assert(vertical < verticalBins_);
1224 
1225  return indexGroups_[vertical * horizontalBins_ + horizontal];
1226 }
1227 
1228 inline Indices32& SpatialDistribution::DistributionArray::operator()(const unsigned int horizontal, const unsigned int vertical)
1229 {
1230  ocean_assert(horizontal < horizontalBins_);
1231  ocean_assert(vertical < verticalBins_);
1232 
1233  return indexGroups_[vertical * horizontalBins_ + horizontal];
1234 }
1235 
1236 inline const Indices32& SpatialDistribution::DistributionArray::operator[](const unsigned int index) const
1237 {
1238  ocean_assert(index < horizontalBins_ * verticalBins_);
1239  return indexGroups_[index];
1240 }
1241 
1243 {
1244  ocean_assert(index < horizontalBins_ * verticalBins_);
1245  return indexGroups_[index];
1246 }
1247 
1249 {
1250  Array::operator=((Array&)object);
1251  indexGroups_ = object.indexGroups_;
1252  hasCopiedNeighborhood8_ = object.hasCopiedNeighborhood8_;
1253 
1254  return *this;
1255 }
1256 
1258 {
1259  if (this != &object)
1260  {
1261  Array::operator=(std::move((Array&)object));
1262  indexGroups_ = std::move(object.indexGroups_);
1263  hasCopiedNeighborhood8_ = object.hasCopiedNeighborhood8_;
1264 
1265  object.hasCopiedNeighborhood8_ = false;
1266  }
1267 
1268  return *this;
1269 }
1270 
1272 {
1273  if (!Array::operator==(distributionArray))
1274  {
1275  return false;
1276  }
1277 
1278  return indexGroups_ == distributionArray.indexGroups_ && hasCopiedNeighborhood8_ && distributionArray.hasCopiedNeighborhood8_;
1279 }
1280 
1282 {
1283  return !(*this == distributionArray);
1284 }
1285 
1287  Array(std::move((Array&)object)),
1288  occupancy_(std::move(object.occupancy_))
1289 {
1290  // nothing to do here
1291 }
1292 
1293 inline SpatialDistribution::OccupancyArray::OccupancyArray(const Box2& boundingBox, const unsigned int horizontalBins, const unsigned int verticalBins, const bool allFree) :
1294  Array(boundingBox.left(), boundingBox.top(), boundingBox.width(), boundingBox.height(), horizontalBins, verticalBins),
1295  occupancy_(horizontalBins * verticalBins, allFree ? 0u : 1u)
1296 {
1297  ocean_assert(NumericT<unsigned int>::isInsideValueRange(uint64_t(horizontalBins) * uint64_t(verticalBins)));
1298 }
1299 
1300 inline SpatialDistribution::OccupancyArray::OccupancyArray(const Scalar left, const Scalar top, const Scalar width, const Scalar height, const unsigned int horizontalBins, const unsigned int verticalBins, const bool allFree) :
1301  Array(left, top, width, height, horizontalBins, verticalBins),
1302  occupancy_(horizontalBins * verticalBins, allFree ? 0u : 1u)
1303 {
1304  ocean_assert(NumericT<unsigned int>::isInsideValueRange(uint64_t(horizontalBins) * uint64_t(verticalBins)));
1305 }
1306 
1307 inline unsigned int SpatialDistribution::OccupancyArray::countOccupiedNeighborhood9(const unsigned int horizontal, const unsigned int vertical) const
1308 {
1309  ocean_assert(horizontal < horizontalBins_);
1310  ocean_assert(vertical < verticalBins_);
1311 
1312  unsigned int number = 0u;
1313 
1314  for (unsigned int y = max(0, int(vertical) - 1); y < min(vertical + 2u, verticalBins_); ++y)
1315  {
1316  for (unsigned int x = max(0, int(horizontal) - 1); x < min(horizontal + 2u, horizontalBins_); ++x)
1317  {
1318  if ((*this)(x, y))
1319  {
1320  number++;
1321  }
1322  }
1323  }
1324 
1325  return number;
1326 }
1327 
1328 inline bool SpatialDistribution::OccupancyArray::isOccupiedNeighborhood9(const unsigned int horizontal, const unsigned int vertical) const
1329 {
1330  ocean_assert(horizontal < horizontalBins_);
1331  ocean_assert(vertical < verticalBins_);
1332 
1333  for (unsigned int y = max(0, int(vertical) - 1); y < min(vertical + 2u, verticalBins_); ++y)
1334  {
1335  for (unsigned int x = max(0, int(horizontal) - 1); x < min(horizontal + 2u, horizontalBins_); ++x)
1336  {
1337  if ((*this)(x, y))
1338  {
1339  return true;
1340  }
1341  }
1342  }
1343 
1344  return false;
1345 }
1346 
1348 {
1349  const unsigned int horizontal = horizontalBin(point.x());
1350  const unsigned int vertical = verticalBin(point.y());
1351 
1352  if (horizontal < horizontalBins_ && vertical < verticalBins_)
1353  {
1354  for (unsigned int y = max(0, int(vertical) - 1); y < min(vertical + 2u, verticalBins_); ++y)
1355  {
1356  for (unsigned int x = max(0, int(horizontal) - 1); x < min(horizontal + 2u, horizontalBins_); ++x)
1357  {
1358  if ((*this)(x, y))
1359  {
1360  return true;
1361  }
1362  }
1363  }
1364  }
1365 
1366  return false;
1367 }
1368 
1369 inline bool SpatialDistribution::OccupancyArray::isNotOccupiedNeighborhood9(const unsigned int horizontal, const unsigned int vertical) const
1370 {
1371  ocean_assert(horizontal < horizontalBins_);
1372  ocean_assert(vertical < verticalBins_);
1373 
1374  for (unsigned int y = max(0, int(vertical) - 1); y < min(vertical + 2u, verticalBins_); ++y)
1375  {
1376  for (unsigned int x = max(0, int(horizontal) - 1); x < min(horizontal + 2u, horizontalBins_); ++x)
1377  {
1378  if (!(*this)(x, y))
1379  {
1380  return true;
1381  }
1382  }
1383  }
1384 
1385  return false;
1386 }
1387 
1389 {
1390  const unsigned int horizontal = horizontalBin(point.x());
1391  const unsigned int vertical = verticalBin(point.y());
1392 
1393  if (horizontal < horizontalBins_ && vertical < verticalBins_)
1394  {
1395  for (unsigned int y = max(0, int(vertical) - 1); y < min(vertical + 2u, verticalBins_); ++y)
1396  {
1397  for (unsigned int x = max(0, int(horizontal) - 1); x < min(horizontal + 2u, horizontalBins_); ++x)
1398  {
1399  if (!(*this)(x, y))
1400  {
1401  return true;
1402  }
1403  }
1404  }
1405  }
1406 
1407  return false;
1408 }
1409 
1411 {
1412  unsigned int count = 0u;
1413 
1414  for (const Index32& bin : occupancy_)
1415  {
1416  if (bin != 0u)
1417  {
1418  ++count;
1419  }
1420  }
1421 
1422  return count;
1423 }
1424 
1426 {
1427  unsigned int count = 0u;
1428 
1429  for (const Index32& bin : occupancy_)
1430  {
1431  if (bin == 0u)
1432  {
1433  ++count;
1434  }
1435  }
1436 
1437  return count;
1438 }
1439 
1441 {
1442  const unsigned int horizontal = (unsigned int)(horizontalBin(point.x()));
1443  const unsigned int vertical = (unsigned int)(verticalBin(point.y()));
1444 
1445  if (horizontal < horizontalBins_ && vertical < verticalBins_)
1446  {
1447  const unsigned int index = vertical * horizontalBins_ + horizontal;
1448 
1449  if (!occupancy_[index])
1450  {
1451  occupancy_[index] = 1u;
1452  return true;
1453  }
1454  }
1455 
1456  return false;
1457 }
1458 
1459 inline bool SpatialDistribution::OccupancyArray::addPointWithCounter(const Vector2& point, const unsigned int maximalOccupancyCounter)
1460 {
1461  const unsigned int horizontal = (unsigned int)(horizontalBin(point.x()));
1462  const unsigned int vertical = (unsigned int)(verticalBin(point.y()));
1463 
1464  if (horizontal < horizontalBins_ && vertical < verticalBins_)
1465  {
1466  const unsigned int index = vertical * horizontalBins_ + horizontal;
1467 
1468  if (occupancy_[index] <= maximalOccupancyCounter)
1469  {
1470  occupancy_[index]++;
1471  return true;
1472  }
1473  }
1474 
1475  return false;
1476 }
1477 
1479 {
1480  const unsigned int horizontal = (unsigned int)(horizontalBin(point.x()));
1481  const unsigned int vertical = (unsigned int)(verticalBin(point.y()));
1482 
1483  if (horizontal < horizontalBins_ && vertical < verticalBins_)
1484  {
1485  const unsigned int index = vertical * horizontalBins_ + horizontal;
1486 
1487  if (occupancy_[index])
1488  {
1489  occupancy_[index] = 0u;
1490  return true;
1491  }
1492  }
1493 
1494  return false;
1495 }
1496 
1498 {
1499  for (size_t n = 0; n < occupancy_.size(); ++n)
1500  {
1501  occupancy_[n] = 0u;
1502  }
1503 }
1504 
1506 {
1507  const unsigned int horizontal = (unsigned int)(horizontalBin(point.x()));
1508  const unsigned int vertical = (unsigned int)(verticalBin(point.y()));
1509 
1510  if (horizontal < horizontalBins_ && vertical < verticalBins_)
1511  {
1512  occupancy_[vertical * horizontalBins_ + horizontal] = 1u;
1513  }
1514 
1515  return *this;
1516 }
1517 
1519 {
1520  const unsigned int horizontal = (unsigned int)(horizontalBin(point.x()));
1521  const unsigned int vertical = (unsigned int)(verticalBin(point.y()));
1522 
1523  if (horizontal < horizontalBins_ && vertical < verticalBins_)
1524  {
1525  occupancy_[vertical * horizontalBins_ + horizontal] = 0u;
1526  }
1527 
1528  return *this;
1529 }
1530 
1531 inline bool SpatialDistribution::OccupancyArray::operator()(const unsigned int horizontal, const unsigned int vertical) const
1532 {
1533  ocean_assert(horizontal < horizontalBins_);
1534  ocean_assert(vertical < verticalBins_);
1535 
1536  return occupancy_[vertical * horizontalBins_ + horizontal] != 0u;
1537 }
1538 
1539 inline unsigned int& SpatialDistribution::OccupancyArray::operator()(const unsigned int horizontal, const unsigned int vertical)
1540 {
1541  ocean_assert(horizontal < horizontalBins_);
1542  ocean_assert(vertical < verticalBins_);
1543 
1544  return occupancy_[vertical * horizontalBins_ + horizontal];
1545 }
1546 
1548 {
1549  const unsigned int xBin = horizontalBin(point.x());
1550  const unsigned int yBin = verticalBin(point.y());
1551 
1552  return xBin < horizontalBins_ && yBin < horizontalBins_ && occupancy_[yBin * horizontalBins_ + xBin] != 0u;
1553 }
1554 
1555 inline bool SpatialDistribution::OccupancyArray::operator[](const unsigned int index) const
1556 {
1557  ocean_assert(index < horizontalBins_ * verticalBins_);
1558  return occupancy_[index] != 0u;
1559 }
1560 
1561 inline unsigned int& SpatialDistribution::OccupancyArray::operator[](const unsigned int index)
1562 {
1563  ocean_assert(index < horizontalBins_ * verticalBins_);
1564  return occupancy_[index];
1565 }
1566 
1568 {
1569  Array::operator=((Array&)object);
1570  occupancy_ = object.occupancy_;
1571 
1572  return *this;
1573 }
1574 
1576 {
1577  if (this != &object)
1578  {
1579  Array::operator=(std::move((Array&)object));
1580  occupancy_ = std::move(object.occupancy_);
1581  }
1582 
1583  return *this;
1584 }
1585 
1586 inline bool SpatialDistribution::OccupancyArray::operator==(const OccupancyArray& occupancyArray) const
1587 {
1588  if (!Array::operator==(occupancyArray))
1589  {
1590  return false;
1591  }
1592 
1593  return occupancy_ == occupancyArray.occupancy_;
1594 }
1595 
1596 inline bool SpatialDistribution::OccupancyArray::operator!=(const OccupancyArray& occupancyArray) const
1597 {
1598  return !(*this == occupancyArray);
1599 }
1600 
1601 inline SpatialDistribution::DistanceElement::DistanceElement(const unsigned int index, const unsigned int candidateIndex, const Scalar distance) :
1602  index_(index),
1603  candidateIndex_(candidateIndex),
1604  distance_(distance)
1605 {
1606  // nothing to do here
1607 }
1608 
1610 {
1611  return index_;
1612 }
1613 
1615 {
1616  return candidateIndex_;
1617 }
1618 
1620 {
1621  return distance_;
1622 }
1623 
1625 {
1626  return left.distance_ < right.distance_;
1627 }
1628 
1630 {
1631  return left.distance_ > right.distance_;
1632 }
1633 
1635 {
1636  // ** TODO** this mismatch between comparison operators should be fixed
1637 
1638  return distance_ > element.distance_;
1639 }
1640 
1641 template <unsigned int tMaximalBins>
1642 inline SpatialDistribution::DistributionArray SpatialDistribution::distributeToArray(const ImagePoint* imagePoints, const size_t number, const Scalar left, const Scalar top, const Scalar width, const Scalar height, const Scalar searchDistance)
1643 {
1644  static_assert(tMaximalBins > 0u, "Invalid maximal bin parameter!");
1645 
1646  const unsigned int horizontalBins = min(tMaximalBins, (unsigned int)Numeric::ceil(width / max(searchDistance, Scalar(2))));
1647  const unsigned int verticalBins = min(tMaximalBins, (unsigned int)Numeric::ceil(height / max(searchDistance, Scalar(2))));
1648 
1649  return distributeToArray(imagePoints, number, left, top, width, height, horizontalBins, verticalBins);
1650 }
1651 
1652 template <typename T, const Vector2& (*tFunction)(const T&)>
1653 SpatialDistribution::DistributionArray SpatialDistribution::distributeToArray(const T* elements, const size_t number, const Scalar left, const Scalar top, const Scalar width, const Scalar height, const unsigned int horizontalBins, const unsigned int verticalBins)
1654 {
1655  ocean_assert(elements);
1656  ocean_assert(width > 0 && height > 0);
1657 
1658  ocean_assert(horizontalBins > 0);
1659  ocean_assert(verticalBins > 0);
1660 
1661  ocean_assert(Scalar(horizontalBins) <= width);
1662  ocean_assert(Scalar(verticalBins) <= width);
1663 
1664  // reserve enough array elements
1665  DistributionArray indexArray(left, top, width, height, horizontalBins, verticalBins);
1666 
1667  for (size_t n = 0; n < number; ++n)
1668  {
1669  const Vector2& point = tFunction(*elements);
1670 
1671  const unsigned int horizontal = (unsigned int)(indexArray.horizontalBin(point.x()));
1672  const unsigned int vertical = (unsigned int)(indexArray.verticalBin(point.y()));
1673 
1674  // discard points with negative bin value or bin value larger than the smallest allowed one (due to unsigned int negative values are discarded as well)
1675  if (horizontal < indexArray.horizontalBins() && vertical < indexArray.verticalBins())
1676  {
1677  indexArray(horizontal, vertical).push_back((unsigned int)n);
1678  }
1679 
1680  ++elements;
1681  }
1682 
1683  return indexArray;
1684 }
1685 
1686 inline SpatialDistribution::DistributionArray SpatialDistribution::distributeToArray(const ImagePoint* imagePoints, const size_t number, const Scalar left, const Scalar top, const Scalar width, const Scalar height, const unsigned int averagePointsPerBin, const unsigned int maxHorizontalBins, const unsigned int maxVerticalBins, unsigned int& horizontalBins, unsigned int& verticalBins)
1687 {
1688  ocean_assert(imagePoints || number == 0);
1689 
1690  ocean_assert(width > 0 && height > 0);
1691  ocean_assert(averagePointsPerBin > 0);
1692 
1693  ocean_assert(maxHorizontalBins >= 1u);
1694  ocean_assert(maxVerticalBins >= 1u);
1695 
1696  if (number == 0)
1697  {
1698  return DistributionArray(left, top, width, height, horizontalBins, verticalBins);
1699  }
1700 
1701  /**
1702  * averagePointsPerBin * horizontalBins * verticalBins = number
1703  * horizontalBins / verticalBins = width / height
1704  */
1705 
1706  const Scalar sqr = max(Scalar(1), (Scalar(number) * width) / (Scalar(averagePointsPerBin) * height));
1707 
1708  horizontalBins = min(maxHorizontalBins, max(1u, (unsigned int)(Numeric::sqrt(sqr))));
1709  verticalBins = min(maxVerticalBins, max(1u, (unsigned int)(Scalar(horizontalBins) * height / width)));
1710 
1711  return distributeToArray(imagePoints, number, left, top, width, height, horizontalBins, verticalBins);
1712 }
1713 
1714 inline ImagePoints SpatialDistribution::distributeAndFilter(const ImagePoint* imagePoints, const size_t numberImagePoints, const Scalar left, const Scalar top, const Scalar width, const Scalar height, const unsigned int horizontalBins, const unsigned int verticalBins)
1715 {
1716  return distributeAndFilter<ImagePoint, &SpatialDistribution::identity>(imagePoints, numberImagePoints, left, top, width, height, horizontalBins, verticalBins);
1717 }
1718 
1719 template <typename TIndex>
1720 inline std::vector<TIndex> SpatialDistribution::distributeAndFilterIndices(const ImagePoint* imagePoints, const size_t numberImagePoints, const Scalar left, const Scalar top, const Scalar width, const Scalar height, const unsigned int horizontalBins, const unsigned int verticalBins)
1721 {
1722  return distributeAndFilterIndices<ImagePoint, TIndex, &SpatialDistribution::identity>(imagePoints, numberImagePoints, left, top, width, height, horizontalBins, verticalBins);
1723 }
1724 
1725 template <typename T, Vector2 (*tFunction)(const T&)>
1726 typename std::vector<T> SpatialDistribution::distributeAndFilter(const T* elements, const size_t numberElements, const Scalar left, const Scalar top, const Scalar width, const Scalar height, const unsigned int horizontalBins, const unsigned int verticalBins)
1727 {
1728  ocean_assert(elements || numberElements == 0);
1729  ocean_assert(width >= 0 && height >= 0);
1730  ocean_assert(horizontalBins >= 1u && verticalBins >= 1u);
1731 
1732  if (numberElements == 0)
1733  {
1734  return std::vector<T>();
1735  }
1736 
1737  OccupancyArray occupancyArray(left, top, width, height, horizontalBins, verticalBins);
1738 
1739  const size_t bins = occupancyArray.bins();
1740 
1741  std::vector<T> result;
1742  result.reserve(bins);
1743 
1744  for (size_t n = 0; n < numberElements && result.size() < bins; ++n)
1745  {
1746  if (occupancyArray.addPoint(tFunction(elements[n])))
1747  {
1748  result.push_back(elements[n]);
1749  }
1750  }
1751 
1752  return result;
1753 }
1754 
1755 template <typename T, Vector2 (*tFunction)(const T&)>
1756 typename std::vector<T> SpatialDistribution::distributeAndFilter(const T* elements, const size_t numberElements, const Scalar left, const Scalar top, const Scalar width, const Scalar height, const unsigned int horizontalBins, const unsigned int verticalBins, const size_t numberDesiredFilteredElements, Indices32* indices)
1757 {
1758  ocean_assert(elements != nullptr || numberElements == 0);
1759  ocean_assert(width >= 0 && height >= 0);
1760  ocean_assert(horizontalBins >= 1u && verticalBins >= 1u);
1761  ocean_assert(numberDesiredFilteredElements <= numberElements);
1762 
1763  if (numberElements == 0 || numberDesiredFilteredElements == 0)
1764  {
1765  return std::vector<T>();
1766  }
1767 
1768  OccupancyArray occupancyArray(left, top, width, height, horizontalBins, verticalBins);
1769 
1770  std::vector<unsigned char> usedElements(numberElements, 0u);
1771 
1772  const size_t bins = occupancyArray.bins();
1773 
1774  std::vector<T> result;
1775  result.reserve(bins);
1776 
1777  unsigned int filterIteration = 0u;
1778 
1779  while (result.size() < numberDesiredFilteredElements && filterIteration < (unsigned int)numberDesiredFilteredElements)
1780  {
1781  for (size_t n = 0; n < numberElements && result.size() < numberDesiredFilteredElements; ++n)
1782  {
1783  if (usedElements[n] == 0u && occupancyArray.addPointWithCounter(tFunction(elements[n]), filterIteration))
1784  {
1785  result.push_back(elements[n]);
1786  usedElements[n] = 1u;
1787  }
1788  }
1789 
1790  filterIteration++;
1791  }
1792 
1793  if (indices)
1794  {
1795  for (size_t n = 0; n < numberElements; ++n)
1796  {
1797  if(usedElements[n])
1798  {
1799  indices->push_back(Index32(n));
1800  }
1801  }
1802  }
1803 
1804  return result;
1805 }
1806 
1807 template <typename T, typename TIndex, Vector2 (*tFunction)(const T&)>
1808 typename std::vector<TIndex> SpatialDistribution::distributeAndFilterIndices(const T* elements, const size_t numberElements, const Scalar left, const Scalar top, const Scalar width, const Scalar height, const unsigned int horizontalBins, const unsigned int verticalBins)
1809 {
1810  ocean_assert(elements || numberElements == 0);
1811  ocean_assert(width >= 0 && height >= 0);
1812  ocean_assert(horizontalBins >= 1u && verticalBins >= 1u);
1813 
1814  if (numberElements == 0)
1815  {
1816  return std::vector<TIndex>();
1817  }
1818 
1819  ocean_assert((unsigned long long)(numberElements) <= (unsigned long long)(NumericT<TIndex>::maxValue()));
1820 
1821  OccupancyArray occupancyArray(left, top, width, height, horizontalBins, verticalBins);
1822 
1823  const size_t bins = occupancyArray.bins();
1824 
1825  std::vector<TIndex> result;
1826  result.reserve(bins);
1827 
1828  for (size_t n = 0; n < numberElements && result.size() < bins; ++n)
1829  {
1830  if (occupancyArray.addPoint(tFunction(elements[n])))
1831  {
1832  result.push_back(TIndex(n));
1833  }
1834  }
1835 
1836  return result;
1837 }
1838 
1839 template <typename T>
1840 inline T SpatialDistribution::identity(const T& value)
1841 {
1842  return value;
1843 }
1844 
1845 }
1846 
1847 }
1848 
1849 #endif // META_OCEAN_GEOMETRY_SPATIAL_DISTRIBUTION_H
This class implements a base class for data arrays.
Definition: SpatialDistribution.h:37
unsigned int horizontalBins() const
Returns the number of horizontal distribution bins.
Definition: SpatialDistribution.h:1079
Scalar width() const
Returns the width of the distribution area.
Definition: SpatialDistribution.h:1069
int horizontalBin(const Scalar x) const
Returns the horizontal bin of a given horizontal position.
Definition: SpatialDistribution.h:1105
int verticalBin(const Scalar y) const
Returns the vertical bin of a given vertical position.
Definition: SpatialDistribution.h:1111
Scalar horizontalPoint2Bin_
Horizontal position to bin factor.
Definition: SpatialDistribution.h:218
Array & operator=(const Array &object)
Assign operator.
Definition: SpatialDistribution.h:1156
Scalar areaTop_
Top position of the distribution area.
Definition: SpatialDistribution.h:203
Scalar top() const
Returns the top position of the distribution area.
Definition: SpatialDistribution.h:1064
unsigned int verticalBins() const
Returns the number of vertical distribution bins.
Definition: SpatialDistribution.h:1084
int clampedVerticalBin(const Scalar y) const
Returns the vertical bin of a given vertical position.
Definition: SpatialDistribution.h:1123
Scalar areaLeft_
Left position of the distribution area.
Definition: SpatialDistribution.h:200
Scalar areaHeight_
Height of the distribution area.
Definition: SpatialDistribution.h:209
Array()=default
Creates an empty array object.
int clampedHorizontalBin(const Scalar x) const
Returns the horizontal bin of a given horizontal position.
Definition: SpatialDistribution.h:1117
bool isValid() const
Returns whether this object holds a valid distribution.
Definition: SpatialDistribution.h:1129
Scalar height() const
Returns the height of the distribution area.
Definition: SpatialDistribution.h:1074
Scalar verticalPoint2Bin_
Vertical position to bin factor.
Definition: SpatialDistribution.h:221
bool operator==(const Array &right) const
Returns whether two Array objects are identical.
Definition: SpatialDistribution.h:1134
bool operator!=(const Array &right) const
Returns whether two Array objects are not identical.
Definition: SpatialDistribution.h:1146
Scalar areaWidth_
Width of the distribution area.
Definition: SpatialDistribution.h:206
unsigned int verticalBins_
Number of vertical distribution bins.
Definition: SpatialDistribution.h:215
Array(const Array &object)=default
Copy constructor.
unsigned int horizontalBins_
Number of horizontal distribution bins.
Definition: SpatialDistribution.h:212
Scalar left() const
Returns the left position of the distribution area.
Definition: SpatialDistribution.h:1059
unsigned int index(const Scalar x, const Scalar y) const
Returns the bin index for a given position.
Definition: SpatialDistribution.h:1094
unsigned int bins() const
Returns the number of bins this distribution holds.
Definition: SpatialDistribution.h:1089
Definition of a class holding an index and a distance.
Definition: SpatialDistribution.h:585
Scalar distance_
Distance value.
Definition: SpatialDistribution.h:645
unsigned int candidateIndex() const
Returns the candidate index of this element.
Definition: SpatialDistribution.h:1614
static bool compareLeftSmaller(const DistanceElement &left, const DistanceElement &right)
Compares two distance elements.
Definition: SpatialDistribution.h:1624
unsigned int index() const
Returns the interest index of this element.
Definition: SpatialDistribution.h:1609
static bool compareLeftHigher(const DistanceElement &left, const DistanceElement &right)
Compares two distance elements.
Definition: SpatialDistribution.h:1629
DistanceElement(const unsigned int index, const unsigned int candidateIndex, const Scalar distance)
Creates a new distance element.
Definition: SpatialDistribution.h:1601
bool operator<(const DistanceElement &element) const
Returns whether the left element holds a higher distance than the right one.
Definition: SpatialDistribution.h:1634
Scalar distance() const
Returns the distance of this element.
Definition: SpatialDistribution.h:1619
This class implements a distribution array.
Definition: SpatialDistribution.h:228
DistributionArray()=default
Creates an empty distribution array object.
bool hasCopiedNeighborhood8() const
Returns whether this distribution array contains copies of indices within the 8-neighborhood of each ...
Definition: SpatialDistribution.h:1215
DistributionArray & operator=(const DistributionArray &object)
Assign operator.
Definition: SpatialDistribution.h:1248
bool hasCopiedNeighborhood8_
True, if the array contains copies of indices within the 8-neighborhood of each individual bin; False...
Definition: SpatialDistribution.h:363
void clear()
Removes all elements form this array.
DistributionArray(const DistributionArray &object)=default
Copy constructor.
const Indices32 & operator()(const unsigned int horizontal, const unsigned int vertical) const
Returns the distribution indices of a specified bin.
Definition: SpatialDistribution.h:1220
IndexGroups32 indexGroups_
Distribution array with point indices.
Definition: SpatialDistribution.h:360
const Indices32 & operator[](const unsigned int index) const
Returns the distribution indices of a specified bin.
Definition: SpatialDistribution.h:1236
DistributionArray(const DistributionArray &distributionArray, const bool copyNeighborhood8)
Copies a given distribution array and optional copies the indices from the 8-neighborhood of each ind...
bool operator!=(const DistributionArray &distributionArray) const
Returns whether two DistributionArray objects are not identical.
Definition: SpatialDistribution.h:1281
bool operator==(const DistributionArray &distributionArray) const
Returns whether two DistributionArray objects are identical.
Definition: SpatialDistribution.h:1271
void indicesNeighborhood9(const unsigned int horizontal, const unsigned int vertical, Indices32 &indices) const
Returns the indices of the 8-neighborhood and the specified bin itself.
Indices32 indicesNeighborhood9(const unsigned int horizontal, const unsigned int vertical) const
Returns the indices of the 8-neighborhood and the specified bin itself.
This class implements an occupancy array.
Definition: SpatialDistribution.h:370
OccupancyArray & operator+=(const Vector2 &point)
Adds an image point to this occupancy array.
Definition: SpatialDistribution.h:1505
bool operator!=(const OccupancyArray &occupancyArray) const
Returns whether two OccupancyArray objects are not identical.
Definition: SpatialDistribution.h:1596
unsigned int freeBins() const
Returns the number of free bins.
Definition: SpatialDistribution.h:1425
bool isNotOccupiedNeighborhood9(const unsigned int horizontal, const unsigned int vertical) const
Returns whether at least one bin in the 8-neighborhood or the specified bin itself is not occupied.
Definition: SpatialDistribution.h:1369
OccupancyArray & operator-=(const Vector2 &point)
Removes an image point from this occupancy array.
Definition: SpatialDistribution.h:1518
unsigned int occupiedBins() const
Returns the number of occupied bins.
Definition: SpatialDistribution.h:1410
unsigned int countOccupiedNeighborhood9(const unsigned int horizontal, const unsigned int vertical) const
Returns the number of occupied bins in the 9-neighborhood (so the specified bin is included).
Definition: SpatialDistribution.h:1307
OccupancyArray()=default
Creates an empty distribution array object.
OccupancyArray & operator=(const OccupancyArray &object)
Assign operator.
Definition: SpatialDistribution.h:1567
bool isOccupiedNeighborhood9(const unsigned int horizontal, const unsigned int vertical) const
Returns whether at least one bin in the 8-neighborhood or the specified bin itself is occupied.
Definition: SpatialDistribution.h:1328
void reset()
Resets all occupied bins so that all bins a free afterwards.
Definition: SpatialDistribution.h:1497
bool removePoint(const Vector2 &point)
Removes an image point and returns whether the corresponding bin was occupied before.
Definition: SpatialDistribution.h:1478
bool addPointWithCounter(const Vector2 &point, const unsigned int maximalOccupancyCounter)
Adds an image point and returns whether the occupancy counter of the corresponding bin was equal or b...
Definition: SpatialDistribution.h:1459
bool addPoint(const Vector2 &point)
Adds an image point and returns whether the corresponding bin was not occupied before (was free befor...
Definition: SpatialDistribution.h:1440
OccupancyArray(const OccupancyArray &object)=default
Copy constructor.
bool operator()(const unsigned int horizontal, const unsigned int vertical) const
Returns whether a specified bin is occupied.
Definition: SpatialDistribution.h:1531
bool operator==(const OccupancyArray &occupancyArray) const
Returns whether two OccupancyArray objects are identical.
Definition: SpatialDistribution.h:1586
Indices32 occupancy_
Occupancy array.
Definition: SpatialDistribution.h:578
bool operator[](const unsigned int index) const
Returns whether a specified bin is occupied.
Definition: SpatialDistribution.h:1555
This class implements spatial distribution function for 2D geometric data.
Definition: SpatialDistribution.h:30
static void determineMinimalSqrDistances(const ImagePoint *imagePoints, const size_t numberImagePoints, const unsigned int width, const unsigned int height, const unsigned int bins, Scalar *sqrDistances)
Determines the minimal square distances for each given 2D image point to all other points in the same...
static Index32 determineNearestNeighbor(const ImagePoint &interestPoint, const ImagePoint *imagePoints, const size_t numberImagePoints, const Scalar radius, const DistributionArray &distributionImagePoints, Scalar *sqrDistance=nullptr)
Determines the nearest image point between an interest point and a set of given image point lying ins...
static DistributionArray distributeToArray(const ImagePoint *imagePoints, const size_t number, const Scalar left, const Scalar top, const Scalar width, const Scalar height, const unsigned int averagePointsPerBin, const unsigned int maxHorizontalBins, const unsigned int maxVerticalBins, unsigned int &horizontalBins, unsigned int &verticalBins)
Distributes the given 2D image points into a spatial array.
Definition: SpatialDistribution.h:1686
static ImagePoints distributeAndFilter(const ImagePoint *imagePoints, const size_t numberImagePoints, const Scalar left, const Scalar top, const Scalar width, const Scalar height, const unsigned int horizontalBins, const unsigned int verticalBins, const size_t size)
Distributes the given image points into an array of specified size and returns as much points as requ...
static OccupancyArray createOccupancyArray(const ImagePoint *imagePoints, const size_t number, const Scalar left, const Scalar top, const Scalar width, const Scalar height, const unsigned int horizontalBins, const unsigned int verticalBins)
Distributes the given 2D image points into a spatial array.
static void idealBins(const unsigned int width, const unsigned int height, const size_t numberBins, unsigned int &horizontalBins, unsigned int &verticalBins, const unsigned int minimalHorizontalBins=2u, const unsigned int minimalVerticalBins=2u)
Calculates the ideal number of horizontal and vertical bins for an array if the overall number of bin...
static DistributionArray distributeToArray(const ImagePoint *imagePoints, const size_t number, const Scalar left, const Scalar top, const Scalar width, const Scalar height, const unsigned int horizontalBins, const unsigned int verticalBins)
Distributes a set of given 2D image points into a spatial array.
static Indices32 filterAccordingDistance(const ImagePoint *imagePoints, const size_t number, const unsigned int width, const unsigned int height, const Scalar distance)
Filters the given 2D image points according to their distance to neighboring image points.
std::vector< DistanceElement > DistanceElements
Definition of a vector holding distance elements.
Definition: SpatialDistribution.h:651
static void determineMinimalSqrDistances(const ImagePoint *imagePoints, const size_t numberImagePoints, const ImagePoint *candidates, const size_t numberCandidates, const unsigned int width, const unsigned int height, const unsigned int bins, Scalar *sqrDistances)
Determines the minimal square distances for each given 2D image point to another given set of 2D imag...
static DistanceElements sortAccordingDistance(const ImagePoint *imagePoints, const size_t number, const unsigned int width, const unsigned int height, const unsigned int bins, const bool minimalDistanceFirst)
Sorts the given 2D image points according to their minimal distance to neighboring image points.
static std::vector< TIndex > distributeAndFilterIndices(const ImagePoint *imagePoints, const size_t numberImagePoints, const Scalar left, const Scalar top, const Scalar width, const Scalar height, const unsigned int horizontalBins, const unsigned int verticalBins)
Distributes the given image points into an array of specified size and returns (at most) one point in...
Definition: SpatialDistribution.h:1720
static void determineMinimalSqrDistances(const ImagePoint *imagePoints, const size_t numberImagePoints, const ImagePoint *candidates, const size_t numberCandidates, const DistributionArray &distributionCandidates, Scalar *sqrDistances, unsigned int *candidateIndices=nullptr)
Determines the minimal square distances for each given image point to another given set of image poin...
static Scalar determineMinimalSqrDistance(const ImagePoint *imagePoints, const size_t numberImagePoints, const unsigned int index, const DistributionArray &distributionImagePoints)
Determines the minimal square distance for one given 2D image point to all other points in the same s...
static DistanceElements sortAccordingDistance(const ImagePoint *imagePoints, const size_t number, const bool minimalDistanceFirst)
Sorts the given 2D image points according to their minimal distance to neighboring image points.
static Indices32 determineNeighbors(const ImagePoint &imagePoint, const ImagePoint *candidatePoints, const size_t numberCandidatePoints, const Scalar radius, const DistributionArray &distributionCandidatePoints)
Determines all candidate points for a given image point (interest point) lying inside a specified cir...
static void idealBinsNeighborhood9(const unsigned int width, const unsigned int height, const Scalar distance, unsigned int &horizontalBins, unsigned int &verticalBins, const unsigned int minimalHorizontalBins=2u, const unsigned int minimalVerticalBins=2u, const unsigned int maximalHorizontalBins=20u, const unsigned int maximalVerticalBins=20u)
Calculates the ideal number of horizontal and vertical bins for an array if bin elements within a cer...
static T identity(const T &value)
This function simply returns the given object (actually a copy of the object).
Definition: SpatialDistribution.h:1840
static ImagePoints distributeAndFilter(const ImagePoint *imagePoints, const size_t numberImagePoints, const Scalar left, const Scalar top, const Scalar width, const Scalar height, const unsigned int horizontalBins, const unsigned int verticalBins)
Distributes the given image points into an array of specified size and returns (at most) one point fr...
Definition: SpatialDistribution.h:1714
static void filterCandidatePoint(const ImagePoint *imagePoints, const size_t numberImagePoints, const ImagePoint *candidatePoints, const size_t numberCandidatePoints, const unsigned int width, const unsigned int height, const Scalar filterDistance, const unsigned int filterSize, Indices32 *filteredIndices=nullptr, ImagePoints *filteredCandidates=nullptr)
Filters the given 2D candidate points according to the distance to the given image points.
static void determineMinimalSqrDistances(const ImagePoint *imagePoints, const size_t numberImagePoints, const unsigned int *interestIndices, const size_t numberInterestIndices, const unsigned int width, const unsigned int height, const unsigned int bins, Scalar *sqrDistances)
Determines the minimal square distances for each specified image point inside their neighborhood.
This class provides basic numeric functionalities.
Definition: Numeric.h:57
static T sqrt(const T value)
Returns the square root of a given value.
Definition: Numeric.h:1533
static constexpr T eps()
Returns a small epsilon.
static T floor(const T value)
Returns the largest integer value that is not greater than the given value.
Definition: Numeric.h:2026
static T ceil(const T value)
Returns the smallest integer value that is not less than the given value.
Definition: Numeric.h:1988
const T & x() const noexcept
Returns the x value.
Definition: Vector2.h:698
const T & y() const noexcept
Returns the y value.
Definition: Vector2.h:710
unsigned int sqrDistance(const char first, const char second)
Returns the square distance between two values.
Definition: base/Utilities.h:1089
std::vector< Indices32 > IndexGroups32
Definition of a vector holding 32 bit indices, so we have groups of indices.
Definition: Base.h:102
std::vector< Index32 > Indices32
Definition of a vector holding 32 bit index values.
Definition: Base.h:96
unsigned int sqr(const char value)
Returns the square value of a given value.
Definition: base/Utilities.h:1029
uint32_t Index32
Definition of a 32 bit index value.
Definition: Base.h:84
std::vector< ImagePoint > ImagePoints
Definition of a vector holding 2D image points.
Definition: geometry/Geometry.h:123
float Scalar
Definition of a scalar type.
Definition: Math.h:128
The namespace covering the entire Ocean framework.
Definition: Accessor.h:15