diff --git a/lib/envelope.dart b/lib/envelope.dart new file mode 100644 index 00000000..6fb4c636 --- /dev/null +++ b/lib/envelope.dart @@ -0,0 +1,4 @@ +library turf_envelope; + +export 'package:geotypes/geotypes.dart'; +export "src/envelope.dart"; \ No newline at end of file diff --git a/lib/src/envelope.dart b/lib/src/envelope.dart new file mode 100644 index 00000000..66e46b77 --- /dev/null +++ b/lib/src/envelope.dart @@ -0,0 +1,10 @@ +import 'package:turf/helpers.dart'; + +import 'package:turf/bbox.dart'; +import 'package:turf/bbox_polygon.dart'; + + +// Returns a rectangular Polygon (envelope) that fully contains the given GeoJSON object. +Feature envelope(GeoJSONObject geojson) { + return bboxPolygon(bbox(geojson)); +} \ No newline at end of file diff --git a/lib/turf.dart b/lib/turf.dart index 482694bb..795a35ee 100644 --- a/lib/turf.dart +++ b/lib/turf.dart @@ -13,6 +13,7 @@ export 'clean_coords.dart'; export 'clusters.dart'; export 'destination.dart'; export 'distance.dart'; +export 'envelope.dart'; export 'explode.dart'; export 'extensions.dart'; export 'helpers.dart'; diff --git a/test/components/envelope_test.dart b/test/components/envelope_test.dart new file mode 100644 index 00000000..8694acc8 --- /dev/null +++ b/test/components/envelope_test.dart @@ -0,0 +1,205 @@ +import 'package:turf/turf.dart'; +import 'package:test/test.dart'; + +void main() { + final point = Feature( + geometry: Point(coordinates: Position.named(lat: 102.0, lng: 0.5))); + + final line = Feature( + geometry: LineString(coordinates: [ + Position.named(lat: 102.0, lng: 0.5), + Position.named(lat: 103.0, lng: 1.5), + Position.named(lat: 104.0, lng: 2.5), + ], + ), + ); + + final poly = Feature( + geometry: Polygon(coordinates: [ + [ + Position.named(lat: 101.0, lng: 0.0), + Position.named(lat: 101.0, lng: 1.0), + Position.named(lat: 100.0, lng: 1.0), + Position.named(lat: 100.0, lng: 0.0), + Position.named(lat: 101.0, lng: 0.0), + ], + ], + ), + ); + + final multiLine = Feature( + geometry: MultiLineString(coordinates: [ + [ + Position.named(lat: 100.0, lng: 0.0), + Position.named(lat: 101.0, lng: 1.0), + ], + [ + Position.named(lat: 102.0, lng: 2.0), + Position.named(lat: 103.0, lng: 3.0), + ], + ], + ), + ); + + final multiPoly = Feature( + geometry: MultiPolygon(coordinates: [ + [ + [ + Position.named(lat: 102.0, lng: 2.0), + Position.named(lat: 103.0, lng: 2.0), + Position.named(lat: 103.0, lng: 3.0), + Position.named(lat: 102.0, lng: 3.0), + Position.named(lat: 102.0, lng: 2.0), + ], + ], + [ + [ + Position.named(lat: 100.0, lng: 0.0), + Position.named(lat: 101.0, lng: 0.0), + Position.named(lat: 101.0, lng: 1.0), + Position.named(lat: 100.0, lng: 1.0), + Position.named(lat: 100.0, lng: 0.0), + ], + [ + Position.named(lat: 100.2, lng: 0.2), + Position.named(lat: 100.8, lng: 0.2), + Position.named(lat: 100.8, lng: 0.8), + Position.named(lat: 100.2, lng: 0.8), + Position.named(lat: 100.2, lng: 0.2), + ], + ], + ], + ), + ); + + final fc = + FeatureCollection(features: [point, line, poly, multiLine, multiPoly]); + + test("envelope for point", () { + // Point + final pointEnvelope = envelope(point); + expect( + pointEnvelope, + equals(Feature( + geometry: Polygon(coordinates: [ + [ + Position.named(lat: 102.0, lng: 0.5), + Position.named(lat: 102.0, lng: 0.5), + Position.named(lat: 102.0, lng: 0.5), + Position.named(lat: 102.0, lng: 0.5), + Position.named(lat: 102.0, lng: 0.5), + ] + ]) + )), + reason: "point", + ); + }); + + test("envelope for linestring", () { + // LineString + final lineEnvelope = envelope(line); + + // Directly use the expected envelope in the expect call + expect( + lineEnvelope, + equals(Feature( + geometry: Polygon(coordinates: [ + [ + Position.named(lat: 102.0, lng: 0.5), + Position.named(lat: 104.0, lng: 0.5), + Position.named(lat: 104.0, lng: 2.5), + Position.named(lat: 102.0, lng: 2.5), + Position.named(lat: 102.0, lng: 0.5), + ] + ]), + )), + reason: "LineString", + ); + }); + + test("envelope for polygon", () { + // Point + final polyEnvelope = envelope(poly); + expect( + polyEnvelope, + equals(Feature( + geometry: Polygon(coordinates: [ + [ + Position.named(lat: 100.0, lng: 0.0), + Position.named(lat: 101.0, lng: 0.0), + Position.named(lat: 101.0, lng: 1.0), + Position.named(lat: 100.0, lng: 1.0), + Position.named(lat: 100.0, lng: 0.0), + ] + ]) + )), + reason: "polygon", + ); + }); + + test("envelope for multilinestring", () { + // MultiLineString + final multiLineEnvelope = envelope(multiLine); + + // Directly use the expected envelope in the expect call + expect( + multiLineEnvelope, + equals(Feature( + geometry: Polygon(coordinates: [ + [ + Position.named(lat: 100.0, lng: 0.0), + Position.named(lat: 103.0, lng: 0.0), + Position.named(lat: 103.0, lng: 3.0), + Position.named(lat: 100.0, lng: 3.0), + Position.named(lat: 100.0, lng: 0.0), + ] + ]), + )), + reason: "MultiLineString", + ); + }); + + test("envelope for multipolygon", () { + // MultiPolygon + final multiPolyEnvelope = envelope(multiPoly); + + // Directly use the expected envelope in the expect call + expect( + multiPolyEnvelope, + equals(Feature( + geometry: Polygon(coordinates: [ + [ + Position.named(lat: 100.0, lng: 0.0), + Position.named(lat: 103.0, lng: 0.0), + Position.named(lat: 103.0, lng: 3.0), + Position.named(lat: 100.0, lng: 3.0), + Position.named(lat: 100.0, lng: 0.0), + ] + ]), + )), + reason: "MultiPolygon", + ); + }); + + test("envelope for featureCollection", () { + final fcEnvelope = envelope(fc); + + // The envelope should be a polygon that represents the minimum bounding rectangle + // containing all features in the collection + expect( + fcEnvelope, + equals(Feature( + geometry: Polygon(coordinates: [ + [ + Position.named(lat: 100.0, lng: 0.0), + Position.named(lat: 104.0, lng: 0.0), + Position.named(lat: 104.0, lng: 3.0), + Position.named(lat: 100.0, lng: 3.0), + Position.named(lat: 100.0, lng: 0.0), + ] + ]), + )), + reason: "FeatureCollection", + ); + }); +} \ No newline at end of file diff --git a/test/examples/envelope/geometryCollection.json b/test/examples/envelope/geometryCollection.json new file mode 100644 index 00000000..96d9abb7 --- /dev/null +++ b/test/examples/envelope/geometryCollection.json @@ -0,0 +1,57 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "geometry": { + "type": "GeometryCollection", + "geometries": [ + { + "type": "Point", + "coordinates": [100.0, 0.0] + }, + { + "type": "LineString", + "coordinates": [ + [100.0, 0.0], + [101.0, 1.0] + ] + }, + { + "type": "Polygon", + "coordinates": [ + [ + [101.0, 0.0], + [102.0, 0.0], + [102.0, 1.0], + [101.0, 1.0], + [101.0, 0.0] + ] + ] + } + ] + }, + "properties": { + "name": "GeometryCollection" + } + }, + { + "type": "Feature", + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [100.0, 0.0], + [102.0, 0.0], + [102.0, 1.0], + [100.0, 1.0], + [100.0, 0.0] + ] + ] + }, + "properties": { + "name": "GeometryCollection Envelope" + } + } + ] +} \ No newline at end of file diff --git a/test/examples/envelope/lineString.geojson b/test/examples/envelope/lineString.geojson new file mode 100644 index 00000000..6119ff0d --- /dev/null +++ b/test/examples/envelope/lineString.geojson @@ -0,0 +1,36 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "geometry": { + "type": "LineString", + "coordinates": [ + [100.0, 0.0], + [101.0, 1.0] + ] + }, + "properties": { + "name": "LineString" + } + }, + { + "type": "Feature", + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [100.0, 0.0], + [101.0, 0.0], + [101.0, 1.0], + [100.0, 1.0], + [100.0, 0.0] + ] + ] + }, + "properties": { + "name": "LineString Envelope" + } + } + ] +} \ No newline at end of file diff --git a/test/examples/envelope/multiLineString.geojson b/test/examples/envelope/multiLineString.geojson new file mode 100644 index 00000000..1ce24d68 --- /dev/null +++ b/test/examples/envelope/multiLineString.geojson @@ -0,0 +1,42 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "geometry": { + "type": "MultiLineString", + "coordinates": [ + [ + [100.0, 0.0], + [101.0, 1.0] + ], + [ + [102.0, 2.0], + [103.0, 3.0] + ] + ] + }, + "properties": { + "name": "MultiLineString" + } + }, + { + "type": "Feature", + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [100.0, 0.0], + [103.0, 0.0], + [103.0, 3.0], + [100.0, 3.0], + [100.0, 0.0] + ] + ] + }, + "properties": { + "name": "MultiLineString Envelope" + } + } + ] +} \ No newline at end of file diff --git a/test/examples/envelope/multiPoint.geojson b/test/examples/envelope/multiPoint.geojson new file mode 100644 index 00000000..ff40d4c7 --- /dev/null +++ b/test/examples/envelope/multiPoint.geojson @@ -0,0 +1,38 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "geometry": { + "type": "MultiPoint", + "coordinates": [ + [100.0, 0.0], + [101.0, 0.0], + [101.0, 1.0], + [100.0, 1.0] + ] + }, + "properties": { + "name": "MultiPoint" + } + }, + { + "type": "Feature", + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [100.0, 0.0], + [101.0, 0.0], + [101.0, 1.0], + [100.0, 1.0], + [100.0, 0.0] + ] + ] + }, + "properties": { + "name": "MultiPoint Envelope" + } + } + ] +} \ No newline at end of file diff --git a/test/examples/envelope/multiPolygon.geojson b/test/examples/envelope/multiPolygon.geojson new file mode 100644 index 00000000..313251f1 --- /dev/null +++ b/test/examples/envelope/multiPolygon.geojson @@ -0,0 +1,52 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + [ + [ + [100.0, 0.0], + [101.0, 0.0], + [101.0, 1.0], + [100.0, 1.0], + [100.0, 0.0] + ] + ], + [ + [ + [102.0, 2.0], + [103.0, 2.0], + [103.0, 3.0], + [102.0, 3.0], + [102.0, 2.0] + ] + ] + ] + }, + "properties": { + "name": "MultiPolygon" + } + }, + { + "type": "Feature", + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [100.0, 0.0], + [103.0, 0.0], + [103.0, 3.0], + [100.0, 3.0], + [100.0, 0.0] + ] + ] + }, + "properties": { + "name": "MultiPolygon Envelope" + } + } + ] +} \ No newline at end of file diff --git a/test/examples/envelope/point.geojson b/test/examples/envelope/point.geojson new file mode 100644 index 00000000..2c927866 --- /dev/null +++ b/test/examples/envelope/point.geojson @@ -0,0 +1,33 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [102.0, 0.5] + }, + "properties": { + "name": "Point" + } + }, + { + "type": "Feature", + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [102.0, 0.5], + [102.1, 0.5], + [102.1, 0.6], + [102.0, 0.6], + [102.0, 0.5] + ] + ] + }, + "properties": { + "name": "Point Envelope" + } + } + ] +} \ No newline at end of file diff --git a/test/examples/envelope/polygon.geojson b/test/examples/envelope/polygon.geojson new file mode 100644 index 00000000..908edee1 --- /dev/null +++ b/test/examples/envelope/polygon.geojson @@ -0,0 +1,48 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [100.0, 0.0], + [101.0, 0.0], + [101.0, 1.0], + [100.0, 1.0], + [100.0, 0.0] + ], + [ + [100.2, 0.2], + [100.8, 0.2], + [100.8, 0.8], + [100.2, 0.8], + [100.2, 0.2] + ] + ] + }, + "properties": { + "name": "Polygon" + } + }, + { + "type": "Feature", + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [100.0, 0.0], + [101.0, 0.0], + [101.0, 1.0], + [100.0, 1.0], + [100.0, 0.0] + ] + ] + }, + "properties": { + "name": "Polygon Envelope" + } + } + ] +} \ No newline at end of file