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 @ 47432

History | View | Annotate | Download (19.1 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 com.vividsolutions.jts.geom.Coordinate;
26
import com.vividsolutions.jts.geom.CoordinateSequence;
27
import java.awt.Shape;
28
import java.awt.geom.AffineTransform;
29
import java.awt.geom.GeneralPath;
30
import java.awt.geom.PathIterator;
31
import java.util.Collections;
32
import java.util.Iterator;
33
import org.apache.commons.lang3.StringUtils;
34
import org.cresques.cts.ICoordTrans;
35
import org.gvsig.fmap.geom.Geometry;
36
import org.gvsig.fmap.geom.jts.gputils.DefaultGeneralPathX;
37
import org.gvsig.fmap.geom.jts.gputils.GeneralPathXIterator;
38
import org.gvsig.fmap.geom.jts.mgeom.MCoordinate;
39
import org.gvsig.fmap.geom.jts.primitive.curve.AbstractCurve;
40
import org.gvsig.fmap.geom.jts.primitive.point.Point2D;
41
import org.gvsig.fmap.geom.jts.primitive.point.PointJTS;
42
import org.gvsig.fmap.geom.jts.util.ArrayListCoordinateSequence;
43
import org.gvsig.fmap.geom.jts.util.JTSUtils;
44
import org.gvsig.fmap.geom.operation.GeometryOperationException;
45
import org.gvsig.fmap.geom.operation.GeometryOperationNotSupportedException;
46
import org.gvsig.fmap.geom.primitive.GeneralPathX;
47
import org.gvsig.fmap.geom.primitive.IGeneralPathX;
48
import org.gvsig.fmap.geom.primitive.OrientablePrimitive;
49
import org.gvsig.fmap.geom.primitive.Point;
50
import org.gvsig.tools.util.GetItem;
51
import org.gvsig.tools.util.Size;
52
import org.slf4j.Logger;
53
import org.slf4j.LoggerFactory;
54

    
55
/**
56
 * @author fdiaz
57
 *
58
 */
59
public abstract class AbstractLine extends AbstractCurve implements Size, GetItem<Point> {
60

    
61
    /**
62
     *
63
     */
64
    private static final long serialVersionUID = 5034197096871344597L;
65
    protected static final Logger LOGGER = LoggerFactory.getLogger(AbstractLine.class);
66

    
67
    protected ArrayListCoordinateSequence coordinates;
68

    
69
    public class VertexIterator implements Iterator<Point> {
70

    
71
        private final PointJTS vertex;
72
        private int current;
73

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

    
83
        @Override
84
        public boolean hasNext() {
85
            return this.current < getNumVertices() ;
86
        }
87

    
88
        @Override
89
        public Point next() {
90
            this.vertex.setJTSCoordinate(coordinates.get(current) );
91
            this.current++;
92
            return this.vertex;
93
        }
94

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

    
100
    }
101
    /**
102
    *
103
     * @param subtype
104
    */
105
    protected AbstractLine(int subtype) {
106
        super(Geometry.TYPES.LINE, subtype);
107
    }
108

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

    
117
    @Override
118
    abstract public Point getVertex(int index);
119

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

    
124
    @Override
125
    public com.vividsolutions.jts.geom.Geometry getJTS() {
126
        return JTSUtils.createJTSLineString(coordinates);
127
    }
128

    
129
    @Override
130
    public OrientablePrimitive addVertex(Point point) {
131
        point = fixPoint(point);
132
        coordinates.add(((PointJTS) point).getJTSCoordinate());
133
        return (OrientablePrimitive) this;
134
    }
135

    
136
    public void setPoints(Point initialPoint, Point endPoint) {
137
        initialPoint = fixPoint(initialPoint);
138
        endPoint = fixPoint(endPoint);
139
        coordinates.clear();
140
        addVertex(initialPoint);
141
        addVertex(endPoint);
142
    }
143

    
144
    /**
145
     * @param point
146
     * @return
147
     */
148
    protected abstract Point fixPoint(Point point);
149

    
150
    @Override
151
    public double getCoordinateAt(int index, int dimension) {
152
        return coordinates.getOrdinate(index, dimension);
153
    }
154

    
155
    @Override
156
    public OrientablePrimitive  setCoordinateAt(int index, int dimension, double value) {
157
        coordinates.setOrdinate(index, dimension, value);
158
        return (OrientablePrimitive) this;
159
    }
160

    
161
    @Override
162
    public void removeVertex(int index) {
163
        coordinates.remove(index);
164
    }
165

    
166
    @Override
167
    public boolean isEmpty() {
168
        return coordinates==null || coordinates.isEmpty();
169
    }
170
    
171
    @Override
172
    public int getNumVertices() {
173
        if( isEmpty() ) {
174
            return 0;
175
        }
176
        return coordinates.size();
177
    }
178

    
179
    @Override
180
    public OrientablePrimitive insertVertex(int index, Point p) {
181
        p = fixPoint(p);
182
        coordinates.add(index, ((PointJTS) p).getJTSCoordinate());
183
        return (OrientablePrimitive) this;
184
    }
185

    
186
    @Override
187
    public OrientablePrimitive setVertex(int index, Point p) {
188
        p = fixPoint(p);
189
        coordinates.set(index, ((PointJTS) p).getJTSCoordinate());
190
        return (OrientablePrimitive) this;
191
    }
192

    
193
    @Override
194
    public void setGeneralPath(GeneralPathX generalPathX) {
195
        PathIterator it = generalPathX.getPathIterator(null);
196
        double[] segment = new double[6];
197
        int i = 0;
198
        while(!it.isDone()){
199
            int type = it.currentSegment(segment);
200
            if(i==0){
201
                switch (type) {
202
                case IGeneralPathX.SEG_MOVETO:
203
                    Point p = new Point2D(segment[0], segment[1]);
204
                    p = fixPoint(p);
205
                    coordinates.add(((PointJTS)p).getJTSCoordinate());
206
                    break;
207
                default:
208
                    String message = StringUtils.replace("Type of segment %(segment)s isn't SEG_MOVETO.","%(segment)s",String.valueOf(i));
209
                    LOGGER.warn(message);
210
                    throw new RuntimeException(message);
211
                }
212
            } else {
213
                //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.
214
                Point p;
215
                switch (type) {
216
                case IGeneralPathX.SEG_LINETO:
217
                    p = new Point2D(segment[0], segment[1]);
218
                    p = fixPoint(p);
219
                    coordinates.add(((PointJTS)p).getJTSCoordinate());
220
                    break;
221
                case IGeneralPathX.SEG_QUADTO:
222
                    for (int j = 0; j <= 1; j++) {
223
                        p = new Point2D(segment[i], segment[i+1]);
224
                        p = fixPoint(p);
225
                        coordinates.add(((PointJTS) p).getJTSCoordinate());
226
                    }
227
                    break;
228
                case IGeneralPathX.SEG_CUBICTO:
229
                    for (int j = 0; j <= 2; j++) {
230
                        p = new Point2D(segment[i], segment[i+1]);
231
                        p = fixPoint(p);
232
                        coordinates.add(((PointJTS) p).getJTSCoordinate());
233
                    }
234
                    break;
235
                case IGeneralPathX.SEG_CLOSE:
236
                    if(!coordinates.get(0).equals(coordinates.get(coordinates.size()-1))){
237
                        coordinates.add(coordinates.get(0));
238
                    }
239
                    break;
240
                default:
241
                    String message = StringUtils.replace("The general path has a gap in segment %(segment)s.","%(segment)s",String.valueOf(i));
242
                    LOGGER.warn(message);
243
                    throw new RuntimeException(message);
244
                }
245
            }
246
            it.next();
247
            i++;
248
        }
249
    }
250

    
251
    @Override
252
    public void addMoveToVertex(Point point) {
253
        notifyDeprecated("Calling deprecated metohd addMoveToVertex in Line");
254
        throw new UnsupportedOperationException();
255
    }
256

    
257
    @Override
258
    public void closePrimitive() {
259
        if (!coordinates.isEmpty() && !isClosed()) {
260
            coordinates.add((Coordinate)coordinates.get(0).clone());
261
        }
262
    }
263

    
264
    @Override
265
    public OrientablePrimitive ensureCapacity(int capacity) {
266
        this.coordinates.ensureCapacity(capacity);
267
        return (OrientablePrimitive) this;
268
    }
269

    
270
    @Override
271
    public void reProject(ICoordTrans ct) {
272
        if (ct == null) {
273
            return;
274
        }
275
        ArrayListCoordinateSequence tmpCoordinates = new ArrayListCoordinateSequence();
276
        tmpCoordinates.ensureCapacity(coordinates.size());
277
        for (Coordinate coordinate : coordinates) {
278
            java.awt.geom.Point2D p = new java.awt.geom.Point2D.Double(coordinate.x, coordinate.y);
279
            try {
280
                p = ct.convert(p, p);
281
                coordinate.x = p.getX();
282
                coordinate.y = p.getY();
283
                tmpCoordinates.add(coordinate);
284
            } catch (Exception exc) {
285
                /*
286
                * This can happen when the reprojection lib is unable
287
                * to reproject (for example the source point
288
                * is out of the valid range and some computing
289
                * problem happens)
290
                */
291
            }
292
        }
293
        coordinates=tmpCoordinates;
294
        this.setProjection(ct.getPDest());
295
    }
296

    
297
    @Override
298
    public void transform(AffineTransform at) {
299
        if (at == null) {
300
            return;
301
        }
302

    
303
        for (int i = 0; i < coordinates.size(); i++) {
304
            Coordinate coordinate = coordinates.get(i);
305
            java.awt.geom.Point2D p = new java.awt.geom.Point2D.Double(coordinate.x, coordinate.y);
306

    
307
            at.transform(p, p);
308
            coordinate.x = p.getX();
309
            coordinate.y = p.getY();
310

    
311
        }
312
    }
313

    
314
    @Override
315
    public int getDimension() {
316
        return this.getGeometryType().getDimension();
317
    }
318

    
319
    @Override
320
    public Shape getShape(AffineTransform affineTransform) {
321
        if( this.isEmpty() ) {
322
            // Esto no deberia de pasar, se trataria de una geometria
323
            // corrupta.
324
            return new GeneralPath();
325
        }
326
        return new DefaultGeneralPathX(getPathIterator(affineTransform),false,0);
327
    }
328

    
329
    @Override
330
    public Shape getShape() {
331
        return new DefaultGeneralPathX(getPathIterator(null),false,0);
332
    }
333

    
334
    @Override
335
    public PathIterator getPathIterator(AffineTransform at) {
336
        LineIterator pi = new LineIterator(at);
337
        return pi;
338
    }
339

    
340
    @Override
341
    public PathIterator getPathIterator(AffineTransform at, double flatness) {
342
        return getPathIterator(at);
343
    }
344

    
345
    @Override
346
    public GeneralPathX getGeneralPath() {
347
        return new DefaultGeneralPathX(getPathIterator(null), false, 0);
348
    }
349

    
350
    protected class LineIterator extends GeneralPathXIterator {
351

    
352
        /** Transform applied on the coordinates during iteration */
353
        private final AffineTransform at;
354

    
355
        /** True when the point has been read once */
356
        private boolean done;
357
        private int index = 0;
358

    
359
        /**
360
         * Creates a new PointIterator object.
361
         * @param at
362
         *            The affine transform applied to coordinates during
363
         *            iteration
364
         */
365
        public LineIterator(AffineTransform at) {
366
            super(new GeneralPathX());
367
            if (at == null) {
368
                at = new AffineTransform();
369
            }
370

    
371
            this.at = at;
372
            done = false;
373
        }
374

    
375
        /**
376
         * Return the winding rule for determining the interior of the path.
377
         *
378
         * @return <code>WIND_EVEN_ODD</code> by default.
379
         */
380
        @Override
381
        public int getWindingRule() {
382
            return PathIterator.WIND_EVEN_ODD;
383
        }
384

    
385
        /**
386
         * @see java.awt.geom.PathIterator#next()
387
         */
388
        @Override
389
        public void next() {
390
            done = (coordinates.size() == ++index);
391
        }
392

    
393
        /**
394
         * @return 
395
         * @see java.awt.geom.PathIterator#isDone()
396
         */
397
        @Override
398
        public boolean isDone() {
399
            return done;
400
        }
401

    
402
        /**
403
         * @param coords
404
         * @return 
405
         * @see java.awt.geom.PathIterator#currentSegment(double[])
406
         */
407
        @Override
408
        public int currentSegment(double[] coords) {
409
            coords[0] = coordinates.getX(index);
410
            coords[1] = coordinates.getY(index);
411
            at.transform(coords, 0, coords, 0, 1);
412

    
413
            if (index == 0) {
414
                return PathIterator.SEG_MOVETO;
415
            } else {
416
                return PathIterator.SEG_LINETO;
417
            }
418
        }
419

    
420
        /*
421
         * (non-Javadoc)
422
         *
423
         * @see java.awt.geom.PathIterator#currentSegment(float[])
424
         */
425
        @Override
426
        public int currentSegment(float[] coords) {
427
            coords[0] = (float) coordinates.getX(index);
428
            coords[1] = (float) coordinates.getY(index);
429
            at.transform(coords, 0, coords, 0, 1);
430

    
431
            if (index == 0) {
432
                return PathIterator.SEG_MOVETO;
433
            } else {
434
                return PathIterator.SEG_LINETO;
435
            }
436
        }
437
    }
438

    
439
    @Override
440
    public boolean is3D() {
441
        int subtype = this.getGeometryType().getType();
442
        return subtype == Geometry.SUBTYPES.GEOM3D || subtype == Geometry.SUBTYPES.GEOM3DM;
443
    }
444

    
445
//    protected boolean isClosed(){
446
//        return coordinates.get(0).equals(coordinates.get(coordinates.size()-1));
447
//    }
448

    
449
    @Override
450
    public void flip() throws GeometryOperationNotSupportedException, GeometryOperationException {
451
        Collections.reverse(coordinates);
452
    }
453

    
454
    protected ArrayListCoordinateSequence cloneCoordinates() {
455
        ArrayListCoordinateSequence cloned = new ArrayListCoordinateSequence();
456
        cloned.ensureCapacity(coordinates.size());
457
        for (Coordinate coordinate : coordinates) {
458
            cloned.add((Coordinate)coordinate.clone());
459
        }
460
        return cloned;
461
    }
462

    
463

    
464
    @Override
465
    public boolean canBeTransformed(AffineTransform at) {
466
        return true;
467
    }
468

    
469
    @Override
470
    public boolean canBeReprojected(ICoordTrans ct) {
471
        return true;
472
    }
473
    
474
    public boolean isClosed() {
475
        return this.isClosed(0);
476
    }
477
    
478
    public boolean isClosed(double tolerance) {
479
        int numVertices = this.getNumVertices();
480
        switch( numVertices ) {
481
            case 0:
482
            case 1:
483
            case 2:
484
                return false;
485
        }
486
            
487
        if( tolerance<0 ) {
488
            tolerance = 0.000001;
489
        }
490
        double[] first = this.getVertex(0).getCoordinates();
491
        double[] last = this.getVertex(numVertices-1).getCoordinates();
492

    
493
        for (int i = 0; i < first.length; i++) {
494
                if (Math.abs(first[i] - last[i]) > tolerance) {
495
                        return false;
496
                }
497
        }
498
        return true;
499
    }
500
    
501
    public void forceClose(double tolerance) {
502
        Point first;
503
        int numVertices = this.getNumVertices();
504
        switch( numVertices ) {
505
            case 0:
506
                return;
507
            case 1:
508
                first = this.getVertex(0);
509
                this.addVertex((Point) first.cloneGeometry());
510
                this.addVertex((Point) first.cloneGeometry());
511
                return;
512
            case 2:
513
                first = this.getVertex(0);
514
                this.addVertex((Point) first.cloneGeometry());
515
                return;
516
        }
517
        if( this.isClosed(0) ) {
518
            return;
519
        }
520
        
521
        first = this.getVertex(0);
522
        if( this.isClosed(tolerance) ) {
523
            this.setVertex(numVertices-1,(Point) first.cloneGeometry());
524
        } else {
525
            this.addVertex((Point) first.cloneGeometry());
526
        }
527
    }
528
    
529

    
530
    @Override
531
    public Geometry force2D() throws GeometryOperationNotSupportedException, GeometryOperationException {
532
        ArrayListCoordinateSequence coordinates2D = new ArrayListCoordinateSequence(coordinates.size());
533
        for (Coordinate coordinate : this.coordinates) {
534
            coordinates2D.add(new Coordinate(coordinate.x, coordinate.y));
535
        }
536
        Line2D l = new Line2D(coordinates2D);
537
        return l;
538
    }
539

    
540
    @Override
541
    public Geometry force2DM() throws GeometryOperationNotSupportedException, GeometryOperationException {
542
        if(this instanceof Line2DM){
543
            return this;
544
        }
545
        ArrayListCoordinateSequence coordinates2DM = new ArrayListCoordinateSequence(coordinates.size());
546
        for (Coordinate coordinate : this.coordinates) {
547
            coordinates2DM.add(MCoordinate.create2dWithMeasure(
548
                    coordinate.x, 
549
                    coordinate.y, 
550
                    (coordinate instanceof MCoordinate)?coordinate.getOrdinate(CoordinateSequence.M):0));
551
        }
552
        Line2DM line = new Line2DM(coordinates2DM);
553
        line.setProjection(this.getProjection());
554
        return line;
555
    }
556

    
557
    @Override
558
    public Geometry force3D() throws GeometryOperationNotSupportedException, GeometryOperationException {
559
        ArrayListCoordinateSequence coordinates3D = new ArrayListCoordinateSequence(coordinates.size());
560
        for (Coordinate coordinate : this.coordinates) {
561
            coordinates3D.add(new Coordinate(
562
                    coordinate.x, 
563
                    coordinate.y, 
564
                    Double.isNaN(coordinate.z)?0:coordinate.z
565
            ));
566
        }
567
        Line3D line = new Line3D(coordinates3D);
568
        line.setProjection(this.getProjection());
569
        return line;
570
    }
571

    
572
    @Override
573
    public Geometry force3DM() throws GeometryOperationNotSupportedException, GeometryOperationException {
574
        ArrayListCoordinateSequence coordinates3DM = new ArrayListCoordinateSequence(coordinates.size());
575
        for (Coordinate coordinate : this.coordinates) {
576
            coordinates3DM.add(MCoordinate.create3dWithMeasure(
577
                    coordinate.x, 
578
                    coordinate.y, 
579
                    (Double.isNaN(coordinate.z))?0:coordinate.z, 
580
                    (coordinate instanceof MCoordinate)?coordinate.getOrdinate(CoordinateSequence.M):0
581
            ));
582
        }
583
        Line3DM line = new Line3DM(coordinates3DM);
584
        line.setProjection(this.getProjection());
585
        return line;
586
    }
587

    
588
    
589
    @Override
590
    public int size() {
591
        return this.getNumVertices();
592
    }
593

    
594
    @Override
595
    public Point get(int position) {
596
        return this.getVertex(position);
597
    }
598
    
599
    public double getPathLength(Point point) {
600
        return JTSUtils.getPathLengthFromLine(this, point);
601
    }
602
    
603
    public Point extractPoint(double length) {
604
        return JTSUtils.extractPointFromLine(this, length);
605
    }
606
    
607

    
608
}