Ocean
Loading...
Searching...
No Matches
SegmentUnion.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_BASE_SEGMENT_UNION_H
9#define META_OCEAN_BASE_SEGMENT_UNION_H
10
11#include "ocean/base/Base.h"
12
13#include <limits>
14#include <map>
15
16namespace Ocean
17{
18
19/**
20 * This class implements a functionality to determine the union of individual segments.
21 * Each segment is defined by a start point and an end point.<br>
22 * The result of such a uion is depicted below:
23 * <pre>
24 * Segment A: S---------P
25 * Segment B: S--P
26 * Segment C: S-----------P
27 * Segment D: S----P
28 * ...
29 * Segment Z: S-P
30 * Resulting Union: S--P S-----------------P S------P
31 *
32 * (with 's' as including start point, and 'p' as including end point)
33 * </pre>
34 * @tparam T The data type of the start and end point of a segment, should be 'float', 'double', or 'int'
35 * @ingroup base
36 */
37template <typename T>
39{
40 public:
41
42 /**
43 * Definition of a map mapping a start point to the corresponding end point of a segment.
44 */
45 typedef std::map<T, T> SegmentMap;
46
47 public:
48
49 /**
50 * Adds a new segment to this union object.
51 * @param startPosition The (including) start position of the segment, with range (-infinity, startPosition)
52 * @param stopPosition The (including) stop position of the segment, with range (stopPosition, infinity)
53 */
54 void addSegment(const T& startPosition, const T& stopPosition);
55
56 /**
57 * Returns the intersection of this union with a given range (an additional segment).
58 * An intersection between this object an a given range/segment is depicted below:
59 * <pre>
60 * Segments of this object: X------X X---X X-----------X
61 * Intersection Segment: S--------------------------------P
62 * Resulting object: X--X X---X X-----------X
63 * </pre>
64 * @param startPosition The (including) start position of the segment, with range (-infinity, startPosition)
65 * @param stopPosition The (including) stop position of the segment, with range (stopPosition, infinity)
66 * @return The new object holding the intersection of this object and the specified segment, may be empty if no intersection exists
67 */
68 SegmentUnion<T> intersection(const T& startPosition, const T& stopPosition) const;
69
70 /**
71 * Returns the maximal gap between all successive segments.
72 * @return The maximal gap, 0 if this object is composed of zero or one segments, with range [0, infinity)
73 */
74 T maximalGap() const;
75
76 /**
77 * Returns the segments of this object.
78 * @return The individual segments defining the union
79 */
80 inline const SegmentMap& segments() const;
81
82 /**
83 * Returns the sum of all segment sizes.
84 * @return The size of all segments, with range [0, infinity)
85 */
86 T unionSize() const;
87
88 /**
89 * Returns whether the union is composed of at least one segment.
90 * @return True, if so
91 */
92 explicit inline operator bool() const;
93
94 protected:
95
96 /**
97 * Returns whether the data structure of this object is correct.
98 * @return True, if so
99 */
100 bool isCorrect() const;
101
102 protected:
103
104 /// The map holding all segments.
106};
107
108template <typename T>
109void SegmentUnion<T>::addSegment(const T& startPosition, const T& stopPosition)
110{
111 ocean_assert(isCorrect());
112
113 ocean_assert(startPosition < stopPosition);
114
115 // existing segments: X----X X------X X-X X------------X
116 // start/stop position: S----P
117
118 if (segmentMap_.empty())
119 {
120 segmentMap_.insert(std::make_pair(startPosition, stopPosition));
121 ocean_assert(isCorrect());
122
123 return;
124 }
125
126 typename SegmentMap::iterator i = segmentMap_.lower_bound(startPosition); // segment with 'startPosition' <= start position (of found segment)
127
128 if (i == segmentMap_.end())
129 {
130 ocean_assert(segmentMap_.rbegin() != segmentMap_.rend());
131
132 typename SegmentMap::reverse_iterator lastSegment = segmentMap_.rbegin();
133
134 if (startPosition > lastSegment->second)
135 {
136 // existing segments: X---X X--------X
137 // start/stop position: S--------P
138
139 segmentMap_.insert(std::make_pair(startPosition, stopPosition));
140 ocean_assert(isCorrect());
141
142 return;
143 }
144
145 if (startPosition == lastSegment->second)
146 {
147 // existing segments: X---X X--------X
148 // start/stop position: S--------P
149
150 lastSegment->second = stopPosition;
151 ocean_assert(isCorrect());
152
153 return;
154 }
155
156 ocean_assert(startPosition > lastSegment->first);
157 ocean_assert(startPosition < lastSegment->second);
158
159 if (stopPosition <= lastSegment->second)
160 {
161 // existing segments: X---X X------------X
162 // start/stop position: S----P
163 // start/stop position: S---------P
164
165 return;
166 }
167
168 ocean_assert(stopPosition > lastSegment->second);
169
170 // existing segments: X---X X-------X
171 // start/stop position: S--------P
172
173 lastSegment->second = stopPosition;
174 ocean_assert(isCorrect());
175
176 return;
177 }
178
179 ocean_assert(startPosition <= i->first);
180
181 if (i == segmentMap_.begin())
182 {
183 if (stopPosition < i->first)
184 {
185 // existing segments: X------------X X--------X
186 // start/stop position: S----P
187
188 segmentMap_.insert(std::make_pair(startPosition, stopPosition));
189 ocean_assert(isCorrect());
190
191 return;
192 }
193
194 if (stopPosition == i->first)
195 {
196 // existing segments: X------------X X--------X
197 // start/stop position: S----P
198
199 const T newStopPosition = i->second;
200
201 segmentMap_.erase(i);
202
203 segmentMap_.insert(std::make_pair(startPosition, newStopPosition));
204
205 ocean_assert(isCorrect());
206
207 return;
208 }
209
210 ocean_assert(stopPosition > i->first);
211
212 typename SegmentMap::iterator iEnd = i;
213
214 while (iEnd != segmentMap_.end())
215 {
216 if (stopPosition < iEnd->first)
217 {
218 // existing segments: X--------X X--------X X------X
219 // start/stop position: S--------------P
220 // start/stop position: S------------------------------P
221
222 segmentMap_.erase(i, iEnd); // remove [i, iEnd - 1]
223
224 segmentMap_.insert(std::make_pair(startPosition, stopPosition));
225
226 ocean_assert(isCorrect());
227
228 return;
229 }
230 else if (stopPosition < iEnd->second)
231 {
232 // existing segments: X------------X X--------X X------X
233 // start/stop position: S------------P
234 // start/stop position: S--------------------------P
235
236 const T newStopPostion = iEnd->second;
237
238 segmentMap_.erase(i, ++iEnd); // remove [i, iEnd]
239
240 segmentMap_.insert(std::make_pair(startPosition, newStopPostion));
241
242 ocean_assert(isCorrect());
243
244 return;
245 }
246
247 ++iEnd;
248 }
249
250 // existing segments: X------------X X--------X X------X
251 // start/stop position: S--------------------------------------------P
252
253 segmentMap_.erase(i, segmentMap_.end()); // remove [i, end)
254
255 segmentMap_.insert(std::make_pair(startPosition, stopPosition));
256
257 ocean_assert(isCorrect());
258
259 return;
260 }
261
262 --i;
263
264 // existing segments: X------------X X--------X
265 // start/stop position: S----P
266 // start/stop position: S--------P
267 // start/stop position: S------------P
268 // start/stop position: S------------P
269 // start/stop position: S---------------------P
270 // start/stop position: S-P
271 // start/stop position: S------P
272
273 if (stopPosition <= i->second)
274 {
275 // existing segments: X---X X------------X
276 // start/stop position: S----P
277
278 return;
279 }
280
281 if (startPosition <= i->second)
282 {
283 typename SegmentMap::iterator iEnd = i;
284
285 while (++iEnd != segmentMap_.end())
286 {
287 if (stopPosition < iEnd->first)
288 {
289 // existing segments: X------------X X--------X X------X
290 // start/stop position: S------------P
291 // start/stop position: S--------------------------P
292
293 i->second = stopPosition;
294
295 segmentMap_.erase(++i, iEnd); // remove [i + 1, iEnd - 1]
296
297 ocean_assert(isCorrect());
298
299 return;
300 }
301 else if (stopPosition < iEnd->second)
302 {
303 // existing segments: X------------X X--------X X------X
304 // start/stop position: S------------------P
305 // start/stop position: S-------------------------------P
306
307 i->second = iEnd->second;
308
309 segmentMap_.erase(++i, ++iEnd); // remove [i + 1, iEnd]
310
311 ocean_assert(isCorrect());
312
313 return;
314 }
315 }
316
317 // existing segments: X------------X X--------X
318 // start/stop position: S---------------------------P
319
320 i->second = stopPosition;
321
322 segmentMap_.erase(++i, segmentMap_.end()); // remove [i + 1, end)
323
324 ocean_assert(isCorrect());
325
326 return;
327 }
328
329 ocean_assert(startPosition > i->second);
330
331 typename SegmentMap::iterator iEnd = i;
332
333 while (++iEnd != segmentMap_.end())
334 {
335 if (stopPosition < iEnd->first)
336 {
337 // existing segments: X------X X--------X X------X
338 // start/stop position: S--P
339 // start/stop position: S---------------P
340 // start/stop position: S-----------------------------P
341
342 segmentMap_.erase(++i, iEnd); // remove [i + 1, iEnd - 1]
343
344 segmentMap_.insert(std::make_pair(startPosition, stopPosition));
345
346 ocean_assert(isCorrect());
347
348 return;
349 }
350 else if (stopPosition < iEnd->second)
351 {
352 // existing segments: X------------X X--------X
353 // start/stop position: S----------P
354 // start/stop position: S------------------------P
355
356 const T newStopPosition = iEnd->second;
357
358 segmentMap_.erase(++i, ++iEnd); // remove [i + 1, iEnd]
359
360 segmentMap_.insert(std::make_pair(startPosition, newStopPosition));
361
362 ocean_assert(isCorrect());
363
364 return;
365 }
366 }
367
368 // existing segments: X------------X X--------X
369 // start/stop position: S----------------------------------P
370
371 segmentMap_.erase(++i, segmentMap_.end()); // remove [i + 1, end)
372
373 segmentMap_.insert(std::make_pair(startPosition, stopPosition));
374
375 ocean_assert(isCorrect());
376}
377
378template <typename T>
379SegmentUnion<T> SegmentUnion<T>::intersection(const T& startPosition, const T& stopPosition) const
380{
381 ocean_assert(isCorrect());
382 ocean_assert(startPosition < stopPosition);
383
384 // Segments of this object: X------X X---X X-----------X
385 // Intersection Segment: S--------------------------------P
386 // Resulting object: X--X X---X X-----------X
387
388 if (segmentMap_.empty())
389 {
390 return SegmentUnion<T>();
391 }
392
393 typename SegmentMap::const_iterator i = segmentMap_.lower_bound(startPosition); // segment with 'startPosition' <= start position (of found segment)
394
395 if (i == segmentMap_.end())
396 {
397 ocean_assert(segmentMap_.rbegin() != segmentMap_.rend());
398
399 typename SegmentMap::const_reverse_iterator lastSegment = segmentMap_.crbegin();
400
401 if (startPosition >= lastSegment->second)
402 {
403 // existing segments: X---X X--------X
404 // start/stop position: S--------P
405 // start/stop position: S--------P
406
407 return SegmentUnion<T>();
408 }
409
410 ocean_assert(startPosition > lastSegment->first);
411 ocean_assert(startPosition < lastSegment->second);
412
413 // existing segments: X---X X------------X
414 // start/stop position: S----P
415 // start/stop position: S---------P
416 // start/stop position: S--------P
417
418 const T newStartPosition = std::max(lastSegment->first, startPosition);
419 const T newStopPosition = std::min(stopPosition, lastSegment->second);
420
421 SegmentUnion<T> result;
422 result.segmentMap_.insert(std::make_pair(newStartPosition, newStopPosition));
423
424 ocean_assert(result.isCorrect());
425
426 return result;
427 }
428
429 ocean_assert(startPosition <= i->first);
430
431 if (i == segmentMap_.begin())
432 {
433 if (stopPosition <= i->first)
434 {
435 // existing segments: X------------X X--------X
436 // start/stop position: S----P
437 // start/stop position: S--------P
438
439 return SegmentUnion<T>();
440 }
441
442 ocean_assert(stopPosition > i->first);
443 }
444 else
445 {
446 --i;
447 }
448
449 // existing segments: X------------X X--------X
450 // start/stop position: S---------P
451 // start/stop position: S------------------P
452 // start/stop position: S----P
453 // start/stop position: S--------P
454 // start/stop position: S------------P
455 // start/stop position: S------------P
456 // start/stop position: S---------------------P
457 // start/stop position: S-P
458 // start/stop position: S------P
459
460 if (stopPosition <= i->second)
461 {
462 // existing segments: X------------X
463 // start/stop position: S----P
464 // start/stop position: S----------P
465 // start/stop position: S------------P
466
467 const T newStartPosition = std::max(i->first, startPosition);
468 const T newStopPosition = std::min(stopPosition, i->second);
469
470 SegmentUnion<T> result;
471 result.segmentMap_.insert(std::make_pair(newStartPosition, newStopPosition));
472
473 ocean_assert(result.isCorrect());
474
475 return result;
476 }
477
478 if (startPosition >= i->second)
479 {
480 i++;
481 }
482
483 ocean_assert(startPosition < i->second);
484
485 if (stopPosition <= i->first)
486 {
487 // existing segments: X------X X--------X X------X
488 // start/stop position: S--P
489
490 return SegmentUnion<T>();
491 }
492
493 typename SegmentMap::const_iterator iEnd = i;
494
495 while (++iEnd != segmentMap_.end())
496 {
497 if (stopPosition <= iEnd->first)
498 {
499 // existing segments: X------X X--------X X------X
500 // start/stop position: S--P
501 // start/stop position: S---------------P
502 // start/stop position: S-----------------------------P
503
504 break;
505 }
506 else if (stopPosition <= iEnd->second)
507 {
508 // existing segments: X------------X X--------X
509 // start/stop position: S----------P
510 // start/stop position: S------------------------P
511
512 iEnd++;
513 break;
514 }
515 }
516
517 SegmentUnion<T> result;
518
519 const T newStartPosition = std::max(startPosition, i->first);
520 result.segmentMap_.insert(std::make_pair(newStartPosition, i->second));
521
522 i++;
523
524 for (typename SegmentMap::const_iterator iN = i; iN != iEnd; ++iN)
525 {
526 result.segmentMap_.insert(std::make_pair(iN->first, iN->second));
527 }
528
529 result.segmentMap_.rbegin()->second = std::min(stopPosition, result.segmentMap_.rbegin()->second);
530
531 ocean_assert(result.isCorrect());
532
533 return result;
534}
535
536template <typename T>
538{
539 ocean_assert(isCorrect());
540
541 if (segmentMap_.size() <= 1)
542 {
543 return T(0);
544 }
545
546 typename SegmentMap::const_iterator left = segmentMap_.cbegin();
547 typename SegmentMap::const_iterator right = left;
548 ++right;
549
550 T maximalValue = right->first - left->second;
551 ocean_assert(maximalValue > T(0));
552
553 while (++right != segmentMap_.cend())
554 {
555 ++left;
556
557 const T value = right->first - left->second;
558 ocean_assert(value > T(0));
559
560 if (value > maximalValue)
561 {
562 maximalValue = value;
563 }
564 }
565
566 return maximalValue;
567}
568
569template <typename T>
571{
572 ocean_assert(isCorrect());
573
574 return segmentMap_;
575}
576
577template <typename T>
579{
580 ocean_assert(isCorrect());
581
582 T sum = (0);
583
584 for (typename SegmentMap::const_iterator i = segmentMap_.cbegin(); i != segmentMap_.cend(); ++i)
585 {
586 ocean_assert(i->first < i->second);
587
588 sum += i->second - i->first;
589 }
590
591 return sum;
592}
593
594template <typename T>
595inline SegmentUnion<T>::operator bool() const
596{
597 ocean_assert(isCorrect());
598
599 return !segmentMap_.empty();
600}
601
602template <typename T>
604{
605 T previousEnd = std::numeric_limits<T>::lowest();
606
607 for (typename SegmentMap::const_iterator i = segmentMap_.cbegin(); i != segmentMap_.cend(); ++i)
608 {
609 if (i->first <= previousEnd)
610 {
611 return false;
612 }
613
614 previousEnd = i->second;
615 }
616
617 return true;
618}
619
620}
621
622#endif // META_OCEAN_BASE_RING_MAP_H
This class implements a functionality to determine the union of individual segments.
Definition SegmentUnion.h:39
const SegmentMap & segments() const
Returns the segments of this object.
Definition SegmentUnion.h:570
std::map< T, T > SegmentMap
Definition of a map mapping a start point to the corresponding end point of a segment.
Definition SegmentUnion.h:45
T maximalGap() const
Returns the maximal gap between all successive segments.
Definition SegmentUnion.h:537
bool isCorrect() const
Returns whether the data structure of this object is correct.
Definition SegmentUnion.h:603
SegmentMap segmentMap_
The map holding all segments.
Definition SegmentUnion.h:105
SegmentUnion< T > intersection(const T &startPosition, const T &stopPosition) const
Returns the intersection of this union with a given range (an additional segment).
Definition SegmentUnion.h:379
void addSegment(const T &startPosition, const T &stopPosition)
Adds a new segment to this union object.
Definition SegmentUnion.h:109
T unionSize() const
Returns the sum of all segment sizes.
Definition SegmentUnion.h:578
The namespace covering the entire Ocean framework.
Definition Accessor.h:15