Statistics
| Revision:

root / org.gvsig.geotools.proj / trunk / org.gvsig.geotools.proj / org.gvsig.geotools.proj.catalog.impl / src / main / java / org / gvsig / geotools / proj / catalog / utils / DistanceCalculator.java @ 867

History | View | Annotate | Download (7.7 KB)

1
package org.gvsig.geotools.proj.catalog.utils;
2

    
3
import javax.measure.IncommensurableException;
4
import javax.measure.UnconvertibleException;
5
import javax.measure.Unit;
6
import javax.measure.quantity.Length;
7

    
8
import org.geotools.referencing.CRS;
9
import org.geotools.referencing.GeodeticCalculator;
10
import org.geotools.referencing.operation.transform.ConcatenatedTransform;
11
import org.gvsig.proj.catalog.exception.CoordinateReferenceSystemException;
12
import org.gvsig.proj.catalog.exception.TransformationException;
13
import org.gvsig.proj.catalog.exception.UnsupportedCoordinateReferenceSystemException;
14
import org.gvsig.proj.exception.DistanceCalculationException;
15
import org.opengis.referencing.crs.CompoundCRS;
16
import org.opengis.referencing.crs.CoordinateReferenceSystem;
17
import org.opengis.referencing.crs.GeneralDerivedCRS;
18
import org.opengis.referencing.crs.GeocentricCRS;
19
import org.opengis.referencing.crs.GeographicCRS;
20
import org.opengis.referencing.crs.ProjectedCRS;
21
import org.opengis.referencing.crs.SingleCRS;
22
import org.opengis.referencing.datum.GeodeticDatum;
23
import org.opengis.referencing.operation.MathTransform;
24
import org.opengis.referencing.operation.NoninvertibleTransformException;
25
import org.opengis.referencing.operation.TransformException;
26

    
27
/**
28
 * Utility class to calculate distances between two points, using different
29
 * calculation methods. Using this class provides performance improvements when
30
 * many distances have to be calculated. This class is NOT thread-safe, only one
31
 * distance can be calculated at the same time by one calculator instance.
32
 * 
33
 * This class also provides static methods to calculate 
34
 * 
35
 * @author Cesar Martinez Izquierdo
36
 *
37
 */
