Statistics
| Revision:

root / branches / libProjection_v2_0_prep / libraries / libJCRS / src / org / geotools / referencing / operation / projection / IdrLabordeMadagascar.java @ 27137

History | View | Annotate | Download (21.4 KB)

1 27137 cmartinez
/*
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.IdrPolyconic.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 IdrLabordeMadagascar} 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: IdrLabordeMadagascar.java 12357 2007-06-27 09:05:41Z dguerrero $
171
 * @author  Rueben Schulz
172
 */
173
public class IdrLabordeMadagascar extends MapProjection {
174
175
        private final double scaleFactorLocal=0.9995;
176
        private final double falseEastingLocal=400000.0;
177
        private final double falseNorthingLocal=800000.0;
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=-18.9;
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=46.4372291700;
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 azimuth=18.9;
200
201
202
    protected IdrLabordeMadagascar(ParameterValueGroup parameters) throws ParameterNotFoundException {
203
            super(parameters);
204
                /*
205
        final Collection expected = getParameterDescriptors().descriptors();
206
        if (expected.contains(Provider.LAT_OF_CENTRE)) {
207
                latitudeOfCentre = Math.abs(doubleValue(expected,
208
                                        Provider.LAT_OF_CENTRE, parameters));
209
            ensureLatitudeInRange(Provider.LAT_OF_CENTRE, latitudeOfCentre, false);
210
        } else {
211
            // standard parallel is the equator (Plate Carree or Equirectangular)
212
                latitudeOfCentre = Double.NaN;
213
        }
214
        if (expected.contains(Provider.LONG_OF_CENTRE)) {
215
                longitudeOfCentre = Math.abs(doubleValue(expected,
216
                                        Provider.LONG_OF_CENTRE, parameters));
217
            ensureLatitudeInRange(Provider.LONG_OF_CENTRE, longitudeOfCentre, false);
218
        } else {
219
            // standard parallel is the equator (Plate Carree or Equirectangular)
220
                longitudeOfCentre = Double.NaN;
221
        }
222
        if (expected.contains(Provider.SCALE_FACTOR_LOCAL)) {
223
                scaleFactorLocal = Math.abs(doubleValue(expected,
224
                                        Provider.SCALE_FACTOR_LOCAL, parameters));
225
            ensureLatitudeInRange(Provider.SCALE_FACTOR_LOCAL, scaleFactorLocal, false);
226
        } else {
227
            // standard parallel is the equator (Plate Carree or Equirectangular)
228
                scaleFactorLocal = Double.NaN;
229
        }
230
        if (expected.contains(Provider.AZIMUTH)) {
231
                azimuth = Math.abs(doubleValue(expected,
232
                                        Provider.AZIMUTH, parameters));
233
            ensureLatitudeInRange(Provider.AZIMUTH, azimuth, false);
234
        } else {
235
            // standard parallel is the equator (Plate Carree or Equirectangular)
236
                azimuth = Double.NaN;
237
        }
238
        if (expected.contains(Provider.FALSE_EASTING_LOCAL)) {
239
                falseEastingLocal = Math.abs(doubleValue(expected,
240
                                        Provider.FALSE_EASTING_LOCAL, parameters));
241
            ensureLatitudeInRange(Provider.FALSE_EASTING_LOCAL, falseEastingLocal, false);
242
        } else {
243
            // standard parallel is the equator (Plate Carree or Equirectangular)
244
                falseEastingLocal = Double.NaN;
245
        }
246
        if (expected.contains(Provider.FALSE_NORTHING_LOCAL)) {
247
                falseNorthingLocal = Math.abs(doubleValue(expected,
248
                                        Provider.FALSE_NORTHING_LOCAL, parameters));
249
            ensureLatitudeInRange(Provider.FALSE_NORTHING_LOCAL, falseNorthingLocal, false);
250
        } else {
251
            // standard parallel is the equator (Plate Carree or Equirectangular)
252
                falseNorthingLocal = Double.NaN;
253
        }
254
        */
255
                // TODO Auto-generated constructor stub
256
        }
257
258
        public ParameterDescriptorGroup getParameterDescriptors() {
259
                // TODO Auto-generated method stub
260
        return Provider.PARAMETERS;
261
        }
262
263
    public ParameterValueGroup getParameterValues() {
264
        final ParameterValueGroup values = super.getParameterValues();
265
        /*
266
        if (!Double.isNaN(latitudeOfCentre)) {
267
            final Collection expected = getParameterDescriptors().descriptors();
268
            set(expected,Provider.LAT_OF_CENTRE, values, latitudeOfCentre);
269
        }
270
        if (!Double.isNaN(longitudeOfCentre)) {
271
            final Collection expected = getParameterDescriptors().descriptors();
272
            set(expected,Provider.LONG_OF_CENTRE, values, longitudeOfCentre);
273
        }
274
        if (!Double.isNaN(falseNorthingLocal)) {
275
            final Collection expected = getParameterDescriptors().descriptors();
276
            set(expected,Provider.FALSE_NORTHING_LOCAL, values, falseNorthingLocal);
277
        }
278
        if (!Double.isNaN(falseEastingLocal)) {
279
            final Collection expected = getParameterDescriptors().descriptors();
280
            set(expected,Provider.FALSE_EASTING_LOCAL, values, falseEastingLocal);
281
        }
282
        if (!Double.isNaN(scaleFactorLocal)) {
283
            final Collection expected = getParameterDescriptors().descriptors();
284
            set(expected,Provider.SCALE_FACTOR_LOCAL, values, scaleFactorLocal);
285
        }
286
        if (!Double.isNaN(azimuth)) {
287
            final Collection expected = getParameterDescriptors().descriptors();
288
            set(expected,Provider.AZIMUTH, values, azimuth);
289
        }
290
        */
291
        return values;
292
    }
293
294
        protected Point2D inverseTransformNormalized(double x, double y,
295
                        Point2D ptDst) throws ProjectionException {
296
                // TODO Auto-generated method stub
297
                return null;
298
        }
299
300
        protected Point2D transformNormalized(double x, double y, Point2D ptDst)
301
                        throws ProjectionException {
302
                // TODO Auto-generated method stub
303
                return null;
304
        }
305
306
        public static class Provider extends AbstractProvider {
307
308
        public static final ParameterDescriptor SCALE_FACTOR_LOCAL = createDescriptor(
309
                new NamedIdentifier[] {
310
                    new NamedIdentifier(CitationImpl.OGC,      "scale_factor"),
311
                    new NamedIdentifier(CitationImpl.EPSG,     "Scale factor on initial line"),
312
                    new NamedIdentifier(CitationImpl.EPSG,    "Scale factor at natural origin"),
313
                    new NamedIdentifier(CitationImpl.GEOTIFF, "ScaleAtNatOrigin"),
314
                    new NamedIdentifier(CitationImpl.GEOTIFF, "ScaleAtCenter")
315
                },
316
                0.9995, 0, Double.POSITIVE_INFINITY, Unit.ONE);
317
318
        public static final ParameterDescriptor FALSE_EASTING_LOCAL = createDescriptor(
319
                new NamedIdentifier[] {
320
                    new NamedIdentifier(CitationImpl.OGC,     "false_easting"),
321
                    new NamedIdentifier(CitationImpl.EPSG,    "False easting"),
322
                    new NamedIdentifier(CitationImpl.EPSG,    "Easting at projection centre"),
323
                    new NamedIdentifier(CitationImpl.EPSG,    "Easting at false origin"),
324
                    new NamedIdentifier(CitationImpl.GEOTIFF, "FalseEasting")
325
                },
326
                400000.0, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, SI.METER);
327
328
        public static final ParameterDescriptor FALSE_NORTHING_LOCAL = createDescriptor(
329
                new NamedIdentifier[] {
330
                    new NamedIdentifier(CitationImpl.OGC,     "false_northing"),
331
                    new NamedIdentifier(CitationImpl.EPSG,    "False northing"),
332
                    new NamedIdentifier(CitationImpl.EPSG,    "Northing at projection centre"),
333
                    new NamedIdentifier(CitationImpl.EPSG,    "Northing at false origin"),
334
                    new NamedIdentifier(CitationImpl.GEOTIFF, "FalseNorthing")
335
                },
336
                800000.0, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, SI.METER);
337
338
339
            /**
340
         * The operation parameter descriptor for the {@link #latitudeOfCentre}
341
         * parameter value. Valid values range is from -90 to 90. Default value is 0.
342
         */
343
        public static final ParameterDescriptor LAT_OF_CENTRE = createDescriptor(
344
                new NamedIdentifier[] {
345
                    new NamedIdentifier(CitationImpl.OGC,      "latitude_of_center"),
346
                    new NamedIdentifier(CitationImpl.EPSG,     "Latitude of projection centre"),
347
                    new NamedIdentifier(CitationImpl.ESRI,     "Latitude_Of_Center"),
348
                    new NamedIdentifier(CitationImpl.GEOTIFF,  "CenterLat")
349
                },
350
                -18.9, -90, 90, NonSI.DEGREE_ANGLE);
351
352
        /**
353
         * The operation parameter descriptor for the {@link #longitudeOfCentre}
354
         * parameter value. Valid values range is from -180 to 180. Default value is 0.
355
         */
356
        public static final ParameterDescriptor LONG_OF_CENTRE = createDescriptor(
357
                new NamedIdentifier[] {
358
                    new NamedIdentifier(CitationImpl.OGC,      "longitude_of_center"),
359
                    new NamedIdentifier(CitationImpl.EPSG,     "Longitude of projection centre"),
360
                    new NamedIdentifier(CitationImpl.ESRI,     "Longitude_Of_Center"),
361
                    new NamedIdentifier(CitationImpl.GEOTIFF,  "CenterLong")
362
                },
363
                46.4372291700, -180, 180, NonSI.DEGREE_ANGLE);
364
365
        /**
366
         * The operation parameter descriptor for the {@link #alpha_c}
367
         * parameter value. Valid values range is from -360 to -270, -90 to 90,
368
         * and 270 to 360 degrees. Default value is 0.
369
         */
370
        public static final ParameterDescriptor AZIMUTH = createDescriptor(
371
                new NamedIdentifier[] {
372
                    new NamedIdentifier(CitationImpl.OGC,      "azimuth"),
373
                    new NamedIdentifier(CitationImpl.ESRI,     "Azimuth"),
374
                    new NamedIdentifier(CitationImpl.EPSG,     "Azimuth of initial line"),
375
                    new NamedIdentifier(CitationImpl.GEOTIFF,  "AzimuthAngle")
376
                },
377
                18.9, -360, 360, NonSI.DEGREE_ANGLE);
378
379
380
        /**
381
         * The parameters group.
382
         */
383
        static final ParameterDescriptorGroup PARAMETERS = createDescriptorGroup(new NamedIdentifier[] {
384
                new NamedIdentifier(CitationImpl.OGC,      "Laborde Madagascar"),
385
                new NamedIdentifier(CitationImpl.EPSG,     "Laborde Madagascar"),
386
                new NamedIdentifier(CitationImpl.EPSG,     "Laborde_Madagascar"),
387
                new NamedIdentifier(CitationImpl.EPSG,     "9813"),
388
                new NamedIdentifier(CitationImpl.GEOTOOLS, Resources.formatInternational(
389
                                                           ResourceKeys.OBLIQUE_MERCATOR_PROJECTION)),
390
                new NamedIdentifier(new CitationImpl("IDR"), "IDR")
391
            }, new ParameterDescriptor[] {
392
                SEMI_MAJOR,          SEMI_MINOR,
393
                LONG_OF_CENTRE,      LAT_OF_CENTRE,
394
                AZIMUTH,
395
                SCALE_FACTOR_LOCAL,
396
                FALSE_EASTING_LOCAL,       FALSE_NORTHING_LOCAL
397
            });
398
399
        /**
400
         * Constructs a new provider.
401
         */
402
        public Provider() {
403
            super(PARAMETERS);
404
        }
405
406
        /**
407
         * Constructs a new provider.
408
         */
409
        protected Provider(final ParameterDescriptorGroup params) {
410
            super(params);
411
        }
412
413
        /**
414
         * Returns the operation type for this map projection.
415
         */
416
        protected Class getOperationType() {
417
            return CylindricalProjection.class;
418
        }
419
420
        /**
421
         * Creates a transform from the specified group of parameter values.
422
         *
423
         * @param  parameters The group of parameter values.
424
         * @return The created math transform.
425
         * @throws ParameterNotFoundException if a required parameter was not found.
426
         */
427
         public MathTransform createMathTransform(final ParameterValueGroup parameters)
428
                throws ParameterNotFoundException
429
        {
430
            //final Collection descriptors = PARAMETERS.descriptors();
431
            return new IdrLabordeMadagascar(parameters);
432
        }
433
    }
434
}