Skip to content
Merged
Show file tree
Hide file tree
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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ Mapbox welcomes participation and contributions from everyone.

### master

- Added support for Turf area measurement method [#1079](https://github.com/mapbox/mapbox-java/pull/1079)

### 4.9.0 - September 23, 2019
- Added intersection search support to MapboxGeocoding [#1074](https://github.com/mapbox/mapbox-java/pull/1074)
- Added support for Turf polygonToLine method [#1075](https://github.com/mapbox/mapbox-java/pull/1075)
Expand Down
2 changes: 1 addition & 1 deletion docs/turf-port.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Below's an on going list of the Turf functions which currently exist inside the

## Measurement
- [x] turf-along
- [ ] turf-area
- [x] turf-area
- [x] turf-bbox
- [x] turf-bbox-polygon
- [x] turf-bearing
Expand Down
124 changes: 124 additions & 0 deletions services-turf/src/main/java/com/mapbox/turf/TurfMeasurement.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@ private TurfMeasurement() {
throw new AssertionError("No Instances.");
}

/**
* Earth's radius in meters.
*/
public static double EARTH_RADIUS = 6378137;

/**
* Takes two {@link Point}s and finds the geographic bearing between them.
*
Expand Down Expand Up @@ -572,4 +577,123 @@ public static BoundingBox square(@NonNull BoundingBox boundingBox) {
);
}
}

/**
* Takes one {@link Feature} and returns it's area in square meters.
*
* @param feature input {@link Feature}
* @return area in square meters
* @since 4.10.0
*/
public static double area(@NonNull Feature feature) {
return feature.geometry() != null ? area(feature.geometry()) : 0.0f;
}

/**
* Takes one {@link FeatureCollection} and returns it's area in square meters.
*
* @param featureCollection input {@link FeatureCollection}
* @return area in square meters
* @since 4.10.0
*/
public static double area(@NonNull FeatureCollection featureCollection) {
List<Feature> features = featureCollection.features();
double total = 0.0f;
if (features != null) {
for (Feature feature : features) {
total += area(feature);
}
}
return total;
}

/**
* Takes one {@link Geometry} and returns it's area in square meters.
*
* @param geometry input {@link Geometry}
* @return area in square meters
* @since 4.10.0
*/
public static double area(@NonNull Geometry geometry) {
return calculateArea(geometry);
}

private static double calculateArea(@NonNull Geometry geometry) {
double total = 0.0f;
if (geometry instanceof Polygon) {
return polygonArea(((Polygon) geometry).coordinates());
} else if (geometry instanceof MultiPolygon) {
List<List<List<Point>>> coordinates = ((MultiPolygon) geometry).coordinates();
for (int i = 0; i < coordinates.size(); i++) {
total += polygonArea(coordinates.get(i));
}
return total;
} else {
// Area should be 0 for case Point, MultiPoint, LineString and MultiLineString
return 0.0f;
}
}

private static double polygonArea(@NonNull List<List<Point>> coordinates) {
double total = 0.0f;
if (coordinates.size() > 0) {
total += Math.abs(ringArea(coordinates.get(0)));
for (int i = 1; i < coordinates.size(); i++) {
total -= Math.abs(ringArea(coordinates.get(i)));
}
}
return total;
}

/**
* Calculate the approximate area of the polygon were it projected onto the earth.
* Note that this area will be positive if ring is oriented clockwise, otherwise
* it will be negative.
*
* Reference:
* Robert. G. Chamberlain and William H. Duquette, "Some Algorithms for Polygons on a Sphere",
* JPL Publication 07-03, Jet Propulsion
* Laboratory, Pasadena, CA, June 2007 https://trs.jpl.nasa.gov/handle/2014/41271
*
* @param coordinates A list of {@link Point} of Ring Coordinates
* @return The approximate signed geodesic area of the polygon in square meters.
*/
private static double ringArea(@NonNull List<Point> coordinates) {
Point p1;
Point p2;
Point p3;
int lowerIndex;
int middleIndex;
int upperIndex;
double total = 0.0f;
final int coordsLength = coordinates.size();

if (coordsLength > 2) {
for (int i = 0; i < coordsLength; i++) {
if (i == coordsLength - 2) { // i = N-2
lowerIndex = coordsLength - 2;
middleIndex = coordsLength - 1;
upperIndex = 0;
} else if (i == coordsLength - 1) { // i = N-1
lowerIndex = coordsLength - 1;
middleIndex = 0;
upperIndex = 1;
} else { // i = 0 to N-3
lowerIndex = i;
middleIndex = i + 1;
upperIndex = i + 2;
}
p1 = coordinates.get(lowerIndex);
p2 = coordinates.get(middleIndex);
p3 = coordinates.get(upperIndex);
total += (rad(p3.longitude()) - rad(p1.longitude())) * Math.sin(rad(p2.latitude()));
}
total = total * EARTH_RADIUS * EARTH_RADIUS / 2;
}
return total;
}

private static double rad(double num) {
return num * Math.PI / 180;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,14 @@ public class TurfMeasurementTest extends TestUtils {
private static final String TURF_ENVELOPE_FEATURE_COLLECTION = "turf-envelope/feature-collection.geojson";
private static final String LINE_DISTANCE_MULTILINESTRING
= "turf-line-distance/multilinestring.geojson";
private static final String TURF_AREA_POLYGON_GEOJSON = "turf-area/polygon.geojson";
private static final String TURF_AREA_POLYGON_RESULT = "turf-area/polygon.json";
private static final String TURF_AREA_MULTIPOLYGON_GEOJSON = "turf-area/multi-polygon.geojson";
private static final String TURF_AREA_MULTIPOLYGON_RESULT = "turf-area/multi-polygon.json";
private static final String TURF_AREA_GEOM_POLYGON_GEOJSON = "turf-area/geometry-polygon.geojson";
private static final String TURF_AREA_GEOM_POLYGON_RESULT = "turf-area/geometry-polygon.json";
private static final String TURF_AREA_FEATURECOLLECTION_POLYGON_GEOJSON = "turf-area/featurecollection-polygon.geojson";
private static final String TURF_AREA_FEATURECOLLECTION_POLYGON_RESULT = "turf-area/featurecollection-polygon.json";

@Rule
public ExpectedException thrown = ExpectedException.none();
Expand Down Expand Up @@ -474,4 +482,30 @@ public void square(){
assertEquals(BoundingBox.fromCoordinates(-2.5, 0, 7.5, 10), sq1);
assertEquals(BoundingBox.fromCoordinates(0, -2.5, 10, 7.5), sq2);
}

@Test
public void areaPolygon() {
double expected = Double.valueOf(loadJsonFixture(TURF_AREA_POLYGON_RESULT));
assertEquals(expected, TurfMeasurement.area(Feature.fromJson(loadJsonFixture(TURF_AREA_POLYGON_GEOJSON))), 1);
}

@Test
public void areaMultiPolygon() {
double expected = Double.valueOf(loadJsonFixture(TURF_AREA_MULTIPOLYGON_RESULT));
assertEquals(expected, TurfMeasurement.area(Feature.fromJson(loadJsonFixture(TURF_AREA_MULTIPOLYGON_GEOJSON))), 1);
}

@Test
public void areaGeometry() {
double expected = Double.valueOf(loadJsonFixture(TURF_AREA_GEOM_POLYGON_RESULT));
assertEquals(expected, TurfMeasurement.area(Polygon.fromJson(loadJsonFixture(TURF_AREA_GEOM_POLYGON_GEOJSON))), 1);
}

@Test
public void areaFeatureCollection() {
double expected = Double.valueOf(loadJsonFixture(TURF_AREA_FEATURECOLLECTION_POLYGON_RESULT));
assertEquals(expected, TurfMeasurement.area(FeatureCollection.fromJson(loadJsonFixture(TURF_AREA_FEATURECOLLECTION_POLYGON_GEOJSON))), 1);
}


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
-2.109375,
47.040182144806664
],
[
4.5703125,
44.59046718130883
],
[
7.03125,
49.15296965617042
],
[
-3.515625,
49.83798245308484
],
[
-2.109375,
47.040182144806664
]
]
]
}
},
{
"type": "Feature",
"properties": {},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
9.64599609375,
47.70976154266637
],
[
9.4482421875,
47.73932336136857
],
[
8.8330078125,
47.47266286861342
],
[
10.21728515625,
46.604167162931844
],
[
11.755371093749998,
46.81509864599243
],
[
11.865234375,
47.90161354142077
],
[
9.64599609375,
47.70976154266637
]
]
]
}
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
294852371360
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"type": "Polygon",
"coordinates": [[
[-2.275543, 53.464547 ],
[-2.275543, 53.489271 ],
[-2.215118, 53.489271 ],
[-2.215118, 53.464547 ],
[-2.275543, 53.464547 ]
]]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
11017976
60 changes: 60 additions & 0 deletions services-turf/src/test/resources/turf-area/multi-polygon.geojson
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
{
"type": "Feature",
"properties": {
"stroke": "#F00",
"stroke-width": 6
},
"geometry": {
"type": "MultiPolygon",
"coordinates": [
[
[
[
102,
2
],
[
103,
2
],
[
103,
3
],
[
102,
3
],
[
102,
2
]
]
],
[
[
[
100,
0
],
[
101,
0
],
[
101,
1
],
[
100,
1
],
[
100,
0
]
]
]
]
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
24771477332
19 changes: 19 additions & 0 deletions services-turf/src/test/resources/turf-area/polygon.geojson
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"type": "Feature",
"properties": {},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[125, -15],
[113, -22],
[117, -37],
[130, -33],
[148, -39],
[154, -27],
[144, -15],
[125, -15]
]
]
}
}
1 change: 1 addition & 0 deletions services-turf/src/test/resources/turf-area/polygon.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
7766240997209