package com.revolsys.geometry.cs.projection;
import com.revolsys.geometry.cs.Datum;
import com.revolsys.geometry.cs.GeographicCoordinateSystem;
import com.revolsys.geometry.cs.ProjectedCoordinateSystem;
import com.revolsys.geometry.cs.ProjectionParameterNames;
import com.revolsys.geometry.cs.Spheroid;
import com.revolsys.math.Angle;
public class Mercator1SP extends AbstractCoordinatesProjection {
private final double a;
private final double e;
private final double eOver2;
private final double lambda0; // central meridian
private final double x0;
private final double y0;
public Mercator1SP(final ProjectedCoordinateSystem cs) {
final GeographicCoordinateSystem geographicCS = cs.getGeographicCoordinateSystem();
final Datum datum = geographicCS.getDatum();
final double centralMeridian = cs
.getDoubleParameter(ProjectionParameterNames.LONGITUDE_OF_CENTER);
final Spheroid spheroid = datum.getSpheroid();
this.x0 = cs.getDoubleParameter(ProjectionParameterNames.FALSE_EASTING);
this.y0 = cs.getDoubleParameter(ProjectionParameterNames.FALSE_NORTHING);
this.lambda0 = Math.toRadians(centralMeridian);
this.a = spheroid.getSemiMajorAxis();
this.e = spheroid.getEccentricity();
this.eOver2 = this.e / 2;
}
@Override
public void inverse(final double x, final double y, final double[] targetCoordinates,
final int targetOffset) {
final double dX = x - this.x0;
final double dY = y - this.y0;
final double lambda = dX / this.a + this.lambda0;
final double t = Math.pow(Math.E, -dY / this.a);
// TODO phi
double phi = Angle.PI_OVER_2 - 2 * Math.atan(t);
double delta = 10e010;
do {
final double eSinPhi = this.e * Math.sin(phi);
final double phi1 = Angle.PI_OVER_2
- 2 * Math.atan(t * Math.pow((1 - eSinPhi) / (1 + eSinPhi), this.eOver2));
delta = Math.abs(phi1 - phi);
phi = phi1;
} while (delta > 1.0e-011);
targetCoordinates[targetOffset] = lambda;
targetCoordinates[targetOffset + 1] = phi;
}
@Override
public void project(final double lambda, final double phi, final double[] targetCoordinates,
final int targetOffset) {
final double x = this.a * (lambda - this.lambda0);
final double eSinPhi = this.e * Math.sin(phi);
final double y = this.a * Math.log(
Math.tan(Angle.PI_OVER_4 + phi / 2) * Math.pow((1 - eSinPhi) / (1 + eSinPhi), this.eOver2));
targetCoordinates[targetOffset] = x;
targetCoordinates[targetOffset + 1] = y;
}
}