The procedure is based on an example that
implements a simplified version of the Mercator projection. The
complete code for this example can be found in the following file:
Defining a new projection class
-
To define a new class, you must first import the projection library located in the package ilog.views.maps.projection.The complete source code of the examples presented in the next sections can be found in the following file:Mercator example.
-
Your projection class must extend the class IlvProjection, which is the base class for all the projections in the package.
import ilog.views.maps.projection.*; import ilog.views.maps.*; class MercatorProjection extends IlvProjection
Writing the constructor
-
You must call the constructor of the superclass
IlvProjection
.MercatorProjection() { super(true, true, IlvProjection.CONFORMAL); }
This constructor takes the following three arguments:- The first argument is a
boolean
value specifying whether the projection supports nonspherical ellipsoids. In our example, this argument is set totrue
since the projection supports the equations for these ellipsoids. - The second argument is a
boolean
value indicating whether the projection supports an inverse method. In our example, this argument is set totrue
since the projection supports an inverse method. - The third argument is an
int
value that indicates the geometric properties of the projection. In our example, this argument isIlvProjection.CONFORMAL
since the Mercator projection is conformal.
Writing the Forward Projection
Before writing the
forward()
method for the Mercator projection, you must be familiar with
the
IlvProjection.forward()
method.
The
IlvProjection.forward()
public method is called by the user to project data. This method
prepares data for projection computation and scales it
appropriately. It then redirects the calls to either one of the
eforward
or
sForward
protected methods which are defined in the projection subclass
(the Mercator class in our example). In most cases, the
forward
method should not be overridden.
The forward method has the following effects:
-
It adjusts the latitude, if the coordinates are geocentric.
-
It adjusts the longitude to the central meridian of the projection.
-
It adjusts the longitude to the range
[-PI;PI]
, if longitude reduction is used (the default value). -
Adjusts the projected data to the dimensions of the ellipsoid and to the Cartesian offset, and converts it to the selected measurement unit.
Projecting data from a sphere
The
sforward()
protected method implements the projection of a sphere.
Since the appropriate scaling is actually carried out by the
method
IlvProjection.forward()
, the
sForward()
method always assumes that the radius of the sphere is 1.
In the example, the Mercator projection is the projection of a
sphere onto a cylinder that is tangential to the equator. The
x
coordinate is equal to the longitude because it is assumed that
the radius of the sphere is 1, and longitude is expressed in
radians. In this case, you do not need to change the
x
value of
ll
.
Because the Mercator projection cannot show regions near the
poles, the exception IlvToleranceConditionException is thrown
if the latitude is too close to
PI/2
.
-
Apply the equation to compute the
y
-coordinate of the projected data.protected void sForward(IlvCoordinate ll) throws IlvToleranceConditionException { if (Math.abs(Math.abs(ll.y) - Math.PI / 2D) <= 1e-10D) throw new IlvToleranceConditionException(); ll.y = Math.log(Math.tan(Math.PI / 4D + .5D * ll.y)); }
Projecting data from an ellipsoid
The
eforward()
protected method is called by the
IlvProjection.forward()
method if data is projected from a nonspherical ellipsoid.
-
It is not necessary for you to implement the
eForward()
method for your projection. If you are projecting data from a nonspherical ellipsoid and if the projection you are using does not support this kind of ellipsoid, theforward()
method will throw the exception IlvUnsupportedProjectionFeature. In this case, you can use any spherical ellipsoid or create an equivalent sphere using the appropriate conversion methods of the classIlvEllipsoid
.TheeForward()
method is slightly more complex than thesForward()
method although their formulas are equivalent ifgetEllipsoid().getE()
returns0
.protected void eForward(IlvCoordinate ll) throws IlvToleranceConditionException { if (Math.abs(Math.abs(ll.y) - Math.PI / 2D) <= 1e-10D) throw new IlvToleranceConditionException(); double e = Math.sqrt(getEllipsoid().getES()); double sinphi = e * Math.sin(ll.y); ll.y = Math.tan (.5D * (Math.PI/2D - ll.y)) / Math.pow((1D - sinphi) / (1D + sinphi), .5D * e); ll.y = -Math.log(ll.y); }
Writing the inverse projection
Before writing the
inverse()
method for the Mercator projection, you should be familiar with
the inverse method.
The
IlvProjection.inverse()
method prepares the data for inversion and processes it for the
appropriate offset. In most cases, you should not have to
override the
IlvProjection.inverse()
method.
This method has the following effects:
-
Suppresses the offset produced by the Cartesian coordinates and converts these coordinates to meters.
-
Reverts the coordinates to their geographic values and applies them to a standard ellipsoid with a semi-major axis of value 1.
-
Calls the method
sInverse()
oreInverse()
depending on whether the ellipsoid is a sphere or not. -
Adds the value of the central meridian to the longitude and adjusts the longitude to the range
[-PI;PI]
if longitude reduction is used (the default value). -
Converts the latitude if the coordinates are geocentric.
Inverse projection onto a sphere
The inverse projection onto a sphere is performed via the sInverse method.
-
It is not necessary for you to implement the
sInverse()
method. If you call theIlvProjection.inverse()
method for a projection that does not support theinverse()
method, the exception IlvUnsupportedProjectionFeature will be thrown. -
The
sInverse()
method can throw the exception IlvToleranceConditionException like all the forward methods. But since the inverse equation of the Mercator projection is defined for all the possible values, this method does not throw any exceptions. -
As with the
sForward()
method, the projection does not modify thex
value, therefore, the inverse equation is applied only to they
value.protected void sInverse(IlvCoordinate xy) { xy.y = Math.PI/2D - 2D * Math.atan(Math.exp(-xy.y)); }
Inverse projection onto an ellipsoid
The inverse projection onto an ellipsoid is performed via the eInverse method.
This method assumes that the value of the
semi-major axis of the ellipsoid is 1.
-
In the particular case of the Mercator projection, the implementation of this method is more complex for an ellipsoid than for a sphere. It requires iterations and might fail, since there is no simple analytical inverse equation of the Mercator projection from a nonspherical ellipsoid.
protected void eInverse(IlvCoordinate xy) throws IlvToleranceConditionException { double ts = Math.exp(- xy.y); double e = Math.sqrt(getEllipsoid().getES()); double eccnth = .5D * e; double Phi = Math.PI/2D - 2D * Math.atan(ts); int i = 15; double dphi; do { double con = e * Math.sin (Phi); dphi = Math.PI/2D - 2D * Math.atan(ts * Math.pow((1D - con) / (1D + con), eccnth)) - Phi; Phi += dphi; } while ((Math.abs(dphi) > 1e-10D) && (--i != 0)); if (i <= 0) throw new IlvToleranceConditionException("non-convergent inverse phi2"); xy.y = Phi; }