// **********************************************************************
//
// **********************************************************************
//
// $Source: /cvs/distapps/openmap/src/openmap/com/bbn/openmap/proj/LambertConformal.java,v $
// $RCSfile: LambertConformal.java,v $
// $Revision: 1.10 $
// $Date: 2009/02/25 22:34:04 $
// $Author: dietrick $
//
// **********************************************************************
package com.bbn.openmap.proj;
import java.awt.Point;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import com.bbn.openmap.MoreMath;
import com.bbn.openmap.proj.coords.LatLonPoint;
import com.bbn.openmap.util.Debug;
/**
* Implements the LambertConformalConic projection. <br>
* <br>
* <b>NOTE: </b> This implementation only works for the northern hemisphere. <br>
* <br>
* Needs to be modified for use in the southern hemisphere.
* <p>
* See http://www.epsg.org/guides/docs/G7-2.pdf
*
* @author David J. Ward
* @author Chris van Lith
*
*/
public class LambertConformal
extends GeoProj {
/**
* The LambertCC name.
*/
public final static transient String LambertConformalName = "Lambert Conformal";
private static final int MODE_2SP = 1;
private static final int MODE_BELGIUM = 2;
private int mode = MODE_2SP;
private double lambert_sp_one;
private double lambert_sp_two;
private double centralMeridian;
double locationCenterXPixel = 0;
double locationCenterYPixel = 0;
double locationCenterXLambert = 0.0;
double locationCenterYLambert = 0.0;
double locationPixelsPerLambert = 0.0;
double locationOriginX = 0.0;
double locationOriginY = 0.0;
double locationOriginXfPixel = 0.0;
double locationOriginYfPixel = 0.0;
double referenceLatitude = 0.0;
double falseEasting = 0.0;
double falseNorthing = 0.0;
// EPSG Guidance Note number 7, part 2 - November 2005
// Lambert Conic Conformal 9802
double n = 0.0;
double F = 0.0;
double rf = 0.0;
double lamdaf = 0.0;
double alpha = 0.0;
private transient Ellipsoid ellps = Ellipsoid.WGS_84;
/**
* A small number 10^(-10) This number can be re-factored into MoreMath
*/
final public static double EPS10 = 1.0e-10;
/**
* Construct a Lambert projection.
* <p>
*
* @param center LatLonPoint center of projection
* @param scale float scale of projection
* @param width width of screen
* @param height height of screen
*/
protected LambertConformal(LatLonPoint center, float scale, int width, int height) {
super(center, scale, width, height);
}
/**
* Constructor for the lambert conformal projection.
*
* @param center center location for projections
* @param scale scale of projection
* @param width width of projection
* @param height height of projection
* @param centralMeridian the Central Meridian in degrees.
* @param sp_one Standard Parallel One in degrees.
* @param sp_two Standard Parallel Two in degrees.
*/
protected LambertConformal(LatLonPoint center, float scale, int width, int height, float centralMeridian, float sp_one,
float sp_two, Ellipsoid ellps) {
this(center, scale, width, height, centralMeridian, sp_one, sp_two, 0f, 0, 0, ellps);
}
/**
* Constructor for the lambert conformal projection.
*
* @param center center location for projections
* @param scale scale of projection
* @param width width of projection
* @param height height of projection
* @param centralMeridian the Central Meridian in degrees.
* @param sp_one Standard Parallel One in degrees.
* @param sp_two Standard Parallel Two in degrees.
* @param reference_latitude the latitude for the origin of the projection
* @param falseEasting number of meters added as buffer to origin E/W.
* @param falseNorthing number of meters added as buffer to origin for N/S.
* @param ellps the {@link Ellipsoid} used for the projection
*/
public LambertConformal(LatLonPoint center, float scale, int width, int height, double centralMeridian, double sp_one,
double sp_two, double reference_latitude, double falseEasting, double falseNorthing, Ellipsoid ellps) {
super(center, scale, width, height);
if (Math.abs(sp_one + sp_two) < EPS10) {
// can not form a corn.
throw new RuntimeException("Unable to create Lambert Cornic");
}
this.centralMeridian = centralMeridian;
this.lambert_sp_one = sp_one;
this.lambert_sp_two = sp_two;
this.referenceLatitude = reference_latitude;
this.falseEasting = falseEasting;
this.falseNorthing = falseNorthing;
this.ellps = ellps;
computeParameters();
}
/**
* Called when some fundamental parameters change.
* <p>
* Each projection will decide how to respond to this change. For instance,
* they may need to recalculate "constant" parameters used in the forward()
* and inverse() calls.
* <p>
*
*/
public void computeParameters() {
// work around problem caused by Proj calling this method before
// constructor is done
if (ellps == null) {
ellps = Ellipsoid.WGS_84;
}
if (mode == MODE_BELGIUM) {
// Belgium EPSG 9803, adjustment 1972
alpha = 0.00014204d;
} else {
alpha = 0d;
}
double phi1 = ProjMath.degToRad(lambert_sp_one);
double phi2 = ProjMath.degToRad(lambert_sp_two);
double phif = ProjMath.degToRad(referenceLatitude);
double e = ellps.ecc;
double sinphi;
sinphi = Math.sin(phi1);
double m1 = lambMsfn(sinphi, Math.cos(phi1), e);
double t1 = lambTsfn(phi1, sinphi, e);
if (MoreMath.approximately_equal(phi1, phi2, EPS10)) {
n = sinphi;
} else {
sinphi = Math.sin(phi2);
double m2 = lambMsfn(sinphi, Math.cos(phi2), e);
double t2 = lambTsfn(phi2, sinphi, e);
n = Math.log(m1 / m2) / Math.log(t1 / t2);
}
F = m1 / (n * Math.pow(t1, n));
if (MoreMath.approximately_equal(phi1, phi2, EPS10)) {
rf = 0.0d;
} else {
rf = ellps.radius * F * Math.pow(lambTsfn(phif, Math.sin(phif), e), n);
}
lamdaf = ProjMath.degToRad(centralMeridian);
locationCenterXPixel = ((double) getWidth() / 2d);
locationCenterYPixel = ((double) getHeight() / 2d);
locationPixelsPerLambert = (double) getPPM() / getScale();
LatLonPoint origin = new LatLonPoint.Double(referenceLatitude, centralMeridian);
Point2D lp = LLToWorld(origin.getY(), origin.getX(), new Point2D.Double());
locationOriginX = lp.getX();
locationOriginY = lp.getY();
LatLonPoint center = getCenter();
lp = LLToWorld(center.getY(), center.getX(), lp);
locationCenterXLambert = lp.getX();
locationCenterYLambert = lp.getY();
// calculate un-truncated true origin pixel value, refer to method
// worldToPixel.
locationOriginXfPixel = locationCenterXPixel + (locationOriginX - locationCenterXLambert) * locationPixelsPerLambert;
locationOriginYfPixel = locationCenterYPixel - (locationOriginY - locationCenterYLambert) * locationPixelsPerLambert;
if (Debug.debugging("Lambert")) {
Debug.output("Creating LambertConformal: center x = " + locationCenterXLambert + ", center y = "
+ locationCenterYLambert);
Debug.output("Creating LambertConformal: origin x = " + locationOriginX + ", origin y = " + locationOriginY);
}
}
/**
* Sets radian latitude to something sane. This is an abstract function
* since some projections don't deal well with extreme latitudes.
* <p>
*
* @param lat float latitude in radians
* @return float latitude (-PI/2 <= y <= PI/2)
*
*/
public double normalizeLatitude(double lat) {
if (lat > NORTH_POLE) {
return NORTH_POLE;
} else if (lat < SOUTH_POLE) {
return SOUTH_POLE;
}
return lat;
}
/*----------------------------------------------------------------------------
* FUNCTION: LLToWorld
* DATE CREATE: 13-4-2006
* CREATED BY: Chris van Lith
* Modified By: steve C. Tang, 02/20/2010
* DESCRIPTION: This function converts lat, lon coordinate to lambert
* coordinate.
*--------------------------------------------------------------------------*/
public Point2D LLToWorld(double lat, double lon, Point2D lp) {
if (lp == null) {
lp = new Point2D.Double();
}
LLToWorldReturningLon(lat, lon, lp);
return lp;
}
/**
* LLToWorld that returns normalized longitude in radians, to be used for
* more calculations in some methods. Do not provide a NULL lp here if you
* want the world coordinates provided back to you.
*
* @param lat latitude in degrees
* @param lon longitude in degrees.
* @param lp world coordinates are provided back in this object, make sure
* it's not null if you care about them.
* @return normalized longitude in radians, radians lon - radians lat.
*/
protected double LLToWorldReturningLon(double lat, double lon, Point2D lp) {
double phi_deg = lat;
double phi = ProjMath.degToRad(phi_deg);
double lamba_deg = lon;
double lamba = ProjMath.degToRad(lamba_deg);
// normalized longitude
double dlamda = lamba - lamdaf;
if (dlamda > Math.PI) {
dlamda -= MoreMath.TWO_PI_D;
} else if (dlamda < -Math.PI) {
dlamda += MoreMath.TWO_PI_D;
}
double e = ellps.ecc;
double r = 0.0d;
if (!MoreMath.approximately_equal(Math.abs(phi), MoreMath.HALF_PI, EPS10)) {
double t = lambTsfn(phi, Math.sin(phi), e);
r = ellps.radius * F * Math.pow(t, n);
}
double theta = n * dlamda;
double easting = falseEasting + r * Math.sin(theta - alpha);
double northing = falseNorthing + rf - r * Math.cos(theta - alpha);
lp.setLocation(easting, northing);
return dlamda;
} /* end of function LLToWorld */
/*----------------------------------------------------------------------------
* FUNCTION: lat_lon_to_pixel
* DATE CREATE: 28 February 1995
* CREATED BY: David J. Ward
* Modified by: Steve C. Tang, 02/20/2010
* DESCRIPTION: This function converts lat, lon coordinate to pixel
* coordinate.
*--------------------------------------------------------------------------*/
public double LLToPixel(double lat, double lon, Point2D p) {
double dlamda;
Point2D lp = new Point2D.Double();
dlamda = LLToWorldReturningLon(lat, lon, lp);
double xrel = lp.getX() - locationCenterXLambert;
double yrel = lp.getY() - locationCenterYLambert;
xrel = (xrel * locationPixelsPerLambert);
yrel = (yrel * locationPixelsPerLambert);
xrel = locationCenterXPixel + xrel;
yrel = locationCenterYPixel - yrel;
if (p == null) {
p = new Point2D.Double();
}
p.setLocation(xrel, yrel);
// In Openmap 4.6.5 and before, the float-2-int truncation in
// World-to-Pixel transform can cause
// the displayed position on the other side if the projection side line
// runs across the pixel.
// For example, a true World coordinate of 678.9 is truncated to (int)
// 678.9=678. while 678.9
// can correspond to dlamda=180.1 that means -179.9 on the other side,
// 678
// can correspond to
// dlamda=179.9 during later map projection. We approximate this
// situation
// by forcing the swap.
// Increase PixelsPerLambert and projection size can reduce the error.
if ((dlamda > 3.1415 && p.getX() < locationOriginXfPixel) || (-dlamda > 3.1415 && p.getX() > locationOriginXfPixel)) {
dlamda = -dlamda;
}
return dlamda;
} /* end of function LLToPixel */
//
public Point worldToPixel(Point2D lp, Point p) {
double x = locationCenterXPixel + (lp.getX() - locationCenterXLambert) * locationPixelsPerLambert;
double y = locationCenterYPixel - (lp.getY() - locationCenterYLambert) * locationPixelsPerLambert;
if (p == null)
p = new Point();
p.setLocation((int) x, (int) y);
return p;
}
//
public Point2D pixelToWorld(Point p, Point2D lp) {
double x = locationCenterXLambert + (p.getX() - locationCenterXPixel) / locationPixelsPerLambert;
double y = locationCenterYLambert - (p.getY() - locationCenterYPixel) / locationPixelsPerLambert;
if (lp == null)
lp = new Point2D.Double();
lp.setLocation(x, y);
return lp;
}
/*----------------------------------------------------------------------------
* FUNCTION: worldToLL
* DATE CREATE: 13-4-2006
* CREATED BY: Chris van Lith
* Modified By: Steve C. Tang, 02/20/2010
* DESCRIPTION: This function converts lambert projections to lat, lon
* coordinate. It is given the lambert projections as the
* input, and the lat, lon coordinate as the output.
*--------------------------------------------------------------------------*/
public Point2D worldToLL(double x, double y, Point2D llp) {
x -= falseEasting;
y = rf - (y - falseNorthing);
double rR = Math.sqrt(x * x + y * y);
if (rR < EPS10) {
llp.setLocation(0.0, n > 0.0 ? 90.0 : -90.0);
return llp;
}
if (n < 0.0) {
rR = -rR;
x = -x;
y = -y;
}
double tR = Math.pow(rR / (ellps.radius * F), 1 / n);
double halfe = 0.5 * ellps.ecc;
double phiT1 = 0.0;
double phiT2 = MoreMath.HALF_PI - 2 * Math.atan(tR);
int iIter = 0, nIter = 10;
double halfesinphi;
do {
phiT1 = phiT2;
halfesinphi = halfe * Math.sin(phiT1);
phiT2 = MoreMath.HALF_PI - 2 * Math.atan(tR * Math.pow((0.5 - halfesinphi) / (0.5 + halfesinphi), halfe));
} while ((Math.abs(phiT2 - phiT1) > EPS10) && (iIter++ < nIter));
double lamda = ((Math.atan2(x, y) + alpha) / n) + lamdaf;
double lamda_deg = ProjMath.radToDeg(lamda);
double phi_deg = ProjMath.radToDeg(phiT2);
if (llp == null) {
llp = new LatLonPoint.Double();
}
// the LatLonPoint.setLocation(double Lon, double Lat) method specifies
// Lat-lon in reversed order compared to other methods such as
// LatLonPoint.setLocation(double Lat, double lon, boolean isRadian).
// This is very confusing.
llp.setLocation(lamda_deg, phi_deg); // Lon, Lat
return llp;
} /* end of function worldToLL */
/*----------------------------------------------------------------------------
* FUNCTION: pixelToLL
* DATE CREATE: 28 February 1995
* CREATED BY: David J. Ward
* Modified By: Steve C. Tang 02/20/2010
* DESCRIPTION: This function converts pixel coordinate into lat, lon
* coordinate.
*--------------------------------------------------------------------------*/
public Point2D pixelToLL(double xabs, double yabs, Point2D llp) {
double x = locationCenterXLambert + ((xabs - locationCenterXPixel) / locationPixelsPerLambert);
double y = locationCenterYLambert + ((locationCenterYPixel - yabs) / locationPixelsPerLambert);
worldToLL(x, y, llp);
return llp;
} /* end of function pixelToLL */
protected Point2D plotablePoint = new Point2D.Double();
/**
* Determine if the location is plotable on the screen. The Lambert
* Conformal projection does not lend its self to a simple determination.
* This method invokes forward to obtain the screen coordinates. If the
* screen coordinates are visible returns true otherwise returns false.
*
* @param lat latitude in degrees
* @param lon longitude in degrees
* @return true is plotable, otherwise false
*/
public boolean isPlotable(double lat, double lon) {
// It is almost impossible to determine it the location
// is plotable without calling forward() for the Point
// and checking if the point is in bounds.
// Be lazy and return true.
if (lat < -70d)
return false;
forward(lat, lon, plotablePoint);
double x = plotablePoint.getX();
double y = plotablePoint.getY();
return (x >= 0 && x < this.width && y >= 0 && y < height);
}
/**
* Determine if the location is plotable
*
* @param llpoint location to check
* @return returns true is plotable, otherwise false
*/
public boolean isPlotable(LatLonPoint llpoint) {
return isPlotable(llpoint.getY(), llpoint.getX());
}
/**
* Forward projects lat,lon into XY space and sets the results in the p
* provided.
* <p>
*
* @return Point2D p
* @param lat latitude
* @param lon longitude
* @param p Resulting XY Point2D
* @param isRadian indicates that lat,lon arguments are in radians
*/
public Point2D forward(double lat, double lon, Point2D p, boolean isRadian) {
if (p == null) {
p = new Point2D.Double();
}
_forward(lat, lon, p, isRadian);
return p;
}
protected double _forward(double lat, double lon, Point2D p, boolean isRadian) {
// Figure out the point for screen coordinates. Need to take
// into account that the origin point of the projection may be
// off screen, so we need to take the calculated world
// coordinates of the center of the screen and subtract the
// screen offset from that.
if (isRadian) {
return LLToPixel(ProjMath.radToDeg(lat), ProjMath.radToDeg(lon), p);
} else {
return LLToPixel(lat, lon, p);
}
}
/**
* Inverse project x,y coordinates into a LatLonPoint.
* <p>
*
* @param x integer x coordinate
* @param y integer y coordinate
* @param llp LatLonPoint
* @return LatLonPoint llp
* @see Proj#inverse(Point2D)
*/
public <T extends Point2D> T inverse(double x, double y, T llp) {
if (llp == null) {
llp = (T) new LatLonPoint.Double();
}
// convert from screen to world coordinates
pixelToLL(x, y, llp);
return llp;
}
/**
* Get the upper left (northwest) point of the projection.
* <p>
* Returns the upper left point (or closest equivalent) of the projection
* based on the center point and height and width of screen.
* <p>
*
* @return LatLonPoint
*/
public LatLonPoint getUpperLeft() {
// In a conic projection the upper left is meaningless
// unless at relatively small scales.
// Return 90.0 -180 until someone figures out a better way.
return new LatLonPoint.Double(90.0, -180.0);
}
/**
* Get the lower right (southeast) point of the projection.
* <p>
* Returns the lower right point (or closest equivalent) of the projection
* based on the center point and height and width of screen.
* <p>
*
* @return LatLonPoint
*/
public LatLonPoint getLowerRight() {
// In a conic projection the upper left is meaningless
// unless at relatively small scales.
// Return 90.0 -180 until someone figures out a better way.
return new LatLonPoint.Double(-90.0, 180.0);
}
public double getReferenceLon() {
return centralMeridian;
}
/**
* Get the name string of the projection.
*
* @return the projection name
*/
public String getName() {
return LambertConformalName;
}
/**
* Forward project a raw array of radian points. This assumes nothing about
* the array of coordinates. In no way does it assume the points are
* connected or that the composite figure is to be filled.
* <p>
* It does populate a visible array indicating whether the points are
* visible on the projected view of the world.
* <p>
*
* @param rawllpts array of lat,lon,... in radians
* @param rawoff offset into rawllpts
* @param xcoords x coordinates
* @param ycoords y coordinates
* @param visible coordinates visible?
* @param copyoff offset into x,y,visible arrays
* @param copylen number of coordinates (coordinate arrays should be at
* least this long, rawllpts should be at least twice as long).
* @return boolean true if all points visible, false if some points not
* visible.
*/
public boolean forwardRaw(float[] rawllpts, int rawoff, float[] xcoords, float[] ycoords, boolean[] visible, int copyoff,
int copylen) {
double[] drawllpts = new double[rawllpts.length];
System.arraycopy(drawllpts, 0, rawllpts, 0, rawllpts.length);
return forwardRaw(drawllpts, rawoff, xcoords, ycoords, visible, copyoff, copylen);
}
public boolean forwardRaw(double[] rawllpts, int rawoff, float[] xcoords, float[] ycoords, boolean[] visible, int copyoff,
int copylen) {
boolean visibleTotal = false;
// HACK grabbed from Cylindrical. Might need fixing.
Point temp = new Point();
int end = copylen + copyoff;
for (int i = copyoff, j = rawoff; i < end; i++, j += 2) {
forward(rawllpts[j], rawllpts[j + 1], temp, true);
xcoords[i] = temp.x;
ycoords[i] = temp.y;
visible[i] = (0 <= temp.x && temp.x <= width) && (0 <= temp.y && temp.y <= height);
if (visible[i] == true && visibleTotal == false) {
visibleTotal = true;
}
}
// if everything is visible
return visibleTotal;
}
/**
* Forward project a lat/lon Poly. Remember to specify vertices in radians!
*
* @param rawllpts float[] of lat,lon,lat,lon,... in RADIANS!
* @param ltype line type (straight, rhumbline, greatcircle)
* @param nsegs number of segment points (only for greatcircle or rhumbline
* line types, and if < 1, this value is generated internally)
* @param isFilled filled poly? this is currently ignored for cylindrical
* projections.
* @return ArrayList float[] of x[], y[], x[], y[], ... projected poly
*/
protected ArrayList<float[]> _forwardPoly(float[] rawllpts, int ltype, int nsegs, boolean isFilled) {
double[] drawllpts = new double[rawllpts.length];
System.arraycopy(drawllpts, 0, rawllpts, 0, rawllpts.length);
return _forwardPoly(drawllpts, ltype, nsegs, isFilled);
}
public ArrayList<float[]> _forwardPoly(double[] rawllpts, int ltype, int nsegs, boolean isFilled) {
int i, j, k;
// determine length of pairs
int len = rawllpts.length >> 1; // len/2, chop off extra
if (len < 2)
return new ArrayList<float[]>(0);
// Not concerned with any polygons that are completely below
// 60S
double minlat = ProjMath.degToRad(-60f);
boolean allBelowMinLat = true;
for (i = 0, j = 0; i < len; i++, j += 2) {
double l = rawllpts[j + 1];
while (l < 0f)
l += Math.PI * 2f;
if (rawllpts[j] > minlat) {
allBelowMinLat = false;
}
}
if (allBelowMinLat) {
return new ArrayList<float[]>(0);
}
// handle complicated line in specific routines
if (isComplicatedLineType(ltype))
return doPolyDispatch(rawllpts, ltype, nsegs, isFilled);
Point temp = new Point();
int[] xa = new int[len];
float[] xs = new float[len];
float[] ys = new float[len];
double dlamda1, dlamda2;
// forward project the points
k = 0;
xa[k] = 0;
i = 0;
dlamda1 = _forward(rawllpts[i], rawllpts[i + 1], temp, true);
xs[i] = temp.x;
ys[i] = temp.y;
for (i = 1, j = 2; i < len; i++, j += 2) {
dlamda2 = _forward(rawllpts[j], rawllpts[j + 1], temp, true);
if (Math.abs(dlamda2 - dlamda1) >= Math.PI) {
xa[++k] = i;
}
xs[i] = temp.x;
ys[i] = temp.y;
dlamda1 = dlamda2;
}
if (xa[k] < len)
xa[++k] = len;
ArrayList<float[]> ret_val = new ArrayList<float[]>(2);
for (i = 0; i < k; i++) {
len = xa[i + 1] - xa[i];
if (len > 0) {
float[] xf = new float[len];
float[] yf = new float[len];
for (j = 0; j < len; j++) {
xf[j] = xs[j + xa[i]];
yf[j] = ys[j + xa[i]];
}
if (i > 0 && i == k - 1 && (xs[0] == xs[xs.length - 1] && ys[0] == ys[ys.length - 1])) {
int len0 = ((float[]) ret_val.get(0)).length;
float[] x0 = new float[len0 + len];
float[] y0 = new float[len0 + len];
System.arraycopy(xf, 0, x0, 0, len);
System.arraycopy(yf, 0, y0, 0, len);
System.arraycopy(((float[]) ret_val.get(0)), 0, x0, len, len0);
System.arraycopy(((float[]) ret_val.get(1)), 0, y0, len, len0);
ret_val.set(0, x0);
ret_val.set(1, y0);
} else {
ret_val.add(xf);
ret_val.add(yf);
}
}
}
return ret_val;
}
/**
* Given a couple of points representing a bounding box, find out what the
* scale should be in order to make those points appear at the corners of
* the projection.
*
* @param ll1 the upper left coordinates of the bounding box.
* @param ll2 the lower right coordinates of the bounding box.
* @param point1 a java.awt.Point reflecting a pixel spot on the projection
* that matches the ll1 coordinate, the upper left corner of the area
* of interest.
* @param point2 a java.awt.Point reflecting a pixel spot on the projection
* that matches the ll2 coordinate, usually the lower right corner of
* the area of interest.
*/
@Override
public float getScale(Point2D ll1, Point2D ll2, Point2D point1, Point2D point2) {
// super does not calculate scale correct for projections that does use
// the same earth radius up north..
double widthPX = point2.getX() - point1.getX();
Point2D xx1 = LLToWorld(ll1.getY(), ll1.getX(), new Point2D.Double());
Point2D xx2 = LLToWorld(ll2.getY(), ll2.getX(), new Point2D.Double());
double widthMap = (xx2.getX() - xx1.getX());
double widthScale = (((double) getPPM()) * (widthMap / widthPX));
// TODO: use width-, height- or medium scale?
// Until then, this isn't needed:
// double heightPX = point2.y - point1.y;
// double heightMap = (xx2.getY() - xx1.getY());
// double heightScale = (((double) getPPM()) * (heightMap / heightPX));
return (float) widthScale;
}
/**
* Draw the background for the projection.
*
* @param g Graphics2D
* @param paint java.awt.Paint to use for the background
*/
public void drawBackground(java.awt.Graphics2D g, java.awt.Paint paint) {
g.setPaint(paint);
drawBackground(g);
}
/**
* Draw the background for the projection.
*
* @param g Graphics
*/
public void drawBackground(java.awt.Graphics g) {
g.fillRect(0, 0, getWidth(), getHeight());
}
/**
* Special function m = cos(phi) / sqrt(1.0 - (e*sin(phi))**2)
*
* @param sinphi double
* @param cosphi double
* @param e double
* @return double
*/
public static double lambMsfn(double sinphi, double cosphi, double e) {
sinphi *= e;
return cosphi / Math.sqrt(1.d - sinphi * sinphi);
}
/**
* Special function t = tan(PI/4-phi/2) / pow((1-sinphi)/(1+sinphi), .5*e)
*
* @param phi double
* @param sinphi double
* @param e double
* @return double
*/
public static double lambTsfn(double phi, double sinphi, double e) {
sinphi *= e;
return Math.tan((MoreMath.HALF_PI - phi) * 0.5d) * Math.pow((1.d + sinphi) / (1.d - sinphi), 0.5d * e);
}
/**
* test method
*
* @param argv command line parameters
*/
public static void main(String argv[]) {
Debug.init();
Debug.put("Lambert");
LambertConformal proj = null;
proj = new LambertConformal(new LatLonPoint.Double(50.679572292f, 5.807370150f), 100000.0f, 620, 480, 4.3569395237f, // centralMeridian
-49.833333109f, // lambert_sp_one
-51.166666321f, // lambert_sp_two
90.0f, // referenceLatitude
150000.01f, // falseEasting
5400088.44f, // falseNorthing
Ellipsoid.WGS_84);
Debug.message("Lambert", "(1)" + proj.inverse(310, 240));
LatLonPoint llp = new LatLonPoint.Double(0.0f, 0.0f);
Debug.message("Lambert", "(2)" + proj.worldToLL(251763.20f, 153034.13f, llp));
LatLonPoint pt = new LatLonPoint.Double(50.679572292f, 5.807370150f);
Point2D lp = proj.LLToWorld(pt.getY(), pt.getX(), new Point2D.Double());
Debug.message("Lambert", "(3)" + lp);
}
}