001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: /**
018: * @author Denis M. Kishenko
019: * @version $Revision$
020: */package java.awt.geom;
021:
022: import java.util.NoSuchElementException;
023:
024: import org.apache.harmony.awt.internal.nls.Messages;
025:
026: public class FlatteningPathIterator implements PathIterator {
027:
028: /**
029: * The default points buffer size
030: */
031: private static final int BUFFER_SIZE = 16;
032:
033: /**
034: * The default curve subdivision limit
035: */
036: private static final int BUFFER_LIMIT = 16;
037:
038: /**
039: * The points buffer capacity
040: */
041: private static final int BUFFER_CAPACITY = 16;
042:
043: /**
044: * The type of current segment to be flat
045: */
046: int bufType;
047:
048: /**
049: * The curve subdivision limit
050: */
051: int bufLimit;
052:
053: /**
054: * The current points buffer size
055: */
056: int bufSize;
057:
058: /**
059: * The inner cursor position in points buffer
060: */
061: int bufIndex;
062:
063: /**
064: * The current subdivision count
065: */
066: int bufSubdiv;
067:
068: /**
069: * The points buffer
070: */
071: double buf[];
072:
073: /**
074: * The indicator of empty points buffer
075: */
076: boolean bufEmpty = true;
077:
078: /**
079: * The source PathIterator
080: */
081: PathIterator p;
082:
083: /**
084: * The flatness of new path
085: */
086: double flatness;
087:
088: /**
089: * The square of flatness
090: */
091: double flatness2;
092:
093: /**
094: * The x coordinate of previous path segment
095: */
096: double px;
097:
098: /**
099: * The y coordinate of previous path segment
100: */
101: double py;
102:
103: /**
104: * The tamporary buffer for getting points from PathIterator
105: */
106: double coords[] = new double[6];
107:
108: public FlatteningPathIterator(PathIterator path, double flatness) {
109: this (path, flatness, BUFFER_LIMIT);
110: }
111:
112: public FlatteningPathIterator(PathIterator path, double flatness,
113: int limit) {
114: if (flatness < 0.0) {
115: // awt.206=Flatness is less then zero
116: throw new IllegalArgumentException(Messages
117: .getString("awt.206")); //$NON-NLS-1$
118: }
119: if (limit < 0) {
120: // awt.207=Limit is less then zero
121: throw new IllegalArgumentException(Messages
122: .getString("awt.207")); //$NON-NLS-1$
123: }
124: if (path == null) {
125: // awt.208=Path is null
126: throw new NullPointerException(Messages
127: .getString("awt.208")); //$NON-NLS-1$
128: }
129: this .p = path;
130: this .flatness = flatness;
131: this .flatness2 = flatness * flatness;
132: this .bufLimit = limit;
133: this .bufSize = Math.min(bufLimit, BUFFER_SIZE);
134: this .buf = new double[bufSize];
135: this .bufIndex = bufSize;
136: }
137:
138: public double getFlatness() {
139: return flatness;
140: }
141:
142: public int getRecursionLimit() {
143: return bufLimit;
144: }
145:
146: public int getWindingRule() {
147: return p.getWindingRule();
148: }
149:
150: public boolean isDone() {
151: return bufEmpty && p.isDone();
152: }
153:
154: /**
155: * Calculates flat path points for current segment of the source shape.
156: *
157: * Line segment is flat by itself. Flatness of quad and cubic curves evaluated by getFlatnessSq() method.
158: * Curves subdivided until current flatness is bigger than user defined and subdivision limit isn't exhausted.
159: * Single source segment translated to series of buffer points. The less flatness the bigger serries.
160: * Every currentSegment() call extract one point from the buffer. When series completed evaluate() takes next source shape segment.
161: */
162: void evaluate() {
163: if (bufEmpty) {
164: bufType = p.currentSegment(coords);
165: }
166:
167: switch (bufType) {
168: case SEG_MOVETO:
169: case SEG_LINETO:
170: px = coords[0];
171: py = coords[1];
172: break;
173: case SEG_QUADTO:
174: if (bufEmpty) {
175: bufIndex -= 6;
176: buf[bufIndex + 0] = px;
177: buf[bufIndex + 1] = py;
178: System.arraycopy(coords, 0, buf, bufIndex + 2, 4);
179: bufSubdiv = 0;
180: }
181:
182: while (bufSubdiv < bufLimit) {
183: if (QuadCurve2D.getFlatnessSq(buf, bufIndex) < flatness2) {
184: break;
185: }
186:
187: // Realloc buffer
188: if (bufIndex <= 4) {
189: double tmp[] = new double[bufSize + BUFFER_CAPACITY];
190: System.arraycopy(buf, bufIndex, tmp, bufIndex
191: + BUFFER_CAPACITY, bufSize - bufIndex);
192: buf = tmp;
193: bufSize += BUFFER_CAPACITY;
194: bufIndex += BUFFER_CAPACITY;
195: }
196:
197: QuadCurve2D.subdivide(buf, bufIndex, buf, bufIndex - 4,
198: buf, bufIndex);
199:
200: bufIndex -= 4;
201: bufSubdiv++;
202: }
203:
204: bufIndex += 4;
205: px = buf[bufIndex];
206: py = buf[bufIndex + 1];
207:
208: bufEmpty = (bufIndex == bufSize - 2);
209: if (bufEmpty) {
210: bufIndex = bufSize;
211: bufType = SEG_LINETO;
212: }
213: break;
214: case SEG_CUBICTO:
215: if (bufEmpty) {
216: bufIndex -= 8;
217: buf[bufIndex + 0] = px;
218: buf[bufIndex + 1] = py;
219: System.arraycopy(coords, 0, buf, bufIndex + 2, 6);
220: bufSubdiv = 0;
221: }
222:
223: while (bufSubdiv < bufLimit) {
224: if (CubicCurve2D.getFlatnessSq(buf, bufIndex) < flatness2) {
225: break;
226: }
227:
228: // Realloc buffer
229: if (bufIndex <= 6) {
230: double tmp[] = new double[bufSize + BUFFER_CAPACITY];
231: System.arraycopy(buf, bufIndex, tmp, bufIndex
232: + BUFFER_CAPACITY, bufSize - bufIndex);
233: buf = tmp;
234: bufSize += BUFFER_CAPACITY;
235: bufIndex += BUFFER_CAPACITY;
236: }
237:
238: CubicCurve2D.subdivide(buf, bufIndex, buf,
239: bufIndex - 6, buf, bufIndex);
240:
241: bufIndex -= 6;
242: bufSubdiv++;
243: }
244:
245: bufIndex += 6;
246: px = buf[bufIndex];
247: py = buf[bufIndex + 1];
248:
249: bufEmpty = (bufIndex == bufSize - 2);
250: if (bufEmpty) {
251: bufIndex = bufSize;
252: bufType = SEG_LINETO;
253: }
254: break;
255: }
256:
257: }
258:
259: public void next() {
260: if (bufEmpty) {
261: p.next();
262: }
263: }
264:
265: public int currentSegment(float[] coords) {
266: if (isDone()) {
267: // awt.4B=Iterator out of bounds
268: throw new NoSuchElementException(Messages
269: .getString("awt.4Bx")); //$NON-NLS-1$
270: }
271: evaluate();
272: int type = bufType;
273: if (type != SEG_CLOSE) {
274: coords[0] = (float) px;
275: coords[1] = (float) py;
276: if (type != SEG_MOVETO) {
277: type = SEG_LINETO;
278: }
279: }
280: return type;
281: }
282:
283: public int currentSegment(double[] coords) {
284: if (isDone()) {
285: // awt.4B=Iterator out of bounds
286: throw new NoSuchElementException(Messages
287: .getString("awt.4B")); //$NON-NLS-1$
288: }
289: evaluate();
290: int type = bufType;
291: if (type != SEG_CLOSE) {
292: coords[0] = px;
293: coords[1] = py;
294: if (type != SEG_MOVETO) {
295: type = SEG_LINETO;
296: }
297: }
298: return type;
299: }
300: }
|