Statistics
| Revision:

svn-gvsig-desktop / trunk / org.gvsig.desktop / org.gvsig.desktop.compat.cdc / org.gvsig.fmap.geometry / org.gvsig.fmap.geometry.generalpath / src / main / java / org / gvsig / fmap / geom / generalpath / gputils / DefaultGeneralPathX.java @ 41611

History | View | Annotate | Download (31.5 KB)

1
/**
2
 * gvSIG. Desktop Geographic Information System.
3
 *
4
 * Copyright (C) 2007-2013 gvSIG Association.
5
 *
6
 * This program is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU General Public License
8
 * as published by the Free Software Foundation; either version 3
9
 * of the License, or (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19
 * MA  02110-1301, USA.
20
 *
21
 * For any additional information, do not hesitate to contact us
22
 * at info AT gvsig.com, or visit our website www.gvsig.com.
23
 */
24
package org.gvsig.fmap.geom.generalpath.gputils;
25

    
26
/*
27
 * Based on portions of code from java.awt.geom.GeneralPath of the
28
 * OpenJDK project (Copyright (c) 1996, 2006, Oracle and/or its affiliates)
29
 */
30
import java.awt.Shape;
31
import java.awt.geom.AffineTransform;
32
import java.awt.geom.FlatteningPathIterator;
33
import java.awt.geom.IllegalPathStateException;
34
import java.awt.geom.PathIterator;
35
import java.awt.geom.Point2D;
36
import java.awt.geom.Rectangle2D;
37
import java.util.ArrayList;
38
import java.util.List;
39

    
40
import org.cresques.cts.ICoordTrans;
41
import org.gvsig.fmap.geom.Geometry;
42
import org.gvsig.fmap.geom.GeometryLocator;
43
import org.gvsig.fmap.geom.GeometryManager;
44
import org.gvsig.fmap.geom.exception.CreateGeometryException;
45
import org.gvsig.jdk.GeomUtilities;
46
import org.slf4j.Logger;
47
import org.slf4j.LoggerFactory;
48

    
49
import com.vividsolutions.jts.algorithm.CGAlgorithms;
50
import com.vividsolutions.jts.geom.Coordinate;
51
import com.vividsolutions.jts.geom.CoordinateList;
52
import com.vividsolutions.jts.geom.CoordinateSequences;
53
import com.vividsolutions.jts.geom.impl.CoordinateArraySequence;
54
import java.io.Serializable;
55
import org.gvsig.fmap.geom.primitive.GeneralPathX;
56
import org.gvsig.fmap.geom.primitive.IGeneralPathX;
57
import org.gvsig.fmap.geom.primitive.Point;
58
import org.gvsig.fmap.geom.generalpath.primitive.point.Point2DZ;
59

    
60
/**
61
 * The <code>GeneralPathX</code> class represents a geometric path
62
 * constructed from straight lines, and quadratic and cubic
63
 * (B&eacute;zier) curves. It can contain multiple subpaths.
64
 * <p>
65
 * The winding rule specifies how the interior of a path is determined. There
66
 * are two types of winding rules: EVEN_ODD and NON_ZERO.
67
 * <p>
68
 * An EVEN_ODD winding rule means that enclosed regions of the path alternate
69
 * between interior and exterior areas as traversed from the outside of the path
70
 * towards a point inside the region.
71
 * <p>
72
 * A NON_ZERO winding rule means that if a ray is drawn in any direction from a
73
 * given point to infinity and the places where the path intersects the ray are
74
 * examined, the point is inside of the path if and only if the number of times
75
 * that the path crosses the ray from left to right does not equal the number of
76
 * times that the path crosses the ray from right to left.
77
 * 
78
 * @version 1.58, 01/23/03
79
 * @author Jim Graham
80
 * @deprecated
81
 *             use the geometry methods
82
 */
