OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libjava/] [classpath/] [java/] [awt/] [geom/] [FlatteningPathIterator.java] - Blame information for rev 771

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 771 jeremybenn
/* FlatteningPathIterator.java -- Approximates curves by straight lines
2
   Copyright (C) 2003 Free Software Foundation
3
 
4
This file is part of GNU Classpath.
5
 
6
GNU Classpath is free software; you can redistribute it and/or modify
7
it under the terms of the GNU General Public License as published by
8
the Free Software Foundation; either version 2, or (at your option)
9
any later version.
10
 
11
GNU Classpath is distributed in the hope that it will be useful, but
12
WITHOUT ANY WARRANTY; without even the implied warranty of
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
General Public License for more details.
15
 
16
You should have received a copy of the GNU General Public License
17
along with GNU Classpath; see the file COPYING.  If not, write to the
18
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19
02110-1301 USA.
20
 
21
Linking this library statically or dynamically with other modules is
22
making a combined work based on this library.  Thus, the terms and
23
conditions of the GNU General Public License cover the whole
24
combination.
25
 
26
As a special exception, the copyright holders of this library give you
27
permission to link this library with independent modules to produce an
28
executable, regardless of the license terms of these independent
29
modules, and to copy and distribute the resulting executable under
30
terms of your choice, provided that you also meet, for each linked
31
independent module, the terms and conditions of the license of that
32
module.  An independent module is a module which is not derived from
33
or based on this library.  If you modify this library, you may extend
34
this exception to your version of the library, but you are not
35
obligated to do so.  If you do not wish to do so, delete this
36
exception statement from your version. */
37
 
38
 
39
package java.awt.geom;
40
 
41
import java.util.NoSuchElementException;
42
 
43
 
44
/**
45
 * A PathIterator for approximating curved path segments by sequences
46
 * of straight lines. Instances of this class will only return
47
 * segments of type {@link PathIterator#SEG_MOVETO}, {@link
48
 * PathIterator#SEG_LINETO}, and {@link PathIterator#SEG_CLOSE}.
49
 *
50
 * <p>The accuracy of the approximation is determined by two
51
 * parameters:
52
 *
53
 * <ul><li>The <i>flatness</i> is a threshold value for deciding when
54
 * a curved segment is consided flat enough for being approximated by
55
 * a single straight line. Flatness is defined as the maximal distance
56
 * of a curve control point to the straight line that connects the
57
 * curve start and end. A lower flatness threshold means a closer
58
 * approximation.  See {@link QuadCurve2D#getFlatness()} and {@link
59
 * CubicCurve2D#getFlatness()} for drawings which illustrate the
60
 * meaning of flatness.</li>
61
 *
62
 * <li>The <i>recursion limit</i> imposes an upper bound for how often
63
 * a curved segment gets subdivided. A limit of <i>n</i> means that
64
 * for each individual quadratic and cubic B&#xe9;zier spline
65
 * segment, at most 2<sup><small><i>n</i></small></sup> {@link
66
 * PathIterator#SEG_LINETO} segments will be created.</li></ul>
67
 *
68
 * <p><b>Memory Efficiency:</b> The memory consumption grows linearly
69
 * with the recursion limit. Neither the <i>flatness</i> parameter nor
70
 * the number of segments in the flattened path will affect the memory
71
 * consumption.
72
 *
73
 * <p><b>Thread Safety:</b> Multiple threads can safely work on
74
 * separate instances of this class. However, multiple threads should
75
 * not concurrently access the same instance, as no synchronization is
76
 * performed.
77
 *
78
 * @see <a href="doc-files/FlatteningPathIterator-1.html"
79
 * >Implementation Note</a>
80
 *
81
 * @author Sascha Brawer (brawer@dandelis.ch)
82
 *
83
 * @since 1.2
84
 */
85
public class FlatteningPathIterator
86
  implements PathIterator
