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

History | View | Annotate | Download (17.3 KB)

1 42267 fdiaz
/* 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 42281 fdiaz
import java.util.Collections;
29 42267 fdiaz
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 42281 fdiaz
import org.gvsig.fmap.geom.operation.GeometryOperationException;
54
import org.gvsig.fmap.geom.operation.GeometryOperationNotSupportedException;
55 42267 fdiaz
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
    }
169
170
    /*
171
     * (non-Javadoc)
172
     *
173
     * @see
174
     * org.gvsig.fmap.geom.primitive.Curve#setPoints(org.gvsig.fmap.geom.primitive
175
     * .Point, org.gvsig.fmap.geom.primitive.Point)
176
     */
177
    public void setPoints(Point initialPoint, Point endPoint) {
178
        initialPoint = fixPoint(initialPoint);
179
        endPoint = fixPoint(endPoint);
180
        coordinates.clear();
181
        addVertex(initialPoint);
182
        addVertex(endPoint);
183
    }
184
185
    /**
186
     * @param initialPoint
187
     * @return
188
     */
189
    protected abstract Point fixPoint(Point point);
190
191
    /*
192
     * (non-Javadoc)
193
     *
194
     * @see
195
     * org.gvsig.fmap.geom.primitive.OrientablePrimitive#getCoordinateAt(int,
196
     * int)
197
     */
198
    public double getCoordinateAt(int index, int dimension) {
199
        return coordinates.getOrdinate(index, dimension);
200
    }
201
202
    /*
203
     * (non-Javadoc)
204
     *
205
     * @see
206
     * org.gvsig.fmap.geom.primitive.OrientablePrimitive#setCoordinateAt(int,
207
     * int, double)
208
     */
209
    public void setCoordinateAt(int index, int dimension, double value) {
210
        coordinates.setOrdinate(index, dimension, value);
211
    }
212
213
    /*
214
     * (non-Javadoc)
215
     *
216
     * @see org.gvsig.fmap.geom.primitive.OrientablePrimitive#removeVertex(int)
217
     */
218
    public void removeVertex(int index) {
219
        coordinates.remove(index);
220
    }
221
222
    /*
223
     * (non-Javadoc)
224
     *
225
     * @see org.gvsig.fmap.geom.primitive.OrientablePrimitive#getNumVertices()
226
     */
227
    public int getNumVertices() {
228
        return coordinates.size();
229
    }
230
231
    /*
232
     * (non-Javadoc)
233
     *
234
     * @see org.gvsig.fmap.geom.primitive.OrientablePrimitive#insertVertex(int,
235
     * org.gvsig.fmap.geom.primitive.Point)
236
     */
237
    public void insertVertex(int index, Point p) {
238
        p = fixPoint(p);
239
        coordinates.add(index, ((PointJTS) p).getJTSCoordinate());
240
    }
241
242
    /*
243
     * (non-Javadoc)
244
     *
245
     * @see org.gvsig.fmap.geom.primitive.OrientablePrimitive#setVertex(int,
246
     * org.gvsig.fmap.geom.primitive.Point)
247
     */
248
    public void setVertex(int index, Point p) {
249
        p = fixPoint(p);
250
        coordinates.set(index, ((PointJTS) p).getJTSCoordinate());
251
    }
252
253
    /*
254
     * (non-Javadoc)
255
     *
256
     * @see
257
     * org.gvsig.fmap.geom.primitive.OrientablePrimitive#setGeneralPath(org.
258
     * gvsig.fmap.geom.primitive.GeneralPathX)
259
     */
260
    public void setGeneralPath(GeneralPathX generalPathX) {
261
262
        PathIterator it = generalPathX.getPathIterator(null);
263
        double[] segment = new double[6];
264
        int i = 0;
265
        while(!it.isDone()){
266
            int type = it.currentSegment(segment);
267
            if(i==0){
268
                switch (type) {
269
                case IGeneralPathX.SEG_MOVETO:
270
                    Point p = new Point2D(segment[0], segment[1]);
271
                    p = fixPoint(p);
272
                    coordinates.add(((PointJTS)p).getJTSCoordinate());
273
                    break;
274
                default:
275
                    String message = StringUtils.replace("Type of segment %(segment)s isn't SEG_MOVETO.","%(segment)s",String.valueOf(i));
276
                    logger.warn(message);
277
                    throw new RuntimeException(message);
278
                }
279
            } else {
280
                //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.
281
                Point p;
282
                switch (type) {
283
                case IGeneralPathX.SEG_LINETO:
284
                    p = new Point2D(segment[0], segment[1]);
285
                    p = fixPoint(p);
286
                    coordinates.add(((PointJTS)p).getJTSCoordinate());
287
                    break;
288
                case IGeneralPathX.SEG_QUADTO:
289
                    for (int j = 0; j <= 1; j++) {
290
                        p = new Point2D(segment[i], segment[i+1]);
291
                        p = fixPoint(p);
292
                        coordinates.add(((PointJTS) p).getJTSCoordinate());
293
                    }
294
                    break;
295
                case IGeneralPathX.SEG_CUBICTO:
296
                    for (int j = 0; j <= 2; j++) {
297
                        p = new Point2D(segment[i], segment[i+1]);
298
                        p = fixPoint(p);
299
                        coordinates.add(((PointJTS) p).getJTSCoordinate());
300
                    }
301
                    break;
302
                case IGeneralPathX.SEG_CLOSE:
303
                    coordinates.add(coordinates.get(0));
304
                    break;
305
                default:
306
                    String message = StringUtils.replace("The general path has a gap in segment %(segment)s.","%(segment)s",String.valueOf(i));
307
                    logger.warn(message);
308
                    throw new RuntimeException(message);
309
                }
310
            }
311
            it.next();
312
            i++;
313
        }
314
    }
