Skip to content

Commit

Permalink
Add logical Projection equality
Browse files Browse the repository at this point in the history
Without this CoordinateReferenceSystem is very fragile, sensative to name and formatting and order of projection parameters array.
  • Loading branch information
echeipesh committed Aug 24, 2019
1 parent 8ab4b31 commit d81a006
Show file tree
Hide file tree
Showing 23 changed files with 378 additions and 137 deletions.
17 changes: 9 additions & 8 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/org/locationtech/proj4j/datum/AxisOrder.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
16 changes: 13 additions & 3 deletions src/main/java/org/locationtech/proj4j/proj/AitoffProjection.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@


public class AitoffProjection extends PseudoCylindricalProjection {

protected final static int AITOFF = 0;
protected final static int WINKEL = 1;

Expand Down Expand Up @@ -65,7 +65,7 @@ public void initialize() {
cosphi1 = 0.636619772367581343;
}
}

public boolean hasInverse() {
return false;
}
Expand All @@ -74,5 +74,15 @@ public String toString() {
return winkel ? "Winkel Tripel" : "Aitoff";
}

@Override
public boolean equals(Object that) {

This comment has been minimized.

Copy link
@Neutius

Neutius Aug 25, 2019

Contributor

It appears you have overridden the equals method without overriding the hashCode method, here and in ten other places. I'm pretty sure that's considered bad practice.

Edit: I'll make it into a separate issue.

if (this == that) {
return true;
}
if (that instanceof AitoffProjection) {
AitoffProjection p = (AitoffProjection) that;
return (winkel == p.winkel && super.equals(that));
}
return false;
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -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) );
}
Expand All @@ -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)
Expand Down Expand Up @@ -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;
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}
Expand All @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -90,4 +90,3 @@ public boolean isRectilinear() {
}

}

Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,23 @@
* @see <a href="https://github.com/OSGeo/proj.4/blob/master/src/proj_etmerc.c">proj_etmerc.c</a>
*/
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);
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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;

Expand Down Expand Up @@ -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];
Expand Down Expand Up @@ -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;
Expand All @@ -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) {
Expand Down Expand Up @@ -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) {
Expand Down
Loading

0 comments on commit d81a006

Please sign in to comment.