38
public class DistanceCalculator {
39
        CoordinateReferenceSystem crs;
40
        GeodeticCalculator calculator;
41

    
42
        public DistanceCalculator(CoordinateReferenceSystem crs) {
43
                this.crs = crs;
44
                calculator = new GeodeticCalculator(crs);
45
        }
46
        
47
        /**
48
         * See {@link org.gvsig.proj.CoordinateReferenceSystem#getDistance(double[], double[], Unit)}
49
         * @throws CoordinateReferenceSystemException
50
         */
51
        public double distance(double[] point1, double[] point2,
52
                        Unit<Length> targetUnit) throws CoordinateReferenceSystemException {
53
                return getDistance(this.crs, this.calculator, point1, point2, false, targetUnit);
54
        }
55
        
56
        /**
57
         * See {@link org.gvsig.proj.CoordinateReferenceSystem#getDistance(double[], double[], boolean, Unit)}
58
         * @throws CoordinateReferenceSystemException
59
         */
60
        public double distance(double[] point1, double[] point2, boolean useBaseCRS,
61
                        Unit<Length> targetUnit) throws CoordinateReferenceSystemException {
62
                return getDistance(this.crs, this.calculator, point1, point2, useBaseCRS, targetUnit);
63
        }
64
        
65
        
66
        public static double getDistance(CoordinateReferenceSystem crs,
67
                        double[] point1, double[] point2, boolean useBaseCRS,
68
                        Unit<Length> targetUnit) throws CoordinateReferenceSystemException {
69
                return getDistance(crs, null, point1, point2, useBaseCRS, targetUnit);
70
        }
71
        
72
        
73
        public static double getDistance(CoordinateReferenceSystem crs,
74
                        GeodeticCalculator calculator,
75
                        double[] point1, double[] point2, boolean useBaseCRS,
76
                        Unit<Length> targetUnit) throws CoordinateReferenceSystemException {
77
                try {
78
                        if (crs instanceof GeographicCRS) {
79
                                return getDistanceGeo((GeographicCRS)crs, getGeodeticCalInstance(calculator, crs), point1, point2, targetUnit);
80
                        }
81
                        else if (crs instanceof GeneralDerivedCRS) {
82
                                if (useBaseCRS) {
83
                                        GeographicCRS baseCRS = getBaseGeographicCRS((GeneralDerivedCRS)crs);
84
                                        if (baseCRS != null) {
85
                                                MathTransform mt = getConversionToGeo((GeneralDerivedCRS)crs);
86
                                                double[] point1geo = new double[2], point2geo = new double[2];
87
                                                mt.transform(point1, 0, point1geo, 0, 1);
88
                                                mt.transform(point2, 0, point2geo, 0, 1);
89
                                                return getDistanceGeo(baseCRS, getGeodeticCalInstance(calculator, crs), point1geo, point2geo, targetUnit);
90
                                        }
91
                                }
92
                                else {
93
                                        return getEuclideanDistance2D((SingleCRS)crs, point1, point2, targetUnit);
94
                                }
95
                        }
96
                        else if (crs instanceof GeocentricCRS) {
97
                                return getEuclideanDistance3D((SingleCRS)crs, point1, point2, targetUnit);
98
                        }
99
                        else if (crs instanceof CompoundCRS) {
100
                                SingleCRS horizontalCRS = CRS.getHorizontalCRS(crs);
101
                                return getDistance(horizontalCRS, getGeodeticCalInstance(calculator, crs), point1, point2, useBaseCRS, targetUnit);
102
                        }
103
                } catch (UnsupportedCoordinateReferenceSystemException
104
                                | UnconvertibleException | UnsupportedOperationException
105
                                | IllegalArgumentException | IllegalStateException
106
                                | IncommensurableException | TransformException
107
                                | TransformationException e) {
108
                        throw new DistanceCalculationException(GtUtils.getIdentifier(crs), e);
109
                }
110
                throw new DistanceCalculationException(GtUtils.getIdentifier(crs));
111
        }
112
        
113
        /**
114
         * Creates a GeodeticCalculator instance if needed
115
         * @param calculator
116
         * @param crs
117
         * @return
118
         */
119
        private static GeodeticCalculator getGeodeticCalInstance(GeodeticCalculator calculator, CoordinateReferenceSystem crs) {
120
                if (calculator==null) {
121
                        return new GeodeticCalculator(crs); 
122
                }
123
                return calculator;
124
        }
125
        
126
        public static double getEuclideanDistance2D(SingleCRS crs,
127
                        double[] point1, double[] point2,
128
                        Unit<Length> targetUnit) 
129
                                        throws CoordinateReferenceSystemException,
130
                                        UnconvertibleException,
131
                                        IncommensurableException {
132
                double euclidean = Math.sqrt(Math.pow(point1[0]-point2[0], 2.0)+Math.pow(point1[1]-point2[1], 2.0));
133
                Unit<?> unit = crs.getCoordinateSystem().getAxis(0).getUnit();
134
                return unit.getConverterToAny(targetUnit).convert(euclidean);
135
        }
136
        
137
        public static double getEuclideanDistance3D(SingleCRS crs,
138
                        double[] point1, double[] point2,
139
                        Unit<Length> targetUnit)
140
                                        throws CoordinateReferenceSystemException,
141
                                        UnconvertibleException, IncommensurableException {
142
                double euclidean = Math.sqrt(Math.pow(point1[0]-point2[0], 2.0)
143
                                +Math.pow(point1[1]-point2[1], 2.0)
144
                                +Math.pow(point1[2]-point2[2], 2.0));
145
                Unit<?> unit = crs.getCoordinateSystem().getAxis(0).getUnit();
146
                return unit.getConverterToAny(targetUnit).convert(euclidean);
147
        }
148
        
149
        public static MathTransform getConversionToGeo(GeneralDerivedCRS crs) throws TransformationException {
150
                CoordinateReferenceSystem baseCRS = crs.getBaseCRS();
151
                if (baseCRS instanceof GeographicCRS) {
152
                        try {
153
                                return crs.getConversionFromBase().getMathTransform().inverse();
154
                        } catch (NoninvertibleTransformException e) {
155
                                throw new TransformationException(GtUtils.getIdentifier(crs), e);
156
                        }
157
                }
158
                if (baseCRS instanceof GeneralDerivedCRS && baseCRS!=crs) {
159
                        try {
160
                                MathTransform baseTransform = crs.getConversionFromBase().getMathTransform().inverse();
161
                                ConcatenatedTransform.create(baseTransform, getConversionToGeo((GeneralDerivedCRS)baseCRS));
162
                        } catch (NoninvertibleTransformException e) {
163
                                throw new TransformationException(GtUtils.getIdentifier(crs), e);
164
                        }
165
                }
166
                throw new TransformationException(GtUtils.getIdentifier(crs));
167
        }
168
        
169
        public static GeographicCRS getBaseGeographicCRS(GeneralDerivedCRS crs) {
170
                CoordinateReferenceSystem baseCRS = crs.getBaseCRS();
171
                if (baseCRS instanceof GeographicCRS) {
172
                        return (GeographicCRS) baseCRS;
173
                }
174
                if (baseCRS instanceof GeneralDerivedCRS && baseCRS!=crs) {
175
                        return getBaseGeographicCRS((GeneralDerivedCRS)baseCRS);
176
                }
177
                return null;
178
        }
179
        
180
        public static double getDistanceGeo(GeographicCRS crs,
181
                        GeodeticCalculator calculator,
182
                        double[] point1, double[] point2,
183
                        Unit<Length> targetUnit) throws CoordinateReferenceSystemException,
184
                        UnconvertibleException, IncommensurableException {
185
                calculator.setStartingGeographicPoint(point1[0], point1[1]);
186
                calculator.setDestinationGeographicPoint(point2[0], point2[1]);
187
                double distance = calculator.getOrthodromicDistance();
188
                Unit<?> unit = ((GeodeticDatum)crs.getDatum()).getEllipsoid().getAxisUnit();
189
                return unit.getConverterToAny(targetUnit).convert(distance);
190
        }
191

    
192
}