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

History | View | Annotate | Download (17.6 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.Iterator;
29

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

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

    
37
import org.gvsig.fmap.geom.Geometry;
38
import org.gvsig.fmap.geom.GeometryException;
39
import org.gvsig.fmap.geom.aggregate.MultiLine;
40
import org.gvsig.fmap.geom.aggregate.MultiPoint;
41
import org.gvsig.fmap.geom.aggregate.MultiPolygon;
42
import org.gvsig.fmap.geom.exception.ReprojectionRuntimeException;
43
import org.gvsig.fmap.geom.handler.Handler;
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.jts.util.ReadOnlyCoordinates;
52
import org.gvsig.fmap.geom.primitive.GeneralPathX;
53
import org.gvsig.fmap.geom.primitive.IGeneralPathX;
54
import org.gvsig.fmap.geom.primitive.Point;
55
import org.gvsig.fmap.geom.primitive.Spline;
56

    
57

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

    
64
    /**
65
     *
66
     */
67
    private static final long serialVersionUID = -1562503359430991082L;
68

    
69
    private static final Logger logger = LoggerFactory.getLogger(AbstractSpline.class);
70

    
71
    protected ArrayListCoordinateSequence coordinates;
72
    protected PointJTS anyVertex;
73
    protected static final double SUBSEGMENTS = 30.0;
74

    
75
    /**
76
    *
77
    */
78
    protected AbstractSpline(int subtype) {
79
        super(Geometry.TYPES.SPLINE, subtype);
80
    }
81

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

    
91

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

    
103
    protected abstract ArrayListCoordinateSequence getSplineCoordinates();
104

    
105

    
106
    static class Spline {
107
        private double y[];
108
        private double y2[];
109

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

    
130
        /**
131
         * Returns a cubic-spline interpolated value y for the point between
132
         * point (n, y[n]) and (n+1, y[n+1), with t ranging from 0 for (n, y[n])
133
         * to 1 for (n+1, y[n+1]).
134
         * @param n The start point.
135
         * @param t The distance to the next point (0..1).
136
         * @return A cubic-spline interpolated value.
137
         */
138
        public double fn(int n, double t) {
139
            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];
140
        }
141

    
142
    }
143

    
144

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

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

    
167
    /*
168
     * (non-Javadoc)
169
     *
170
     * @see
171
     * org.gvsig.fmap.geom.primitive.Curve#setPoints(org.gvsig.fmap.geom.primitive
172
     * .Point, org.gvsig.fmap.geom.primitive.Point)
173
     */
174
    public void setPoints(Point initialPoint, Point endPoint) {
175
        initialPoint = fixPoint(initialPoint);
176
        endPoint = fixPoint(endPoint);
177
        coordinates.clear();
178
        addVertex(initialPoint);
179
        addVertex(endPoint);
180
    }
181

    
182
    /**
183
     * @param initialPoint
184
     * @return
185
     */
186
    protected abstract Point fixPoint(Point point);
187

    
188
    /*
189
     * (non-Javadoc)
190
     *
191
     * @see
192
     * org.gvsig.fmap.geom.primitive.OrientablePrimitive#getCoordinateAt(int,
193
     * int)
194
     */
195
    public double getCoordinateAt(int index, int dimension) {
196
        return coordinates.getOrdinate(index, dimension);
197
    }
198

    
199
    /*
200
     * (non-Javadoc)
201
     *
202
     * @see
203
     * org.gvsig.fmap.geom.primitive.OrientablePrimitive#setCoordinateAt(int,
204
     * int, double)
205
     */
206
    public void setCoordinateAt(int index, int dimension, double value) {
207
        coordinates.setOrdinate(index, dimension, value);
208
    }
209

    
210
    /*
211
     * (non-Javadoc)
212
     *
213
     * @see org.gvsig.fmap.geom.primitive.OrientablePrimitive#removeVertex(int)
214
     */
215
    public void removeVertex(int index) {
216
        coordinates.remove(index);
217
    }
