Statistics
| Revision:

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

History | View | Annotate | Download (31.4 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.jts.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

    
42
import org.gvsig.fmap.geom.Geometry;
43
import org.gvsig.fmap.geom.GeometryLocator;
44
import org.gvsig.fmap.geom.GeometryManager;
45
import org.gvsig.fmap.geom.exception.CreateGeometryException;
46
import org.gvsig.fmap.geom.jts.primitive.point.Point3D;
47
import org.gvsig.jdk.GeomUtilities;
48

    
49
import org.slf4j.Logger;
50
import org.slf4j.LoggerFactory;
51

    
52
import com.vividsolutions.jts.algorithm.CGAlgorithms;
53
import com.vividsolutions.jts.geom.Coordinate;
54
import com.vividsolutions.jts.geom.CoordinateList;
55
import com.vividsolutions.jts.geom.CoordinateSequences;
56
import com.vividsolutions.jts.geom.impl.CoordinateArraySequence;
57

    
58
import java.io.Serializable;
59

    
60
import org.gvsig.fmap.geom.primitive.GeneralPathX;
61
import org.gvsig.fmap.geom.primitive.IGeneralPathX;
62
import org.gvsig.fmap.geom.primitive.Point;
63

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

    
89
    /**
90
     * Default serial version ID
91
     */
92
    private static final long serialVersionUID = 1L;
93

    
94
    private static final Logger LOG = LoggerFactory
95
        .getLogger(DefaultGeneralPathX.class);
96

    
97
    protected static GeometryManager geomManager = GeometryLocator
98
        .getGeometryManager();
99

    
100
    private List pointTypes = new ArrayList();
101
    private List pointCoords = new ArrayList();
102

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

    
117
    int windingRule;
118

    
119
    private boolean isSimple = true;
120

    
121
    static final int EXPAND_MAX = 500;
122

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

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

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

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

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

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

    
213
    public synchronized void lineTo(Point point) {
214
        needRoom(1, 2, true);
215
        pointTypes.add(SEG_TYPES[SEG_LINETO]);
216
        addPoint(point);
217
    }
218

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

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

    
238
    private void addPoint(Point point) {
239
        pointCoords.add(point);
240
    }
241

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

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

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

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

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

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

    
339
        while (!theIterator.isDone()) {
340
            // while not done
341
            int theType = theIterator.currentSegment(theData);
342

    
343
            switch (theType) {
344
            case PathIterator.SEG_MOVETO:
345
                xIni = theData[0];
346
                yIni = theData[1];
347
                if (!first) {
348
                    break;
349
                }
350
                first = false;
351
                break;
352

    
353
            case PathIterator.SEG_LINETO:
354
                xFinal = theData[0];
355
                yFinal = theData[1];
356
                break;
357
            case PathIterator.SEG_CLOSE:
358
                return true;
359

    
360
            } // end switch
361

    
362
            theIterator.next();
363
        }
364
        if ((xFinal == xIni) && (yFinal == yIni))
365
            return true;
366
        return false;
367
    }
368

    
369
    /**
370
     * Appends the geometry of the specified {@link PathIterator} object
371
     * to the path, possibly connecting the new geometry to the existing
372
     * path segments with a line segment.
373
     * If the <code>connect</code> parameter is <code>true</code> and the
374
     * path is not empty then any initial <code>moveTo</code> in the
375
     * geometry of the appended <code>Shape</code> is turned into a
376
     * <code>lineTo</code> segment.
377
     * If the destination coordinates of such a connecting <code>lineTo</code>
378
     * segment match the ending coordinates of a currently open
379
     * subpath then the segment is omitted as superfluous.
380
     * The winding rule of the specified <code>Shape</code> is ignored
381
     * and the appended geometry is governed by the winding
382
     * rule specified for this path.
383
     *
384
     * @param pi
385
     *            the <code>PathIterator</code> whose geometry is appended to
386
     *            this path
387
     * @param connect
388
     *            a boolean to control whether or not to turn an
389
     *            initial <code>moveTo</code> segment into a <code>lineTo</code>
390
     *            segment
391
     *            to connect the new geometry to the existing path
392
     */
