Source Code Cross Referenced for Area.java in  » 6.0-JDK-Core » AWT » java » awt » geom » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Home
Java Source Code / Java Documentation
1.6.0 JDK Core
2.6.0 JDK Modules
3.6.0 JDK Modules com.sun
4.6.0 JDK Modules com.sun.java
5.6.0 JDK Modules sun
6.6.0 JDK Platform
7.Ajax
8.Apache Harmony Java SE
9.Aspect oriented
10.Authentication Authorization
11.Blogger System
12.Build
13.Byte Code
14.Cache
15.Chart
16.Chat
17.Code Analyzer
18.Collaboration
19.Content Management System
20.Database Client
21.Database DBMS
22.Database JDBC Connection Pool
23.Database ORM
24.Development
25.EJB Server
26.ERP CRM Financial
27.ESB
28.Forum
29.Game
30.GIS
31.Graphic 3D
32.Graphic Library
33.Groupware
34.HTML Parser
35.IDE
36.IDE Eclipse
37.IDE Netbeans
38.Installer
39.Internationalization Localization
40.Inversion of Control
41.Issue Tracking
42.J2EE
43.J2ME
44.JBoss
45.JMS
46.JMX
47.Library
48.Mail Clients
49.Music
50.Net
51.Parser
52.PDF
53.Portal
54.Profiler
55.Project Management
56.Report
57.RSS RDF
58.Rule Engine
59.Science
60.Scripting
61.Search Engine
62.Security
63.Sevlet Container
64.Source Control
65.Swing Library
66.Template Engine
67.Test Coverage
68.Testing
69.UML
70.Web Crawler
71.Web Framework
72.Web Mail
73.Web Server
74.Web Services
75.Web Services apache cxf 2.2.6
76.Web Services AXIS2
77.Wiki Engine
78.Workflow Engines
79.XML
80.XML UI
Java Source Code / Java Documentation » 6.0 JDK Core » AWT » java.awt.geom 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001        /*
002         * Copyright 1998-2006 Sun Microsystems, Inc.  All Rights Reserved.
003         * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004         *
005         * This code is free software; you can redistribute it and/or modify it
006         * under the terms of the GNU General Public License version 2 only, as
007         * published by the Free Software Foundation.  Sun designates this
008         * particular file as subject to the "Classpath" exception as provided
009         * by Sun in the LICENSE file that accompanied this code.
010         *
011         * This code is distributed in the hope that it will be useful, but WITHOUT
012         * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013         * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
014         * version 2 for more details (a copy is included in the LICENSE file that
015         * accompanied this code).
016         *
017         * You should have received a copy of the GNU General Public License version
018         * 2 along with this work; if not, write to the Free Software Foundation,
019         * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020         *
021         * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022         * CA 95054 USA or visit www.sun.com if you need additional information or
023         * have any questions.
024         */
025
026        package java.awt.geom;
027
028        import java.awt.Shape;
029        import java.awt.Rectangle;
030        import java.util.Vector;
031        import java.util.Enumeration;
032        import java.util.NoSuchElementException;
033        import sun.awt.geom.Curve;
034        import sun.awt.geom.Crossings;
035        import sun.awt.geom.AreaOp;
036
037        /**
038         * An <code>Area</code> object stores and manipulates a
039         * resolution-independent description of an enclosed area of
040         * 2-dimensional space.
041         * <code>Area</code> objects can be transformed and can perform
042         * various Constructive Area Geometry (CAG) operations when combined
043         * with other <code>Area</code> objects.
044         * The CAG operations include area
045         * {@link #add addition}, {@link #subtract subtraction},
046         * {@link #intersect intersection}, and {@link #exclusiveOr exclusive or}.
047         * See the linked method documentation for examples of the various
048         * operations.
049         * <p>
050         * The <code>Area</code> class implements the <code>Shape</code>
051         * interface and provides full support for all of its hit-testing
052         * and path iteration facilities, but an <code>Area</code> is more
053         * specific than a generalized path in a number of ways:
054         * <ul>
055         * <li>Only closed paths and sub-paths are stored.
056         *     <code>Area</code> objects constructed from unclosed paths
057         *     are implicitly closed during construction as if those paths
058         *     had been filled by the <code>Graphics2D.fill</code> method.
059         * <li>The interiors of the individual stored sub-paths are all
060         *     non-empty and non-overlapping.  Paths are decomposed during
061         *     construction into separate component non-overlapping parts,
062         *     empty pieces of the path are discarded, and then these
063         *     non-empty and non-overlapping properties are maintained
064         *     through all subsequent CAG operations.  Outlines of different
065         *     component sub-paths may touch each other, as long as they
066         *     do not cross so that their enclosed areas overlap.
067         * <li>The geometry of the path describing the outline of the
068         *     <code>Area</code> resembles the path from which it was
069         *     constructed only in that it describes the same enclosed
070         *     2-dimensional area, but may use entirely different types
071         *     and ordering of the path segments to do so.
072         * </ul>
073         * Interesting issues which are not always obvious when using
074         * the <code>Area</code> include:
075         * <ul>
076         * <li>Creating an <code>Area</code> from an unclosed (open)
077         *     <code>Shape</code> results in a closed outline in the
078         *     <code>Area</code> object.
079         * <li>Creating an <code>Area</code> from a <code>Shape</code>
080         *     which encloses no area (even when "closed") produces an
081         *     empty <code>Area</code>.  A common example of this issue
082         *     is that producing an <code>Area</code> from a line will
083         *     be empty since the line encloses no area.  An empty
084         *     <code>Area</code> will iterate no geometry in its
085         *     <code>PathIterator</code> objects.
086         * <li>A self-intersecting <code>Shape</code> may be split into
087         *     two (or more) sub-paths each enclosing one of the
088         *     non-intersecting portions of the original path.
089         * <li>An <code>Area</code> may take more path segments to
090         *     describe the same geometry even when the original
091         *     outline is simple and obvious.  The analysis that the
092         *     <code>Area</code> class must perform on the path may
093         *     not reflect the same concepts of "simple and obvious"
094         *     as a human being perceives.
095         * </ul>
096         *
097         * @since 1.2
098         */
099        public class Area implements  Shape, Cloneable {
100            private static Vector EmptyCurves = new Vector();
101
102            private Vector curves;
103
104            /**
105             * Default constructor which creates an empty area.
106             * @since 1.2
107             */
108            public Area() {
109                curves = EmptyCurves;
110            }
111
112            /**
113             * The <code>Area</code> class creates an area geometry from the
114             * specified {@link Shape} object.  The geometry is explicitly
115             * closed, if the <code>Shape</code> is not already closed.  The
116             * fill rule (even-odd or winding) specified by the geometry of the
117             * <code>Shape</code> is used to determine the resulting enclosed area.
118             * @param s  the <code>Shape</code> from which the area is constructed
119             * @throws NullPointerException if <code>s</code> is null
120             * @since 1.2
121             */
122            public Area(Shape s) {
123                if (s instanceof  Area) {
124                    curves = ((Area) s).curves;
125                } else {
126                    curves = pathToCurves(s.getPathIterator(null));
127                }
128            }
129
130            private static Vector pathToCurves(PathIterator pi) {
131                Vector curves = new Vector();
132                int windingRule = pi.getWindingRule();
133                // coords array is big enough for holding:
134                //     coordinates returned from currentSegment (6)
135                //     OR
136                //         two subdivided quadratic curves (2+4+4=10)
137                //         AND
138                //             0-1 horizontal splitting parameters
139                //             OR
140                //             2 parametric equation derivative coefficients
141                //     OR
142                //         three subdivided cubic curves (2+6+6+6=20)
143                //         AND
144                //             0-2 horizontal splitting parameters
145                //             OR
146                //             3 parametric equation derivative coefficients
147                double coords[] = new double[23];
148                double movx = 0, movy = 0;
149                double curx = 0, cury = 0;
150                double newx, newy;
151                while (!pi.isDone()) {
152                    switch (pi.currentSegment(coords)) {
153                    case PathIterator.SEG_MOVETO:
154                        Curve.insertLine(curves, curx, cury, movx, movy);
155                        curx = movx = coords[0];
156                        cury = movy = coords[1];
157                        Curve.insertMove(curves, movx, movy);
158                        break;
159                    case PathIterator.SEG_LINETO:
160                        newx = coords[0];
161                        newy = coords[1];
162                        Curve.insertLine(curves, curx, cury, newx, newy);
163                        curx = newx;
164                        cury = newy;
165                        break;
166                    case PathIterator.SEG_QUADTO:
167                        newx = coords[2];
168                        newy = coords[3];
169                        Curve.insertQuad(curves, curx, cury, coords);
170                        curx = newx;
171                        cury = newy;
172                        break;
173                    case PathIterator.SEG_CUBICTO:
174                        newx = coords[4];
175                        newy = coords[5];
176                        Curve.insertCubic(curves, curx, cury, coords);
177                        curx = newx;
178                        cury = newy;
179                        break;
180                    case PathIterator.SEG_CLOSE:
181                        Curve.insertLine(curves, curx, cury, movx, movy);
182                        curx = movx;
183                        cury = movy;
184                        break;
185                    }
186                    pi.next();
187                }
188                Curve.insertLine(curves, curx, cury, movx, movy);
189                AreaOp operator;
190                if (windingRule == PathIterator.WIND_EVEN_ODD) {
191                    operator = new AreaOp.EOWindOp();
192                } else {
193                    operator = new AreaOp.NZWindOp();
194                }
195                return operator.calculate(curves, EmptyCurves);
196            }
197
198            /**
199             * Adds the shape of the specified <code>Area</code> to the
200             * shape of this <code>Area</code>.
201             * The resulting shape of this <code>Area</code> will include
202             * the union of both shapes, or all areas that were contained
203             * in either this or the specified <code>Area</code>.
204             * <pre>
205             *     // Example:
206             *     Area a1 = new Area([triangle 0,0 =&gt; 8,0 =&gt; 0,8]);
207             *     Area a2 = new Area([triangle 0,0 =&gt; 8,0 =&gt; 8,8]);
208             *     a1.add(a2);
209             *
210             *        a1(before)     +         a2         =     a1(after)
211             *
212             *     ################     ################     ################
213             *     ##############         ##############     ################
214             *     ############             ############     ################
215             *     ##########                 ##########     ################
216             *     ########                     ########     ################
217             *     ######                         ######     ######    ######
218             *     ####                             ####     ####        ####
219             *     ##                                 ##     ##            ##
220             * </pre>
221             * @param   rhs  the <code>Area</code> to be added to the
222             *          current shape
223             * @throws NullPointerException if <code>rhs</code> is null
224             * @since 1.2
225             */
226            public void add(Area rhs) {
227                curves = new AreaOp.AddOp().calculate(this .curves, rhs.curves);
228                invalidateBounds();
229            }
230
231            /**
232             * Subtracts the shape of the specified <code>Area</code> from the 
233             * shape of this <code>Area</code>.
234             * The resulting shape of this <code>Area</code> will include
235             * areas that were contained only in this <code>Area</code>
236             * and not in the specified <code>Area</code>.
237             * <pre>
238             *     // Example:
239             *     Area a1 = new Area([triangle 0,0 =&gt; 8,0 =&gt; 0,8]);
240             *     Area a2 = new Area([triangle 0,0 =&gt; 8,0 =&gt; 8,8]);
241             *     a1.subtract(a2);
242             *
243             *        a1(before)     -         a2         =     a1(after)
244             *
245             *     ################     ################
246             *     ##############         ##############     ##
247             *     ############             ############     ####
248             *     ##########                 ##########     ######
249             *     ########                     ########     ########
250             *     ######                         ######     ######
251             *     ####                             ####     ####
252             *     ##                                 ##     ##
253             * </pre>
254             * @param   rhs  the <code>Area</code> to be subtracted from the 
255             *		current shape
256             * @throws NullPointerException if <code>rhs</code> is null
257             * @since 1.2
258             */
259            public void subtract(Area rhs) {
260                curves = new AreaOp.SubOp().calculate(this .curves, rhs.curves);
261                invalidateBounds();
262            }
263
264            /**
265             * Sets the shape of this <code>Area</code> to the intersection of 
266             * its current shape and the shape of the specified <code>Area</code>.
267             * The resulting shape of this <code>Area</code> will include
268             * only areas that were contained in both this <code>Area</code>
269             * and also in the specified <code>Area</code>.
270             * <pre>
271             *     // Example:
272             *     Area a1 = new Area([triangle 0,0 =&gt; 8,0 =&gt; 0,8]);
273             *     Area a2 = new Area([triangle 0,0 =&gt; 8,0 =&gt; 8,8]);
274             *     a1.intersect(a2);
275             *
276             *      a1(before)   intersect     a2         =     a1(after)
277             *
278             *     ################     ################     ################
279             *     ##############         ##############       ############
280             *     ############             ############         ########
281             *     ##########                 ##########           ####
282             *     ########                     ########
283             *     ######                         ######
284             *     ####                             ####
285             *     ##                                 ##
286             * </pre>
287             * @param   rhs  the <code>Area</code> to be intersected with this
288             *		<code>Area</code>
289             * @throws NullPointerException if <code>rhs</code> is null
290             * @since 1.2
291             */
292            public void intersect(Area rhs) {
293                curves = new AreaOp.IntOp().calculate(this .curves, rhs.curves);
294                invalidateBounds();
295            }
296
297            /**
298             * Sets the shape of this <code>Area</code> to be the combined area
299             * of its current shape and the shape of the specified <code>Area</code>, 
300             * minus their intersection.
301             * The resulting shape of this <code>Area</code> will include
302             * only areas that were contained in either this <code>Area</code>
303             * or in the specified <code>Area</code>, but not in both.
304             * <pre>
305             *     // Example:
306             *     Area a1 = new Area([triangle 0,0 =&gt; 8,0 =&gt; 0,8]);
307             *     Area a2 = new Area([triangle 0,0 =&gt; 8,0 =&gt; 8,8]);
308             *     a1.exclusiveOr(a2);
309             *
310             *        a1(before)    xor        a2         =     a1(after)
311             *
312             *     ################     ################
313             *     ##############         ##############     ##            ##
314             *     ############             ############     ####        ####
315             *     ##########                 ##########     ######    ######
316             *     ########                     ########     ################
317             *     ######                         ######     ######    ######
318             *     ####                             ####     ####        ####
319             *     ##                                 ##     ##            ##
320             * </pre>
321             * @param   rhs  the <code>Area</code> to be exclusive ORed with this 
322             *		<code>Area</code>.
323             * @throws NullPointerException if <code>rhs</code> is null
324             * @since 1.2
325             */
326            public void exclusiveOr(Area rhs) {
327                curves = new AreaOp.XorOp().calculate(this .curves, rhs.curves);
328                invalidateBounds();
329            }
330
331            /**
332             * Removes all of the geometry from this <code>Area</code> and
333             * restores it to an empty area.
334             * @since 1.2
335             */
336            public void reset() {
337                curves = new Vector();
338                invalidateBounds();
339            }
340
341            /**
342             * Tests whether this <code>Area</code> object encloses any area.
343             * @return    <code>true</code> if this <code>Area</code> object
344             * represents an empty area; <code>false</code> otherwise.
345             * @since 1.2
346             */
347            public boolean isEmpty() {
348                return (curves.size() == 0);
349            }
350
351            /**
352             * Tests whether this <code>Area</code> consists entirely of
353             * straight edged polygonal geometry.
354             * @return    <code>true</code> if the geometry of this
355             * <code>Area</code> consists entirely of line segments;
356             * <code>false</code> otherwise.
357             * @since 1.2
358             */
359            public boolean isPolygonal() {
360                Enumeration enum_ = curves.elements();
361                while (enum_.hasMoreElements()) {
362                    if (((Curve) enum_.nextElement()).getOrder() > 1) {
363                        return false;
364                    }
365                }
366                return true;
367            }
368
369            /**
370             * Tests whether this <code>Area</code> is rectangular in shape.
371             * @return    <code>true</code> if the geometry of this
372             * <code>Area</code> is rectangular in shape; <code>false</code>
373             * otherwise.
374             * @since 1.2
375             */
376            public boolean isRectangular() {
377                int size = curves.size();
378                if (size == 0) {
379                    return true;
380                }
381                if (size > 3) {
382                    return false;
383                }
384                Curve c1 = (Curve) curves.get(1);
385                Curve c2 = (Curve) curves.get(2);
386                if (c1.getOrder() != 1 || c2.getOrder() != 1) {
387                    return false;
388                }
389                if (c1.getXTop() != c1.getXBot()
390                        || c2.getXTop() != c2.getXBot()) {
391                    return false;
392                }
393                if (c1.getYTop() != c2.getYTop()
394                        || c1.getYBot() != c2.getYBot()) {
395                    // One might be able to prove that this is impossible...
396                    return false;
397                }
398                return true;
399            }
400
401            /**
402             * Tests whether this <code>Area</code> is comprised of a single
403             * closed subpath.  This method returns <code>true</code> if the 
404             * path contains 0 or 1 subpaths, or <code>false</code> if the path
405             * contains more than 1 subpath.  The subpaths are counted by the 
406             * number of {@link PathIterator#SEG_MOVETO SEG_MOVETO}  segments 
407             * that appear in the path.
408             * @return    <code>true</code> if the <code>Area</code> is comprised
409             * of a single basic geometry; <code>false</code> otherwise.
410             * @since 1.2
411             */
412            public boolean isSingular() {
413                if (curves.size() < 3) {
414                    return true;
415                }
416                Enumeration enum_ = curves.elements();
417                enum_.nextElement(); // First Order0 "moveto"
418                while (enum_.hasMoreElements()) {
419                    if (((Curve) enum_.nextElement()).getOrder() == 0) {
420                        return false;
421                    }
422                }
423                return true;
424            }
425
426            private Rectangle2D cachedBounds;
427
428            private void invalidateBounds() {
429                cachedBounds = null;
430            }
431
432            private Rectangle2D getCachedBounds() {
433                if (cachedBounds != null) {
434                    return cachedBounds;
435                }
436                Rectangle2D r = new Rectangle2D.Double();
437                if (curves.size() > 0) {
438                    Curve c = (Curve) curves.get(0);
439                    // First point is always an order 0 curve (moveto)
440                    r.setRect(c.getX0(), c.getY0(), 0, 0);
441                    for (int i = 1; i < curves.size(); i++) {
442                        ((Curve) curves.get(i)).enlarge(r);
443                    }
444                }
445                return (cachedBounds = r);
446            }
447
448            /**
449             * Returns a high precision bounding {@link Rectangle2D} that
450             * completely encloses this <code>Area</code>.
451             * <p>
452             * The Area class will attempt to return the tightest bounding
453             * box possible for the Shape.  The bounding box will not be
454             * padded to include the control points of curves in the outline
455             * of the Shape, but should tightly fit the actual geometry of
456             * the outline itself.
457             * @return    the bounding <code>Rectangle2D</code> for the
458             * <code>Area</code>.
459             * @since 1.2
460             */
461            public Rectangle2D getBounds2D() {
462                return getCachedBounds().getBounds2D();
463            }
464
465            /**
466             * Returns a bounding {@link Rectangle} that completely encloses
467             * this <code>Area</code>.
468             * <p>
469             * The Area class will attempt to return the tightest bounding
470             * box possible for the Shape.  The bounding box will not be
471             * padded to include the control points of curves in the outline
472             * of the Shape, but should tightly fit the actual geometry of
473             * the outline itself.  Since the returned object represents
474             * the bounding box with integers, the bounding box can only be
475             * as tight as the nearest integer coordinates that encompass
476             * the geometry of the Shape.
477             * @return    the bounding <code>Rectangle</code> for the
478             * <code>Area</code>.
479             * @since 1.2
480             */
481            public Rectangle getBounds() {
482                return getCachedBounds().getBounds();
483            }
484
485            /**
486             * Returns an exact copy of this <code>Area</code> object.
487             * @return    Created clone object
488             * @since 1.2
489             */
490            public Object clone() {
491                return new Area(this );
492            }
493
494            /**
495             * Tests whether the geometries of the two <code>Area</code> objects
496             * are equal.
497             * This method will return false if the argument is null.
498             * @param   other  the <code>Area</code> to be compared to this
499             *		<code>Area</code>
500             * @return  <code>true</code> if the two geometries are equal;
501             *		<code>false</code> otherwise.
502             * @since 1.2
503             */
504            public boolean equals(Area other) {
505                // REMIND: A *much* simpler operation should be possible...
506                // Should be able to do a curve-wise comparison since all Areas
507                // should evaluate their curves in the same top-down order.
508                if (other == this ) {
509                    return true;
510                }
511                if (other == null) {
512                    return false;
513                }
514                Vector c = new AreaOp.XorOp().calculate(this .curves,
515                        other.curves);
516                return c.isEmpty();
517            }
518
519            /**
520             * Transforms the geometry of this <code>Area</code> using the specified 
521             * {@link AffineTransform}.  The geometry is transformed in place, which 
522             * permanently changes the enclosed area defined by this object.
523             * @param t  the transformation used to transform the area
524             * @throws NullPointerException if <code>t</code> is null
525             * @since 1.2
526             */
527            public void transform(AffineTransform t) {
528                if (t == null) {
529                    throw new NullPointerException("transform must not be null");
530                }
531                // REMIND: A simpler operation can be performed for some types
532                // of transform.
533                curves = pathToCurves(getPathIterator(t));
534                invalidateBounds();
535            }
536
537            /**
538             * Creates a new <code>Area</code> object that contains the same
539             * geometry as this <code>Area</code> transformed by the specified
540             * <code>AffineTransform</code>.  This <code>Area</code> object 
541             * is unchanged.
542             * @param t  the specified <code>AffineTransform</code> used to transform 
543             *           the new <code>Area</code>
544             * @throws NullPointerException if <code>t</code> is null
545             * @return   a new <code>Area</code> object representing the transformed 
546             *           geometry.
547             * @since 1.2
548             */
549            public Area createTransformedArea(AffineTransform t) {
550                Area a = new Area(this );
551                a.transform(t);
552                return a;
553            }
554
555            /**
556             * {@inheritDoc}
557             * @since 1.2
558             */
559            public boolean contains(double x, double y) {
560                if (!getCachedBounds().contains(x, y)) {
561                    return false;
562                }
563                Enumeration enum_ = curves.elements();
564                int crossings = 0;
565                while (enum_.hasMoreElements()) {
566                    Curve c = (Curve) enum_.nextElement();
567                    crossings += c.crossingsFor(x, y);
568                }
569                return ((crossings & 1) == 1);
570            }
571
572            /**
573             * {@inheritDoc}
574             * @since 1.2
575             */
576            public boolean contains(Point2D p) {
577                return contains(p.getX(), p.getY());
578            }
579
580            /**
581             * {@inheritDoc}
582             * @since 1.2
583             */
584            public boolean contains(double x, double y, double w, double h) {
585                if (w < 0 || h < 0) {
586                    return false;
587                }
588                if (!getCachedBounds().contains(x, y, w, h)) {
589                    return false;
590                }
591                Crossings c = Crossings.findCrossings(curves, x, y, x + w, y
592                        + h);
593                return (c != null && c.covers(y, y + h));
594            }
595
596            /**
597             * {@inheritDoc}
598             * @since 1.2
599             */
600            public boolean contains(Rectangle2D r) {
601                return contains(r.getX(), r.getY(), r.getWidth(), r.getHeight());
602            }
603
604            /**
605             * {@inheritDoc}
606             * @since 1.2
607             */
608            public boolean intersects(double x, double y, double w, double h) {
609                if (w < 0 || h < 0) {
610                    return false;
611                }
612                if (!getCachedBounds().intersects(x, y, w, h)) {
613                    return false;
614                }
615                Crossings c = Crossings.findCrossings(curves, x, y, x + w, y
616                        + h);
617                return (c == null || !c.isEmpty());
618            }
619
620            /**
621             * {@inheritDoc}
622             * @since 1.2
623             */
624            public boolean intersects(Rectangle2D r) {
625                return intersects(r.getX(), r.getY(), r.getWidth(), r
626                        .getHeight());
627            }
628
629            /**
630             * Creates a {@link PathIterator} for the outline of this 
631             * <code>Area</code> object.  This <code>Area</code> object is unchanged.
632             * @param at an optional <code>AffineTransform</code> to be applied to
633             * the coordinates as they are returned in the iteration, or
634             * <code>null</code> if untransformed coordinates are desired
635             * @return    the <code>PathIterator</code> object that returns the 
636             *		geometry of the outline of this <code>Area</code>, one 
637             *		segment at a time.
638             * @since 1.2
639             */
640            public PathIterator getPathIterator(AffineTransform at) {
641                return new AreaIterator(curves, at);
642            }
643
644            /**
645             * Creates a <code>PathIterator</code> for the flattened outline of 
646             * this <code>Area</code> object.  Only uncurved path segments
647             * represented by the SEG_MOVETO, SEG_LINETO, and SEG_CLOSE point
648             * types are returned by the iterator.  This <code>Area</code>
649             * object is unchanged.
650             * @param at an optional <code>AffineTransform</code> to be 
651             * applied to the coordinates as they are returned in the 
652             * iteration, or <code>null</code> if untransformed coordinates 
653             * are desired
654             * @param flatness the maximum amount that the control points
655             * for a given curve can vary from colinear before a subdivided
656             * curve is replaced by a straight line connecting the end points
657             * @return    the <code>PathIterator</code> object that returns the 
658             * geometry of the outline of this <code>Area</code>, one segment
659             * at a time.
660             * @since 1.2
661             */
662            public PathIterator getPathIterator(AffineTransform at,
663                    double flatness) {
664                return new FlatteningPathIterator(getPathIterator(at), flatness);
665            }
666        }
667
668        class AreaIterator implements  PathIterator {
669            private AffineTransform transform;
670            private Vector curves;
671            private int index;
672            private Curve prevcurve;
673            private Curve this curve;
674
675            public AreaIterator(Vector curves, AffineTransform at) {
676                this .curves = curves;
677                this .transform = at;
678                if (curves.size() >= 1) {
679                    this curve = (Curve) curves.get(0);
680                }
681            }
682
683            public int getWindingRule() {
684                // REMIND: Which is better, EVEN_ODD or NON_ZERO?
685                //         The paths calculated could be classified either way.
686                //return WIND_EVEN_ODD;
687                return WIND_NON_ZERO;
688            }
689
690            public boolean isDone() {
691                return (prevcurve == null && this curve == null);
692            }
693
694            public void next() {
695                if (prevcurve != null) {
696                    prevcurve = null;
697                } else {
698                    prevcurve = this curve;
699                    index++;
700                    if (index < curves.size()) {
701                        this curve = (Curve) curves.get(index);
702                        if (this curve.getOrder() != 0
703                                && prevcurve.getX1() == this curve.getX0()
704                                && prevcurve.getY1() == this curve.getY0()) {
705                            prevcurve = null;
706                        }
707                    } else {
708                        this curve = null;
709                    }
710                }
711            }
712
713            public int currentSegment(float coords[]) {
714                double dcoords[] = new double[6];
715                int segtype = currentSegment(dcoords);
716                int numpoints = (segtype == SEG_CLOSE ? 0
717                        : (segtype == SEG_QUADTO ? 2
718                                : (segtype == SEG_CUBICTO ? 3 : 1)));
719                for (int i = 0; i < numpoints * 2; i++) {
720                    coords[i] = (float) dcoords[i];
721                }
722                return segtype;
723            }
724
725            public int currentSegment(double coords[]) {
726                int segtype;
727                int numpoints;
728                if (prevcurve != null) {
729                    // Need to finish off junction between curves
730                    if (this curve == null || this curve.getOrder() == 0) {
731                        return SEG_CLOSE;
732                    }
733                    coords[0] = this curve.getX0();
734                    coords[1] = this curve.getY0();
735                    segtype = SEG_LINETO;
736                    numpoints = 1;
737                } else if (this curve == null) {
738                    throw new NoSuchElementException(
739                            "area iterator out of bounds");
740                } else {
741                    segtype = this curve.getSegment(coords);
742                    numpoints = this curve.getOrder();
743                    if (numpoints == 0) {
744                        numpoints = 1;
745                    }
746                }
747                if (transform != null) {
748                    transform.transform(coords, 0, coords, 0, numpoints);
749                }
750                return segtype;
751            }
752        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.