001: /*
002: * GeoTools - OpenSource mapping toolkit
003: * http://geotools.org
004: *
005: * (C) 2003-2006, Geotools Project Managment Committee (PMC)
006: * (C) 2001, Institut de Recherche pour le Développement
007: * (C) 2000, Frank Warmerdam
008: * (C) 1999, Fisheries and Oceans Canada
009: *
010: * This library is free software; you can redistribute it and/or
011: * modify it under the terms of the GNU Lesser General Public
012: * License as published by the Free Software Foundation; either
013: * version 2.1 of the License, or (at your option) any later version.
014: *
015: * This library is distributed in the hope that it will be useful,
016: * but WITHOUT ANY WARRANTY; without even the implied warranty of
017: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
018: * Lesser General Public License for more details.
019: *
020: * This package contains formulas from the PROJ package of USGS.
021: * USGS's work is fully acknowledged here. This derived work has
022: * been relicensed under LGPL with Frank Warmerdam's permission.
023: */
024: package org.geotools.referencing.operation.projection;
025:
026: // J2SE dependencies and extensions
027: import java.awt.geom.Point2D;
028:
029: // OpenGIS dependencies
030: import org.opengis.parameter.ParameterValueGroup;
031: import org.opengis.parameter.ParameterDescriptorGroup;
032: import org.opengis.parameter.ParameterNotFoundException;
033:
034: // Geotools dependencies
035: import org.geotools.resources.i18n.Errors;
036: import org.geotools.resources.i18n.ErrorKeys;
037:
038: /**
039: * The USGS equatorial case of the {@linkplain Stereographic stereographic} projection.
040: * This is a special case of oblique stereographic projection for
041: * {@linkplain #latitudeOfOrigin latitude of origin} == 0.0.
042: *
043: * @since 2.4
044: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/referencing/src/main/java/org/geotools/referencing/operation/projection/EquatorialStereographic.java $
045: * @version $Id: EquatorialStereographic.java 24576 2007-02-24 00:07:40Z desruisseaux $
046: * @author André Gosselin
047: * @author Martin Desruisseaux
048: * @author Rueben Schulz
049: */
050: public class EquatorialStereographic extends StereographicUSGS {
051: /**
052: * Maximum difference allowed when comparing real numbers.
053: */
054: private static final double EPSILON = 1E-6;
055:
056: /**
057: * A constant used in the transformations.
058: * This is <strong>not</strong> equal to the {@link #scaleFactor}.
059: */
060: static final double k0 = 2;
061:
062: /**
063: * Constructs an equatorial stereographic projection (EPSG equations).
064: *
065: * @param parameters The group of parameter values.
066: * @throws ParameterNotFoundException if a required parameter was not found.
067: */
068: protected EquatorialStereographic(
069: final ParameterValueGroup parameters)
070: throws ParameterNotFoundException {
071: this (parameters, Stereographic.Provider.PARAMETERS);
072: }
073:
074: /**
075: * Constructs an equatorial stereographic projection (USGS equations).
076: *
077: * @param parameters The group of parameter values.
078: * @param descriptor The expected parameter descriptor.
079: * @throws ParameterNotFoundException if a required parameter was not found.
080: */
081: EquatorialStereographic(final ParameterValueGroup parameters,
082: final ParameterDescriptorGroup descriptor)
083: throws ParameterNotFoundException {
084: super (parameters, descriptor);
085: assert super .k0 == k0 : super .k0;
086: latitudeOfOrigin = 0.0;
087: }
088:
089: /**
090: * Transforms the specified (<var>λ</var>,<var>φ</var>) coordinates
091: * (units in radians) and stores the result in {@code ptDst} (linear distance
092: * on a unit sphere).
093: */
094: protected Point2D transformNormalized(double x, double y,
095: Point2D ptDst) throws ProjectionException {
096: // Compute using oblique formulas, for comparaison later.
097: assert (ptDst = super .transformNormalized(x, y, ptDst)) != null;
098:
099: final double chi = 2.0 * Math.atan(ssfn(y, Math.sin(y)))
100: - (Math.PI / 2);
101: final double cosChi = Math.cos(chi);
102: final double A = k0 / (1.0 + cosChi * Math.cos(x)); // typo in (12-29)
103: x = A * cosChi * Math.sin(x);
104: y = A * Math.sin(chi);
105:
106: assert checkTransform(x, y, ptDst);
107: if (ptDst != null) {
108: ptDst.setLocation(x, y);
109: return ptDst;
110: }
111: return new Point2D.Double(x, y);
112: }
113:
114: /**
115: * Provides the transform equations for the spherical case of the
116: * equatorial stereographic projection.
117: *
118: * @version $Id: EquatorialStereographic.java 24576 2007-02-24 00:07:40Z desruisseaux $
119: * @author Martin Desruisseaux
120: * @author Rueben Schulz
121: */
122: static final class Spherical extends EquatorialStereographic {
123: /**
124: * Constructs a spherical equatorial stereographic projection (USGS equations).
125: *
126: * @param parameters The group of parameter values.
127: * @param descriptor The expected parameter descriptor.
128: * @throws ParameterNotFoundException if a required parameter was not found.
129: */
130: Spherical(final ParameterValueGroup parameters,
131: final ParameterDescriptorGroup descriptor)
132: throws ParameterNotFoundException {
133: super (parameters, descriptor);
134: ensureSpherical();
135: }
136:
137: /**
138: * Transforms the specified (<var>λ</var>,<var>φ</var>) coordinates
139: * (units in radians) and stores the result in {@code ptDst} (linear distance
140: * on a unit sphere).
141: */
142: protected Point2D transformNormalized(double x, double y,
143: Point2D ptDst) throws ProjectionException {
144: //Compute using ellipsoidal formulas, for comparaison later.
145: assert (ptDst = super .transformNormalized(x, y, ptDst)) != null;
146:
147: final double coslat = Math.cos(y);
148: double f = 1.0 + coslat * Math.cos(x);
149: if (f < EPSILON) {
150: throw new ProjectionException(Errors
151: .format(ErrorKeys.VALUE_TEND_TOWARD_INFINITY));
152: }
153: f = k0 / f; // (21-14)
154: x = f * coslat * Math.sin(x); // (21-2)
155: y = f * Math.sin(y); // (21-13)
156:
157: assert checkTransform(x, y, ptDst);
158: if (ptDst != null) {
159: ptDst.setLocation(x, y);
160: return ptDst;
161: }
162: return new Point2D.Double(x, y);
163: }
164:
165: /**
166: * Transforms the specified (<var>x</var>,<var>y</var>) coordinate
167: * and stores the result in {@code ptDst}.
168: */
169: protected Point2D inverseTransformNormalized(double x,
170: double y, Point2D ptDst) throws ProjectionException {
171: // Compute using ellipsoidal formulas, for comparaison later.
172: assert (ptDst = super .inverseTransformNormalized(x, y,
173: ptDst)) != null;
174:
175: final double rho = Math.sqrt(x * x + y * y);
176: if (Math.abs(rho) < EPSILON) {
177: y = 0.0; // latitudeOfOrigin
178: x = 0.0;
179: } else {
180: final double c = 2.0 * Math.atan(rho / k0);
181: final double cosc = Math.cos(c);
182: final double sinc = Math.sin(c);
183: y = Math.asin(y * sinc / rho); // (20-14) with phi1=0
184: final double t = x * sinc;
185: final double ct = rho * cosc;
186: x = (Math.abs(t) < EPSILON && Math.abs(ct) < EPSILON) ? 0.0
187: : Math.atan2(t, ct);
188: }
189:
190: assert checkInverseTransform(x, y, ptDst);
191: if (ptDst != null) {
192: ptDst.setLocation(x, y);
193: return ptDst;
194: }
195: return new Point2D.Double(x, y);
196: }
197: }
198: }
|