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.

290 lines
9.1KB

  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. #if JUCE_MSVC && JUCE_DEBUG
  19. #pragma optimize ("t", on)
  20. #endif
  21. const float PathFlatteningIterator::defaultTolerance = 0.6f;
  22. //==============================================================================
  23. PathFlatteningIterator::PathFlatteningIterator (const Path& path_,
  24. const AffineTransform& transform_,
  25. const float tolerance)
  26. : x2 (0),
  27. y2 (0),
  28. closesSubPath (false),
  29. subPathIndex (-1),
  30. path (path_),
  31. transform (transform_),
  32. points (path_.data.elements),
  33. toleranceSquared (tolerance * tolerance),
  34. subPathCloseX (0),
  35. subPathCloseY (0),
  36. isIdentityTransform (transform_.isIdentity()),
  37. stackBase (32),
  38. index (0),
  39. stackSize (32)
  40. {
  41. stackPos = stackBase;
  42. }
  43. PathFlatteningIterator::~PathFlatteningIterator()
  44. {
  45. }
  46. bool PathFlatteningIterator::isLastInSubpath() const noexcept
  47. {
  48. return stackPos == stackBase.getData()
  49. && (index >= path.numElements || points [index] == Path::moveMarker);
  50. }
  51. bool PathFlatteningIterator::next()
  52. {
  53. x1 = x2;
  54. y1 = y2;
  55. float x3 = 0;
  56. float y3 = 0;
  57. float x4 = 0;
  58. float y4 = 0;
  59. float type;
  60. for (;;)
  61. {
  62. if (stackPos == stackBase)
  63. {
  64. if (index >= path.numElements)
  65. {
  66. return false;
  67. }
  68. else
  69. {
  70. type = points [index++];
  71. if (type != Path::closeSubPathMarker)
  72. {
  73. x2 = points [index++];
  74. y2 = points [index++];
  75. if (type == Path::quadMarker)
  76. {
  77. x3 = points [index++];
  78. y3 = points [index++];
  79. if (! isIdentityTransform)
  80. transform.transformPoints (x2, y2, x3, y3);
  81. }
  82. else if (type == Path::cubicMarker)
  83. {
  84. x3 = points [index++];
  85. y3 = points [index++];
  86. x4 = points [index++];
  87. y4 = points [index++];
  88. if (! isIdentityTransform)
  89. transform.transformPoints (x2, y2, x3, y3, x4, y4);
  90. }
  91. else
  92. {
  93. if (! isIdentityTransform)
  94. transform.transformPoint (x2, y2);
  95. }
  96. }
  97. }
  98. }
  99. else
  100. {
  101. type = *--stackPos;
  102. if (type != Path::closeSubPathMarker)
  103. {
  104. x2 = *--stackPos;
  105. y2 = *--stackPos;
  106. if (type == Path::quadMarker)
  107. {
  108. x3 = *--stackPos;
  109. y3 = *--stackPos;
  110. }
  111. else if (type == Path::cubicMarker)
  112. {
  113. x3 = *--stackPos;
  114. y3 = *--stackPos;
  115. x4 = *--stackPos;
  116. y4 = *--stackPos;
  117. }
  118. }
  119. }
  120. if (type == Path::lineMarker)
  121. {
  122. ++subPathIndex;
  123. closesSubPath = (stackPos == stackBase)
  124. && (index < path.numElements)
  125. && (points [index] == Path::closeSubPathMarker)
  126. && x2 == subPathCloseX
  127. && y2 == subPathCloseY;
  128. return true;
  129. }
  130. else if (type == Path::quadMarker)
  131. {
  132. const size_t offset = (size_t) (stackPos - stackBase);
  133. if (offset >= stackSize - 10)
  134. {
  135. stackSize <<= 1;
  136. stackBase.realloc (stackSize);
  137. stackPos = stackBase + offset;
  138. }
  139. const float m1x = (x1 + x2) * 0.5f;
  140. const float m1y = (y1 + y2) * 0.5f;
  141. const float m2x = (x2 + x3) * 0.5f;
  142. const float m2y = (y2 + y3) * 0.5f;
  143. const float m3x = (m1x + m2x) * 0.5f;
  144. const float m3y = (m1y + m2y) * 0.5f;
  145. const float errorX = m3x - x2;
  146. const float errorY = m3y - y2;
  147. if (errorX * errorX + errorY * errorY > toleranceSquared)
  148. {
  149. *stackPos++ = y3;
  150. *stackPos++ = x3;
  151. *stackPos++ = m2y;
  152. *stackPos++ = m2x;
  153. *stackPos++ = Path::quadMarker;
  154. *stackPos++ = m3y;
  155. *stackPos++ = m3x;
  156. *stackPos++ = m1y;
  157. *stackPos++ = m1x;
  158. *stackPos++ = Path::quadMarker;
  159. }
  160. else
  161. {
  162. *stackPos++ = y3;
  163. *stackPos++ = x3;
  164. *stackPos++ = Path::lineMarker;
  165. *stackPos++ = m3y;
  166. *stackPos++ = m3x;
  167. *stackPos++ = Path::lineMarker;
  168. }
  169. jassert (stackPos < stackBase + stackSize);
  170. }
  171. else if (type == Path::cubicMarker)
  172. {
  173. const size_t offset = (size_t) (stackPos - stackBase);
  174. if (offset >= stackSize - 16)
  175. {
  176. stackSize <<= 1;
  177. stackBase.realloc (stackSize);
  178. stackPos = stackBase + offset;
  179. }
  180. const float m1x = (x1 + x2) * 0.5f;
  181. const float m1y = (y1 + y2) * 0.5f;
  182. const float m2x = (x3 + x2) * 0.5f;
  183. const float m2y = (y3 + y2) * 0.5f;
  184. const float m3x = (x3 + x4) * 0.5f;
  185. const float m3y = (y3 + y4) * 0.5f;
  186. const float m4x = (m1x + m2x) * 0.5f;
  187. const float m4y = (m1y + m2y) * 0.5f;
  188. const float m5x = (m3x + m2x) * 0.5f;
  189. const float m5y = (m3y + m2y) * 0.5f;
  190. const float error1X = m4x - x2;
  191. const float error1Y = m4y - y2;
  192. const float error2X = m5x - x3;
  193. const float error2Y = m5y - y3;
  194. if (error1X * error1X + error1Y * error1Y > toleranceSquared
  195. || error2X * error2X + error2Y * error2Y > toleranceSquared)
  196. {
  197. *stackPos++ = y4;
  198. *stackPos++ = x4;
  199. *stackPos++ = m3y;
  200. *stackPos++ = m3x;
  201. *stackPos++ = m5y;
  202. *stackPos++ = m5x;
  203. *stackPos++ = Path::cubicMarker;
  204. *stackPos++ = (m4y + m5y) * 0.5f;
  205. *stackPos++ = (m4x + m5x) * 0.5f;
  206. *stackPos++ = m4y;
  207. *stackPos++ = m4x;
  208. *stackPos++ = m1y;
  209. *stackPos++ = m1x;
  210. *stackPos++ = Path::cubicMarker;
  211. }
  212. else
  213. {
  214. *stackPos++ = y4;
  215. *stackPos++ = x4;
  216. *stackPos++ = Path::lineMarker;
  217. *stackPos++ = m5y;
  218. *stackPos++ = m5x;
  219. *stackPos++ = Path::lineMarker;
  220. *stackPos++ = m4y;
  221. *stackPos++ = m4x;
  222. *stackPos++ = Path::lineMarker;
  223. }
  224. }
  225. else if (type == Path::closeSubPathMarker)
  226. {
  227. if (x2 != subPathCloseX || y2 != subPathCloseY)
  228. {
  229. x1 = x2;
  230. y1 = y2;
  231. x2 = subPathCloseX;
  232. y2 = subPathCloseY;
  233. closesSubPath = true;
  234. return true;
  235. }
  236. }
  237. else
  238. {
  239. jassert (type == Path::moveMarker);
  240. subPathIndex = -1;
  241. subPathCloseX = x1 = x2;
  242. subPathCloseY = y1 = y2;
  243. }
  244. }
  245. }
  246. #if JUCE_MSVC && JUCE_DEBUG
  247. #pragma optimize ("", on) // resets optimisations to the project defaults
  248. #endif