JUCE-7.0.12-0-g4f43011b96 JUCE-7.0.12-0-g4f43011b96
JUCE — C++ application framework with suport for VST, VST3, LV2 audio plug-ins

« « « Anklang Documentation
Loading...
Searching...
No Matches
juce_RectangleList.h
Go to the documentation of this file.
1 /*
2 ==============================================================================
3
4 This file is part of the JUCE library.
5 Copyright (c) 2022 - Raw Material Software Limited
6
7 JUCE is an open source library subject to commercial or open-source
8 licensing.
9
10 By using JUCE, you agree to the terms of both the JUCE 7 End-User License
11 Agreement and JUCE Privacy Policy.
12
13 End User License Agreement: www.juce.com/juce-7-licence
14 Privacy Policy: www.juce.com/juce-privacy-policy
15
16 Or: You may also use this code under the terms of the GPL v3 (see
17 www.gnu.org/licenses).
18
19 JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
20 EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
21 DISCLAIMED.
22
23 ==============================================================================
24*/
25
26namespace juce
27{
28
29//==============================================================================
41template <typename ValueType>
43{
44public:
46
47 //==============================================================================
49 RectangleList() = default;
50
52 RectangleList (const RectangleList& other) : rects (other.rects)
53 {
54 }
55
58 {
59 addWithoutMerging (rect);
60 }
61
64 {
65 rects = other.rects;
66 return *this;
67 }
68
71 : rects (std::move (other.rects))
72 {
73 }
74
77 {
78 rects = std::move (other.rects);
79 return *this;
80 }
81
82 //==============================================================================
84 bool isEmpty() const noexcept { return rects.isEmpty(); }
85
87 int getNumRectangles() const noexcept { return rects.size(); }
88
92 RectangleType getRectangle (int index) const noexcept { return rects[index]; }
93
94 //==============================================================================
96 void clear()
97 {
98 rects.clearQuick();
99 }
100
110 void add (RectangleType rect)
111 {
112 jassert (rect.isFinite()); // You must provide a valid rectangle to this method!
113
114 if (! rect.isEmpty())
115 {
116 if (isEmpty())
117 {
118 rects.add (rect);
119 }
120 else
121 {
122 bool anyOverlaps = false;
123
124 for (int j = rects.size(); --j >= 0;)
125 {
126 auto& ourRect = rects.getReference (j);
127
128 if (rect.intersects (ourRect))
129 {
130 if (rect.contains (ourRect))
131 rects.remove (j);
132 else if (! ourRect.reduceIfPartlyContainedIn (rect))
133 anyOverlaps = true;
134 }
135 }
136
137 if (anyOverlaps && ! isEmpty())
138 {
139 RectangleList r (rect);
140
141 for (auto& ourRect : rects)
142 {
143 if (rect.intersects (ourRect))
144 {
145 r.subtract (ourRect);
146
147 if (r.isEmpty())
148 return;
149 }
150 }
151
152 rects.addArray (r.rects);
153 }
154 else
155 {
156 rects.add (rect);
157 }
158 }
159 }
160 }
161
167 void add (ValueType x, ValueType y, ValueType width, ValueType height)
168 {
169 add (RectangleType (x, y, width, height));
170 }
171
181 {
182 jassert (rect.isFinite()); // You must provide a valid rectangle to this method!
183
184 if (! rect.isEmpty())
185 rects.add (rect);
186 }
187
193 void add (const RectangleList& other)
194 {
195 for (auto& r : other)
196 add (r);
197 }
198
204 void subtract (const RectangleType rect)
205 {
206 if (auto numRects = rects.size())
207 {
208 const auto x1 = rect.getX();
209 const auto y1 = rect.getY();
210 const auto x2 = x1 + rect.getWidth();
211 const auto y2 = y1 + rect.getHeight();
212
213 for (int i = numRects; --i >= 0;)
214 {
215 auto& r = rects.getReference (i);
216
217 const auto rx1 = r.getX();
218 const auto ry1 = r.getY();
219 const auto rx2 = rx1 + r.getWidth();
220 const auto ry2 = ry1 + r.getHeight();
221
222 const auto isNotEqual = [&] (const RectangleType newRect)
223 {
224 // When subtracting tiny slices from relatively large rectangles, the
225 // subtraction may have no effect (due to limited-precision floating point
226 // maths) and the original rectangle may remain unchanged.
227 // We check that any 'new' rectangle has different dimensions to the rectangle
228 // being tested before adding it to the rects array.
229 // Integer arithmetic is not susceptible to this problem, so there's no need
230 // for this additional equality check when working with integral rectangles.
231 if constexpr (std::is_floating_point_v<ValueType>)
232 {
233 return newRect != r;
234 }
235 else
236 {
238 return true;
239 }
240 };
241
242 if (rx1 < x2 && x1 < rx2 && ry1 < y2 && y1 < ry2)
243 {
244 if (rx1 < x1 && x1 < rx2)
245 {
246 if (y1 <= ry1 && ry2 <= y2 && rx2 <= x2)
247 {
248 r.setWidth (x1 - rx1);
249 }
250 else
251 {
252 if (const RectangleType newRect (rx1, ry1, x1 - rx1, ry2 - ry1); isNotEqual (newRect))
253 {
254 r.setX (x1);
255 r.setWidth (rx2 - x1);
256
257 rects.insert (++i, newRect);
258 ++i;
259 }
260 }
261 }
262 else if (rx1 < x2 && x2 < rx2)
263 {
264 r.setX (x2);
265 r.setWidth (rx2 - x2);
266
267 if (ry1 < y1 || y2 < ry2 || rx1 < x1)
268 {
269 if (const RectangleType newRect (rx1, ry1, x2 - rx1, ry2 - ry1); isNotEqual (newRect))
270 {
271 rects.insert (++i, newRect);
272 ++i;
273 }
274 }
275 }
276 else if (ry1 < y1 && y1 < ry2)
277 {
278 if (x1 <= rx1 && rx2 <= x2 && ry2 <= y2)
279 {
280 r.setHeight (y1 - ry1);
281 }
282 else
283 {
284 if (const RectangleType newRect (rx1, ry1, rx2 - rx1, y1 - ry1); isNotEqual (newRect))
285 {
286 r.setY (y1);
287 r.setHeight (ry2 - y1);
288
289 rects.insert (++i, newRect);
290 ++i;
291 }
292 }
293 }
294 else if (ry1 < y2 && y2 < ry2)
295 {
296 r.setY (y2);
297 r.setHeight (ry2 - y2);
298
299 if (rx1 < x1 || x2 < rx2 || ry1 < y1)
300 {
301 if (const RectangleType newRect (rx1, ry1, rx2 - rx1, y2 - ry1); isNotEqual (newRect))
302 {
303 rects.insert (++i, newRect);
304 ++i;
305 }
306 }
307 }
308 else
309 {
310 rects.remove (i);
311 }
312 }
313 }
314 }
315 }
316
325 {
326 for (auto& r : otherList)
327 {
328 if (isEmpty())
329 return false;
330
331 subtract (r);
332 }
333
334 return ! isEmpty();
335 }
336
347 {
348 jassert (rect.isFinite()); // You must provide a valid rectangle to this method!
349
350 bool notEmpty = false;
351
352 if (rect.isEmpty())
353 {
354 clear();
355 }
356 else
357 {
358 for (int i = rects.size(); --i >= 0;)
359 {
360 auto& r = rects.getReference (i);
361
362 if (! rect.intersectRectangle (r))
363 rects.remove (i);
364 else
365 notEmpty = true;
366 }
367 }
368
369 return notEmpty;
370 }
371
381 template <typename OtherValueType>
383 {
384 if (isEmpty())
385 return false;
386
387 RectangleList result;
388
389 for (auto& rect : rects)
390 {
391 for (auto& r : other)
392 {
393 auto clipped = r.template toType<ValueType>();
394
395 if (rect.intersectRectangle (clipped))
396 result.rects.add (clipped);
397 }
398 }
399
400 swapWith (result);
401 return ! isEmpty();
402 }
403
414 {
415 jassert (rect.isFinite()); // You must provide a valid rectangle to this method!
416
417 destRegion.clear();
418
419 if (! rect.isEmpty())
420 for (auto r : rects)
421 if (rect.intersectRectangle (r))
422 destRegion.rects.add (r);
423
424 return ! destRegion.isEmpty();
425 }
426
433 {
434 rects.swapWith (otherList.rects);
435 }
436
437 //==============================================================================
441 bool containsPoint (Point<ValueType> point) const noexcept
442 {
443 for (auto& r : rects)
444 if (r.contains (point))
445 return true;
446
447 return false;
448 }
449
453 bool containsPoint (ValueType x, ValueType y) const noexcept
454 {
455 return containsPoint (Point<ValueType> (x, y));
456 }
457
465 {
466 if (rects.size() > 1)
467 {
469
470 for (auto& rect : rects)
471 {
472 r.subtract (rect);
473
474 if (r.isEmpty())
475 return true;
476 }
477 }
478 else if (! isEmpty())
479 {
480 return rects.getReference (0).contains (rectangleToCheck);
481 }
482
483 return false;
484 }
485
493 {
494 for (auto& r : rects)
495 if (r.intersects (rectangleToCheck))
496 return true;
497
498 return false;
499 }
500
504 bool intersects (const RectangleList& other) const noexcept
505 {
506 for (auto& r : rects)
507 if (other.intersectsRectangle (r))
508 return true;
509
510 return false;
511 }
512
513 //==============================================================================
516 {
517 if (isEmpty())
518 return {};
519
520 auto& r = rects.getReference (0);
521
522 if (rects.size() == 1)
523 return r;
524
525 auto minX = r.getX();
526 auto minY = r.getY();
527 auto maxX = minX + r.getWidth();
528 auto maxY = minY + r.getHeight();
529
530 for (int i = rects.size(); --i > 0;)
531 {
532 auto& r2 = rects.getReference (i);
533
534 minX = jmin (minX, r2.getX());
535 minY = jmin (minY, r2.getY());
536 maxX = jmax (maxX, r2.getRight());
537 maxY = jmax (maxY, r2.getBottom());
538 }
539
540 return { minX, minY, maxX - minX, maxY - minY };
541 }
542
550 {
551 for (int i = 0; i < rects.size() - 1; ++i)
552 {
553 auto& r = rects.getReference (i);
554 auto rx1 = r.getX();
555 auto ry1 = r.getY();
556 auto rx2 = rx1 + r.getWidth();
557 auto ry2 = ry1 + r.getHeight();
558
559 for (int j = rects.size(); --j > i;)
560 {
561 auto& r2 = rects.getReference (j);
562 auto jrx1 = r2.getX();
563 auto jry1 = r2.getY();
564 auto jrx2 = jrx1 + r2.getWidth();
565 auto jry2 = jry1 + r2.getHeight();
566
567 // if the vertical edges of any blocks are touching and their horizontals don't
568 // line up, split them horizontally..
569 if (jrx1 == rx2 || jrx2 == rx1)
570 {
571 if (jry1 > ry1 && jry1 < ry2)
572 {
573 r.setHeight (jry1 - ry1);
574 rects.add (RectangleType (rx1, jry1, rx2 - rx1, ry2 - jry1));
575 i = -1;
576 break;
577 }
578
579 if (jry2 > ry1 && jry2 < ry2)
580 {
581 r.setHeight (jry2 - ry1);
582 rects.add (RectangleType (rx1, jry2, rx2 - rx1, ry2 - jry2));
583 i = -1;
584 break;
585 }
586 else if (ry1 > jry1 && ry1 < jry2)
587 {
588 r2.setHeight (ry1 - jry1);
589 rects.add (RectangleType (jrx1, ry1, jrx2 - jrx1, jry2 - ry1));
590 i = -1;
591 break;
592 }
593 else if (ry2 > jry1 && ry2 < jry2)
594 {
595 r2.setHeight (ry2 - jry1);
596 rects.add (RectangleType (jrx1, ry2, jrx2 - jrx1, jry2 - ry2));
597 i = -1;
598 break;
599 }
600 }
601 }
602 }
603
604 for (int i = 0; i < rects.size() - 1; ++i)
605 {
606 auto& r = rects.getReference (i);
607
608 for (int j = rects.size(); --j > i;)
609 {
610 if (r.enlargeIfAdjacent (rects.getReference (j)))
611 {
612 rects.remove (j);
613 i = -1;
614 break;
615 }
616 }
617 }
618 }
619
621 void offsetAll (Point<ValueType> offset) noexcept
622 {
623 for (auto& r : rects)
624 r += offset;
625 }
626
628 void offsetAll (ValueType dx, ValueType dy) noexcept
629 {
631 }
632
634 template <typename ScaleType>
635 void scaleAll (ScaleType scaleFactor) noexcept
636 {
637 for (auto& r : rects)
638 r *= scaleFactor;
639 }
640
645 void transformAll (const AffineTransform& transform) noexcept
646 {
647 for (auto& r : rects)
648 r = r.transformedBy (transform);
649 }
650
651 //==============================================================================
653 Path toPath() const
654 {
655 Path p;
656
657 for (auto& r : rects)
658 p.addRectangle (r);
659
660 return p;
661 }
662
663 //==============================================================================
665 const RectangleType* begin() const noexcept { return rects.begin(); }
667 const RectangleType* end() const noexcept { return rects.end(); }
668
676 {
677 rects.ensureStorageAllocated (minNumRectangles);
678 }
679
680private:
681 //==============================================================================
683};
684
685} // namespace juce
Represents a 2D affine-transformation matrix.
Holds a resizable array of primitive or copy-by-value objects.
Definition juce_Array.h:56
A path is a sequence of lines and curves that may either form a closed shape or be open-ended.
Definition juce_Path.h:65
void addRectangle(float x, float y, float width, float height)
Adds a rectangle to the path.
A pair of (x, y) coordinates.
Definition juce_Point.h:42
Maintains a set of rectangles as a complex region.
bool containsPoint(ValueType x, ValueType y) const noexcept
Checks whether the region contains a given point.
RectangleType getRectangle(int index) const noexcept
Returns one of the rectangles at a particular index.
bool clipTo(const RectangleList< OtherValueType > &other)
Removes any areas of the region that lie outside a given rectangle list.
void clear()
Removes all rectangles to leave an empty region.
RectangleType getBounds() const noexcept
Returns the smallest rectangle that can enclose the whole of this region.
void add(ValueType x, ValueType y, ValueType width, ValueType height)
Merges a new rectangle into the list.
RectangleList(RectangleList &&other) noexcept
Move constructor.
void addWithoutMerging(RectangleType rect)
Dumbly adds a rectangle to the list without checking for overlaps.
void offsetAll(ValueType dx, ValueType dy) noexcept
Adds an x and y value to all the coordinates.
void add(const RectangleList &other)
Merges another rectangle list into this one.
Path toPath() const
Creates a Path object to represent this region.
bool subtract(const RectangleList &otherList)
Removes all areas in another RectangleList from this one.
void offsetAll(Point< ValueType > offset) noexcept
Adds an x and y value to all the coordinates.
bool intersectsRectangle(RectangleType rectangleToCheck) const noexcept
Checks whether the region contains any part of a given rectangle.
RectangleList & operator=(const RectangleList &other)
Copies this list from another one.
bool containsRectangle(RectangleType rectangleToCheck) const
Checks whether the region contains the whole of a given rectangle.
void scaleAll(ScaleType scaleFactor) noexcept
Scales all the coordinates.
RectangleList()=default
Creates an empty RectangleList.
bool intersects(const RectangleList &other) const noexcept
Checks whether this region intersects any part of another one.
bool clipTo(RectangleType rect)
Removes any areas of the region that lie outside a given rectangle.
const RectangleType * begin() const noexcept
Standard method for iterating the rectangles in the list.
bool containsPoint(Point< ValueType > point) const noexcept
Checks whether the region contains a given point.
const RectangleType * end() const noexcept
Standard method for iterating the rectangles in the list.
RectangleList(const RectangleList &other)
Creates a copy of another list.
RectangleList(RectangleType rect)
Creates a list containing just one rectangle.
void add(RectangleType rect)
Merges a new rectangle into the list.
int getNumRectangles() const noexcept
Returns the number of rectangles in the list.
void subtract(const RectangleType rect)
Removes a rectangular region from the list.
bool isEmpty() const noexcept
Returns true if the region is empty.
void swapWith(RectangleList &otherList) noexcept
Swaps the contents of this and another list.
void ensureStorageAllocated(int minNumRectangles)
Increases the internal storage to hold a minimum number of rectangles.
void consolidate()
Optimises the list into a minimum number of constituent rectangles.
bool getIntersectionWith(RectangleType rect, RectangleList &destRegion) const
Creates a region which is the result of clipping this one to a given rectangle.
void transformAll(const AffineTransform &transform) noexcept
Applies a transform to all the rectangles.
Manages a rectangle and allows geometric operations to be performed on it.
bool intersects(Rectangle other) const noexcept
Returns true if any part of another rectangle overlaps this one.
bool contains(ValueType xCoord, ValueType yCoord) const noexcept
Returns true if this coordinate is inside the rectangle.
ValueType getX() const noexcept
Returns the x coordinate of the rectangle's left-hand-side.
ValueType getWidth() const noexcept
Returns the width of the rectangle.
bool isFinite() const noexcept
Returns true if the rectangle's values are all finite numbers, i.e.
ValueType getY() const noexcept
Returns the y coordinate of the rectangle's top edge.
bool isEmpty() const noexcept
Returns true if the rectangle's width or height are zero or less.
ValueType getHeight() const noexcept
Returns the height of the rectangle.
bool intersectRectangle(ValueType &otherX, ValueType &otherY, ValueType &otherW, ValueType &otherH) const noexcept
Clips a set of rectangle coordinates so that they lie only within this one.
#define jassert(expression)
Platform-independent assertion macro.
JUCE Namespace.
constexpr Type jmin(Type a, Type b)
Returns the smaller of two values.
constexpr Type jmax(Type a, Type b)
Returns the larger of two values.
void ignoreUnused(Types &&...) noexcept
Handy function for avoiding unused variables warning.
Type unalignedPointerCast(void *ptr) noexcept
Casts a pointer to another type via void*, which suppresses the cast-align warning which sometimes ar...
Definition juce_Memory.h:88
y1