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 / spline / AbstractSpline.java @ 42283

History | View | Annotate | Download (17.8 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.spline;
24

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

    
31
import com.vividsolutions.jts.geom.Coordinate;
32

    
33
import org.apache.commons.lang3.StringUtils;
34
import org.cresques.cts.ICoordTrans;
35
import org.slf4j.Logger;
36
import org.slf4j.LoggerFactory;
37

    
38
import org.gvsig.fmap.geom.Geometry;
39
import org.gvsig.fmap.geom.GeometryException;
40
import org.gvsig.fmap.geom.aggregate.MultiLine;
41
import org.gvsig.fmap.geom.aggregate.MultiPoint;
42
import org.gvsig.fmap.geom.aggregate.MultiPolygon;
43
import org.gvsig.fmap.geom.exception.ReprojectionRuntimeException;
44
import org.gvsig.fmap.geom.handler.Handler;
45
import org.gvsig.fmap.geom.jts.gputils.DefaultGeneralPathX;
46
import org.gvsig.fmap.geom.jts.gputils.GeneralPathXIterator;
47
import org.gvsig.fmap.geom.jts.primitive.curve.AbstractCurve;
48
import org.gvsig.fmap.geom.jts.primitive.point.Point2D;
49
import org.gvsig.fmap.geom.jts.primitive.point.PointJTS;
50
import org.gvsig.fmap.geom.jts.util.ArrayListCoordinateSequence;
51
import org.gvsig.fmap.geom.jts.util.JTSUtils;
52
import org.gvsig.fmap.geom.jts.util.ReadOnlyCoordinates;
53
import org.gvsig.fmap.geom.operation.GeometryOperationException;
54
import org.gvsig.fmap.geom.operation.GeometryOperationNotSupportedException;
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.primitive.Spline;
59

    
60

    
61
/**
62
 * @author fdiaz
63
 *
64
 */
65
public abstract class AbstractSpline extends AbstractCurve implements Spline {
66

    
67
    /**
68
     *
69
     */
70
    private static final long serialVersionUID = -1562503359430991082L;
71

    
72
    private static final Logger logger = LoggerFactory.getLogger(AbstractSpline.class);
73

    
74
    protected ArrayListCoordinateSequence coordinates;
75
    protected PointJTS anyVertex;
76
    protected static final double SUBSEGMENTS = 30.0;
77

    
78
    /**
79
    *
80
    */
81
    protected AbstractSpline(int subtype) {
82
        super(Geometry.TYPES.SPLINE, subtype);
83
    }
84

    
85
    /**
86
     *
87
     */
88
    public AbstractSpline(int subtype, Coordinate[] coordinates, PointJTS aVertex) {
89
        this(subtype);
90
        this.coordinates = new ArrayListCoordinateSequence(new ReadOnlyCoordinates(coordinates));
91
        anyVertex = aVertex;
92
    }
93

    
94

    
95
    /*
96
     * (non-Javadoc)
97
     *
98
     * @see org.gvsig.fmap.geom.jts.GeometryJTS#getJTS()
99
     */
100
    public com.vividsolutions.jts.geom.Geometry getJTS() {
101
//        if (ps[0].getX()==ps[ps.length-1].getX() && ps[0].getY()==ps[ps.length-1].getY())
102
//            gpx.closePath();
103
        return JTSUtils.createJTSLineString(getSplineCoordinates());
104
    }
105

    
106
    protected abstract ArrayListCoordinateSequence getSplineCoordinates();
107

    
108

    
109
    static class Spline {
110
        private double y[];
111
        private double y2[];
112

    
113
        /**
114
         * The constructor calculates the second derivatives of the interpolating function
115
         * at the tabulated points xi, with xi = (i, y[i]).
116
         * Based on numerical recipes in C, http://www.library.cornell.edu/nr/bookcpdf/c3-3.pdf .
117
         * @param y Array of y coordinates for cubic-spline interpolation.
118
         */
119
        public Spline(double y[]) {
120
            this.y = y;
121
            int n = y.length;
122
            y2 = new double[n];
123
            double u[] = new double[n];
124
            for (int i = 1; i < n - 1; i++) {
125
                y2[i] = -1.0 / (4.0 + y2[i - 1]);
126
                u[i] = (6.0 * (y[i + 1] - 2.0 * y[i] + y[i - 1]) - u[i - 1]) / (4.0 + y2[i - 1]);
127
            }
128
            for (int i = n - 2; i >= 0; i--) {
129
                y2[i] = y2[i] * y2[i + 1] + u[i];
130
            }
131
        }
132

    
133
        /**
134
         * Returns a cubic-spline interpolated value y for the point between
135
         * point (n, y[n]) and (n+1, y[n+1), with t ranging from 0 for (n, y[n])
136
         * to 1 for (n+1, y[n+1]).
137
         * @param n The start point.
138
         * @param t The distance to the next point (0..1).
139
         * @return A cubic-spline interpolated value.
140
         */
141
        public double fn(int n, double t) {
142
            return t * y[n + 1] - ((t - 1.0) * t * ((t - 2.0) * y2[n] - (t + 1.0) * y2[n + 1])) / 6.0 + y[n] - t * y[n];
143
        }
144

    
145
    }
146

    
147

    
148
//    /*
149
//     * (non-Javadoc)
150
//     *
151
//     * @see org.gvsig.fmap.geom.primitive.OrientablePrimitive#getVertex(int)
152
//     */
153
//    public Point getVertex(int index) {
154
//        anyVertex.setJTSCoordinate(coordinates.get(index));
155
//        return anyVertex;
156
//    }
157

    
158
    /*
159
     * (non-Javadoc)
160
     *
161
     * @see
162
     * org.gvsig.fmap.geom.primitive.OrientablePrimitive#addVertex(org.gvsig
163
     * .fmap.geom.primitive.Point)
164
     */
165
    public void addVertex(Point point) {
166
        point = fixPoint(point);
167
        coordinates.add(((PointJTS) point).getJTSCoordinate());
168
        anyVertex = (PointJTS) point;
169
    }
170

    
171
    /*
172
     * (non-Javadoc)
173
     *
174
     * @see
175
     * org.gvsig.fmap.geom.primitive.Curve#setPoints(org.gvsig.fmap.geom.primitive
176
     * .Point, org.gvsig.fmap.geom.primitive.Point)
177
     */
178
    public void setPoints(Point initialPoint, Point endPoint) {
179
        initialPoint = fixPoint(initialPoint);
180
        endPoint = fixPoint(endPoint);
181
        coordinates.clear();
182
        addVertex(initialPoint);
183
        addVertex(endPoint);
184
        anyVertex = (PointJTS) endPoint;
185
    }
186

    
187
    /**
188
     * @param initialPoint
189
     * @return
190
     */
191
    protected abstract Point fixPoint(Point point);
192

    
193
    /*
194
     * (non-Javadoc)
195
     *
196
     * @see
197
     * org.gvsig.fmap.geom.primitive.OrientablePrimitive#getCoordinateAt(int,
198
     * int)
199
     */
200
    public double getCoordinateAt(int index, int dimension) {
201
        return coordinates.getOrdinate(index, dimension);
202
    }
203

    
204
    /*
205
     * (non-Javadoc)
206
     *
207
     * @see
208
     * org.gvsig.fmap.geom.primitive.OrientablePrimitive#setCoordinateAt(int,
209
     * int, double)
210
     */
211
    public void setCoordinateAt(int index, int dimension, double value) {
212
        coordinates.setOrdinate(index, dimension, value);
213
    }
214

    
215
    /*
216
     * (non-Javadoc)
217
     *
218
     * @see org.gvsig.fmap.geom.primitive.OrientablePrimitive#removeVertex(int)
219
     */
220
    public void removeVertex(int index) {
221
        coordinates.remove(index);
222
    }
223

    
224
    /*
225
     * (non-Javadoc)
226
     *
227
     * @see org.gvsig.fmap.geom.primitive.OrientablePrimitive#getNumVertices()
228
     */
229
    public int getNumVertices() {
230
        return coordinates.size();
231
    }
232

    
233
    /*
234
     * (non-Javadoc)
235
     *
236
     * @see org.gvsig.fmap.geom.primitive.OrientablePrimitive#insertVertex(int,
237
     * org.gvsig.fmap.geom.primitive.Point)
238
     */
239
    public void insertVertex(int index, Point p) {
240
        p = fixPoint(p);
241
        coordinates.add(index, ((PointJTS) p).getJTSCoordinate());
242
    }
243

    
244
    /*
245
     * (non-Javadoc)
246
     *
247
     * @see org.gvsig.fmap.geom.primitive.OrientablePrimitive#setVertex(int,
248
     * org.gvsig.fmap.geom.primitive.Point)
249
     */
250
    public void setVertex(int index, Point p) {
251
        p = fixPoint(p);
252
        coordinates.set(index, ((PointJTS) p).getJTSCoordinate());
253
    }
254

    
255
    /*
256
     * (non-Javadoc)
257
     *
258
     * @see
259
     * org.gvsig.fmap.geom.primitive.OrientablePrimitive#setGeneralPath(org.
260
     * gvsig.fmap.geom.primitive.GeneralPathX)
261
     */
262
    public void setGeneralPath(GeneralPathX generalPathX) {
263

    
264
        PathIterator it = generalPathX.getPathIterator(null);
265
        double[] segment = new double[6];
266
        int i = 0;
267
        while(!it.isDone()){
268
            int type = it.currentSegment(segment);
269
            if(i==0){
270
                switch (type) {
271
                case IGeneralPathX.SEG_MOVETO:
272
                    Point p = new Point2D(segment[0], segment[1]);
273
                    p = fixPoint(p);
274
                    coordinates.add(((PointJTS)p).getJTSCoordinate());
275
                    break;
276
                default:
277
                    String message = StringUtils.replace("Type of segment %(segment)s isn't SEG_MOVETO.","%(segment)s",String.valueOf(i));
278
                    logger.warn(message);
279
                    throw new RuntimeException(message);
280
                }
281
            } else {
282
                //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.
283
                Point p;
284
                switch (type) {
285
                case IGeneralPathX.SEG_LINETO:
286
                    p = new Point2D(segment[0], segment[1]);
287
                    p = fixPoint(p);
288
                    coordinates.add(((PointJTS)p).getJTSCoordinate());
289
                    break;
290
                case IGeneralPathX.SEG_QUADTO:
291
                    for (int j = 0; j <= 1; j++) {
292
                        p = new Point2D(segment[i], segment[i+1]);
293
                        p = fixPoint(p);
294
                        coordinates.add(((PointJTS) p).getJTSCoordinate());
295
                    }
296
                    break;
297
                case IGeneralPathX.SEG_CUBICTO:
298
                    for (int j = 0; j <= 2; j++) {
299
                        p = new Point2D(segment[i], segment[i+1]);
300
                        p = fixPoint(p);
301
                        coordinates.add(((PointJTS) p).getJTSCoordinate());
302
                    }
303
                    break;
304
                case IGeneralPathX.SEG_CLOSE:
305
                    coordinates.add(coordinates.get(0));
306
                    break;
307
                default:
308
                    String message = StringUtils.replace("The general path has a gap in segment %(segment)s.","%(segment)s",String.valueOf(i));
309
                    logger.warn(message);
310
                    throw new RuntimeException(message);
311
                }
312
            }
313
            it.next();
314
            i++;
315
        }
316
    }
317

    
318
    /*
319
     * (non-Javadoc)
320
     *
321
     * @see
322
     * org.gvsig.fmap.geom.primitive.OrientablePrimitive#addMoveToVertex(org
323
     * .gvsig.fmap.geom.primitive.Point)
324
     */
325
    public void addMoveToVertex(Point point) {
326
        throw new UnsupportedOperationException();
327
    }
328

    
329
    /*
330
     * (non-Javadoc)
331
     *
332
     * @see org.gvsig.fmap.geom.primitive.OrientablePrimitive#closePrimitive()
333
     */
334
    public void closePrimitive() {
335
        if (!coordinates.get(0).equals(coordinates.get(coordinates.size()))) {
336
            coordinates.add(coordinates.get(coordinates.size()));
337
        }
338
    }
339

    
340
    /*
341
     * (non-Javadoc)
342
     *
343
     * @see
344
     * org.gvsig.fmap.geom.primitive.OrientablePrimitive#ensureCapacity(int)
345
     */
346
    public void ensureCapacity(int capacity) {
347
        coordinates.ensureCapacity(capacity);
348
    }
349

    
350
    /*
351
     * (non-Javadoc)
352
     *
353
     * @see org.gvsig.fmap.geom.Geometry#reProject(org.cresques.cts.ICoordTrans)
354
     */
355
    public void reProject(ICoordTrans ct) {
356
        if (ct == null) {
357
            return;
358
        }
359
        for (Iterator<Coordinate> iterator = coordinates.iterator(); iterator.hasNext();) {
360
            Coordinate coordinate = (Coordinate) iterator.next();
361

    
362
            java.awt.geom.Point2D p = new java.awt.geom.Point2D.Double(coordinate.x, coordinate.y);
363
            try {
364
                p = ct.convert(p, p);
365
                coordinate.x = p.getX();
366
                coordinate.y = p.getY();
367
            } catch (Exception exc) {
368
                /*
369
                 * This can happen when the reprojection lib is unable
370
                 * to reproject (for example the source point
371
                 * is out of the valid range and some computing
372
                 * problem happens)
373
                 */
374
                throw new ReprojectionRuntimeException(ct.getPOrig(), ct.getPDest(), p, exc);
375
            }
376
        }
377
    }
378

    
379
    /*
380
     * (non-Javadoc)
381
     *
382
     * @see
383
     * org.gvsig.fmap.geom.Geometry#transform(java.awt.geom.AffineTransform)
384
     */
385
    public void transform(AffineTransform at) {
386
        if (at == null) {
387
            return;
388
        }
389

    
390
        for (Iterator<Coordinate> iterator = coordinates.iterator(); iterator.hasNext();) {
391
            Coordinate coordinate = (Coordinate) iterator.next();
392
            java.awt.geom.Point2D p = new java.awt.geom.Point2D.Double(coordinate.x, coordinate.y);
393

    
394
            at.transform(p, p);
395
            coordinate.x = p.getX();
396
            coordinate.y = p.getY();
397
        }
398
    }
399

    
400
    /*
401
     * (non-Javadoc)
402
     *
403
     * @see org.gvsig.fmap.geom.Geometry#getDimension()
404
     */
405
    public int getDimension() {
406
        return anyVertex.getDimension();
407
    }
408

    
409
    /*
410
     * (non-Javadoc)
411
     *
412
     * @see org.gvsig.fmap.geom.Geometry#getShape(java.awt.geom.AffineTransform)
413
     */
414
    public Shape getShape(AffineTransform affineTransform) {
415
        return new DefaultGeneralPathX(new SplineIterator(affineTransform),false,0);
416
    }
417

    
418
    /*
419
     * (non-Javadoc)
420
     *
421
     * @see org.gvsig.fmap.geom.Geometry#getShape()
422
     */
423
    public Shape getShape() {
424
        return getShape(null);
425
    }
426

    
427
    /*
428
     * (non-Javadoc)
429
     *
430
     * @see org.gvsig.fmap.geom.Geometry#getHandlers(int)
431
     */
432
    public Handler[] getHandlers(int type) {
433
        notifyDeprecated("Calling deprecated method getHandlers of a line");
434
        throw new UnsupportedOperationException("Calling deprecated method getHandlers of a line");
435
    }
436

    
437
    /*
438
     * (non-Javadoc)
439
     *
440
     * @see
441
     * org.gvsig.fmap.geom.Geometry#getPathIterator(java.awt.geom.AffineTransform
442
     * )
443
     */
444
    public PathIterator getPathIterator(AffineTransform at) {
445
        SplineIterator pi = new SplineIterator(at);
446
        return pi;
447
    }
448

    
449
    /*
450
     * (non-Javadoc)
451
     *
452
     * @see
453
     * org.gvsig.fmap.geom.Geometry#getPathIterator(java.awt.geom.AffineTransform
454
     * , double)
455
     */
456
    public PathIterator getPathIterator(AffineTransform at, double flatness) {
457
        return getPathIterator(at);
458
    }
459

    
460
    /*
461
     * (non-Javadoc)
462
     *
463
     * @see org.gvsig.fmap.geom.Geometry#getGeneralPath()
464
     */
465
    public GeneralPathX getGeneralPath() {
466
        return new DefaultGeneralPathX(new SplineIterator(null),false,0);
467
    }
468

    
469
    public class SplineIterator extends GeneralPathXIterator {
470

    
471
        /** Transform applied on the coordinates during iteration */
472
        private AffineTransform at;
473

    
474
        /** True when the point has been read once */
475
        private boolean done;
476
        private int index = 0;
477

    
478
        /**
479
         * Creates a new PointIterator object.
480
         *
481
         * @param p
482
         *            The polygon
483
         * @param at
484
         *            The affine transform applied to coordinates during
485
         *            iteration
486
         */
487
        public SplineIterator(AffineTransform at) {
488
            super(new GeneralPathX());
489
            if (at == null) {
490
                at = new AffineTransform();
491
            }
492

    
493
            this.at = at;
494
            done = false;
495
        }
496

    
497
        /**
498
         * Return the winding rule for determining the interior of the path.
499
         *
500
         * @return <code>WIND_EVEN_ODD</code> by default.
501
         */
502
        public int getWindingRule() {
503
            return PathIterator.WIND_EVEN_ODD;
504
        }
505

    
506
        /**
507
         * @see java.awt.geom.PathIterator#next()
508
         */
509
        public void next() {
510
            done = (getJTS().getCoordinates().length == ++index);
511
        }
512

    
513
        /**
514
         * @see java.awt.geom.PathIterator#isDone()
515
         */
516
        public boolean isDone() {
517
            return done;
518
        }
519

    
520
        /**
521
         * @see java.awt.geom.PathIterator#currentSegment(double[])
522
         */
523
        public int currentSegment(double[] coords) {
524
            Coordinate[] jtsCoordinates = getJTS().getCoordinates();
525
            coords[0] = jtsCoordinates[index].x;
526
            coords[1] = jtsCoordinates[index].y;
527
            at.transform(coords, 0, coords, 0, 1);
528

    
529
            if (index == 0) {
530
                return PathIterator.SEG_MOVETO;
531
            } else {
532
                return PathIterator.SEG_LINETO;
533
            }
534
        }
535

    
536
        /*
537
         * (non-Javadoc)
538
         *
539
         * @see java.awt.geom.PathIterator#currentSegment(float[])
540
         */
541
        public int currentSegment(float[] coords) {
542
            Coordinate[] jtsCoordinates = getJTS().getCoordinates();
543
            coords[0] = (float)jtsCoordinates[index].x;
544
            coords[1] = (float)jtsCoordinates[index].y;
545
            at.transform(coords, 0, coords, 0, 1);
546

    
547
            if (index == 0) {
548
                return PathIterator.SEG_MOVETO;
549
            } else {
550
                return PathIterator.SEG_LINETO;
551
            }
552
        }
553
    }
554

    
555

    
556
    /*
557
     * (non-Javadoc)
558
     *
559
     * @see org.gvsig.fmap.geom.jts.GeometryJTS#is3D()
560
     */
561
    public boolean is3D() {
562
        return anyVertex.is3D();
563
    }
564

    
565

    
566
    /* (non-Javadoc)
567
     * @see org.gvsig.fmap.geom.jts.GeometryJTS#flip()
568
     */
569
    public void flip() throws GeometryOperationNotSupportedException, GeometryOperationException {
570
        Collections.reverse(coordinates);
571
    }
572

    
573
    protected ArrayListCoordinateSequence cloneCoordinates() {
574
        ArrayListCoordinateSequence cloned = new ArrayListCoordinateSequence();
575
        cloned.ensureCapacity(coordinates.size());
576
        for (Iterator iterator = coordinates.iterator(); iterator.hasNext();) {
577
            Coordinate coordinate = (Coordinate) iterator.next();
578
            cloned.add((Coordinate)coordinate.clone());
579
        }
580
        return cloned;
581
    }
582

    
583
}