001: /*
002: * GeoTools - OpenSource mapping toolkit
003: * http://geotools.org
004: *
005: * (C) 2004-2006, Geotools Project Managment Committee (PMC)
006: * (C) 2000, Frank Warmerdam
007: *
008: * This library is free software; you can redistribute it and/or
009: * modify it under the terms of the GNU Lesser General Public
010: * License as published by the Free Software Foundation; either
011: * version 2.1 of the License, or (at your option) any later version.
012: *
013: * This library is distributed in the hope that it will be useful,
014: * but WITHOUT ANY WARRANTY; without even the implied warranty of
015: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
016: * Lesser General Public License for more details.
017: *
018: * This package contains formulas from the PROJ package of USGS.
019: * USGS's work is fully acknowledged here. This derived work has
020: * been relicensed under LGPL with Frank Warmerdam's permission.
021: */
022: package org.geotools.referencing.operation.projection;
023:
024: // J2SE dependencies and extensions
025: import java.awt.geom.Point2D;
026:
027: // OpenGIS dependencies
028: import org.opengis.parameter.ParameterNotFoundException;
029: import org.opengis.parameter.ParameterValueGroup;
030:
031: // Geotools dependencies
032: import org.geotools.resources.i18n.Errors;
033: import org.geotools.resources.i18n.ErrorKeys;
034:
035: /**
036: * The polar case of the {@link Orthographic} projection. Only the spherical
037: * form is given here.
038: *
039: * @since 2.4
040: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/referencing/src/main/java/org/geotools/referencing/operation/projection/PolarOrthographic.java $
041: * @version $Id: PolarOrthographic.java 24578 2007-02-24 00:57:19Z desruisseaux $
042: * @author Rueben Schulz
043: */
044: public class PolarOrthographic extends Orthographic {
045: /**
046: * Maximum difference allowed when comparing real numbers.
047: */
048: private static final double EPSILON = 1E-6;
049:
050: /**
051: * {@code true} if this projection is for the north pole, or {@code false}
052: * if it is for the south pole.
053: */
054: private final boolean northPole;
055:
056: /**
057: * Constructs a polar orthographic projection.
058: *
059: * @param parameters The parameter values in standard units.
060: * @throws ParameterNotFoundException if a mandatory parameter is missing.
061: */
062: protected PolarOrthographic(final ParameterValueGroup parameters)
063: throws ParameterNotFoundException {
064: super (parameters);
065: ensureLatitudeEquals(Provider.LATITUDE_OF_ORIGIN,
066: latitudeOfOrigin, Math.PI / 2);
067: northPole = (latitudeOfOrigin > 0);
068: latitudeOfOrigin = (northPole) ? Math.PI / 2.0 : -Math.PI / 2.0;
069: ensureSpherical();
070: }
071:
072: /**
073: * Transforms the specified (<var>λ</var>,<var>φ</var>) coordinates
074: * (units in radians) and stores the result in {@code ptDst} (linear distance
075: * on a unit sphere).
076: */
077: protected Point2D transformNormalized(double x, double y,
078: final Point2D ptDst) throws ProjectionException {
079: if (Math.abs(y - latitudeOfOrigin) - EPSILON > Math.PI / 2.0) {
080: throw new ProjectionException(Errors
081: .format(ErrorKeys.POINT_OUTSIDE_HEMISPHERE));
082: }
083: double cosphi = Math.cos(y);
084: double coslam = Math.cos(x);
085: if (northPole) {
086: coslam = -coslam;
087: }
088: y = cosphi * coslam;
089: x = cosphi * Math.sin(x);
090:
091: if (ptDst != null) {
092: ptDst.setLocation(x, y);
093: return ptDst;
094: }
095: return new Point2D.Double(x, y);
096: }
097:
098: /**
099: * Transforms the specified (<var>x</var>,<var>y</var>) coordinates
100: * and stores the result in {@code ptDst}.
101: */
102: protected Point2D inverseTransformNormalized(double x, double y,
103: final Point2D ptDst) throws ProjectionException {
104: final double rho = Math.sqrt(x * x + y * y);
105: double sinc = rho;
106: if (sinc > 1.0) {
107: if ((sinc - 1.0) > EPSILON) {
108: throw new ProjectionException(Errors
109: .format(ErrorKeys.POINT_OUTSIDE_HEMISPHERE));
110: }
111: sinc = 1.0;
112: }
113: if (rho <= EPSILON) {
114: y = latitudeOfOrigin;
115: x = 0.0;
116: } else {
117: double phi;
118: if (northPole) {
119: y = -y;
120: phi = Math.acos(sinc); // equivalent to asin(cos(c)) over the range [0:1]
121: } else {
122: phi = -Math.acos(sinc);
123: }
124: x = Math.atan2(x, y);
125: y = phi;
126: }
127: if (ptDst != null) {
128: ptDst.setLocation(x, y);
129: return ptDst;
130: }
131: return new Point2D.Double(x, y);
132: }
133: }
|