1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-10 23:44:24 +00:00
JUCE/modules/juce_graphics/geometry/juce_RectangleList.cpp

526 lines
14 KiB
C++

/*
==============================================================================
This file is part of the JUCE library - "Jules' Utility Class Extensions"
Copyright 2004-11 by Raw Material Software Ltd.
------------------------------------------------------------------------------
JUCE can be redistributed and/or modified under the terms of the GNU General
Public License (Version 2), as published by the Free Software Foundation.
A copy of the license is included in the JUCE distribution, or can be found
online at www.gnu.org/licenses.
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.rawmaterialsoftware.com/juce for more information.
==============================================================================
*/
BEGIN_JUCE_NAMESPACE
//==============================================================================
RectangleList::RectangleList() noexcept
{
}
RectangleList::RectangleList (const Rectangle<int>& rect)
{
if (! rect.isEmpty())
rects.add (rect);
}
RectangleList::RectangleList (const RectangleList& other)
: rects (other.rects)
{
}
RectangleList& RectangleList::operator= (const RectangleList& other)
{
rects = other.rects;
return *this;
}
RectangleList::~RectangleList()
{
}
//==============================================================================
void RectangleList::clear()
{
rects.clearQuick();
}
Rectangle<int> RectangleList::getRectangle (const int index) const noexcept
{
if (isPositiveAndBelow (index, rects.size()))
return rects.getReference (index);
return Rectangle<int>();
}
bool RectangleList::isEmpty() const noexcept
{
return rects.size() == 0;
}
//==============================================================================
RectangleList::Iterator::Iterator (const RectangleList& list) noexcept
: current (nullptr),
owner (list),
index (list.rects.size())
{
}
RectangleList::Iterator::~Iterator()
{
}
bool RectangleList::Iterator::next() noexcept
{
if (--index >= 0)
{
current = & (owner.rects.getReference (index));
return true;
}
return false;
}
//==============================================================================
void RectangleList::add (const Rectangle<int>& rect)
{
if (! rect.isEmpty())
{
if (rects.size() == 0)
{
rects.add (rect);
}
else
{
bool anyOverlaps = false;
int i;
for (i = rects.size(); --i >= 0;)
{
Rectangle<int>& ourRect = rects.getReference (i);
if (rect.intersects (ourRect))
{
if (rect.contains (ourRect))
rects.remove (i);
else if (! ourRect.reduceIfPartlyContainedIn (rect))
anyOverlaps = true;
}
}
if (anyOverlaps && rects.size() > 0)
{
RectangleList r (rect);
for (i = rects.size(); --i >= 0;)
{
const Rectangle<int>& ourRect = rects.getReference (i);
if (rect.intersects (ourRect))
{
r.subtract (ourRect);
if (r.rects.size() == 0)
return;
}
}
for (i = r.getNumRectangles(); --i >= 0;)
rects.add (r.rects.getReference (i));
}
else
{
rects.add (rect);
}
}
}
}
void RectangleList::addWithoutMerging (const Rectangle<int>& rect)
{
if (! rect.isEmpty())
rects.add (rect);
}
void RectangleList::add (const int x, const int y, const int w, const int h)
{
if (rects.size() == 0)
{
if (w > 0 && h > 0)
rects.add (Rectangle<int> (x, y, w, h));
}
else
{
add (Rectangle<int> (x, y, w, h));
}
}
void RectangleList::add (const RectangleList& other)
{
for (int i = 0; i < other.rects.size(); ++i)
add (other.rects.getReference (i));
}
void RectangleList::subtract (const Rectangle<int>& rect)
{
const int originalNumRects = rects.size();
if (originalNumRects > 0)
{
const int x1 = rect.x;
const int y1 = rect.y;
const int x2 = x1 + rect.w;
const int y2 = y1 + rect.h;
for (int i = getNumRectangles(); --i >= 0;)
{
Rectangle<int>& r = rects.getReference (i);
const int rx1 = r.x;
const int ry1 = r.y;
const int rx2 = rx1 + r.w;
const int ry2 = ry1 + r.h;
if (! (x2 <= rx1 || x1 >= rx2 || y2 <= ry1 || y1 >= ry2))
{
if (x1 > rx1 && x1 < rx2)
{
if (y1 <= ry1 && y2 >= ry2 && x2 >= rx2)
{
r.w = x1 - rx1;
}
else
{
r.x = x1;
r.w = rx2 - x1;
rects.insert (i + 1, Rectangle<int> (rx1, ry1, x1 - rx1, ry2 - ry1));
i += 2;
}
}
else if (x2 > rx1 && x2 < rx2)
{
r.x = x2;
r.w = rx2 - x2;
if (y1 > ry1 || y2 < ry2 || x1 > rx1)
{
rects.insert (i + 1, Rectangle<int> (rx1, ry1, x2 - rx1, ry2 - ry1));
i += 2;
}
}
else if (y1 > ry1 && y1 < ry2)
{
if (x1 <= rx1 && x2 >= rx2 && y2 >= ry2)
{
r.h = y1 - ry1;
}
else
{
r.y = y1;
r.h = ry2 - y1;
rects.insert (i + 1, Rectangle<int> (rx1, ry1, rx2 - rx1, y1 - ry1));
i += 2;
}
}
else if (y2 > ry1 && y2 < ry2)
{
r.y = y2;
r.h = ry2 - y2;
if (x1 > rx1 || x2 < rx2 || y1 > ry1)
{
rects.insert (i + 1, Rectangle<int> (rx1, ry1, rx2 - rx1, y2 - ry1));
i += 2;
}
}
else
{
rects.remove (i);
}
}
}
}
}
bool RectangleList::subtract (const RectangleList& otherList)
{
for (int i = otherList.rects.size(); --i >= 0 && rects.size() > 0;)
subtract (otherList.rects.getReference (i));
return rects.size() > 0;
}
bool RectangleList::clipTo (const Rectangle<int>& rect)
{
bool notEmpty = false;
if (rect.isEmpty())
{
clear();
}
else
{
for (int i = rects.size(); --i >= 0;)
{
Rectangle<int>& r = rects.getReference (i);
if (! rect.intersectRectangle (r.x, r.y, r.w, r.h))
rects.remove (i);
else
notEmpty = true;
}
}
return notEmpty;
}
bool RectangleList::clipTo (const RectangleList& other)
{
if (rects.size() == 0)
return false;
RectangleList result;
for (int j = 0; j < rects.size(); ++j)
{
const Rectangle<int>& rect = rects.getReference (j);
for (int i = other.rects.size(); --i >= 0;)
{
Rectangle<int> r (other.rects.getReference (i));
if (rect.intersectRectangle (r.x, r.y, r.w, r.h))
result.rects.add (r);
}
}
swapWith (result);
return ! isEmpty();
}
bool RectangleList::getIntersectionWith (const Rectangle<int>& rect, RectangleList& destRegion) const
{
destRegion.clear();
if (! rect.isEmpty())
{
for (int i = rects.size(); --i >= 0;)
{
Rectangle<int> r (rects.getReference (i));
if (rect.intersectRectangle (r.x, r.y, r.w, r.h))
destRegion.rects.add (r);
}
}
return destRegion.rects.size() > 0;
}
void RectangleList::swapWith (RectangleList& otherList) noexcept
{
rects.swapWithArray (otherList.rects);
}
//==============================================================================
void RectangleList::consolidate()
{
int i;
for (i = 0; i < getNumRectangles() - 1; ++i)
{
Rectangle<int>& r = rects.getReference (i);
const int rx1 = r.x;
const int ry1 = r.y;
const int rx2 = rx1 + r.w;
const int ry2 = ry1 + r.h;
for (int j = rects.size(); --j > i;)
{
Rectangle<int>& r2 = rects.getReference (j);
const int jrx1 = r2.x;
const int jry1 = r2.y;
const int jrx2 = jrx1 + r2.w;
const int jry2 = jry1 + r2.h;
// if the vertical edges of any blocks are touching and their horizontals don't
// line up, split them horizontally..
if (jrx1 == rx2 || jrx2 == rx1)
{
if (jry1 > ry1 && jry1 < ry2)
{
r.h = jry1 - ry1;
rects.add (Rectangle<int> (rx1, jry1, rx2 - rx1, ry2 - jry1));
i = -1;
break;
}
if (jry2 > ry1 && jry2 < ry2)
{
r.h = jry2 - ry1;
rects.add (Rectangle<int> (rx1, jry2, rx2 - rx1, ry2 - jry2));
i = -1;
break;
}
else if (ry1 > jry1 && ry1 < jry2)
{
r2.h = ry1 - jry1;
rects.add (Rectangle<int> (jrx1, ry1, jrx2 - jrx1, jry2 - ry1));
i = -1;
break;
}
else if (ry2 > jry1 && ry2 < jry2)
{
r2.h = ry2 - jry1;
rects.add (Rectangle<int> (jrx1, ry2, jrx2 - jrx1, jry2 - ry2));
i = -1;
break;
}
}
}
}
for (i = 0; i < rects.size() - 1; ++i)
{
Rectangle<int>& r = rects.getReference (i);
for (int j = rects.size(); --j > i;)
{
if (r.enlargeIfAdjacent (rects.getReference (j)))
{
rects.remove (j);
i = -1;
break;
}
}
}
}
//==============================================================================
bool RectangleList::containsPoint (const int x, const int y) const noexcept
{
for (int i = getNumRectangles(); --i >= 0;)
if (rects.getReference (i).contains (x, y))
return true;
return false;
}
bool RectangleList::containsRectangle (const Rectangle<int>& rectangleToCheck) const
{
if (rects.size() > 1)
{
RectangleList r (rectangleToCheck);
for (int i = rects.size(); --i >= 0;)
{
r.subtract (rects.getReference (i));
if (r.rects.size() == 0)
return true;
}
}
else if (rects.size() > 0)
{
return rects.getReference (0).contains (rectangleToCheck);
}
return false;
}
bool RectangleList::intersectsRectangle (const Rectangle<int>& rectangleToCheck) const noexcept
{
for (int i = rects.size(); --i >= 0;)
if (rects.getReference (i).intersects (rectangleToCheck))
return true;
return false;
}
bool RectangleList::intersects (const RectangleList& other) const noexcept
{
for (int i = rects.size(); --i >= 0;)
if (other.intersectsRectangle (rects.getReference (i)))
return true;
return false;
}
Rectangle<int> RectangleList::getBounds() const noexcept
{
if (rects.size() <= 1)
{
if (rects.size() == 0)
return Rectangle<int>();
else
return rects.getReference (0);
}
else
{
const Rectangle<int>& r = rects.getReference (0);
int minX = r.x;
int minY = r.y;
int maxX = minX + r.w;
int maxY = minY + r.h;
for (int i = rects.size(); --i > 0;)
{
const Rectangle<int>& r2 = rects.getReference (i);
minX = jmin (minX, r2.x);
minY = jmin (minY, r2.y);
maxX = jmax (maxX, r2.getRight());
maxY = jmax (maxY, r2.getBottom());
}
return Rectangle<int> (minX, minY, maxX - minX, maxY - minY);
}
}
void RectangleList::offsetAll (const int dx, const int dy) noexcept
{
for (int i = rects.size(); --i >= 0;)
{
Rectangle<int>& r = rects.getReference (i);
r.x += dx;
r.y += dy;
}
}
//==============================================================================
Path RectangleList::toPath() const
{
Path p;
for (int i = rects.size(); --i >= 0;)
{
const Rectangle<int>& r = rects.getReference (i);
p.addRectangle ((float) r.x,
(float) r.y,
(float) r.w,
(float) r.h);
}
return p;
}
END_JUCE_NAMESPACE