Ocean
Loading...
Searching...
No Matches
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
14
15#include "ocean/math/Box2.h"
16
17#include <algorithm>
18
19namespace Ocean
20{
21
22namespace Geometry
23{
24
25/**
26 * This class implements spatial distribution function for 2D geometric data.
27 * @ingroup geometry
28 */
29class 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.
464 * @param point The point to be added, with range (-infinity, infinity)x(-infinity, infinity)
465 * @return True, if the point was added to an empty bin; False, if the bin was already occupied or the point was outside the array
466 */
467 inline bool addPoint(const Vector2& point);
468
469 /**
470 * Adds an image point and returns whether the occupancy counter of the corresponding bin was equal or below a specified value.
471 * If the point lies outside the array False is returned.<br>
472 * The occupancy counter of the bin (if valid) to which the given point belongs will be incremented.<br>
473 * Beware: This function should not be used in conjunction with any other addPoint(), removePoint() function not leveraging a occupancy counter.
474 * @param point The point to be added, with range (-infinity, infinity)x(-infinity, infinity)
475 * @param maximalOccupancyCounter The maximal occupancy counter the corresponding bin may have to add the point.
476 * @return True, if so
477 */
478 inline bool addPointWithCounter(const Vector2& point, const unsigned int maximalOccupancyCounter);
479
480 /**
481 * Removes an image point and returns whether the corresponding bin was occupied before.
482 * If the point lies outside the array False is returned.<br>
483 * The bin (if valid) which belongs to the given point is free (not occupied) after the function returns.
484 * @param point The point to be removed, with range (-infinity, infinity)x(-infinity, infinity)
485 * @return True, if so
486 */
487 inline bool removePoint(const Vector2& point);
488
489 /**
490 * Resets all occupied bins so that all bins a free afterwards.
491 */
492 inline void reset();
493
494 /**
495 * Adds an image point to this occupancy array.
496 * The bin (if valid) which belongs to the given point is occupied after the function returns.
497 * @param point The point to be added, with range (-infinity, infinity)x(-infinity, infinity)
498 * @return Reference to this object
499 */
500 inline OccupancyArray& operator+=(const Vector2& point);
501
502 /**
503 * Removes an image point from this occupancy array.
504 * The bin (if valid) which belongs to the given point is free (not occupied) after the function returns.
505 * @return Reference to this object
506 */
507 inline OccupancyArray& operator-=(const Vector2& point);
508
509 /**
510 * Returns whether a specified bin is occupied.
511 * @param horizontal The horizontal distribution bin, with range [0, horizontalBins() - 1]
512 * @param vertical The vertical distribution bin, with range [0, verticalBins() - 1]
513 * @return True, if so
514 */
515 inline bool operator()(const unsigned int horizontal, const unsigned int vertical) const;
516
517 /**
518 * Returns whether the bin corresponding to a given point is occupied.
519 * @param point The point for which the bin has to be checked, with range (-infinity, infinity)x(-infinity, infinity)
520 * @return True, if so
521 */
522 inline bool operator()(const Vector2& point) const;
523
524 /**
525 * Returns whether a specified bin is occupied.
526 * @param horizontal The horizontal distribution bin, with range [0, horizontalBins() - 1]
527 * @param vertical The vertical distribution bin, with range [0, verticalBins() - 1]
528 * @return Non-zero, if so
529 */
530 inline unsigned int& operator()(const unsigned int horizontal, const unsigned int vertical);
531
532 /**
533 * Returns whether a specified bin is occupied.
534 * @param index The index of the specified bin, with range [0, horizontalBins() * verticalBins() - 1]
535 * @return True, if so
536 */
537 inline bool operator[](const unsigned int index) const;
538
539 /**
540 * Returns whether a specified bin is occupied.
541 * @param index The index of the specified bin, with range [0, horizontalBins() * verticalBins() - 1]
542 * @return Non-zero, if so
543 */
544 inline unsigned int& operator[](const unsigned int index);
545
546 /**
547 * Assign operator.
548 * @param object Occupancy array object to be assigned
549 * @return Reference to this object
550 */
551 inline OccupancyArray& operator=(const OccupancyArray& object);
552
553 /**
554 * Move operator.
555 * @param object Occupancy array object to be moved
556 * @return Reference to this object
557 */
558 inline OccupancyArray& operator=(OccupancyArray&& object) noexcept;
559
560 /**
561 * Returns whether two OccupancyArray objects are identical.
562 * @param occupancyArray The second array object to compare
563 * @return True, if so
564 */
565 inline bool operator==(const OccupancyArray& occupancyArray) const;
566
567 /**
568 * Returns whether two OccupancyArray objects are not identical.
569 * @param occupancyArray The second array object to compare
570 * @return True, if so
571 */
572 inline bool operator!=(const OccupancyArray& occupancyArray) const;
573
574 private:
575
576 /// Occupancy array.
578 };
579
580 /**
581 * Definition of a class holding an index and a distance.
582 */
583 class OCEAN_GEOMETRY_EXPORT DistanceElement
584 {
585 public:
586
587 /**
588 * Creates a new distance element.
589 * @param index Interest index to be stored
590 * @param candidateIndex Index of the candidate to be stored
591 * @param distance The distance to be stored
592 */
593 inline DistanceElement(const unsigned int index, const unsigned int candidateIndex, const Scalar distance);
594
595 /**
596 * Returns the interest index of this element.
597 * @return Stored index
598 */
599 inline unsigned int index() const;
600
601 /**
602 * Returns the candidate index of this element.
603 * @return Stored candidate index
604 */
605 inline unsigned int candidateIndex() const;
606
607 /**
608 * Returns the distance of this element.
609 * @return Stored distance
610 */
611 inline Scalar distance() const;
612
613 /**
614 * Compares two distance elements.
615 * @param left The left element to compare
616 * @param right The right element to compare
617 * @return True, if the left element has a smaller distance value than the right one
618 */
619 static inline bool compareLeftSmaller(const DistanceElement& left, const DistanceElement& right);
620
621 /**
622 * Compares two distance elements.
623 * @param left The left element to compare
624 * @param right The right element to compare
625 * @return True, if the left element has a higher distance value than the right one
626 */
627 static inline bool compareLeftHigher(const DistanceElement& left, const DistanceElement& right);
628
629 /**
630 * Returns whether the left element holds a higher distance than the right one.
631 * @return True, if so
632 */
633 inline bool operator<(const DistanceElement& element) const;
634
635 private:
636
637 /// Interest index.
638 unsigned int index_ = 0u;
639
640 /// Candidate index.
641 unsigned int candidateIndex_ = 0u;
642
643 /// Distance value.
644 Scalar distance_ = Scalar(-1);
645 };
646
647 /**
648 * Definition of a vector holding distance elements.
649 */
650 using DistanceElements = std::vector<DistanceElement>;
651
652 public:
653
654 /**
655 * Calculates the ideal number of horizontal and vertical bins for an array if the overall number of bins is known.
656 * This function tries to get bins with almost identical horizontal and vertical size.
657 * @param width The width of the area the array covers, with range [1, infinity)
658 * @param height The height of the area the array covers, with range [1, infinity)
659 * @param numberBins The number of bins that would be perfect, with range [1, infinity)
660 * @param horizontalBins The resulting number of horizontal bins that fit best with the given parameters, with range [minimalHorizontalBins, width]
661 * @param verticalBins The resulting number of vertical bins that fit best with the given parameters, with range [minimalVerticalBins, height]
662 * @param minimalHorizontalBins The minimal number of horizontal bins, with range [1, width]
663 * @param minimalVerticalBins The minimal number of vertical bins, with range [1, height]
664 */
665 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);
666
667 /**
668 * 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
669 * This function tries to get bins with almost identical horizontal and vertical size.
670 * @param width The width of the area the array covers, with range [1, infinity)
671 * @param height The height of the area the array covers, with range [1, infinity)
672 * @param distance The distance to other bin elements that should be guaranteed to be located in the 9 neighborhood, with range [1, infinity)
673 * @param horizontalBins The resulting number of horizontal bins that fit best with the given parameters, with range [minimalHorizontalBins, width]
674 * @param verticalBins The resulting number of vertical bins that fit best with the given parameters, with range [minimalVerticalBins, height]
675 * @param minimalHorizontalBins The minimal number of horizontal bins, with range [1, maximalHorizontalBins]
676 * @param minimalVerticalBins The minimal number of vertical bins, with range [1, maximalVerticalBins]
677 * @param maximalHorizontalBins The maximal number of horizontal bins, with range [minimalHorizontalBins, width]
678 * @param maximalVerticalBins The maximal number of vertical bins, with range [minimalVerticalBins, height]
679 */
680 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);
681
682 /**
683 * Distributes the given 2D image points into a spatial array.
684 * The number of used horizontal and vertical bins are calculated automatically.
685 * 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>
686 * Image points not fitting into the array bins are discarded.<br>
687 * @param imagePoints Image points to be distributed, may be nullptr if number==0
688 * @param number The number of given image points, with range [0, infinity)
689 * @param left Horizontal position of the area, may be 0 for e.g. an entire image, with range (-infinity, infinity)
690 * @param top Vertical position of the area, may be 0 for e.g. an entire image, with range (-infinity, infinity)
691 * @param width The width of the area holding the elements, with range (0, infinity)
692 * @param height The height of the area holding the elements, with range (0, infinity)
693 * @param averagePointsPerBin Average number of points per bin, with range [1, infinity)
694 * @param maxHorizontalBins Maximal number of horizontal bins, with range [1, infinity)
695 * @param maxVerticalBins Maximal number of vertical bins, with range [1, infinity)
696 * @param horizontalBins Resulting horizontal bins, with range [1, infinity)
697 * @param verticalBins Resulting vertical bins, with range [1, infinity)
698 * @return Resulting array holding the indices of the distributed image points, will be cleared before usage
699 */
700 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);
701
702 /**
703 * Distributes a set of given 2D image points into a spatial array.
704 * Image points not fitting into the array bins are discarded.
705 * @param imagePoints Image points to be distributed, with range (-infinity, infinity)x(-infinity, infinity), may be nullptr if number==0
706 * @param number The number of given image points, with range [0, infinity)
707 * @param left Horizontal position of the area, may be 0 for e.g. an entire image, with range (-infinity, infinity)
708 * @param top Vertical position of the area, may be 0 for e.g. an entire image, with range (-infinity, infinity)
709 * @param width The width of the area holding the points, with range (0, infinity)
710 * @param height The height of the area holding the points, with range (0, infinity)
711 * @param horizontalBins Number of horizontal bins to distribute the image points into, with range [1, infinity)
712 * @param verticalBins Number of vertical bins to distribute the image points into, with range [1, infinity)
713 * @return Resulting array holding the indices of the distributed image points
714 */
715 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);
716
717 /**
718 * Distributes the given elements into a spatial array.
719 * Elements not fitting into the array bins are discarded.
720 * @param elements The elements (e.g. holding image points) to be distributed
721 * @param number The number of given image points
722 * @param left Horizontal position of the area, may be 0 for e.g. an entire image, with range (-infinity, infinity)
723 * @param top Vertical position of the area, may be 0 for e.g. an entire image, with range (-infinity, infinity)
724 * @param width The width of the area holding the elements, with range (0, infinity)
725 * @param height The height of the area holding the elements, with range (0, infinity)
726 * @param horizontalBins Number of horizontal bins to distribute the image points into, with range [1, width]
727 * @param verticalBins Number of vertical bins to distribute the image points into, with range [1, height]
728 * @return Resulting array holding the indices of the distributed elements
729 * @tparam T Data type of the given elements
730 * @tparam tFunction Function pointer type of a function returning the 2D position of any element
731 */
732 template <typename T, const Vector2& (*tFunction)(const T&)>
733 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);
734
735 /**
736 * Distributes the given 2D image points into a spatial array.
737 * 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.
738 * Image points not fitting into the array bins are discarded.<br>
739 * @param imagePoints Image points to be distributed
740 * @param number The number of given image points
741 * @param left Horizontal position of the area, may be 0 for e.g. an entire image, with range (-infinity, infinity)
742 * @param top Vertical position of the area, may be 0 for e.g. an entire image, with range (-infinity, infinity)
743 * @param width The width of the area holding the points, with range (0, infinity)
744 * @param height The height of the area holding the points, with range (0, infinity)
745 * @param searchDistance Search distance that will be applied (minimal size of each bin)
746 * @return Resulting array holding the indices of the distributed image points
747 * @tparam tMaximalBins Number of maximal bins in each direction (horizontal and vertical), width range [1, infinity)
748 */
749 template <unsigned int tMaximalBins>
750 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);
751
752 /**
753 * Distributes the given 2D image points into a spatial array.
754 * 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.
755 * Image points not fitting into the array bins are discarded.<br>
756 * @param imagePoints Image points to be distributed, must be valid if the specified number is not zero
757 * @param number The number of given image points, with range [0, infinity)
758 * @param left Horizontal position of the area, may be 0 for e.g. an entire image, with range (-infinity, infinity)
759 * @param top Vertical position of the area, may be 0 for e.g. an entire image, with range (-infinity, infinity)
760 * @param width The width of the area holding the points, with range (0, infinity)
761 * @param height The height of the area holding the points, with range (0, infinity)
762 * @param horizontalBins Number of horizontal bins to distribute the image points into, with range [1, width]
763 * @param verticalBins Number of vertical bins to distribute the image points into, with range [1, height]
764 * @return Resulting array holding the indices of the distributed image points
765 */
766 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);
767
768 /**
769 * Filters the given 2D image points according to their distance to neighboring image points.
770 * @param imagePoints Image points (e.g. holding image points) to be filtered
771 * @param number The number of given image points
772 * @param width The width of the area holding the points in pixel, with range [1, infinity)
773 * @param height The height of the area holding the points in pixel, with range [1, infinity)
774 * @param distance The distance threshold to be used for filtering
775 * @return Resulting vector holding the indices of the found image points
776 */
777 static Indices32 filterAccordingDistance(const ImagePoint* imagePoints, const size_t number, const unsigned int width, const unsigned int height, const Scalar distance);
778
779 /**
780 * Filters the given 2D candidate points according to the distance to the given image points.
781 * @param imagePoints Image points for that the filtered candidate points have to be found
782 * @param numberImagePoints Number of image points
783 * @param candidatePoints Candidate points that will be filtered
784 * @param numberCandidatePoints Number of candidate points
785 * @param width The width of the area holding the image points, with range [1, infinity)
786 * @param height The height of the area holding the image points, with range [1, infinity)
787 * @param filterDistance Distance threshold that define whether a candidate point belongs to one image point
788 * @param filterSize Number of candidate points that can belong to one image point
789 * @param filteredIndices Resulting indices of the filtered candidate points, if defined
790 * @param filteredCandidates Resulting filtered candidate points, if defined
791 */
792 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);
793
794 /**
795 * Sorts the given 2D image points according to their minimal distance to neighboring image points.
796 * Points with higher distances will be returned before points with lower distances.
797 * @param imagePoints Image points (e.g. holding image points) to be sorted
798 * @param number The number of given image points
799 * @param minimalDistanceFirst True, to sort minimal distance to the front
800 * @return Resulting vector holding the indices and distances of the sorted image points
801 */
802 static DistanceElements sortAccordingDistance(const ImagePoint* imagePoints, const size_t number, const bool minimalDistanceFirst);
803
804 /**
805 * Sorts the given 2D image points according to their minimal distance to neighboring image points.
806 * Points with higher distances will be returned before points with lower distances.
807 * This function first distributes all points to array bins to speed up the computation.<br>
808 * @param imagePoints Image points (e.g. holding image points) to be sorted
809 * @param number The number of given image points
810 * @param width The width of the area holding the image points in pixel, with range [1, infinity)
811 * @param height The height of the area holding the image points in pixel, with range [1, infinity)
812 * @param bins Number of bins in each direction used for image point distribution
813 * @param minimalDistanceFirst True, to sort minimal distance to the front
814 * @return Resulting vector holding the indices and distances of the sorted image points
815 */
816 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);
817
818 /**
819 * Determines the minimal square distance for one given 2D image point to all other points in the same set.
820 * This function uses an already create point distribution to speed up the computation.<br>
821 * 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.
822 * @param imagePoints Image points to calculate the distances for
823 * @param numberImagePoints Number of given image points
824 * @param index The index of the image point to find the minimal square distance for, with range [0, numberImagePoints)
825 * @param distributionImagePoints Already created distribution array of the image points
826 * @return Resulting square distances calculated for the given image point
827 */
828 static Scalar determineMinimalSqrDistance(const ImagePoint* imagePoints, const size_t numberImagePoints, const unsigned int index, const DistributionArray& distributionImagePoints);
829
830 /**
831 * Determines the minimal square distances for each given 2D image point to all other points in the same set.
832 * This function first distributes all points to array bins to speed up the computation.<br>
833 * 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.
834 * @param imagePoints Image points to calculate the distances for, may be nullptr if numberImagePoints==0
835 * @param numberImagePoints Number of given image points, with range [0, infinity)
836 * @param width The width of the area holding the image points in pixel, with range [1, infinity)
837 * @param height The height of the area holding the image points in pixel, with range [1, infinity)
838 * @param bins Number of bins in each direction used for image point distribution, with range [1, infinity)
839 * @param sqrDistances Resulting square distances calculated for each given image point, make sure that this buffer holds enough space
840 */
841 static void determineMinimalSqrDistances(const ImagePoint* imagePoints, const size_t numberImagePoints, const unsigned int width, const unsigned int height, const unsigned int bins, Scalar* sqrDistances);
842
843 /**
844 * Determines the minimal square distances for each given 2D image point to another given set of 2D image points.
845 * This function first distributes all points to array bins to speed up the computation.<br>
846 * 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.
847 * @param imagePoints Image points to calculate the distances for, may be nullptr if numberImagePoints==0
848 * @param numberImagePoints Number of given image points, with range [0, infinity)
849 * @param candidates Image points being candidates as nearest neighbors for the given image points
850 * @param numberCandidates Number of given candidates
851 * @param width The width of the area holding the image points in pixel, with range [1, infinity)
852 * @param height The height of the area holding the image points in pixel, with range [1, infinity)
853 * @param bins Number of bins in each direction used for image point distribution
854 * @param sqrDistances Resulting square distances calculated for each given image point, make sure that this buffer holds enough space
855 */
856 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);
857
858 /**
859 * Determines the minimal square distances for each given image point to another given set of image points.
860 * 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.
861 * @param imagePoints Image points to calculate the distances for, may be nullptr if numberImagePoints==0
862 * @param numberImagePoints Number of given image points, with range [0, infinity)
863 * @param candidates Image points being candidates as nearest neighbors for the given image points
864 * @param numberCandidates Number of given candidates
865 * @param distributionCandidates Already created distribution array of the candidates
866 * @param sqrDistances Resulting square distances calculated for each given element, make sure that this buffer holds enough space
867 * @param candidateIndices Optional resulting indices of the candidate with minimal distance, make sure that this buffer holds enough space (if defined)
868 */
869 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);
870
871 /**
872 * Determines the minimal square distances for each specified image point inside their neighborhood.
873 * This function first distributes all image points to array bins to speed up the computation.<br>
874 * 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.
875 * @param imagePoints Image points holding the entire set, may be nullptr if numberImagePoints==0
876 * @param numberImagePoints Number of given image points, with range [0, infinity)
877 * @param interestIndices Indices of all interest image points to calculate the minimal distance for
878 * @param numberInterestIndices Number of given interest indices
879 * @param width The width of the area holding the elements in pixel, with range [1, infinity)
880 * @param height The height of the area holding the elements in pixel, with range [1, infinity)
881 * @param bins Number of bins in each direction used for element distribution
882 * @param sqrDistances Resulting square distances calculated for each given interest index, make sure that this buffer holds enough space
883 */
884 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);
885
886 /**
887 * Determines all candidate points for a given image point (interest point) lying inside a specified circle around the interest point.
888 * @param imagePoint The interest image point to find the neighboring candidate points for, with range (-infinity, infinity)x(-infinity, infinity)
889 * @param candidatePoints Candidate points to find the neighbors in
890 * @param numberCandidatePoints Number of given candidate points
891 * @param radius The radius specifying the circle around the interest point, with range [0, infinity)
892 * @param distributionCandidatePoints Already created distribution array of the candidate points
893 * @return Resulting indices of all neighbors out the candidate set lying within the specified circle.
894 */
895 static Indices32 determineNeighbors(const ImagePoint& imagePoint, const ImagePoint* candidatePoints, const size_t numberCandidatePoints, const Scalar radius, const DistributionArray& distributionCandidatePoints);
896
897 /**
898 * 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.
899 * @param interestPoint The interest image point for which the nearest neighbor will be determined, with range (-infinity, infinity)x(-infinity, infinity)
900 * @param imagePoints The set of image points from which the nearest neighbor will be determined
901 * @param numberImagePoints Number of given image points, with range [0, infinity)
902 * @param radius The radius specifying the circle around the interest point, with range [0, infinity)
903 * @param distributionImagePoints Already created distribution array of the image points
904 * @param sqrDistance Optional resulting square distance of the nearest image point, if any
905 * @return Resulting index of the nearest neighbor image point, -1 if no image point lies within the specified radius
906 */
907 static Index32 determineNearestNeighbor(const ImagePoint& interestPoint, const ImagePoint* imagePoints, const size_t numberImagePoints, const Scalar radius, const DistributionArray& distributionImagePoints, Scalar* sqrDistance = nullptr);
908
909 /**
910 * Distributes the given image points into an array of specified size and returns (at most) one point from each bin.
911 * @param imagePoints Image points to be distributed and filtered, may be nullptr if numberImagePoints==0
912 * @param numberImagePoints Number of given image points, with range [0, infinity)
913 * @param left Horizontal position of the area, may be 0 for e.g. an entire image, with range (-infinity, infinity)
914 * @param top Vertical position of the area, may be 0 for e.g. an entire image, with range (-infinity, infinity)
915 * @param width The width of the area holding the elements, with range (0, infinity)
916 * @param height The height of the area holding the elements, with range (0, infinity)
917 * @param horizontalBins Number of horizontal bins to be used for distribution, with range [1, infinity)
918 * @param verticalBins Number of vertical bins to be used for distribution, with range [1, infinity)
919 * @return Resulting filtered elements
920 */
921 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);
922
923 /**
924 * 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.
925 * @param imagePoints Image points to be distributed and filtered, may be nullptr if numberImagePoints==0
926 * @param numberImagePoints Number of given image points, with range [0, infinity)
927 * @param left Horizontal position of the area, may be 0 for e.g. an entire image, with range (-infinity, infinity)
928 * @param top Vertical position of the area, may be 0 for e.g. an entire image, with range (-infinity, infinity)
929 * @param width The width of the area holding the elements, with range (0, infinity)
930 * @param height The height of the area holding the elements, with range (0, infinity)
931 * @param horizontalBins Number of horizontal bins to be used for distribution, with range [1, infinity)
932 * @param verticalBins Number of vertical bins to be used for distribution, with range [1, infinity)
933 * @param size The number of requested feature points, with range [0, numberImagePoints]
934 * @return Resulting filtered elements
935 */
936 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);
937
938 /**
939 * Distributes the given image points into an array of specified size and returns (at most) one point index from each bin.
940 * The resulting indices can be used to filter the actual set of image points.<br>
941 * @param imagePoints Image points to be distributed and filtered, may be nullptr if numberImagePoints==0
942 * @param numberImagePoints Number of given image points, with range [0, infinity)
943 * @param left Horizontal position of the area, may be 0 for e.g. an entire image, with range (-infinity, infinity)
944 * @param top Vertical position of the area, may be 0 for e.g. an entire image, with range (-infinity, infinity)
945 * @param width The width of the area holding the elements, with range (0, infinity)
946 * @param height The height of the area holding the elements, with range (0, infinity)
947 * @param horizontalBins Number of horizontal bins to be used for distribution, with range [1, infinity)
948 * @param verticalBins Number of vertical bins to be used for distribution, with range [1, infinity)
949 * @return Resulting indices of the filtered elements
950 * @tparam TIndex The data type of the indices (e.g., may be Index32 or Index64)
951 */
952 template <typename TIndex>
953 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);
954
955 /**
956 * Distributes the given elements into an array of specified size and returns (at most) one element from each bin.
957 * @param elements The elements to be distributed and filtered, may be nullptr if numberImagePoints==0
958 * @param numberElements Number of given elements, with range [0, infinity)
959 * @param left Horizontal position of the area, may be 0 for e.g. an entire image, with range (-infinity, infinity)
960 * @param top Vertical position of the area, may be 0 for e.g. an entire image, with range (-infinity, infinity)
961 * @param width The width of the area holding the elements, with range (0, infinity)
962 * @param height The height of the area holding the elements, with range (0, infinity)
963 * @param horizontalBins Number of horizontal bins to be used for distribution, with range [1, infinity)
964 * @param verticalBins Number of vertical bins to be used for distribution, with range [1, infinity)
965 * @return Resulting filtered elements
966 * @tparam T The data type of the elements to be distributed
967 * @tparam tFunction The function pointer that returns the 2D position of each element
968 */
969 template <typename T, Vector2 (*tFunction)(const T&)>
970 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);
971
972 /**
973 * 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.
974 * This function should be used whenever the given elements are not distributed equally while a specified amount of feature points is desired.
975 * The function applies several filter iterations until the desired number of elements is reached.<br>
976 * After the first iteration each bin will contain at most one element, after the second iteration at most two elements, and so on.
977 * @param elements The elements to be distributed and filtered, may be nullptr if numberImagePoints==0
978 * @param numberElements Number of given elements, with range [0, infinity)
979 * @param left Horizontal position of the area, may be 0 for e.g. an entire image, with range (-infinity, infinity)
980 * @param top Vertical position of the area, may be 0 for e.g. an entire image, with range (-infinity, infinity)
981 * @param width The width of the area holding the elements, with range (0, infinity)
982 * @param height The height of the area holding the elements, with range (0, infinity)
983 * @param horizontalBins Number of horizontal bins to be used for distribution, with range [1, infinity)
984 * @param verticalBins Number of vertical bins to be used for distribution, with range [1, infinity)
985 * @param numberDesiredFilteredElements The desired number of filtered elements, with range [1, numberElements]
986 * @param indices Optional resulting indices of the selected keypoints, if defined indices will be pushed at the back.
987 * @return Resulting filtered elements
988 * @tparam T The data type of the elements to be distributed
989 * @tparam tFunction The function pointer that returns the 2D position of each element
990 */
991 template <typename T, Vector2 (*tFunction)(const T&)>
992 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);
993
994 /**
995 * Distributes the given elements into an array of specified size and returns (at most) one point index from each bin.
996 * The resulting indices can be used to filter the actual set of image points.<br>
997 * @param elements The elements to be distributed and filtered, may be nullptr if numberImagePoints==0
998 * @param numberElements Number of given elements, with range [0, infinity)
999 * @param left Horizontal position of the area, may be 0 for e.g. an entire image, with range (-infinity, infinity)
1000 * @param top Vertical position of the area, may be 0 for e.g. an entire image, with range (-infinity, infinity)
1001 * @param width The width of the area holding the elements, with range (0, infinity)
1002 * @param height The height of the area holding the elements, with range (0, infinity)
1003 * @param horizontalBins Number of horizontal bins to be used for distribution, with range [1, infinity)
1004 * @param verticalBins Number of vertical bins to be used for distribution, with range [1, infinity)
1005 * @return Resulting indices of the filtered elements
1006 * @tparam T The data type of the elements to be distributed
1007 * @tparam TIndex The data type of the indices (e.g., may be Index32 or Index64)
1008 * @tparam tFunction The function pointer that returns the 2D position of each element
1009 */
1010 template <typename T, typename TIndex, Vector2 (*tFunction)(const T&)>
1011 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);
1012
1013 protected:
1014
1015 /**
1016 * This function simply returns the given object (actually a copy of the object).
1017 * @param value The value to be returned
1018 * @return The given value
1019 * @tparam T The data type of the value
1020 */
1021 template <typename T>
1022 static inline T identity(const T& value);
1023};
1024
1025inline SpatialDistribution::Array::Array(Array&& object) noexcept :
1026 areaLeft_(object.areaLeft_),
1027 areaTop_(object.areaTop_),
1028 areaWidth_(object.areaWidth_),
1029 areaHeight_(object.areaHeight_),
1030 horizontalBins_(object.horizontalBins_),
1031 verticalBins_(object.verticalBins_),
1032 horizontalPoint2Bin_(object.horizontalPoint2Bin_),
1033 verticalPoint2Bin_(object.verticalPoint2Bin_)
1034{
1035 object.areaLeft_ = Scalar(0);
1036 object.areaTop_ = Scalar(0);
1037 object.areaWidth_ = Scalar(0);
1038 object.areaHeight_ = Scalar(0);
1039 object.horizontalBins_ = 0u;
1040 object.verticalBins_ = 0u;
1041 object.horizontalPoint2Bin_ = Scalar(0);
1042 object.verticalPoint2Bin_ = Scalar(0);
1043}
1044
1045inline SpatialDistribution::Array::Array(const Scalar left, const Scalar top, const Scalar width, const Scalar height, const unsigned int horizontalBins, const unsigned int verticalBins) :
1046 areaLeft_(left),
1047 areaTop_(top),
1048 areaWidth_(width),
1049 areaHeight_(height),
1050 horizontalBins_(horizontalBins),
1051 verticalBins_(verticalBins),
1052 horizontalPoint2Bin_(width > Numeric::eps() ? (Scalar(horizontalBins) / (Scalar(width) + Numeric::eps())) : Scalar(0)),
1053 verticalPoint2Bin_(height > Numeric::eps() ? (Scalar(verticalBins) / (Scalar(height) + Numeric::eps())) : Scalar(0))
1054{
1055 ocean_assert(width > Numeric::eps() && height > Numeric::eps());
1056}
1057
1059{
1060 return areaLeft_;
1061}
1062
1064{
1065 return areaTop_;
1066}
1067
1069{
1070 return areaWidth_;
1071}
1072
1074{
1075 return areaHeight_;
1076}
1077
1079{
1080 return horizontalBins_;
1081}
1082
1084{
1085 return verticalBins_;
1086}
1087
1088inline unsigned int SpatialDistribution::Array::bins() const
1089{
1090 return horizontalBins_ * verticalBins_;
1091}
1092
1093inline unsigned int SpatialDistribution::Array::index(const Scalar x, const Scalar y) const
1094{
1095 const int xBin = horizontalBin(x);
1096 const int yBin = verticalBin(y);
1097
1098 ocean_assert(xBin >= 0 && xBin < int(horizontalBins_));
1099 ocean_assert(yBin >= 0 && yBin < int(verticalBins_));
1100
1101 return yBin * horizontalBins_ + xBin;
1102}
1103
1105{
1106 // for positive values we could avoid to use floor(), however for negative values we e.g., need -0.2 to be -1
1107 return int(Numeric::floor((x - areaLeft_) * horizontalPoint2Bin_));
1108}
1109
1111{
1112 // for positive values we could avoid to use floor(), however for negative values we e.g., need -0.2 to be -1
1113 return int(Numeric::floor((y - areaTop_) * verticalPoint2Bin_));
1114}
1115
1117{
1118 ocean_assert(isValid());
1119 return minmax<int>(0, horizontalBin(x), horizontalBins_ - 1);
1120}
1121
1123{
1124 ocean_assert(isValid());
1125 return minmax<int>(0, verticalBin(y), verticalBins_ - 1);
1126}
1127
1129{
1130 return horizontalBins_ != 0u && verticalBins_ != 0u;
1131}
1132
1133inline bool SpatialDistribution::Array::operator==(const Array& right) const
1134{
1135 return areaLeft_ == right.areaLeft_
1136 && areaTop_ == right.areaTop_
1137 && areaWidth_ == right.areaWidth_
1138 && areaHeight_ == right.areaHeight_
1139 && horizontalBins_ == right.horizontalBins_
1140 && verticalBins_ == right.verticalBins_
1141 && horizontalPoint2Bin_ == right.horizontalPoint2Bin_
1142 && verticalPoint2Bin_ == right.verticalPoint2Bin_;
1143}
1144
1145inline bool SpatialDistribution::Array::operator!=(const Array& right) const
1146{
1147 return !(*this == right);
1148}
1149
1150inline SpatialDistribution::Array::operator bool() const
1151{
1152 return isValid();
1153}
1154
1156{
1157 if (this != &object)
1158 {
1159 areaLeft_ = object.areaLeft_;
1160 areaTop_ = object.areaTop_;
1161 areaWidth_ = object.areaWidth_;
1162 areaHeight_ = object.areaHeight_;
1163 horizontalBins_ = object.horizontalBins_;
1164 verticalBins_ = object.verticalBins_;
1165 horizontalPoint2Bin_ = object.horizontalPoint2Bin_;
1166 verticalPoint2Bin_ = object.verticalPoint2Bin_;
1167 }
1168
1169 return *this;
1170}
1171
1173{
1174 if (this != &object)
1175 {
1176 areaLeft_ = object.areaLeft_;
1177 areaTop_ = object.areaTop_;
1178 areaWidth_ = object.areaWidth_;
1179 areaHeight_ = object.areaHeight_;
1180 horizontalBins_ = object.horizontalBins_;
1181 verticalBins_ = object.verticalBins_;
1182 horizontalPoint2Bin_ = object.horizontalPoint2Bin_;
1183 verticalPoint2Bin_ = object.verticalPoint2Bin_;
1184
1185 object.areaLeft_ = Scalar(0);
1186 object.areaTop_ = Scalar(0);
1187 object.areaWidth_ = Scalar(0);
1188 object.areaHeight_ = Scalar(0);
1189 object.horizontalBins_ = 0u;
1190 object.verticalBins_ = 0u;
1191 object.horizontalPoint2Bin_ = Scalar(0);
1192 object.verticalPoint2Bin_ = Scalar(0);
1193 }
1194
1195 return *this;
1196}
1197
1199 Array(object),
1200 indexGroups_(std::move(object.indexGroups_)),
1201 hasCopiedNeighborhood8_(object.hasCopiedNeighborhood8_)
1202{
1203 object = DistributionArray();
1204}
1205
1206inline SpatialDistribution::DistributionArray::DistributionArray(const Scalar left, const Scalar top, const Scalar width, const Scalar height, const unsigned int horizontalBins, const unsigned int verticalBins) :
1207 Array(left, top, width, height, horizontalBins, verticalBins),
1208 indexGroups_(horizontalBins * verticalBins),
1209 hasCopiedNeighborhood8_(false)
1210{
1211 // nothing to do here
1212}
1213
1215{
1216 return hasCopiedNeighborhood8_;
1217}
1218
1219inline const Indices32& SpatialDistribution::DistributionArray::operator()(const unsigned int horizontal, const unsigned int vertical) const
1220{
1221 ocean_assert(horizontal < horizontalBins_);
1222 ocean_assert(vertical < verticalBins_);
1223
1224 return indexGroups_[vertical * horizontalBins_ + horizontal];
1225}
1226
1227inline Indices32& SpatialDistribution::DistributionArray::operator()(const unsigned int horizontal, const unsigned int vertical)
1228{
1229 ocean_assert(horizontal < horizontalBins_);
1230 ocean_assert(vertical < verticalBins_);
1231
1232 return indexGroups_[vertical * horizontalBins_ + horizontal];
1233}
1234
1235inline const Indices32& SpatialDistribution::DistributionArray::operator[](const unsigned int index) const
1236{
1237 ocean_assert(index < horizontalBins_ * verticalBins_);
1238 return indexGroups_[index];
1239}
1240
1242{
1243 ocean_assert(index < horizontalBins_ * verticalBins_);
1244 return indexGroups_[index];
1245}
1246
1248{
1249 Array::operator=((Array&)object);
1250 indexGroups_ = object.indexGroups_;
1251 hasCopiedNeighborhood8_ = object.hasCopiedNeighborhood8_;
1252
1253 return *this;
1254}
1255
1257{
1258 if (this != &object)
1259 {
1260 Array::operator=(std::move((Array&)object));
1261 indexGroups_ = std::move(object.indexGroups_);
1262 hasCopiedNeighborhood8_ = object.hasCopiedNeighborhood8_;
1263
1264 object.hasCopiedNeighborhood8_ = false;
1265 }
1266
1267 return *this;
1268}
1269
1271{
1272 if (!Array::operator==(distributionArray))
1273 {
1274 return false;
1275 }
1276
1277 return indexGroups_ == distributionArray.indexGroups_ && hasCopiedNeighborhood8_ && distributionArray.hasCopiedNeighborhood8_;
1278}
1279
1281{
1282 return !(*this == distributionArray);
1283}
1284
1286 Array(std::move((Array&)object)),
1287 occupancy_(std::move(object.occupancy_))
1288{
1289 // nothing to do here
1290}
1291
1292inline SpatialDistribution::OccupancyArray::OccupancyArray(const Box2& boundingBox, const unsigned int horizontalBins, const unsigned int verticalBins, const bool allFree) :
1293 Array(boundingBox.left(), boundingBox.top(), boundingBox.width(), boundingBox.height(), horizontalBins, verticalBins),
1294 occupancy_(horizontalBins * verticalBins, allFree ? 0u : 1u)
1295{
1296 ocean_assert(NumericT<unsigned int>::isInsideValueRange(uint64_t(horizontalBins) * uint64_t(verticalBins)));
1297}
1298
1299inline 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) :
1300 Array(left, top, width, height, horizontalBins, verticalBins),
1301 occupancy_(horizontalBins * verticalBins, allFree ? 0u : 1u)
1302{
1303 ocean_assert(NumericT<unsigned int>::isInsideValueRange(uint64_t(horizontalBins) * uint64_t(verticalBins)));
1304}
1305
1306inline unsigned int SpatialDistribution::OccupancyArray::countOccupiedNeighborhood9(const unsigned int horizontal, const unsigned int vertical) const
1307{
1308 ocean_assert(horizontal < horizontalBins_);
1309 ocean_assert(vertical < verticalBins_);
1310
1311 unsigned int number = 0u;
1312
1313 for (unsigned int y = max(0, int(vertical) - 1); y < min(vertical + 2u, verticalBins_); ++y)
1314 {
1315 for (unsigned int x = max(0, int(horizontal) - 1); x < min(horizontal + 2u, horizontalBins_); ++x)
1316 {
1317 if ((*this)(x, y))
1318 {
1319 number++;
1320 }
1321 }
1322 }
1323
1324 return number;
1325}
1326
1327inline bool SpatialDistribution::OccupancyArray::isOccupiedNeighborhood9(const unsigned int horizontal, const unsigned int vertical) const
1328{
1329 ocean_assert(horizontal < horizontalBins_);
1330 ocean_assert(vertical < verticalBins_);
1331
1332 for (unsigned int y = max(0, int(vertical) - 1); y < min(vertical + 2u, verticalBins_); ++y)
1333 {
1334 for (unsigned int x = max(0, int(horizontal) - 1); x < min(horizontal + 2u, horizontalBins_); ++x)
1335 {
1336 if ((*this)(x, y))
1337 {
1338 return true;
1339 }
1340 }
1341 }
1342
1343 return false;
1344}
1345
1347{
1348 const unsigned int horizontal = horizontalBin(point.x());
1349 const unsigned int vertical = verticalBin(point.y());
1350
1351 if (horizontal < horizontalBins_ && vertical < verticalBins_)
1352 {
1353 for (unsigned int y = max(0, int(vertical) - 1); y < min(vertical + 2u, verticalBins_); ++y)
1354 {
1355 for (unsigned int x = max(0, int(horizontal) - 1); x < min(horizontal + 2u, horizontalBins_); ++x)
1356 {
1357 if ((*this)(x, y))
1358 {
1359 return true;
1360 }
1361 }
1362 }
1363 }
1364
1365 return false;
1366}
1367
1368inline bool SpatialDistribution::OccupancyArray::isNotOccupiedNeighborhood9(const unsigned int horizontal, const unsigned int vertical) const
1369{
1370 ocean_assert(horizontal < horizontalBins_);
1371 ocean_assert(vertical < verticalBins_);
1372
1373 for (unsigned int y = max(0, int(vertical) - 1); y < min(vertical + 2u, verticalBins_); ++y)
1374 {
1375 for (unsigned int x = max(0, int(horizontal) - 1); x < min(horizontal + 2u, horizontalBins_); ++x)
1376 {
1377 if (!(*this)(x, y))
1378 {
1379 return true;
1380 }
1381 }
1382 }
1383
1384 return false;
1385}
1386
1388{
1389 const unsigned int horizontal = horizontalBin(point.x());
1390 const unsigned int vertical = verticalBin(point.y());
1391
1392 if (horizontal < horizontalBins_ && vertical < verticalBins_)
1393 {
1394 for (unsigned int y = max(0, int(vertical) - 1); y < min(vertical + 2u, verticalBins_); ++y)
1395 {
1396 for (unsigned int x = max(0, int(horizontal) - 1); x < min(horizontal + 2u, horizontalBins_); ++x)
1397 {
1398 if (!(*this)(x, y))
1399 {
1400 return true;
1401 }
1402 }
1403 }
1404 }
1405
1406 return false;
1407}
1408
1410{
1411 unsigned int count = 0u;
1412
1413 for (const Index32& bin : occupancy_)
1414 {
1415 if (bin != 0u)
1416 {
1417 ++count;
1418 }
1419 }
1420
1421 return count;
1422}
1423
1425{
1426 unsigned int count = 0u;
1427
1428 for (const Index32& bin : occupancy_)
1429 {
1430 if (bin == 0u)
1431 {
1432 ++count;
1433 }
1434 }
1435
1436 return count;
1437}
1438
1440{
1441 const unsigned int horizontal = (unsigned int)(horizontalBin(point.x()));
1442 const unsigned int vertical = (unsigned int)(verticalBin(point.y()));
1443
1444 if (horizontal < horizontalBins_ && vertical < verticalBins_)
1445 {
1446 const unsigned int index = vertical * horizontalBins_ + horizontal;
1447
1448 if (!occupancy_[index])
1449 {
1450 occupancy_[index] = 1u;
1451 return true;
1452 }
1453 }
1454
1455 return false;
1456}
1457
1458inline bool SpatialDistribution::OccupancyArray::addPointWithCounter(const Vector2& point, const unsigned int maximalOccupancyCounter)
1459{
1460 const unsigned int horizontal = (unsigned int)(horizontalBin(point.x()));
1461 const unsigned int vertical = (unsigned int)(verticalBin(point.y()));
1462
1463 if (horizontal < horizontalBins_ && vertical < verticalBins_)
1464 {
1465 const unsigned int index = vertical * horizontalBins_ + horizontal;
1466
1467 if (occupancy_[index] <= maximalOccupancyCounter)
1468 {
1469 occupancy_[index]++;
1470 return true;
1471 }
1472 }
1473
1474 return false;
1475}
1476
1478{
1479 const unsigned int horizontal = (unsigned int)(horizontalBin(point.x()));
1480 const unsigned int vertical = (unsigned int)(verticalBin(point.y()));
1481
1482 if (horizontal < horizontalBins_ && vertical < verticalBins_)
1483 {
1484 const unsigned int index = vertical * horizontalBins_ + horizontal;
1485
1486 if (occupancy_[index])
1487 {
1488 occupancy_[index] = 0u;
1489 return true;
1490 }
1491 }
1492
1493 return false;
1494}
1495
1497{
1498 for (size_t n = 0; n < occupancy_.size(); ++n)
1499 {
1500 occupancy_[n] = 0u;
1501 }
1502}
1503
1505{
1506 const unsigned int horizontal = (unsigned int)(horizontalBin(point.x()));
1507 const unsigned int vertical = (unsigned int)(verticalBin(point.y()));
1508
1509 if (horizontal < horizontalBins_ && vertical < verticalBins_)
1510 {
1511 occupancy_[vertical * horizontalBins_ + horizontal] = 1u;
1512 }
1513
1514 return *this;
1515}
1516
1518{
1519 const unsigned int horizontal = (unsigned int)(horizontalBin(point.x()));
1520 const unsigned int vertical = (unsigned int)(verticalBin(point.y()));
1521
1522 if (horizontal < horizontalBins_ && vertical < verticalBins_)
1523 {
1524 occupancy_[vertical * horizontalBins_ + horizontal] = 0u;
1525 }
1526
1527 return *this;
1528}
1529
1530inline bool SpatialDistribution::OccupancyArray::operator()(const unsigned int horizontal, const unsigned int vertical) const
1531{
1532 ocean_assert(horizontal < horizontalBins_);
1533 ocean_assert(vertical < verticalBins_);
1534
1535 return occupancy_[vertical * horizontalBins_ + horizontal] != 0u;
1536}
1537
1538inline unsigned int& SpatialDistribution::OccupancyArray::operator()(const unsigned int horizontal, const unsigned int vertical)
1539{
1540 ocean_assert(horizontal < horizontalBins_);
1541 ocean_assert(vertical < verticalBins_);
1542
1543 return occupancy_[vertical * horizontalBins_ + horizontal];
1544}
1545
1547{
1548 const unsigned int xBin = horizontalBin(point.x());
1549 const unsigned int yBin = verticalBin(point.y());
1550
1551 return xBin < horizontalBins_ && yBin < horizontalBins_ && occupancy_[yBin * horizontalBins_ + xBin] != 0u;
1552}
1553
1554inline bool SpatialDistribution::OccupancyArray::operator[](const unsigned int index) const
1555{
1556 ocean_assert(index < horizontalBins_ * verticalBins_);
1557 return occupancy_[index] != 0u;
1558}
1559
1560inline unsigned int& SpatialDistribution::OccupancyArray::operator[](const unsigned int index)
1561{
1562 ocean_assert(index < horizontalBins_ * verticalBins_);
1563 return occupancy_[index];
1564}
1565
1567{
1568 Array::operator=((Array&)object);
1569 occupancy_ = object.occupancy_;
1570
1571 return *this;
1572}
1573
1575{
1576 if (this != &object)
1577 {
1578 Array::operator=(std::move((Array&)object));
1579 occupancy_ = std::move(object.occupancy_);
1580 }
1581
1582 return *this;
1583}
1584
1586{
1587 if (!Array::operator==(occupancyArray))
1588 {
1589 return false;
1590 }
1591
1592 return occupancy_ == occupancyArray.occupancy_;
1593}
1594
1596{
1597 return !(*this == occupancyArray);
1598}
1599
1600inline SpatialDistribution::DistanceElement::DistanceElement(const unsigned int index, const unsigned int candidateIndex, const Scalar distance) :
1601 index_(index),
1602 candidateIndex_(candidateIndex),
1603 distance_(distance)
1604{
1605 // nothing to do here
1606}
1607
1609{
1610 return index_;
1611}
1612
1614{
1615 return candidateIndex_;
1616}
1617
1619{
1620 return distance_;
1621}
1622
1624{
1625 return left.distance_ < right.distance_;
1626}
1627
1629{
1630 return left.distance_ > right.distance_;
1631}
1632
1634{
1635 // ** TODO** this mismatch between comparison operators should be fixed
1636
1637 return distance_ > element.distance_;
1638}
1639
1640template <unsigned int tMaximalBins>
1641inline 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)
1642{
1643 static_assert(tMaximalBins > 0u, "Invalid maximal bin parameter!");
1644
1645 const unsigned int horizontalBins = min(tMaximalBins, (unsigned int)Numeric::ceil(width / max(searchDistance, Scalar(2))));
1646 const unsigned int verticalBins = min(tMaximalBins, (unsigned int)Numeric::ceil(height / max(searchDistance, Scalar(2))));
1647
1648 return distributeToArray(imagePoints, number, left, top, width, height, horizontalBins, verticalBins);
1649}
1650
1651template <typename T, const Vector2& (*tFunction)(const T&)>
1652SpatialDistribution::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)
1653{
1654 ocean_assert(elements);
1655 ocean_assert(width > 0 && height > 0);
1656
1657 ocean_assert(horizontalBins > 0);
1658 ocean_assert(verticalBins > 0);
1659
1660 ocean_assert(Scalar(horizontalBins) <= width);
1661 ocean_assert(Scalar(verticalBins) <= width);
1662
1663 // reserve enough array elements
1664 DistributionArray indexArray(left, top, width, height, horizontalBins, verticalBins);
1665
1666 for (size_t n = 0; n < number; ++n)
1667 {
1668 const Vector2& point = tFunction(*elements);
1669
1670 const unsigned int horizontal = (unsigned int)(indexArray.horizontalBin(point.x()));
1671 const unsigned int vertical = (unsigned int)(indexArray.verticalBin(point.y()));
1672
1673 // 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)
1674 if (horizontal < indexArray.horizontalBins() && vertical < indexArray.verticalBins())
1675 {
1676 indexArray(horizontal, vertical).push_back((unsigned int)n);
1677 }
1678
1679 ++elements;
1680 }
1681
1682 return indexArray;
1683}
1684
1685inline 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)
1686{
1687 ocean_assert(imagePoints || number == 0);
1688
1689 ocean_assert(width > 0 && height > 0);
1690 ocean_assert(averagePointsPerBin > 0);
1691
1692 ocean_assert(maxHorizontalBins >= 1u);
1693 ocean_assert(maxVerticalBins >= 1u);
1694
1695 if (number == 0)
1696 {
1697 return DistributionArray(left, top, width, height, horizontalBins, verticalBins);
1698 }
1699
1700 /**
1701 * averagePointsPerBin * horizontalBins * verticalBins = number
1702 * horizontalBins / verticalBins = width / height
1703 */
1704
1705 const Scalar sqr = max(Scalar(1), (Scalar(number) * width) / (Scalar(averagePointsPerBin) * height));
1706
1707 horizontalBins = min(maxHorizontalBins, max(1u, (unsigned int)(Numeric::sqrt(sqr))));
1708 verticalBins = min(maxVerticalBins, max(1u, (unsigned int)(Scalar(horizontalBins) * height / width)));
1709
1710 return distributeToArray(imagePoints, number, left, top, width, height, horizontalBins, verticalBins);
1711}
1712
1713inline 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)
1714{
1715 return distributeAndFilter<ImagePoint, &SpatialDistribution::identity>(imagePoints, numberImagePoints, left, top, width, height, horizontalBins, verticalBins);
1716}
1717
1718template <typename TIndex>
1719inline 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)
1720{
1721 return distributeAndFilterIndices<ImagePoint, TIndex, &SpatialDistribution::identity>(imagePoints, numberImagePoints, left, top, width, height, horizontalBins, verticalBins);
1722}
1723
1724template <typename T, Vector2 (*tFunction)(const T&)>
1725typename 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)
1726{
1727 ocean_assert(elements || numberElements == 0);
1728 ocean_assert(width >= 0 && height >= 0);
1729 ocean_assert(horizontalBins >= 1u && verticalBins >= 1u);
1730
1731 if (numberElements == 0)
1732 {
1733 return std::vector<T>();
1734 }
1735
1736 OccupancyArray occupancyArray(left, top, width, height, horizontalBins, verticalBins);
1737
1738 const size_t bins = occupancyArray.bins();
1739
1740 std::vector<T> result;
1741 result.reserve(bins);
1742
1743 for (size_t n = 0; n < numberElements && result.size() < bins; ++n)
1744 {
1745 if (occupancyArray.addPoint(tFunction(elements[n])))
1746 {
1747 result.push_back(elements[n]);
1748 }
1749 }
1750
1751 return result;
1752}
1753
1754template <typename T, Vector2 (*tFunction)(const T&)>
1755typename 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)
1756{
1757 ocean_assert(elements != nullptr || numberElements == 0);
1758 ocean_assert(width >= 0 && height >= 0);
1759 ocean_assert(horizontalBins >= 1u && verticalBins >= 1u);
1760 ocean_assert(numberDesiredFilteredElements <= numberElements);
1761
1762 if (numberElements == 0 || numberDesiredFilteredElements == 0)
1763 {
1764 return std::vector<T>();
1765 }
1766
1767 OccupancyArray occupancyArray(left, top, width, height, horizontalBins, verticalBins);
1768
1769 std::vector<unsigned char> usedElements(numberElements, 0u);
1770
1771 const size_t bins = occupancyArray.bins();
1772
1773 std::vector<T> result;
1774 result.reserve(bins);
1775
1776 unsigned int filterIteration = 0u;
1777
1778 while (result.size() < numberDesiredFilteredElements && filterIteration < (unsigned int)numberDesiredFilteredElements)
1779 {
1780 for (size_t n = 0; n < numberElements && result.size() < numberDesiredFilteredElements; ++n)
1781 {
1782 if (usedElements[n] == 0u && occupancyArray.addPointWithCounter(tFunction(elements[n]), filterIteration))
1783 {
1784 result.push_back(elements[n]);
1785 usedElements[n] = 1u;
1786 }
1787 }
1788
1789 filterIteration++;
1790 }
1791
1792 if (indices)
1793 {
1794 for (size_t n = 0; n < numberElements; ++n)
1795 {
1796 if(usedElements[n])
1797 {
1798 indices->push_back(Index32(n));
1799 }
1800 }
1801 }
1802
1803 return result;
1804}
1805
1806template <typename T, typename TIndex, Vector2 (*tFunction)(const T&)>
1807typename 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)
1808{
1809 ocean_assert(elements || numberElements == 0);
1810 ocean_assert(width >= 0 && height >= 0);
1811 ocean_assert(horizontalBins >= 1u && verticalBins >= 1u);
1812
1813 if (numberElements == 0)
1814 {
1815 return std::vector<TIndex>();
1816 }
1817
1818 ocean_assert((unsigned long long)(numberElements) <= (unsigned long long)(NumericT<TIndex>::maxValue()));
1819
1820 OccupancyArray occupancyArray(left, top, width, height, horizontalBins, verticalBins);
1821
1822 const size_t bins = occupancyArray.bins();
1823
1824 std::vector<TIndex> result;
1825 result.reserve(bins);
1826
1827 for (size_t n = 0; n < numberElements && result.size() < bins; ++n)
1828 {
1829 if (occupancyArray.addPoint(tFunction(elements[n])))
1830 {
1831 result.push_back(TIndex(n));
1832 }
1833 }
1834
1835 return result;
1836}
1837
1838template <typename T>
1839inline T SpatialDistribution::identity(const T& value)
1840{
1841 return value;
1842}
1843
1844}
1845
1846}
1847
1848#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:1078
Scalar width() const
Returns the width of the distribution area.
Definition SpatialDistribution.h:1068
int horizontalBin(const Scalar x) const
Returns the horizontal bin of a given horizontal position.
Definition SpatialDistribution.h:1104
int verticalBin(const Scalar y) const
Returns the vertical bin of a given vertical position.
Definition SpatialDistribution.h:1110
Scalar horizontalPoint2Bin_
Horizontal position to bin factor.
Definition SpatialDistribution.h:218
Array & operator=(const Array &object)
Assign operator.
Definition SpatialDistribution.h:1155
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:1063
unsigned int verticalBins() const
Returns the number of vertical distribution bins.
Definition SpatialDistribution.h:1083
int clampedVerticalBin(const Scalar y) const
Returns the vertical bin of a given vertical position.
Definition SpatialDistribution.h:1122
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:1116
bool isValid() const
Returns whether this object holds a valid distribution.
Definition SpatialDistribution.h:1128
Scalar height() const
Returns the height of the distribution area.
Definition SpatialDistribution.h:1073
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:1133
bool operator!=(const Array &right) const
Returns whether two Array objects are not identical.
Definition SpatialDistribution.h:1145
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:1058
unsigned int index(const Scalar x, const Scalar y) const
Returns the bin index for a given position.
Definition SpatialDistribution.h:1093
unsigned int bins() const
Returns the number of bins this distribution holds.
Definition SpatialDistribution.h:1088
Definition of a class holding an index and a distance.
Definition SpatialDistribution.h:584
Scalar distance_
Distance value.
Definition SpatialDistribution.h:644
unsigned int candidateIndex() const
Returns the candidate index of this element.
Definition SpatialDistribution.h:1613
static bool compareLeftSmaller(const DistanceElement &left, const DistanceElement &right)
Compares two distance elements.
Definition SpatialDistribution.h:1623
unsigned int index() const
Returns the interest index of this element.
Definition SpatialDistribution.h:1608
static bool compareLeftHigher(const DistanceElement &left, const DistanceElement &right)
Compares two distance elements.
Definition SpatialDistribution.h:1628
DistanceElement(const unsigned int index, const unsigned int candidateIndex, const Scalar distance)
Creates a new distance element.
Definition SpatialDistribution.h:1600
bool operator<(const DistanceElement &element) const
Returns whether the left element holds a higher distance than the right one.
Definition SpatialDistribution.h:1633
Scalar distance() const
Returns the distance of this element.
Definition SpatialDistribution.h:1618
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:1214
DistributionArray & operator=(const DistributionArray &object)
Assign operator.
Definition SpatialDistribution.h:1247
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:1219
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:1235
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:1280
bool operator==(const DistributionArray &distributionArray) const
Returns whether two DistributionArray objects are identical.
Definition SpatialDistribution.h:1270
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:1504
bool operator!=(const OccupancyArray &occupancyArray) const
Returns whether two OccupancyArray objects are not identical.
Definition SpatialDistribution.h:1595
unsigned int freeBins() const
Returns the number of free bins.
Definition SpatialDistribution.h:1424
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:1368
OccupancyArray & operator-=(const Vector2 &point)
Removes an image point from this occupancy array.
Definition SpatialDistribution.h:1517
unsigned int occupiedBins() const
Returns the number of occupied bins.
Definition SpatialDistribution.h:1409
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:1306
OccupancyArray()=default
Creates an empty distribution array object.
OccupancyArray & operator=(const OccupancyArray &object)
Assign operator.
Definition SpatialDistribution.h:1566
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:1327
void reset()
Resets all occupied bins so that all bins a free afterwards.
Definition SpatialDistribution.h:1496
bool removePoint(const Vector2 &point)
Removes an image point and returns whether the corresponding bin was occupied before.
Definition SpatialDistribution.h:1477
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:1458
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:1439
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:1530
bool operator==(const OccupancyArray &occupancyArray) const
Returns whether two OccupancyArray objects are identical.
Definition SpatialDistribution.h:1585
Indices32 occupancy_
Occupancy array.
Definition SpatialDistribution.h:577
bool operator[](const unsigned int index) const
Returns whether a specified bin is occupied.
Definition SpatialDistribution.h:1554
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:1685
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...
std::vector< DistanceElement > DistanceElements
Definition of a vector holding distance elements.
Definition SpatialDistribution.h:650
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.
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:1719
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:1839
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:1713
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:2029
static T ceil(const T value)
Returns the smallest integer value that is not less than the given value.
Definition Numeric.h:1991
const T & x() const noexcept
Returns the x value.
Definition Vector2.h:710
const T & y() const noexcept
Returns the y value.
Definition Vector2.h:722
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:1053
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:129
The namespace covering the entire Ocean framework.
Definition Accessor.h:15