/*
* GeoTools - The Open Source Java GIS Toolkit
* http://geotools.org
*
* (C) 2014, Open Source Geospatial Foundation (OSGeo)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* This package contains formulas from the PROJ package of USGS.
* USGS's work is fully acknowledged here. This derived work has
* been relicensed under LGPL with Frank Warmerdam's permission.
*/
package org.geotools.referencing.operation.projection;
import static java.lang.Math.cos;
import static java.lang.Math.sin;
import static java.lang.Math.sqrt;
import java.awt.geom.Point2D;
import org.geotools.metadata.iso.citation.Citations;
import org.geotools.referencing.NamedIdentifier;
import org.geotools.resources.i18n.ErrorKeys;
import org.opengis.parameter.ParameterDescriptor;
import org.opengis.parameter.ParameterDescriptorGroup;
import org.opengis.parameter.ParameterNotFoundException;
import org.opengis.parameter.ParameterValueGroup;
import org.opengis.referencing.operation.MathTransform;
/**
* Sinusoidal (Sanson–Flamsteed) projection
*
* @see <A HREF="http://en.wikipedia.org/wiki/Sinusoidal_projection">Sinusoidal projection on
* Wikipedia</A>
* @see <A HREF="http://www.remotesensing.org/geotiff/proj_list/sinusoidal.html">"Sinusoidal" on
* RemoteSensing.org</A>
*
* @since 14.0
*
*
* @source $URL$
* @author Mihail Andreev
*/
public class Sinusoidal extends MapProjection {
/**
* For cross-version compatibility.
*/
private static final long serialVersionUID = 7528023862968814860L;
private final static double EPS10 = 1e-10;
private final static double HALFPI = Math.PI /2.;
/**
* Constructs a new map projection from the supplied parameters.
*
* @param parameters The parameter values in standard units.
* @throws ParameterNotFoundException if a mandatory parameter is missing.
*/
protected Sinusoidal(final ParameterValueGroup parameters) throws ParameterNotFoundException {
super(parameters);
}
/**
* {@inheritDoc}
*/
public ParameterDescriptorGroup getParameterDescriptors() {
return Provider.PARAMETERS;
}
/**
* Transforms the specified (<var>λ</var>,<var>φ</var>) coordinates
* (units in radians) and stores the result in {@code ptDst} (linear distance
* on a unit sphere).
*/
protected Point2D transformNormalized(double lam, double phi, final Point2D ptDst)
throws ProjectionException {
double x,y;
if (isSpherical) {
x = lam * cos(phi);
y = phi;
} else {
double s = sin(phi);
double c = cos(phi);
y = mlfn(phi, sin(phi), cos(phi));
x = lam * c / sqrt(1. - excentricitySquared * s * s);
}
if(ptDst != null) {
ptDst.setLocation(x, y);
return ptDst;
} else {
return new Point2D.Double(x, y);
}
}
/**
* Transforms the specified (<var>x</var>,<var>y</var>) coordinates
* and stores the result in {@code ptDst}.
*/
protected Point2D inverseTransformNormalized(double x, double y, final Point2D ptDst)
throws ProjectionException {
double phi;
double lam;
if( isSpherical ) {
phi = y;
lam = x / cos( y);
} else {
phi = inv_mlfn(y);
double s = Math.abs( phi );
double diff = Math.abs(s - HALFPI);
if (diff < EPS10) {
lam = 0.;
} else if (s < HALFPI) {
s = sin(phi);
lam = (x * sqrt(1. - excentricitySquared * s * s) / cos(phi)) % Math.PI;
} else {
throw new ProjectionException(ErrorKeys.TOLERANCE_ERROR);
// throw new ProjectionException("Tolerance error occurred appling inverse Sinusoidal projection");
}
}
if (ptDst != null) {
ptDst.setLocation(lam, phi);
return ptDst;
} else {
return new Point2D.Double(lam, phi);
}
}
/**
* Compares the specified object with this map projection for equality.
*/
@Override
public boolean equals(final Object object) {
if (object == this) {
// Slight optimization
return true;
}
return super.equals(object);
}
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
//////// ////////
//////// PROVIDERS ////////
//////// ////////
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
/**
* The {@linkplain org.geotools.referencing.operation.MathTransformProvider math transform
* provider} for the Sinusoidal projection (not part of the EPSG database).
*
* @since 14.0
* @author Mihail Andreev
*
* @see org.geotools.referencing.operation.DefaultMathTransformFactory
*/
public static class Provider extends AbstractProvider {
/**
* For cross-version compatibility.
*/
private static final long serialVersionUID = 8374488793001927036L;
/**
* The parameters group.
*/
static final ParameterDescriptorGroup PARAMETERS = createDescriptorGroup(new NamedIdentifier[] {
new NamedIdentifier(Citations.GEOTOOLS, "Sinusoidal"),
new NamedIdentifier(Citations.ESRI, "Sinusoidal")
}, new ParameterDescriptor[] {
SEMI_MAJOR, SEMI_MINOR,
CENTRAL_MERIDIAN, FALSE_EASTING, FALSE_NORTHING
});
/**
* Constructs a new provider.
*/
public Provider() {
super(PARAMETERS);
}
/**
* Creates a transform from the specified group of parameter values.
*
* @param parameters The group of parameter values.
* @return The created math transform.
* @throws ParameterNotFoundException if a required parameter was not found.
*/
protected MathTransform createMathTransform(final ParameterValueGroup parameters)
throws ParameterNotFoundException
{
return new Sinusoidal(parameters);
}
}
}