Browse Source

Simplified the Path class by making it use an Array for starage.

tags/2021-05-28
jules 7 years ago
parent
commit
5e9267e5d8
5 changed files with 179 additions and 259 deletions
  1. +1
    -1
      modules/juce_graphics/geometry/juce_EdgeTable.cpp
  2. +153
    -232
      modules/juce_graphics/geometry/juce_Path.cpp
  3. +2
    -3
      modules/juce_graphics/geometry/juce_Path.h
  4. +21
    -21
      modules/juce_graphics/geometry/juce_PathIterator.cpp
  5. +2
    -2
      modules/juce_graphics/geometry/juce_PathIterator.h

+ 1
- 1
modules/juce_graphics/geometry/juce_EdgeTable.cpp View File

@@ -36,7 +36,7 @@ EdgeTable::EdgeTable (Rectangle<int> area, const Path& path, const AffineTransfo
// for a given path, such that it's big enough to mostly avoid remapping, but also // for a given path, such that it's big enough to mostly avoid remapping, but also
// not so big that it's wasteful for simple paths. // not so big that it's wasteful for simple paths.
maxEdgesPerLine (jmax (juce_edgeTableDefaultEdgesPerLine / 2, maxEdgesPerLine (jmax (juce_edgeTableDefaultEdgesPerLine / 2,
4 * (int) std::sqrt (path.numElements))),
4 * (int) std::sqrt (path.data.size()))),
lineStrideElements (maxEdgesPerLine * 2 + 1) lineStrideElements (maxEdgesPerLine * 2 + 1)
{ {
allocate(); allocate();


+ 153
- 232
modules/juce_graphics/geometry/juce_Path.cpp View File

@@ -137,37 +137,26 @@ Path::~Path()
} }
Path::Path (const Path& other) Path::Path (const Path& other)
: numElements (other.numElements),
: data (other.data),
bounds (other.bounds), bounds (other.bounds),
useNonZeroWinding (other.useNonZeroWinding) 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) Path& Path::operator= (const Path& other)
{ {
if (this != &other) if (this != &other)
{ {
data.ensureAllocatedSize ((int) other.numElements);
numElements = other.numElements;
data = other.data;
bounds = other.bounds; bounds = other.bounds;
useNonZeroWinding = other.useNonZeroWinding; useNonZeroWinding = other.useNonZeroWinding;
if (numElements > 0)
memcpy (data.elements, other.data.elements, numElements * sizeof (float));
} }
return *this; return *this;
} }
Path::Path (Path&& other) noexcept 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), bounds (other.bounds),
useNonZeroWinding (other.useNonZeroWinding) useNonZeroWinding (other.useNonZeroWinding)
{ {
@@ -175,40 +164,24 @@ Path::Path (Path&& other) noexcept
Path& Path::operator= (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; bounds = other.bounds;
useNonZeroWinding = other.useNonZeroWinding; useNonZeroWinding = other.useNonZeroWinding;
return *this; 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 void Path::clear() noexcept
{ {
numElements = 0;
data.clearQuick();
bounds.reset(); bounds.reset();
} }
void Path::swapWithPath (Path& other) noexcept void Path::swapWithPath (Path& other) noexcept
{ {
data.swapWith (other.data); data.swapWith (other.data);
std::swap (numElements, other.numElements);
std::swap (bounds.pathXMin, other.bounds.pathXMin); std::swap (bounds.pathXMin, other.bounds.pathXMin);
std::swap (bounds.pathXMax, other.bounds.pathXMax); std::swap (bounds.pathXMax, other.bounds.pathXMax);
std::swap (bounds.pathYMin, other.bounds.pathYMin); 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 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)) if (isMarker (type, moveMarker))
{ {
@@ -264,23 +235,19 @@ Rectangle<float> Path::getBoundsTransformed (const AffineTransform& transform) c
//============================================================================== //==============================================================================
void Path::preallocateSpace (int numExtraCoordsToMakeSpaceFor) void Path::preallocateSpace (int numExtraCoordsToMakeSpaceFor)
{ {
data.ensureAllocatedSize ((int) numElements + numExtraCoordsToMakeSpaceFor);
data.ensureStorageAllocated (data.size() + numExtraCoordsToMakeSpaceFor);
} }
void Path::startNewSubPath (const float x, const float y) void Path::startNewSubPath (const float x, const float y)
{ {
JUCE_CHECK_COORDS_ARE_VALID (x, y); JUCE_CHECK_COORDS_ARE_VALID (x, y);
if (numElements == 0)
if (data.isEmpty())
bounds.reset (x, y); bounds.reset (x, y);
else else
bounds.extend (x, y); 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) 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); JUCE_CHECK_COORDS_ARE_VALID (x, y);
if (numElements == 0)
if (data.isEmpty())
startNewSubPath (0, 0); 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); 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 (x1, y1);
JUCE_CHECK_COORDS_ARE_VALID (x2, y2); JUCE_CHECK_COORDS_ARE_VALID (x2, y2);
if (numElements == 0)
if (data.isEmpty())
startNewSubPath (0, 0); 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); 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 (x2, y2);
JUCE_CHECK_COORDS_ARE_VALID (x3, y3); JUCE_CHECK_COORDS_ARE_VALID (x3, y3);
if (numElements == 0)
if (data.isEmpty())
startNewSubPath (0, 0); 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 (x1, y1, x2, y2);
bounds.extend (x3, y3); bounds.extend (x3, y3);
} }
@@ -371,48 +317,43 @@ void Path::cubicTo (Point<float> controlPoint1,
void Path::closeSubPath() 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 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; i += 2;
break; break;
} }
--i;
} }
} }
if (i > 0)
return { data.elements[i - 1], data.elements[i] };
if (i != data.begin())
return { *(i - 1), *i };
return {}; 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 (w < 0) std::swap (x1, x2);
if (h < 0) std::swap (y1, y2); if (h < 0) std::swap (y1, y2);
preallocateSpace (13);
if (numElements == 0)
if (data.isEmpty())
{ {
bounds.pathXMin = x1; bounds.pathXMin = x1;
bounds.pathXMax = x2; bounds.pathXMax = x2;
@@ -427,19 +368,11 @@ void Path::addRectangle (const float x, const float y,
bounds.pathYMax = jmax (bounds.pathYMax, y2); 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) 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 x2, float y2,
float x3, float y3) 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) 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(); 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); startNewSubPath (x1, y1);
lineTo (x2, y2); 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) 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) void Path::addEllipse (Rectangle<float> area)
@@ -558,11 +491,9 @@ void Path::addEllipse (Rectangle<float> area)
closeSubPath(); 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 radiusX = w / 2.0f;
auto radiusY = h / 2.0f; auto radiusY = h / 2.0f;
@@ -575,16 +506,15 @@ void Path::addArc (const float x, const float y,
startAsNewSubPath); 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) 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 rotation = AffineTransform::rotation (rotationOfEllipse, centreX, centreY);
auto angle = fromRadians; 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)); startNewSubPath (centre.getPointOnCircumference (radiusX, radiusY, fromRadians));
addArc (x, y, width, height, fromRadians, toRadians); 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, void Path::addPieSegment (Rectangle<float> segmentBounds,
const float fromRadians,
const float toRadians,
const float innerCircleProportionalSize)
float fromRadians, float toRadians,
float innerCircleProportionalSize)
{ {
addPieSegment (segmentBounds.getX(), addPieSegment (segmentBounds.getX(),
segmentBounds.getY(), segmentBounds.getY(),
@@ -760,8 +687,8 @@ void Path::addStar (Point<float> centre, int numberOfPoints, float innerRadius,
void Path::addBubble (Rectangle<float> bodyArea, void Path::addBubble (Rectangle<float> bodyArea,
Rectangle<float> maximumArea, Rectangle<float> maximumArea,
Point<float> arrowTip, Point<float> arrowTip,
const float cornerSize,
const float arrowBaseWidth)
float cornerSize,
float arrowBaseWidth)
{ {
auto halfW = bodyArea.getWidth() / 2.0f; auto halfW = bodyArea.getWidth() / 2.0f;
auto halfH = bodyArea.getHeight() / 2.0f; auto halfH = bodyArea.getHeight() / 2.0f;
@@ -824,10 +751,9 @@ void Path::addBubble (Rectangle<float> bodyArea,
void Path::addPath (const Path& other) 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++]; auto type = d[i++];
@@ -866,10 +792,9 @@ void Path::addPath (const Path& other)
void Path::addPath (const Path& other, void Path::addPath (const Path& other,
const AffineTransform& transformToApply) 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++]; auto type = d[i++];
@@ -923,8 +848,8 @@ void Path::applyTransform (const AffineTransform& transform) noexcept
{ {
bounds.reset(); bounds.reset();
bool firstPoint = true; bool firstPoint = true;
float* d = data.elements;
auto* end = d + numElements;
float* d = data.begin();
auto* end = data.end();
while (d < end) while (d < end)
{ {
@@ -977,9 +902,8 @@ AffineTransform Path::getTransformToScaleToFit (Rectangle<float> area, bool pres
preserveProportions, justification); 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 Justification justification) const
{ {
auto boundsRect = getBounds(); 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 if (x <= bounds.pathXMin || x >= bounds.pathXMax
|| y <= bounds.pathYMin || y >= bounds.pathYMax) || 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; : ((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); 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); PathFlatteningIterator i (*this, AffineTransform(), tolerance);
Point<float> intersection; Point<float> intersection;
@@ -1078,7 +1002,7 @@ bool Path::intersectsLine (Line<float> line, const float tolerance)
return false; 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); Line<float> result (line);
const bool startInside = contains (line.getStart()); const bool startInside = contains (line.getStart());
@@ -1174,23 +1098,23 @@ Path Path::createPathWithRoundedCorners (const float cornerRadius) const
return *this; return *this;
Path p; 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; 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)) if (isMarker (type, moveMarker))
{ {
indexOfPathStart = p.numElements;
indexOfPathStart = p.data.size();
indexOfPathStartThis = n - 1; 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); p.startNewSubPath (x, y);
lastWasLine = false; lastWasLine = false;
firstWasLine = (isMarker (data.elements[n], lineMarker));
firstWasLine = (isMarker (elements[n], lineMarker));
} }
else if (isMarker (type, lineMarker) || isMarker (type, closeSubPathMarker)) else if (isMarker (type, lineMarker) || isMarker (type, closeSubPathMarker))
{ {
@@ -1198,28 +1122,28 @@ Path Path::createPathWithRoundedCorners (const float cornerRadius) const
if (isMarker (type, lineMarker)) if (isMarker (type, lineMarker))
{ {
endX = data.elements[n++];
endY = data.elements[n++];
endX = elements[n++];
endY = elements[n++];
if (n > 8) 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 else
{ {
endX = data.elements[indexOfPathStartThis + 1];
endY = data.elements[indexOfPathStartThis + 2];
endX = elements[indexOfPathStartThis + 1];
endY = elements[indexOfPathStartThis + 2];
if (n > 6) 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); 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); auto len2 = PathHelpers::lengthOf (endX, endY, joinX, joinY);
@@ -1258,12 +1182,12 @@ Path Path::createPathWithRoundedCorners (const float cornerRadius) const
{ {
if (firstWasLine) if (firstWasLine)
{ {
startX = data.elements[n - 3];
startY = data.elements[n - 2];
startX = elements[n - 3];
startY = elements[n - 2];
joinX = endX; joinX = endX;
joinY = endY; 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); 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); 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); 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.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)) else if (isMarker (type, quadMarker))
{ {
lastWasLine = false; 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); p.quadraticTo (x1, y1, x2, y2);
} }
else if (isMarker (type, cubicMarker)) else if (isMarker (type, cubicMarker))
{ {
lastWasLine = false; 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); p.cubicTo (x1, y1, x2, y2, x3, y3);
} }
} }
@@ -1396,39 +1320,39 @@ void Path::writePathToStream (OutputStream& dest) const
{ {
dest.writeByte (useNonZeroWinding ? 'n' : 'z'); 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)) if (isMarker (type, moveMarker))
{ {
dest.writeByte ('m'); dest.writeByte ('m');
dest.writeFloat (data.elements[i++]);
dest.writeFloat (data.elements[i++]);
dest.writeFloat (*i++);
dest.writeFloat (*i++);
} }
else if (isMarker (type, lineMarker)) else if (isMarker (type, lineMarker))
{ {
dest.writeByte ('l'); dest.writeByte ('l');
dest.writeFloat (data.elements[i++]);
dest.writeFloat (data.elements[i++]);
dest.writeFloat (*i++);
dest.writeFloat (*i++);
} }
else if (isMarker (type, quadMarker)) else if (isMarker (type, quadMarker))
{ {
dest.writeByte ('q'); 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)) else if (isMarker (type, cubicMarker))
{ {
dest.writeByte ('b'); 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)) else if (isMarker (type, closeSubPathMarker))
{ {
@@ -1445,12 +1369,11 @@ String Path::toString() const
if (! useNonZeroWinding) if (! useNonZeroWinding)
s << 'a'; s << 'a';
size_t i = 0;
float lastMarker = 0.0f; 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; char markerChar = 0;
int numCoords = 0; int numCoords = 0;
@@ -1489,9 +1412,9 @@ String Path::toString() const
lastMarker = type; 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") while (coord.endsWithChar ('0') && coord != "0")
coord = coord.dropLastCharacters (1); coord = coord.dropLastCharacters (1);
@@ -1576,7 +1499,7 @@ void Path::restoreFromString (StringRef stringVersion)
//============================================================================== //==============================================================================
Path::Iterator::Iterator (const Path& p) noexcept 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 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)) if (isMarker (type, moveMarker))
{ {
elementType = startNewSubPath; elementType = startNewSubPath;
x1 = elements[index++];
y1 = elements[index++];
x1 = *index++;
y1 = *index++;
} }
else if (isMarker (type, lineMarker)) else if (isMarker (type, lineMarker))
{ {
elementType = lineTo; elementType = lineTo;
x1 = elements[index++];
y1 = elements[index++];
x1 = *index++;
y1 = *index++;
} }
else if (isMarker (type, quadMarker)) else if (isMarker (type, quadMarker))
{ {
elementType = quadraticTo; 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)) else if (isMarker (type, cubicMarker))
{ {
elementType = cubicTo; 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)) else if (isMarker (type, closeSubPathMarker))
{ {


+ 2
- 3
modules/juce_graphics/geometry/juce_Path.h View File

@@ -753,7 +753,7 @@ public:
//============================================================================== //==============================================================================
private: private:
const Path& path; const Path& path;
size_t index = 0;
const float* index;
JUCE_DECLARE_NON_COPYABLE (Iterator) JUCE_DECLARE_NON_COPYABLE (Iterator)
}; };
@@ -803,8 +803,7 @@ private:
friend class Path::Iterator; friend class Path::Iterator;
friend class EdgeTable; friend class EdgeTable;
ArrayAllocationBase<float, DummyCriticalSection> data;
size_t numElements = 0;
Array<float> data;
struct PathBounds struct PathBounds
{ {


+ 21
- 21
modules/juce_graphics/geometry/juce_PathIterator.cpp View File

@@ -32,18 +32,18 @@ namespace juce
#endif #endif
//============================================================================== //==============================================================================
PathFlatteningIterator::PathFlatteningIterator (const Path& path_,
const AffineTransform& transform_,
const float tolerance)
PathFlatteningIterator::PathFlatteningIterator (const Path& pathToUse,
const AffineTransform& t,
float tolerance)
: x2 (0), : x2 (0),
y2 (0), y2 (0),
closesSubPath (false), closesSubPath (false),
subPathIndex (-1), subPathIndex (-1),
path (path_),
transform (transform_),
points (path_.data.elements),
path (pathToUse),
transform (t),
source (path.data.begin()),
toleranceSquared (tolerance * tolerance), toleranceSquared (tolerance * tolerance),
isIdentityTransform (transform_.isIdentity())
isIdentityTransform (t.isIdentity())
{ {
stackPos = stackBase; stackPos = stackBase;
} }
@@ -55,7 +55,7 @@ PathFlatteningIterator::~PathFlatteningIterator()
bool PathFlatteningIterator::isLastInSubpath() const noexcept bool PathFlatteningIterator::isLastInSubpath() const noexcept
{ {
return stackPos == stackBase.get() return stackPos == stackBase.get()
&& (index >= path.numElements || isMarker (points[index], Path::moveMarker));
&& (source == path.data.end() || isMarker (*source, Path::moveMarker));
} }
bool PathFlatteningIterator::next() bool PathFlatteningIterator::next()
@@ -74,30 +74,30 @@ bool PathFlatteningIterator::next()
if (stackPos == stackBase) if (stackPos == stackBase)
{ {
if (index >= path.numElements)
if (source == path.data.end())
return false; return false;
type = points [index++];
type = *source++;
if (! isMarker (type, Path::closeSubPathMarker)) if (! isMarker (type, Path::closeSubPathMarker))
{ {
x2 = points [index++];
y2 = points [index++];
x2 = *source++;
y2 = *source++;
if (isMarker (type, Path::quadMarker)) if (isMarker (type, Path::quadMarker))
{ {
x3 = points [index++];
y3 = points [index++];
x3 = *source++;
y3 = *source++;
if (! isIdentityTransform) if (! isIdentityTransform)
transform.transformPoints (x2, y2, x3, y3); transform.transformPoints (x2, y2, x3, y3);
} }
else if (isMarker (type, Path::cubicMarker)) else if (isMarker (type, Path::cubicMarker))
{ {
x3 = points [index++];
y3 = points [index++];
x4 = points [index++];
y4 = points [index++];
x3 = *source++;
y3 = *source++;
x4 = *source++;
y4 = *source++;
if (! isIdentityTransform) if (! isIdentityTransform)
transform.transformPoints (x2, y2, x3, y3, x4, y4); transform.transformPoints (x2, y2, x3, y3, x4, y4);
@@ -137,9 +137,9 @@ bool PathFlatteningIterator::next()
{ {
++subPathIndex; ++subPathIndex;
closesSubPath = (stackPos == stackBase)
&& (index < path.numElements)
&& (points [index] == Path::closeSubPathMarker)
closesSubPath = stackPos == stackBase
&& source != path.data.end()
&& *source == Path::closeSubPathMarker
&& x2 == subPathCloseX && x2 == subPathCloseX
&& y2 == subPathCloseY; && y2 == subPathCloseY;


+ 2
- 2
modules/juce_graphics/geometry/juce_PathIterator.h View File

@@ -95,14 +95,14 @@ private:
//============================================================================== //==============================================================================
const Path& path; const Path& path;
const AffineTransform transform; const AffineTransform transform;
float* points;
const float* source;
const float toleranceSquared; const float toleranceSquared;
float subPathCloseX = 0, subPathCloseY = 0; float subPathCloseX = 0, subPathCloseY = 0;
const bool isIdentityTransform; const bool isIdentityTransform;
HeapBlock<float> stackBase { 32 }; HeapBlock<float> stackBase { 32 };
float* stackPos; float* stackPos;
size_t index = 0, stackSize = 32;
size_t stackSize = 32;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PathFlatteningIterator) JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PathFlatteningIterator)
}; };


Loading…
Cancel
Save