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 |
} |