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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ Mapbox welcomes participation and contributions from everyone.
### master

- 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)

### v4.9.0-alpha.1 - September 4, 2019

Expand Down
2 changes: 1 addition & 1 deletion docs/turf-port.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ Below's an on going list of the Turf functions which currently exist inside the
- [ ] turf-flatten
- [ ] turf-line-to-polygon
- [ ] turf-polygonize
- [ ] turf-polygon-to-line
- [x] turf-polygon-to-line

## Misc
- [ ] turf-kinks
Expand Down
145 changes: 145 additions & 0 deletions services-turf/src/main/java/com/mapbox/turf/TurfConversion.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,17 @@
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;

import com.google.gson.JsonObject;
import com.mapbox.geojson.Feature;
import com.mapbox.geojson.FeatureCollection;
import com.mapbox.geojson.Geometry;
import com.mapbox.geojson.LineString;
import com.mapbox.geojson.MultiLineString;
import com.mapbox.geojson.MultiPolygon;
import com.mapbox.geojson.Point;
import com.mapbox.geojson.Polygon;
import com.mapbox.turf.TurfConstants.TurfUnitCriteria;
import com.sun.istack.internal.NotNull;

import java.util.ArrayList;
import java.util.HashMap;
Expand Down Expand Up @@ -201,4 +208,142 @@ public static FeatureCollection explode(@NonNull Feature feature) {
}
return FeatureCollection.fromFeatures(finalFeatureList);
}

/**
* Takes a {@link Feature} that contains {@link Polygon} and
* covert it to a {@link Feature} that contains {@link LineString} or {@link MultiLineString}.
*
* @param feature a {@link Feature} object that contains {@link Polygon}
* @return a {@link Feature} object that contains {@link LineString} or {@link MultiLineString}
* @since 4.10.0
*/
public static Feature polygonToLine(@NotNull Feature feature) {
return polygonToLine(feature, null);
}

/**
* Takes a {@link Feature} that contains {@link Polygon} and a properties {@link JsonObject} and
* covert it to a {@link Feature} that contains {@link LineString} or {@link MultiLineString}.
*
* @param feature a {@link Feature} object that contains {@link Polygon}
* @param properties a {@link JsonObject} that represents a feature's properties
* @return a {@link Feature} object that contains {@link LineString} or {@link MultiLineString}
* @since 4.10.0
*/
public static Feature polygonToLine(@NotNull Feature feature, @Nullable JsonObject properties) {
Geometry geometry = feature.geometry();
if (geometry instanceof Polygon) {
return polygonToLine((Polygon) geometry,properties != null ? properties :
feature.type().equals("Feature") ? feature.properties() : new JsonObject());
}
throw new TurfException("Feature's geometry must be Polygon");
}

/**
* Takes a {@link Polygon} and
* covert it to a {@link Feature} that contains {@link LineString} or {@link MultiLineString}.
*
* @param polygon a {@link Polygon} object
* @return a {@link Feature} object that contains {@link LineString} or {@link MultiLineString}
* @since 4.10.0
*/
public static Feature polygonToLine(@NotNull Polygon polygon) {
return polygonToLine(polygon, null);
}

/**
* Takes a {@link MultiPolygon} and
* covert it to a {@link FeatureCollection} that contains list
* of {@link Feature} of {@link LineString} or {@link MultiLineString}.
*
* @param multiPolygon a {@link MultiPolygon} object
* @return a {@link FeatureCollection} object that contains
* list of {@link Feature} of {@link LineString} or {@link MultiLineString}
* @since 4.10.0
*/
public static FeatureCollection polygonToLine(@NotNull MultiPolygon multiPolygon) {
return polygonToLine(multiPolygon, null);
}

/**
* Takes a {@link Polygon} and a properties {@link JsonObject} and
* covert it to a {@link Feature} that contains {@link LineString} or {@link MultiLineString}.
*
* @param polygon a {@link Polygon} object
* @param properties a {@link JsonObject} that represents a feature's properties
* @return a {@link Feature} object that contains {@link LineString} or {@link MultiLineString}
* @since 4.10.0
*/
public static Feature polygonToLine(@NotNull Polygon polygon, @Nullable JsonObject properties) {
return coordsToLine(polygon.coordinates(), properties);
}

