com.mapbox.turf.TurfMeasurement Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of mapbox-sdk-turf Show documentation
Show all versions of mapbox-sdk-turf Show documentation
Mapbox Services SDK (Turf support)
package com.mapbox.turf;
import static com.mapbox.turf.TurfConversion.degreesToRadians;
import static com.mapbox.turf.TurfConversion.radiansToDegrees;
import android.support.annotation.FloatRange;
import android.support.annotation.NonNull;
import com.mapbox.geojson.Geometry;
import com.mapbox.geojson.GeometryCollection;
import com.mapbox.geojson.LineString;
import com.mapbox.geojson.MultiLineString;
import com.mapbox.geojson.MultiPoint;
import com.mapbox.geojson.Point;
import com.mapbox.geojson.Polygon;
import com.mapbox.geojson.MultiPolygon;
import java.util.ArrayList;
import java.util.List;
/**
* Class contains an assortment of methods used to calculate measurements such as bearing,
* destination, midpoint, etc.
*
* @see Turf documentation
* @since 1.2.0
*/
public final class TurfMeasurement {
private TurfMeasurement() {
throw new AssertionError("No Instances.");
}
/**
* Takes two {@link Point}s and finds the geographic bearing between them.
*
* @param point1 first point used for calculating the bearing
* @param point2 second point used for calculating the bearing
* @return bearing in decimal degrees
* @see Turf Bearing documentation
* @since 1.3.0
*/
public static double bearing(@NonNull Point point1, @NonNull Point point2) {
double lon1 = degreesToRadians(point1.longitude());
double lon2 = degreesToRadians(point2.longitude());
double lat1 = degreesToRadians(point1.latitude());
double lat2 = degreesToRadians(point2.latitude());
double value1 = Math.sin(lon2 - lon1) * Math.cos(lat2);
double value2 = Math.cos(lat1) * Math.sin(lat2) - Math.sin(lat1)
* Math.cos(lat2) * Math.cos(lon2 - lon1);
return radiansToDegrees(Math.atan2(value1, value2));
}
/**
* Takes a Point and calculates the location of a destination point given a distance in
* degrees, radians, miles, or kilometers; and bearing in degrees. This uses the Haversine
* formula to account for global curvature.
*
* @param point starting point used for calculating the destination
* @param distance distance from the starting point
* @param bearing ranging from -180 to 180 in decimal degrees
* @param units one of the units found inside {@link TurfConstants.TurfUnitCriteria}
* @return destination {@link Point} result where you specified
* @see Turf Destination documetation
* @since 1.2.0
*/
@NonNull
public static Point destination(@NonNull Point point, @FloatRange(from = 0) double distance,
@FloatRange(from = -180, to = 180) double bearing,
@NonNull @TurfConstants.TurfUnitCriteria String units) {
double longitude1 = degreesToRadians(point.longitude());
double latitude1 = degreesToRadians(point.latitude());
double bearingRad = degreesToRadians(bearing);
double radians = TurfConversion.lengthToRadians(distance, units);
double latitude2 = Math.asin(Math.sin(latitude1) * Math.cos(radians)
+ Math.cos(latitude1) * Math.sin(radians) * Math.cos(bearingRad));
double longitude2 = longitude1 + Math.atan2(Math.sin(bearingRad)
* Math.sin(radians) * Math.cos(latitude1),
Math.cos(radians) - Math.sin(latitude1) * Math.sin(latitude2));
return Point.fromLngLat(
radiansToDegrees(longitude2), radiansToDegrees(latitude2));
}
/**
* Calculates the distance between two points in kilometers. This uses the Haversine formula to
* account for global curvature.
*
* @param point1 first point used for calculating the bearing
* @param point2 second point used for calculating the bearing
* @return distance between the two points in kilometers
* @see Turf distance documentation
* @since 1.2.0
*/
public static double distance(@NonNull Point point1, @NonNull Point point2) {
return distance(point1, point2, TurfConstants.UNIT_DEFAULT);
}
/**
* Calculates the distance between two points in degress, radians, miles, or kilometers. This
* uses the Haversine formula to account for global curvature.
*
* @param point1 first point used for calculating the bearing
* @param point2 second point used for calculating the bearing
* @param units one of the units found inside {@link TurfConstants.TurfUnitCriteria}
* @return distance between the two points in kilometers
* @see Turf distance documentation
* @since 1.2.0
*/
public static double distance(@NonNull Point point1, @NonNull Point point2,
@NonNull @TurfConstants.TurfUnitCriteria String units) {
double difLat = degreesToRadians((point2.latitude() - point1.latitude()));
double difLon = degreesToRadians((point2.longitude() - point1.longitude()));
double lat1 = degreesToRadians(point1.latitude());
double lat2 = degreesToRadians(point2.latitude());
double value = Math.pow(Math.sin(difLat / 2), 2)
+ Math.pow(Math.sin(difLon / 2), 2) * Math.cos(lat1) * Math.cos(lat2);
return TurfConversion.radiansToLength(
2 * Math.atan2(Math.sqrt(value), Math.sqrt(1 - value)), units);
}
/**
* Takes a {@link LineString} and measures its length in the specified units.
*
* @param lineString geometry to measure
* @param units one of the units found inside {@link TurfConstants.TurfUnitCriteria}
* @return length of the input line in the units specified
* @see Turf Line Distance documentation
* @since 1.2.0
*/
public static double length(@NonNull LineString lineString,
@NonNull @TurfConstants.TurfUnitCriteria String units) {
List coordinates = lineString.coordinates();
return length(coordinates, units);
}
/**
* Takes a {@link MultiLineString} and measures its length in the specified units.
*
* @param multiLineString geometry to measure
* @param units one of the units found inside {@link TurfConstants.TurfUnitCriteria}
* @return length of the input lines combined, in the units specified
* @see Turf Line Distance documentation
* @since 1.2.0
*/
public static double length(@NonNull MultiLineString multiLineString,
@NonNull @TurfConstants.TurfUnitCriteria String units) {
double len = 0;
for (List points : multiLineString.coordinates()) {
len += length(points, units);
}
return len;
}
/**
* Takes a {@link Polygon} and measures its perimeter in the specified units. if the polygon
* contains holes, the perimeter will also be included.
*
* @param polygon geometry to measure
* @param units one of the units found inside {@link TurfConstants.TurfUnitCriteria}
* @return total perimeter of the input polygon in the units specified
* @see Turf Line Distance documentation
* @since 1.2.0
*/
public static double length(@NonNull Polygon polygon,
@NonNull @TurfConstants.TurfUnitCriteria String units) {
double len = 0;
for (List points : polygon.coordinates()) {
len += length(points, units);
}
return len;
}
/**
* Takes a {@link MultiPolygon} and measures each polygons perimeter in the specified units. if
* one of the polygons contains holes, the perimeter will also be included.
*
* @param multiPolygon geometry to measure
* @param units one of the units found inside {@link TurfConstants.TurfUnitCriteria}
* @return total perimeter of the input polygons combined, in the units specified
* @see Turf Line Distance documentation
* @since 1.2.0
*/
public static double length(@NonNull MultiPolygon multiPolygon,
@NonNull @TurfConstants.TurfUnitCriteria String units) {
double len = 0;
List>> coordinates = multiPolygon.coordinates();
for (List> coordinate : coordinates) {
for (List theCoordinate : coordinate) {
len += length(theCoordinate, units);
}
}
return len;
}
private static double length(List coords, String units) {
double travelled = 0;
Point prevCoords = coords.get(0);
Point curCoords;
for (int i = 1; i < coords.size(); i++) {
curCoords = coords.get(i);
travelled += distance(prevCoords, curCoords, units);
prevCoords = curCoords;
}
return travelled;
}
/**
* Takes two {@link Point}s and returns a point midway between them. The midpoint is calculated
* geodesically, meaning the curvature of the earth is taken into account.
*
* @param from first point used for calculating the midpoint
* @param to second point used for calculating the midpoint
* @return a {@link Point} midway between point1 and point2
* @see Turf Midpoint documentation
* @since 1.3.0
*/
public static Point midpoint(@NonNull Point from, @NonNull Point to) {
double dist = distance(from, to, TurfConstants.UNIT_MILES);
double heading = bearing(from, to);
return destination(from, dist / 2, heading, TurfConstants.UNIT_MILES);
}
/**
* Takes a line and returns a point at a specified distance along the line.
*
* @param line that the point should be placed upon
* @param distance along the linestring geometry which the point should be placed on
* @param units one of the units found inside {@link TurfConstants.TurfUnitCriteria}
* @return a {@link Point} which is on the linestring provided and at the distance from the origin
* of that line to the end of the distance
* @since 1.3.0
*/
public static Point along(@NonNull LineString line, @FloatRange(from = 0) double distance,
@NonNull @TurfConstants.TurfUnitCriteria String units) {
List coords = line.coordinates();
double travelled = 0;
for (int i = 0; i < coords.size(); i++) {
if (distance >= travelled && i == coords.size() - 1) {
break;
} else if (travelled >= distance) {
double overshot = distance - travelled;
if (overshot == 0) {
return coords.get(i);
} else {
double direction = bearing(coords.get(i), coords.get(i - 1)) - 180;
return destination(coords.get(i), overshot, direction, units);
}
} else {
travelled += distance(coords.get(i), coords.get(i + 1), units);
}
}
return coords.get(coords.size() - 1);
}
/**
* Takes a set of features, calculates the bbox of all input features, and returns a bounding box.
*
* @param point a {@link Point} object
* @return A double array defining the bounding box in this order {@code [minX, minY, maxX, maxY]}
* @since 2.0.0
*/
public static double[] bbox(@NonNull Point point) {
List resultCoords = TurfMeta.coordAll(point);
return bboxCalculator(resultCoords);
}
/**
* Takes a set of features, calculates the bbox of all input features, and returns a bounding box.
*
* @param lineString a {@link LineString} object
* @return A double array defining the bounding box in this order {@code [minX, minY, maxX, maxY]}
* @since 2.0.0
*/
public static double[] bbox(@NonNull LineString lineString) {
List resultCoords = TurfMeta.coordAll(lineString);
return bboxCalculator(resultCoords);
}
/**
* Takes a set of features, calculates the bbox of all input features, and returns a bounding box.
*
* @param multiPoint a {@link MultiPoint} object
* @return a double array defining the bounding box in this order {@code [minX, minY, maxX, maxY]}
* @since 2.0.0
*/
public static double[] bbox(@NonNull MultiPoint multiPoint) {
List resultCoords = TurfMeta.coordAll(multiPoint);
return bboxCalculator(resultCoords);
}
/**
* Takes a set of features, calculates the bbox of all input features, and returns a bounding box.
*
* @param polygon a {@link Polygon} object
* @return a double array defining the bounding box in this order {@code [minX, minY, maxX, maxY]}
* @since 2.0.0
*/
public static double[] bbox(@NonNull Polygon polygon) {
List resultCoords = TurfMeta.coordAll(polygon, false);
return bboxCalculator(resultCoords);
}
/**
* Takes a set of features, calculates the bbox of all input features, and returns a bounding box.
*
* @param multiLineString a {@link MultiLineString} object
* @return a double array defining the bounding box in this order {@code [minX, minY, maxX, maxY]}
* @since 2.0.0
*/
public static double[] bbox(@NonNull MultiLineString multiLineString) {
List resultCoords = TurfMeta.coordAll(multiLineString);
return bboxCalculator(resultCoords);
}
/**
* Takes a set of features, calculates the bbox of all input features, and returns a bounding box.
*
* @param multiPolygon a {@link MultiPolygon} object
* @return a double array defining the bounding box in this order {@code [minX, minY, maxX, maxY]}
* @since 2.0.0
*/
public static double[] bbox(MultiPolygon multiPolygon) {
List resultCoords = TurfMeta.coordAll(multiPolygon, false);
return bboxCalculator(resultCoords);
}
/**
* Takes an arbitrary {@link Geometry} and calculates a bounding box.
*
* @param geometry a {@link Geometry} object
* @return a double array defining the bounding box in this order {@code [minX, minY, maxX, maxY]}
* @since 2.0.0
*/
public static double[] bbox(Geometry geometry) {
if (geometry instanceof Point) {
return bbox((Point) geometry);
} else if (geometry instanceof MultiPoint) {
return bbox((MultiPoint) geometry);
} else if (geometry instanceof LineString) {
return bbox((LineString) geometry);
} else if (geometry instanceof MultiLineString) {
return bbox((MultiLineString) geometry);
} else if (geometry instanceof Polygon) {
return bbox((Polygon) geometry);
} else if (geometry instanceof MultiPolygon) {
return bbox((MultiPolygon) geometry);
} else if (geometry instanceof GeometryCollection) {
List points = new ArrayList<>();
for (Geometry geo : ((GeometryCollection) geometry).geometries()) {
// recursive
double[] bbox = bbox(geo);
points.add(Point.fromLngLat(bbox[0], bbox[1]));
points.add(Point.fromLngLat(bbox[2], bbox[1]));
points.add(Point.fromLngLat(bbox[2], bbox[3]));
points.add(Point.fromLngLat(bbox[0], bbox[3]));
}
return TurfMeasurement.bbox(MultiPoint.fromLngLats(points));
} else {
throw new RuntimeException(("Unknown geometry class: " + geometry.getClass()));
}
}
private static double[] bboxCalculator(List resultCoords) {
double[] bbox = new double[4];
bbox[0] = Double.POSITIVE_INFINITY;
bbox[1] = Double.POSITIVE_INFINITY;
bbox[2] = Double.NEGATIVE_INFINITY;
bbox[3] = Double.NEGATIVE_INFINITY;
for (Point point : resultCoords) {
if (bbox[0] > point.longitude()) {
bbox[0] = point.longitude();
}
if (bbox[1] > point.latitude()) {
bbox[1] = point.latitude();
}
if (bbox[2] < point.longitude()) {
bbox[2] = point.longitude();
}
if (bbox[3] < point.latitude()) {
bbox[3] = point.latitude();
}
}
return bbox;
}
}