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 / primitive / curve / line / AbstractLine.java @ 44612

History | View | Annotate | Download (18.7 KB)

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

    
25
import java.awt.Shape;
26
import java.awt.geom.AffineTransform;
27
import java.awt.geom.GeneralPath;
28
import java.awt.geom.PathIterator;
29
import java.util.Collections;
30
import java.util.Iterator;
31

    
32
import com.vividsolutions.jts.geom.Coordinate;
33
import java.util.ArrayList;
34
import java.util.List;
35

    
36
import org.apache.commons.lang3.StringUtils;
37
import org.cresques.cts.ICoordTrans;
38
import org.slf4j.Logger;
39
import org.slf4j.LoggerFactory;
40

    
41
import org.gvsig.fmap.geom.Geometry;
42
import org.gvsig.fmap.geom.aggregate.MultiPoint;
43
import org.gvsig.fmap.geom.jts.aggregate.MultiPoint2D;
44
import org.gvsig.fmap.geom.jts.gputils.DefaultGeneralPathX;
45
import org.gvsig.fmap.geom.jts.gputils.GeneralPathXIterator;
46
import org.gvsig.fmap.geom.jts.primitive.curve.AbstractCurve;
47
import org.gvsig.fmap.geom.jts.primitive.point.Point2D;
48
import org.gvsig.fmap.geom.jts.primitive.point.PointJTS;
49
import org.gvsig.fmap.geom.jts.util.ArrayListCoordinateSequence;
50
import org.gvsig.fmap.geom.jts.util.JTSUtils;
51
import org.gvsig.fmap.geom.operation.GeometryOperationException;
52
import org.gvsig.fmap.geom.operation.GeometryOperationNotSupportedException;
53
import org.gvsig.fmap.geom.primitive.GeneralPathX;
54
import org.gvsig.fmap.geom.primitive.IGeneralPathX;
55
import org.gvsig.fmap.geom.primitive.Line;
56
import org.gvsig.fmap.geom.primitive.Point;
57

    
58
/**
59
 * @author fdiaz
60
 *
61
 */