83
public class DefaultGeneralPathX extends GeneralPathX implements  Shape, Cloneable, Serializable { 
84

    
85
    /**
86
     * Default serial version ID
87
     */
88
    private static final long serialVersionUID = 1L;
89

    
90
    private static final Logger LOG = LoggerFactory
91
        .getLogger(DefaultGeneralPathX.class);
92

    
93
    protected static GeometryManager geomManager = GeometryLocator
94
        .getGeometryManager();
95

    
96
    private List pointTypes = new ArrayList();
97
    private List pointCoords = new ArrayList();
98

    
99
    private Byte[] SEG_TYPES = new Byte[] {
100
        new Byte((byte)0),
101
        new Byte((byte)1),
102
        new Byte((byte)2),
103
        new Byte((byte)3),
104
        new Byte((byte)4),
105
        new Byte((byte)5),
106
        new Byte((byte)6),
107
        new Byte((byte)7),
108
        new Byte((byte)8),
109
        new Byte((byte)9),
110
        new Byte((byte)10)
111
    };
112
    
113
    int windingRule;
114

    
115
    private boolean isSimple = true;
116

    
117
    static final int EXPAND_MAX = 500;
118

    
119
    private  DefaultGeneralPathX() {
120
        super(false);
121
        setWindingRule(WIND_EVEN_ODD);
122
    }
123
    /**
124
     * Constructs a new <code>GeneralPathX</code> object with the specified
125
     * winding rule to control operations that require the interior of the
126
     * path to be defined.
127
     * 
128
     * @param rule
129
     *            the winding rule
130
     * @see #WIND_EVEN_ODD
131
     * @see #WIND_NON_ZERO
132
     */
133
    public DefaultGeneralPathX(int rule) {
134
        super(false);
135
        setWindingRule(rule);
136
    }
137

    
138
    /**
139
     * Constructs a new <code>GeneralPathX</code> object from an arbitrary
140
     * {@link Shape} object.
141
     * All of the initial geometry and the winding rule for this path are
142
     * taken from the specified <code>Shape</code> object.
143
     * 
144
     * @param s
145
     *            the specified <code>Shape</code> object
146
     */
147
    public DefaultGeneralPathX(PathIterator piter) {
148
        this(WIND_EVEN_ODD);
149
        setWindingRule(piter.getWindingRule());
150
        append(piter, false);
151
    }
152

    
153
    private void needRoom(int newTypes, int newCoords, boolean needMove) {
154
        if (needMove && getNumTypes() == 0) {
155
            throw new IllegalPathStateException("missing initial moveto "
156
                + "in path definition");
157
        }
158
    }
159

    
160
    /**
161
     * Adds a point to the path by moving to the specified
162
     * coordinates.
163
     * 
164
     * @param x
165
     *            ,&nbsp;y the specified coordinates
166
     * @deprecated
167
     *             use moveTo(Point)
168
     */
169
    public synchronized void moveTo(double x, double y) {
170
        int numtypes = getNumTypes();
171
        if (numtypes > 0 && getTypeAt(numtypes - 1) == SEG_MOVETO) {
172
            Point point = getPointAt(getNumCoords() - 1);
173
            point.setX(x);
174
            point.setY(y);
175
        } else {
176
            needRoom(1, 2, false);
177
            pointTypes.add(SEG_TYPES[SEG_MOVETO]);
178
            addPoint(x, y);
179
        }
180
    }
181

    
182
    public synchronized void moveTo(Point point) {
183
        int numtypes = getNumTypes();
184
        if (numtypes > 0 && getTypeAt(numtypes - 1) == SEG_MOVETO) {
185
            pointCoords.remove(getNumCoords() - 1);
186
            addPoint(point);
187
        } else {
188
            needRoom(1, 2, false);
189
            pointTypes.add(SEG_TYPES[SEG_MOVETO]);
190
            addPoint(point);
191
        }
192
    }
193

    
194
    /**
195
     * Adds a point to the path by drawing a straight line from the
196
     * current coordinates to the new specified coordinates.
197
     * 
198
     * @param x
199
     *            ,&nbsp;y the specified coordinates
200
     * @deprecated
201
     *             use lineTo(Point)
202
     */
203
    public synchronized void lineTo(double x, double y) {
204
        needRoom(1, 2, true);
205
        pointTypes.add(SEG_TYPES[SEG_LINETO]);
206
        addPoint(x, y);
207
    }
208

    
209
    public synchronized void lineTo(Point point) {
210
        needRoom(1, 2, true);
211
        pointTypes.add(SEG_TYPES[SEG_LINETO]);
212
        addPoint(point);
213
    }
214

    
215
    public synchronized void addSegment(Point[] segment) {
216
        if (segment != null && segment.length > 0) {
217
            needRoom(segment.length, 2 * segment.length, true);
218
            for (int i = 0; i < segment.length; i++) {
219
                pointTypes.add(SEG_TYPES[SEG_LINETO]);
220
                addPoint(segment[i]);
221
            }
222
        }
223
    }
224

    
225
    private void addPoint(double x, double y) {
226
        try {
227
            pointCoords.add(geomManager.createPoint(x, y,
228
                Geometry.SUBTYPES.GEOM2D));
229
        } catch (CreateGeometryException e) {
230
            LOG.error("Error creating a point", e);
231
        }
232
    }
233

    
234
    private void addPoint(Point point) {
235
        pointCoords.add(point);
236
    }
237

    
238
    /**
239
     * Adds a curved segment, defined by two new points, to the path by
240
     * drawing a Quadratic curve that intersects both the current
241
     * coordinates and the coordinates (x2,&nbsp;y2), using the
242
     * specified point (x1,&nbsp;y1) as a quadratic parametric control
243
     * point.
244
     * 
245
     * @param x1
246
     *            ,&nbsp;y1 the coordinates of the first quadratic control
247
     *            point
248
     * @param x2
249
     *            ,&nbsp;y2 the coordinates of the final endpoint
250
     * @deprecated
251
     *             use quadTo(Point, Point)
252
     */
253
    public synchronized void quadTo(double x1, double y1, double x2, double y2) {
254
        needRoom(1, 4, true);
255
        pointTypes.add(SEG_TYPES[SEG_QUADTO]);
256
        addPoint(x1, y1);
257
        addPoint(x2, y2);
258
        isSimple = false;
259
    }
260

    
261
    public synchronized void quadTo(Point point1, Point point2) {
262
        needRoom(1, 4, true);
263
        pointTypes.add(SEG_TYPES[SEG_QUADTO]);
264
        addPoint(point1);
265
        addPoint(point2);
266
        isSimple = false;
267
    }
268

    
269
    /**
270
     * Adds a curved segment, defined by three new points, to the path by
271
     * drawing a B&eacute;zier curve that intersects both the current
272
     * coordinates and the coordinates (x3,&nbsp;y3), using the
273
     * specified points (x1,&nbsp;y1) and (x2,&nbsp;y2) as
274
     * B&eacute;zier control points.
275
     * 
276
     * @param x1
277
     *            ,&nbsp;y1 the coordinates of the first B&eacute;ezier
278
     *            control point
279
     * @param x2
280
     *            ,&nbsp;y2 the coordinates of the second B&eacute;zier
281
     *            control point
282
     * @param x3
283
     *            ,&nbsp;y3 the coordinates of the final endpoint
284
     * @deprecated
285
     *             use curveTo(Point, Point, Point)
286
     */
287
    public synchronized void curveTo(double x1, double y1, double x2,
288
        double y2, double x3, double y3) {
289
        needRoom(1, 6, true);
290
        pointTypes.add(SEG_TYPES[SEG_CUBICTO]);
291
        addPoint(x1, y1);
292
        addPoint(x2, y2);
293
        addPoint(x3, y3);
294
        isSimple = false;
295
    }
296

    
297
    public synchronized void curveTo(Point point1, Point point2, Point point3) {
298
        needRoom(1, 6, true);
299
        pointTypes.add(SEG_TYPES[SEG_CUBICTO]);
300
        addPoint(point1);
301
        addPoint(point2);
302
        addPoint(point3);
303
        isSimple = false;
304
    }
305

    
306
    /**
307
     * Closes the current subpath by drawing a straight line back to
308
     * the coordinates of the last <code>moveTo</code>. If the path is already
309
     * closed then this method has no effect.
310
     */
311
    public synchronized void closePath() {
312
        if (getNumTypes() == 0 || getTypeAt(getNumTypes() - 1) != SEG_CLOSE) {
313
            needRoom(1, 0, true);
314
            // Adding a geometry like the last geometry
315
            // addPoint(100, 100);
316
            pointTypes.add(SEG_TYPES[SEG_CLOSE]);
317
        }
318
    }
319

    
320
    /**
321
     * Check if the first part is closed.
322
     * 
323
     * @return
324
     */
325
    public boolean isClosed() {
326
        PathIterator theIterator =
327
            getPathIterator(null, geomManager.getFlatness());
328
        double[] theData = new double[6];
329
        double xFinal = 0;
330
        double yFinal = 0;
331
        double xIni = 0;
332
        double yIni = 0;
333
        boolean first = true;
334

    
335
        while (!theIterator.isDone()) {
336
            // while not done
337
            int theType = theIterator.currentSegment(theData);
338

    
339
            switch (theType) {
340
            case PathIterator.SEG_MOVETO:
341
                xIni = theData[0];
342
                yIni = theData[1];
343
                if (!first) {
344
                    break;
345
                }
346
                first = false;
347
                break;
348

    
349
            case PathIterator.SEG_LINETO:
350
                xFinal = theData[0];
351
                yFinal = theData[1];
352
                break;
353
            case PathIterator.SEG_CLOSE:
354
                return true;
355

    
356
            } // end switch
357

    
358
            theIterator.next();
359
        }
360
        if ((xFinal == xIni) && (yFinal == yIni))
361
            return true;
362
        return false;
363
    }
364

    
365
    /**
366
     * Appends the geometry of the specified {@link PathIterator} object
367
     * to the path, possibly connecting the new geometry to the existing
368
     * path segments with a line segment.
369
     * If the <code>connect</code> parameter is <code>true</code> and the
370
     * path is not empty then any initial <code>moveTo</code> in the
371
     * geometry of the appended <code>Shape</code> is turned into a
372
     * <code>lineTo</code> segment.
373
     * If the destination coordinates of such a connecting <code>lineTo</code>
374
     * segment match the ending coordinates of a currently open
375
     * subpath then the segment is omitted as superfluous.
376
     * The winding rule of the specified <code>Shape</code> is ignored
377
     * and the appended geometry is governed by the winding
378
     * rule specified for this path.
379
     * 
380
     * @param pi
381
     *            the <code>PathIterator</code> whose geometry is appended to
382
     *            this path
383
     * @param connect
384
     *            a boolean to control whether or not to turn an
385
     *            initial <code>moveTo</code> segment into a <code>lineTo</code>
386
     *            segment
387
     *            to connect the new geometry to the existing path
388
     */
389
    public void append(PathIterator pi, boolean connect) {
390
        double coords[] = new double[6];
391
        while (!pi.isDone()) {
392
            switch (pi.currentSegment(coords)) {
393
            case SEG_MOVETO:
394
                if (!connect || getNumTypes() < 1 || getNumCoords() < 2) {
395
                    moveTo(coords[0], coords[1]);
396
                    break;
397
                }
398
                if (getTypeAt(getNumTypes() - 1) != SEG_CLOSE
399
                    && getPointAt(getNumCoords() - 1).getX() == coords[0]
400
                    && getPointAt(getNumCoords() - 1).getY() == coords[1]) {
401
                    // Collapse out initial moveto/lineto
402
                    break;
403
                }
404
                // NO BREAK;
405
            case SEG_LINETO:
406
                lineTo(coords[0], coords[1]);
407
                break;
408
            case SEG_QUADTO:
409
                quadTo(coords[0], coords[1], coords[2], coords[3]);
410
                break;
411
            case SEG_CUBICTO:
412
                curveTo(coords[0], coords[1], coords[2], coords[3], coords[4],
413
                    coords[5]);
414
                break;
415
            case SEG_CLOSE:
416
                closePath();
417
                break;
418
            }
419
            pi.next();
420
            connect = false;
421
        }
422
    }
423
   
424
    public void append(GeneralPathX gp) {
425
        for( int i=0 ; i<gp.getNumCoords(); i++ ) {
426
            byte type = gp.getTypeAt(i);
427
            Point point = gp.getPointAt(i);
428
            pointTypes.add(SEG_TYPES[type]);
429
            addPoint(point);
430
        }
431
    }
432
  
433
    /**
434
     * Returns the fill style winding rule.
435
     * 
436
     * @return an integer representing the current winding rule.
437
     * @see #WIND_EVEN_ODD
438
     * @see #WIND_NON_ZERO
439
     * @see #setWindingRule
440
     */
441
    public synchronized int getWindingRule() {
442
        return windingRule;
443
    }
444

    
445
    /**
446
     * Sets the winding rule for this path to the specified value.
447
     * 
448
     * @param rule
449
     *            an integer representing the specified
450
     *            winding rule
451
     * @exception <code>IllegalArgumentException</code> if <code>rule</code> is
452
     *            not either <code>WIND_EVEN_ODD</code> or
453
     *            <code>WIND_NON_ZERO</code>
454
     * @see #WIND_EVEN_ODD
455
     * @see #WIND_NON_ZERO
456
     * @see #getWindingRule
457
     */
458
    public void setWindingRule(int rule) {
459
        if (rule != WIND_EVEN_ODD && rule != WIND_NON_ZERO) {
460
            throw new IllegalArgumentException("winding rule must be "
461
                + "WIND_EVEN_ODD or " + "WIND_NON_ZERO");
462
        }
463
        windingRule = rule;
464
    }
465

    
466
    /**
467
     * Returns the coordinates most recently added to the end of the path
468
     * as a {@link Point2D} object.
469
     * 
470
     * @return a <code>Point2D</code> object containing the ending
471
     *         coordinates of the path or <code>null</code> if there are no
472
     *         points
473
     *         in the path.
474
     */
475
    public synchronized Point2D getCurrentPoint() {
476
        if (getNumTypes() < 1 || getNumCoords() < 1) {
477
            return null;
478
        }
479
        int index = getNumCoords();
480
        if (getTypeAt(getNumTypes() - 1) == SEG_CLOSE) {
481
            loop: for (int i = getNumTypes() - 2; i > 0; i--) {
482
                switch (getTypeAt(i)) {
483
                case SEG_MOVETO:
484
                    break loop;
485
                case SEG_LINETO:
486
                    index -= 2;
487
                    break;
488
                case SEG_QUADTO:
489
                    index -= 4;
490
                    break;
491
                case SEG_CUBICTO:
492
                    index -= 6;
493
                    break;
494
                case SEG_CLOSE:
495
                    break;
496
                }
497
            }
498
        }
499
        return new Point2D.Double(getPointAt(index - 1).getX(), getPointAt(
500
            index - 1).getY());
501
    }
502

    
503
    /**
504
     * Resets the path to empty. The append position is set back to the
505
     * beginning of the path and all coordinates and point types are
506
     * forgotten.
507
     */
508
    public synchronized void reset() {
509
        pointCoords.clear();
510
        pointTypes.clear();
511
    }
512

    
513
    /**
514
     * Transforms the geometry of this path using the specified
515
     * {@link AffineTransform}.
516
     * The geometry is transformed in place, which permanently changes the
517
     * boundary defined by this object.
518
     * 
519
     * @param at
520
     *            the <code>AffineTransform</code> used to transform the area
521
     */
522
    public void transform(AffineTransform at) {
523
        for (int i = 0; i < getNumCoords(); i++) {
524
            getPointAt(i).transform(at);
525
        }
526
    }
527

    
528
    public void reProject(ICoordTrans ct) {
529
        for (int i = 0; i < getNumCoords(); i++) {
530
            getPointAt(i).reProject(ct);
531
        }
532
    }
533

    
534
    /**
535
     * Returns a new transformed <code>Shape</code>.
536
     * 
537
     * @param at
538
     *            the <code>AffineTransform</code> used to transform a
539
     *            new <code>Shape</code>.
540
     * @return a new <code>Shape</code>, transformed with the specified
541
     *         <code>AffineTransform</code>.
542
     */
543
    public synchronized Shape createTransformedShape(AffineTransform at) {
544
        DefaultGeneralPathX gp = (DefaultGeneralPathX) clone();
545
        if (at != null) {
546
            gp.transform(at);
547
        }
548
        return gp;
549
    }
550

    
551
    /**
552
     * Return the bounding box of the path.
553
     * 
554
     * @return a {@link java.awt.Rectangle} object that
555
     *         bounds the current path.
556
     */
557
    public java.awt.Rectangle getBounds() {
558
        return getBounds2D().getBounds();
559
    }
560

    
561
    /**
562
     * Returns the bounding box of the path.
563
     * 
564
     * @return a {@link Rectangle2D} object that
565
     *         bounds the current path.
566
     */
567
    public synchronized Rectangle2D getBounds2D() {
568
        double x1, y1, x2, y2;
569
        int i = getNumCoords();
570
        if (i > 0) {
571
            y1 = y2 = getPointAt(--i).getY();
572
            x1 = x2 = getPointAt(i).getX();
573
            while (i > 0) {
574
                double y = getPointAt(--i).getY();
575
                double x = getPointAt(i).getX();
576
                if (x < x1)
577
                    x1 = x;
578
                if (y < y1)
579
                    y1 = y;
580
                if (x > x2)
581
                    x2 = x;
582
                if (y > y2)
583
                    y2 = y;
584
            }
585
        } else {
586
            x1 = y1 = x2 = y2 = 0.0f;
587
        }
588
        return new Rectangle2D.Double(x1, y1, x2 - x1, y2 - y1);
589
    }
590

    
591
    /**
592
     * Tests if the specified coordinates are inside the boundary of
593
     * this <code>Shape</code>.
594
     * 
595
     * @param x
596
     *            ,&nbsp;y the specified coordinates
597
     * @return <code>true</code> if the specified coordinates are inside this
598
     *         <code>Shape</code>; <code>false</code> otherwise
599
     */
600
    public boolean contains(double x, double y) {
601
        if (pointTypes.size() < 2) {
602
            return false;
603
        }
604
        int cross =
605
            GeomUtilities.pointCrossingsForPath(getPathIterator(null), x, y);
606
        if (windingRule == WIND_NON_ZERO) {
607
            return (cross != 0);
608
        } else {
609
            return ((cross & 1) != 0);
610
        }
611
    }
612

    
613
    /**
614
     * Tests if the specified <code>Point2D</code> is inside the boundary
615
     * of this <code>Shape</code>.
616
     * 
617
     * @param p
618
     *            the specified <code>Point2D</code>
619
     * @return <code>true</code> if this <code>Shape</code> contains the
620
     *         specified <code>Point2D</code>, <code>false</code> otherwise.
621
     */
622
    public boolean contains(Point2D p) {
623
        return contains(p.getX(), p.getY());
624
    }
625

    
626
    /**
627
     * Tests if the specified rectangular area is inside the boundary of
628
     * this <code>Shape</code>.
629
     * 
630
     * @param x
631
     *            ,&nbsp;y the specified coordinates
632
     * @param w
633
     *            the width of the specified rectangular area
634
     * @param h
635
     *            the height of the specified rectangular area
636
     * @return <code>true</code> if this <code>Shape</code> contains
637
     *         the specified rectangluar area; <code>false</code> otherwise.
638
     */
639
    public boolean contains(double x, double y, double w, double h) {
640
        return GeomUtilities
641
            .contains(getPathIterator(null), x, y, x + w, y + h);
642
    }
643

    
644
    /**
645
     * Tests if the specified <code>Rectangle2D</code> is inside the boundary of
646
     * this <code>Shape</code>.
647
     * 
648
     * @param r
649
     *            a specified <code>Rectangle2D</code>
650
     * @return <code>true</code> if this <code>Shape</code> bounds the
651
     *         specified <code>Rectangle2D</code>; <code>false</code> otherwise.
652
     */
653
    public boolean contains(Rectangle2D r) {
654
        return contains(r.getX(), r.getY(), r.getWidth(), r.getHeight());
655
    }
656

    
657
    /**
658
     * Tests if the interior of this <code>Shape</code> intersects the
659
     * interior of a specified set of rectangular coordinates.
660
     * 
661
     * @param x
662
     *            ,&nbsp;y the specified coordinates
663
     * @param w
664
     *            the width of the specified rectangular coordinates
665
     * @param h
666
     *            the height of the specified rectangular coordinates
667
     * @return <code>true</code> if this <code>Shape</code> and the
668
     *         interior of the specified set of rectangular coordinates
669
     *         intersect
670
     *         each other; <code>false</code> otherwise.
671
     */
672
    public boolean intersects(double x, double y, double w, double h) {
673
        return GeomUtilities.intersects(getPathIterator(null), x, y, w, h);
674
    }
675

    
676
    /**
677
     * Tests if the interior of this <code>Shape</code> intersects the
678
     * interior of a specified <code>Rectangle2D</code>.
679
     * 
680
     * @param r
681
     *            the specified <code>Rectangle2D</code>
682
     * @return <code>true</code> if this <code>Shape</code> and the interior
683
     *         of the specified <code>Rectangle2D</code> intersect each
684
     *         other; <code>false</code> otherwise.
685
     */
686
    public boolean intersects(Rectangle2D r) {
687
        return intersects(r.getX(), r.getY(), r.getWidth(), r.getHeight());
688
    }
689

    
690
    /**
691
     * Returns a <code>PathIterator</code> object that iterates along the
692
     * boundary of this <code>Shape</code> and provides access to the
693
     * geometry of the outline of this <code>Shape</code>.
694
     * The iterator for this class is not multi-threaded safe,
695
     * which means that this <code>GeneralPathX</code> class does not
696
     * guarantee that modifications to the geometry of this
697
     * <code>GeneralPathX</code> object do not affect any iterations of
698
     * that geometry that are already in process.
699
     * 
700
     * @param at
701
     *            an <code>AffineTransform</code>
702
     * @return a new <code>PathIterator</code> that iterates along the
703
     *         boundary of this <code>Shape</code> and provides access to the
704
     *         geometry of this <code>Shape</code>'s outline
705
     */
706
    public PathIterator getPathIterator(AffineTransform at) {
707
        if (isSimple) {
708
            return new GeneralPathXIteratorSimple(this, at);
709
        } else {
710
            return new GeneralPathXIterator(this, at);
711
        }
712
    }
713

    
714
    /**
715
     * Returns a <code>PathIterator</code> object that iterates along the
716
     * boundary of the flattened <code>Shape</code> and provides access to the
717
     * geometry of the outline of the <code>Shape</code>.
718
     * The iterator for this class is not multi-threaded safe,
719
     * which means that this <code>GeneralPathX</code> class does not
720
     * guarantee that modifications to the geometry of this
721
     * <code>GeneralPathX</code> object do not affect any iterations of
722
     * that geometry that are already in process.
723
     * 
724
     * @param at
725
     *            an <code>AffineTransform</code>
726
     * @param flatness
727
     *            the maximum distance that the line segments used to
728
     *            approximate the curved segments are allowed to deviate
729
     *            from any point on the original curve
730
     * @return a new <code>PathIterator</code> that iterates along the flattened
731
     *         <code>Shape</code> boundary.
732
     */
733
    public PathIterator getPathIterator(AffineTransform at, double flatness) {
734
        return new FlatteningPathIterator(getPathIterator(at), flatness);
735
    }
736

    
737
    /**
738
     * Creates a new object of the same class as this object.
739
     * 
740
     * @return a clone of this instance.
741
     * @exception OutOfMemoryError
742
     *                if there is not enough memory.
743
     * @see java.lang.Cloneable
744
     * @since 1.2
745
     */
746
    public Object clone() {
747
        DefaultGeneralPathX copy = new DefaultGeneralPathX();
748
        copy.windingRule = windingRule;
749
        copy.isSimple = isSimple;
750
        for (int i = 0; i < getNumTypes(); i++) {
751
            copy.pointTypes.add(pointTypes.get(i));
752
        }
753
        for (int i = 0; i < getNumCoords(); i++) {
754
            copy.addPoint((Point) getPointAt(i).cloneGeometry());
755
        }
756
        return copy;
757

    
758
    }
759

    
760
    DefaultGeneralPathX(int windingRule, byte[] pointTypes, int numTypes,
761
        double[] pointCoords, int numCoords) {
762

    
763
        // used to construct from native
764
        super(false);
765

    
766
        this.windingRule = windingRule;
767
        this.setPointTypes(pointTypes);
768
        this.setNumTypes(numTypes);
769
        this.setPointCoords(pointCoords);
770
        this.setNumCoords(numCoords);
771
    }
772

    
773
    public void setNumTypes(int numTypes) {
774

    
775
    }
776

    
777
    public int getNumTypes() {
778
        return pointTypes.size();
779
    }
780

    
781
    public int setNumCoords(int numCoords) {
782
        return pointCoords.size();
783
    }
784

    
785
    public int getNumCoords() {
786
        return pointCoords.size();
787
    }
788

    
789
    public byte getTypeAt(int index) {
790
        return ((Byte) pointTypes.get(index)).byteValue();
791
    }
792

    
793
    /**
794
     * @deprecated
795
     *             use the geometry methods.
796
     */
797
    public void setPointTypes(byte[] pointTypes) {
798
        this.pointTypes.clear();
799
        for (int i = 0; i < pointTypes.length; i++) {
800
            this.pointTypes.add(SEG_TYPES[pointTypes[i]]);
801
        }
802
    }
803

    
804
    /**
805
     * @deprecated
806
     *             use the geometry methods.
807
     */
808
    public byte[] getPointTypes() {
809
        byte[] bytes = new byte[pointTypes.size()];
810
        for (int i = 0; i < pointTypes.size(); i++) {
811
            bytes[i] = ((Byte) pointTypes.get(i)).byteValue();
812
        }
813
        return bytes;
814
    }
815

    
816
    /**
817
     * @param pointCoords
818
     * @deprecated
819
     *             use the geometry methods.
820
     */
821
    public void setPointCoords(double[] pointCoords) {
822
        this.pointCoords.clear();
823
        for (int i = 0; i < pointCoords.length; i = i + 2) {
824
            try {
825
                addPoint(geomManager.createPoint(pointCoords[i],
826
                    pointCoords[i + 1], Geometry.SUBTYPES.GEOM2D));
827
            } catch (CreateGeometryException e) {
828
                LOG.error("Error creating a point", e);
829
            }
830
        }
831
    }
832

    
833
    /**
834
     * @deprecated
835
     *             use the geometry methods.
836
     */
837
    public double[] getPointCoords() {
838
        double[] doubles = new double[pointCoords.size() * 2];
839
        for (int i = 0; i < getNumCoords(); i++) {
840
            doubles[i * 2] = getPointAt(i).getX();
841
            doubles[(i * 2) + 1] = getPointAt(i).getY();
842
        }
843
        return doubles;
844
    }
845

    
846
    public Point getPointAt(int index) {
847
        return (Point) pointCoords.get(index);
848
    }
849

    
850
    public double[] getCoordinatesAt(int index) {
851
        return getPointAt(index).getCoordinates();
852
    }
853
    
854
    public double[] get3DCoordinatesAt(int index) {
855
            Point p = getPointAt(index);
856
            if(p instanceof Point2DZ) {
857
                    return getPointAt(index).getCoordinates();
858
            }
859
            double[] coords = new double[3];
860
            coords[0] = p.getX();
861
            coords[1] = p.getY();
862
            coords[2] = 0D;
863
            return coords;
864
    }
865

    
866
    /**
867
     * Convertimos el path a puntos y luego le damos la vuelta.
868
     */
869
    public void flip() {
870
        PathIterator theIterator =
871
            getPathIterator(null, geomManager.getFlatness());
872
        double[] theData = new double[6];
873
        CoordinateList coordList = new CoordinateList();
874
        Coordinate c1;
875
        DefaultGeneralPathX newGp = new DefaultGeneralPathX();
876
        ArrayList listOfParts = new ArrayList();
877
        while (!theIterator.isDone()) {
878
            // while not done
879
            int type = theIterator.currentSegment(theData);
880
            switch (type) {
881
            case SEG_MOVETO:
882
                coordList = new CoordinateList();
883
                listOfParts.add(coordList);
884
                c1 = new Coordinate(theData[0], theData[1]);
885
                coordList.add(c1, true);
886
                break;
887
            case SEG_LINETO:
888
                c1 = new Coordinate(theData[0], theData[1]);
889
                coordList.add(c1, true);
890
                break;
891

    
892
            case SEG_CLOSE:
893
                coordList.add(coordList.getCoordinate(0));
894
                break;
895

    
896
            }
897
            theIterator.next();
898
        }
899

    
900
        for (int i = listOfParts.size() - 1; i >= 0; i--) {
901
            coordList = (CoordinateList) listOfParts.get(i);
902
            Coordinate[] coords = coordList.toCoordinateArray();
903
            CoordinateArraySequence seq = new CoordinateArraySequence(coords);
904
            CoordinateSequences.reverse(seq);
905
            coords = seq.toCoordinateArray();
906
            newGp.moveTo(coords[0].x, coords[0].y);
907
            for (int j = 1; j < coords.length; j++) {
908
                newGp.lineTo(coords[j].x, coords[j].y);
909
            }
910
        }
911
        reset();
912
        append(newGp.getPathIterator(null), false);
913
    }
914

    
915
    /**
916
     * Check if the first part is CCW.
917
     * 
918
     * @return
919
     */
920
    public boolean isCCW() {
921
        PathIterator theIterator =
922
            getPathIterator(null, geomManager.getFlatness()); // polyLine.getPathIterator(null,
923
                                                              // flatness);
924
        double[] theData = new double[6];
925
        Coordinate first = null;
926
        CoordinateList coordList = new CoordinateList();
927
        Coordinate c1;
928
        boolean bFirst = true;
929
        while (!theIterator.isDone()) {
930
            // while not done
931
            int type = theIterator.currentSegment(theData);
932
            switch (type) {
933
            case SEG_MOVETO:
934
                c1 = new Coordinate(theData[0], theData[1]);
935
                if (bFirst == false) // Ya tenemos la primera parte.
936
                    break;
937
                if (bFirst) {
938
                    bFirst = false;
939
                    first = c1;
940
                }
941
                coordList.add(c1, true);
942
                break;
943
            case SEG_LINETO:
944
                c1 = new Coordinate(theData[0], theData[1]);
945
                coordList.add(c1, true);
946
                break;
947

    
948
            }
949
            theIterator.next();
950
        }
951
        coordList.add(first, true);
952
        return CGAlgorithms.isCCW(coordList.toCoordinateArray());
953
    }
954

    
955
    /**
956
     * @return the isSimple
957
     */
958
    public boolean isSimple() {
959
        return isSimple;
960
    }
961
    
962
    public void ensureCapacity(int capacity) {
963
        
964
    }
965
}