315
316
    /*
317
     * (non-Javadoc)
318
     *
319
     * @see
320
     * org.gvsig.fmap.geom.primitive.OrientablePrimitive#addMoveToVertex(org
321
     * .gvsig.fmap.geom.primitive.Point)
322
     */
323
    public void addMoveToVertex(Point point) {
324
        throw new UnsupportedOperationException();
325
    }
326
327
    /*
328
     * (non-Javadoc)
329
     *
330
     * @see org.gvsig.fmap.geom.primitive.OrientablePrimitive#closePrimitive()
331
     */
332
    public void closePrimitive() {
333
        if (!coordinates.get(0).equals(coordinates.get(coordinates.size()))) {
334
            coordinates.add(coordinates.get(coordinates.size()));
335
        }
336
    }
337
338
    /*
339
     * (non-Javadoc)
340
     *
341
     * @see
342
     * org.gvsig.fmap.geom.primitive.OrientablePrimitive#ensureCapacity(int)
343
     */
344
    public void ensureCapacity(int capacity) {
345
        coordinates.ensureCapacity(capacity);
346
    }
347
348
    /*
349
     * (non-Javadoc)
350
     *
351
     * @see org.gvsig.fmap.geom.Geometry#reProject(org.cresques.cts.ICoordTrans)
352
     */
353
    public void reProject(ICoordTrans ct) {
354
        if (ct == null) {
355
            return;
356
        }
357 42271 fdiaz
        for (Iterator<Coordinate> iterator = coordinates.iterator(); iterator.hasNext();) {
358 42267 fdiaz
            Coordinate coordinate = (Coordinate) iterator.next();
359
360
            java.awt.geom.Point2D p = new java.awt.geom.Point2D.Double(coordinate.x, coordinate.y);
361
            try {
362
                p = ct.convert(p, p);
363
                coordinate.x = p.getX();
364
                coordinate.y = p.getY();
365
            } catch (Exception exc) {
366
                /*
367
                 * This can happen when the reprojection lib is unable
368
                 * to reproject (for example the source point
369
                 * is out of the valid range and some computing
370
                 * problem happens)
371
                 */
372
                throw new ReprojectionRuntimeException(ct.getPOrig(), ct.getPDest(), p, exc);
373
            }
374
        }
375
    }
376
377
    /*
378
     * (non-Javadoc)
379
     *
380
     * @see
381
     * org.gvsig.fmap.geom.Geometry#transform(java.awt.geom.AffineTransform)
382
     */
383
    public void transform(AffineTransform at) {
384
        if (at == null) {
385
            return;
386
        }
387
388 42271 fdiaz
        for (Iterator<Coordinate> iterator = coordinates.iterator(); iterator.hasNext();) {
389 42267 fdiaz
            Coordinate coordinate = (Coordinate) iterator.next();
390
            java.awt.geom.Point2D p = new java.awt.geom.Point2D.Double(coordinate.x, coordinate.y);
391
392
            at.transform(p, p);
393
            coordinate.x = p.getX();
394
            coordinate.y = p.getY();
395
        }
396
    }
397
398
    /*
399
     * (non-Javadoc)
400
     *
401
     * @see org.gvsig.fmap.geom.Geometry#getDimension()
402
     */
403
    public int getDimension() {
404
        return anyVertex.getDimension();
405
    }
406
407
    /*
408
     * (non-Javadoc)
409
     *
410
     * @see org.gvsig.fmap.geom.Geometry#getShape(java.awt.geom.AffineTransform)
411
     */
412
    public Shape getShape(AffineTransform affineTransform) {
413
        return new DefaultGeneralPathX(new SplineIterator(affineTransform),false,0);
414
    }
415
416
    /*
417
     * (non-Javadoc)
418
     *
419
     * @see org.gvsig.fmap.geom.Geometry#getShape()
420
     */
