root / org.gvsig.jcrs / libJCRS / src / org / geotools / referencing / operation / projection / IdrObliqueMercator.java @ 38
History | View | Annotate | Download (45.7 KB)
1 |
/*
|
---|---|
2 |
* Geotools - OpenSource mapping toolkit
|
3 |
* (C) 2005, Geotools Project Managment Committee (PMC)
|
4 |
*
|
5 |
* This library is free software; you can redistribute it and/or
|
6 |
* modify it under the terms of the GNU Lesser General Public
|
7 |
* License as published by the Free Software Foundation; either
|
8 |
* version 2.1 of the License, or (at your option) any later version.
|
9 |
*
|
10 |
* This library 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 GNU
|
13 |
* Lesser General Public License for more details.
|
14 |
*
|
15 |
* You should have received a copy of the GNU Lesser General Public
|
16 |
* License along with this library; if not, write to the Free Software
|
17 |
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
18 |
*
|
19 |
*
|
20 |
* This package contains formulas from the PROJ package of USGS.
|
21 |
* USGS's work is fully acknowledged here.
|
22 |
*/
|
23 |
/*
|
24 |
** libproj -- library of cartographic projections
|
25 |
** Some parts Copyright (c) 2003 Gerald I. Evenden
|
26 |
**
|
27 |
** Permission is hereby granted, free of charge, to any person obtaining
|
28 |
** a copy of this software and associated documentation files (the
|
29 |
** "Software"), to deal in the Software without restriction, including
|
30 |
** without limitation the rights to use, copy, modify, merge, publish,
|
31 |
** distribute, sublicense, and/or sell copies of the Software, and to
|
32 |
** permit persons to whom the Software is furnished to do so, subject to
|
33 |
** the following conditions:
|
34 |
**
|
35 |
** The above copyright notice and this permission notice shall be
|
36 |
** included in all copies or substantial portions of the Software.
|
37 |
**
|
38 |
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
39 |
** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
40 |
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
41 |
** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
42 |
** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
43 |
** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
44 |
** SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
45 |
*/
|
46 |
package org.geotools.referencing.operation.projection; |
47 |
|
48 |
// J2SE dependencies and extensions
|
49 |
import java.awt.geom.Point2D; |
50 |
import java.util.Collection; |
51 |
|
52 |
import javax.units.NonSI; |
53 |
import javax.units.SI; |
54 |
import javax.units.Unit; |
55 |
|
56 |
import org.geotools.metadata.iso.citation.CitationImpl; |
57 |
import org.geotools.referencing.NamedIdentifier; |
58 |
import org.geotools.referencing.operation.projection.IdrAzimuthalEquidistant.Provider; |
59 |
import org.geotools.resources.cts.ResourceKeys; |
60 |
import org.geotools.resources.cts.Resources; |
61 |
import org.opengis.parameter.ParameterDescriptor; |
62 |
import org.opengis.parameter.ParameterDescriptorGroup; |
63 |
import org.opengis.parameter.ParameterNotFoundException; |
64 |
import org.opengis.parameter.ParameterValueGroup; |
65 |
import org.opengis.referencing.operation.CylindricalProjection; |
66 |
import org.opengis.referencing.operation.MathTransform; |
67 |
|
68 |
|
69 |
/**
|
70 |
* Oblique Mercator Projection. A conformal, oblique, cylindrical projection
|
71 |
* with the cylinder touching the ellipsoid (or sphere) along a great circle
|
72 |
* path (the central line). The Mercator and Transverse Mercator projections
|
73 |
* can be thought of as special cases of the oblique mercator, where the central
|
74 |
* line is along the equator or a meridian, respectively. The Oblique Mercator
|
75 |
* projection has been used in Switzerland, Hungary, Madagascar,
|
76 |
* Malaysia, Borneo and the panhandle of Alaska.
|
77 |
* <br><br>
|
78 |
*
|
79 |
* The Oblique Mercator projection uses a (U,V) coordinate system, with the
|
80 |
* U axis along the central line. During the forward projection, coordinates
|
81 |
* from the ellipsoid are projected conformally to a sphere of constant total
|
82 |
* curvature, called the 'aposphere', before being projected onto the plane.
|
83 |
* The projection coordinates are further convented to a (X,Y) coordinate system
|
84 |
* by rotating the calculated (u,v) coordinates to give output (x,y) coordinates.
|
85 |
* The rotation value is usually the same as the projection azimuth (the angle,
|
86 |
* east of north, of the central line), but some cases allow a separate
|
87 |
* rotation parameter.
|
88 |
* <br><br>
|
89 |
*
|
90 |
* There are two forms of the oblique mercator, differing in the origin of
|
91 |
* their grid coordinates. The Hotine_Oblique_Mercator (EPSG code 9812) has grid
|
92 |
* coordinates start at the intersection of the central line and the equator of the
|
93 |
* aposphere. The Oblique_Mercator (EPSG code 9815) is the same, except the grid
|
94 |
* coordinates begin at the central point (where the latitude of center and
|
95 |
* central line intersect). ESRI separates these two case by appending
|
96 |
* "Natural_Origin" (for the Hotine_Oblique_Mercator) and "Center"
|
97 |
* (for the Obique_Mercator) to the projection names.
|
98 |
* <br><br>
|
99 |
*
|
100 |
* Two different methods are used to specify the central line for the
|
101 |
* oblique mercator: 1) a central point and an azimuth,
|
102 |
* east of north, describing the central line and
|
103 |
* 2) two points on the central line. The EPSG does not use the two point method,
|
104 |
* while ESRI separates the two cases by putting "Azimuth" and "Two_Point" in
|
105 |
* their projection names. Both cases use the point where the "latitude_of_center"
|
106 |
* parameter crosses the central line as the projection's central point.
|
107 |
* The central meridian is not a projection parameter, and is instead calculated
|
108 |
* as the intersection between the central line and the equator of the aposphere.
|
109 |
* <br><br>
|
110 |
*
|
111 |
* For the azimuth method, the central latitude cannot be +- 90.0 degrees
|
112 |
* and the central line cannot be at a maximum or minimum latitude at the central point.
|
113 |
* In the two point method, the latitude of the first and second points cannot be
|
114 |
* equal. Also, the latitude of the first point and central point cannot be
|
115 |
* +- 90.0 degrees. Furthermore, the latitude of the first point cannot be 0.0 and
|
116 |
* the latitude of the second point cannot be - 90.0 degrees. A change of
|
117 |
* 10^-7 radians can allow calculation at these special cases. Snyder's restriction
|
118 |
* of the central latitude being 0.0 has been removed, since the equaitons appear
|
119 |
* to work correctly in this case.
|
120 |
* <br><br>
|
121 |
*
|
122 |
* Azimuth values of 0.0 and +- 90.0 degrees are allowed (and used in Hungary
|
123 |
* and Switzerland), though these cases would usually use a Mercator or
|
124 |
* Transverse Mercator projection instead. Azimuth values > 90 degrees cause
|
125 |
* errors in the equations.
|
126 |
* <br><br>
|
127 |
*
|
128 |
* The oblique mercator is also called the "Rectified Skew Orthomorphic" (RSO).
|
129 |
* It appears is that the only difference from the oblique mercator is that
|
130 |
* the RSO allows the rotation from the (U,V) to (X,Y) coordinate system to be different
|
131 |
* from the azimuth. This separate parameter is called "rectified_grid_angle" (or
|
132 |
* "XY_Plane_Rotation" by ESRI) and is also included in the EPSG's parameters
|
133 |
* for the Oblique Mercator and Hotine Oblique Mercator.
|
134 |
* The rotation parameter is optional in all the non-two point projections and will be
|
135 |
* set to the azimuth if not specified.
|
136 |
* <br><br>
|
137 |
*
|
138 |
* Projection cases and aliases implemented by the {@link IdrObliqueMercator} are:
|
139 |
* <ul>
|
140 |
* <li>Oblique_Mercator (EPSG code 9815) - grid coordinates begin at the central point, has "rectified_grid_angle" parameter.</li>
|
141 |
* <li>Hotine_Oblique_Mercator_Azimuth_Center (ESRI) - grid coordinates begin at the central point.</li>
|
142 |
* <li>Rectified_Skew_Orthomorphic_Center (ESRI) - grid coordinates begin at the central point, has "rectified_grid_angle" parameter.</li>
|
143 |
*
|
144 |
* <li>Hotine_Oblique_Mercator (EPSG code 9812) - grid coordinates begin at the interseciton of the central line and aposphere equator, has "rectified_grid_angle" parameter.</li>
|
145 |
* <li>Hotine_Oblique_Mercator_Azimuth_Natural_Origin (ESRI) - grid coordinates begin at the interseciton of the central line and aposphere equator.</li>
|
146 |
* <li>Rectified_Skew_Orthomorphic_Natural_Origin (ESRI) - grid coordinates begin at the interseciton of the central line and aposphere equator, has "rectified_grid_angle" parameter.</li>
|
147 |
*
|
148 |
* <li>Hotine_Oblique_Mercator_Two_Point_Center (ESRI) - grid coordinates begin at the central point.</li>
|
149 |
* <li>Hotine_Oblique_Mercator_Two_Point_Natural_Origin (ESRI) - grid coordinates begin at the interseciton of the central line and aposphere equator.</li>
|
150 |
* </ul>
|
151 |
*
|
152 |
* <strong>References:</strong>
|
153 |
* <ul>
|
154 |
* <li><code>libproj4</code> is available at
|
155 |
* <A HREF="http://members.bellatlantic.net/~vze2hc4d/proj4/">libproj4 Miscellanea</A><br>
|
156 |
* Relevent files are: <code>PJ_omerc.c</code>, <code>pj_tsfn.c</code>,
|
157 |
* <code>pj_fwd.c</code>, <code>pj_inv.c</code> and <code>lib_proj.h</code></li>
|
158 |
* <li> John P. Snyder (Map Projections - A Working Manual,
|
159 |
* U.S. Geological Survey Professional Paper 1395, 1987)</li>
|
160 |
* <li> "Coordinate Conversions and Transformations including Formulas",
|
161 |
* EPSG Guidence Note Number 7 part 2, Version 24.</li>
|
162 |
* <li>Gerald Evenden, 2004, <a href="http://members.verizon.net/~vze2hc4d/proj4/omerc.pdf">
|
163 |
* Documentation of revised Oblique Mercator</a></li>
|
164 |
* </ul>
|
165 |
*
|
166 |
* @see <A HREF="http://mathworld.wolfram.com/MercatorProjection.html">Oblique Mercator projection on MathWorld</A>
|
167 |
* @see <A HREF="http://www.remotesensing.org/geotiff/proj_list/hotine_oblique_mercator.html">hotine_oblique_mercator on Remote Sensing</A>
|
168 |
* @see <A HREF="http://www.remotesensing.org/geotiff/proj_list/oblique_mercator.html">oblique_mercator on Remote Sensing</A>
|
169 |
*
|
170 |
* @version $Id: IdrObliqueMercator.java 18139 2008-01-16 16:21:08Z jlgomez $
|
171 |
* @author Rueben Schulz
|
172 |
*/
|
173 |
public class IdrObliqueMercator extends MapProjection { |
174 |
|
175 |
private final double scaleFactorLocal; |
176 |
private final double falseEastingLocal; |
177 |
private final double falseNorthingLocal; |
178 |
|
179 |
/**
|
180 |
* Latitude of the projection centre. This is similar to the
|
181 |
* {@link #latitudeOfOrigin}, but the latitude of origin is the
|
182 |
* Earth equator on aposphere for the oblique mercator. Needed
|
183 |
* for WKT.
|
184 |
*/
|
185 |
private final double latitudeOfCentre; |
186 |
|
187 |
/**
|
188 |
* Longitude of the projection centre. This is <strong>NOT</strong> equal
|
189 |
* to the {@link #centralMeridian}, which is the meridian where the
|
190 |
* central line intersects the Earth equator on aposphere. Needed for
|
191 |
* for non-two point WKT.
|
192 |
*/
|
193 |
private final double longitudeOfCentre; |
194 |
|
195 |
/**
|
196 |
* The azimuth of the central line passing throught the centre of the
|
197 |
* projection, needed for for non-two point WKT.
|
198 |
*/
|
199 |
private double alpha_c; |
200 |
|
201 |
/**
|
202 |
* The rectified bearing of the central line, needed for non-two point WKT. Equals
|
203 |
* {@link #alpha_c} if the "rectified_grid_angle" parameter value is not set.
|
204 |
*/
|
205 |
private double rectGridAngle; |
206 |
|
207 |
/**
|
208 |
* The latitude of the 1st point used to specify the central line, needed for two point
|
209 |
* WKT.
|
210 |
*/
|
211 |
private final double latitudeOf1stPoint; |
212 |
|
213 |
/**
|
214 |
* The longitude of the 1st point used to specify the central line, needed for two point
|
215 |
* WKT.
|
216 |
*/
|
217 |
private final double longitudeOf1stPoint; |
218 |
|
219 |
/**
|
220 |
* The latitude of the 2nd point used to specify the central line, needed for two point
|
221 |
* WKT.
|
222 |
*/
|
223 |
private final double latitudeOf2ndPoint; |
224 |
|
225 |
/**
|
226 |
* The longitude of the 2nd point used to specify the central line, needed for two point
|
227 |
* WKT.
|
228 |
*/
|
229 |
private double longitudeOf2ndPoint; |
230 |
|
231 |
/**
|
232 |
* Constants used in the transformation.
|
233 |
*/
|
234 |
private double B, A, E; |
235 |
|
236 |
/**
|
237 |
* Convenience values equal to {@link #A} / {@link #B},
|
238 |
* {@link #A}×{@link #B}, and {@link #B} / {@link #A}.
|
239 |
*/
|
240 |
private final double ArB, AB, BrA; |
241 |
|
242 |
/**
|
243 |
* v values when the input latitude is a pole.
|
244 |
*/
|
245 |
private final double v_pole_n, v_pole_s; |
246 |
|
247 |
/**
|
248 |
* Sine and Cosine values for gamma0 (the angle between the meridian
|
249 |
* and central line at the intersection between the central line and
|
250 |
* the Earth equator on aposphere).
|
251 |
*/
|
252 |
private final double singamma0, cosgamma0; |
253 |
|
254 |
/**
|
255 |
* Sine and Cosine values for the rotation between (U,V) and
|
256 |
* (X,Y) coordinate systems
|
257 |
*/
|
258 |
private final double sinrot, cosrot; |
259 |
|
260 |
/**
|
261 |
* u value (in (U,V) coordinate system) of the central point. Used in the
|
262 |
* oblique mercater case. The v value of the central point is 0.0.
|
263 |
*/
|
264 |
private double u_c; |
265 |
|
266 |
/**
|
267 |
* <code>true</code> if using two points on the central line to specify
|
268 |
* the azimuth.
|
269 |
*/
|
270 |
private final boolean twoPoint; |
271 |
|
272 |
/**
|
273 |
* <code>true</code> for hotine oblique mercator, or <code>false</code>
|
274 |
* for the oblique mercator case.
|
275 |
*/
|
276 |
private final boolean hotine; |
277 |
|
278 |
/**
|
279 |
* The {@link org.geotools.referencing.operation.MathTransformProvider}
|
280 |
* for an {@link IdrObliqueMercator} projection.
|
281 |
*
|
282 |
* @see org.geotools.referencing.operation.DefaultMathTransformFactory
|
283 |
*
|
284 |
* @version $Id: IdrObliqueMercator.java 18139 2008-01-16 16:21:08Z jlgomez $
|
285 |
* @author Rueben Schulz
|
286 |
*/
|
287 |
public static class Provider extends AbstractProvider { |
288 |
|
289 |
public static final ParameterDescriptor SCALE_FACTOR_LOCAL = createDescriptor( |
290 |
new NamedIdentifier[] { |
291 |
new NamedIdentifier(CitationImpl.OGC, "scale_factor"), |
292 |
new NamedIdentifier(CitationImpl.EPSG, "Scale factor on initial line"), |
293 |
new NamedIdentifier(CitationImpl.EPSG, "Scale factor at natural origin"), |
294 |
new NamedIdentifier(CitationImpl.GEOTIFF, "ScaleAtNatOrigin"), |
295 |
new NamedIdentifier(CitationImpl.GEOTIFF, "ScaleAtCenter") |
296 |
}, |
297 |
1, 0, Double.POSITIVE_INFINITY, Unit.ONE); |
298 |
|
299 |
public static final ParameterDescriptor FALSE_EASTING_LOCAL = createDescriptor( |
300 |
new NamedIdentifier[] { |
301 |
new NamedIdentifier(CitationImpl.OGC, "false_easting"), |
302 |
new NamedIdentifier(CitationImpl.EPSG, "False easting"), |
303 |
new NamedIdentifier(CitationImpl.EPSG, "Easting at projection centre"), |
304 |
new NamedIdentifier(CitationImpl.EPSG, "Easting at false origin"), |
305 |
new NamedIdentifier(CitationImpl.GEOTIFF, "FalseEasting") |
306 |
}, |
307 |
0, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, SI.METER); |
308 |
|
309 |
public static final ParameterDescriptor FALSE_NORTHING_LOCAL = createDescriptor( |
310 |
new NamedIdentifier[] { |
311 |
new NamedIdentifier(CitationImpl.OGC, "false_northing"), |
312 |
new NamedIdentifier(CitationImpl.EPSG, "False northing"), |
313 |
new NamedIdentifier(CitationImpl.EPSG, "Northing at projection centre"), |
314 |
new NamedIdentifier(CitationImpl.EPSG, "Northing at false origin"), |
315 |
new NamedIdentifier(CitationImpl.GEOTIFF, "FalseNorthing") |
316 |
}, |
317 |
0, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, SI.METER); |
318 |
|
319 |
|
320 |
/**
|
321 |
* The operation parameter descriptor for the {@link #latitudeOfCentre}
|
322 |
* parameter value. Valid values range is from -90 to 90. Default value is 0.
|
323 |
*/
|
324 |
public static final ParameterDescriptor LAT_OF_CENTRE = createDescriptor( |
325 |
new NamedIdentifier[] { |
326 |
new NamedIdentifier(CitationImpl.OGC, "latitude_of_center"), |
327 |
new NamedIdentifier(CitationImpl.EPSG, "Latitude of projection centre"), |
328 |
new NamedIdentifier(CitationImpl.ESRI, "Latitude_Of_Center"), |
329 |
new NamedIdentifier(CitationImpl.GEOTIFF, "CenterLat") |
330 |
}, |
331 |
0, -90, 90, NonSI.DEGREE_ANGLE); |
332 |
|
333 |
/**
|
334 |
* The operation parameter descriptor for the {@link #longitudeOfCentre}
|
335 |
* parameter value. Valid values range is from -180 to 180. Default value is 0.
|
336 |
*/
|
337 |
public static final ParameterDescriptor LONG_OF_CENTRE = createDescriptor( |
338 |
new NamedIdentifier[] { |
339 |
new NamedIdentifier(CitationImpl.OGC, "longitude_of_center"), |
340 |
new NamedIdentifier(CitationImpl.EPSG, "Longitude of projection centre"), |
341 |
new NamedIdentifier(CitationImpl.ESRI, "Longitude_Of_Center"), |
342 |
new NamedIdentifier(CitationImpl.GEOTIFF, "CenterLong") |
343 |
}, |
344 |
0, -180, 180, NonSI.DEGREE_ANGLE); |
345 |
|
346 |
/**
|
347 |
* The operation parameter descriptor for the {@link #alpha_c}
|
348 |
* parameter value. Valid values range is from -360 to -270, -90 to 90,
|
349 |
* and 270 to 360 degrees. Default value is 0.
|
350 |
*/
|
351 |
public static final ParameterDescriptor AZIMUTH = createDescriptor( |
352 |
new NamedIdentifier[] { |
353 |
new NamedIdentifier(CitationImpl.OGC, "azimuth"), |
354 |
new NamedIdentifier(CitationImpl.ESRI, "Azimuth"), |
355 |
new NamedIdentifier(CitationImpl.EPSG, "Azimuth of initial line"), |
356 |
new NamedIdentifier(CitationImpl.GEOTIFF, "AzimuthAngle") |
357 |
}, |
358 |
0, -360, 360, NonSI.DEGREE_ANGLE); |
359 |
|
360 |
/**
|
361 |
* The operation parameter descriptor for the {@link #rectGridAngle}
|
362 |
* parameter value. It is an optional parameter with valid values ranging
|
363 |
* from -360 to 360. Default value is {@link #alpha_c}.
|
364 |
*/
|
365 |
public static final ParameterDescriptor RECTIFIED_GRID_ANGLE = createOptionalDescriptor( |
366 |
new NamedIdentifier[] { |
367 |
new NamedIdentifier(CitationImpl.OGC, "rectified_grid_angle"), |
368 |
new NamedIdentifier(CitationImpl.EPSG, "Angle from Rectified to Skew Grid"), |
369 |
new NamedIdentifier(CitationImpl.ESRI, "XY_Plane_Rotation"), |
370 |
new NamedIdentifier(CitationImpl.GEOTIFF, "RectifiedGridAngle") |
371 |
}, |
372 |
-360, 360, NonSI.DEGREE_ANGLE); |
373 |
|
374 |
/**
|
375 |
* The parameters group.
|
376 |
*/
|
377 |
static final ParameterDescriptorGroup PARAMETERS = createDescriptorGroup(new NamedIdentifier[] { |
378 |
new NamedIdentifier(CitationImpl.OGC, "Oblique_Mercator"), |
379 |
new NamedIdentifier(CitationImpl.EPSG, "Oblique Mercator"), |
380 |
new NamedIdentifier(CitationImpl.EPSG, "9815"), |
381 |
new NamedIdentifier(CitationImpl.GEOTIFF, "CT_ObliqueMercator"), |
382 |
new NamedIdentifier(CitationImpl.ESRI, "Hotine_Oblique_Mercator_Azimuth_Center"), |
383 |
new NamedIdentifier(CitationImpl.ESRI, "Rectified_Skew_Orthomorphic_Center"), |
384 |
new NamedIdentifier(CitationImpl.GEOTOOLS, Resources.formatInternational(
|
385 |
ResourceKeys.OBLIQUE_MERCATOR_PROJECTION)), |
386 |
new NamedIdentifier(new CitationImpl("IDR"), "IDR") |
387 |
}, new ParameterDescriptor[] { |
388 |
SEMI_MAJOR, SEMI_MINOR, |
389 |
LONG_OF_CENTRE, LAT_OF_CENTRE, |
390 |
AZIMUTH, RECTIFIED_GRID_ANGLE, |
391 |
SCALE_FACTOR_LOCAL, |
392 |
FALSE_EASTING_LOCAL, FALSE_NORTHING_LOCAL |
393 |
}); |
394 |
|
395 |
/**
|
396 |
* Constructs a new provider.
|
397 |
*/
|
398 |
public Provider() { |
399 |
super(PARAMETERS);
|
400 |
} |
401 |
|
402 |
/**
|
403 |
* Constructs a new provider.
|
404 |
*/
|
405 |
protected Provider(final ParameterDescriptorGroup params) { |
406 |
super(params);
|
407 |
} |
408 |
|
409 |
/**
|
410 |
* Returns the operation type for this map projection.
|
411 |
*/
|
412 |
protected Class getOperationType() { |
413 |
return CylindricalProjection.class;
|
414 |
} |
415 |
|
416 |
/**
|
417 |
* Creates a transform from the specified group of parameter values.
|
418 |
*
|
419 |
* @param parameters The group of parameter values.
|
420 |
* @return The created math transform.
|
421 |
* @throws ParameterNotFoundException if a required parameter was not found.
|
422 |
*/
|
423 |
public MathTransform createMathTransform(final ParameterValueGroup parameters) |
424 |
throws ParameterNotFoundException
|
425 |
{ |
426 |
final Collection descriptors = PARAMETERS.descriptors(); |
427 |
return new IdrObliqueMercator(parameters, descriptors, false, false); |
428 |
} |
429 |
} |
430 |
|
431 |
/**
|
432 |
* The {@link org.geotools.referencing.operation.MathTransformProvider}
|
433 |
* for a Hotine {@link IdrObliqueMercator} projection.
|
434 |
*
|
435 |
* @see org.geotools.referencing.operation.DefaultMathTransformFactory
|
436 |
*
|
437 |
* @version $Id: IdrObliqueMercator.java 18139 2008-01-16 16:21:08Z jlgomez $
|
438 |
* @author Rueben Schulz
|
439 |
*/
|
440 |
public static final class Provider_Hotine extends Provider { |
441 |
/**
|
442 |
* The parameters group.
|
443 |
*/
|
444 |
static final ParameterDescriptorGroup PARAMETERS = createDescriptorGroup(new NamedIdentifier[] { |
445 |
new NamedIdentifier(CitationImpl.OGC, "Hotine_Oblique_Mercator"), |
446 |
new NamedIdentifier(CitationImpl.EPSG, "Hotine Oblique Mercator"), |
447 |
new NamedIdentifier(CitationImpl.EPSG, "9812"), |
448 |
new NamedIdentifier(CitationImpl.GEOTIFF, "CT_ObliqueMercator_Hotine"), |
449 |
new NamedIdentifier(CitationImpl.ESRI, "Hotine_Oblique_Mercator_Azimuth_Natural_Origin"), |
450 |
new NamedIdentifier(CitationImpl.ESRI, "Rectified_Skew_Orthomorphic_Natural_Origin"), |
451 |
new NamedIdentifier(CitationImpl.GEOTOOLS, Resources.formatInternational(
|
452 |
ResourceKeys.OBLIQUE_MERCATOR_PROJECTION)), |
453 |
new NamedIdentifier(new CitationImpl("IDR"), "IDR") |
454 |
}, new ParameterDescriptor[] { |
455 |
SEMI_MAJOR, SEMI_MINOR, |
456 |
LONG_OF_CENTRE, LAT_OF_CENTRE, |
457 |
AZIMUTH, RECTIFIED_GRID_ANGLE, |
458 |
SCALE_FACTOR_LOCAL, |
459 |
FALSE_EASTING_LOCAL, FALSE_NORTHING_LOCAL |
460 |
}); |
461 |
|
462 |
/**
|
463 |
* Constructs a new provider.
|
464 |
*/
|
465 |
public Provider_Hotine() {
|
466 |
super(PARAMETERS);
|
467 |
} |
468 |
|
469 |
/**
|
470 |
* Returns the operation type for this map projection.
|
471 |
*/
|
472 |
protected Class getOperationType() { |
473 |
return CylindricalProjection.class;
|
474 |
} |
475 |
|
476 |
/**
|
477 |
* Creates a transform from the specified group of parameter values.
|
478 |
*
|
479 |
* @param parameters The group of parameter values.
|
480 |
* @return The created math transform.
|
481 |
* @throws ParameterNotFoundException if a required parameter was not found.
|
482 |
*/
|
483 |
public MathTransform createMathTransform(final ParameterValueGroup parameters) |
484 |
throws ParameterNotFoundException
|
485 |
{ |
486 |
final Collection descriptors = PARAMETERS.descriptors(); |
487 |
return new IdrObliqueMercator(parameters, descriptors, true, false); |
488 |
} |
489 |
} |
490 |
|
491 |
/**
|
492 |
* The {@link org.geotools.referencing.operation.MathTransformProvider}
|
493 |
* for a {@link IdrObliqueMercator} projection, specified with
|
494 |
* two points on the central line (instead of a central point and azimuth).
|
495 |
*
|
496 |
* @see org.geotools.referencing.operation.DefaultMathTransformFactory
|
497 |
*
|
498 |
* @version $Id: IdrObliqueMercator.java 18139 2008-01-16 16:21:08Z jlgomez $
|
499 |
* @author Rueben Schulz
|
500 |
*/
|
501 |
public static class Provider_TwoPoint extends Provider { |
502 |
/**
|
503 |
* The operation parameter descriptor for the {@link #latitudeOfCentre}
|
504 |
* parameter value. Valid values range is from -90 to 90. Default value is 0.
|
505 |
*/
|
506 |
public static final ParameterDescriptor LAT_OF_CENTRE = createDescriptor( |
507 |
new NamedIdentifier[] { |
508 |
new NamedIdentifier(CitationImpl.OGC, "latitude_of_center"), |
509 |
new NamedIdentifier(CitationImpl.EPSG, "Latitude of projection centre"), |
510 |
new NamedIdentifier(CitationImpl.ESRI, "Latitude_Of_Center"), |
511 |
new NamedIdentifier(CitationImpl.GEOTIFF, "CenterLat") |
512 |
}, |
513 |
0, -90, 90, NonSI.DEGREE_ANGLE); |
514 |
|
515 |
/**
|
516 |
* The operation parameter descriptor for the {@link #latitudeOf1stPoint}
|
517 |
* parameter value. Valid values range is from -90 to 90. Default value is 0.
|
518 |
*/
|
519 |
public static final ParameterDescriptor LAT_OF_1ST_POINT = createDescriptor( |
520 |
new NamedIdentifier[] { |
521 |
new NamedIdentifier(CitationImpl.ESRI, "Latitude_Of_1st_Point") |
522 |
}, |
523 |
0, -90, 90, NonSI.DEGREE_ANGLE); |
524 |
|
525 |
/**
|
526 |
* The operation parameter descriptor for the {@link #longitudeOf1stPoint}
|
527 |
* parameter value. Valid values range is from -180 to 180. Default value is 0.
|
528 |
*/
|
529 |
public static final ParameterDescriptor LONG_OF_1ST_POINT = createDescriptor( |
530 |
new NamedIdentifier[] { |
531 |
new NamedIdentifier(CitationImpl.ESRI, "Longitude_Of_1st_Point") |
532 |
}, |
533 |
0, -180, 180, NonSI.DEGREE_ANGLE); |
534 |
|
535 |
/**
|
536 |
* The operation parameter descriptor for the {@link #latitudeOf2ndPoint}
|
537 |
* parameter value. Valid values range is from -90 to 90. Default value is 0.
|
538 |
*/
|
539 |
public static final ParameterDescriptor LAT_OF_2ND_POINT = createDescriptor( |
540 |
new NamedIdentifier[] { |
541 |
new NamedIdentifier(CitationImpl.ESRI, "Latitude_Of_2nd_Point") |
542 |
}, |
543 |
0, -90, 90, NonSI.DEGREE_ANGLE); |
544 |
|
545 |
/**
|
546 |
* The operation parameter descriptor for the {@link #longitudeOf2ndPoint}
|
547 |
* parameter value. Valid values range is from -180 to 180. Default value is 0.
|
548 |
*/
|
549 |
public static final ParameterDescriptor LONG_OF_2ND_POINT = createDescriptor( |
550 |
new NamedIdentifier[] { |
551 |
new NamedIdentifier(CitationImpl.ESRI, "Longitude_Of_2nd_Point") |
552 |
}, |
553 |
0, -180, 180, NonSI.DEGREE_ANGLE); |
554 |
|
555 |
/**
|
556 |
* The parameters group.
|
557 |
*/
|
558 |
static final ParameterDescriptorGroup PARAMETERS = createDescriptorGroup(new NamedIdentifier[] { |
559 |
new NamedIdentifier(CitationImpl.ESRI, "Hotine_Oblique_Mercator_Two_Point_Center"), |
560 |
new NamedIdentifier(CitationImpl.GEOTOOLS, Resources.formatInternational(
|
561 |
ResourceKeys.OBLIQUE_MERCATOR_PROJECTION)), |
562 |
new NamedIdentifier(new CitationImpl("IDR"), "IDR") |
563 |
}, new ParameterDescriptor[] { |
564 |
SEMI_MAJOR, SEMI_MINOR, |
565 |
LAT_OF_1ST_POINT, LONG_OF_1ST_POINT, |
566 |
LAT_OF_2ND_POINT, LONG_OF_2ND_POINT, |
567 |
LAT_OF_CENTRE, SCALE_FACTOR_LOCAL, |
568 |
FALSE_EASTING_LOCAL, FALSE_NORTHING_LOCAL |
569 |
}); |
570 |
|
571 |
/**
|
572 |
* Constructs a new provider.
|
573 |
*/
|
574 |
public Provider_TwoPoint() {
|
575 |
super(PARAMETERS);
|
576 |
} |
577 |
|
578 |
/**
|
579 |
* Constructs a new provider.
|
580 |
*/
|
581 |
protected Provider_TwoPoint(final ParameterDescriptorGroup params) { |
582 |
super(params);
|
583 |
} |
584 |
|
585 |
/**
|
586 |
* Returns the operation type for this map projection.
|
587 |
*/
|
588 |
protected Class getOperationType() { |
589 |
return CylindricalProjection.class;
|
590 |
} |
591 |
|
592 |
/**
|
593 |
* Creates a transform from the specified group of parameter values.
|
594 |
*
|
595 |
* @param parameters The group of parameter values.
|
596 |
* @return The created math transform.
|
597 |
* @throws ParameterNotFoundException if a required parameter was not found.
|
598 |
*/
|
599 |
public MathTransform createMathTransform(final ParameterValueGroup parameters) |
600 |
throws ParameterNotFoundException
|
601 |
{ |
602 |
final Collection descriptors = PARAMETERS.descriptors(); |
603 |
return new IdrObliqueMercator(parameters, descriptors, false, true); |
604 |
} |
605 |
|
606 |
} |
607 |
|
608 |
|
609 |
/**
|
610 |
* The {@link org.geotools.referencing.operation.MathTransformProvider}
|
611 |
* for a Hotine {@link IdrObliqueMercator} projection, specified with
|
612 |
* two points on the central line (instead of a central point and azimuth).
|
613 |
*
|
614 |
* @see org.geotools.referencing.operation.DefaultMathTransformFactory
|
615 |
*
|
616 |
* @version $Id: IdrObliqueMercator.java 18139 2008-01-16 16:21:08Z jlgomez $
|
617 |
* @author Rueben Schulz
|
618 |
*/
|
619 |
public static final class Provider_Hotine_TwoPoint extends Provider_TwoPoint { |
620 |
/**
|
621 |
* The parameters group.
|
622 |
*/
|
623 |
static final ParameterDescriptorGroup PARAMETERS = createDescriptorGroup(new NamedIdentifier[] { |
624 |
new NamedIdentifier(CitationImpl.ESRI, "Hotine_Oblique_Mercator_Two_Point_Natural_Origin"), |
625 |
new NamedIdentifier(CitationImpl.GEOTOOLS, Resources.formatInternational(
|
626 |
ResourceKeys.OBLIQUE_MERCATOR_PROJECTION)), |
627 |
new NamedIdentifier(new CitationImpl("IDR"), "IDR") |
628 |
}, new ParameterDescriptor[] { |
629 |
SEMI_MAJOR, SEMI_MINOR, |
630 |
LAT_OF_1ST_POINT, LONG_OF_1ST_POINT, |
631 |
LAT_OF_2ND_POINT, LONG_OF_2ND_POINT, |
632 |
LAT_OF_CENTRE, SCALE_FACTOR_LOCAL, |
633 |
FALSE_EASTING_LOCAL, FALSE_NORTHING_LOCAL |
634 |
}); |
635 |
|
636 |
/**
|
637 |
* Constructs a new provider.
|
638 |
*/
|
639 |
public Provider_Hotine_TwoPoint() {
|
640 |
super(PARAMETERS);
|
641 |
} |
642 |
|
643 |
/**
|
644 |
* Returns the operation type for this map projection.
|
645 |
*/
|
646 |
protected Class getOperationType() { |
647 |
return CylindricalProjection.class;
|
648 |
} |
649 |
|
650 |
/**
|
651 |
* Creates a transform from the specified group of parameter values.
|
652 |
*
|
653 |
* @param parameters The group of parameter values.
|
654 |
* @return The created math transform.
|
655 |
* @throws ParameterNotFoundException if a required parameter was not found.
|
656 |
*/
|
657 |
public MathTransform createMathTransform(final ParameterValueGroup parameters) |
658 |
throws ParameterNotFoundException
|
659 |
{ |
660 |
final Collection descriptors = PARAMETERS.descriptors(); |
661 |
return new IdrObliqueMercator(parameters, descriptors, true, true); |
662 |
} |
663 |
|
664 |
} |
665 |
|
666 |
/**
|
667 |
* Constructs a new map projection from the supplied parameters.
|
668 |
*
|
669 |
* @param parameters The parameter values in standard units.
|
670 |
* @param expected The expected parameter descriptors.
|
671 |
* @throws ParameterNotFoundException if a mandatory parameter is missing.
|
672 |
*/
|
673 |
IdrObliqueMercator(final ParameterValueGroup parameters, final Collection expected, |
674 |
final boolean hotine, final boolean twoPoint) |
675 |
throws ParameterNotFoundException
|
676 |
{ |
677 |
|
678 |
//Fetch parameters
|
679 |
super(parameters, expected);
|
680 |
|
681 |
this.hotine = hotine;
|
682 |
this.twoPoint = twoPoint;
|
683 |
|
684 |
//NaN for safety (centralMeridian calculated below)
|
685 |
latitudeOfOrigin = Double.NaN;
|
686 |
centralMeridian = Double.NaN;
|
687 |
|
688 |
//scaleFactorLocal=1.0;
|
689 |
//falseEastingLocal=0.0;
|
690 |
//falseNorthingLocal=0.0;
|
691 |
|
692 |
final Collection miExpected = getParameterDescriptors().descriptors(); |
693 |
if (miExpected.contains(Provider.SCALE_FACTOR_LOCAL)) { |
694 |
scaleFactorLocal = Math.abs(doubleValue(expected,
|
695 |
Provider.SCALE_FACTOR_LOCAL, parameters));
|
696 |
//ensureInRange(Provider.SCALE_FACTOR_LOCAL, scaleFactorLocal, false);
|
697 |
} else {
|
698 |
scaleFactorLocal = 1.0;
|
699 |
} |
700 |
if (miExpected.contains(Provider.FALSE_EASTING_LOCAL)) { |
701 |
falseEastingLocal = Math.abs(doubleValue(expected,
|
702 |
Provider.FALSE_EASTING_LOCAL, parameters));
|
703 |
//ensureLatitudeInRange(Provider.FALSE_EASTING_LOCAL, falseEastingLocal, false);
|
704 |
} else {
|
705 |
falseEastingLocal = 0.0;
|
706 |
} |
707 |
if (miExpected.contains(Provider.FALSE_NORTHING_LOCAL)) { |
708 |
falseNorthingLocal = Math.abs(doubleValue(expected,
|
709 |
Provider.FALSE_NORTHING_LOCAL, parameters));
|
710 |
//ensureLatitudeInRange(Provider.FALSE_NORTHING_LOCAL, falseNorthingLocal, false);
|
711 |
} else {
|
712 |
falseNorthingLocal = 0.0;
|
713 |
} |
714 |
|
715 |
latitudeOfCentre = doubleValue(expected, Provider.LAT_OF_CENTRE, parameters);
|
716 |
//checks that latitudeOfCentre is not +- 90 degrees
|
717 |
//not checking if latitudeOfCentere is 0, since equations behave correctly
|
718 |
ensureLatitudeInRange(Provider.LAT_OF_CENTRE, latitudeOfCentre, false); |
719 |
|
720 |
if (twoPoint) {
|
721 |
longitudeOfCentre = Double.NaN;
|
722 |
latitudeOf1stPoint = doubleValue(expected, Provider_TwoPoint.LAT_OF_1ST_POINT, parameters); |
723 |
//checks that latOf1stPoint is not +-90 degrees
|
724 |
ensureLatitudeInRange(Provider_TwoPoint.LAT_OF_1ST_POINT, latitudeOf1stPoint, false);
|
725 |
longitudeOf1stPoint = doubleValue(expected, Provider_TwoPoint.LONG_OF_1ST_POINT, parameters); |
726 |
ensureLongitudeInRange(Provider_TwoPoint.LONG_OF_1ST_POINT, longitudeOf1stPoint, true);
|
727 |
latitudeOf2ndPoint = doubleValue(expected, Provider_TwoPoint.LAT_OF_2ND_POINT, parameters); |
728 |
ensureLatitudeInRange(Provider_TwoPoint.LAT_OF_2ND_POINT, latitudeOf2ndPoint, true);
|
729 |
longitudeOf2ndPoint = doubleValue(expected, Provider_TwoPoint.LONG_OF_2ND_POINT, parameters); |
730 |
ensureLongitudeInRange(Provider_TwoPoint.LONG_OF_2ND_POINT, longitudeOf2ndPoint, true);
|
731 |
|
732 |
/*
|
733 |
double con = Math.abs(latitudeOf1stPoint);
|
734 |
if (Math.abs(latitudeOf1stPoint - latitudeOf2ndPoint) < TOL) {
|
735 |
throw new IllegalArgumentException(Resources.format(ResourceKeys.ERROR_LAT1_EQ_LAT2));
|
736 |
}
|
737 |
if (Math.abs(latitudeOf1stPoint) < TOL) {
|
738 |
throw new IllegalArgumentException(Resources.format(ResourceKeys.ERROR_LAT1_EQ_ZERO));
|
739 |
}
|
740 |
if (Math.abs(latitudeOf2ndPoint + Math.PI/2.0) < TOL) {
|
741 |
throw new IllegalArgumentException(Resources.format(ResourceKeys.ERROR_LAT2_EQ_NEG_90));
|
742 |
}
|
743 |
*/
|
744 |
} else {
|
745 |
latitudeOf1stPoint = Double.NaN;
|
746 |
longitudeOf1stPoint = Double.NaN;
|
747 |
latitudeOf2ndPoint = Double.NaN;
|
748 |
longitudeOf2ndPoint = Double.NaN;
|
749 |
|
750 |
longitudeOfCentre = doubleValue(expected, Provider.LONG_OF_CENTRE, parameters);
|
751 |
ensureLongitudeInRange(Provider.LONG_OF_CENTRE, longitudeOfCentre, true); |
752 |
|
753 |
alpha_c = doubleValue(expected, Provider.AZIMUTH, parameters);
|
754 |
//already checked for +-360 deg. above.
|
755 |
if ((alpha_c > -1.5*Math.PI && alpha_c < -0.5*Math.PI) || |
756 |
(alpha_c > 0.5*Math.PI && alpha_c < 1.5*Math.PI)) { |
757 |
throw new IllegalArgumentException( |
758 |
Resources.format(ResourceKeys.ERROR_VALUE_OUT_OF_BOUNDS_$3, |
759 |
new Double(Math.toDegrees(alpha_c)), new Double(-90), new Double(90))); |
760 |
} |
761 |
|
762 |
rectGridAngle = doubleValue(expected, Provider.RECTIFIED_GRID_ANGLE, parameters);
|
763 |
if (Double.isNaN(rectGridAngle)) { |
764 |
rectGridAngle = alpha_c; |
765 |
} |
766 |
} |
767 |
/*
|
768 |
double com = Math.sqrt(1.0-excentricitySquared);
|
769 |
double sinphi0 = Math.sin(latitudeOfCentre);
|
770 |
double cosphi0 = Math.cos(latitudeOfCentre);
|
771 |
B = cosphi0 * cosphi0;
|
772 |
B = Math.sqrt(1.0 + excentricitySquared * B * B / (1.0-excentricitySquared));
|
773 |
double con = 1.0 - excentricitySquared * sinphi0 * sinphi0;
|
774 |
A = B * com / con;
|
775 |
double D = B * com / (cosphi0 * Math.sqrt(con));
|
776 |
double F = D * D - 1.0;
|
777 |
if (F < 0.0) {
|
778 |
F = 0.0;
|
779 |
} else {
|
780 |
F = Math.sqrt(F);
|
781 |
if (latitudeOfCentre < 0.0) { //taking sign of latOfCentre
|
782 |
F = -F;
|
783 |
}
|
784 |
}
|
785 |
F = F += D;
|
786 |
E = F* Math.pow(tsfn(latitudeOfCentre, sinphi0), B);
|
787 |
double gamma0;
|
788 |
if (twoPoint) {
|
789 |
double H = Math.pow(tsfn(latitudeOf1stPoint, Math.sin(latitudeOf1stPoint)), B);
|
790 |
double L = Math.pow(tsfn(latitudeOf2ndPoint, Math.sin(latitudeOf2ndPoint)), B);
|
791 |
double Fp = E / H;
|
792 |
double P = (L - H) / (L + H);
|
793 |
double J = E * E;
|
794 |
J = (J - L * H) / (J + L * H);
|
795 |
double diff = longitudeOf1stPoint - longitudeOf2ndPoint;
|
796 |
if (diff < -Math.PI) {
|
797 |
longitudeOf2ndPoint -= 2.0* Math.PI;
|
798 |
} else if (diff > Math.PI) {
|
799 |
longitudeOf2ndPoint += 2.0* Math.PI;
|
800 |
}
|
801 |
|
802 |
centralMeridian = rollLongitude(0.5 * (longitudeOf1stPoint + longitudeOf2ndPoint) -
|
803 |
Math.atan(J * Math.tan(0.5 * B * (longitudeOf1stPoint - longitudeOf2ndPoint)) / P) / B);
|
804 |
gamma0 = Math.atan(2.0 * Math.sin(B * rollLongitude(longitudeOf1stPoint - centralMeridian)) /
|
805 |
(Fp - 1.0 / Fp));
|
806 |
alpha_c = Math.asin(D * Math.sin(gamma0));
|
807 |
rectGridAngle = alpha_c;
|
808 |
} else {
|
809 |
gamma0 = Math.asin(Math.sin(alpha_c) / D);
|
810 |
//check for asin(+-1.00000001)
|
811 |
double temp = 0.5 * (F - 1.0 / F) * Math.tan(gamma0);
|
812 |
if (Math.abs(temp) > 1.0) {
|
813 |
if (Math.abs(Math.abs(temp) - 1.0) > EPS) {
|
814 |
throw new IllegalArgumentException("Tolerance condition error");
|
815 |
}
|
816 |
temp = (temp > 0) ? 1.0 : -1.0;
|
817 |
}
|
818 |
centralMeridian = longitudeOfCentre - Math.asin(temp) / B;
|
819 |
}
|
820 |
singamma0 = Math.sin(gamma0);
|
821 |
cosgamma0 = Math.cos(gamma0);
|
822 |
sinrot = Math.sin(rectGridAngle);
|
823 |
cosrot = Math.cos(rectGridAngle);
|
824 |
ArB = A/B;
|
825 |
AB = A*B;
|
826 |
BrA = B/A;
|
827 |
v_pole_n = ArB * Math.log(Math.tan(0.5 * (Math.PI/2.0 - gamma0)));
|
828 |
v_pole_s = ArB * Math.log(Math.tan(0.5 * (Math.PI/2.0 + gamma0)));
|
829 |
if (hotine) {
|
830 |
u_c = 0.0;
|
831 |
} else {
|
832 |
if (Math.abs(Math.abs(alpha_c) - Math.PI/2.0) < TOL) {
|
833 |
//longitudeOfCentre = NaN in twopoint, but alpha_c cannot be 90 here (lat1 != lat2)
|
834 |
u_c = A * (longitudeOfCentre - centralMeridian);
|
835 |
} else {
|
836 |
u_c = Math.abs(ArB * Math.atan2(Math.sqrt(D * D - 1.0), Math.cos(alpha_c)));
|
837 |
if (latitudeOfCentre < 0.0) {
|
838 |
u_c = -u_c;
|
839 |
}
|
840 |
}
|
841 |
}
|
842 |
*/
|
843 |
singamma0 = 0;
|
844 |
cosgamma0 = 0;
|
845 |
sinrot = 0;
|
846 |
cosrot = 0;
|
847 |
ArB = 0;
|
848 |
AB = 0;
|
849 |
BrA = 0;
|
850 |
v_pole_n =0;
|
851 |
v_pole_s =0;
|
852 |
} |
853 |
|
854 |
/**
|
855 |
* {@inheritDoc}
|
856 |
*/
|
857 |
public ParameterDescriptorGroup getParameterDescriptors() {
|
858 |
if (hotine) {
|
859 |
return (twoPoint) ? Provider_Hotine_TwoPoint.PARAMETERS : Provider_Hotine.PARAMETERS;
|
860 |
} else {
|
861 |
return (twoPoint) ? Provider_TwoPoint.PARAMETERS : Provider.PARAMETERS; |
862 |
} |
863 |
} |
864 |
|
865 |
/**
|
866 |
* {@inheritDoc}
|
867 |
*/
|
868 |
public ParameterValueGroup getParameterValues() {
|
869 |
final ParameterValueGroup values = super.getParameterValues(); |
870 |
final Collection expected = getParameterDescriptors().descriptors(); |
871 |
if (twoPoint) {
|
872 |
set(expected, Provider_TwoPoint.LAT_OF_CENTRE, values, latitudeOfCentre); |
873 |
set(expected, Provider_TwoPoint.LAT_OF_1ST_POINT, values, latitudeOf1stPoint); |
874 |
set(expected, Provider_TwoPoint.LONG_OF_1ST_POINT, values, longitudeOf1stPoint); |
875 |
set(expected, Provider_TwoPoint.LAT_OF_2ND_POINT, values, latitudeOf2ndPoint); |
876 |
set(expected, Provider_TwoPoint.LONG_OF_2ND_POINT, values, longitudeOf2ndPoint); |
877 |
} else {
|
878 |
set(expected, Provider.LAT_OF_CENTRE, values, latitudeOfCentre);
|
879 |
set(expected, Provider.LONG_OF_CENTRE, values, longitudeOfCentre);
|
880 |
set(expected, Provider.AZIMUTH, values, alpha_c );
|
881 |
set(expected, Provider.RECTIFIED_GRID_ANGLE, values, rectGridAngle);
|
882 |
} |
883 |
set(expected, Provider.SCALE_FACTOR_LOCAL, values, scaleFactorLocal);
|
884 |
set(expected, Provider.FALSE_NORTHING_LOCAL, values, falseNorthingLocal);
|
885 |
set(expected, Provider.FALSE_EASTING_LOCAL, values, falseEastingLocal);
|
886 |
return values;
|
887 |
} |
888 |
|
889 |
/**
|
890 |
* {@inheritDoc}
|
891 |
*/
|
892 |
protected Point2D transformNormalized(double x, double y, Point2D ptDst) |
893 |
throws ProjectionException
|
894 |
{ |
895 |
double u, v;
|
896 |
if (Math.abs(Math.abs(y) - Math.PI/2.0) > EPS) { |
897 |
double Q = E / Math.pow(tsfn(y, Math.sin(y)), B); |
898 |
double temp = 1.0 / Q; |
899 |
double S = 0.5 * (Q - temp); |
900 |
double V = Math.sin(B * x); |
901 |
double U = (S * singamma0 - V * cosgamma0) / (0.5 * (Q + temp)); |
902 |
if (Math.abs(Math.abs(U) - 1.0) < EPS) { |
903 |
throw new ProjectionException(Resources.format(ResourceKeys.ERROR_V_INFINITE)); |
904 |
} |
905 |
v = 0.5 * ArB * Math.log((1.0 - U) / (1.0 + U)); |
906 |
temp = Math.cos(B * x);
|
907 |
if (Math.abs(temp) < TOL) { |
908 |
u = AB * x; |
909 |
} else {
|
910 |
u = ArB * Math.atan2((S * cosgamma0 + V * singamma0), temp);
|
911 |
} |
912 |
} else {
|
913 |
v = y > 0 ? v_pole_n : v_pole_s;
|
914 |
u = ArB * y; |
915 |
} |
916 |
|
917 |
u -= u_c; |
918 |
x = v * cosrot + u * sinrot; |
919 |
y = u * cosrot - v * sinrot; |
920 |
|
921 |
if (ptDst != null) { |
922 |
ptDst.setLocation(x,y); |
923 |
return ptDst;
|
924 |
} |
925 |
return new Point2D.Double(x,y); |
926 |
} |
927 |
|
928 |
/**
|
929 |
* {@inheritDoc}
|
930 |
*/
|
931 |
protected Point2D inverseTransformNormalized(double x, double y, Point2D ptDst) |
932 |
throws ProjectionException
|
933 |
{ |
934 |
double v = x * cosrot - y * sinrot;
|
935 |
double u = y * cosrot + x * sinrot + u_c;
|
936 |
|
937 |
double Qp = Math.exp(-BrA * v); |
938 |
double temp = 1.0 / Qp; |
939 |
double Sp = 0.5 * (Qp - temp); |
940 |
double Vp = Math.sin(BrA * u); |
941 |
double Up = (Vp * cosgamma0 + Sp * singamma0) / (0.5 * (Qp + temp)); |
942 |
if (Math.abs(Math.abs(Up) - 1.0) < EPS) { |
943 |
x = 0.0;
|
944 |
y = Up < 0.0 ? -Math.PI / 2.0 : Math.PI / 2.0; |
945 |
} else {
|
946 |
y = Math.pow(E / Math.sqrt((1. + Up) / (1. - Up)), 1.0 / B); //calculate t |
947 |
y = cphi2(y); |
948 |
x = -Math.atan2((Sp * cosgamma0 - Vp * singamma0), Math.cos(BrA * u)) / B; |
949 |
} |
950 |
|
951 |
if (ptDst != null) { |
952 |
ptDst.setLocation(x,y); |
953 |
return ptDst;
|
954 |
} |
955 |
return new Point2D.Double(x,y); |
956 |
} |
957 |
|
958 |
/**
|
959 |
* Maximal error (in metres) tolerated for assertion, if enabled.
|
960 |
*
|
961 |
* @param longitude The longitude in degrees.
|
962 |
* @param latitude The latitude in degrees.
|
963 |
* @return The tolerance level for assertions, in meters.
|
964 |
*/
|
965 |
protected double getToleranceForAssertions(final double longitude, final double latitude) { |
966 |
if (Math.abs(longitude - centralMeridian)/2 + |
967 |
Math.abs(latitude - latitudeOfCentre) > 10) |
968 |
{ |
969 |
// When far from the valid area, use a larger tolerance.
|
970 |
return 1; |
971 |
} |
972 |
return super.getToleranceForAssertions(longitude, latitude); |
973 |
} |
974 |
|
975 |
/**
|
976 |
* Returns a hash value for this projection.
|
977 |
*/
|
978 |
public int hashCode() { |
979 |
long code = Double.doubleToLongBits(latitudeOfCentre); |
980 |
code = code*37 + Double.doubleToLongBits(longitudeOfCentre); |
981 |
code = code*37 + Double.doubleToLongBits(alpha_c); |
982 |
code = code*37 + Double.doubleToLongBits(rectGridAngle); |
983 |
code = code*37 + Double.doubleToLongBits(latitudeOf1stPoint); |
984 |
code = code*37 + Double.doubleToLongBits(latitudeOf2ndPoint); |
985 |
return ((int)code ^ (int)(code >>> 32)) + 37*super.hashCode(); |
986 |
} |
987 |
|
988 |
/**
|
989 |
* Compares the specified object with this map projection for equality.
|
990 |
*/
|
991 |
public boolean equals(final Object object) { |
992 |
if (object == this) { |
993 |
// Slight optimization
|
994 |
return true; |
995 |
} |
996 |
if (super.equals(object)) { |
997 |
final IdrObliqueMercator that = (IdrObliqueMercator) object;
|
998 |
return equals(this.latitudeOfCentre , that.latitudeOfCentre ) && |
999 |
equals(this.longitudeOfCentre , that.longitudeOfCentre ) &&
|
1000 |
equals(this.alpha_c , that.alpha_c ) &&
|
1001 |
equals(this.rectGridAngle , that.rectGridAngle ) &&
|
1002 |
equals(this.u_c , that.u_c ) &&
|
1003 |
equals(this.latitudeOf1stPoint , that.latitudeOf1stPoint ) &&
|
1004 |
equals(this.longitudeOf1stPoint, that.longitudeOf1stPoint) &&
|
1005 |
equals(this.latitudeOf2ndPoint , that.latitudeOf2ndPoint ) &&
|
1006 |
equals(this.longitudeOf2ndPoint, that.longitudeOf2ndPoint) &&
|
1007 |
this.twoPoint == that.twoPoint &&
|
1008 |
this.hotine == that.hotine;
|
1009 |
} |
1010 |
return false; |
1011 |
} |
1012 |
} |