30#define JUCE_CHECK_COORDS_ARE_VALID(x, y) \
31 jassert (! std::isnan (x) && ! std::isnan (y));
36 const float ellipseAngularIncrement = 0.05f;
40 t.incrementToEndOfWhitespace();
45 while (! (t.isEmpty() || t.isWhitespace()))
51 return { start, numChars };
54 inline double lengthOf (
float x1,
float y1,
float x2,
float y2)
noexcept
56 return juce_hypot ((
double) (x1 - x2), (
double) (y1 - y2));
62const float Path::defaultToleranceForTesting = 1.0f;
63const float Path::defaultToleranceForMeasurement = 0.6f;
65static bool isMarker (
float value,
float marker)
noexcept
71Path::PathBounds::PathBounds() noexcept
75Rectangle<float> Path::PathBounds::getRectangle() const noexcept
77 return { pathXMin, pathYMin, pathXMax - pathXMin, pathYMax - pathYMin };
80void Path::PathBounds::reset() noexcept
82 pathXMin = pathYMin = pathYMax = pathXMax = 0;
85void Path::PathBounds::reset (
float x,
float y)
noexcept
87 pathXMin = pathXMax = x;
88 pathYMin = pathYMax = y;
91void Path::PathBounds::extend (
float x,
float y)
noexcept
93 if (x < pathXMin) pathXMin = x;
94 else if (x > pathXMax) pathXMax = x;
96 if (y < pathYMin) pathYMin = y;
97 else if (y > pathYMax) pathYMax = y;
111 bounds (other.bounds),
112 useNonZeroWinding (other.useNonZeroWinding)
121 bounds = other.bounds;
122 useNonZeroWinding = other.useNonZeroWinding;
129 : data (std::move (other.data)),
130 bounds (other.bounds),
131 useNonZeroWinding (other.useNonZeroWinding)
137 data = std::move (other.data);
138 bounds = other.bounds;
139 useNonZeroWinding = other.useNonZeroWinding;
143bool Path::operator== (
const Path& other)
const noexcept {
return useNonZeroWinding == other.useNonZeroWinding && data == other.data; }
144bool Path::operator!= (
const Path& other)
const noexcept {
return ! operator== (other); }
154 data.swapWith (other.data);
155 std::swap (bounds.pathXMin, other.bounds.pathXMin);
156 std::swap (bounds.pathXMax, other.bounds.pathXMax);
157 std::swap (bounds.pathYMin, other.bounds.pathYMin);
158 std::swap (bounds.pathYMax, other.bounds.pathYMax);
159 std::swap (useNonZeroWinding, other.useNonZeroWinding);
165 useNonZeroWinding = isNonZero;
168void Path::scaleToFit (
float x,
float y,
float w,
float h,
bool preserveProportions)
noexcept
170 applyTransform (getTransformToScaleToFit (x, y, w, h, preserveProportions));
176 for (
auto i = data.
begin(), e = data.
end(); i != e; ++i)
180 if (isMarker (type, moveMarker))
184 else if (isMarker (type, lineMarker)
185 || isMarker (type, quadMarker)
186 || isMarker (type, cubicMarker))
197 return bounds.getRectangle();
213 JUCE_CHECK_COORDS_ARE_VALID (x, y)
218 bounds.extend (x, y);
220 data.
add (moveMarker, x, y);
230 JUCE_CHECK_COORDS_ARE_VALID (x, y)
235 data.
add (lineMarker, x, y);
236 bounds.extend (x, y);
245 const float x2,
const float y2)
247 JUCE_CHECK_COORDS_ARE_VALID (x1,
y1)
248 JUCE_CHECK_COORDS_ARE_VALID (x2, y2)
253 data.
add (quadMarker, x1,
y1, x2, y2);
254 bounds.extend (x1,
y1, x2, y2);
260 endPoint.
x, endPoint.
y);
264 const float x2,
const float y2,
265 const float x3,
const float y3)
267 JUCE_CHECK_COORDS_ARE_VALID (x1,
y1)
268 JUCE_CHECK_COORDS_ARE_VALID (x2, y2)
269 JUCE_CHECK_COORDS_ARE_VALID (x3, y3)
274 data.
add (cubicMarker, x1,
y1, x2, y2, x3, y3);
275 bounds.extend (x1,
y1, x2, y2, x3, y3);
282 cubicTo (controlPoint1.
x, controlPoint1.
y,
283 controlPoint2.
x, controlPoint2.
y,
284 endPoint.
x, endPoint.
y);
289 if (! (data.
isEmpty() || isMarker (data.
getLast(), closeSubPathMarker)))
290 data.
add (closeSubPathMarker);
298 auto* i = data.
end() - 1;
300 if (isMarker (*i, closeSubPathMarker))
302 while (i != data.
begin())
304 if (isMarker (*--i, moveMarker))
312 if (i != data.
begin())
313 return { *(i - 1), *i };
320 auto x1 = x,
y1 = y, x2 = x + w, y2 = y + h;
327 bounds.pathXMin = x1;
328 bounds.pathXMax = x2;
329 bounds.pathYMin =
y1;
330 bounds.pathYMax = y2;
334 bounds.pathXMin =
jmin (bounds.pathXMin, x1);
335 bounds.pathXMax =
jmax (bounds.pathXMax, x2);
336 bounds.pathYMin =
jmin (bounds.pathYMin,
y1);
337 bounds.pathYMax =
jmax (bounds.pathYMax, y2);
340 data.
add (moveMarker, x1, y2,
353 float csx,
float csy,
354 const bool curveTopLeft,
const bool curveTopRight,
355 const bool curveBottomLeft,
const bool curveBottomRight)
357 csx =
jmin (csx, w * 0.5f);
358 csy =
jmin (csy, h * 0.5f);
359 auto cs45x = csx * 0.45f;
360 auto cs45y = csy * 0.45f;
367 cubicTo (x, y + cs45y, x + cs45x, y, x + csx, y);
377 cubicTo (x2 - cs45x, y, x2, y + cs45y, x2, y + csy);
384 if (curveBottomRight)
387 cubicTo (x2, y2 - cs45y, x2 - cs45x, y2, x2 - csx, y2);
397 cubicTo (x + cs45x, y2, x, y2 - cs45y, x, y2 - csy);
449 auto hw55 = hw * 0.55f;
451 auto hh55 = hh * 0.55f;
452 auto cx = area.
getX() + hw;
453 auto cy = area.
getY() + hh;
456 cubicTo (cx + hw55, cy - hh, cx + hw, cy - hh55, cx + hw, cy);
457 cubicTo (cx + hw, cy + hh55, cx + hw55, cy + hh, cx, cy + hh);
458 cubicTo (cx - hw55, cy + hh, cx - hw, cy + hh55, cx - hw, cy);
459 cubicTo (cx - hw, cy - hh55, cx - hw55, cy - hh, cx, cy - hh);
464 float fromRadians,
float toRadians,
465 bool startAsNewSubPath)
467 auto radiusX = w / 2.0f;
468 auto radiusY = h / 2.0f;
474 fromRadians, toRadians,
479 float radiusX,
float radiusY,
480 float rotationOfEllipse,
481 float fromRadians,
float toRadians,
482 bool startAsNewSubPath)
484 if (radiusX > 0.0f && radiusY > 0.0f)
488 auto angle = fromRadians;
490 if (startAsNewSubPath)
493 if (fromRadians < toRadians)
495 if (startAsNewSubPath)
496 angle += PathHelpers::ellipseAngularIncrement;
498 while (angle < toRadians)
501 angle += PathHelpers::ellipseAngularIncrement;
506 if (startAsNewSubPath)
507 angle -= PathHelpers::ellipseAngularIncrement;
509 while (angle > toRadians)
512 angle -= PathHelpers::ellipseAngularIncrement;
521 float fromRadians,
float toRadians,
522 float innerCircleProportionalSize)
524 auto radiusX = width * 0.5f;
525 auto radiusY = height * 0.5f;
529 addArc (x, y, width, height, fromRadians, toRadians);
535 if (innerCircleProportionalSize > 0)
537 radiusX *= innerCircleProportionalSize;
538 radiusY *= innerCircleProportionalSize;
541 addArc (centre.
x - radiusX, centre.
y - radiusY, radiusX * 2.0f, radiusY * 2.0f, toRadians, fromRadians);
546 if (innerCircleProportionalSize > 0)
548 radiusX *= innerCircleProportionalSize;
549 radiusY *= innerCircleProportionalSize;
551 addArc (centre.
x - radiusX, centre.
y - radiusY, radiusX * 2.0f, radiusY * 2.0f, toRadians, fromRadians);
563 float fromRadians,
float toRadians,
564 float innerCircleProportionalSize)
567 segmentBounds.
getY(),
572 innerCircleProportionalSize);
579 lineThickness *= 0.5f;
583 lineTo (reversed.getPointAlongLine (0, lineThickness));
584 lineTo (reversed.getPointAlongLine (0, -lineThickness));
589 float arrowheadWidth,
float arrowheadLength)
592 lineThickness *= 0.5f;
593 arrowheadWidth *= 0.5f;
594 arrowheadLength =
jmin (arrowheadLength, 0.8f * line.
getLength());
598 lineTo (reversed.getPointAlongLine (arrowheadLength, lineThickness));
599 lineTo (reversed.getPointAlongLine (arrowheadLength, arrowheadWidth));
601 lineTo (reversed.getPointAlongLine (arrowheadLength, -arrowheadWidth));
602 lineTo (reversed.getPointAlongLine (arrowheadLength, -lineThickness));
607 float radius,
float startAngle)
611 if (numberOfSides > 1)
615 for (
int i = 0; i < numberOfSides; ++i)
617 auto angle = startAngle + (
float) i * angleBetweenPoints;
631 float outerRadius,
float startAngle)
635 if (numberOfPoints > 1)
639 for (
int i = 0; i < numberOfPoints; ++i)
641 auto angle = startAngle + (
float) i * angleBetweenPoints;
660 float arrowBaseWidth)
662 auto halfW = bodyArea.
getWidth() / 2.0f;
663 auto halfH = bodyArea.
getHeight() / 2.0f;
664 auto cornerSizeW =
jmin (cornerSize, halfW);
665 auto cornerSizeH =
jmin (cornerSize, halfH);
666 auto cornerSizeW2 = 2.0f * cornerSizeW;
667 auto cornerSizeH2 = 2.0f * cornerSizeH;
671 auto targetLimit = bodyArea.
reduced (
jmin (halfW - 1.0f, cornerSizeW + arrowBaseWidth),
672 jmin (halfH - 1.0f, cornerSizeH + arrowBaseWidth));
675 targetLimit.getWidth(), bodyArea.
getY() - maximumArea.
getY()).
contains (arrowTip))
677 lineTo (arrowTip.
x - arrowBaseWidth, bodyArea.
getY());
679 lineTo (arrowTip.
x + arrowBaseWidth, bodyArea.
getY());
708 bodyArea.
getX() - maximumArea.
getX(), targetLimit.getHeight()).
contains (arrowTip))
710 lineTo (bodyArea.
getX(), arrowTip.
y + arrowBaseWidth);
712 lineTo (bodyArea.
getX(), arrowTip.
y - arrowBaseWidth);
723 const auto* d = other.data.
begin();
724 const auto size = other.data.
size();
726 for (
int i = 0; i < size;)
728 const auto type = d[i++];
730 if (isMarker (type, moveMarker))
735 else if (isMarker (type, lineMarker))
740 else if (isMarker (type, quadMarker))
745 else if (isMarker (type, cubicMarker))
747 cubicTo (d[i], d[i + 1], d[i + 2], d[i + 3], d[i + 4], d[i + 5]);
750 else if (isMarker (type, closeSubPathMarker))
765 const auto* d = other.data.
begin();
766 const auto size = other.data.
size();
768 for (
int i = 0; i < size;)
770 const auto type = d[i++];
772 if (isMarker (type, closeSubPathMarker))
782 if (isMarker (type, moveMarker))
786 else if (isMarker (type, lineMarker))
790 else if (isMarker (type, quadMarker))
798 else if (isMarker (type, cubicMarker))
806 cubicTo (x, y, x2, y2, x3, y3);
821 bool firstPoint =
true;
822 float* d = data.begin();
823 auto*
end = data.end();
829 if (isMarker (type, moveMarker))
831 transform.transformPoint (d[0], d[1]);
832 JUCE_CHECK_COORDS_ARE_VALID (d[0], d[1])
837 bounds.reset (d[0], d[1]);
841 bounds.extend (d[0], d[1]);
846 else if (isMarker (type, lineMarker))
848 transform.transformPoint (d[0], d[1]);
849 JUCE_CHECK_COORDS_ARE_VALID (d[0], d[1])
850 bounds.extend (d[0], d[1]);
853 else if (isMarker (type, quadMarker))
855 transform.transformPoints (d[0], d[1], d[2], d[3]);
856 JUCE_CHECK_COORDS_ARE_VALID (d[0], d[1])
857 JUCE_CHECK_COORDS_ARE_VALID (d[2], d[3])
858 bounds.extend (d[0], d[1], d[2], d[3]);
861 else if (isMarker (type, cubicMarker))
863 transform.transformPoints (d[0], d[1], d[2], d[3], d[4], d[5]);
864 JUCE_CHECK_COORDS_ARE_VALID (d[0], d[1])
865 JUCE_CHECK_COORDS_ARE_VALID (d[2], d[3])
866 JUCE_CHECK_COORDS_ARE_VALID (d[4], d[5])
867 bounds.extend (d[0], d[1], d[2], d[3], d[4], d[5]);
879 preserveProportions, justification);
883 bool preserveProportions,
888 if (preserveProportions)
890 if (w <= 0 || h <= 0 || boundsRect.isEmpty())
894 auto srcRatio = boundsRect.getHeight() / boundsRect.getWidth();
896 if (srcRatio > h / w)
912 else newXCentre += w * 0.5f;
916 else newYCentre += h * 0.5f;
919 boundsRect.getHeight() * -0.5f - boundsRect.getY())
920 .
scaled (newW / boundsRect.getWidth(),
921 newH / boundsRect.getHeight())
927 .
scaled (w / boundsRect.getWidth(),
928 h / boundsRect.getHeight())
936 if (x <= bounds.pathXMin || x >= bounds.pathXMax
937 || y <= bounds.pathYMin || y >= bounds.pathYMax)
942 int positiveCrossings = 0;
943 int negativeCrossings = 0;
947 if ((i.
y1 <= y && i.
y2 > y) || (i.
y2 <= y && i.
y1 > y))
949 auto intersectX = i.
x1 + (i.
x2 - i.
x1) * (y - i.
y1) / (i.
y2 - i.
y1);
961 return useNonZeroWinding ? (negativeCrossings != positiveCrossings)
962 : ((negativeCrossings + positiveCrossings) & 1) != 0;
967 return contains (point.
x, point.
y, tolerance);
988 if (startInside == endInside)
990 if (keepSectionOutsidePath == startInside)
1000 if (line.
intersects ({ i.x1, i.y1, i.x2, i.y2 }, intersection))
1002 if ((startInside && keepSectionOutsidePath) || (endInside && ! keepSectionOutsidePath))
1005 result.
setEnd (intersection);
1026 float tolerance)
const
1035 if (distanceFromStart <= lineLength)
1038 distanceFromStart -= lineLength;
1041 return { i.
x2, i.
y2 };
1046 float tolerance)
const
1058 if (distance < bestDistance)
1060 bestDistance = distance;
1062 pointOnPath = pointOnLine;
1068 return bestPosition;
1074 if (cornerRadius <= 0.01f)
1078 int n = 0, indexOfPathStart = 0, indexOfPathStartThis = 0;
1079 auto* elements = data.
begin();
1080 bool lastWasLine =
false, firstWasLine =
false;
1082 while (n < data.
size())
1084 auto type = elements[n++];
1086 if (isMarker (type, moveMarker))
1088 indexOfPathStart = p.data.
size();
1089 indexOfPathStartThis = n - 1;
1090 auto x = elements[n++];
1091 auto y = elements[n++];
1093 lastWasLine =
false;
1094 firstWasLine = (isMarker (elements[n], lineMarker));
1096 else if (isMarker (type, lineMarker) || isMarker (type, closeSubPathMarker))
1098 float startX = 0, startY = 0, joinX = 0, joinY = 0, endX, endY;
1100 if (isMarker (type, lineMarker))
1102 endX = elements[n++];
1103 endY = elements[n++];
1107 startX = elements[n - 8];
1108 startY = elements[n - 7];
1109 joinX = elements[n - 5];
1110 joinY = elements[n - 4];
1115 endX = elements[indexOfPathStartThis + 1];
1116 endY = elements[indexOfPathStartThis + 2];
1120 startX = elements[n - 6];
1121 startY = elements[n - 5];
1122 joinX = elements[n - 3];
1123 joinY = elements[n - 2];
1129 auto len1 = PathHelpers::lengthOf (startX, startY, joinX, joinY);
1133 auto propNeeded =
jmin (0.5, cornerRadius / len1);
1135 *(p.data.
end() - 2) = (
float) (joinX - (joinX - startX) * propNeeded);
1136 *(p.data.
end() - 1) = (
float) (joinY - (joinY - startY) * propNeeded);
1139 auto len2 = PathHelpers::lengthOf (endX, endY, joinX, joinY);
1143 auto propNeeded =
jmin (0.5, cornerRadius / len2);
1146 (
float) (joinX + (endX - joinX) * propNeeded),
1147 (
float) (joinY + (endY - joinY) * propNeeded));
1152 else if (isMarker (type, lineMarker))
1158 if (isMarker (type, closeSubPathMarker))
1162 startX = elements[n - 3];
1163 startY = elements[n - 2];
1166 endX = elements[indexOfPathStartThis + 4];
1167 endY = elements[indexOfPathStartThis + 5];
1169 auto len1 = PathHelpers::lengthOf (startX, startY, joinX, joinY);
1173 auto propNeeded =
jmin (0.5, cornerRadius / len1);
1175 *(p.data.
end() - 2) = (
float) (joinX - (joinX - startX) * propNeeded);
1176 *(p.data.
end() - 1) = (
float) (joinY - (joinY - startY) * propNeeded);
1179 auto len2 = PathHelpers::lengthOf (endX, endY, joinX, joinY);
1183 auto propNeeded =
jmin (0.5, cornerRadius / len2);
1185 endX = (
float) (joinX + (endX - joinX) * propNeeded);
1186 endY = (
float) (joinY + (endY - joinY) * propNeeded);
1190 p.data.
begin()[indexOfPathStart + 1] = endX;
1191 p.data.
begin()[indexOfPathStart + 2] = endY;
1198 else if (isMarker (type, quadMarker))
1200 lastWasLine =
false;
1201 auto x1 = elements[n++];
1202 auto y1 = elements[n++];
1203 auto x2 = elements[n++];
1204 auto y2 = elements[n++];
1207 else if (isMarker (type, cubicMarker))
1209 lastWasLine =
false;
1210 auto x1 = elements[n++];
1211 auto y1 = elements[n++];
1212 auto x2 = elements[n++];
1213 auto y2 = elements[n++];
1214 auto x3 = elements[n++];
1215 auto y3 = elements[n++];
1273 useNonZeroWinding =
true;
1277 useNonZeroWinding =
false;
1298 dest.
writeByte (useNonZeroWinding ?
'n' :
'z');
1300 for (
auto* i = data.
begin(); i != data.
end();)
1304 if (isMarker (type, moveMarker))
1310 else if (isMarker (type, lineMarker))
1316 else if (isMarker (type, quadMarker))
1324 else if (isMarker (type, cubicMarker))
1334 else if (isMarker (type, closeSubPathMarker))
1346 if (! useNonZeroWinding)
1349 float lastMarker = 0.0f;
1351 for (
int i = 0; i < data.
size();)
1353 auto type = data.
begin()[i++];
1354 char markerChar = 0;
1357 if (isMarker (type, moveMarker))
1362 else if (isMarker (type, lineMarker))
1367 else if (isMarker (type, quadMarker))
1372 else if (isMarker (type, cubicMarker))
1379 jassert (isMarker (type, closeSubPathMarker));
1383 if (! isMarker (type, lastMarker))
1392 while (--numCoords >= 0 && i < data.
size())
1417 auto t = stringVersion.
text;
1424 auto token = PathHelpers::nextToken (t);
1425 auto firstChar = token[0];
1431 if (firstChar ==
'm' || firstChar ==
'l')
1436 else if (firstChar ==
'q')
1441 else if (firstChar ==
'c')
1446 else if (firstChar ==
'z')
1451 else if (firstChar ==
'a')
1459 values [0] = token.getFloatValue();
1462 for (
int i = startNum; i < numValues; ++i)
1463 values [i] = PathHelpers::nextToken (t).getFloatValue();
1468 case 'l':
lineTo (values[0], values[1]);
break;
1469 case 'q':
quadraticTo (values[0], values[1], values[2], values[3]);
break;
1470 case 'c':
cubicTo (values[0], values[1], values[2], values[3], values[4], values[5]);
break;
1478Path::Iterator::Iterator (
const Path& p) noexcept
1479 : elementType (startNewSubPath), path (p), index (path.data.begin())
1483Path::Iterator::~Iterator() noexcept
1489 if (index != path.data.end())
1491 auto type = *index++;
1493 if (isMarker (type, moveMarker))
1499 else if (isMarker (type, lineMarker))
1505 else if (isMarker (type, quadMarker))
1513 else if (isMarker (type, cubicMarker))
1523 else if (isMarker (type, closeSubPathMarker))
1525 elementType = closePath;
1534#undef JUCE_CHECK_COORDS_ARE_VALID
bool isEmpty() const noexcept
Returns true if the array is empty, false otherwise.
void ensureStorageAllocated(int minNumElements)
Increases the array's internal storage to hold a minimum number of elements.
void clearQuick()
Removes all elements from the array without freeing the array's allocated storage.
int size() const noexcept
Returns the current number of elements in the array.
ElementType * begin() noexcept
Returns a pointer to the first element in the array.
ElementType * end() noexcept
Returns a pointer to the element which follows the last element in the array.
void add(const ElementType &newElement)
Appends a new element at the end of the array.
ElementType getLast() const noexcept
Returns the last element in the array, or a default value if the array is empty.
Represents a type of justification to be used when positioning graphical items.
@ left
Indicates that the item should be aligned against the left edge of the available space.
@ bottom
Indicates that the item should be aligned against the bottom edge of the available space.
@ top
Indicates that the item should be aligned against the top edge of the available space.
@ right
Indicates that the item should be aligned against the right edge of the available space.
bool testFlags(int flagsToTest) const noexcept
Tests a set of flags for this object.
Line reversed() const noexcept
Returns a line that is the same as this one, but with the start and end reversed,.
void setStart(ValueType newStartX, ValueType newStartY) noexcept
Changes this line's start point.
Point< ValueType > getPointAlongLine(ValueType distanceFromStart) const noexcept
Returns the location of the point which is a given distance along this line.
ValueType getLength() const noexcept
Returns the length of the line.
ValueType getDistanceFromPoint(Point< ValueType > targetPoint, Point< ValueType > &pointOnLine) const noexcept
Returns the smallest distance between this line segment and a given point.
void setEnd(ValueType newEndX, ValueType newEndY) noexcept
Changes this line's end point.
Point< ValueType > getEnd() const noexcept
Returns the line's end point.
bool intersects(Line line, Point< ValueType > &intersection) const noexcept
Finds the intersection between two lines.
Point< ValueType > getStart() const noexcept
Returns the line's start point.
Writes data to an internal memory buffer, which grows as required.
String toUTF8() const
Returns a String created from the (UTF8) data that has been written to the stream.
size_t getDataSize() const noexcept
Returns the number of bytes of data that have been written to the stream.
The base class for streams that write data to some kind of destination.
virtual bool writeFloat(float value)
Writes a 32-bit floating point value to the stream in a binary format.
virtual bool writeByte(char byte)
Writes a single byte to the stream.
Flattens a Path object into a series of straight-line sections.
bool next()
Fetches the next line segment from the path.
float y2
The y position of the end of the current line segment.
float x2
The x position of the end of the current line segment.
float y1
The y position of the start of the current line segment.
float x1
The x position of the start of the current line segment.
bool next() noexcept
Moves onto the next element in the path.
A path is a sequence of lines and curves that may either form a closed shape or be open-ended.
float getNearestPoint(Point< float > targetPoint, Point< float > &pointOnPath, const AffineTransform &transform=AffineTransform(), float tolerance=defaultToleranceForMeasurement) const
Finds the point along the path which is nearest to a given position.
float getLength(const AffineTransform &transform=AffineTransform(), float tolerance=defaultToleranceForMeasurement) const
Returns the length of the path.
bool contains(float x, float y, float tolerance=defaultToleranceForTesting) const
Checks whether a point lies within the path.
void loadPathFromData(const void *data, size_t numberOfBytes)
Loads a stored path from a block of data.
void addRoundedRectangle(float x, float y, float width, float height, float cornerSize)
Adds a rectangle with rounded corners to the path.
void startNewSubPath(float startX, float startY)
Begins a new subpath with a given starting position.
void addPieSegment(float x, float y, float width, float height, float fromRadians, float toRadians, float innerCircleProportionalSize)
Adds a "pie-chart" shape to the path.
void addTriangle(float x1, float y1, float x2, float y2, float x3, float y3)
Adds a triangle to the path.
void addEllipse(float x, float y, float width, float height)
Adds an ellipse to the path.
void preallocateSpace(int numExtraCoordsToMakeSpaceFor)
Preallocates enough space for adding the given number of coordinates to the path.
Point< float > getCurrentPosition() const
Returns the last point that was added to the path by one of the drawing methods.
Path()
Creates an empty path.
void addPath(const Path &pathToAppend)
Adds another path to this one.
void quadraticTo(float controlPointX, float controlPointY, float endPointX, float endPointY)
Adds a quadratic bezier curve from the shape's last position to a new position.
AffineTransform getTransformToScaleToFit(float x, float y, float width, float height, bool preserveProportions, Justification justificationType=Justification::centred) const
Returns a transform that can be used to rescale the path to fit into a given space.
void cubicTo(float controlPoint1X, float controlPoint1Y, float controlPoint2X, float controlPoint2Y, float endPointX, float endPointY)
Adds a cubic bezier curve from the shape's last position to a new position.
Path & operator=(const Path &)
Copies this path from another one.
Rectangle< float > getBoundsTransformed(const AffineTransform &transform) const noexcept
Returns the smallest rectangle that contains all points within the path after it's been transformed w...
bool intersectsLine(Line< float > line, float tolerance=defaultToleranceForTesting) const
Checks whether a line crosses the path.
void addRectangle(float x, float y, float width, float height)
Adds a rectangle to the path.
void scaleToFit(float x, float y, float width, float height, bool preserveProportions) noexcept
Rescales this path to make it fit neatly into a given space.
void addBubble(Rectangle< float > bodyArea, Rectangle< float > maximumArea, Point< float > arrowTipPosition, float cornerSize, float arrowBaseWidth)
Adds a speech-bubble shape to the path.
void clear() noexcept
Removes all lines and curves, resetting the path completely.
void applyTransform(const AffineTransform &transform) noexcept
Applies a 2D transform to all the vertices in the path.
void addCentredArc(float centreX, float centreY, float radiusX, float radiusY, float rotationOfEllipse, float fromRadians, float toRadians, bool startAsNewSubPath=false)
Adds an arc which is centred at a given point, and can have a rotation specified.
void restoreFromString(StringRef stringVersion)
Restores this path from a string that was created with the toString() method.
void closeSubPath()
Closes a the current sub-path with a line back to its start-point.
void writePathToStream(OutputStream &destination) const
Stores the path by writing it out to a stream.
Line< float > getClippedLine(Line< float > line, bool keepSectionOutsidePath) const
Cuts off parts of a line to keep the parts that are either inside or outside this path.
Rectangle< float > getBounds() const noexcept
Returns the smallest rectangle that contains all points within the path.
String toString() const
Creates a string containing a textual representation of this path.
Point< float > getPointAlongPath(float distanceFromStart, const AffineTransform &transform=AffineTransform(), float tolerance=defaultToleranceForMeasurement) const
Returns a point that is the specified distance along the path.
void lineTo(float endX, float endY)
Adds a line from the shape's last position to a new end-point.
Path createPathWithRoundedCorners(float cornerRadius) const
Creates a version of this path where all sharp corners have been replaced by curves.
void addArc(float x, float y, float width, float height, float fromRadians, float toRadians, bool startAsNewSubPath=false)
Adds an elliptical arc to the current path.
void addLineSegment(Line< float > line, float lineThickness)
Adds a line with a specified thickness.
void addStar(Point< float > centre, int numberOfPoints, float innerRadius, float outerRadius, float startAngle=0.0f)
Adds a star shape to the path.
void swapWithPath(Path &) noexcept
Swaps the contents of this path with another one.
void loadPathFromStream(InputStream &source)
Loads a stored path from a data stream.
void addArrow(Line< float > line, float lineThickness, float arrowheadWidth, float arrowheadLength)
Adds a line with an arrowhead on the end.
void setUsingNonZeroWinding(bool isNonZeroWinding) noexcept
Changes the winding-rule to be used when filling the path.
bool isEmpty() const noexcept
Returns true if the path doesn't contain any lines or curves.
void addQuadrilateral(float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4)
Adds a quadrilateral to the path.
void addPolygon(Point< float > centre, int numberOfSides, float radius, float startAngle=0.0f)
Adds a polygon shape to the path.
A pair of (x, y) coordinates.
ValueType getDistanceFrom(Point other) const noexcept
Returns the straight-line distance between this point and another one.
ValueType y
The point's Y coordinate.
ValueType x
The point's X coordinate.
Point< FloatType > getPointOnCircumference(float radius, float angle) const noexcept
Taking this point to be the centre of a circle, this returns a point on its circumference.
Manages a rectangle and allows geometric operations to be performed on it.
ValueType getRight() const noexcept
Returns the x coordinate of the rectangle's right-hand-side.
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 getBottom() const noexcept
Returns the y coordinate of the rectangle's bottom edge.
ValueType getWidth() const noexcept
Returns the width of the rectangle.
Rectangle reduced(ValueType deltaX, ValueType deltaY) const noexcept
Returns a rectangle that is smaller than this one by a given amount.
ValueType getY() const noexcept
Returns the y coordinate of the rectangle's top edge.
Rectangle transformedBy(const AffineTransform &transform) const noexcept
Returns the smallest rectangle that can contain the shape created by applying a transform to this rec...
ValueType getHeight() const noexcept
Returns the height of the rectangle.
A simple class for holding temporary references to a string literal or String.
String::CharPointerType text
The text that is referenced.
bool endsWithChar(juce_wchar character) const noexcept
Tests whether the string ends with a particular character.
String dropLastCharacters(int numberToDrop) const
Returns a version of this string with a number of characters removed from the end.
CharPointer_UTF8 CharPointerType
This is the character encoding type used internally to store the string.
wchar_t juce_wchar
A platform-independent 32-bit unicode character type.
constexpr Type jmin(Type a, Type b)
Returns the smaller of two values.
constexpr bool exactlyEqual(Type a, Type b)
Equivalent to operator==, but suppresses float-equality warnings.
constexpr Type jmax(Type a, Type b)
Returns the larger of two values.
RangedDirectoryIterator end(const RangedDirectoryIterator &)
Returns a default-constructed sentinel value.
Type juce_hypot(Type a, Type b) noexcept
Using juce_hypot is easier than dealing with the different types of hypot function that are provided ...
Commonly used mathematical constants.