diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7157e8a..625b442 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,17 +6,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
+## [1.1.0] - 2019-09-05
+
### Added
-- Added `GeostationarySatelliteProjection`/`geos` projection by [@Yaqiang](https://github.com/Yaqiang)
-- Registry.getProjections exposes all available projects by [@noberasco](https://github.com/noberasco)
-- OSGi compatibility by [@Neutius](https://github.com/Neutius)
+- Added `GeostationarySatelliteProjection`/`geos` projection
+- Registry.getProjections exposes all available projects
+- OSGi compatibility
### Changed
-- Parse `geos` (Geostationary Satellite Projection) proj4 strings by [@pomadchin](https://github.com/pomadchin)
-- Projection units reported as meters by default by [@bosborn](https://github.com/bosborn)
-- BasicCoordinateTransform now thread-safe by [@sebasbaumh](https://github.com/sebasbaumh)
-- Improve CRS Caching performance by [@pomadchin](https://github.com/pomadchin)
-- CoordinateReferenceSystem.equals considered logical equality by [@pomadchin](https://github.com/pomadchin)
+- Parse `geos` (Geostationary Satellite Projection) proj4 strings
+- Projection units reported as meters by default
+- BasicCoordinateTransform now thread-safe
+- Improve CRS Caching performance
+- CoordinateReferenceSystem.equals considered logical equality
+- Projection.equals considered logical equality
## [1.0.0] - 2019-12-12
diff --git a/pom.xml b/pom.xml
index 457f5a2..76c23ba 100755
--- a/pom.xml
+++ b/pom.xml
@@ -3,7 +3,7 @@
org.locationtech.proj4j
proj4j
- 1.0.1-SNAPSHOT
+ 1.1.0-SNAPSHOT
bundle
Proj4J
https://github.com/locationtech/proj4j
@@ -120,7 +120,7 @@
true
-
+
diff --git a/src/main/java/org/locationtech/proj4j/CoordinateReferenceSystem.java b/src/main/java/org/locationtech/proj4j/CoordinateReferenceSystem.java
index cc0b993..ab78ab2 100755
--- a/src/main/java/org/locationtech/proj4j/CoordinateReferenceSystem.java
+++ b/src/main/java/org/locationtech/proj4j/CoordinateReferenceSystem.java
@@ -129,7 +129,8 @@ public boolean equals(Object that) {
}
if (that instanceof CoordinateReferenceSystem) {
CoordinateReferenceSystem cr = (CoordinateReferenceSystem) that;
- return name.equals(cr.name) && datum.isEqual(cr.getDatum()) && Arrays.equals(params, cr.params);
+ // Projection equality contains Ellipsoid and Unit equality
+ return datum.isEqual(cr.getDatum()) && proj.equals(cr.proj);
}
return false;
}
diff --git a/src/main/java/org/locationtech/proj4j/datum/AxisOrder.java b/src/main/java/org/locationtech/proj4j/datum/AxisOrder.java
index 9cf8862..8c6da20 100644
--- a/src/main/java/org/locationtech/proj4j/datum/AxisOrder.java
+++ b/src/main/java/org/locationtech/proj4j/datum/AxisOrder.java
@@ -86,7 +86,7 @@ static Axis fromChar(char c) {
public abstract void toENU(double x, ProjCoordinate c);
}
- public final static AxisOrder ENU =
+ public final static AxisOrder ENU =
new AxisOrder(Axis.Easting, Axis.Northing, Axis.Up);
private final Axis x, y, z;
diff --git a/src/main/java/org/locationtech/proj4j/proj/AiryProjection.java b/src/main/java/org/locationtech/proj4j/proj/AiryProjection.java
index f93b439..a8dd2f3 100644
--- a/src/main/java/org/locationtech/proj4j/proj/AiryProjection.java
+++ b/src/main/java/org/locationtech/proj4j/proj/AiryProjection.java
@@ -45,7 +45,7 @@ public AiryProjection() {
maxLongitude = Math.toRadians(90);
initialize();
}
-
+
public ProjCoordinate project(double lplam, double lpphi, ProjCoordinate out) {
double sinlam, coslam, cosphi, sinphi, t, s, Krho, cosz;
diff --git a/src/main/java/org/locationtech/proj4j/proj/AitoffProjection.java b/src/main/java/org/locationtech/proj4j/proj/AitoffProjection.java
index b79a4cc..e3326d1 100644
--- a/src/main/java/org/locationtech/proj4j/proj/AitoffProjection.java
+++ b/src/main/java/org/locationtech/proj4j/proj/AitoffProjection.java
@@ -23,7 +23,7 @@
public class AitoffProjection extends PseudoCylindricalProjection {
-
+
protected final static int AITOFF = 0;
protected final static int WINKEL = 1;
@@ -65,7 +65,7 @@ public void initialize() {
cosphi1 = 0.636619772367581343;
}
}
-
+
public boolean hasInverse() {
return false;
}
@@ -74,5 +74,15 @@ public String toString() {
return winkel ? "Winkel Tripel" : "Aitoff";
}
+ @Override
+ public boolean equals(Object that) {
+ if (this == that) {
+ return true;
+ }
+ if (that instanceof AitoffProjection) {
+ AitoffProjection p = (AitoffProjection) that;
+ return (winkel == p.winkel && super.equals(that));
+ }
+ return false;
+ }
}
-
diff --git a/src/main/java/org/locationtech/proj4j/proj/AzimuthalProjection.java b/src/main/java/org/locationtech/proj4j/proj/AzimuthalProjection.java
index 99ccb78..b2c64b2 100644
--- a/src/main/java/org/locationtech/proj4j/proj/AzimuthalProjection.java
+++ b/src/main/java/org/locationtech/proj4j/proj/AzimuthalProjection.java
@@ -27,11 +27,11 @@ public abstract class AzimuthalProjection extends Projection {
public final static int SOUTH_POLE = 2;
public final static int EQUATOR = 3;
public final static int OBLIQUE = 4;
-
+
protected int mode;
protected double sinphi0, cosphi0;
private double mapRadius = 90.0;
-
+
public AzimuthalProjection() {
this( Math.toRadians(45.0), Math.toRadians(45.0) );
}
@@ -41,7 +41,7 @@ public AzimuthalProjection(double projectionLatitude, double projectionLongitude
this.projectionLongitude = projectionLongitude;
initialize();
}
-
+
public void initialize() {
super.initialize();
if (Math.abs(Math.abs(projectionLatitude) - ProjectionMath.HALFPI) < EPS10)
@@ -69,5 +69,20 @@ public double getMapRadius() {
return mapRadius;
}
+ @Override
+ public boolean equals(Object that) {
+ if (this == that) {
+ return true;
+ }
+ if (that instanceof AzimuthalProjection) {
+ AzimuthalProjection p = (AzimuthalProjection) that;
+ return (
+ mode == p.mode &&
+ sinphi0 == p.sinphi0 &&
+ cosphi0 == p.cosphi0 &&
+ mapRadius == p.mapRadius &&
+ super.equals(that));
+ }
+ return false;
+ }
}
-
diff --git a/src/main/java/org/locationtech/proj4j/proj/BipolarProjection.java b/src/main/java/org/locationtech/proj4j/proj/BipolarProjection.java
index eb92360..fb8eff8 100644
--- a/src/main/java/org/locationtech/proj4j/proj/BipolarProjection.java
+++ b/src/main/java/org/locationtech/proj4j/proj/BipolarProjection.java
@@ -54,7 +54,7 @@ public BipolarProjection() {
minLongitude = Math.toRadians(-90);
maxLongitude = Math.toRadians(90);
}
-
+
public ProjCoordinate project(double lplam, double lpphi, ProjCoordinate out) {
double cphi, sphi, tphi, t, al, Az, z, Av, cdlam, sdlam, r;
boolean tag;
@@ -112,8 +112,8 @@ public ProjCoordinate project(double lplam, double lpphi, ProjCoordinate out) {
out.y += (tag ? -r : r) * Math.cos(t);
if (noskew) {
t = out.x;
- out.x = -out.x * cAzc - out.y * sAzc;
- out.y = -out.y * cAzc + t * sAzc;
+ out.x = -out.x * cAzc - out.y * sAzc;
+ out.y = -out.y * cAzc + t * sAzc;
}
return out;
}
@@ -125,8 +125,8 @@ public ProjCoordinate projectInverse(double xyx, double xyy, ProjCoordinate out)
if (noskew) {
t = xyx;
- out.x = -xyx * cAzc + xyy * sAzc;
- out.y = -xyy * cAzc - t * sAzc;
+ out.x = -xyx * cAzc + xyy * sAzc;
+ out.y = -xyy * cAzc - t * sAzc;
}
if (neg = (xyx < 0.)) {
out.y = rhoc - xyy;
diff --git a/src/main/java/org/locationtech/proj4j/proj/CentralCylindricalProjection.java b/src/main/java/org/locationtech/proj4j/proj/CentralCylindricalProjection.java
index 01e5982..7bcff04 100644
--- a/src/main/java/org/locationtech/proj4j/proj/CentralCylindricalProjection.java
+++ b/src/main/java/org/locationtech/proj4j/proj/CentralCylindricalProjection.java
@@ -25,15 +25,13 @@
public class CentralCylindricalProjection extends CylindricalProjection {
- private double ap;
-
private final static double EPS10 = 1.e-10;
public CentralCylindricalProjection() {
minLatitude = Math.toRadians(-80);
maxLatitude = Math.toRadians(80);
}
-
+
public ProjCoordinate project(double lplam, double lpphi, ProjCoordinate out) {
if (Math.abs(Math.abs(lpphi) - ProjectionMath.HALFPI) <= EPS10) throw new ProjectionException("F");
out.x = lplam;
diff --git a/src/main/java/org/locationtech/proj4j/proj/CylindricalEqualAreaProjection.java b/src/main/java/org/locationtech/proj4j/proj/CylindricalEqualAreaProjection.java
index 5108c63..76b8a96 100644
--- a/src/main/java/org/locationtech/proj4j/proj/CylindricalEqualAreaProjection.java
+++ b/src/main/java/org/locationtech/proj4j/proj/CylindricalEqualAreaProjection.java
@@ -31,14 +31,14 @@ public class CylindricalEqualAreaProjection extends Projection {
public CylindricalEqualAreaProjection() {
this(0.0, 0.0, 0.0);
}
-
+
public CylindricalEqualAreaProjection(double projectionLatitude, double projectionLongitude, double trueScaleLatitude) {
this.projectionLatitude = projectionLatitude;
this.projectionLongitude = projectionLongitude;
this.trueScaleLatitude = trueScaleLatitude;
initialize();
}
-
+
public void initialize() {
super.initialize();
double t = trueScaleLatitude;
@@ -51,7 +51,7 @@ public void initialize() {
qp = ProjectionMath.qsfn(1., e, one_es);
}
}
-
+
public ProjCoordinate project(double lam, double phi, ProjCoordinate xy) {
if (spherical) {
xy.x = scaleFactor * lam;
@@ -90,4 +90,3 @@ public boolean isRectilinear() {
}
}
-
diff --git a/src/main/java/org/locationtech/proj4j/proj/ExtendedTransverseMercatorProjection.java b/src/main/java/org/locationtech/proj4j/proj/ExtendedTransverseMercatorProjection.java
index bc17b2f..2099857 100644
--- a/src/main/java/org/locationtech/proj4j/proj/ExtendedTransverseMercatorProjection.java
+++ b/src/main/java/org/locationtech/proj4j/proj/ExtendedTransverseMercatorProjection.java
@@ -9,19 +9,23 @@
* @see proj_etmerc.c
*/
public class ExtendedTransverseMercatorProjection extends CylindricalProjection {
-
+
private static final long serialVersionUID = 1L;
-
- double Qn; /* Merid. quad., scaled to the projection */
- double Zb; /* Radius vector in polar coord. systems */
- double[] cgb = new double[6]; /* Constants for Gauss -> Geo lat */
- double[] cbg = new double[6]; /* Constants for Geo lat -> Gauss */
- double[] utg = new double[6]; /* Constants for transv. merc. -> geo */
+
+ double Qn; /* Merid. quad., scaled to the projection */
+ double Zb; /* Radius vector in polar coord. systems */
+ double[] cgb = new double[6]; /* Constants for Gauss -> Geo lat */
+ double[] cbg = new double[6]; /* Constants for Geo lat -> Gauss */
+ double[] utg = new double[6]; /* Constants for transv. merc. -> geo */
double[] gtu = new double[6]; /* Constants for geo -> transv. merc. */
+ /**
+ * Indicates whether a Southern Hemisphere UTM zone
+ */
+ protected boolean isSouth = false;
private static final int PROJ_ETMERC_ORDER = 6;
private static final double HUGE_VAL = Double.POSITIVE_INFINITY;
-
+
public ExtendedTransverseMercatorProjection() {
ellipsoid = Ellipsoid.GRS80;
projectionLatitude = Math.toRadians(0);
@@ -30,7 +34,7 @@ public ExtendedTransverseMercatorProjection() {
maxLongitude = Math.toRadians(90);
initialize();
}
-
+
public ExtendedTransverseMercatorProjection(Ellipsoid ellipsoid, double lon_0, double lat_0, double k, double x_0, double y_0) {
setEllipsoid(ellipsoid);
projectionLongitude = lon_0;
@@ -40,7 +44,17 @@ public ExtendedTransverseMercatorProjection(Ellipsoid ellipsoid, double lon_0, d
falseNorthing = y_0;
initialize();
}
-
+
+ @Override
+ public void setSouthernHemisphere(boolean isSouth) {
+ this.isSouth = isSouth;
+ }
+
+ @Override
+ public boolean getSouthernHemisphere() {
+ return isSouth;
+ }
+
static double log1py(double x) { /* Compute log(1+x) accurately */
double y = 1 + x;
double z = y - 1;
@@ -50,26 +64,26 @@ static double log1py(double x) { /* Compute log(1+x) accurately */
* (log(y)/z) introduces little additional error. */
return z == 0 ? x : x * Math.log(y) / z;
}
-
+
static double asinhy(double x) { /* Compute asinh(x) accurately */
double y = Math.abs(x); /* Enforce odd parity */
y = log1py(y * (1 + y/(Math.hypot(1.0, y) + 1)));
return x < 0 ? -y : y;
}
-
+
static double gatg(double[] p1, int len_p1, double B) {
double h = 0, h1, h2 = 0;
double cos_2B = 2*Math.cos(2*B);
-
+
int p1i;
for (p1i = len_p1, h1 = p1[--p1i]; p1i > 0; h2 = h1, h1 = h) {
h = -h2 + cos_2B*h1 + p1[--p1i];
}
-
+
return (B + h*Math.sin(2*B));
}
-
+
static double clenS(double[] a, int size, double arg_r, double arg_i, double[] R, double[] I) {
double hr, hr1, hr2, hi, hi1, hi2;
@@ -115,7 +129,7 @@ static double clens(double[] a, int size, double arg_r) {
}
return Math.sin (arg_r)*hr;
}
-
+
public ProjCoordinate project(double lplam, double lpphi, ProjCoordinate xy) {
double sin_Cn, cos_Cn, cos_Ce, sin_Ce;
double[] dCn = new double[1];
@@ -171,10 +185,10 @@ public ProjCoordinate projectInverse(double x, double y, ProjCoordinate out) {
out.y = gatg (cgb, PROJ_ETMERC_ORDER, Cn);
out.x = Ce;
}
-
+
return out;
}
-
+
public void setUTMZone(int zone) {
zone--;
projectionLongitude = (zone + .5) * Math.PI / 30. - Math.PI;
@@ -184,10 +198,10 @@ public void setUTMZone(int zone) {
falseNorthing = isSouth ? 10000000.0 : 0.0;
initialize();
}
-
+
public void initialize() {
super.initialize();
-
+
double f, n, np, Z;
if (es <= 0) {
@@ -270,15 +284,15 @@ public void initialize() {
/* i.e. true northing = N - P->Zb */
Zb = - Qn*(Z + clens(gtu, PROJ_ETMERC_ORDER, 2*Z));
}
-
+
public boolean hasInverse() {
return true;
}
-
+
public boolean isRectilinear() {
return false;
}
-
+
public Object clone() {
ExtendedTransverseMercatorProjection p = (ExtendedTransverseMercatorProjection) super.clone();
if (cgb != null) {
diff --git a/src/main/java/org/locationtech/proj4j/proj/GeostationarySatelliteProjection.java b/src/main/java/org/locationtech/proj4j/proj/GeostationarySatelliteProjection.java
index f4d6dac..8d8d1ce 100644
--- a/src/main/java/org/locationtech/proj4j/proj/GeostationarySatelliteProjection.java
+++ b/src/main/java/org/locationtech/proj4j/proj/GeostationarySatelliteProjection.java
@@ -14,12 +14,17 @@
*/
public class GeostationarySatelliteProjection extends Projection {
+ /**
+ * Height of orbit - Geostationary satellite projection
+ */
+ protected double heightOfOrbit = 35785831.0;
+
private double _radiusP;
private double _radiusP2;
private double _radiusPInv2;
private double _radiusG;
private double _radiusG1;
- private double _c;
+ private double _c;
/**
* Constructor
@@ -43,6 +48,17 @@ public void initialize() {
}
}
+
+ @Override
+ public double getHeightOfOrbit(){
+ return this.heightOfOrbit;
+ }
+
+ @Override
+ public void setHeightOfOrbit(double h){
+ this.heightOfOrbit = h;
+ }
+
@Override
public ProjCoordinate project(double lplam, double lpphi, ProjCoordinate out) {
if (spherical) {
@@ -187,4 +203,16 @@ public boolean hasInverse() {
public String toString() {
return "Geostationary Satellite";
}
+
+ @Override
+ public boolean equals(Object that) {
+ if (this == that) {
+ return true;
+ }
+ if (that instanceof GeostationarySatelliteProjection) {
+ GeostationarySatelliteProjection p = (GeostationarySatelliteProjection) that;
+ return (this.heightOfOrbit == p.heightOfOrbit) && super.equals(that);
+ }
+ return false;
+ }
}
diff --git a/src/main/java/org/locationtech/proj4j/proj/HammerProjection.java b/src/main/java/org/locationtech/proj4j/proj/HammerProjection.java
index b7e3c09..baa2444 100644
--- a/src/main/java/org/locationtech/proj4j/proj/HammerProjection.java
+++ b/src/main/java/org/locationtech/proj4j/proj/HammerProjection.java
@@ -30,7 +30,7 @@ public class HammerProjection extends PseudoCylindricalProjection {
public HammerProjection() {
}
-
+
public ProjCoordinate project(double lplam, double lpphi, ProjCoordinate xy) {
double cosphi, d;
@@ -66,21 +66,35 @@ public boolean isEqualArea() {
public void setW( double w ) {
this.w = w;
}
-
+
public double getW() {
return w;
}
-
+
public void setM( double m ) {
this.m = m;
}
-
+
public double getM() {
return m;
}
-
+
public String toString() {
return "Hammer & Eckert-Greifendorff";
}
+ @Override
+ public boolean equals(Object that) {
+ if (this == that) {
+ return true;
+ }
+ if (that instanceof HammerProjection) {
+ HammerProjection p = (HammerProjection) that;
+ return (
+ m == p.m &&
+ w == p.w &&
+ super.equals(that));
+ }
+ return false;
+ }
}
diff --git a/src/main/java/org/locationtech/proj4j/proj/LagrangeProjection.java b/src/main/java/org/locationtech/proj4j/proj/LagrangeProjection.java
index fc64dd2..ce91be1 100644
--- a/src/main/java/org/locationtech/proj4j/proj/LagrangeProjection.java
+++ b/src/main/java/org/locationtech/proj4j/proj/LagrangeProjection.java
@@ -53,7 +53,7 @@ public ProjCoordinate project(double lplam, double lpphi, ProjCoordinate xy) {
public void setW( double w ) {
this.rw = w;
}
-
+
public double getW() {
return rw;
}
@@ -75,7 +75,7 @@ public void initialize() {
public boolean isConformal() {
return true;
}
-
+
public boolean hasInverse() {
return false;
}
@@ -84,4 +84,15 @@ public String toString() {
return "Lagrange";
}
+ @Override
+ public boolean equals(Object that) {
+ if (this == that) {
+ return true;
+ }
+ if (that instanceof LagrangeProjection) {
+ LagrangeProjection p = (LagrangeProjection) that;
+ return (rw == p.rw) && super.equals(that);
+ }
+ return false;
+ }
}
diff --git a/src/main/java/org/locationtech/proj4j/proj/MolleweideProjection.java b/src/main/java/org/locationtech/proj4j/proj/MolleweideProjection.java
index 9e9eaf2..a1cd92c 100644
--- a/src/main/java/org/locationtech/proj4j/proj/MolleweideProjection.java
+++ b/src/main/java/org/locationtech/proj4j/proj/MolleweideProjection.java
@@ -36,7 +36,7 @@ public class MolleweideProjection extends PseudoCylindricalProjection {
public MolleweideProjection() {
this(Math.PI/2);
}
-
+
public MolleweideProjection(int type) {
this.type = type;
switch (type) {
@@ -54,11 +54,11 @@ public MolleweideProjection(int type) {
break;
}
}
-
+
public MolleweideProjection(double p) {
init(p);
}
-
+
public void init(double p) {
double r, sp, p2 = p + p;
@@ -96,7 +96,7 @@ public ProjCoordinate project(double lplam, double lpphi, ProjCoordinate xy) {
public ProjCoordinate projectInverse(double x, double y, ProjCoordinate lp) {
double lat, lon;
-
+
lat = Math.asin(y / cy);
lon = x / (cx * Math.cos(lat));
lat += lat;
@@ -105,7 +105,7 @@ public ProjCoordinate projectInverse(double x, double y, ProjCoordinate lp) {
lp.y = lat;
return lp;
}
-
+
public boolean hasInverse() {
return true;
}
@@ -113,7 +113,7 @@ public boolean hasInverse() {
public boolean isEqualArea() {
return true;
}
-
+
public String toString() {
switch (type) {
case WAGNER4:
@@ -123,4 +123,21 @@ public String toString() {
}
return "Molleweide";
}
+
+ @Override
+ public boolean equals(Object that) {
+ if (this == that) {
+ return true;
+ }
+ if (that instanceof MolleweideProjection) {
+ MolleweideProjection p = (MolleweideProjection) that;
+ return (
+ type == p.type &&
+ cx == p.cx &&
+ cy == p.cy &&
+ cp == p.cp &&
+ super.equals(that));
+ }
+ return false;
+ }
}
diff --git a/src/main/java/org/locationtech/proj4j/proj/ObliqueMercatorProjection.java b/src/main/java/org/locationtech/proj4j/proj/ObliqueMercatorProjection.java
index aab85c5..ae94fa3 100644
--- a/src/main/java/org/locationtech/proj4j/proj/ObliqueMercatorProjection.java
+++ b/src/main/java/org/locationtech/proj4j/proj/ObliqueMercatorProjection.java
@@ -45,7 +45,7 @@ public ObliqueMercatorProjection() {
alpha = Math.toRadians(-45);//FIXME
initialize();
}
-
+
/**
* Set up a projection suitable for State Plane Coordinates.
*/
@@ -59,7 +59,7 @@ public ObliqueMercatorProjection(Ellipsoid ellipsoid, double lon_0, double lat_0
falseNorthing = y_0;
initialize();
}
-
+
public void initialize() {
super.initialize();
double con, com, cosphi0, d, f, h, l, sinphi0, p, j;
@@ -67,7 +67,7 @@ public void initialize() {
//FIXME-setup rot, alpha, longc,lon/lat1/2
rot = true;
lamc = lonc;
-
+
// true if alpha provided
int azi = Double.isNaN(alpha) ? 0 : 1;
if (azi != 0) { // alpha specified
@@ -228,4 +228,19 @@ public String toString() {
return "Oblique Mercator";
}
+ @Override
+ public boolean equals(Object that) {
+ if (this == that) {
+ return true;
+ }
+ if (that instanceof ObliqueMercatorProjection) {
+ ObliqueMercatorProjection p = (ObliqueMercatorProjection) that;
+ return (
+ Gamma == p.Gamma &&
+ alpha == p.alpha &&
+ lonc == p.lonc &&
+ super.equals(that));
+ }
+ return false;
+ }
}
diff --git a/src/main/java/org/locationtech/proj4j/proj/Projection.java b/src/main/java/org/locationtech/proj4j/proj/Projection.java
index 5e820fd..22bbbb9 100644
--- a/src/main/java/org/locationtech/proj4j/proj/Projection.java
+++ b/src/main/java/org/locationtech/proj4j/proj/Projection.java
@@ -16,6 +16,8 @@
package org.locationtech.proj4j.proj;
+import java.util.NoSuchElementException;
+
import org.locationtech.proj4j.*;
import org.locationtech.proj4j.datum.AxisOrder;
import org.locationtech.proj4j.datum.Ellipsoid;
@@ -102,10 +104,6 @@ public abstract class Projection implements Cloneable, java.io.Serializable {
*/
protected double falseNorthing = 0;
- /**
- * Indicates whether a Southern Hemisphere UTM zone
- */
- protected boolean isSouth = false;
/**
* The latitude of true scale. Only used by specific projections.
*/
@@ -191,11 +189,6 @@ public abstract class Projection implements Cloneable, java.io.Serializable {
* northing, vertical (up)
*/
private AxisOrder axes = AxisOrder.ENU;
-
- /**
- * Height of orbit - Geostationary satellite projection
- */
- protected double heightOfOrbit = 35785831.0;
// Some useful constants
protected final static double EPS10 = 1e-10;
@@ -701,12 +694,13 @@ public double getFalseEasting() {
return falseEasting;
}
- public void setSouthernHemisphere(boolean isSouth)
- {
- this.isSouth = isSouth;
+ public void setSouthernHemisphere(boolean isSouth) {
+ throw new NoSuchElementException();
}
- public boolean getSouthernHemisphere() { return isSouth; }
+ public boolean getSouthernHemisphere() {
+ throw new NoSuchElementException();
+ }
/**
* Set the projection scale factor. This is set to 1 by default.
@@ -767,21 +761,21 @@ public void setUnits(Unit unit)
public Unit getUnits() {
return this.unit != null ? this.unit : Units.METRES;
}
-
+
/**
* Get height of orbit - Geostationary satellite projection
* @return Height of orbit
*/
public double getHeightOfOrbit(){
- return this.heightOfOrbit;
+ throw new NoSuchElementException();
}
-
+
/**
* Set height of orbit - Geostationary satellite projection
* @param h Height of orbit
*/
public void setHeightOfOrbit(double h){
- this.heightOfOrbit = h;
+ throw new NoSuchElementException();
}
/**
@@ -825,4 +819,36 @@ public void setGamma(double gamma) {
public Boolean isGeographic() {
return false;
}
+
+ @Override
+ public boolean equals(Object that) {
+ if (this == that) {
+ return true;
+ }
+ if (that instanceof Projection) {
+ Projection p = (Projection) that;
+ // Using Double.compare when values can be NaN and should still be equal
+ return (
+ // class represents implementation of project method
+ this.getClass().equals(that.getClass()) &&
+ ellipsoid.isEqual(p.ellipsoid) &&
+ falseNorthing == p.falseNorthing &&
+ falseEasting == p.falseEasting &&
+ scaleFactor == p.scaleFactor &&
+ fromMetres == p.fromMetres &&
+ trueScaleLatitude == p.trueScaleLatitude &&
+ projectionLatitude == p.projectionLatitude &&
+ projectionLongitude == p.projectionLongitude &&
+ projectionLatitude1 == p.projectionLatitude1 &&
+ projectionLatitude2 == p.projectionLatitude2 &&
+ minLatitude == p.minLatitude &&
+ maxLatitude == p.maxLatitude &&
+ minLongitude == p.minLongitude &&
+ maxLongitude == p.maxLongitude &&
+ axes.equals(p.axes) &&
+ unit.equals(p.unit) &&
+ primeMeridian.equals(p.primeMeridian));
+ }
+ return false;
+ }
}
diff --git a/src/main/java/org/locationtech/proj4j/proj/SimpleConicProjection.java b/src/main/java/org/locationtech/proj4j/proj/SimpleConicProjection.java
index 4a8dbe7..0b0d4dc 100644
--- a/src/main/java/org/locationtech/proj4j/proj/SimpleConicProjection.java
+++ b/src/main/java/org/locationtech/proj4j/proj/SimpleConicProjection.java
@@ -44,13 +44,13 @@ public class SimpleConicProjection extends ConicProjection {
public SimpleConicProjection() {
this( EULER );
}
-
+
public SimpleConicProjection(int type) {
this.type = type;
minLatitude = Math.toRadians(0);
maxLatitude = Math.toRadians(80);
}
-
+
public String toString() {
return "Simple Conic";
}
@@ -157,7 +157,7 @@ public void initialize() {
case EULER:
n = Math.sin(sig) * Math.sin(del) / del;
del *= 0.5;
- rho_c = del / (Math.tan(del) * Math.tan(sig)) + sig;
+ rho_c = del / (Math.tan(del) * Math.tan(sig)) + sig;
rho_0 = rho_c - projectionLatitude;
break;
case PCONIC:
@@ -176,4 +176,16 @@ public void initialize() {
break;
}
}
+
+ @Override
+ public boolean equals(Object that) {
+ if (this == that) {
+ return true;
+ }
+ if (that instanceof SimpleConicProjection) {
+ SimpleConicProjection p = (SimpleConicProjection) that;
+ return (this.type == p.type) && super.equals(that);
+ }
+ return false;
+ }
}
diff --git a/src/main/java/org/locationtech/proj4j/proj/SineTangentSeriesProjection.java b/src/main/java/org/locationtech/proj4j/proj/SineTangentSeriesProjection.java
index ef9b672..7294854 100644
--- a/src/main/java/org/locationtech/proj4j/proj/SineTangentSeriesProjection.java
+++ b/src/main/java/org/locationtech/proj4j/proj/SineTangentSeriesProjection.java
@@ -36,7 +36,7 @@ protected SineTangentSeriesProjection( double p, double q, boolean mode ) {
tan_mode = mode;
initialize();
}
-
+
public ProjCoordinate project(double lplam, double lpphi, ProjCoordinate xy) {
double c;
@@ -56,7 +56,7 @@ public ProjCoordinate project(double lplam, double lpphi, ProjCoordinate xy) {
public ProjCoordinate projectInverse(double xyx, double xyy, ProjCoordinate lp) {
double c;
-
+
xyy /= C_y;
c = Math.cos(lp.y = tan_mode ? Math.atan(xyy) : ProjectionMath.asin(xyy));
lp.y /= C_p;
@@ -72,4 +72,20 @@ public boolean hasInverse() {
return true;
}
+ @Override
+ public boolean equals(Object that) {
+ if (this == that) {
+ return true;
+ }
+ if (that instanceof SineTangentSeriesProjection) {
+ SineTangentSeriesProjection p = (SineTangentSeriesProjection) that;
+ return (
+ C_x == p.C_x &&
+ C_y == p.C_y &&
+ C_p == p.C_p &&
+ tan_mode == p.tan_mode &&
+ super.equals(that));
+ }
+ return false;
+ }
}
diff --git a/src/main/java/org/locationtech/proj4j/proj/StereographicAzimuthalProjection.java b/src/main/java/org/locationtech/proj4j/proj/StereographicAzimuthalProjection.java
index 78e01d3..2837a5d 100644
--- a/src/main/java/org/locationtech/proj4j/proj/StereographicAzimuthalProjection.java
+++ b/src/main/java/org/locationtech/proj4j/proj/StereographicAzimuthalProjection.java
@@ -25,9 +25,9 @@
public class StereographicAzimuthalProjection extends AzimuthalProjection {
private final static double TOL = 1.e-8;
-
+
private double akm1;
-
+
public StereographicAzimuthalProjection() {
this(Math.toRadians(90.0), Math.toRadians(0.0));
}
@@ -36,7 +36,7 @@ public StereographicAzimuthalProjection(double projectionLatitude, double projec
super(projectionLatitude, projectionLongitude);
initialize();
}
-
+
public void setupUPS(int pole) {
projectionLatitude = (pole == SOUTH_POLE) ? -ProjectionMath.HALFPI: ProjectionMath.HALFPI;
projectionLongitude = 0.0;
@@ -46,7 +46,7 @@ public void setupUPS(int pole) {
trueScaleLatitude = ProjectionMath.HALFPI;
initialize();
}
-
+
public void initialize() {
double t;
@@ -245,14 +245,14 @@ public ProjCoordinate projectInverse(double x, double y, ProjCoordinate lp) {
}
return lp;
}
-
+
/**
* Returns true if this projection is conformal
*/
public boolean isConformal() {
return true;
}
-
+
public boolean hasInverse() {
return true;
}
@@ -266,6 +266,4 @@ private double ssfn(double phit, double sinphi, double eccen) {
public String toString() {
return "Stereographic Azimuthal";
}
-
-}
-
+}
\ No newline at end of file
diff --git a/src/main/java/org/locationtech/proj4j/proj/TransverseMercatorProjection.java b/src/main/java/org/locationtech/proj4j/proj/TransverseMercatorProjection.java
index fdb56d4..44a3d0b 100644
--- a/src/main/java/org/locationtech/proj4j/proj/TransverseMercatorProjection.java
+++ b/src/main/java/org/locationtech/proj4j/proj/TransverseMercatorProjection.java
@@ -27,7 +27,7 @@
* Transverse Mercator Projection algorithm is taken from the USGS PROJ package.
*/
public class TransverseMercatorProjection extends CylindricalProjection {
-
+
private final static double FC1 = 1.0;
private final static double FC2 = 0.5;
private final static double FC3 = 0.16666666666666666666;
@@ -37,6 +37,10 @@ public class TransverseMercatorProjection extends CylindricalProjection {
private final static double FC7 = 0.02380952380952380952;
private final static double FC8 = 0.01785714285714285714;
+ /**
+ * Indicates whether a Southern Hemisphere UTM zone
+ */
+ protected boolean isSouth = false;
private int utmZone = -1;
private double esp;
private double ml0;
@@ -50,7 +54,7 @@ public TransverseMercatorProjection() {
maxLongitude = Math.toRadians(90);
initialize();
}
-
+
/**
* Set up a projection suitable for State Plane Coordinates.
*/
@@ -63,14 +67,24 @@ public TransverseMercatorProjection(Ellipsoid ellipsoid, double lon_0, double la
falseNorthing = y_0;
initialize();
}
-
+
+ @Override
+ public void setSouthernHemisphere(boolean isSouth) {
+ this.isSouth = isSouth;
+ }
+
+ @Override
+ public boolean getSouthernHemisphere() {
+ return isSouth;
+ }
+
public Object clone() {
TransverseMercatorProjection p = (TransverseMercatorProjection)super.clone();
if (en != null)
p.en = (double[])en.clone();
return p;
}
-
+
public boolean isRectilinear() {
return false;
}
@@ -95,7 +109,7 @@ public static int getRowFromNearestParallel(double latitude) {
return 24;
return (degrees + 80) / 8 + 3;
}
-
+
public static int getZoneFromNearestMeridian(double longitude) {
int zone = (int)Math.floor((ProjectionMath.normalizeLongitude(longitude) + Math.PI) * 30.0 / Math.PI) + 1;
if (zone < 1)
@@ -104,7 +118,7 @@ else if (zone > 60)
zone = 60;
return zone;
}
-
+
public void setUTMZone(int zone) {
utmZone = zone;
zone--;
diff --git a/src/main/java/org/locationtech/proj4j/proj/UrmaevFlatPolarSinusoidalProjection.java b/src/main/java/org/locationtech/proj4j/proj/UrmaevFlatPolarSinusoidalProjection.java
index 9e2047e..5dede37 100644
--- a/src/main/java/org/locationtech/proj4j/proj/UrmaevFlatPolarSinusoidalProjection.java
+++ b/src/main/java/org/locationtech/proj4j/proj/UrmaevFlatPolarSinusoidalProjection.java
@@ -33,7 +33,7 @@ public class UrmaevFlatPolarSinusoidalProjection extends Projection {
public UrmaevFlatPolarSinusoidalProjection() {
}
-
+
public ProjCoordinate project(double lplam, double lpphi, ProjCoordinate out) {
out.y = ProjectionMath.asin(n * Math.sin(lpphi));
out.x = C_x * lplam * Math.cos(lpphi);
@@ -63,13 +63,24 @@ public void initialize() { // urmfps
public void setN( double n ) {
this.n = n;
}
-
+
public double getN() {
return n;
}
-
+
public String toString() {
return "Urmaev Flat-Polar Sinusoidal";
}
+ @Override
+ public boolean equals(Object that) {
+ if (this == that) {
+ return true;
+ }
+ if (that instanceof UrmaevFlatPolarSinusoidalProjection) {
+ UrmaevFlatPolarSinusoidalProjection p = (UrmaevFlatPolarSinusoidalProjection) that;
+ return (n == p.n) && super.equals(that);
+ }
+ return false;
+ }
}
diff --git a/src/test/java/org/locationtech/proj4j/proj/ProjectionEqualityTest.java b/src/test/java/org/locationtech/proj4j/proj/ProjectionEqualityTest.java
new file mode 100644
index 0000000..9860373
--- /dev/null
+++ b/src/test/java/org/locationtech/proj4j/proj/ProjectionEqualityTest.java
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * Copyright 2019 Azavea
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *******************************************************************************/
+package org.locationtech.proj4j.proj;
+
+import org.locationtech.proj4j.CRSFactory;
+import org.locationtech.proj4j.CoordinateReferenceSystem;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+
+import org.junit.Test;
+
+/**
+ * Tests that Projection equality is semantically correct
+ */
+public class ProjectionEqualityTest
+{
+ private static CRSFactory csFactory = new CRSFactory();
+
+ @Test
+ public void utmEquality() {
+
+ CoordinateReferenceSystem cs1 = csFactory.createFromName("EPSG:26710");
+ CoordinateReferenceSystem cs2 = csFactory.createFromParameters(null, "+proj=utm +zone=10 +datum=NAD27 +units=m +no_defs");
+ assertEquals(cs1, cs2);
+
+ CoordinateReferenceSystem cs3 = csFactory.createFromName("EPSG:26711");
+ assertNotEquals(cs1, cs3);
+ }
+}
diff --git a/src/test/java/org/locationtech/proj4j/proj/ProjectionGridRoundTripper.java b/src/test/java/org/locationtech/proj4j/proj/ProjectionGridRoundTripper.java
index faaa96b..773799c 100644
--- a/src/test/java/org/locationtech/proj4j/proj/ProjectionGridRoundTripper.java
+++ b/src/test/java/org/locationtech/proj4j/proj/ProjectionGridRoundTripper.java
@@ -23,7 +23,7 @@
import org.locationtech.proj4j.proj.Projection;
import org.locationtech.proj4j.util.ProjectionUtil;
-public class ProjectionGridRoundTripper
+public class ProjectionGridRoundTripper
{
private static final CoordinateTransformFactory ctFactory = new CoordinateTransformFactory();
CRSFactory csFactory = new CRSFactory();
@@ -38,38 +38,36 @@ public class ProjectionGridRoundTripper
private boolean debug = false;
private int transformCount = 0;
private double[] gridExtent;
-
+
public ProjectionGridRoundTripper(CoordinateReferenceSystem cs)
{
this.cs = cs;
- transInverse = ctFactory.createTransform(cs, WGS84);
- transForward = ctFactory.createTransform(WGS84, cs);
+ transInverse = ctFactory.createTransform(cs, WGS84);
+ transForward = ctFactory.createTransform(WGS84, cs);
}
-
+
public void setLevelDebug(boolean debug)
{
this.debug = debug;
}
-
+
public int getTransformCount()
{
return transformCount;
}
-
+
public double[] getExtent()
{
return gridExtent;
}
public boolean runGrid(double tolerance)
{
- boolean isWithinTolerance = true;
-
gridExtent = gridExtent(cs.getProjection());
double minx = gridExtent[0];
double miny = gridExtent[1];
double maxx = gridExtent[2];
double maxy = gridExtent[3];
-
+
ProjCoordinate p = new ProjCoordinate();
double dx = (maxx - minx) / gridSize;
double dy = (maxy - miny) / gridSize;
@@ -82,7 +80,7 @@ public boolean runGrid(double tolerance)
p.y = iy == gridSize ?
maxy
: miny + iy * dy;
-
+
boolean isWithinTol = roundTrip(p, tolerance);
if (! isWithinTol)
return false;
@@ -90,50 +88,50 @@ public boolean runGrid(double tolerance)
}
return true;
}
-
+
ProjCoordinate p2 = new ProjCoordinate();
ProjCoordinate p3 = new ProjCoordinate();
private boolean roundTrip(ProjCoordinate p, double tolerance)
{
transformCount++;
-
+
transForward.transform(p, p2);
transInverse.transform(p2, p3);
-
- if (debug)
+
+ if (debug)
System.out.println(ProjectionUtil.toString(p) + " -> " + ProjectionUtil.toString(p2) + " -> " + ProjectionUtil.toString(p3));
-
+
double dx = Math.abs(p3.x - p.x);
double dy = Math.abs(p3.y - p.y);
-
+
boolean isInTol = dx <= tolerance && dy <= tolerance;
-
- if (! isInTol)
+
+ if (! isInTol)
System.out.println("FAIL: " + ProjectionUtil.toString(p) + " -> " + ProjectionUtil.toString(p2) + " -> " + ProjectionUtil.toString(p3));
-
+
return isInTol;
}
-
+
public static double[] gridExtent(Projection proj)
{
// scan all lat/lon params to try and determine a reasonable extent
-
+
double lon = proj.getProjectionLongitudeDegrees();
-
+
double[] latExtent = new double[] {Double.MAX_VALUE, Double.MIN_VALUE };
updateLat(proj.getProjectionLatitudeDegrees(), latExtent);
updateLat(proj.getProjectionLatitude1Degrees(), latExtent);
updateLat(proj.getProjectionLatitude2Degrees(), latExtent);
-
+
double centrex = lon;
double centrey = 0.0;
double gridWidth = 10;
-
+
if (latExtent[0] < Double.MAX_VALUE && latExtent[1] > Double.MIN_VALUE) {
// got a good candidate
-
+
double dlat = latExtent[1] - latExtent[0];
if (dlat > 0) gridWidth = 2 * dlat;
centrey = (latExtent[1] + latExtent[0]) /2;
@@ -145,7 +143,7 @@ public static double[] gridExtent(Projection proj)
extent[3] = centrey + gridWidth/2;
return extent;
}
-
+
private static void updateLat(double lat, double[] latExtent)
{
// 0.0 indicates not set (for most projections?)