Add remaining files
[juce-lv2.git] / juce / source / src / gui / graphics / geometry / juce_PathIterator.cpp
blob94d034a3194de21062334636851bed82d437b067
1 /*
2 ==============================================================================
4 This file is part of the JUCE library - "Jules' Utility Class Extensions"
5 Copyright 2004-11 by Raw Material Software Ltd.
7 ------------------------------------------------------------------------------
9 JUCE can be redistributed and/or modified under the terms of the GNU General
10 Public License (Version 2), as published by the Free Software Foundation.
11 A copy of the license is included in the JUCE distribution, or can be found
12 online at www.gnu.org/licenses.
14 JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
15 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
16 A PARTICULAR PURPOSE. See the GNU General Public License for more details.
18 ------------------------------------------------------------------------------
20 To release a closed-source product which uses JUCE, commercial licenses are
21 available: visit www.rawmaterialsoftware.com/juce for more information.
23 ==============================================================================
26 #include "../../../core/juce_StandardHeader.h"
28 BEGIN_JUCE_NAMESPACE
30 #include "juce_PathIterator.h"
32 #if JUCE_MSVC && JUCE_DEBUG
33 #pragma optimize ("t", on)
34 #endif
36 //==============================================================================
37 const float PathFlatteningIterator::defaultTolerance = 0.6f;
40 //==============================================================================
41 PathFlatteningIterator::PathFlatteningIterator (const Path& path_,
42 const AffineTransform& transform_,
43 const float tolerance)
44 : x2 (0),
45 y2 (0),
46 closesSubPath (false),
47 subPathIndex (-1),
48 path (path_),
49 transform (transform_),
50 points (path_.data.elements),
51 toleranceSquared (tolerance * tolerance),
52 subPathCloseX (0),
53 subPathCloseY (0),
54 isIdentityTransform (transform_.isIdentity()),
55 stackBase (32),
56 index (0),
57 stackSize (32)
59 stackPos = stackBase;
62 PathFlatteningIterator::~PathFlatteningIterator()
66 bool PathFlatteningIterator::isLastInSubpath() const noexcept
68 return stackPos == stackBase.getData()
69 && (index >= path.numElements || points [index] == Path::moveMarker);
72 bool PathFlatteningIterator::next()
74 x1 = x2;
75 y1 = y2;
77 float x3 = 0;
78 float y3 = 0;
79 float x4 = 0;
80 float y4 = 0;
81 float type;
83 for (;;)
85 if (stackPos == stackBase)
87 if (index >= path.numElements)
89 return false;
91 else
93 type = points [index++];
95 if (type != Path::closeSubPathMarker)
97 x2 = points [index++];
98 y2 = points [index++];
100 if (type == Path::quadMarker)
102 x3 = points [index++];
103 y3 = points [index++];
105 if (! isIdentityTransform)
106 transform.transformPoints (x2, y2, x3, y3);
108 else if (type == Path::cubicMarker)
110 x3 = points [index++];
111 y3 = points [index++];
112 x4 = points [index++];
113 y4 = points [index++];
115 if (! isIdentityTransform)
116 transform.transformPoints (x2, y2, x3, y3, x4, y4);
118 else
120 if (! isIdentityTransform)
121 transform.transformPoint (x2, y2);
126 else
128 type = *--stackPos;
130 if (type != Path::closeSubPathMarker)
132 x2 = *--stackPos;
133 y2 = *--stackPos;
135 if (type == Path::quadMarker)
137 x3 = *--stackPos;
138 y3 = *--stackPos;
140 else if (type == Path::cubicMarker)
142 x3 = *--stackPos;
143 y3 = *--stackPos;
144 x4 = *--stackPos;
145 y4 = *--stackPos;
150 if (type == Path::lineMarker)
152 ++subPathIndex;
154 closesSubPath = (stackPos == stackBase)
155 && (index < path.numElements)
156 && (points [index] == Path::closeSubPathMarker)
157 && x2 == subPathCloseX
158 && y2 == subPathCloseY;
160 return true;
162 else if (type == Path::quadMarker)
164 const size_t offset = (size_t) (stackPos - stackBase);
166 if (offset >= stackSize - 10)
168 stackSize <<= 1;
169 stackBase.realloc (stackSize);
170 stackPos = stackBase + offset;
173 const float m1x = (x1 + x2) * 0.5f;
174 const float m1y = (y1 + y2) * 0.5f;
175 const float m2x = (x2 + x3) * 0.5f;
176 const float m2y = (y2 + y3) * 0.5f;
177 const float m3x = (m1x + m2x) * 0.5f;
178 const float m3y = (m1y + m2y) * 0.5f;
180 const float errorX = m3x - x2;
181 const float errorY = m3y - y2;
183 if (errorX * errorX + errorY * errorY > toleranceSquared)
185 *stackPos++ = y3;
186 *stackPos++ = x3;
187 *stackPos++ = m2y;
188 *stackPos++ = m2x;
189 *stackPos++ = Path::quadMarker;
191 *stackPos++ = m3y;
192 *stackPos++ = m3x;
193 *stackPos++ = m1y;
194 *stackPos++ = m1x;
195 *stackPos++ = Path::quadMarker;
197 else
199 *stackPos++ = y3;
200 *stackPos++ = x3;
201 *stackPos++ = Path::lineMarker;
203 *stackPos++ = m3y;
204 *stackPos++ = m3x;
205 *stackPos++ = Path::lineMarker;
208 jassert (stackPos < stackBase + stackSize);
210 else if (type == Path::cubicMarker)
212 const size_t offset = (size_t) (stackPos - stackBase);
214 if (offset >= stackSize - 16)
216 stackSize <<= 1;
217 stackBase.realloc (stackSize);
218 stackPos = stackBase + offset;
221 const float m1x = (x1 + x2) * 0.5f;
222 const float m1y = (y1 + y2) * 0.5f;
223 const float m2x = (x3 + x2) * 0.5f;
224 const float m2y = (y3 + y2) * 0.5f;
225 const float m3x = (x3 + x4) * 0.5f;
226 const float m3y = (y3 + y4) * 0.5f;
227 const float m4x = (m1x + m2x) * 0.5f;
228 const float m4y = (m1y + m2y) * 0.5f;
229 const float m5x = (m3x + m2x) * 0.5f;
230 const float m5y = (m3y + m2y) * 0.5f;
232 const float error1X = m4x - x2;
233 const float error1Y = m4y - y2;
234 const float error2X = m5x - x3;
235 const float error2Y = m5y - y3;
237 if (error1X * error1X + error1Y * error1Y > toleranceSquared
238 || error2X * error2X + error2Y * error2Y > toleranceSquared)
240 *stackPos++ = y4;
241 *stackPos++ = x4;
242 *stackPos++ = m3y;
243 *stackPos++ = m3x;
244 *stackPos++ = m5y;
245 *stackPos++ = m5x;
246 *stackPos++ = Path::cubicMarker;
248 *stackPos++ = (m4y + m5y) * 0.5f;
249 *stackPos++ = (m4x + m5x) * 0.5f;
250 *stackPos++ = m4y;
251 *stackPos++ = m4x;
252 *stackPos++ = m1y;
253 *stackPos++ = m1x;
254 *stackPos++ = Path::cubicMarker;
256 else
258 *stackPos++ = y4;
259 *stackPos++ = x4;
260 *stackPos++ = Path::lineMarker;
262 *stackPos++ = m5y;
263 *stackPos++ = m5x;
264 *stackPos++ = Path::lineMarker;
266 *stackPos++ = m4y;
267 *stackPos++ = m4x;
268 *stackPos++ = Path::lineMarker;
271 else if (type == Path::closeSubPathMarker)
273 if (x2 != subPathCloseX || y2 != subPathCloseY)
275 x1 = x2;
276 y1 = y2;
277 x2 = subPathCloseX;
278 y2 = subPathCloseY;
279 closesSubPath = true;
281 return true;
284 else
286 jassert (type == Path::moveMarker);
288 subPathIndex = -1;
289 subPathCloseX = x1 = x2;
290 subPathCloseY = y1 = y2;
295 #if JUCE_MSVC && JUCE_DEBUG
296 #pragma optimize ("", on) // resets optimisations to the project defaults
297 #endif
299 END_JUCE_NAMESPACE