/**
* Takes a {@link MultiPolygon} and a properties {@link JsonObject} and
* covert it to a {@link FeatureCollection} that contains list
* of {@link Feature} of {@link LineString} or {@link MultiLineString}.
*
* @param multiPolygon a {@link MultiPolygon} object
* @param properties a {@link JsonObject} that represents a feature's properties
* @return a {@link FeatureCollection} object that contains
* list of {@link Feature} of {@link LineString} or {@link MultiLineString}
* @since 4.10.0
*/
public static FeatureCollection polygonToLine(@NotNull MultiPolygon multiPolygon,
@Nullable JsonObject properties) {
List<List<List<Point>>> coordinates = multiPolygon.coordinates();
List<Feature> finalFeatureList = new ArrayList<>();
for (List<List<Point>> polygonCoordinates : coordinates) {
finalFeatureList.add(coordsToLine(polygonCoordinates, properties));
}
return FeatureCollection.fromFeatures(finalFeatureList);
}

/**
* Takes a {@link Feature} that contains {@link MultiPolygon} and
* covert it to a {@link FeatureCollection} that contains list of {@link Feature}
* of {@link LineString} or {@link MultiLineString}.
*
* @param feature a {@link Feature} object that contains {@link Polygon}
* @return a {@link FeatureCollection} object that contains list of {@link Feature}
* of {@link LineString} or {@link MultiLineString}
* @since 4.10.0
*/
public static FeatureCollection multiPolygonToLine(@NotNull Feature feature) {
return multiPolygonToLine(feature, null);
}

/**
* Takes a {@link Feature} that contains {@link MultiPolygon} and a
* properties {@link JsonObject} and
* covert it to a {@link FeatureCollection} that contains
* list of {@link Feature} of {@link LineString} or {@link MultiLineString}.
*
* @param feature a {@link Feature} object that contains {@link MultiPolygon}
* @param properties a {@link JsonObject} that represents a feature's properties
* @return a {@link FeatureCollection} object that contains
* list of {@link Feature} of {@link LineString} or {@link MultiLineString}
* @since 4.10.0
*/
public static FeatureCollection multiPolygonToLine(@NotNull Feature feature,
@Nullable JsonObject properties) {
Geometry geometry = feature.geometry();
if (geometry instanceof MultiPolygon) {
return polygonToLine((MultiPolygon) geometry, properties != null ? properties :
feature.type().equals("Feature") ? feature.properties() : new JsonObject());
}
throw new TurfException("Feature's geometry must be MultiPolygon");
}

@Nullable
private static Feature coordsToLine(@NotNull List<List<Point>> coordinates,
@Nullable JsonObject properties) {
if (coordinates.size() > 1) {
return Feature.fromGeometry(MultiLineString.fromLngLats(coordinates), properties);
} else if (coordinates.size() == 1) {
LineString lineString = LineString.fromLngLats(coordinates.get(0));
return Feature.fromGeometry(lineString, properties);
}
return null;
}
}
17 changes: 16 additions & 1 deletion services-turf/src/test/java/com/mapbox/turf/TestUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,15 @@

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

import static java.nio.charset.StandardCharsets.UTF_8;
Expand All @@ -27,7 +31,7 @@ public void compareJson(String expectedJson, String actualJson) {
assertThat(parser.parse(actualJson), Matchers.equalTo(parser.parse(expectedJson)));
}

