Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make BasicCoordinateTransform thread-safe #29

Merged
merged 1 commit into from
Jun 25, 2019
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 26 additions & 36 deletions src/main/java/org/locationtech/proj4j/BasicCoordinateTransform.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@
*/
package org.locationtech.proj4j;

import java.util.Arrays;

import org.locationtech.proj4j.datum.*;

/**
Expand All @@ -41,9 +39,6 @@
* <pre>
* [ SrcProjCRS {InverseProjection} ] SrcGeoCRS [ {Datum Conversion} ] TgtGeoCRS [ {Projection} TgtProjCRS ]
* </pre>
* <tt>BasicCoordinateTransform</tt> objects are stateful,
* and thus are not thread-safe.
* However, they may be reused any number of times within a single thread.
* <p>
* Information about the transformation procedure is pre-computed
* and cached in this object for efficient computation.
Expand All @@ -53,17 +48,14 @@
*/
public class BasicCoordinateTransform implements CoordinateTransform {

private CoordinateReferenceSystem srcCRS;
private CoordinateReferenceSystem tgtCRS;

// temporary variable for intermediate results
private ProjCoordinate geoCoord = new ProjCoordinate(0, 0);
private final CoordinateReferenceSystem srcCRS;
private final CoordinateReferenceSystem tgtCRS;

// precomputed information
private boolean doInverseProjection = true;
private boolean doForwardProjection = true;
private boolean doDatumTransform = false;
private boolean transformViaGeocentric = false;
private final boolean doInverseProjection;
private final boolean doForwardProjection;
private final boolean doDatumTransform;
private final boolean transformViaGeocentric;
private GeocentricConverter srcGeoConv;
private GeocentricConverter tgtGeoConv;

Expand All @@ -82,19 +74,16 @@ public BasicCoordinateTransform(CoordinateReferenceSystem srcCRS,
// compute strategy for transformation at initialization time, to make transformation more efficient
// this may include precomputing sets of parameters

doInverseProjection = (srcCRS != null && srcCRS != CoordinateReferenceSystem.CS_GEO);
doForwardProjection = (tgtCRS != null && tgtCRS != CoordinateReferenceSystem.CS_GEO);
doInverseProjection = (srcCRS != CoordinateReferenceSystem.CS_GEO);
doForwardProjection = (tgtCRS != CoordinateReferenceSystem.CS_GEO);
doDatumTransform = doInverseProjection && doForwardProjection
&& srcCRS.getDatum() != tgtCRS.getDatum();

if (doDatumTransform) {

boolean isEllipsoidEqual = srcCRS.getDatum().getEllipsoid().isEqual(tgtCRS.getDatum().getEllipsoid());
if (!isEllipsoidEqual)
transformViaGeocentric = true;
if (srcCRS.getDatum().hasTransformToWGS84()
|| tgtCRS.getDatum().hasTransformToWGS84())
transformViaGeocentric = true;
transformViaGeocentric = ! isEllipsoidEqual || srcCRS.getDatum().hasTransformToWGS84()
|| tgtCRS.getDatum().hasTransformToWGS84();

if (transformViaGeocentric) {
srcGeoConv = new GeocentricConverter(srcCRS.getDatum().getEllipsoid());
Expand All @@ -109,14 +98,18 @@ public BasicCoordinateTransform(CoordinateReferenceSystem srcCRS,
}
}

} else {
transformViaGeocentric=false;
}
}

public CoordinateReferenceSystem getSourceCRS() {
@Override
public CoordinateReferenceSystem getSourceCRS() {
return srcCRS;
}

public CoordinateReferenceSystem getTargetCRS() {
@Override
public CoordinateReferenceSystem getTargetCRS() {
return tgtCRS;
}

Expand All @@ -131,35 +124,32 @@ public CoordinateReferenceSystem getTargetCRS() {
* @throws Proj4jException if a computation error is encountered
*/
// transform corresponds to the pj_transform function in proj.4
public ProjCoordinate transform(ProjCoordinate src, ProjCoordinate tgt)
@Override
public ProjCoordinate transform(ProjCoordinate src, ProjCoordinate tgt)
throws Proj4jException {
geoCoord.setValue(src);
srcCRS.getProjection().getAxisOrder().toENU(geoCoord);
tgt.setValue(src);
srcCRS.getProjection().getAxisOrder().toENU(tgt);

// NOTE: this method may be called many times, so needs to be as efficient as possible
if (doInverseProjection) {
// inverse project to geographic
ProjCoordinate coord = new ProjCoordinate();
coord.setValue(geoCoord);
srcCRS.getProjection().inverseProjectRadians(coord, geoCoord);
srcCRS.getProjection().inverseProjectRadians(tgt, tgt);
}

srcCRS.getProjection().getPrimeMeridian().toGreenwich(geoCoord);
srcCRS.getProjection().getPrimeMeridian().toGreenwich(tgt);

// fixes bug where computed Z value sticks around
geoCoord.clearZ();
tgt.clearZ();

if (doDatumTransform) {
datumTransform(geoCoord);
datumTransform(tgt);
}

tgtCRS.getProjection().getPrimeMeridian().fromGreenwich(geoCoord);
tgtCRS.getProjection().getPrimeMeridian().fromGreenwich(tgt);

if (doForwardProjection) {
// project from geographic to planar
tgtCRS.getProjection().projectRadians(geoCoord, tgt);
} else {
tgt.setValue(geoCoord);
tgtCRS.getProjection().projectRadians(tgt, tgt);
}

tgtCRS.getProjection().getAxisOrder().fromENU(tgt);
Expand Down