@@ -212,95 +212,24 @@ class RectangleList final
212212 */
213213 void subtract (const RectangleType rect)
214214 {
215- using PointType = Point<ValueType>;
216-
217- const auto numRects = rects.size ();
218-
219- if (numRects == 0 )
215+ if (rects.isEmpty ())
220216 return ;
221217
222- struct AABB
218+ if constexpr (std::is_floating_point_v<ValueType>)
223219 {
224- AABB () = default ;
225- AABB (const RectangleType& r) : tl (r.getTopLeft()), br (r.getBottomRight()) {}
226- AABB (PointType a, PointType b) : tl (a), br (b) {}
227- operator RectangleType () const { return RectangleType { tl, br }; }
228-
229- bool completelyOutside (const AABB& other) const
230- {
231- return other.br .x <= tl.x || br.x <= other.tl .x || other.br .y <= tl.y || br.y <= other.tl .y ;
232- }
233-
234- PointType tl, br;
235- };
220+ Array<AABB> alternativeRepresentation;
221+ alternativeRepresentation.resize (rects.size ());
222+ std::copy (rects.begin (), rects.end (), alternativeRepresentation.begin ());
236223
237- Array<AABB> aabbs;
238- aabbs.resize (rects.size ());
239- std::copy (rects.begin (), rects.end (), aabbs.begin ());
240- const AABB aabb { rect };
224+ subtract (alternativeRepresentation, rect);
241225
242- for (int i = numRects; --i >= 0 ;)
226+ rects.resize (alternativeRepresentation.size ());
227+ std::copy (alternativeRepresentation.begin (), alternativeRepresentation.end (), rects.begin ());
228+ }
229+ else
243230 {
244- auto & rRef = aabbs.getReference (i);;
245- const auto r = rRef;
246-
247- if (r.completelyOutside (aabb))
248- continue ;
249-
250- if (r.tl .x < aabb.tl .x && aabb.tl .x < r.br .x )
251- {
252- if (aabb.tl .y <= r.tl .y && r.br .y <= aabb.br .y && r.br .x <= aabb.br .x )
253- {
254- rRef.br .x = aabb.tl .x ;
255- }
256- else
257- {
258- rRef.tl .x = aabb.tl .x ;
259- aabbs.insert (++i, { r.tl , { aabb.tl .x , r.br .y } });
260- ++i;
261- }
262- }
263- else if (r.tl .x < aabb.br .x && aabb.br .x < r.br .x )
264- {
265- rRef.tl .x = aabb.br .x ;
266-
267- if (r.tl .y < aabb.tl .y || aabb.br .y < r.br .y || r.tl .x < aabb.tl .x )
268- {
269- aabbs.insert (++i, { r.tl , { aabb.br .x , r.br .y } });
270- ++i;
271- }
272- }
273- else if (r.tl .y < aabb.tl .y && aabb.tl .y < r.br .y )
274- {
275- if (aabb.tl .x <= r.tl .x && r.br .x <= aabb.br .x && r.br .y <= aabb.br .y )
276- {
277- rRef.br .y = aabb.tl .y ;
278- }
279- else
280- {
281- rRef.tl .y = aabb.tl .y ;
282- aabbs.insert (++i, { r.tl , { r.br .x , aabb.tl .y } });
283- ++i;
284- }
285- }
286- else if (r.tl .y < aabb.br .y && aabb.br .y < r.br .y )
287- {
288- rRef.tl .y = aabb.br .y ;
289-
290- if (r.tl .x < aabb.tl .x || aabb.br .x < r.br .x || r.tl .y < aabb.tl .y )
291- {
292- aabbs.insert (++i, { r.tl , { r.br .x , aabb.br .y } });
293- ++i;
294- }
295- }
296- else
297- {
298- aabbs.remove (i);
299- }
231+ subtract (rects, rect);
300232 }
301-
302- rects.resize (aabbs.size ());
303- std::copy (aabbs.begin (), aabbs.end (), rects.begin ());
304233 }
305234
306235 /* * Removes all areas in another RectangleList from this one.
@@ -667,6 +596,130 @@ class RectangleList final
667596 }
668597
669598private:
599+ using PointType = Point<ValueType>;
600+
601+ struct AABB
602+ {
603+ AABB () = default ;
604+ AABB (const RectangleType& r) : tl (r.getTopLeft()), br (r.getBottomRight()) {}
605+ AABB (PointType a, PointType b) : tl (a), br (b) {}
606+ operator RectangleType () const { return RectangleType { tl, br }; }
607+
608+ bool completelyOutside (const AABB& other) const
609+ {
610+ return other.br .x <= tl.x || br.x <= other.tl .x || other.br .y <= tl.y || br.y <= other.tl .y ;
611+ }
612+
613+ PointType tl, br;
614+ };
615+
616+ static PointType getTL (const AABB& aabb)
617+ {
618+ return aabb.tl ;
619+ }
620+
621+ static PointType getBR (const AABB& aabb)
622+ {
623+ return aabb.br ;
624+ }
625+
626+ static PointType getTL (const RectangleType& r)
627+ {
628+ return r.getTopLeft ();
629+ }
630+
631+ static PointType getBR (const RectangleType& r)
632+ {
633+ return r.getBottomRight ();
634+ }
635+
636+ template <typename Rect>
637+ static void subtract (Array<Rect>& rectList, RectangleType rect)
638+ {
639+ jassert (! rectList.isEmpty ());
640+
641+ const AABB rAABB { getTL (rect), getBR (rect) };
642+
643+ for (int i = rectList.size (); --i >= 0 ;)
644+ {
645+ auto & iRef = rectList.getReference (i);
646+ const AABB iAABB { getTL (iRef), getBR (iRef) };
647+
648+ if (iAABB.completelyOutside (rAABB))
649+ continue ;
650+
651+ std::invoke ([&]
652+ {
653+ // For each rectangle in the list, we check for an overlap with the parameter rect
654+ // and subdivide the list rectangles as necessary.
655+ // The checks for each list rectangle happen in two stages, treating first the X
656+ // then the Y axis as the 'major' axis. The terms 'major' and 'minor' are somewhat
657+ // arbitrary. Essentially, in each pass, the rectangles in the list are only
658+ // modified and/or subdivided on the major axis, without changing any minor axis
659+ // coordinates. Subdividing an overlapping rect in this way may produce new rects
660+ // that still overlap with the parameter rect. However, those will get cleaned up
661+ // on the subsequent pass, where the major/minor axes are swapped.
662+
663+ struct Fields
664+ {
665+ ValueType PointType::* major;
666+ ValueType PointType::* minor;
667+ };
668+
669+ for (const auto & fields : { Fields { &PointType::x, &PointType::y },
670+ Fields { &PointType::y, &PointType::x } })
671+ {
672+ const auto replaceMajor = [&] (auto modified, const auto & replacement)
673+ {
674+ modified.*(fields.major ) = replacement.*(fields.major );
675+ return modified;
676+ };
677+
678+ const auto insert = [&] (const PointType& rAABBpt)
679+ {
680+ rectList.insert (++i, { iAABB.tl , replaceMajor (iAABB.br , rAABBpt) });
681+ ++i;
682+ };
683+
684+ if ( iAABB.tl .*(fields.major ) < rAABB.tl .*(fields.major )
685+ && rAABB.tl .*(fields.major ) < iAABB.br .*(fields.major ))
686+ {
687+ if ( rAABB.tl .*(fields.minor ) <= iAABB.tl .*(fields.minor )
688+ && iAABB.br .*(fields.minor ) <= rAABB.br .*(fields.minor )
689+ && iAABB.br .*(fields.major ) <= rAABB.br .*(fields.major ))
690+ {
691+ iRef = { iAABB.tl , replaceMajor (iAABB.br , rAABB.tl ) };
692+ }
693+ else
694+ {
695+ iRef = { replaceMajor (iAABB.tl , rAABB.tl ), iAABB.br };
696+ insert (rAABB.tl );
697+ }
698+
699+ return ;
700+ }
701+
702+ if ( iAABB.tl .*(fields.major ) < rAABB.br .*(fields.major )
703+ && rAABB.br .*(fields.major ) < iAABB.br .*(fields.major ))
704+ {
705+ iRef = { replaceMajor (iAABB.tl , rAABB.br ), iAABB.br };
706+
707+ if ( iAABB.tl .*(fields.minor ) < rAABB.tl .*(fields.minor )
708+ || rAABB.br .*(fields.minor ) < iAABB.br .*(fields.minor )
709+ || iAABB.tl .*(fields.major ) < rAABB.tl .*(fields.major ))
710+ {
711+ insert (rAABB.br );
712+ }
713+
714+ return ;
715+ }
716+ }
717+
718+ rectList.remove (i);
719+ });
720+ }
721+ }
722+
670723 // ==============================================================================
671724 Array<RectangleType> rects;
672725};
0 commit comments