421
    public Shape getShape() {
422
        return getShape(null);
423
    }
424
425
    /*
426
     * (non-Javadoc)
427
     *
428
     * @see org.gvsig.fmap.geom.Geometry#getHandlers(int)
429
     */
430
    public Handler[] getHandlers(int type) {
431
        notifyDeprecated("Calling deprecated method getHandlers of a line");
432
        throw new UnsupportedOperationException("Calling deprecated method getHandlers of a line");
433
    }
434
435
    /*
436
     * (non-Javadoc)
437
     *
438
     * @see
439
     * org.gvsig.fmap.geom.Geometry#getPathIterator(java.awt.geom.AffineTransform
440
     * )
441
     */
442
    public PathIterator getPathIterator(AffineTransform at) {
443
        SplineIterator pi = new SplineIterator(at);
444
        return pi;
445
    }
446
447
    /*
448
     * (non-Javadoc)
449
     *
450
     * @see
451
     * org.gvsig.fmap.geom.Geometry#getPathIterator(java.awt.geom.AffineTransform
452
     * , double)
453
     */
454
    public PathIterator getPathIterator(AffineTransform at, double flatness) {
455
        return getPathIterator(at);
456
    }
457
458
    /*
459
     * (non-Javadoc)
460
     *
461
     * @see org.gvsig.fmap.geom.Geometry#getGeneralPath()
462
     */
463
    public GeneralPathX getGeneralPath() {
464
        return new DefaultGeneralPathX(new SplineIterator(null),false,0);
465
    }
466
467
    public class SplineIterator extends GeneralPathXIterator {
468
469
        /** Transform applied on the coordinates during iteration */
470
        private AffineTransform at;
471
472
        /** True when the point has been read once */
473
        private boolean done;
474
        private int index = 0;
475
476
        /**
477
         * Creates a new PointIterator object.
478
         *
479
         * @param p
480
         *            The polygon
481
         * @param at
482
         *            The affine transform applied to coordinates during
483
         *            iteration
484
         */
485
        public SplineIterator(AffineTransform at) {
486
            super(new GeneralPathX());
487
            if (at == null) {
488
                at = new AffineTransform();
489
            }
490
491
            this.at = at;
492
            done = false;
493
        }
494
495
        /**
496
         * Return the winding rule for determining the interior of the path.
497
         *
498
         * @return <code>WIND_EVEN_ODD</code> by default.
499
         */
500
        public int getWindingRule() {
501
            return PathIterator.WIND_EVEN_ODD;
502
        }
503
504
        /**
505
         * @see java.awt.geom.PathIterator#next()
506
         */
507
        public void next() {
508
            done = (getJTS().getCoordinates().length == index++);
509
        }
510
511
        /**
512
         * @see java.awt.geom.PathIterator#isDone()
513
         */
514
        public boolean isDone() {
515
            return done;
516
        }
517
518
        /**
519
         * @see java.awt.geom.PathIterator#currentSegment(double[])
520
         */
521
        public int currentSegment(double[] coords) {
522
            Coordinate[] jtsCoordinates = getJTS().getCoordinates();
523
            coords[0] = jtsCoordinates[index].x;
524
            coords[1] = jtsCoordinates[index].y;
525
            at.transform(coords, 0, coords, 0, 1);
526
527
            if (index == 0) {
528
                return PathIterator.SEG_MOVETO;
529
            } else {
530
                return PathIterator.SEG_LINETO;
531
            }
532
        }
533
534
        /*
535
         * (non-Javadoc)
536
         *
537
         * @see java.awt.geom.PathIterator#currentSegment(float[])
538
         */
539
        public int currentSegment(float[] coords) {
540
            Coordinate[] jtsCoordinates = getJTS().getCoordinates();
541
            coords[0] = (float)jtsCoordinates[index].x;
542
            coords[1] = (float)jtsCoordinates[index].y;
543
            at.transform(coords, 0, coords, 0, 1);
544
545
            if (index == 0) {
546
                return PathIterator.SEG_MOVETO;
547
            } else {
548
                return PathIterator.SEG_LINETO;
549
            }
550
        }
551
    }
552
553
554
    /*
555
     * (non-Javadoc)
556
     *
557
     * @see org.gvsig.fmap.geom.jts.GeometryJTS#is3D()
558
     */
559
    public boolean is3D() {
560
        return anyVertex.is3D();
561
    }
562
563 42281 fdiaz
564
    /* (non-Javadoc)
565
     * @see org.gvsig.fmap.geom.jts.GeometryJTS#flip()
566
     */
567
    public void flip() throws GeometryOperationNotSupportedException, GeometryOperationException {
568
        Collections.reverse(coordinates);
569
    }
570
571 42267 fdiaz
}