Skip to content

Commit ba24e99

Browse files
authored
[turf] Add polygonToLine method. (#1075)
* [turf] Add polygonToLine method. * [turf] Fix the unit test by parsing json to Feature object and convert to json string again. * [turf] Change since 4.9.0 to 4.10.0. * [turf] Update change log and docs/turf-port.md * [turf] Fix unit test.
1 parent 20e01b5 commit ba24e99

17 files changed

+1072
-13
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ Mapbox welcomes participation and contributions from everyone.
55
### master
66

77
- Added intersection search support to MapboxGeocoding [#1074](https://github.com/mapbox/mapbox-java/pull/1074)
8+
- Added support for Turf polygonToLine method [#1075](https://github.com/mapbox/mapbox-java/pull/1075)
89

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

docs/turf-port.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ Below's an on going list of the Turf functions which currently exist inside the
6262
- [ ] turf-flatten
6363
- [ ] turf-line-to-polygon
6464
- [ ] turf-polygonize
65-
- [ ] turf-polygon-to-line
65+
- [x] turf-polygon-to-line
6666

6767
## Misc
6868
- [ ] turf-kinks

services-turf/src/main/java/com/mapbox/turf/TurfConversion.java

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,17 @@
44
import android.support.annotation.NonNull;
55
import android.support.annotation.Nullable;
66

7+
import com.google.gson.JsonObject;
78
import com.mapbox.geojson.Feature;
89
import com.mapbox.geojson.FeatureCollection;
10+
import com.mapbox.geojson.Geometry;
11+
import com.mapbox.geojson.LineString;
12+
import com.mapbox.geojson.MultiLineString;
13+
import com.mapbox.geojson.MultiPolygon;
914
import com.mapbox.geojson.Point;
15+
import com.mapbox.geojson.Polygon;
1016
import com.mapbox.turf.TurfConstants.TurfUnitCriteria;
17+
import com.sun.istack.internal.NotNull;
1118

1219
import java.util.ArrayList;
1320
import java.util.HashMap;
@@ -201,4 +208,142 @@ public static FeatureCollection explode(@NonNull Feature feature) {
201208
}
202209
return FeatureCollection.fromFeatures(finalFeatureList);
203210
}
211+
212+
/**
213+
* Takes a {@link Feature} that contains {@link Polygon} and
214+
* covert it to a {@link Feature} that contains {@link LineString} or {@link MultiLineString}.
215+
*
216+
* @param feature a {@link Feature} object that contains {@link Polygon}
217+
* @return a {@link Feature} object that contains {@link LineString} or {@link MultiLineString}
218+
* @since 4.10.0
219+
*/
220+
public static Feature polygonToLine(@NotNull Feature feature) {
221+
return polygonToLine(feature, null);
222+
}
223+
224+
/**
225+
* Takes a {@link Feature} that contains {@link Polygon} and a properties {@link JsonObject} and
226+
* covert it to a {@link Feature} that contains {@link LineString} or {@link MultiLineString}.
227+
*
228+
* @param feature a {@link Feature} object that contains {@link Polygon}
229+
* @param properties a {@link JsonObject} that represents a feature's properties
230+
* @return a {@link Feature} object that contains {@link LineString} or {@link MultiLineString}
231+
* @since 4.10.0
232+
*/
233+
public static Feature polygonToLine(@NotNull Feature feature, @Nullable JsonObject properties) {
234+
Geometry geometry = feature.geometry();
235+
if (geometry instanceof Polygon) {
236+
return polygonToLine((Polygon) geometry,properties != null ? properties :
237+
feature.type().equals("Feature") ? feature.properties() : new JsonObject());
238+
}
239+
throw new TurfException("Feature's geometry must be Polygon");
240+
}
241+
242+
/**
243+
* Takes a {@link Polygon} and
244+
* covert it to a {@link Feature} that contains {@link LineString} or {@link MultiLineString}.
245+
*
246+
* @param polygon a {@link Polygon} object
247+
* @return a {@link Feature} object that contains {@link LineString} or {@link MultiLineString}
248+
* @since 4.10.0
249+
*/
250+
public static Feature polygonToLine(@NotNull Polygon polygon) {
251+
return polygonToLine(polygon, null);
252+
}
253+
254+
/**
255+
* Takes a {@link MultiPolygon} and
256+
* covert it to a {@link FeatureCollection} that contains list
257+
* of {@link Feature} of {@link LineString} or {@link MultiLineString}.
258+
*
259+
* @param multiPolygon a {@link MultiPolygon} object
260+
* @return a {@link FeatureCollection} object that contains
261+
* list of {@link Feature} of {@link LineString} or {@link MultiLineString}
262+
* @since 4.10.0
263+
*/
264+
public static FeatureCollection polygonToLine(@NotNull MultiPolygon multiPolygon) {
265+
return polygonToLine(multiPolygon, null);
266+
}
267+
268+
/**
269+
* Takes a {@link Polygon} and a properties {@link JsonObject} and
270+
* covert it to a {@link Feature} that contains {@link LineString} or {@link MultiLineString}.
271+
*
272+
* @param polygon a {@link Polygon} object
273+
* @param properties a {@link JsonObject} that represents a feature's properties
274+
* @return a {@link Feature} object that contains {@link LineString} or {@link MultiLineString}
275+
* @since 4.10.0
276+
*/
277+
public static Feature polygonToLine(@NotNull Polygon polygon, @Nullable JsonObject properties) {
278+
return coordsToLine(polygon.coordinates(), properties);
279+
}
280+
281+
/**
282+
* Takes a {@link MultiPolygon} and a properties {@link JsonObject} and
283+
* covert it to a {@link FeatureCollection} that contains list
284+
* of {@link Feature} of {@link LineString} or {@link MultiLineString}.
285+
*
286+
* @param multiPolygon a {@link MultiPolygon} object
287+
* @param properties a {@link JsonObject} that represents a feature's properties
288+
* @return a {@link FeatureCollection} object that contains
289+
* list of {@link Feature} of {@link LineString} or {@link MultiLineString}
290+
* @since 4.10.0
291+
*/
292+
public static FeatureCollection polygonToLine(@NotNull MultiPolygon multiPolygon,
293+
@Nullable JsonObject properties) {
294+
List<List<List<Point>>> coordinates = multiPolygon.coordinates();
295+
List<Feature> finalFeatureList = new ArrayList<>();
296+
for (List<List<Point>> polygonCoordinates : coordinates) {
297+
finalFeatureList.add(coordsToLine(polygonCoordinates, properties));
298+
}
299+
return FeatureCollection.fromFeatures(finalFeatureList);
300+
}
301+
302+
/**
303+
* Takes a {@link Feature} that contains {@link MultiPolygon} and
304+
* covert it to a {@link FeatureCollection} that contains list of {@link Feature}
305+
* of {@link LineString} or {@link MultiLineString}.
306+
*
307+
* @param feature a {@link Feature} object that contains {@link Polygon}
308+
* @return a {@link FeatureCollection} object that contains list of {@link Feature}
309+
* of {@link LineString} or {@link MultiLineString}
310+
* @since 4.10.0
311+
*/
312+
public static FeatureCollection multiPolygonToLine(@NotNull Feature feature) {
313+
return multiPolygonToLine(feature, null);
314+
}
315+
316+
/**
317+
* Takes a {@link Feature} that contains {@link MultiPolygon} and a
318+
* properties {@link JsonObject} and
319+
* covert it to a {@link FeatureCollection} that contains
320+
* list of {@link Feature} of {@link LineString} or {@link MultiLineString}.
321+
*
322+
* @param feature a {@link Feature} object that contains {@link MultiPolygon}
323+
* @param properties a {@link JsonObject} that represents a feature's properties
324+
* @return a {@link FeatureCollection} object that contains
325+
* list of {@link Feature} of {@link LineString} or {@link MultiLineString}
326+
* @since 4.10.0
327+
*/
328+
public static FeatureCollection multiPolygonToLine(@NotNull Feature feature,
329+
@Nullable JsonObject properties) {
330+
Geometry geometry = feature.geometry();
331+
if (geometry instanceof MultiPolygon) {
332+
return polygonToLine((MultiPolygon) geometry, properties != null ? properties :
333+
feature.type().equals("Feature") ? feature.properties() : new JsonObject());
334+
}
335+
throw new TurfException("Feature's geometry must be MultiPolygon");
336+
}
337+
338+
@Nullable
339+
private static Feature coordsToLine(@NotNull List<List<Point>> coordinates,
340+
@Nullable JsonObject properties) {
341+
if (coordinates.size() > 1) {
342+
return Feature.fromGeometry(MultiLineString.fromLngLats(coordinates), properties);
343+
} else if (coordinates.size() == 1) {
344+
LineString lineString = LineString.fromLngLats(coordinates.get(0));
345+
return Feature.fromGeometry(lineString, properties);
346+
}
347+
return null;
348+
}
204349
}

services-turf/src/test/java/com/mapbox/turf/TestUtils.java

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,15 @@
66

77
import java.io.ByteArrayInputStream;
88
import java.io.ByteArrayOutputStream;
9+
import java.io.File;
910
import java.io.IOException;
1011
import java.io.InputStream;
1112
import java.io.ObjectInputStream;
1213
import java.io.ObjectOutputStream;
1314
import java.io.Serializable;
15+
import java.net.URL;
16+
import java.util.ArrayList;
17+
import java.util.List;
1418
import java.util.Scanner;
1519

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

30-
protected String loadJsonFixture(String filename) throws IOException {
34+
protected String loadJsonFixture(String filename) {
3135
ClassLoader classLoader = getClass().getClassLoader();
3236
InputStream inputStream = classLoader.getResourceAsStream(filename);
3337
Scanner scanner = new Scanner(inputStream, UTF_8.name()).useDelimiter("\\A");
@@ -58,4 +62,15 @@ public static void expectNearNumber(double expected, double actual, double epsil
5862
assertTrue(String.format("Expected %f to be near %f", actual, expected),
5963
Math.abs(expected - actual) <= epsilon);
6064
}
65+
66+
protected List<String> getResourceFolderFileNames (String folder) {
67+
ClassLoader loader = getClass().getClassLoader();
68+
URL url = loader.getResource(folder);
69+
String path = url.getPath();
70+
List<String> names = new ArrayList<>();
71+
for (File file : new File(path).listFiles()) {
72+
names.add(file.getName());
73+
}
74+
return names;
75+
}
6176
}

services-turf/src/test/java/com/mapbox/turf/TurfConversionTest.java

Lines changed: 65 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,23 @@ public class TurfConversionTest extends TestUtils {
2727
private static final String TURF_EXPLODE_MULTIPOLYGON = "turf-explode/multipolygon.geojson";
2828
private static final String TURF_EXPLODE_GEOMETRY_COLLECTION = "turf-explode/geometrycollection.geojson";
2929

30+
private static final String TURF_POLYGON_TO_LINE_PATH_IN = "turf-polygon-to-line/in/";
31+
private static final String TURF_POLYGON_TO_LINE_PATH_OUT = "turf-polygon-to-line/expected/";
32+
33+
private static final String TURF_POLYGON_TO_LINE_FILENAME_POLYGON= "polygon.geojson";
34+
private static final String TURF_POLYGON_TO_LINE_FILENAME_GEOMETRY_POLYGON= "geometry-polygon.geojson";
35+
private static final String TURF_POLYGON_TO_LINE_FILENAME_POLYGON_WITH_HOLE = "polygon-with-hole.geojson";
36+
37+
private static final String TURF_POLYGON_TO_LINE_FILENAME_MULTIPOLYGON = "multi-polygon.geojson";
38+
private static final String TURF_POLYGON_TO_LINE_FILENAME_MULTIPOLYGON_OUTER_DOUGHNUT = "multi-polygon-outer-doughnut.geojson";
39+
private static final String TURF_POLYGON_TO_LINE_FILENAME_MULTIPOLYGON_WITH_HOLES = "multi-polygon-with-holes.geojson";
40+
41+
3042
@Rule
3143
public ExpectedException thrown = ExpectedException.none();
3244

3345
@Test
34-
public void radiansToDistance() throws Exception {
46+
public void radiansToDistance() {
3547
assertEquals(
3648
1, TurfConversion.radiansToLength(1, TurfConstants.UNIT_RADIANS), DELTA);
3749
assertEquals(
@@ -41,7 +53,7 @@ public void radiansToDistance() throws Exception {
4153
}
4254

4355
@Test
44-
public void distanceToRadians() throws Exception {
56+
public void distanceToRadians() {
4557
assertEquals(
4658
1, TurfConversion.lengthToRadians(1, TurfConstants.UNIT_RADIANS), DELTA);
4759
assertEquals(
@@ -51,7 +63,7 @@ public void distanceToRadians() throws Exception {
5163
}
5264

5365
@Test
54-
public void distanceToDegrees() throws Exception {
66+
public void distanceToDegrees() {
5567
assertEquals(
5668
57.29577951308232, TurfConversion.lengthToDegrees(1, TurfConstants.UNIT_RADIANS), DELTA);
5769
assertEquals(
@@ -79,25 +91,25 @@ public void convertDistance() throws TurfException {
7991
}
8092

8193
@Test
82-
public void explodePointSingleFeature() throws IOException, NullPointerException {
94+
public void explodePointSingleFeature() throws NullPointerException {
8395
Point point = Point.fromLngLat(102, 0.5);
8496
assertEquals(1, TurfConversion.explode(Feature.fromGeometry(point)).features().size());
8597
}
8698

8799
@Test
88-
public void explodeMultiPointSingleFeature() throws IOException, NullPointerException {
100+
public void explodeMultiPointSingleFeature() throws NullPointerException {
89101
MultiPoint multiPoint = MultiPoint.fromJson(loadJsonFixture(TURF_EXPLODE_MULTI_POINT));
90102
assertEquals(4, TurfConversion.explode(Feature.fromGeometry(multiPoint)).features().size());
91103
}
92104

93105
@Test
94-
public void explodeLineStringSingleFeature() throws IOException, NullPointerException {
106+
public void explodeLineStringSingleFeature() throws NullPointerException {
95107
LineString lineString = LineString.fromJson(loadJsonFixture(TURF_EXPLODE_LINESTRING));
96108
assertEquals(4, TurfConversion.explode(Feature.fromGeometry(lineString)).features().size());
97109
}
98110

99111
@Test
100-
public void explodePolygonSingleFeature() throws IOException, NullPointerException {
112+
public void explodePolygonSingleFeature() throws NullPointerException {
101113
Polygon polygon = Polygon.fromLngLats(Arrays.asList(
102114
Arrays.asList(
103115
Point.fromLngLat(0, 101),
@@ -108,29 +120,71 @@ public void explodePolygonSingleFeature() throws IOException, NullPointerExcepti
108120
}
109121

110122
@Test
111-
public void explodeMultiLineStringSingleFeature() throws IOException, NullPointerException {
123+
public void explodeMultiLineStringSingleFeature() throws NullPointerException {
112124
MultiLineString multiLineString = MultiLineString.fromJson(loadJsonFixture(TURF_EXPLODE_MULTILINESTRING));
113125
assertEquals(4, TurfConversion.explode(Feature.fromGeometry(multiLineString)).features().size());
114126
}
115127

116128
@Test
117-
public void explodeMultiPolygonSingleFeature() throws IOException, NullPointerException {
129+
public void explodeMultiPolygonSingleFeature() throws NullPointerException {
118130
MultiPolygon multiPolygon = MultiPolygon.fromJson(loadJsonFixture(TURF_EXPLODE_MULTIPOLYGON));
119131
assertEquals(12, TurfConversion.explode(Feature.fromGeometry(multiPolygon)).features().size());
120132
}
121133

122134
@Test
123-
public void explodeGeometryCollectionSingleFeature() throws IOException, NullPointerException {
135+
public void explodeGeometryCollectionSingleFeature() throws NullPointerException {
124136
GeometryCollection geometryCollection = GeometryCollection.fromJson(loadJsonFixture(TURF_EXPLODE_GEOMETRY_COLLECTION));
125137
assertEquals(3, TurfConversion.explode(Feature.fromGeometry(geometryCollection)).features().size());
126138
}
127139

128140
@Test
129-
public void explodeFeatureCollection() throws IOException, NullPointerException {
141+
public void explodeFeatureCollection() throws NullPointerException {
130142
FeatureCollection featureCollection = FeatureCollection.fromFeatures(new Feature[] {
131143
Feature.fromGeometry(MultiLineString.fromJson(loadJsonFixture(TURF_EXPLODE_MULTILINESTRING))),
132144
Feature.fromGeometry(MultiPolygon.fromJson(loadJsonFixture(TURF_EXPLODE_MULTIPOLYGON)))
133145
});
134146
assertEquals(16, TurfConversion.explode(featureCollection).features().size());
135147
}
148+
149+
@Test
150+
public void polygonToLine_GeometryPolygon() throws NullPointerException {
151+
Polygon polygon = Polygon.fromJson(loadJsonFixture(TURF_POLYGON_TO_LINE_PATH_IN + TURF_POLYGON_TO_LINE_FILENAME_GEOMETRY_POLYGON));
152+
Feature expected = Feature.fromJson(loadJsonFixture(TURF_POLYGON_TO_LINE_PATH_OUT + TURF_POLYGON_TO_LINE_FILENAME_GEOMETRY_POLYGON));
153+
compareJson(expected.toJson(), TurfConversion.polygonToLine(polygon).toJson());
154+
}
155+
156+
@Test
157+
public void polygonToLine_Polygon() throws NullPointerException {
158+
Feature polygon = Feature.fromJson(loadJsonFixture(TURF_POLYGON_TO_LINE_PATH_IN + TURF_POLYGON_TO_LINE_FILENAME_POLYGON));
159+
Feature expected = Feature.fromJson(loadJsonFixture(TURF_POLYGON_TO_LINE_PATH_OUT + TURF_POLYGON_TO_LINE_FILENAME_POLYGON));
160+
compareJson(expected.toJson(), TurfConversion.polygonToLine(polygon).toJson());
161+
}
162+
163+
@Test
164+
public void polygonToLine_PolygonWithHole() throws NullPointerException {
165+
Feature polygon = Feature.fromJson(loadJsonFixture(TURF_POLYGON_TO_LINE_PATH_IN + TURF_POLYGON_TO_LINE_FILENAME_POLYGON_WITH_HOLE));
166+
Feature expected = Feature.fromJson(loadJsonFixture(TURF_POLYGON_TO_LINE_PATH_OUT + TURF_POLYGON_TO_LINE_FILENAME_POLYGON_WITH_HOLE));
167+
compareJson(expected.toJson(), TurfConversion.polygonToLine(polygon).toJson());
168+
}
169+
170+
@Test
171+
public void polygonToLine_MultiPolygon() throws NullPointerException {
172+
Feature multiPolygon = Feature.fromJson(loadJsonFixture(TURF_POLYGON_TO_LINE_PATH_IN + TURF_POLYGON_TO_LINE_FILENAME_MULTIPOLYGON));
173+
FeatureCollection expected = FeatureCollection.fromJson(loadJsonFixture(TURF_POLYGON_TO_LINE_PATH_OUT + TURF_POLYGON_TO_LINE_FILENAME_MULTIPOLYGON));
174+
compareJson(expected.toJson(), TurfConversion.multiPolygonToLine(multiPolygon).toJson());
175+
}
176+
177+
@Test
178+
public void polygonToLine_MultiPolygonWithHoles() throws NullPointerException {
179+
Feature multiPolygon = Feature.fromJson(loadJsonFixture(TURF_POLYGON_TO_LINE_PATH_IN + TURF_POLYGON_TO_LINE_FILENAME_MULTIPOLYGON_WITH_HOLES));
180+
FeatureCollection expected = FeatureCollection.fromJson(loadJsonFixture(TURF_POLYGON_TO_LINE_PATH_OUT + TURF_POLYGON_TO_LINE_FILENAME_MULTIPOLYGON_WITH_HOLES));
181+
compareJson(expected.toJson(), TurfConversion.multiPolygonToLine(multiPolygon).toJson());
182+
}
183+
184+
@Test
185+
public void polygonToLine_MultiPolygonWithOuterDoughnut() throws NullPointerException {
186+
Feature multiPolygon = Feature.fromJson(loadJsonFixture(TURF_POLYGON_TO_LINE_PATH_IN + TURF_POLYGON_TO_LINE_FILENAME_MULTIPOLYGON_OUTER_DOUGHNUT));
187+
FeatureCollection expected = FeatureCollection.fromJson(loadJsonFixture(TURF_POLYGON_TO_LINE_PATH_OUT + TURF_POLYGON_TO_LINE_FILENAME_MULTIPOLYGON_OUTER_DOUGHNUT));
188+
compareJson(expected.toJson(), TurfConversion.multiPolygonToLine(multiPolygon).toJson());
189+
}
136190
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
{
2+
"type": "Feature",
3+
"properties": {},
4+
"geometry": {
5+
"type": "LineString",
6+
"coordinates": [
7+
[
8+
-2.275543,
9+
53.464547
10+
],
11+
[
12+
-2.275543,
13+
53.489271
14+
],
15+
[
16+
-2.215118,
17+
53.489271
18+
],
19+
[
20+
-2.215118,
21+
53.464547
22+
],
23+
[
24+
-2.275543,
25+
53.464547
26+
]
27+
]
28+
}
29+
}

0 commit comments

Comments
 (0)