62
public abstract class AbstractLine extends AbstractCurve {
63

    
64
    /**
65
     *
66
     */
67
    private static final long serialVersionUID = 5034197096871344597L;
68
    private static final Logger logger = LoggerFactory.getLogger(AbstractLine.class);
69

    
70
    protected ArrayListCoordinateSequence coordinates;
71

    
72
    public class VertexIterator implements Iterator<Point> {
73

    
74
        private PointJTS vertex;
75
        private int current;
76

    
77
        public VertexIterator() {
78
            this.current = 0;
79
            if( getNumVertices()>0 ) {
80
                this.vertex = (PointJTS) getVertex(0).cloneGeometry();
81
            } else {
82
                this.vertex = null;
83
            }
84
        }
85

    
86
        @Override
87
        public boolean hasNext() {
88
            return this.current < getNumVertices() ;
89
        }
90

    
91
        @Override
92
        public Point next() {
93
            this.vertex.setJTSCoordinate(coordinates.get(current) );
94
            this.current++;
95
            return this.vertex;
96
        }
97

    
98
        @Override
99
        public void remove() {
100
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
101
        }
102

    
103
    }
104
    /**
105
    *
106
    */
107
    protected AbstractLine(int subtype) {
108
        super(Geometry.TYPES.LINE, subtype);
109
    }
110

    
111
    /**
112
     * @param type
113
     * @param subtype
114
     */
115
    public AbstractLine(int type, int subtype) {
116
        super(type, subtype);
117
    }
118

    
119
    abstract public Point getVertex(int index);
120

    
121
    public Iterator<Point> iterator() {
122
        return new VertexIterator();
123
    }
124

    
125
    /*
126
     * (non-Javadoc)
127
     *
128
     * @see org.gvsig.fmap.geom.jts.GeometryJTS#getJTS()
129
     */
130
    public com.vividsolutions.jts.geom.Geometry getJTS() {
131
        return JTSUtils.createJTSLineString(coordinates);
132
    }
133

    
134
    /*
135
     * (non-Javadoc)
136
     *
137
     * @see
138
     * org.gvsig.fmap.geom.primitive.OrientablePrimitive#addVertex(org.gvsig
139
     * .fmap.geom.primitive.Point)
140
     */
141
    public void addVertex(Point point) {
142
        point = fixPoint(point);
143
        coordinates.add(((PointJTS) point).getJTSCoordinate());
144
    }
145

    
146
    /*
147
     * (non-Javadoc)
148
     *
149
     * @see
150
     * org.gvsig.fmap.geom.primitive.Curve#setPoints(org.gvsig.fmap.geom.primitive
151
     * .Point, org.gvsig.fmap.geom.primitive.Point)
152
     */
153
    public void setPoints(Point initialPoint, Point endPoint) {
154
        initialPoint = fixPoint(initialPoint);
155
        endPoint = fixPoint(endPoint);
156
        coordinates.clear();
157
        addVertex(initialPoint);
158
        addVertex(endPoint);
159
    }
160

    
161
    /**
162
     * @param point
163
     * @return
164
     */
165
    protected abstract Point fixPoint(Point point);
166

    
167
    /*
168
     * (non-Javadoc)
169
     *
170
     * @see
171
     * org.gvsig.fmap.geom.primitive.OrientablePrimitive#getCoordinateAt(int,
172
     * int)
173
     */
174
    public double getCoordinateAt(int index, int dimension) {
175
        return coordinates.getOrdinate(index, dimension);
176
    }
177

    
178
    /*
179
     * (non-Javadoc)
180
     *
181
     * @see
182
     * org.gvsig.fmap.geom.primitive.OrientablePrimitive#setCoordinateAt(int,
183
     * int, double)
184
     */
185
    public void setCoordinateAt(int index, int dimension, double value) {
186
        coordinates.setOrdinate(index, dimension, value);
187
    }
188

    
189
    /*
190
     * (non-Javadoc)
191
     *
192
     * @see org.gvsig.fmap.geom.primitive.OrientablePrimitive#removeVertex(int)
193
     */
194
    public void removeVertex(int index) {
195
        coordinates.remove(index);
196
    }
197

    
198

    
199
    public boolean isEmpty() {
200
        return coordinates==null || coordinates.isEmpty();
201
    }
202
    
203
    public int getNumVertices() {
204
        if( isEmpty() ) {
205
            return 0;
206
        }
207
        return coordinates.size();
208
    }
209

    
210
    /*
211
     * (non-Javadoc)
212
     *
213
     * @see org.gvsig.fmap.geom.primitive.OrientablePrimitive#insertVertex(int,
214
     * org.gvsig.fmap.geom.primitive.Point)
215
     */
216
    public void insertVertex(int index, Point p) {
217
        p = fixPoint(p);
218
        coordinates.add(index, ((PointJTS) p).getJTSCoordinate());
219
    }
220

    
221
    /*
222
     * (non-Javadoc)
223
     *
224
     * @see org.gvsig.fmap.geom.primitive.OrientablePrimitive#setVertex(int,
225
     * org.gvsig.fmap.geom.primitive.Point)
226
     */
227
    public void setVertex(int index, Point p) {
228
        p = fixPoint(p);
229
        coordinates.set(index, ((PointJTS) p).getJTSCoordinate());
230
    }
231

    
232
    /*
233
     * (non-Javadoc)
234
     *
235
     * @see
236
     * org.gvsig.fmap.geom.primitive.OrientablePrimitive#setGeneralPath(org.
237
     * gvsig.fmap.geom.primitive.GeneralPathX)
238
     */
239
    public void setGeneralPath(GeneralPathX generalPathX) {
240
        PathIterator it = generalPathX.getPathIterator(null);
241
        double[] segment = new double[6];
242
        int i = 0;
243
        while(!it.isDone()){
244
            int type = it.currentSegment(segment);
245
            if(i==0){
246
                switch (type) {
247
                case IGeneralPathX.SEG_MOVETO:
248
                    Point p = new Point2D(segment[0], segment[1]);
249
                    p = fixPoint(p);
250
                    coordinates.add(((PointJTS)p).getJTSCoordinate());
251
                    break;
252
                default:
253
                    String message = StringUtils.replace("Type of segment %(segment)s isn't SEG_MOVETO.","%(segment)s",String.valueOf(i));
254
                    logger.warn(message);
255
                    throw new RuntimeException(message);
256
                }
257
            } else {
258
                //Dudo de que los casos SEG_QUADTO y SEG_CUBICTO est?n bien pero se hac?a lo mismo en la librer?a de geometr?as vieja.
259
                Point p;
260
                switch (type) {
261
                case IGeneralPathX.SEG_LINETO:
262
                    p = new Point2D(segment[0], segment[1]);
263
                    p = fixPoint(p);
264
                    coordinates.add(((PointJTS)p).getJTSCoordinate());
265
                    break;
266
                case IGeneralPathX.SEG_QUADTO:
267
                    for (int j = 0; j <= 1; j++) {
268
                        p = new Point2D(segment[i], segment[i+1]);
269
                        p = fixPoint(p);
270
                        coordinates.add(((PointJTS) p).getJTSCoordinate());
271
                    }
272
                    break;
273
                case IGeneralPathX.SEG_CUBICTO:
274
                    for (int j = 0; j <= 2; j++) {
275
                        p = new Point2D(segment[i], segment[i+1]);
276
                        p = fixPoint(p);
277
                        coordinates.add(((PointJTS) p).getJTSCoordinate());
278
                    }
279
                    break;
280
                case IGeneralPathX.SEG_CLOSE:
281
                    if(!coordinates.get(0).equals(coordinates.get(coordinates.size()-1))){
282
                        coordinates.add(coordinates.get(0));
283
                    }
284
                    break;
285
                default:
286
                    String message = StringUtils.replace("The general path has a gap in segment %(segment)s.","%(segment)s",String.valueOf(i));
287
                    logger.warn(message);
288
                    throw new RuntimeException(message);
289
                }
290
            }
291
            it.next();
292
            i++;
293
        }
294
    }
295

    
296
    /*
297
     * (non-Javadoc)
298
     *
299
     * @deprecated
300
     */
301
    public void addMoveToVertex(Point point) {
302
        notifyDeprecated("Calling deprecated metohd addMoveToVertex in Line");
303
        throw new UnsupportedOperationException();
304
    }
305

    
306
    /*
307
     * (non-Javadoc)
308
     *
309
     * @see org.gvsig.fmap.geom.primitive.OrientablePrimitive#closePrimitive()
310
     */
311
    public void closePrimitive() {
312
        if (!coordinates.isEmpty() && !isClosed()) {
313
            coordinates.add((Coordinate)coordinates.get(0).clone());
314
        }
315
    }
316

    
317
    /*
318
     * (non-Javadoc)
319
     *
320
     * @see
321
     * org.gvsig.fmap.geom.primitive.OrientablePrimitive#ensureCapacity(int)
322
     */
323
    public void ensureCapacity(int capacity) {
324
        this.coordinates.ensureCapacity(capacity);
325
    }
326

    
327
    /*
328
     * (non-Javadoc)
329
     *
330
     * @see org.gvsig.fmap.geom.Geometry#reProject(org.cresques.cts.ICoordTrans)
331
     */
332
    public void reProject(ICoordTrans ct) {
333
        if (ct == null) {
334
            return;
335
        }
336
        ArrayListCoordinateSequence tmpCoordinates = new ArrayListCoordinateSequence();
337
        tmpCoordinates.ensureCapacity(coordinates.size());
338
        for (Iterator<Coordinate> iterator = coordinates.iterator(); iterator.hasNext();) {
339
            Coordinate coordinate = (Coordinate) iterator.next();
340

    
341
            java.awt.geom.Point2D p = new java.awt.geom.Point2D.Double(coordinate.x, coordinate.y);
342
            try {
343
                p = ct.convert(p, p);
344
                coordinate.x = p.getX();
345
                coordinate.y = p.getY();
346
                tmpCoordinates.add(coordinate);
347
            } catch (Exception exc) {
348
                /*
349
                 * This can happen when the reprojection lib is unable
350
                 * to reproject (for example the source point
351
                 * is out of the valid range and some computing
352
                 * problem happens)
353
                 */
354
            }
355
        }
356
        coordinates=tmpCoordinates;
357
        this.setProjection(ct.getPDest());
358
    }
359

    
360
    /*
361
     * (non-Javadoc)
362
     *
363
     * @see
364
     * org.gvsig.fmap.geom.Geometry#transform(java.awt.geom.AffineTransform)
365
     */
366
    public void transform(AffineTransform at) {
367
        if (at == null) {
368
            return;
369
        }
370

    
371
        for (int i = 0; i < coordinates.size(); i++) {
372
            Coordinate coordinate = coordinates.get(i);
373
            java.awt.geom.Point2D p = new java.awt.geom.Point2D.Double(coordinate.x, coordinate.y);
374

    
375
            at.transform(p, p);
376
            coordinate.x = p.getX();
377
            coordinate.y = p.getY();
378

    
379
        }
380
    }
381

    
382
    /*
383
     * (non-Javadoc)
384
     *
385
     * @see org.gvsig.fmap.geom.Geometry#getDimension()
386
     */
387
    public int getDimension() {
388
        return this.getGeometryType().getDimension();
389
    }
390

    
391
    @Override
392
    public Shape getShape(AffineTransform affineTransform) {
393
        if( this.isEmpty() ) {
394
            // Esto no deberia de pasar, se trataria de una geometria
395
            // corrupta.
396
            return new GeneralPath();
397
        }
398
        return new DefaultGeneralPathX(getPathIterator(affineTransform),false,0);
399
    }
400

    
401
    /*
402
     * (non-Javadoc)
403
     *
404
     * @see org.gvsig.fmap.geom.Geometry#getShape()
405
     */
406
    public Shape getShape() {
407
        return new DefaultGeneralPathX(getPathIterator(null),false,0);
408
    }
409

    
410

    
411
    /*
412
     * (non-Javadoc)
413
     *
414
     * @see
415
     * org.gvsig.fmap.geom.Geometry#getPathIterator(java.awt.geom.AffineTransform
416
     * )
417
     */
418
    public PathIterator getPathIterator(AffineTransform at) {
419
        LineIterator pi = new LineIterator(at);
420
        return pi;
421
    }
422

    
423
    /*
424
     * (non-Javadoc)
425
     *
426
     * @see
427
     * org.gvsig.fmap.geom.Geometry#getPathIterator(java.awt.geom.AffineTransform
428
     * , double)
429
     */
430
    public PathIterator getPathIterator(AffineTransform at, double flatness) {
431
        return getPathIterator(at);
432
    }
433

    
434
    /*
435
     * (non-Javadoc)
436
     *
437
     * @see org.gvsig.fmap.geom.Geometry#getGeneralPath()
438
     */
439
    public GeneralPathX getGeneralPath() {
440
        return new DefaultGeneralPathX(getPathIterator(null), false, 0);
441
    }
442

    
443
    protected class LineIterator extends GeneralPathXIterator {
444

    
445
        /** Transform applied on the coordinates during iteration */
446
        private AffineTransform at;
447

    
448
        /** True when the point has been read once */
449
        private boolean done;
450
        private int index = 0;
451

    
452
        /**
453
         * Creates a new PointIterator object.
454
         *
455
         * @param p
456
         *            The polygon
457
         * @param at
458
         *            The affine transform applied to coordinates during
459
         *            iteration
460
         */
461
        public LineIterator(AffineTransform at) {
462
            super(new GeneralPathX());
463
            if (at == null) {
464
                at = new AffineTransform();
465
            }
466

    
467
            this.at = at;
468
            done = false;
469
        }
470

    
471
        /**
472
         * Return the winding rule for determining the interior of the path.
473
         *
474
         * @return <code>WIND_EVEN_ODD</code> by default.
475
         */
476
        public int getWindingRule() {
477
            return PathIterator.WIND_EVEN_ODD;
478
        }
479

    
480
        /**
481
         * @see java.awt.geom.PathIterator#next()
482
         */
483
        public void next() {
484
            done = (coordinates.size() == ++index);
485
        }
486

    
487
        /**
488
         * @see java.awt.geom.PathIterator#isDone()
489
         */
490
        public boolean isDone() {
491
            return done;
492
        }
493

    
494
        /**
495
         * @see java.awt.geom.PathIterator#currentSegment(double[])
496
         */
497
        public int currentSegment(double[] coords) {
498
            coords[0] = coordinates.getX(index);
499
            coords[1] = coordinates.getY(index);
500
            at.transform(coords, 0, coords, 0, 1);
501

    
502
            if (index == 0) {
503
                return PathIterator.SEG_MOVETO;
504
            } else {
505
                return PathIterator.SEG_LINETO;
506
            }
507
        }
508

    
509
        /*
510
         * (non-Javadoc)
511
         *
512
         * @see java.awt.geom.PathIterator#currentSegment(float[])
513
         */
514
        public int currentSegment(float[] coords) {
515
            coords[0] = (float) coordinates.getX(index);
516
            coords[1] = (float) coordinates.getY(index);
517
            at.transform(coords, 0, coords, 0, 1);
518

    
519
            if (index == 0) {
520
                return PathIterator.SEG_MOVETO;
521
            } else {
522
                return PathIterator.SEG_LINETO;
523
            }
524
        }
525
    }
526

    
527
    /*
528
     * (non-Javadoc)
529
     *
530
     * @see org.gvsig.fmap.geom.jts.GeometryJTS#is3D()
531
     */
532
    public boolean is3D() {
533
        int subtype = this.getGeometryType().getType();
534
        return subtype == Geometry.SUBTYPES.GEOM3D || subtype == Geometry.SUBTYPES.GEOM3DM;
535
    }
536

    
537
//    protected boolean isClosed(){
538
//        return coordinates.get(0).equals(coordinates.get(coordinates.size()-1));
539
//    }
540

    
541
    /* (non-Javadoc)
542
     * @see org.gvsig.fmap.geom.jts.GeometryJTS#flip()
543
     */
544
    public void flip() throws GeometryOperationNotSupportedException, GeometryOperationException {
545
        Collections.reverse(coordinates);
546
    }
547

    
548
    protected ArrayListCoordinateSequence cloneCoordinates() {
549
        ArrayListCoordinateSequence cloned = new ArrayListCoordinateSequence();
550
        cloned.ensureCapacity(coordinates.size());
551
        for (Iterator iterator = coordinates.iterator(); iterator.hasNext();) {
552
            Coordinate coordinate = (Coordinate) iterator.next();
553
            cloned.add((Coordinate)coordinate.clone());
554
        }
555
        return cloned;
556
    }
557

    
558

    
559
    @Override
560
    public boolean canBeTransformed(AffineTransform at) {
561
        return true;
562
    }
563

    
564
    @Override
565
    public boolean canBeReprojected(ICoordTrans ct) {
566
        return true;
567
    }
568
    
569
    public boolean isClosed() {
570
        return this.isClosed(0);
571
    }
572
    
573
    public boolean isClosed(double tolerance) {
574
        int numVertices = this.getNumVertices();
575
        switch( numVertices ) {
576
            case 0:
577
            case 1:
578
            case 2:
579
                return false;
580
        }
581
            
582
        if( tolerance<0 ) {
583
            tolerance = 0.000001;
584
        }
585
        double[] first = this.getVertex(0).getCoordinates();
586
        double[] last = this.getVertex(numVertices-1).getCoordinates();
587

    
588
        for (int i = 0; i < first.length; i++) {
589
                if (Math.abs(first[i] - last[i]) > tolerance) {
590
                        return false;
591
                }
592
        }
593
        return true;
594
    }
595
    
596
    public void forceClose(double tolerance) {
597
        Point first;
598
        int numVertices = this.getNumVertices();
599
        switch( numVertices ) {
600
            case 0:
601
                return;
602
            case 1:
603
                first = this.getVertex(0);
604
                this.addVertex((Point) first.cloneGeometry());
605
                this.addVertex((Point) first.cloneGeometry());
606
                return;
607
            case 2:
608
                first = this.getVertex(0);
609
                this.addVertex((Point) first.cloneGeometry());
610
                return;
611
        }
612
        if( this.isClosed(0) ) {
613
            return;
614
        }
615
        
616
        first = this.getVertex(0);
617
        if( this.isClosed(tolerance) ) {
618
            this.setVertex(numVertices-1,(Point) first.cloneGeometry());
619
        } else {
620
            this.addVertex((Point) first.cloneGeometry());
621
        }
622
    }
623
    
624

    
625
    @Override
626
    public Geometry force2D() throws GeometryOperationNotSupportedException, GeometryOperationException {
627
        ArrayListCoordinateSequence coordinates2D = new ArrayListCoordinateSequence(coordinates.size());
628
        for (Coordinate coordinate : this.coordinates) {
629
            coordinates2D.add(new Coordinate(coordinate.x, coordinate.y));
630
        }
631
        Line2D l = new Line2D(coordinates2D);
632
        return l;
633
    }
634

    
635
}