393
    public void append(PathIterator pi, boolean connect) {
394
        double coords[] = new double[6];
395
        while (!pi.isDone()) {
396
            switch (pi.currentSegment(coords)) {
397
            case SEG_MOVETO:
398
                if (!connect || getNumTypes() < 1 || getNumCoords() < 2) {
399
                    moveTo(coords[0], coords[1]);
400
                    break;
401
                }
402
                if (getTypeAt(getNumTypes() - 1) != SEG_CLOSE
403
                    && getPointAt(getNumCoords() - 1).getX() == coords[0]
404
                    && getPointAt(getNumCoords() - 1).getY() == coords[1]) {
405
                    // Collapse out initial moveto/lineto
406
                    break;
407
                }
408
                // NO BREAK;
409
            case SEG_LINETO:
410
                lineTo(coords[0], coords[1]);
411
                break;
412
            case SEG_QUADTO:
413
                quadTo(coords[0], coords[1], coords[2], coords[3]);
414
                break;
415
            case SEG_CUBICTO:
416
                curveTo(coords[0], coords[1], coords[2], coords[3], coords[4],
417
                    coords[5]);
418
                break;
419
            case SEG_CLOSE:
420
                closePath();
421
                break;
422
            }
423
            pi.next();
424
            connect = false;
425
        }
426
    }
427

    
428
    public void append(GeneralPathX gp) {
429
        for( int i=0 ; i<gp.getNumCoords(); i++ ) {
430
            byte type = gp.getTypeAt(i);
431
            Point point = gp.getPointAt(i);
432
            pointTypes.add(SEG_TYPES[type]);
433
            addPoint(point);
434
        }
435
    }
436

    
437
    /**
438
     * Returns the fill style winding rule.
439
     *
440
     * @return an integer representing the current winding rule.
441
     * @see #WIND_EVEN_ODD
442
     * @see #WIND_NON_ZERO
443
     * @see #setWindingRule
444
     */
445
    public synchronized int getWindingRule() {
446
        return windingRule;
447
    }
448

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

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

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

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

    
532
    public void reProject(ICoordTrans ct) {
533
        for (int i = 0; i < getNumCoords(); i++) {
534
            getPointAt(i).reProject(ct);
535
        }
536
    }
537

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

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

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

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

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

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

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

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

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

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

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

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

    
762
    }
763

    
764
    DefaultGeneralPathX(int windingRule, byte[] pointTypes, int numTypes,
765
        double[] pointCoords, int numCoords) {
766

    
767
        // used to construct from native
768
        super(false);
769

    
770
        this.windingRule = windingRule;
771
        this.setPointTypes(pointTypes);
772
        this.setNumTypes(numTypes);
773
        this.setPointCoords(pointCoords);
774
        this.setNumCoords(numCoords);
775
    }
776

    
777
    public void setNumTypes(int numTypes) {
778

    
779
    }
780

    
781
    public int getNumTypes() {
782
        return pointTypes.size();
783
    }
784

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

    
789
    public int getNumCoords() {
790
        return pointCoords.size();
791
    }
792

    
793
    public byte getTypeAt(int index) {
794
        return ((Byte) pointTypes.get(index)).byteValue();
795
    }
796

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

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

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

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

    
850
    public Point getPointAt(int index) {
851
        return (Point) pointCoords.get(index);
852
    }
853

    
854
    public double[] getCoordinatesAt(int index) {
855
        return getPointAt(index).getCoordinates();
856
    }
857

    
858
    public double[] get3DCoordinatesAt(int index) {
859
            Point p = getPointAt(index);
860
            if(p instanceof Point3D) {
861
                    return getPointAt(index).getCoordinates();
862
            }
863
            double[] coords = new double[3];
864
            coords[0] = p.getX();
865
            coords[1] = p.getY();
866
            coords[2] = 0D;
867
            return coords;
868
    }
869

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

    
896
            case SEG_CLOSE:
897
                coordList.add(coordList.getCoordinate(0));
898
                break;
899

    
900
            }
901
            theIterator.next();
902
        }
903

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

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

    
952
            }
953
            theIterator.next();
954
        }
955
        coordList.add(first, true);
956
        return CGAlgorithms.isCCW(coordList.toCoordinateArray());
957
    }
958

    
959
    /**
960
     * @return the isSimple
961
     */
962
    public boolean isSimple() {
963
        return isSimple;
964
    }
965

    
966
    public void ensureCapacity(int capacity) {
967

    
968
    }
969
}