218

    
219
    /*
220
     * (non-Javadoc)
221
     *
222
     * @see org.gvsig.fmap.geom.primitive.OrientablePrimitive#getNumVertices()
223
     */
224
    public int getNumVertices() {
225
        return coordinates.size();
226
    }
227

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

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

    
250
    /*
251
     * (non-Javadoc)
252
     *
253
     * @see
254
     * org.gvsig.fmap.geom.primitive.OrientablePrimitive#setGeneralPath(org.
255
     * gvsig.fmap.geom.primitive.GeneralPathX)
256
     */
257
    public void setGeneralPath(GeneralPathX generalPathX) {
258

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

    
313
    /*
314
     * (non-Javadoc)
315
     *
316
     * @see
317
     * org.gvsig.fmap.geom.primitive.OrientablePrimitive#addMoveToVertex(org
318
     * .gvsig.fmap.geom.primitive.Point)
319
     */
320
    public void addMoveToVertex(Point point) {
321
        throw new UnsupportedOperationException();
322
    }
323

    
324
    /*
325
     * (non-Javadoc)
326
     *
327
     * @see org.gvsig.fmap.geom.primitive.OrientablePrimitive#closePrimitive()
328
     */
329
    public void closePrimitive() {
330
        if (!coordinates.get(0).equals(coordinates.get(coordinates.size()))) {
331
            coordinates.add(coordinates.get(coordinates.size()));
332
        }
333
    }
334

    
335
    /*
336
     * (non-Javadoc)
337
     *
338
     * @see
339
     * org.gvsig.fmap.geom.primitive.OrientablePrimitive#ensureCapacity(int)
340
     */
341
    public void ensureCapacity(int capacity) {
342
        coordinates.ensureCapacity(capacity);
343
    }
344

    
345
    /*
346
     * (non-Javadoc)
347
     *
348
     * @see org.gvsig.fmap.geom.Geometry#reProject(org.cresques.cts.ICoordTrans)
349
     */
350
    public void reProject(ICoordTrans ct) {
351
        if (ct == null) {
352
            return;
353
        }
354
        for (Iterator iterator = coordinates.iterator(); iterator.hasNext();) {
355
            Coordinate coordinate = (Coordinate) iterator.next();
356

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

    
374
    /*
375
     * (non-Javadoc)
376
     *
377
     * @see
378
     * org.gvsig.fmap.geom.Geometry#transform(java.awt.geom.AffineTransform)
379
     */
380
    public void transform(AffineTransform at) {
381
        if (at == null) {
382
            return;
383
        }
384

    
385
        for (Iterator iterator = coordinates.iterator(); iterator.hasNext();) {
386
            Coordinate coordinate = (Coordinate) iterator.next();
387
            java.awt.geom.Point2D p = new java.awt.geom.Point2D.Double(coordinate.x, coordinate.y);
388

    
389
            at.transform(p, p);
390
            coordinate.x = p.getX();
391
            coordinate.y = p.getY();
392
        }
393
    }
394

    
395
    /*
396
     * (non-Javadoc)
397
     *
398
     * @see org.gvsig.fmap.geom.Geometry#getDimension()
399
     */
400
    public int getDimension() {
401
        return anyVertex.getDimension();
402
    }
403

    
404
    /*
405
     * (non-Javadoc)
406
     *
407
     * @see org.gvsig.fmap.geom.Geometry#getShape(java.awt.geom.AffineTransform)
408
     */
409
    public Shape getShape(AffineTransform affineTransform) {
410
        return new DefaultGeneralPathX(new SplineIterator(affineTransform),false,0);
411
    }
412

    
413
    /*
414
     * (non-Javadoc)
415
     *
416
     * @see org.gvsig.fmap.geom.Geometry#getShape()
417
     */
418
    public Shape getShape() {
419
        return getShape(null);
420
    }
421

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

    
432
    /*
433
     * (non-Javadoc)
434
     *
435
     * @see
436
     * org.gvsig.fmap.geom.Geometry#getPathIterator(java.awt.geom.AffineTransform
437
     * )
438
     */
439
    public PathIterator getPathIterator(AffineTransform at) {
440
        SplineIterator pi = new SplineIterator(at);
441
        return pi;
442
    }
443

    
444
    /*
445
     * (non-Javadoc)
446
     *
447
     * @see
448
     * org.gvsig.fmap.geom.Geometry#getPathIterator(java.awt.geom.AffineTransform
449
     * , double)
450
     */
451
    public PathIterator getPathIterator(AffineTransform at, double flatness) {
452
        return getPathIterator(at);
453
    }
454

    
455
    /*
456
     * (non-Javadoc)
457
     *
458
     * @see org.gvsig.fmap.geom.Geometry#getGeneralPath()
459
     */
460
    public GeneralPathX getGeneralPath() {
461
        return new DefaultGeneralPathX(new SplineIterator(null),false,0);
462
    }
463

    
464
    public class SplineIterator extends GeneralPathXIterator {
465

    
466
        /** Transform applied on the coordinates during iteration */
467
        private AffineTransform at;
468

    
469
        /** True when the point has been read once */
470
        private boolean done;
471
        private int index = 0;
472

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

    
488
            this.at = at;
489
            done = false;
490
        }
491

    
492
        /**
493
         * Return the winding rule for determining the interior of the path.
494
         *
495
         * @return <code>WIND_EVEN_ODD</code> by default.
496
         */
497
        public int getWindingRule() {
498
            return PathIterator.WIND_EVEN_ODD;
499
        }
500

    
501
        /**
502
         * @see java.awt.geom.PathIterator#next()
503
         */
504
        public void next() {
505
            done = (getJTS().getCoordinates().length == index++);
506
        }
507

    
508
        /**
509
         * @see java.awt.geom.PathIterator#isDone()
510
         */
511
        public boolean isDone() {
512
            return done;
513
        }
514

    
515
        /**
516
         * @see java.awt.geom.PathIterator#currentSegment(double[])
517
         */
518
        public int currentSegment(double[] coords) {
519
            Coordinate[] jtsCoordinates = getJTS().getCoordinates();
520
            coords[0] = jtsCoordinates[index].x;
521
            coords[1] = jtsCoordinates[index].y;
522
            at.transform(coords, 0, coords, 0, 1);
523

    
524
            if (index == 0) {
525
                return PathIterator.SEG_MOVETO;
526
            } else {
527
                return PathIterator.SEG_LINETO;
528
            }
529
        }
530

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

    
542
            if (index == 0) {
543
                return PathIterator.SEG_MOVETO;
544
            } else {
545
                return PathIterator.SEG_LINETO;
546
            }
547
        }
548
    }
549

    
550

    
551
    /*
552
     * (non-Javadoc)
553
     *
554
     * @see org.gvsig.fmap.geom.jts.GeometryJTS#is3D()
555
     */
556
    public boolean is3D() {
557
        return anyVertex.is3D();
558
    }
559

    
560
    /*
561
     * (non-Javadoc)
562
     *
563
     * @see org.gvsig.fmap.geom.primitive.Line#toPoints()
564
     */
565
    public MultiPoint toPoints() throws GeometryException {
566
        // TODO Auto-generated method stub
567
        return null;
568
    }
569

    
570
    /*
571
     * (non-Javadoc)
572
     *
573
     * @see org.gvsig.fmap.geom.primitive.Line#toLines()
574
     */
575
    public MultiLine toLines() throws GeometryException {
576
        // TODO Auto-generated method stub
577
        return null;
578
    }
579

    
580
    /*
581
     * (non-Javadoc)
582
     *
583
     * @see org.gvsig.fmap.geom.primitive.Line#toPolygons()
584
     */
585
    public MultiPolygon toPolygons() throws GeometryException {
586
        // TODO Auto-generated method stub
587
        return null;
588
    }
589

    
590
    /**
591
     * @param arrayList
592
     */
593
}