protected String loadJsonFixture(String filename) throws IOException {
protected String loadJsonFixture(String filename) {
ClassLoader classLoader = getClass().getClassLoader();
InputStream inputStream = classLoader.getResourceAsStream(filename);
Scanner scanner = new Scanner(inputStream, UTF_8.name()).useDelimiter("\\A");
Expand Down Expand Up @@ -58,4 +62,15 @@ public static void expectNearNumber(double expected, double actual, double epsil
assertTrue(String.format("Expected %f to be near %f", actual, expected),
Math.abs(expected - actual) <= epsilon);
}

protected List<String> getResourceFolderFileNames (String folder) {
ClassLoader loader = getClass().getClassLoader();
URL url = loader.getResource(folder);
String path = url.getPath();
List<String> names = new ArrayList<>();
for (File file : new File(path).listFiles()) {
names.add(file.getName());
}
return names;
}
}
76 changes: 65 additions & 11 deletions services-turf/src/test/java/com/mapbox/turf/TurfConversionTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,23 @@ public class TurfConversionTest extends TestUtils {
private static final String TURF_EXPLODE_MULTIPOLYGON = "turf-explode/multipolygon.geojson";
private static final String TURF_EXPLODE_GEOMETRY_COLLECTION = "turf-explode/geometrycollection.geojson";

private static final String TURF_POLYGON_TO_LINE_PATH_IN = "turf-polygon-to-line/in/";
private static final String TURF_POLYGON_TO_LINE_PATH_OUT = "turf-polygon-to-line/expected/";

private static final String TURF_POLYGON_TO_LINE_FILENAME_POLYGON= "polygon.geojson";
private static final String TURF_POLYGON_TO_LINE_FILENAME_GEOMETRY_POLYGON= "geometry-polygon.geojson";
private static final String TURF_POLYGON_TO_LINE_FILENAME_POLYGON_WITH_HOLE = "polygon-with-hole.geojson";

private static final String TURF_POLYGON_TO_LINE_FILENAME_MULTIPOLYGON = "multi-polygon.geojson";
private static final String TURF_POLYGON_TO_LINE_FILENAME_MULTIPOLYGON_OUTER_DOUGHNUT = "multi-polygon-outer-doughnut.geojson";
private static final String TURF_POLYGON_TO_LINE_FILENAME_MULTIPOLYGON_WITH_HOLES = "multi-polygon-with-holes.geojson";


@Rule
public ExpectedException thrown = ExpectedException.none();

@Test
public void radiansToDistance() throws Exception {
public void radiansToDistance() {
assertEquals(
1, TurfConversion.radiansToLength(1, TurfConstants.UNIT_RADIANS), DELTA);
assertEquals(
Expand All @@ -41,7 +53,7 @@ public void radiansToDistance() throws Exception {
}

@Test
public void distanceToRadians() throws Exception {
public void distanceToRadians() {
assertEquals(
1, TurfConversion.lengthToRadians(1, TurfConstants.UNIT_RADIANS), DELTA);
assertEquals(
Expand All @@ -51,7 +63,7 @@ public void distanceToRadians() throws Exception {
}

@Test
public void distanceToDegrees() throws Exception {
public void distanceToDegrees() {
assertEquals(
57.29577951308232, TurfConversion.lengthToDegrees(1, TurfConstants.UNIT_RADIANS), DELTA);
assertEquals(
Expand Down Expand Up @@ -79,25 +91,25 @@ public void convertDistance() throws TurfException {
}

@Test
public void explodePointSingleFeature() throws IOException, NullPointerException {
public void explodePointSingleFeature() throws NullPointerException {
Point point = Point.fromLngLat(102, 0.5);
assertEquals(1, TurfConversion.explode(Feature.fromGeometry(point)).features().size());
}

@Test
public void explodeMultiPointSingleFeature() throws IOException, NullPointerException {
public void explodeMultiPointSingleFeature() throws NullPointerException {
MultiPoint multiPoint = MultiPoint.fromJson(loadJsonFixture(TURF_EXPLODE_MULTI_POINT));
assertEquals(4, TurfConversion.explode(Feature.fromGeometry(multiPoint)).features().size());
}

@Test
public void explodeLineStringSingleFeature() throws IOException, NullPointerException {
public void explodeLineStringSingleFeature() throws NullPointerException {
LineString lineString = LineString.fromJson(loadJsonFixture(TURF_EXPLODE_LINESTRING));
assertEquals(4, TurfConversion.explode(Feature.fromGeometry(lineString)).features().size());
}

@Test
public void explodePolygonSingleFeature() throws IOException, NullPointerException {
public void explodePolygonSingleFeature() throws NullPointerException {
Polygon polygon = Polygon.fromLngLats(Arrays.asList(
Arrays.asList(
Point.fromLngLat(0, 101),
Expand All @@ -108,29 +120,71 @@ public void explodePolygonSingleFeature() throws IOException, NullPointerExcepti
}

@Test
public void explodeMultiLineStringSingleFeature() throws IOException, NullPointerException {
public void explodeMultiLineStringSingleFeature() throws NullPointerException {
MultiLineString multiLineString = MultiLineString.fromJson(loadJsonFixture(TURF_EXPLODE_MULTILINESTRING));
assertEquals(4, TurfConversion.explode(Feature.fromGeometry(multiLineString)).features().size());
}

@Test
public void explodeMultiPolygonSingleFeature() throws IOException, NullPointerException {
public void explodeMultiPolygonSingleFeature() throws NullPointerException {
MultiPolygon multiPolygon = MultiPolygon.fromJson(loadJsonFixture(TURF_EXPLODE_MULTIPOLYGON));
assertEquals(12, TurfConversion.explode(Feature.fromGeometry(multiPolygon)).features().size());
}

@Test
public void explodeGeometryCollectionSingleFeature() throws IOException, NullPointerException {
public void explodeGeometryCollectionSingleFeature() throws NullPointerException {
GeometryCollection geometryCollection = GeometryCollection.fromJson(loadJsonFixture(TURF_EXPLODE_GEOMETRY_COLLECTION));
assertEquals(3, TurfConversion.explode(Feature.fromGeometry(geometryCollection)).features().size());
}

@Test
public void explodeFeatureCollection() throws IOException, NullPointerException {
public void explodeFeatureCollection() throws NullPointerException {
FeatureCollection featureCollection = FeatureCollection.fromFeatures(new Feature[] {
Feature.fromGeometry(MultiLineString.fromJson(loadJsonFixture(TURF_EXPLODE_MULTILINESTRING))),
Feature.fromGeometry(MultiPolygon.fromJson(loadJsonFixture(TURF_EXPLODE_MULTIPOLYGON)))
});
assertEquals(16, TurfConversion.explode(featureCollection).features().size());
}

@Test
public void polygonToLine_GeometryPolygon() throws NullPointerException {
Polygon polygon = Polygon.fromJson(loadJsonFixture(TURF_POLYGON_TO_LINE_PATH_IN + TURF_POLYGON_TO_LINE_FILENAME_GEOMETRY_POLYGON));
Feature expected = Feature.fromJson(loadJsonFixture(TURF_POLYGON_TO_LINE_PATH_OUT + TURF_POLYGON_TO_LINE_FILENAME_GEOMETRY_POLYGON));
compareJson(expected.toJson(), TurfConversion.polygonToLine(polygon).toJson());
}

@Test
public void polygonToLine_Polygon() throws NullPointerException {
Feature polygon = Feature.fromJson(loadJsonFixture(TURF_POLYGON_TO_LINE_PATH_IN + TURF_POLYGON_TO_LINE_FILENAME_POLYGON));
Feature expected = Feature.fromJson(loadJsonFixture(TURF_POLYGON_TO_LINE_PATH_OUT + TURF_POLYGON_TO_LINE_FILENAME_POLYGON));
compareJson(expected.toJson(), TurfConversion.polygonToLine(polygon).toJson());
}

@Test
public void polygonToLine_PolygonWithHole() throws NullPointerException {
Feature polygon = Feature.fromJson(loadJsonFixture(TURF_POLYGON_TO_LINE_PATH_IN + TURF_POLYGON_TO_LINE_FILENAME_POLYGON_WITH_HOLE));
Feature expected = Feature.fromJson(loadJsonFixture(TURF_POLYGON_TO_LINE_PATH_OUT + TURF_POLYGON_TO_LINE_FILENAME_POLYGON_WITH_HOLE));
compareJson(expected.toJson(), TurfConversion.polygonToLine(polygon).toJson());
}

@Test
public void polygonToLine_MultiPolygon() throws NullPointerException {
Feature multiPolygon = Feature.fromJson(loadJsonFixture(TURF_POLYGON_TO_LINE_PATH_IN + TURF_POLYGON_TO_LINE_FILENAME_MULTIPOLYGON));
FeatureCollection expected = FeatureCollection.fromJson(loadJsonFixture(TURF_POLYGON_TO_LINE_PATH_OUT + TURF_POLYGON_TO_LINE_FILENAME_MULTIPOLYGON));
compareJson(expected.toJson(), TurfConversion.multiPolygonToLine(multiPolygon).toJson());
}

@Test
public void polygonToLine_MultiPolygonWithHoles() throws NullPointerException {
Feature multiPolygon = Feature.fromJson(loadJsonFixture(TURF_POLYGON_TO_LINE_PATH_IN + TURF_POLYGON_TO_LINE_FILENAME_MULTIPOLYGON_WITH_HOLES));
FeatureCollection expected = FeatureCollection.fromJson(loadJsonFixture(TURF_POLYGON_TO_LINE_PATH_OUT + TURF_POLYGON_TO_LINE_FILENAME_MULTIPOLYGON_WITH_HOLES));
compareJson(expected.toJson(), TurfConversion.multiPolygonToLine(multiPolygon).toJson());
}

@Test
public void polygonToLine_MultiPolygonWithOuterDoughnut() throws NullPointerException {
Feature multiPolygon = Feature.fromJson(loadJsonFixture(TURF_POLYGON_TO_LINE_PATH_IN + TURF_POLYGON_TO_LINE_FILENAME_MULTIPOLYGON_OUTER_DOUGHNUT));
FeatureCollection expected = FeatureCollection.fromJson(loadJsonFixture(TURF_POLYGON_TO_LINE_PATH_OUT + TURF_POLYGON_TO_LINE_FILENAME_MULTIPOLYGON_OUTER_DOUGHNUT));
compareJson(expected.toJson(), TurfConversion.multiPolygonToLine(multiPolygon).toJson());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"type": "Feature",
"properties": {},
"geometry": {
"type": "LineString",
"coordinates": [
[
-2.275543,
53.464547
],
[
-2.275543,
53.489271
],
[
-2.215118,
53.489271
],
[
-2.215118,
53.464547
],
[
-2.275543,
53.464547
]
]
}
}
Loading