Audio plugin host https://kx.studio/carla
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

juce_Path.h 37KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839
  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2020 - Raw Material Software Limited
  5. JUCE is an open source library subject to commercial or open-source
  6. licensing.
  7. By using JUCE, you agree to the terms of both the JUCE 6 End-User License
  8. Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
  9. End User License Agreement: www.juce.com/juce-6-licence
  10. Privacy Policy: www.juce.com/juce-privacy-policy
  11. Or: You may also use this code under the terms of the GPL v3 (see
  12. www.gnu.org/licenses).
  13. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  14. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  15. DISCLAIMED.
  16. ==============================================================================
  17. */
  18. namespace juce
  19. {
  20. //==============================================================================
  21. /**
  22. A path is a sequence of lines and curves that may either form a closed shape
  23. or be open-ended.
  24. To use a path, you can create an empty one, then add lines and curves to it
  25. to create shapes, then it can be rendered by a Graphics context or used
  26. for geometric operations.
  27. e.g. @code
  28. Path myPath;
  29. myPath.startNewSubPath (10.0f, 10.0f); // move the current position to (10, 10)
  30. myPath.lineTo (100.0f, 200.0f); // draw a line from here to (100, 200)
  31. myPath.quadraticTo (0.0f, 150.0f, 5.0f, 50.0f); // draw a curve that ends at (5, 50)
  32. myPath.closeSubPath(); // close the subpath with a line back to (10, 10)
  33. // add an ellipse as well, which will form a second sub-path within the path..
  34. myPath.addEllipse (50.0f, 50.0f, 40.0f, 30.0f);
  35. // double the width of the whole thing..
  36. myPath.applyTransform (AffineTransform::scale (2.0f, 1.0f));
  37. // and draw it to a graphics context with a 5-pixel thick outline.
  38. g.strokePath (myPath, PathStrokeType (5.0f));
  39. @endcode
  40. A path object can actually contain multiple sub-paths, which may themselves
  41. be open or closed.
  42. @see PathFlatteningIterator, PathStrokeType, Graphics
  43. @tags{Graphics}
  44. */
  45. class JUCE_API Path final
  46. {
  47. public:
  48. //==============================================================================
  49. /** Creates an empty path. */
  50. Path();
  51. /** Creates a copy of another path. */
  52. Path (const Path&);
  53. /** Destructor. */
  54. ~Path();
  55. /** Copies this path from another one. */
  56. Path& operator= (const Path&);
  57. /** Move constructor */
  58. Path (Path&&) noexcept;
  59. /** Move assignment operator */
  60. Path& operator= (Path&&) noexcept;
  61. bool operator== (const Path&) const noexcept;
  62. bool operator!= (const Path&) const noexcept;
  63. static const float defaultToleranceForTesting;
  64. static const float defaultToleranceForMeasurement;
  65. //==============================================================================
  66. /** Returns true if the path doesn't contain any lines or curves. */
  67. bool isEmpty() const noexcept;
  68. /** Returns the smallest rectangle that contains all points within the path. */
  69. Rectangle<float> getBounds() const noexcept;
  70. /** Returns the smallest rectangle that contains all points within the path
  71. after it's been transformed with the given transform matrix.
  72. */
  73. Rectangle<float> getBoundsTransformed (const AffineTransform& transform) const noexcept;
  74. /** Checks whether a point lies within the path.
  75. This is only relevant for closed paths (see closeSubPath()), and
  76. may produce false results if used on a path which has open sub-paths.
  77. The path's winding rule is taken into account by this method.
  78. The tolerance parameter is the maximum error allowed when flattening the path,
  79. so this method could return a false positive when your point is up to this distance
  80. outside the path's boundary.
  81. @see closeSubPath, setUsingNonZeroWinding
  82. */
  83. bool contains (float x, float y,
  84. float tolerance = defaultToleranceForTesting) const;
  85. /** Checks whether a point lies within the path.
  86. This is only relevant for closed paths (see closeSubPath()), and
  87. may produce false results if used on a path which has open sub-paths.
  88. The path's winding rule is taken into account by this method.
  89. The tolerance parameter is the maximum error allowed when flattening the path,
  90. so this method could return a false positive when your point is up to this distance
  91. outside the path's boundary.
  92. @see closeSubPath, setUsingNonZeroWinding
  93. */
  94. bool contains (Point<float> point,
  95. float tolerance = defaultToleranceForTesting) const;
  96. /** Checks whether a line crosses the path.
  97. This will return positive if the line crosses any of the paths constituent
  98. lines or curves. It doesn't take into account whether the line is inside
  99. or outside the path, or whether the path is open or closed.
  100. The tolerance parameter is the maximum error allowed when flattening the path,
  101. so this method could return a false positive when your point is up to this distance
  102. outside the path's boundary.
  103. */
  104. bool intersectsLine (Line<float> line,
  105. float tolerance = defaultToleranceForTesting);
  106. /** Cuts off parts of a line to keep the parts that are either inside or
  107. outside this path.
  108. Note that this isn't smart enough to cope with situations where the
  109. line would need to be cut into multiple pieces to correctly clip against
  110. a re-entrant shape.
  111. @param line the line to clip
  112. @param keepSectionOutsidePath if true, it's the section outside the path
  113. that will be kept; if false its the section inside
  114. the path
  115. */
  116. Line<float> getClippedLine (Line<float> line, bool keepSectionOutsidePath) const;
  117. /** Returns the length of the path.
  118. @see getPointAlongPath
  119. */
  120. float getLength (const AffineTransform& transform = AffineTransform(),
  121. float tolerance = defaultToleranceForMeasurement) const;
  122. /** Returns a point that is the specified distance along the path.
  123. If the distance is greater than the total length of the path, this will return the
  124. end point.
  125. @see getLength
  126. */
  127. Point<float> getPointAlongPath (float distanceFromStart,
  128. const AffineTransform& transform = AffineTransform(),
  129. float tolerance = defaultToleranceForMeasurement) const;
  130. /** Finds the point along the path which is nearest to a given position.
  131. This sets pointOnPath to the nearest point, and returns the distance of this point from the start
  132. of the path.
  133. */
  134. float getNearestPoint (Point<float> targetPoint,
  135. Point<float>& pointOnPath,
  136. const AffineTransform& transform = AffineTransform(),
  137. float tolerance = defaultToleranceForMeasurement) const;
  138. //==============================================================================
  139. /** Removes all lines and curves, resetting the path completely. */
  140. void clear() noexcept;
  141. /** Begins a new subpath with a given starting position.
  142. This will move the path's current position to the coordinates passed in and
  143. make it ready to draw lines or curves starting from this position.
  144. After adding whatever lines and curves are needed, you can either
  145. close the current sub-path using closeSubPath() or call startNewSubPath()
  146. to move to a new sub-path, leaving the old one open-ended.
  147. @see lineTo, quadraticTo, cubicTo, closeSubPath
  148. */
  149. void startNewSubPath (float startX, float startY);
  150. /** Begins a new subpath with a given starting position.
  151. This will move the path's current position to the coordinates passed in and
  152. make it ready to draw lines or curves starting from this position.
  153. After adding whatever lines and curves are needed, you can either
  154. close the current sub-path using closeSubPath() or call startNewSubPath()
  155. to move to a new sub-path, leaving the old one open-ended.
  156. @see lineTo, quadraticTo, cubicTo, closeSubPath
  157. */
  158. void startNewSubPath (Point<float> start);
  159. /** Closes a the current sub-path with a line back to its start-point.
  160. When creating a closed shape such as a triangle, don't use 3 lineTo()
  161. calls - instead use two lineTo() calls, followed by a closeSubPath()
  162. to join the final point back to the start.
  163. This ensures that closes shapes are recognised as such, and this is
  164. important for tasks like drawing strokes, which needs to know whether to
  165. draw end-caps or not.
  166. @see startNewSubPath, lineTo, quadraticTo, cubicTo, closeSubPath
  167. */
  168. void closeSubPath();
  169. /** Adds a line from the shape's last position to a new end-point.
  170. This will connect the end-point of the last line or curve that was added
  171. to a new point, using a straight line.
  172. See the class description for an example of how to add lines and curves to a path.
  173. @see startNewSubPath, quadraticTo, cubicTo, closeSubPath
  174. */
  175. void lineTo (float endX, float endY);
  176. /** Adds a line from the shape's last position to a new end-point.
  177. This will connect the end-point of the last line or curve that was added
  178. to a new point, using a straight line.
  179. See the class description for an example of how to add lines and curves to a path.
  180. @see startNewSubPath, quadraticTo, cubicTo, closeSubPath
  181. */
  182. void lineTo (Point<float> end);
  183. /** Adds a quadratic bezier curve from the shape's last position to a new position.
  184. This will connect the end-point of the last line or curve that was added
  185. to a new point, using a quadratic spline with one control-point.
  186. See the class description for an example of how to add lines and curves to a path.
  187. @see startNewSubPath, lineTo, cubicTo, closeSubPath
  188. */
  189. void quadraticTo (float controlPointX,
  190. float controlPointY,
  191. float endPointX,
  192. float endPointY);
  193. /** Adds a quadratic bezier curve from the shape's last position to a new position.
  194. This will connect the end-point of the last line or curve that was added
  195. to a new point, using a quadratic spline with one control-point.
  196. See the class description for an example of how to add lines and curves to a path.
  197. @see startNewSubPath, lineTo, cubicTo, closeSubPath
  198. */
  199. void quadraticTo (Point<float> controlPoint,
  200. Point<float> endPoint);
  201. /** Adds a cubic bezier curve from the shape's last position to a new position.
  202. This will connect the end-point of the last line or curve that was added
  203. to a new point, using a cubic spline with two control-points.
  204. See the class description for an example of how to add lines and curves to a path.
  205. @see startNewSubPath, lineTo, quadraticTo, closeSubPath
  206. */
  207. void cubicTo (float controlPoint1X,
  208. float controlPoint1Y,
  209. float controlPoint2X,
  210. float controlPoint2Y,
  211. float endPointX,
  212. float endPointY);
  213. /** Adds a cubic bezier curve from the shape's last position to a new position.
  214. This will connect the end-point of the last line or curve that was added
  215. to a new point, using a cubic spline with two control-points.
  216. See the class description for an example of how to add lines and curves to a path.
  217. @see startNewSubPath, lineTo, quadraticTo, closeSubPath
  218. */
  219. void cubicTo (Point<float> controlPoint1,
  220. Point<float> controlPoint2,
  221. Point<float> endPoint);
  222. /** Returns the last point that was added to the path by one of the drawing methods.
  223. */
  224. Point<float> getCurrentPosition() const;
  225. //==============================================================================
  226. /** Adds a rectangle to the path.
  227. The rectangle is added as a new sub-path. (Any currently open paths will be left open).
  228. @see addRoundedRectangle, addTriangle
  229. */
  230. void addRectangle (float x, float y, float width, float height);
  231. /** Adds a rectangle to the path.
  232. The rectangle is added as a new sub-path. (Any currently open paths will be left open).
  233. @see addRoundedRectangle, addTriangle
  234. */
  235. template <typename ValueType>
  236. void addRectangle (Rectangle<ValueType> rectangle)
  237. {
  238. addRectangle (static_cast<float> (rectangle.getX()), static_cast<float> (rectangle.getY()),
  239. static_cast<float> (rectangle.getWidth()), static_cast<float> (rectangle.getHeight()));
  240. }
  241. /** Adds a rectangle with rounded corners to the path.
  242. The rectangle is added as a new sub-path. (Any currently open paths will be left open).
  243. @see addRectangle, addTriangle
  244. */
  245. void addRoundedRectangle (float x, float y, float width, float height,
  246. float cornerSize);
  247. /** Adds a rectangle with rounded corners to the path.
  248. The rectangle is added as a new sub-path. (Any currently open paths will be left open).
  249. @see addRectangle, addTriangle
  250. */
  251. void addRoundedRectangle (float x, float y, float width, float height,
  252. float cornerSizeX,
  253. float cornerSizeY);
  254. /** Adds a rectangle with rounded corners to the path.
  255. The rectangle is added as a new sub-path. (Any currently open paths will be left open).
  256. @see addRectangle, addTriangle
  257. */
  258. void addRoundedRectangle (float x, float y, float width, float height,
  259. float cornerSizeX, float cornerSizeY,
  260. bool curveTopLeft, bool curveTopRight,
  261. bool curveBottomLeft, bool curveBottomRight);
  262. /** Adds a rectangle with rounded corners to the path.
  263. The rectangle is added as a new sub-path. (Any currently open paths will be left open).
  264. @see addRectangle, addTriangle
  265. */
  266. template <typename ValueType>
  267. void addRoundedRectangle (Rectangle<ValueType> rectangle, float cornerSizeX, float cornerSizeY)
  268. {
  269. addRoundedRectangle (static_cast<float> (rectangle.getX()), static_cast<float> (rectangle.getY()),
  270. static_cast<float> (rectangle.getWidth()), static_cast<float> (rectangle.getHeight()),
  271. cornerSizeX, cornerSizeY);
  272. }
  273. /** Adds a rectangle with rounded corners to the path.
  274. The rectangle is added as a new sub-path. (Any currently open paths will be left open).
  275. @see addRectangle, addTriangle
  276. */
  277. template <typename ValueType>
  278. void addRoundedRectangle (Rectangle<ValueType> rectangle, float cornerSize)
  279. {
  280. addRoundedRectangle (rectangle, cornerSize, cornerSize);
  281. }
  282. /** Adds a triangle to the path.
  283. The triangle is added as a new closed sub-path. (Any currently open paths will be left open).
  284. Note that whether the vertices are specified in clockwise or anticlockwise
  285. order will affect how the triangle is filled when it overlaps other
  286. shapes (the winding order setting will affect this of course).
  287. */
  288. void addTriangle (float x1, float y1,
  289. float x2, float y2,
  290. float x3, float y3);
  291. /** Adds a triangle to the path.
  292. The triangle is added as a new closed sub-path. (Any currently open paths will be left open).
  293. Note that whether the vertices are specified in clockwise or anticlockwise
  294. order will affect how the triangle is filled when it overlaps other
  295. shapes (the winding order setting will affect this of course).
  296. */
  297. void addTriangle (Point<float> point1,
  298. Point<float> point2,
  299. Point<float> point3);
  300. /** Adds a quadrilateral to the path.
  301. The quad is added as a new closed sub-path. (Any currently open paths will be left open).
  302. Note that whether the vertices are specified in clockwise or anticlockwise
  303. order will affect how the quad is filled when it overlaps other
  304. shapes (the winding order setting will affect this of course).
  305. */
  306. void addQuadrilateral (float x1, float y1,
  307. float x2, float y2,
  308. float x3, float y3,
  309. float x4, float y4);
  310. /** Adds an ellipse to the path.
  311. The shape is added as a new sub-path. (Any currently open paths will be left open).
  312. @see addArc
  313. */
  314. void addEllipse (float x, float y, float width, float height);
  315. /** Adds an ellipse to the path.
  316. The shape is added as a new sub-path. (Any currently open paths will be left open).
  317. @see addArc
  318. */
  319. void addEllipse (Rectangle<float> area);
  320. /** Adds an elliptical arc to the current path.
  321. Note that when specifying the start and end angles, the curve will be drawn either clockwise
  322. or anti-clockwise according to whether the end angle is greater than the start. This means
  323. that sometimes you may need to use values greater than 2*Pi for the end angle.
  324. @param x the left-hand edge of the rectangle in which the elliptical outline fits
  325. @param y the top edge of the rectangle in which the elliptical outline fits
  326. @param width the width of the rectangle in which the elliptical outline fits
  327. @param height the height of the rectangle in which the elliptical outline fits
  328. @param fromRadians the angle (clockwise) in radians at which to start the arc segment (where 0 is the
  329. top-centre of the ellipse)
  330. @param toRadians the angle (clockwise) in radians at which to end the arc segment (where 0 is the
  331. top-centre of the ellipse). This angle can be greater than 2*Pi, so for example to
  332. draw a curve clockwise from the 9 o'clock position to the 3 o'clock position via
  333. 12 o'clock, you'd use 1.5*Pi and 2.5*Pi as the start and finish points.
  334. @param startAsNewSubPath if true, the arc will begin a new subpath from its starting point; if false,
  335. it will be added to the current sub-path, continuing from the current position
  336. @see addCentredArc, arcTo, addPieSegment, addEllipse
  337. */
  338. void addArc (float x, float y, float width, float height,
  339. float fromRadians,
  340. float toRadians,
  341. bool startAsNewSubPath = false);
  342. /** Adds an arc which is centred at a given point, and can have a rotation specified.
  343. Note that when specifying the start and end angles, the curve will be drawn either clockwise
  344. or anti-clockwise according to whether the end angle is greater than the start. This means
  345. that sometimes you may need to use values greater than 2*Pi for the end angle.
  346. @param centreX the centre x of the ellipse
  347. @param centreY the centre y of the ellipse
  348. @param radiusX the horizontal radius of the ellipse
  349. @param radiusY the vertical radius of the ellipse
  350. @param rotationOfEllipse an angle by which the whole ellipse should be rotated about its centre, in radians (clockwise)
  351. @param fromRadians the angle (clockwise) in radians at which to start the arc segment (where 0 is the
  352. top-centre of the ellipse)
  353. @param toRadians the angle (clockwise) in radians at which to end the arc segment (where 0 is the
  354. top-centre of the ellipse). This angle can be greater than 2*Pi, so for example to
  355. draw a curve clockwise from the 9 o'clock position to the 3 o'clock position via
  356. 12 o'clock, you'd use 1.5*Pi and 2.5*Pi as the start and finish points.
  357. @param startAsNewSubPath if true, the arc will begin a new subpath from its starting point; if false,
  358. it will be added to the current sub-path, continuing from the current position
  359. @see addArc, arcTo
  360. */
  361. void addCentredArc (float centreX, float centreY,
  362. float radiusX, float radiusY,
  363. float rotationOfEllipse,
  364. float fromRadians,
  365. float toRadians,
  366. bool startAsNewSubPath = false);
  367. /** Adds a "pie-chart" shape to the path.
  368. The shape is added as a new sub-path. (Any currently open paths will be
  369. left open).
  370. Note that when specifying the start and end angles, the curve will be drawn either clockwise
  371. or anti-clockwise according to whether the end angle is greater than the start. This means
  372. that sometimes you may need to use values greater than 2*Pi for the end angle.
  373. @param x the left-hand edge of the rectangle in which the elliptical outline fits
  374. @param y the top edge of the rectangle in which the elliptical outline fits
  375. @param width the width of the rectangle in which the elliptical outline fits
  376. @param height the height of the rectangle in which the elliptical outline fits
  377. @param fromRadians the angle (clockwise) in radians at which to start the arc segment (where 0 is the
  378. top-centre of the ellipse)
  379. @param toRadians the angle (clockwise) in radians at which to end the arc segment (where 0 is the
  380. top-centre of the ellipse)
  381. @param innerCircleProportionalSize if this is > 0, then the pie will be drawn as a curved band around a hollow
  382. ellipse at its centre, where this value indicates the inner ellipse's size with
  383. respect to the outer one.
  384. @see addArc
  385. */
  386. void addPieSegment (float x, float y,
  387. float width, float height,
  388. float fromRadians,
  389. float toRadians,
  390. float innerCircleProportionalSize);
  391. /** Adds a "pie-chart" shape to the path.
  392. The shape is added as a new sub-path. (Any currently open paths will be left open).
  393. Note that when specifying the start and end angles, the curve will be drawn either clockwise
  394. or anti-clockwise according to whether the end angle is greater than the start. This means
  395. that sometimes you may need to use values greater than 2*Pi for the end angle.
  396. @param segmentBounds the outer rectangle in which the elliptical outline fits
  397. @param fromRadians the angle (clockwise) in radians at which to start the arc segment (where 0 is the
  398. top-centre of the ellipse)
  399. @param toRadians the angle (clockwise) in radians at which to end the arc segment (where 0 is the
  400. top-centre of the ellipse)
  401. @param innerCircleProportionalSize if this is > 0, then the pie will be drawn as a curved band around a hollow
  402. ellipse at its centre, where this value indicates the inner ellipse's size with
  403. respect to the outer one.
  404. @see addArc
  405. */
  406. void addPieSegment (Rectangle<float> segmentBounds,
  407. float fromRadians,
  408. float toRadians,
  409. float innerCircleProportionalSize);
  410. /** Adds a line with a specified thickness.
  411. The line is added as a new closed sub-path. (Any currently open paths will be
  412. left open).
  413. @see addArrow
  414. */
  415. void addLineSegment (Line<float> line, float lineThickness);
  416. /** Adds a line with an arrowhead on the end.
  417. The arrow is added as a new closed sub-path. (Any currently open paths will be left open).
  418. @see PathStrokeType::createStrokeWithArrowheads
  419. */
  420. void addArrow (Line<float> line,
  421. float lineThickness,
  422. float arrowheadWidth,
  423. float arrowheadLength);
  424. /** Adds a polygon shape to the path.
  425. @see addStar
  426. */
  427. void addPolygon (Point<float> centre,
  428. int numberOfSides,
  429. float radius,
  430. float startAngle = 0.0f);
  431. /** Adds a star shape to the path.
  432. @see addPolygon
  433. */
  434. void addStar (Point<float> centre,
  435. int numberOfPoints,
  436. float innerRadius,
  437. float outerRadius,
  438. float startAngle = 0.0f);
  439. /** Adds a speech-bubble shape to the path.
  440. @param bodyArea the area of the body of the bubble shape
  441. @param maximumArea an area which encloses the body area and defines the limits within which
  442. the arrow tip can be drawn - if the tip lies outside this area, the bubble
  443. will be drawn without an arrow
  444. @param arrowTipPosition the location of the tip of the arrow
  445. @param cornerSize the size of the rounded corners
  446. @param arrowBaseWidth the width of the base of the arrow where it joins the main rectangle
  447. */
  448. void addBubble (Rectangle<float> bodyArea,
  449. Rectangle<float> maximumArea,
  450. const Point<float> arrowTipPosition,
  451. const float cornerSize,
  452. const float arrowBaseWidth);
  453. /** Adds another path to this one.
  454. The new path is added as a new sub-path. (Any currently open paths in this
  455. path will be left open).
  456. @param pathToAppend the path to add
  457. */
  458. void addPath (const Path& pathToAppend);
  459. /** Adds another path to this one, transforming it on the way in.
  460. The new path is added as a new sub-path, its points being transformed by the given
  461. matrix before being added.
  462. @param pathToAppend the path to add
  463. @param transformToApply an optional transform to apply to the incoming vertices
  464. */
  465. void addPath (const Path& pathToAppend,
  466. const AffineTransform& transformToApply);
  467. /** Swaps the contents of this path with another one.
  468. The internal data of the two paths is swapped over, so this is much faster than
  469. copying it to a temp variable and back.
  470. */
  471. void swapWithPath (Path&) noexcept;
  472. //==============================================================================
  473. /** Preallocates enough space for adding the given number of coordinates to the path.
  474. If you're about to add a large number of lines or curves to the path, it can make
  475. the task much more efficient to call this first and avoid costly reallocations
  476. as the structure grows.
  477. The actual value to pass is a bit tricky to calculate because the space required
  478. depends on what you're adding - e.g. each lineTo() or startNewSubPath() will
  479. require 3 coords (x, y and a type marker). Each quadraticTo() will need 5, and
  480. a cubicTo() will require 7. Closing a sub-path will require 1.
  481. */
  482. void preallocateSpace (int numExtraCoordsToMakeSpaceFor);
  483. //==============================================================================
  484. /** Applies a 2D transform to all the vertices in the path.
  485. @see AffineTransform, scaleToFit, getTransformToScaleToFit
  486. */
  487. void applyTransform (const AffineTransform& transform) noexcept;
  488. /** Rescales this path to make it fit neatly into a given space.
  489. This is effectively a quick way of calling
  490. applyTransform (getTransformToScaleToFit (x, y, w, h, preserveProportions))
  491. @param x the x position of the rectangle to fit the path inside
  492. @param y the y position of the rectangle to fit the path inside
  493. @param width the width of the rectangle to fit the path inside
  494. @param height the height of the rectangle to fit the path inside
  495. @param preserveProportions if true, it will fit the path into the space without altering its
  496. horizontal/vertical scale ratio; if false, it will distort the
  497. path to fill the specified ratio both horizontally and vertically
  498. @see applyTransform, getTransformToScaleToFit
  499. */
  500. void scaleToFit (float x, float y, float width, float height,
  501. bool preserveProportions) noexcept;
  502. /** Returns a transform that can be used to rescale the path to fit into a given space.
  503. @param x the x position of the rectangle to fit the path inside
  504. @param y the y position of the rectangle to fit the path inside
  505. @param width the width of the rectangle to fit the path inside
  506. @param height the height of the rectangle to fit the path inside
  507. @param preserveProportions if true, it will fit the path into the space without altering its
  508. horizontal/vertical scale ratio; if false, it will distort the
  509. path to fill the specified ratio both horizontally and vertically
  510. @param justificationType if the proportions are preserved, the resultant path may be smaller
  511. than the available rectangle, so this describes how it should be
  512. positioned within the space.
  513. @returns an appropriate transformation
  514. @see applyTransform, scaleToFit
  515. */
  516. AffineTransform getTransformToScaleToFit (float x, float y, float width, float height,
  517. bool preserveProportions,
  518. Justification justificationType = Justification::centred) const;
  519. /** Returns a transform that can be used to rescale the path to fit into a given space.
  520. @param area the rectangle to fit the path inside
  521. @param preserveProportions if true, it will fit the path into the space without altering its
  522. horizontal/vertical scale ratio; if false, it will distort the
  523. path to fill the specified ratio both horizontally and vertically
  524. @param justificationType if the proportions are preserved, the resultant path may be smaller
  525. than the available rectangle, so this describes how it should be
  526. positioned within the space.
  527. @returns an appropriate transformation
  528. @see applyTransform, scaleToFit
  529. */
  530. AffineTransform getTransformToScaleToFit (Rectangle<float> area,
  531. bool preserveProportions,
  532. Justification justificationType = Justification::centred) const;
  533. /** Creates a version of this path where all sharp corners have been replaced by curves.
  534. Wherever two lines meet at an angle, this will replace the corner with a curve
  535. of the given radius.
  536. */
  537. Path createPathWithRoundedCorners (float cornerRadius) const;
  538. //==============================================================================
  539. /** Changes the winding-rule to be used when filling the path.
  540. If set to true (which is the default), then the path uses a non-zero-winding rule
  541. to determine which points are inside the path. If set to false, it uses an
  542. alternate-winding rule.
  543. The winding-rule comes into play when areas of the shape overlap other
  544. areas, and determines whether the overlapping regions are considered to be
  545. inside or outside.
  546. Changing this value just sets a flag - it doesn't affect the contents of the
  547. path.
  548. @see isUsingNonZeroWinding
  549. */
  550. void setUsingNonZeroWinding (bool isNonZeroWinding) noexcept;
  551. /** Returns the flag that indicates whether the path should use a non-zero winding rule.
  552. The default for a new path is true.
  553. @see setUsingNonZeroWinding
  554. */
  555. bool isUsingNonZeroWinding() const { return useNonZeroWinding; }
  556. //==============================================================================
  557. /** Iterates the lines and curves that a path contains.
  558. @see Path, PathFlatteningIterator
  559. */
  560. class JUCE_API Iterator
  561. {
  562. public:
  563. //==============================================================================
  564. Iterator (const Path& path) noexcept;
  565. ~Iterator() noexcept;
  566. //==============================================================================
  567. /** Moves onto the next element in the path.
  568. If this returns false, there are no more elements. If it returns true,
  569. the elementType variable will be set to the type of the current element,
  570. and some of the x and y variables will be filled in with values.
  571. */
  572. bool next() noexcept;
  573. //==============================================================================
  574. enum PathElementType
  575. {
  576. startNewSubPath, /**< For this type, x1 and y1 will be set to indicate the first point in the subpath. */
  577. lineTo, /**< For this type, x1 and y1 indicate the end point of the line. */
  578. quadraticTo, /**< For this type, x1, y1, x2, y2 indicate the control point and endpoint of a quadratic curve. */
  579. cubicTo, /**< For this type, x1, y1, x2, y2, x3, y3 indicate the two control points and the endpoint of a cubic curve. */
  580. closePath /**< Indicates that the sub-path is being closed. None of the x or y values are valid in this case. */
  581. };
  582. PathElementType elementType;
  583. float x1 = 0, y1 = 0, x2 = 0, y2 = 0, x3 = 0, y3 = 0;
  584. //==============================================================================
  585. private:
  586. const Path& path;
  587. const float* index;
  588. JUCE_DECLARE_NON_COPYABLE (Iterator)
  589. };
  590. //==============================================================================
  591. /** Loads a stored path from a data stream.
  592. The data in the stream must have been written using writePathToStream().
  593. Note that this will append the stored path to whatever is currently in
  594. this path, so you might need to call clear() beforehand.
  595. @see loadPathFromData, writePathToStream
  596. */
  597. void loadPathFromStream (InputStream& source);
  598. /** Loads a stored path from a block of data.
  599. This is similar to loadPathFromStream(), but just reads from a block
  600. of data. Useful if you're including stored shapes in your code as a
  601. block of static data.
  602. @see loadPathFromStream, writePathToStream
  603. */
  604. void loadPathFromData (const void* data, size_t numberOfBytes);
  605. /** Stores the path by writing it out to a stream.
  606. After writing out a path, you can reload it using loadPathFromStream().
  607. @see loadPathFromStream, loadPathFromData
  608. */
  609. void writePathToStream (OutputStream& destination) const;
  610. //==============================================================================
  611. /** Creates a string containing a textual representation of this path.
  612. @see restoreFromString
  613. */
  614. String toString() const;
  615. /** Restores this path from a string that was created with the toString() method.
  616. @see toString()
  617. */
  618. void restoreFromString (StringRef stringVersion);
  619. private:
  620. //==============================================================================
  621. friend class PathFlatteningIterator;
  622. friend class Path::Iterator;
  623. friend class EdgeTable;
  624. Array<float> data;
  625. struct PathBounds
  626. {
  627. PathBounds() noexcept;
  628. Rectangle<float> getRectangle() const noexcept;
  629. void reset() noexcept;
  630. void reset (float, float) noexcept;
  631. void extend (float, float) noexcept;
  632. template <typename... Coords>
  633. void extend (float x, float y, Coords... coords) noexcept
  634. {
  635. extend (x, y);
  636. extend (coords...);
  637. }
  638. float pathXMin = 0, pathXMax = 0, pathYMin = 0, pathYMax = 0;
  639. };
  640. PathBounds bounds;
  641. bool useNonZeroWinding = true;
  642. static const float lineMarker;
  643. static const float moveMarker;
  644. static const float quadMarker;
  645. static const float cubicMarker;
  646. static const float closeSubPathMarker;
  647. JUCE_LEAK_DETECTOR (Path)
  648. };
  649. } // namespace juce