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"
30 #include "juce_PathIterator.h"
32 #if JUCE_MSVC && JUCE_DEBUG
33 #pragma optimize ("t", on)
36 //==============================================================================
37 const float PathFlatteningIterator::defaultTolerance
= 0.6f
;
40 //==============================================================================
41 PathFlatteningIterator::PathFlatteningIterator (const Path
& path_
,
42 const AffineTransform
& transform_
,
43 const float tolerance
)
46 closesSubPath (false),
49 transform (transform_
),
50 points (path_
.data
.elements
),
51 toleranceSquared (tolerance
* tolerance
),
54 isIdentityTransform (transform_
.isIdentity()),
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()
85 if (stackPos
== stackBase
)
87 if (index
>= path
.numElements
)
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
);
120 if (! isIdentityTransform
)
121 transform
.transformPoint (x2
, y2
);
130 if (type
!= Path::closeSubPathMarker
)
135 if (type
== Path::quadMarker
)
140 else if (type
== Path::cubicMarker
)
150 if (type
== Path::lineMarker
)
154 closesSubPath
= (stackPos
== stackBase
)
155 && (index
< path
.numElements
)
156 && (points
[index
] == Path::closeSubPathMarker
)
157 && x2
== subPathCloseX
158 && y2
== subPathCloseY
;
162 else if (type
== Path::quadMarker
)
164 const size_t offset
= (size_t) (stackPos
- stackBase
);
166 if (offset
>= stackSize
- 10)
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
)
189 *stackPos
++ = Path::quadMarker
;
195 *stackPos
++ = Path::quadMarker
;
201 *stackPos
++ = Path::lineMarker
;
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)
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
)
246 *stackPos
++ = Path::cubicMarker
;
248 *stackPos
++ = (m4y
+ m5y
) * 0.5f
;
249 *stackPos
++ = (m4x
+ m5x
) * 0.5f
;
254 *stackPos
++ = Path::cubicMarker
;
260 *stackPos
++ = Path::lineMarker
;
264 *stackPos
++ = Path::lineMarker
;
268 *stackPos
++ = Path::lineMarker
;
271 else if (type
== Path::closeSubPathMarker
)
273 if (x2
!= subPathCloseX
|| y2
!= subPathCloseY
)
279 closesSubPath
= true;
286 jassert (type
== Path::moveMarker
);
289 subPathCloseX
= x1
= x2
;
290 subPathCloseY
= y1
= y2
;
295 #if JUCE_MSVC && JUCE_DEBUG
296 #pragma optimize ("", on) // resets optimisations to the project defaults