Skip to content

Commit

Permalink
Merge WGS84 / web Mercator conversion functions
Browse files Browse the repository at this point in the history
These existed in two places: on Grid and WebMercatorGridPointSet.
I retained the more general version that takes a zoom parameter.
Math functions were all switched to Java built-in standard Math.

We used both FastMath and Java standard Math. FastMath existed because
standard Math used to be strict, but Java now has separate StrictMath
and standard Math is optimized. This still deserves to be profiled.

Also removed IsochroneFeature which is unused, but called some removed
functions. IsochroneFeature was ported to JS as Jsolines, and sees
destination travel times as being located at the top left corner of
Mercator pixels. Removing it eliminates a source of confusion if someone
sees unused code using pixel corners.
  • Loading branch information
abyrd committed Oct 19, 2023
1 parent 84abd10 commit 2d64566
Show file tree
Hide file tree
Showing 5 changed files with 51 additions and 486 deletions.
41 changes: 23 additions & 18 deletions src/main/java/com/conveyal/r5/analyst/Grid.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import com.csvreader.CsvReader;
import com.google.common.io.LittleEndianDataInputStream;
import com.google.common.io.LittleEndianDataOutputStream;
import org.apache.commons.math3.util.FastMath;
import org.geotools.coverage.grid.GridCoverage2D;
import org.geotools.coverage.grid.GridCoverageFactory;
import org.geotools.coverage.grid.io.AbstractGridFormat;
Expand Down Expand Up @@ -64,15 +63,17 @@

import static com.conveyal.gtfs.util.Util.human;
import static com.conveyal.r5.common.GeometryUtils.checkWgsEnvelopeSize;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkState;
import static java.lang.Double.parseDouble;
import static org.apache.commons.math3.util.FastMath.atan;
import static org.apache.commons.math3.util.FastMath.cos;
import static org.apache.commons.math3.util.FastMath.log;
import static org.apache.commons.math3.util.FastMath.sinh;
import static org.apache.commons.math3.util.FastMath.tan;
import static org.apache.commons.math3.util.FastMath.toRadians;
import static java.lang.Math.PI;
import static java.lang.Math.atan;
import static java.lang.Math.cos;
import static java.lang.Math.log;
import static java.lang.Math.pow;
import static java.lang.Math.sinh;
import static java.lang.Math.tan;
import static java.lang.Math.toDegrees;
import static java.lang.Math.toRadians;

/**
* Class that represents a grid of opportunity counts in the spherical Mercator "projection" at a given zoom level.
Expand Down Expand Up @@ -482,7 +483,7 @@ public static int lonToPixel (double lon, int zoom) {
* Naming should somehow be revised to clarify that it doesn't return the center of the pixel.
*/
public static double pixelToLon (double xPixel, int zoom) {
return xPixel / (Math.pow(2, zoom) * 256) * 360 - 180;
return xPixel / (pow(2, zoom) * 256) * 360 - 180;
}

/**
Expand All @@ -505,20 +506,24 @@ public static int latToPixel (double lat, int zoom) {
}

/**
* Return the latitude of the center of all pixels at the given zoom level and absolute (world) y pixel number
* measured southward from the north edge of the world.
* Given an integer web Mercator pixel number, return the latitude in degrees of the north edge of that pixel at the
* given zoom level relative to the top (north) edge of the world (not relative to this grid or to any particular
* tile). Given a non-integer web Mercator pixel number, return WGS84 locations within that pixel.
*
* TODO Profile this some time because we had versions using both FastMath and built-in Math functions.
* The difference should be less significant these days. Java now has a StrictMath and the normal Math is optimized.
*/
public static double pixelToCenterLat (int yPixel, int zoom) {
return pixelToLat(yPixel + 0.5, zoom);
public static double pixelToLat (double yPixel, int zoom) {
final double tile = yPixel / 256d;
return toDegrees(atan(sinh(PI - tile * PI * 2 / pow(2, zoom))));
}

/**
* Return the latitude of the north edge of any pixel at the given zoom level and y coordinate relative to the top
* edge of the world (assuming an integer pixel). Noninteger pixels will return locations within the pixel.
* We're using FastMath here, because the built-in math functions were taking a large amount of time in profiling.
* Return the latitude of the center of all pixels at the given zoom level and absolute (world) y pixel number
* measured southward from the north edge of the world.
*/
public static double pixelToLat (double yPixel, int zoom) {
return FastMath.toDegrees(atan(sinh(Math.PI - (yPixel / 256d) / Math.pow(2, zoom) * 2 * Math.PI)));
public static double pixelToCenterLat (int yPixel, int zoom) {
return pixelToLat(yPixel + 0.5, zoom);
}

/**
Expand Down
Loading

0 comments on commit 2d64566

Please sign in to comment.