The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
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.

294 lines
9.2KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-11 by Raw Material Software Ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the GNU General
  7. Public License (Version 2), as published by the Free Software Foundation.
  8. A copy of the license is included in the JUCE distribution, or can be found
  9. online at www.gnu.org/licenses.
  10. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  11. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  12. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  13. ------------------------------------------------------------------------------
  14. To release a closed-source product which uses JUCE, commercial licenses are
  15. available: visit www.rawmaterialsoftware.com/juce for more information.
  16. ==============================================================================
  17. */
  18. BEGIN_JUCE_NAMESPACE
  19. #if JUCE_MSVC && JUCE_DEBUG
  20. #pragma optimize ("t", on)
  21. #endif
  22. const float PathFlatteningIterator::defaultTolerance = 0.6f;
  23. //==============================================================================
  24. PathFlatteningIterator::PathFlatteningIterator (const Path& path_,
  25. const AffineTransform& transform_,
  26. const float tolerance)
  27. : x2 (0),
  28. y2 (0),
  29. closesSubPath (false),
  30. subPathIndex (-1),
  31. path (path_),
  32. transform (transform_),
  33. points (path_.data.elements),
  34. toleranceSquared (tolerance * tolerance),
  35. subPathCloseX (0),
  36. subPathCloseY (0),
  37. isIdentityTransform (transform_.isIdentity()),
  38. stackBase (32),
  39. index (0),
  40. stackSize (32)
  41. {
  42. stackPos = stackBase;
  43. }
  44. PathFlatteningIterator::~PathFlatteningIterator()
  45. {
  46. }
  47. bool PathFlatteningIterator::isLastInSubpath() const noexcept
  48. {
  49. return stackPos == stackBase.getData()
  50. && (index >= path.numElements || points [index] == Path::moveMarker);
  51. }
  52. bool PathFlatteningIterator::next()
  53. {
  54. x1 = x2;
  55. y1 = y2;
  56. float x3 = 0;
  57. float y3 = 0;
  58. float x4 = 0;
  59. float y4 = 0;
  60. float type;
  61. for (;;)
  62. {
  63. if (stackPos == stackBase)
  64. {
  65. if (index >= path.numElements)
  66. {
  67. return false;
  68. }
  69. else
  70. {
  71. type = points [index++];
  72. if (type != Path::closeSubPathMarker)
  73. {
  74. x2 = points [index++];
  75. y2 = points [index++];
  76. if (type == Path::quadMarker)
  77. {
  78. x3 = points [index++];
  79. y3 = points [index++];
  80. if (! isIdentityTransform)
  81. transform.transformPoints (x2, y2, x3, y3);
  82. }
  83. else if (type == Path::cubicMarker)
  84. {
  85. x3 = points [index++];
  86. y3 = points [index++];
  87. x4 = points [index++];
  88. y4 = points [index++];
  89. if (! isIdentityTransform)
  90. transform.transformPoints (x2, y2, x3, y3, x4, y4);
  91. }
  92. else
  93. {
  94. if (! isIdentityTransform)
  95. transform.transformPoint (x2, y2);
  96. }
  97. }
  98. }
  99. }
  100. else
  101. {
  102. type = *--stackPos;
  103. if (type != Path::closeSubPathMarker)
  104. {
  105. x2 = *--stackPos;
  106. y2 = *--stackPos;
  107. if (type == Path::quadMarker)
  108. {
  109. x3 = *--stackPos;
  110. y3 = *--stackPos;
  111. }
  112. else if (type == Path::cubicMarker)
  113. {
  114. x3 = *--stackPos;
  115. y3 = *--stackPos;
  116. x4 = *--stackPos;
  117. y4 = *--stackPos;
  118. }
  119. }
  120. }
  121. if (type == Path::lineMarker)
  122. {
  123. ++subPathIndex;
  124. closesSubPath = (stackPos == stackBase)
  125. && (index < path.numElements)
  126. && (points [index] == Path::closeSubPathMarker)
  127. && x2 == subPathCloseX
  128. && y2 == subPathCloseY;
  129. return true;
  130. }
  131. else if (type == Path::quadMarker)
  132. {
  133. const size_t offset = (size_t) (stackPos - stackBase);
  134. if (offset >= stackSize - 10)
  135. {
  136. stackSize <<= 1;
  137. stackBase.realloc (stackSize);
  138. stackPos = stackBase + offset;
  139. }
  140. const float m1x = (x1 + x2) * 0.5f;
  141. const float m1y = (y1 + y2) * 0.5f;
  142. const float m2x = (x2 + x3) * 0.5f;
  143. const float m2y = (y2 + y3) * 0.5f;
  144. const float m3x = (m1x + m2x) * 0.5f;
  145. const float m3y = (m1y + m2y) * 0.5f;
  146. const float errorX = m3x - x2;
  147. const float errorY = m3y - y2;
  148. if (errorX * errorX + errorY * errorY > toleranceSquared)
  149. {
  150. *stackPos++ = y3;
  151. *stackPos++ = x3;
  152. *stackPos++ = m2y;
  153. *stackPos++ = m2x;
  154. *stackPos++ = Path::quadMarker;
  155. *stackPos++ = m3y;
  156. *stackPos++ = m3x;
  157. *stackPos++ = m1y;
  158. *stackPos++ = m1x;
  159. *stackPos++ = Path::quadMarker;
  160. }
  161. else
  162. {
  163. *stackPos++ = y3;
  164. *stackPos++ = x3;
  165. *stackPos++ = Path::lineMarker;
  166. *stackPos++ = m3y;
  167. *stackPos++ = m3x;
  168. *stackPos++ = Path::lineMarker;
  169. }
  170. jassert (stackPos < stackBase + stackSize);
  171. }
  172. else if (type == Path::cubicMarker)
  173. {
  174. const size_t offset = (size_t) (stackPos - stackBase);
  175. if (offset >= stackSize - 16)
  176. {
  177. stackSize <<= 1;
  178. stackBase.realloc (stackSize);
  179. stackPos = stackBase + offset;
  180. }
  181. const float m1x = (x1 + x2) * 0.5f;
  182. const float m1y = (y1 + y2) * 0.5f;
  183. const float m2x = (x3 + x2) * 0.5f;
  184. const float m2y = (y3 + y2) * 0.5f;
  185. const float m3x = (x3 + x4) * 0.5f;
  186. const float m3y = (y3 + y4) * 0.5f;
  187. const float m4x = (m1x + m2x) * 0.5f;
  188. const float m4y = (m1y + m2y) * 0.5f;
  189. const float m5x = (m3x + m2x) * 0.5f;
  190. const float m5y = (m3y + m2y) * 0.5f;
  191. const float error1X = m4x - x2;
  192. const float error1Y = m4y - y2;
  193. const float error2X = m5x - x3;
  194. const float error2Y = m5y - y3;
  195. if (error1X * error1X + error1Y * error1Y > toleranceSquared
  196. || error2X * error2X + error2Y * error2Y > toleranceSquared)
  197. {
  198. *stackPos++ = y4;
  199. *stackPos++ = x4;
  200. *stackPos++ = m3y;
  201. *stackPos++ = m3x;
  202. *stackPos++ = m5y;
  203. *stackPos++ = m5x;
  204. *stackPos++ = Path::cubicMarker;
  205. *stackPos++ = (m4y + m5y) * 0.5f;
  206. *stackPos++ = (m4x + m5x) * 0.5f;
  207. *stackPos++ = m4y;
  208. *stackPos++ = m4x;
  209. *stackPos++ = m1y;
  210. *stackPos++ = m1x;
  211. *stackPos++ = Path::cubicMarker;
  212. }
  213. else
  214. {
  215. *stackPos++ = y4;
  216. *stackPos++ = x4;
  217. *stackPos++ = Path::lineMarker;
  218. *stackPos++ = m5y;
  219. *stackPos++ = m5x;
  220. *stackPos++ = Path::lineMarker;
  221. *stackPos++ = m4y;
  222. *stackPos++ = m4x;
  223. *stackPos++ = Path::lineMarker;
  224. }
  225. }
  226. else if (type == Path::closeSubPathMarker)
  227. {
  228. if (x2 != subPathCloseX || y2 != subPathCloseY)
  229. {
  230. x1 = x2;
  231. y1 = y2;
  232. x2 = subPathCloseX;
  233. y2 = subPathCloseY;
  234. closesSubPath = true;
  235. return true;
  236. }
  237. }
  238. else
  239. {
  240. jassert (type == Path::moveMarker);
  241. subPathIndex = -1;
  242. subPathCloseX = x1 = x2;
  243. subPathCloseY = y1 = y2;
  244. }
  245. }
  246. }
  247. #if JUCE_MSVC && JUCE_DEBUG
  248. #pragma optimize ("", on) // resets optimisations to the project defaults
  249. #endif
  250. END_JUCE_NAMESPACE