|
|
|
@@ -137,37 +137,26 @@ Path::~Path() |
|
|
|
}
|
|
|
|
|
|
|
|
Path::Path (const Path& other)
|
|
|
|
: numElements (other.numElements),
|
|
|
|
: data (other.data),
|
|
|
|
bounds (other.bounds),
|
|
|
|
useNonZeroWinding (other.useNonZeroWinding)
|
|
|
|
{
|
|
|
|
if (numElements > 0)
|
|
|
|
{
|
|
|
|
data.setAllocatedSize ((int) numElements);
|
|
|
|
memcpy (data.elements, other.data.elements, numElements * sizeof (float));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Path& Path::operator= (const Path& other)
|
|
|
|
{
|
|
|
|
if (this != &other)
|
|
|
|
{
|
|
|
|
data.ensureAllocatedSize ((int) other.numElements);
|
|
|
|
|
|
|
|
numElements = other.numElements;
|
|
|
|
data = other.data;
|
|
|
|
bounds = other.bounds;
|
|
|
|
useNonZeroWinding = other.useNonZeroWinding;
|
|
|
|
|
|
|
|
if (numElements > 0)
|
|
|
|
memcpy (data.elements, other.data.elements, numElements * sizeof (float));
|
|
|
|
}
|
|
|
|
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
Path::Path (Path&& other) noexcept
|
|
|
|
: data (static_cast<ArrayAllocationBase <float, DummyCriticalSection>&&> (other.data)),
|
|
|
|
numElements (other.numElements),
|
|
|
|
: data (static_cast<Array<float>&&> (other.data)),
|
|
|
|
bounds (other.bounds),
|
|
|
|
useNonZeroWinding (other.useNonZeroWinding)
|
|
|
|
{
|
|
|
|
@@ -175,40 +164,24 @@ Path::Path (Path&& other) noexcept |
|
|
|
|
|
|
|
Path& Path::operator= (Path&& other) noexcept
|
|
|
|
{
|
|
|
|
data = static_cast<ArrayAllocationBase <float, DummyCriticalSection>&&> (other.data);
|
|
|
|
numElements = other.numElements;
|
|
|
|
data = static_cast<Array<float>&&> (other.data);
|
|
|
|
bounds = other.bounds;
|
|
|
|
useNonZeroWinding = other.useNonZeroWinding;
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Path::operator== (const Path& other) const noexcept
|
|
|
|
{
|
|
|
|
return ! operator!= (other);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Path::operator!= (const Path& other) const noexcept
|
|
|
|
{
|
|
|
|
if (numElements != other.numElements || useNonZeroWinding != other.useNonZeroWinding)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
for (size_t i = 0; i < numElements; ++i)
|
|
|
|
if (data.elements[i] != other.data.elements[i])
|
|
|
|
return true;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
bool Path::operator== (const Path& other) const noexcept { return useNonZeroWinding == other.useNonZeroWinding && data == other.data; }
|
|
|
|
bool Path::operator!= (const Path& other) const noexcept { return ! operator== (other); }
|
|
|
|
|
|
|
|
void Path::clear() noexcept
|
|
|
|
{
|
|
|
|
numElements = 0;
|
|
|
|
data.clearQuick();
|
|
|
|
bounds.reset();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Path::swapWithPath (Path& other) noexcept
|
|
|
|
{
|
|
|
|
data.swapWith (other.data);
|
|
|
|
std::swap (numElements, other.numElements);
|
|
|
|
std::swap (bounds.pathXMin, other.bounds.pathXMin);
|
|
|
|
std::swap (bounds.pathXMax, other.bounds.pathXMax);
|
|
|
|
std::swap (bounds.pathYMin, other.bounds.pathYMin);
|
|
|
|
@@ -230,11 +203,9 @@ void Path::scaleToFit (float x, float y, float w, float h, bool preserveProporti |
|
|
|
//==============================================================================
|
|
|
|
bool Path::isEmpty() const noexcept
|
|
|
|
{
|
|
|
|
size_t i = 0;
|
|
|
|
|
|
|
|
while (i < numElements)
|
|
|
|
for (auto i = data.begin(), e = data.end(); i != e; ++i)
|
|
|
|
{
|
|
|
|
auto type = data.elements[i++];
|
|
|
|
auto type = *i;
|
|
|
|
|
|
|
|
if (isMarker (type, moveMarker))
|
|
|
|
{
|
|
|
|
@@ -264,23 +235,19 @@ Rectangle<float> Path::getBoundsTransformed (const AffineTransform& transform) c |
|
|
|
//==============================================================================
|
|
|
|
void Path::preallocateSpace (int numExtraCoordsToMakeSpaceFor)
|
|
|
|
{
|
|
|
|
data.ensureAllocatedSize ((int) numElements + numExtraCoordsToMakeSpaceFor);
|
|
|
|
data.ensureStorageAllocated (data.size() + numExtraCoordsToMakeSpaceFor);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Path::startNewSubPath (const float x, const float y)
|
|
|
|
{
|
|
|
|
JUCE_CHECK_COORDS_ARE_VALID (x, y);
|
|
|
|
|
|
|
|
if (numElements == 0)
|
|
|
|
if (data.isEmpty())
|
|
|
|
bounds.reset (x, y);
|
|
|
|
else
|
|
|
|
bounds.extend (x, y);
|
|
|
|
|
|
|
|
preallocateSpace (3);
|
|
|
|
|
|
|
|
data.elements[numElements++] = moveMarker;
|
|
|
|
data.elements[numElements++] = x;
|
|
|
|
data.elements[numElements++] = y;
|
|
|
|
data.add (moveMarker, x, y);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Path::startNewSubPath (Point<float> start)
|
|
|
|
@@ -292,15 +259,10 @@ void Path::lineTo (const float x, const float y) |
|
|
|
{
|
|
|
|
JUCE_CHECK_COORDS_ARE_VALID (x, y);
|
|
|
|
|
|
|
|
if (numElements == 0)
|
|
|
|
if (data.isEmpty())
|
|
|
|
startNewSubPath (0, 0);
|
|
|
|
|
|
|
|
preallocateSpace (3);
|
|
|
|
|
|
|
|
data.elements[numElements++] = lineMarker;
|
|
|
|
data.elements[numElements++] = x;
|
|
|
|
data.elements[numElements++] = y;
|
|
|
|
|
|
|
|
data.add (lineMarker, x, y);
|
|
|
|
bounds.extend (x, y);
|
|
|
|
}
|
|
|
|
|
|
|
|
@@ -315,17 +277,10 @@ void Path::quadraticTo (const float x1, const float y1, |
|
|
|
JUCE_CHECK_COORDS_ARE_VALID (x1, y1);
|
|
|
|
JUCE_CHECK_COORDS_ARE_VALID (x2, y2);
|
|
|
|
|
|
|
|
if (numElements == 0)
|
|
|
|
if (data.isEmpty())
|
|
|
|
startNewSubPath (0, 0);
|
|
|
|
|
|
|
|
preallocateSpace (5);
|
|
|
|
|
|
|
|
data.elements[numElements++] = quadMarker;
|
|
|
|
data.elements[numElements++] = x1;
|
|
|
|
data.elements[numElements++] = y1;
|
|
|
|
data.elements[numElements++] = x2;
|
|
|
|
data.elements[numElements++] = y2;
|
|
|
|
|
|
|
|
data.add (quadMarker, x1, y1, x2, y2);
|
|
|
|
bounds.extend (x1, y1, x2, y2);
|
|
|
|
}
|
|
|
|
|
|
|
|
@@ -343,19 +298,10 @@ void Path::cubicTo (const float x1, const float y1, |
|
|
|
JUCE_CHECK_COORDS_ARE_VALID (x2, y2);
|
|
|
|
JUCE_CHECK_COORDS_ARE_VALID (x3, y3);
|
|
|
|
|
|
|
|
if (numElements == 0)
|
|
|
|
if (data.isEmpty())
|
|
|
|
startNewSubPath (0, 0);
|
|
|
|
|
|
|
|
preallocateSpace (7);
|
|
|
|
|
|
|
|
data.elements[numElements++] = cubicMarker;
|
|
|
|
data.elements[numElements++] = x1;
|
|
|
|
data.elements[numElements++] = y1;
|
|
|
|
data.elements[numElements++] = x2;
|
|
|
|
data.elements[numElements++] = y2;
|
|
|
|
data.elements[numElements++] = x3;
|
|
|
|
data.elements[numElements++] = y3;
|
|
|
|
|
|
|
|
data.add (cubicMarker, x1, y1, x2, y2, x3, y3);
|
|
|
|
bounds.extend (x1, y1, x2, y2);
|
|
|
|
bounds.extend (x3, y3);
|
|
|
|
}
|
|
|
|
@@ -371,48 +317,43 @@ void Path::cubicTo (Point<float> controlPoint1, |
|
|
|
|
|
|
|
void Path::closeSubPath()
|
|
|
|
{
|
|
|
|
if (numElements > 0 && ! isMarker (data.elements[numElements - 1], closeSubPathMarker))
|
|
|
|
{
|
|
|
|
preallocateSpace (1);
|
|
|
|
data.elements[numElements++] = closeSubPathMarker;
|
|
|
|
}
|
|
|
|
if (! (data.isEmpty() || isMarker (data.getLast(), closeSubPathMarker)))
|
|
|
|
data.add (closeSubPathMarker);
|
|
|
|
}
|
|
|
|
|
|
|
|
Point<float> Path::getCurrentPosition() const
|
|
|
|
{
|
|
|
|
int i = (int) numElements - 1;
|
|
|
|
if (data.isEmpty())
|
|
|
|
return {};
|
|
|
|
|
|
|
|
auto* i = data.end() - 1;
|
|
|
|
|
|
|
|
if (i > 0 && isMarker (data.elements[i], closeSubPathMarker))
|
|
|
|
if (isMarker (*i, closeSubPathMarker))
|
|
|
|
{
|
|
|
|
while (i >= 0)
|
|
|
|
while (i != data.begin())
|
|
|
|
{
|
|
|
|
if (isMarker (data.elements[i], moveMarker))
|
|
|
|
if (isMarker (*--i, moveMarker))
|
|
|
|
{
|
|
|
|
i += 2;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
--i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (i > 0)
|
|
|
|
return { data.elements[i - 1], data.elements[i] };
|
|
|
|
if (i != data.begin())
|
|
|
|
return { *(i - 1), *i };
|
|
|
|
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
|
|
|
void Path::addRectangle (const float x, const float y,
|
|
|
|
const float w, const float h)
|
|
|
|
void Path::addRectangle (float x, float y, float w, float h)
|
|
|
|
{
|
|
|
|
float x1 = x, y1 = y, x2 = x + w, y2 = y + h;
|
|
|
|
auto x1 = x, y1 = y, x2 = x + w, y2 = y + h;
|
|
|
|
|
|
|
|
if (w < 0) std::swap (x1, x2);
|
|
|
|
if (h < 0) std::swap (y1, y2);
|
|
|
|
|
|
|
|
preallocateSpace (13);
|
|
|
|
|
|
|
|
if (numElements == 0)
|
|
|
|
if (data.isEmpty())
|
|
|
|
{
|
|
|
|
bounds.pathXMin = x1;
|
|
|
|
bounds.pathXMax = x2;
|
|
|
|
@@ -427,19 +368,11 @@ void Path::addRectangle (const float x, const float y, |
|
|
|
bounds.pathYMax = jmax (bounds.pathYMax, y2);
|
|
|
|
}
|
|
|
|
|
|
|
|
data.elements[numElements++] = moveMarker;
|
|
|
|
data.elements[numElements++] = x1;
|
|
|
|
data.elements[numElements++] = y2;
|
|
|
|
data.elements[numElements++] = lineMarker;
|
|
|
|
data.elements[numElements++] = x1;
|
|
|
|
data.elements[numElements++] = y1;
|
|
|
|
data.elements[numElements++] = lineMarker;
|
|
|
|
data.elements[numElements++] = x2;
|
|
|
|
data.elements[numElements++] = y1;
|
|
|
|
data.elements[numElements++] = lineMarker;
|
|
|
|
data.elements[numElements++] = x2;
|
|
|
|
data.elements[numElements++] = y2;
|
|
|
|
data.elements[numElements++] = closeSubPathMarker;
|
|
|
|
data.add (moveMarker, x1, y2,
|
|
|
|
lineMarker, x1, y1,
|
|
|
|
lineMarker, x2, y1,
|
|
|
|
lineMarker, x2, y2,
|
|
|
|
closeSubPathMarker);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Path::addRoundedRectangle (float x, float y, float w, float h, float csx, float csy)
|
|
|
|
@@ -511,9 +444,9 @@ void Path::addTriangle (float x1, float y1, |
|
|
|
float x2, float y2,
|
|
|
|
float x3, float y3)
|
|
|
|
{
|
|
|
|
addTriangle (Point<float> (x1, y1),
|
|
|
|
Point<float> (x2, y2),
|
|
|
|
Point<float> (x3, y3));
|
|
|
|
addTriangle ({ x1, y1 },
|
|
|
|
{ x2, y2 },
|
|
|
|
{ x3, y3 });
|
|
|
|
}
|
|
|
|
|
|
|
|
void Path::addTriangle (Point<float> p1, Point<float> p2, Point<float> p3)
|
|
|
|
@@ -524,10 +457,10 @@ void Path::addTriangle (Point<float> p1, Point<float> p2, Point<float> p3) |
|
|
|
closeSubPath();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Path::addQuadrilateral (const float x1, const float y1,
|
|
|
|
const float x2, const float y2,
|
|
|
|
const float x3, const float y3,
|
|
|
|
const float x4, const float y4)
|
|
|
|
void Path::addQuadrilateral (float x1, float y1,
|
|
|
|
float x2, float y2,
|
|
|
|
float x3, float y3,
|
|
|
|
float x4, float y4)
|
|
|
|
{
|
|
|
|
startNewSubPath (x1, y1);
|
|
|
|
lineTo (x2, y2);
|
|
|
|
@@ -538,7 +471,7 @@ void Path::addQuadrilateral (const float x1, const float y1, |
|
|
|
|
|
|
|
void Path::addEllipse (float x, float y, float w, float h)
|
|
|
|
{
|
|
|
|
addEllipse (Rectangle<float> (x, y, w, h));
|
|
|
|
addEllipse ({ x, y, w, h });
|
|
|
|
}
|
|
|
|
|
|
|
|
void Path::addEllipse (Rectangle<float> area)
|
|
|
|
@@ -558,11 +491,9 @@ void Path::addEllipse (Rectangle<float> area) |
|
|
|
closeSubPath();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Path::addArc (const float x, const float y,
|
|
|
|
const float w, const float h,
|
|
|
|
const float fromRadians,
|
|
|
|
const float toRadians,
|
|
|
|
const bool startAsNewSubPath)
|
|
|
|
void Path::addArc (float x, float y, float w, float h,
|
|
|
|
float fromRadians, float toRadians,
|
|
|
|
bool startAsNewSubPath)
|
|
|
|
{
|
|
|
|
auto radiusX = w / 2.0f;
|
|
|
|
auto radiusY = h / 2.0f;
|
|
|
|
@@ -575,16 +506,15 @@ void Path::addArc (const float x, const float y, |
|
|
|
startAsNewSubPath);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Path::addCentredArc (const float centreX, const float centreY,
|
|
|
|
const float radiusX, const float radiusY,
|
|
|
|
const float rotationOfEllipse,
|
|
|
|
const float fromRadians,
|
|
|
|
float toRadians,
|
|
|
|
const bool startAsNewSubPath)
|
|
|
|
void Path::addCentredArc (float centreX, float centreY,
|
|
|
|
float radiusX, float radiusY,
|
|
|
|
float rotationOfEllipse,
|
|
|
|
float fromRadians, float toRadians,
|
|
|
|
bool startAsNewSubPath)
|
|
|
|
{
|
|
|
|
if (radiusX > 0.0f && radiusY > 0.0f)
|
|
|
|
{
|
|
|
|
const Point<float> centre (centreX, centreY);
|
|
|
|
Point<float> centre (centreX, centreY);
|
|
|
|
auto rotation = AffineTransform::rotation (rotationOfEllipse, centreX, centreY);
|
|
|
|
auto angle = fromRadians;
|
|
|
|
|
|
|
|
@@ -618,15 +548,13 @@ void Path::addCentredArc (const float centreX, const float centreY, |
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Path::addPieSegment (const float x, const float y,
|
|
|
|
const float width, const float height,
|
|
|
|
const float fromRadians,
|
|
|
|
const float toRadians,
|
|
|
|
const float innerCircleProportionalSize)
|
|
|
|
void Path::addPieSegment (float x, float y, float width, float height,
|
|
|
|
float fromRadians, float toRadians,
|
|
|
|
float innerCircleProportionalSize)
|
|
|
|
{
|
|
|
|
float radiusX = width * 0.5f;
|
|
|
|
float radiusY = height * 0.5f;
|
|
|
|
const Point<float> centre (x + radiusX, y + radiusY);
|
|
|
|
auto radiusX = width * 0.5f;
|
|
|
|
auto radiusY = height * 0.5f;
|
|
|
|
Point<float> centre (x + radiusX, y + radiusY);
|
|
|
|
|
|
|
|
startNewSubPath (centre.getPointOnCircumference (radiusX, radiusY, fromRadians));
|
|
|
|
addArc (x, y, width, height, fromRadians, toRadians);
|
|
|
|
@@ -663,9 +591,8 @@ void Path::addPieSegment (const float x, const float y, |
|
|
|
}
|
|
|
|
|
|
|
|
void Path::addPieSegment (Rectangle<float> segmentBounds,
|
|
|
|
const float fromRadians,
|
|
|
|
const float toRadians,
|
|
|
|
const float innerCircleProportionalSize)
|
|
|
|
float fromRadians, float toRadians,
|
|
|
|
float innerCircleProportionalSize)
|
|
|
|
{
|
|
|
|
addPieSegment (segmentBounds.getX(),
|
|
|
|
segmentBounds.getY(),
|
|
|
|
@@ -760,8 +687,8 @@ void Path::addStar (Point<float> centre, int numberOfPoints, float innerRadius, |
|
|
|
void Path::addBubble (Rectangle<float> bodyArea,
|
|
|
|
Rectangle<float> maximumArea,
|
|
|
|
Point<float> arrowTip,
|
|
|
|
const float cornerSize,
|
|
|
|
const float arrowBaseWidth)
|
|
|
|
float cornerSize,
|
|
|
|
float arrowBaseWidth)
|
|
|
|
{
|
|
|
|
auto halfW = bodyArea.getWidth() / 2.0f;
|
|
|
|
auto halfH = bodyArea.getHeight() / 2.0f;
|
|
|
|
@@ -824,10 +751,9 @@ void Path::addBubble (Rectangle<float> bodyArea, |
|
|
|
|
|
|
|
void Path::addPath (const Path& other)
|
|
|
|
{
|
|
|
|
size_t i = 0;
|
|
|
|
const float* d = other.data.elements;
|
|
|
|
const auto* d = other.data.begin();
|
|
|
|
|
|
|
|
while (i < other.numElements)
|
|
|
|
for (int i = 0; i < other.data.size();)
|
|
|
|
{
|
|
|
|
auto type = d[i++];
|
|
|
|
|
|
|
|
@@ -866,10 +792,9 @@ void Path::addPath (const Path& other) |
|
|
|
void Path::addPath (const Path& other,
|
|
|
|
const AffineTransform& transformToApply)
|
|
|
|
{
|
|
|
|
size_t i = 0;
|
|
|
|
const float* d = other.data.elements;
|
|
|
|
const auto* d = other.data.begin();
|
|
|
|
|
|
|
|
while (i < other.numElements)
|
|
|
|
for (int i = 0; i < other.data.size();)
|
|
|
|
{
|
|
|
|
auto type = d[i++];
|
|
|
|
|
|
|
|
@@ -923,8 +848,8 @@ void Path::applyTransform (const AffineTransform& transform) noexcept |
|
|
|
{
|
|
|
|
bounds.reset();
|
|
|
|
bool firstPoint = true;
|
|
|
|
float* d = data.elements;
|
|
|
|
auto* end = d + numElements;
|
|
|
|
float* d = data.begin();
|
|
|
|
auto* end = data.end();
|
|
|
|
|
|
|
|
while (d < end)
|
|
|
|
{
|
|
|
|
@@ -977,9 +902,8 @@ AffineTransform Path::getTransformToScaleToFit (Rectangle<float> area, bool pres |
|
|
|
preserveProportions, justification);
|
|
|
|
}
|
|
|
|
|
|
|
|
AffineTransform Path::getTransformToScaleToFit (const float x, const float y,
|
|
|
|
const float w, const float h,
|
|
|
|
const bool preserveProportions,
|
|
|
|
AffineTransform Path::getTransformToScaleToFit (float x, float y, float w, float h,
|
|
|
|
bool preserveProportions,
|
|
|
|
Justification justification) const
|
|
|
|
{
|
|
|
|
auto boundsRect = getBounds();
|
|
|
|
@@ -1030,7 +954,7 @@ AffineTransform Path::getTransformToScaleToFit (const float x, const float y, |
|
|
|
}
|
|
|
|
|
|
|
|
//==============================================================================
|
|
|
|
bool Path::contains (const float x, const float y, const float tolerance) const
|
|
|
|
bool Path::contains (float x, float y, float tolerance) const
|
|
|
|
{
|
|
|
|
if (x <= bounds.pathXMin || x >= bounds.pathXMax
|
|
|
|
|| y <= bounds.pathYMin || y >= bounds.pathYMax)
|
|
|
|
@@ -1061,12 +985,12 @@ bool Path::contains (const float x, const float y, const float tolerance) const |
|
|
|
: ((negativeCrossings + positiveCrossings) & 1) != 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Path::contains (Point<float> point, const float tolerance) const
|
|
|
|
bool Path::contains (Point<float> point, float tolerance) const
|
|
|
|
{
|
|
|
|
return contains (point.x, point.y, tolerance);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Path::intersectsLine (Line<float> line, const float tolerance)
|
|
|
|
bool Path::intersectsLine (Line<float> line, float tolerance)
|
|
|
|
{
|
|
|
|
PathFlatteningIterator i (*this, AffineTransform(), tolerance);
|
|
|
|
Point<float> intersection;
|
|
|
|
@@ -1078,7 +1002,7 @@ bool Path::intersectsLine (Line<float> line, const float tolerance) |
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
Line<float> Path::getClippedLine (Line<float> line, const bool keepSectionOutsidePath) const
|
|
|
|
Line<float> Path::getClippedLine (Line<float> line, bool keepSectionOutsidePath) const
|
|
|
|
{
|
|
|
|
Line<float> result (line);
|
|
|
|
const bool startInside = contains (line.getStart());
|
|
|
|
@@ -1174,23 +1098,23 @@ Path Path::createPathWithRoundedCorners (const float cornerRadius) const |
|
|
|
return *this;
|
|
|
|
|
|
|
|
Path p;
|
|
|
|
size_t indexOfPathStart = 0, indexOfPathStartThis = 0;
|
|
|
|
size_t n = 0;
|
|
|
|
int n = 0, indexOfPathStart = 0, indexOfPathStartThis = 0;
|
|
|
|
auto* elements = data.begin();
|
|
|
|
bool lastWasLine = false, firstWasLine = false;
|
|
|
|
|
|
|
|
while (n < numElements)
|
|
|
|
while (n < data.size())
|
|
|
|
{
|
|
|
|
auto type = data.elements[n++];
|
|
|
|
auto type = elements[n++];
|
|
|
|
|
|
|
|
if (isMarker (type, moveMarker))
|
|
|
|
{
|
|
|
|
indexOfPathStart = p.numElements;
|
|
|
|
indexOfPathStart = p.data.size();
|
|
|
|
indexOfPathStartThis = n - 1;
|
|
|
|
auto x = data.elements[n++];
|
|
|
|
auto y = data.elements[n++];
|
|
|
|
auto x = elements[n++];
|
|
|
|
auto y = elements[n++];
|
|
|
|
p.startNewSubPath (x, y);
|
|
|
|
lastWasLine = false;
|
|
|
|
firstWasLine = (isMarker (data.elements[n], lineMarker));
|
|
|
|
firstWasLine = (isMarker (elements[n], lineMarker));
|
|
|
|
}
|
|
|
|
else if (isMarker (type, lineMarker) || isMarker (type, closeSubPathMarker))
|
|
|
|
{
|
|
|
|
@@ -1198,28 +1122,28 @@ Path Path::createPathWithRoundedCorners (const float cornerRadius) const |
|
|
|
|
|
|
|
if (isMarker (type, lineMarker))
|
|
|
|
{
|
|
|
|
endX = data.elements[n++];
|
|
|
|
endY = data.elements[n++];
|
|
|
|
endX = elements[n++];
|
|
|
|
endY = elements[n++];
|
|
|
|
|
|
|
|
if (n > 8)
|
|
|
|
{
|
|
|
|
startX = data.elements[n - 8];
|
|
|
|
startY = data.elements[n - 7];
|
|
|
|
joinX = data.elements[n - 5];
|
|
|
|
joinY = data.elements[n - 4];
|
|
|
|
startX = elements[n - 8];
|
|
|
|
startY = elements[n - 7];
|
|
|
|
joinX = elements[n - 5];
|
|
|
|
joinY = elements[n - 4];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
endX = data.elements[indexOfPathStartThis + 1];
|
|
|
|
endY = data.elements[indexOfPathStartThis + 2];
|
|
|
|
endX = elements[indexOfPathStartThis + 1];
|
|
|
|
endY = elements[indexOfPathStartThis + 2];
|
|
|
|
|
|
|
|
if (n > 6)
|
|
|
|
{
|
|
|
|
startX = data.elements[n - 6];
|
|
|
|
startY = data.elements[n - 5];
|
|
|
|
joinX = data.elements[n - 3];
|
|
|
|
joinY = data.elements[n - 2];
|
|
|
|
startX = elements[n - 6];
|
|
|
|
startY = elements[n - 5];
|
|
|
|
joinX = elements[n - 3];
|
|
|
|
joinY = elements[n - 2];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@@ -1231,8 +1155,8 @@ Path Path::createPathWithRoundedCorners (const float cornerRadius) const |
|
|
|
{
|
|
|
|
auto propNeeded = jmin (0.5, cornerRadius / len1);
|
|
|
|
|
|
|
|
p.data.elements[p.numElements - 2] = (float) (joinX - (joinX - startX) * propNeeded);
|
|
|
|
p.data.elements[p.numElements - 1] = (float) (joinY - (joinY - startY) * propNeeded);
|
|
|
|
*(p.data.end() - 2) = (float) (joinX - (joinX - startX) * propNeeded);
|
|
|
|
*(p.data.end() - 1) = (float) (joinY - (joinY - startY) * propNeeded);
|
|
|
|
}
|
|
|
|
|
|
|
|
auto len2 = PathHelpers::lengthOf (endX, endY, joinX, joinY);
|
|
|
|
@@ -1258,12 +1182,12 @@ Path Path::createPathWithRoundedCorners (const float cornerRadius) const |
|
|
|
{
|
|
|
|
if (firstWasLine)
|
|
|
|
{
|
|
|
|
startX = data.elements[n - 3];
|
|
|
|
startY = data.elements[n - 2];
|
|
|
|
startX = elements[n - 3];
|
|
|
|
startY = elements[n - 2];
|
|
|
|
joinX = endX;
|
|
|
|
joinY = endY;
|
|
|
|
endX = data.elements[indexOfPathStartThis + 4];
|
|
|
|
endY = data.elements[indexOfPathStartThis + 5];
|
|
|
|
endX = elements[indexOfPathStartThis + 4];
|
|
|
|
endY = elements[indexOfPathStartThis + 5];
|
|
|
|
|
|
|
|
auto len1 = PathHelpers::lengthOf (startX, startY, joinX, joinY);
|
|
|
|
|
|
|
|
@@ -1271,8 +1195,8 @@ Path Path::createPathWithRoundedCorners (const float cornerRadius) const |
|
|
|
{
|
|
|
|
auto propNeeded = jmin (0.5, cornerRadius / len1);
|
|
|
|
|
|
|
|
p.data.elements[p.numElements - 2] = (float) (joinX - (joinX - startX) * propNeeded);
|
|
|
|
p.data.elements[p.numElements - 1] = (float) (joinY - (joinY - startY) * propNeeded);
|
|
|
|
*(p.data.end() - 2) = (float) (joinX - (joinX - startX) * propNeeded);
|
|
|
|
*(p.data.end() - 1) = (float) (joinY - (joinY - startY) * propNeeded);
|
|
|
|
}
|
|
|
|
|
|
|
|
auto len2 = PathHelpers::lengthOf (endX, endY, joinX, joinY);
|
|
|
|
@@ -1286,8 +1210,8 @@ Path Path::createPathWithRoundedCorners (const float cornerRadius) const |
|
|
|
|
|
|
|
p.quadraticTo (joinX, joinY, endX, endY);
|
|
|
|
|
|
|
|
p.data.elements[indexOfPathStart + 1] = endX;
|
|
|
|
p.data.elements[indexOfPathStart + 2] = endY;
|
|
|
|
p.data.begin()[indexOfPathStart + 1] = endX;
|
|
|
|
p.data.begin()[indexOfPathStart + 2] = endY;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@@ -1297,21 +1221,21 @@ Path Path::createPathWithRoundedCorners (const float cornerRadius) const |
|
|
|
else if (isMarker (type, quadMarker))
|
|
|
|
{
|
|
|
|
lastWasLine = false;
|
|
|
|
auto x1 = data.elements[n++];
|
|
|
|
auto y1 = data.elements[n++];
|
|
|
|
auto x2 = data.elements[n++];
|
|
|
|
auto y2 = data.elements[n++];
|
|
|
|
auto x1 = elements[n++];
|
|
|
|
auto y1 = elements[n++];
|
|
|
|
auto x2 = elements[n++];
|
|
|
|
auto y2 = elements[n++];
|
|
|
|
p.quadraticTo (x1, y1, x2, y2);
|
|
|
|
}
|
|
|
|
else if (isMarker (type, cubicMarker))
|
|
|
|
{
|
|
|
|
lastWasLine = false;
|
|
|
|
auto x1 = data.elements[n++];
|
|
|
|
auto y1 = data.elements[n++];
|
|
|
|
auto x2 = data.elements[n++];
|
|
|
|
auto y2 = data.elements[n++];
|
|
|
|
auto x3 = data.elements[n++];
|
|
|
|
auto y3 = data.elements[n++];
|
|
|
|
auto x1 = elements[n++];
|
|
|
|
auto y1 = elements[n++];
|
|
|
|
auto x2 = elements[n++];
|
|
|
|
auto y2 = elements[n++];
|
|
|
|
auto x3 = elements[n++];
|
|
|
|
auto y3 = elements[n++];
|
|
|
|
p.cubicTo (x1, y1, x2, y2, x3, y3);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@@ -1396,39 +1320,39 @@ void Path::writePathToStream (OutputStream& dest) const |
|
|
|
{
|
|
|
|
dest.writeByte (useNonZeroWinding ? 'n' : 'z');
|
|
|
|
|
|
|
|
for (size_t i = 0; i < numElements;)
|
|
|
|
for (auto* i = data.begin(); i != data.end();)
|
|
|
|
{
|
|
|
|
auto type = data.elements[i++];
|
|
|
|
auto type = *i++;
|
|
|
|
|
|
|
|
if (isMarker (type, moveMarker))
|
|
|
|
{
|
|
|
|
dest.writeByte ('m');
|
|
|
|
dest.writeFloat (data.elements[i++]);
|
|
|
|
dest.writeFloat (data.elements[i++]);
|
|
|
|
dest.writeFloat (*i++);
|
|
|
|
dest.writeFloat (*i++);
|
|
|
|
}
|
|
|
|
else if (isMarker (type, lineMarker))
|
|
|
|
{
|
|
|
|
dest.writeByte ('l');
|
|
|
|
dest.writeFloat (data.elements[i++]);
|
|
|
|
dest.writeFloat (data.elements[i++]);
|
|
|
|
dest.writeFloat (*i++);
|
|
|
|
dest.writeFloat (*i++);
|
|
|
|
}
|
|
|
|
else if (isMarker (type, quadMarker))
|
|
|
|
{
|
|
|
|
dest.writeByte ('q');
|
|
|
|
dest.writeFloat (data.elements[i++]);
|
|
|
|
dest.writeFloat (data.elements[i++]);
|
|
|
|
dest.writeFloat (data.elements[i++]);
|
|
|
|
dest.writeFloat (data.elements[i++]);
|
|
|
|
dest.writeFloat (*i++);
|
|
|
|
dest.writeFloat (*i++);
|
|
|
|
dest.writeFloat (*i++);
|
|
|
|
dest.writeFloat (*i++);
|
|
|
|
}
|
|
|
|
else if (isMarker (type, cubicMarker))
|
|
|
|
{
|
|
|
|
dest.writeByte ('b');
|
|
|
|
dest.writeFloat (data.elements[i++]);
|
|
|
|
dest.writeFloat (data.elements[i++]);
|
|
|
|
dest.writeFloat (data.elements[i++]);
|
|
|
|
dest.writeFloat (data.elements[i++]);
|
|
|
|
dest.writeFloat (data.elements[i++]);
|
|
|
|
dest.writeFloat (data.elements[i++]);
|
|
|
|
dest.writeFloat (*i++);
|
|
|
|
dest.writeFloat (*i++);
|
|
|
|
dest.writeFloat (*i++);
|
|
|
|
dest.writeFloat (*i++);
|
|
|
|
dest.writeFloat (*i++);
|
|
|
|
dest.writeFloat (*i++);
|
|
|
|
}
|
|
|
|
else if (isMarker (type, closeSubPathMarker))
|
|
|
|
{
|
|
|
|
@@ -1445,12 +1369,11 @@ String Path::toString() const |
|
|
|
if (! useNonZeroWinding)
|
|
|
|
s << 'a';
|
|
|
|
|
|
|
|
size_t i = 0;
|
|
|
|
float lastMarker = 0.0f;
|
|
|
|
|
|
|
|
while (i < numElements)
|
|
|
|
for (int i = 0; i < data.size();)
|
|
|
|
{
|
|
|
|
auto type = data.elements[i++];
|
|
|
|
auto type = data.begin()[i++];
|
|
|
|
char markerChar = 0;
|
|
|
|
int numCoords = 0;
|
|
|
|
|
|
|
|
@@ -1489,9 +1412,9 @@ String Path::toString() const |
|
|
|
lastMarker = type;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (--numCoords >= 0 && i < numElements)
|
|
|
|
while (--numCoords >= 0 && i < data.size())
|
|
|
|
{
|
|
|
|
String coord (data.elements[i++], 3);
|
|
|
|
String coord (data.begin()[i++], 3);
|
|
|
|
|
|
|
|
while (coord.endsWithChar ('0') && coord != "0")
|
|
|
|
coord = coord.dropLastCharacters (1);
|
|
|
|
@@ -1576,7 +1499,7 @@ void Path::restoreFromString (StringRef stringVersion) |
|
|
|
|
|
|
|
//==============================================================================
|
|
|
|
Path::Iterator::Iterator (const Path& p) noexcept
|
|
|
|
: elementType (startNewSubPath), path (p)
|
|
|
|
: elementType (startNewSubPath), path (p), index (path.data.begin())
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
@@ -1586,41 +1509,39 @@ Path::Iterator::~Iterator() noexcept |
|
|
|
|
|
|
|
bool Path::Iterator::next() noexcept
|
|
|
|
{
|
|
|
|
const float* elements = path.data.elements;
|
|
|
|
|
|
|
|
if (index < path.numElements)
|
|
|
|
if (index != path.data.end())
|
|
|
|
{
|
|
|
|
auto type = elements[index++];
|
|
|
|
auto type = *index++;
|
|
|
|
|
|
|
|
if (isMarker (type, moveMarker))
|
|
|
|
{
|
|
|
|
elementType = startNewSubPath;
|
|
|
|
x1 = elements[index++];
|
|
|
|
y1 = elements[index++];
|
|
|
|
x1 = *index++;
|
|
|
|
y1 = *index++;
|
|
|
|
}
|
|
|
|
else if (isMarker (type, lineMarker))
|
|
|
|
{
|
|
|
|
elementType = lineTo;
|
|
|
|
x1 = elements[index++];
|
|
|
|
y1 = elements[index++];
|
|
|
|
x1 = *index++;
|
|
|
|
y1 = *index++;
|
|
|
|
}
|
|
|
|
else if (isMarker (type, quadMarker))
|
|
|
|
{
|
|
|
|
elementType = quadraticTo;
|
|
|
|
x1 = elements[index++];
|
|
|
|
y1 = elements[index++];
|
|
|
|
x2 = elements[index++];
|
|
|
|
y2 = elements[index++];
|
|
|
|
x1 = *index++;
|
|
|
|
y1 = *index++;
|
|
|
|
x2 = *index++;
|
|
|
|
y2 = *index++;
|
|
|
|
}
|
|
|
|
else if (isMarker (type, cubicMarker))
|
|
|
|
{
|
|
|
|
elementType = cubicTo;
|
|
|
|
x1 = elements[index++];
|
|
|
|
y1 = elements[index++];
|
|
|
|
x2 = elements[index++];
|
|
|
|
y2 = elements[index++];
|
|
|
|
x3 = elements[index++];
|
|
|
|
y3 = elements[index++];
|
|
|
|
x1 = *index++;
|
|
|
|
y1 = *index++;
|
|
|
|
x2 = *index++;
|
|
|
|
y2 = *index++;
|
|
|
|
x3 = *index++;
|
|
|
|
y3 = *index++;
|
|
|
|
}
|
|
|
|
else if (isMarker (type, closeSubPathMarker))
|
|
|
|
{
|
|
|
|
|