87
{
88
  /**
89
   * The PathIterator whose curved segments are being approximated.
90
   */
91
  private final PathIterator srcIter;
92
 
93
 
94
  /**
95
   * The square of the flatness threshold value, which determines when
96
   * a curve segment is considered flat enough that no further
97
   * subdivision is needed.
98
   *
99
   * <p>Calculating flatness actually produces the squared flatness
100
   * value. To avoid the relatively expensive calculation of a square
101
   * root for each curve segment, we perform all flatness comparisons
102
   * on squared values.
103
   *
104
   * @see QuadCurve2D#getFlatnessSq()
105
   * @see CubicCurve2D#getFlatnessSq()
106
   */
107
  private final double flatnessSq;
108
 
109
 
110
  /**
111
   * The maximal number of subdivions that are performed to
112
   * approximate a quadratic or cubic curve segment.
113
   */
114
  private final int recursionLimit;
115
 
116
 
117
  /**
118
   * A stack for holding the coordinates of subdivided segments.
119
   *
120
   * @see <a href="doc-files/FlatteningPathIterator-1.html"
121
   * >Implementation Note</a>
122
   */
123
  private double[] stack;
124
 
125
 
126
  /**
127
   * The current stack size.
128
   *
129
   * @see <a href="doc-files/FlatteningPathIterator-1.html"
130
   * >Implementation Note</a>
131
   */
132
  private int stackSize;
133
 
134
 
135
  /**
136
   * The number of recursions that were performed to arrive at
137
   * a segment on the stack.
138
   *
139
   * @see <a href="doc-files/FlatteningPathIterator-1.html"
140
   * >Implementation Note</a>
141
   */
142
  private int[] recLevel;
143
 
144
 
145
 
146
  private final double[] scratch = new double[6];
147
 
148
 
149
  /**
150
   * The segment type of the last segment that was returned by
151
   * the source iterator.
152
   */
153
  private int srcSegType;
154
 
155
 
156
  /**
157
   * The current <i>x</i> position of the source iterator.
158
   */
159
  private double srcPosX;
160
 
161
 
162
  /**
163
   * The current <i>y</i> position of the source iterator.
164
   */
165
  private double srcPosY;
166
 
167
 
168
  /**
169
   * A flag that indicates when this path iterator has finished its
170
   * iteration over path segments.
171
   */
172
  private boolean done;
173
 
174
 
175
  /**
176
   * Constructs a new PathIterator for approximating an input
177
   * PathIterator with straight lines. The approximation works by
178
   * recursive subdivisons, until the specified flatness threshold is
179
   * not exceeded.
180
   *
181
   * <p>There will not be more than 10 nested recursion steps, which
182
   * means that a single <code>SEG_QUADTO</code> or
183
   * <code>SEG_CUBICTO</code> segment is approximated by at most
184
   * 2<sup><small>10</small></sup> = 1024 straight lines.
185
   */
186
  public FlatteningPathIterator(PathIterator src, double flatness)
187
  {
188
    this(src, flatness, 10);
189
  }
190
 
191
 
192
  /**
193
   * Constructs a new PathIterator for approximating an input
194
   * PathIterator with straight lines. The approximation works by
195
   * recursive subdivisons, until the specified flatness threshold is
196
   * not exceeded.  Additionally, the number of recursions is also
197
   * bound by the specified recursion limit.
198
   */
199
  public FlatteningPathIterator(PathIterator src, double flatness,
200
                                int limit)
201
  {
202
    if (flatness < 0 || limit < 0)
203
      throw new IllegalArgumentException();
204
 
205
    srcIter = src;
206
    flatnessSq = flatness * flatness;
207
    recursionLimit = limit;
208
    fetchSegment();
209
  }
210
 
211
 
212
  /**
213
   * Returns the maximally acceptable flatness.
214
   *
215
   * @see QuadCurve2D#getFlatness()
216
   * @see CubicCurve2D#getFlatness()
217
   */
218
  public double getFlatness()
219
  {
220
    return Math.sqrt(flatnessSq);
221
  }
222
 
223
 
224
  /**
225
   * Returns the maximum number of recursive curve subdivisions.
226
   */
227
  public int getRecursionLimit()
228
  {
229
    return recursionLimit;
230
  }
231
 
232
 
233
  // Documentation will be copied from PathIterator.
234
  public int getWindingRule()
235
  {
236
    return srcIter.getWindingRule();
237
  }
238
 
239
 
240
  // Documentation will be copied from PathIterator.
241
  public boolean isDone()
242
  {
243
    return done;
244
  }
245
 
246
 
247
  // Documentation will be copied from PathIterator.
248
  public void next()
249
  {
250
    if (stackSize > 0)
251
    {
252
      --stackSize;
253
      if (stackSize > 0)
254
      {
255
        switch (srcSegType)
256
        {
257
        case PathIterator.SEG_QUADTO:
258
          subdivideQuadratic();
259
          return;
260
 
261
        case PathIterator.SEG_CUBICTO:
262
          subdivideCubic();
263
          return;
264
 
265
        default:
266
          throw new IllegalStateException();
267
        }
268
      }
269
    }
270
 
271
    srcIter.next();
272
    fetchSegment();
273
  }
274
 
275
 
276
  // Documentation will be copied from PathIterator.
277
  public int currentSegment(double[] coords)
278
  {
279
    if (done)
280
      throw new NoSuchElementException();
281
 
282
    switch (srcSegType)
283
    {
284
    case PathIterator.SEG_CLOSE:
285
      return srcSegType;
286
 
287
    case PathIterator.SEG_MOVETO:
288
    case PathIterator.SEG_LINETO:
289
      coords[0] = srcPosX;
290
      coords[1] = srcPosY;
291
      return srcSegType;
292
 
293
    case PathIterator.SEG_QUADTO:
294
      if (stackSize == 0)
295
      {
296
        coords[0] = srcPosX;
297
        coords[1] = srcPosY;
298
      }
299
      else
300
      {
301
        int sp = stack.length - 4 * stackSize;
302
        coords[0] = stack[sp + 2];
303
        coords[1] = stack[sp + 3];
304
      }
305
      return PathIterator.SEG_LINETO;
306
 
307
    case PathIterator.SEG_CUBICTO:
308
      if (stackSize == 0)
309
      {
310
        coords[0] = srcPosX;
311
        coords[1] = srcPosY;
312
      }
313
      else
314
      {
315
        int sp = stack.length - 6 * stackSize;
316
        coords[0] = stack[sp + 4];
317
        coords[1] = stack[sp + 5];
318
      }
319
      return PathIterator.SEG_LINETO;
320
    }
321
 
322
    throw new IllegalStateException();
323
  }
324
 
325
 
326
  // Documentation will be copied from PathIterator.
327
  public int currentSegment(float[] coords)
328
  {
329
    if (done)
330
      throw new NoSuchElementException();
331
 
332
    switch (srcSegType)
333
    {
334
    case PathIterator.SEG_CLOSE:
335
      return srcSegType;
336
 
337
    case PathIterator.SEG_MOVETO:
338
    case PathIterator.SEG_LINETO:
339
      coords[0] = (float) srcPosX;
340
      coords[1] = (float) srcPosY;
341
      return srcSegType;
342
 
343
    case PathIterator.SEG_QUADTO:
344
      if (stackSize == 0)
345
      {
346
        coords[0] = (float) srcPosX;
347
        coords[1] = (float) srcPosY;
348
      }
349
      else
350
      {
351
        int sp = stack.length - 4 * stackSize;
352
        coords[0] = (float) stack[sp + 2];
353
        coords[1] = (float) stack[sp + 3];
354
      }
355
      return PathIterator.SEG_LINETO;
356
 
357
    case PathIterator.SEG_CUBICTO:
358
      if (stackSize == 0)
359
      {
360
        coords[0] = (float) srcPosX;
361
        coords[1] = (float) srcPosY;
362
      }
363
      else
364
      {
365
        int sp = stack.length - 6 * stackSize;
366
        coords[0] = (float) stack[sp + 4];
367
        coords[1] = (float) stack[sp + 5];
368
      }
369
      return PathIterator.SEG_LINETO;
370
    }
371
 
372
    throw new IllegalStateException();
373
  }
374
 
375
 
376
  /**
377
   * Fetches the next segment from the source iterator.
378
   */
379
  private void fetchSegment()
380
  {
381
    int sp;
382
 
383
    if (srcIter.isDone())
384
    {
385
      done = true;
386
      return;
387
    }
388
 
389
    srcSegType = srcIter.currentSegment(scratch);
390
 
391
    switch (srcSegType)
392
    {
393
    case PathIterator.SEG_CLOSE:
394
      return;
395
 
396
    case PathIterator.SEG_MOVETO:
397
    case PathIterator.SEG_LINETO:
398
      srcPosX = scratch[0];
399
      srcPosY = scratch[1];
400
      return;
401
 
402
    case PathIterator.SEG_QUADTO:
403
      if (recursionLimit == 0)
404
      {
405
        srcPosX = scratch[2];
406
        srcPosY = scratch[3];
407
        stackSize = 0;
408
        return;
409
      }
410
      sp = 4 * recursionLimit;
411
      stackSize = 1;
412
      if (stack == null)
413
      {
414
        stack = new double[sp + /* 4 + 2 */ 6];
415
        recLevel = new int[recursionLimit + 1];
416
      }
417
      recLevel[0] = 0;
418
      stack[sp] = srcPosX;                  // P1.x
419
      stack[sp + 1] = srcPosY;              // P1.y
420
      stack[sp + 2] = scratch[0];           // C.x
421
      stack[sp + 3] = scratch[1];           // C.y
422
      srcPosX = stack[sp + 4] = scratch[2]; // P2.x
423
      srcPosY = stack[sp + 5] = scratch[3]; // P2.y
424
      subdivideQuadratic();
425
      break;
426
 
427
    case PathIterator.SEG_CUBICTO:
428
      if (recursionLimit == 0)
429
      {
430
        srcPosX = scratch[4];
431
        srcPosY = scratch[5];
432
        stackSize = 0;
433
        return;
434
      }
435
      sp = 6 * recursionLimit;
436
      stackSize = 1;
437
      if ((stack == null) || (stack.length < sp + 8))
438
      {
439
        stack = new double[sp + /* 6 + 2 */ 8];
440
        recLevel = new int[recursionLimit + 1];
441
      }
442
      recLevel[0] = 0;
443
      stack[sp] = srcPosX;                  // P1.x
444
      stack[sp + 1] = srcPosY;              // P1.y
445
      stack[sp + 2] = scratch[0];           // C1.x
446
      stack[sp + 3] = scratch[1];           // C1.y
447
      stack[sp + 4] = scratch[2];           // C2.x
448
      stack[sp + 5] = scratch[3];           // C2.y
449
      srcPosX = stack[sp + 6] = scratch[4]; // P2.x
450
      srcPosY = stack[sp + 7] = scratch[5]; // P2.y
451
      subdivideCubic();
452
      return;
453
    }
454
  }
455
 
456
 
457
  /**
458
   * Repeatedly subdivides the quadratic curve segment that is on top
459
   * of the stack. The iteration terminates when the recursion limit
460
   * has been reached, or when the resulting segment is flat enough.
461
   */
462
  private void subdivideQuadratic()
463
  {
464
    int sp;
465
    int level;
466
 
467
    sp = stack.length - 4 * stackSize - 2;
468
    level = recLevel[stackSize - 1];
469
    while ((level < recursionLimit)
470
           && (QuadCurve2D.getFlatnessSq(stack, sp) >= flatnessSq))
471
    {
472
      recLevel[stackSize] = recLevel[stackSize - 1] = ++level;
473
      QuadCurve2D.subdivide(stack, sp, stack, sp - 4, stack, sp);
474
      ++stackSize;
475
      sp -= 4;
476
    }
477
  }
478
 
479
 
480
  /**
481
   * Repeatedly subdivides the cubic curve segment that is on top
482
   * of the stack. The iteration terminates when the recursion limit
483
   * has been reached, or when the resulting segment is flat enough.
484
   */
485
  private void subdivideCubic()
486
  {
487
    int sp;
488
    int level;
489
 
490
    sp = stack.length - 6 * stackSize - 2;
491
    level = recLevel[stackSize - 1];
492
    while ((level < recursionLimit)
493
           && (CubicCurve2D.getFlatnessSq(stack, sp) >= flatnessSq))
494
    {
495
      recLevel[stackSize] = recLevel[stackSize - 1] = ++level;
496
 
497
      CubicCurve2D.subdivide(stack, sp, stack, sp - 6, stack, sp);
498
      ++stackSize;
499
      sp -= 6;
500
    }
501
  }
502
 
503
 
504
  /* These routines were useful for debugging. Since they would
505
   * just bloat the implementation, they are commented out.
506
   *
507
   *
508
 
509
  private static String segToString(int segType, double[] d, int offset)
510
  {
511
    String s;
512
 
513
    switch (segType)
514
    {
515
    case PathIterator.SEG_CLOSE:
516
      return "SEG_CLOSE";
517
 
518
    case PathIterator.SEG_MOVETO:
519
      return "SEG_MOVETO (" + d[offset] + ", " + d[offset + 1] + ")";
520
 
521
    case PathIterator.SEG_LINETO:
522
      return "SEG_LINETO (" + d[offset] + ", " + d[offset + 1] + ")";
523
 
524
    case PathIterator.SEG_QUADTO:
525
      return "SEG_QUADTO (" + d[offset] + ", " + d[offset + 1]
526
        + ") (" + d[offset + 2] + ", " + d[offset + 3] + ")";
527
 
528
    case PathIterator.SEG_CUBICTO:
529
      return "SEG_CUBICTO (" + d[offset] + ", " + d[offset + 1]
530
        + ") (" + d[offset + 2] + ", " + d[offset + 3]
531
        + ") (" + d[offset + 4] + ", " + d[offset + 5] + ")";
532
    }
533
 
534
    throw new IllegalStateException();
535
  }
536
 
537
 
538
  private void dumpQuadraticStack(String msg)
539
  {
540
    int sp = stack.length - 4 * stackSize - 2;
541
    int i = 0;
542
    System.err.print("    " + msg + ":");
543
    while (sp < stack.length)
544
    {
545
      System.err.print(" (" + stack[sp] + ", " + stack[sp+1] + ")");
546
      if (i < recLevel.length)
547
        System.out.print("/" + recLevel[i++]);
548
      if (sp + 3 < stack.length)
549
        System.err.print(" [" + stack[sp+2] + ", " + stack[sp+3] + "]");
550
      sp += 4;
551
    }
552
    System.err.println();
553
  }
554
 
555
 
556
  private void dumpCubicStack(String msg)
557
  {
558
    int sp = stack.length - 6 * stackSize - 2;
559
    int i = 0;
560
    System.err.print("    " + msg + ":");
561
    while (sp < stack.length)
562
    {
563
      System.err.print(" (" + stack[sp] + ", " + stack[sp+1] + ")");
564
      if (i < recLevel.length)
565
        System.out.print("/" + recLevel[i++]);
566
      if (sp + 3 < stack.length)
567
      {
568
        System.err.print(" [" + stack[sp+2] + ", " + stack[sp+3] + "]");
569
        System.err.print(" [" + stack[sp+4] + ", " + stack[sp+5] + "]");
570
      }
571
      sp += 6;
572
    }
573
    System.err.println();
574
  }
575
 
576
  *
577
  *
578
  */
579
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.