From b02af15f456334027ebccfad92f854a5d273a82b Mon Sep 17 00:00:00 2001 From: Lukas Himsel Date: Wed, 15 Dec 2021 01:42:23 +0100 Subject: [PATCH 1/3] add implementation proposals --- lib/src/geojson.dart | 65 ++++++ lib/src/geomeach_extension.dart | 112 ++++++++++ lib/src/meta.dart | 8 +- .../geomeach_class_extension_test.dart | 210 ++++++++++++++++++ test/components/geomeach_class_test.dart | 209 +++++++++++++++++ 5 files changed, 600 insertions(+), 4 deletions(-) create mode 100644 lib/src/geomeach_extension.dart create mode 100644 test/components/geomeach_class_extension_test.dart create mode 100644 test/components/geomeach_class_test.dart diff --git a/lib/src/geojson.dart b/lib/src/geojson.dart index 516effc..2797b1e 100644 --- a/lib/src/geojson.dart +++ b/lib/src/geojson.dart @@ -1,4 +1,5 @@ import 'package:json_annotation/json_annotation.dart'; +import 'package:turf/meta.dart'; part 'geojson.g.dart'; @JsonEnum(alwaysCreate: true) @@ -63,6 +64,8 @@ abstract class GeoJSONObject { toJson(); GeoJSONObject clone(); + + void geomEachImpl1(GeomEachCallback callback); } /// Coordinate types, following https://tools.ietf.org/html/rfc7946#section-4 @@ -363,11 +366,40 @@ abstract class GeometryObject extends GeoJSONObject { ? GeometryCollection.fromJson(json) : GeometryType.deserialize(json); } + + @override + void geomEachImpl1( + GeomEachCallback callback, { + Map? featureProperties, + BBox? featureBBox, + dynamic featureId, + int? featureIndex, + }); } abstract class GeometryType extends GeometryObject { T coordinates; + @override + void geomEachImpl1( + GeomEachCallback callback, { + Map? featureProperties, + BBox? featureBBox, + dynamic featureId, + int? featureIndex, + }) { + if (callback( + this, + featureIndex, + featureProperties, + featureBBox, + featureId, + ) == + false) { + throw ShortCircuit(); + } + } + GeometryType.withType(this.coordinates, GeoJSONObjectType type, {BBox? bbox}) : super.withType(type, bbox: bbox); @@ -585,6 +617,25 @@ class GeometryCollection extends GeometryObject { geometries: geometries.map((e) => e.clone()).toList(), bbox: bbox?.clone(), ); + + @override + void geomEachImpl1( + GeomEachCallback callback, { + Map? featureProperties, + BBox? featureBBox, + featureId, + int? featureIndex, + }) { + for (var geom in geometries) { + geom.geomEachImpl1( + callback, + featureProperties: featureProperties, + featureBBox: featureBBox, + featureId: featureId, + featureIndex: featureIndex, + ); + } + } } /// Feature, as specified here https://tools.ietf.org/html/rfc7946#section-3.2 @@ -661,6 +712,11 @@ class Feature extends GeoJSONObject { properties: Map.of(properties ?? {}), id: id, ); + + @override + void geomEachImpl1(GeomEachCallback callback, {int? featureIndex}) { + geometry?.geomEachImpl1(callback); + } } /// FeatureCollection, as specified here https://tools.ietf.org/html/rfc7946#section-3.3 @@ -693,4 +749,13 @@ class FeatureCollection extends GeoJSONObject { features: features.map((e) => e.clone()).toList(), bbox: bbox?.clone(), ); + + @override + void geomEachImpl1(GeomEachCallback callback) { + int featuresLength = features.length; + for (int featureIndex = 0; featureIndex < featuresLength; featureIndex++) { + features[featureIndex] + .geomEachImpl1(callback, featureIndex: featureIndex); + } + } } diff --git a/lib/src/geomeach_extension.dart b/lib/src/geomeach_extension.dart new file mode 100644 index 0000000..8e80731 --- /dev/null +++ b/lib/src/geomeach_extension.dart @@ -0,0 +1,112 @@ +import 'package:turf/src/meta.dart'; + +import '../helpers.dart'; + +extension GeomEachGeoJSONObject on GeoJSONObject { + void geomEachImpl2(GeomEachCallback callback) { + if (this is GeometryObject) { + (this as GeometryObject).geomEachImpl2(callback); + } else if (this is Feature) { + (this as Feature).geomEachImpl2(callback); + } else if (this is FeatureCollection) { + (this as FeatureCollection).geomEachImpl2(callback); + } else { + throw Exception('Unknown GeoJSON Type'); + } + } +} + +extension GeomEachGeometryObject on GeometryObject { + void geomEachImpl2( + GeomEachCallback callback, { + Map? featureProperties, + BBox? featureBBox, + dynamic featureId, + int? featureIndex, + }) { + if (this is GeometryType) { + (this as GeometryType).geomEachImpl2( + callback, + featureBBox: featureBBox, + featureId: featureId, + featureIndex: featureIndex, + featureProperties: featureProperties, + ); + } else if (this is GeometryCollection) { + (this as GeometryCollection).geomEachImpl2( + callback, + featureBBox: featureBBox, + featureId: featureId, + featureIndex: featureIndex, + featureProperties: featureProperties, + ); + } else { + throw Exception('Unknown Geometry Type'); + } + } +} + +extension GeomEachGeometryType on GeometryType { + void geomEachImpl2( + GeomEachCallback callback, { + Map? featureProperties, + BBox? featureBBox, + dynamic featureId, + int? featureIndex, + }) { + if (callback( + this, + featureIndex, + featureProperties, + featureBBox, + featureId, + ) == + false) { + throw ShortCircuit(); + } + } +} + +extension GeomEachGeometryCollection on GeometryCollection { + void geomEachImpl2( + GeomEachCallback callback, { + Map? featureProperties, + BBox? featureBBox, + featureId, + int? featureIndex, + }) { + for (var geom in geometries) { + geom.geomEachImpl2( + callback, + featureProperties: featureProperties, + featureBBox: featureBBox, + featureId: featureId, + featureIndex: featureIndex, + ); + } + } +} + +extension GeomEachFeature on Feature { + void geomEachImpl2(GeomEachCallback callback, {int? featureIndex}) { + if (geometry != null) { + (geometry as GeometryObject).geomEachImpl2( + callback, + featureBBox: bbox, + featureId: id, + featureIndex: featureIndex, + featureProperties: properties, + ); + } + } +} + +extension GeomEachFeatureCollection on FeatureCollection { + void geomEachImpl2(GeomEachCallback callback) { + int featuresLength = features.length; + for (int featureIndex = 0; featureIndex < featuresLength; featureIndex++) { + features[featureIndex] + .geomEachImpl2(callback, featureIndex: featureIndex); + } + } +} diff --git a/lib/src/meta.dart b/lib/src/meta.dart index e673cae..5d26b0f 100644 --- a/lib/src/meta.dart +++ b/lib/src/meta.dart @@ -10,8 +10,8 @@ typedef GeomEachCallback = dynamic Function( /// A simple class to manage short circuiting from *Each functions while still /// allowing an Exception to be thrown and raised -class _ShortCircuit { - _ShortCircuit(); +class ShortCircuit { + ShortCircuit(); } /// Iterate over each geometry in [geoJSON], calling [callback] on each @@ -42,7 +42,7 @@ void geomEach(GeoJSONObject geoJSON, GeomEachCallback callback) { } else { throw Exception('Unknown Geometry Type'); } - } on _ShortCircuit { + } on ShortCircuit { return; } } @@ -78,7 +78,7 @@ void _forEachGeomInGeometryObject( featureId, ) == false) { - throw _ShortCircuit(); + throw ShortCircuit(); } } else if (geometryObject is GeometryCollection) { num geometryCollectionLength = geometryObject.geometries.length; diff --git a/test/components/geomeach_class_extension_test.dart b/test/components/geomeach_class_extension_test.dart new file mode 100644 index 0000000..e0c19a6 --- /dev/null +++ b/test/components/geomeach_class_extension_test.dart @@ -0,0 +1,210 @@ +import 'package:test/test.dart'; +import 'package:turf/helpers.dart'; +import 'package:turf/src/geomeach_extension.dart'; + +Feature pt = Feature( + geometry: Point.fromJson({ + 'coordinates': [0, 0], + }), + properties: { + 'a': 1, + }, +); +Feature line = Feature( + geometry: LineString.fromJson({ + 'coordinates': [ + [0, 0], + [1, 1], + ] + }), +); +Feature multiline = Feature( + geometry: MultiLineString.fromJson({ + 'coordinates': [ + [ + [0, 0], + [1, 1], + ], + [ + [3, 3], + [4, 4], + ], + ], + }), +); +Feature geomCollection = Feature( + geometry: GeometryCollection( + geometries: [ + pt.geometry!, + line.geometry!, + multiline.geometry!, + ], + ), +); + +List collection(Feature feature) { + FeatureCollection featureCollection = FeatureCollection( + features: [ + feature, + ], + ); + return [feature, featureCollection]; +} + +List featureAndCollection(GeometryObject geometry) { + Feature feature = Feature( + geometry: geometry, + properties: { + 'a': 1, + }, + ); + FeatureCollection featureCollection = FeatureCollection( + features: [ + feature, + ], + ); + return [geometry, feature, featureCollection]; +} + +main() { + test('geomEach -- GeometryCollection', () { + featureAndCollection(geomCollection.geometry!) + .forEach((GeoJSONObject input) { + List output = []; + input.geomEachImpl2((geom, i, props, bbox, id) { + output.add(geom!); + }); + expect(output, geomCollection.geometry!.geometries); + }); + }); + + test('geomEach -- bare-GeometryCollection', () { + List output = []; + geomCollection.geomEachImpl2((geom, i, props, bbox, id) { + output.add(geom!); + }); + expect(output, geomCollection.geometry!.geometries); + }); + + test('geomEach -- bare-pointGeometry', () { + List output = []; + pt.geometry!.geomEachImpl2((geom, i, props, bbox, id) { + output.add(geom!); + }); + expect(output, [pt.geometry]); + }); + + test('geomEach -- bare-pointFeature', () { + List output = []; + pt.geomEachImpl2((geom, i, props, bbox, id) { + output.add(geom!); + }); + expect(output, [pt.geometry]); + }); + + test('geomEach -- multiGeometryFeature-properties', () { + Map? lastProperties = {}; + geomCollection.geomEachImpl2((geom, i, props, bbox, id) { + lastProperties = props; + }); + expect(lastProperties, geomCollection.properties); + }); + + test('geomEach -- callback BBox & Id', () { + Map properties = {'foo': 'bar'}; + BBox bbox = BBox.fromJson([0, 0, 0, 0, 0, 0]); + String id = 'foo'; + Feature pt = Feature( + geometry: Point.fromJson({ + 'coordinates': [0, 0], + }), + properties: properties, + bbox: bbox, + id: id, + ); + pt.geomEachImpl2( + (GeometryObject? currentGeometry, + int? featureIndex, + Map? featureProperties, + BBox? featureBBox, + dynamic featureId) { + expect(featureIndex, 0, reason: 'featureIndex'); + expect(featureProperties, properties, reason: 'featureProperties'); + expect(featureBBox, bbox, reason: 'featureBBox'); + expect(featureId, id, reason: 'featureId'); + }, + ); + }); + + test('meta -- breaking of iterations', () { + FeatureCollection lines = FeatureCollection( + features: [ + Feature( + geometry: LineString.fromJson({ + 'coordinates': [ + [10, 10], + [50, 30], + [30, 40] + ] + }), + ), + Feature( + geometry: LineString.fromJson({ + 'coordinates': [ + [-10, -10], + [-50, -30], + [-30, -40] + ] + }), + ), + ], + ); + Feature multiLine = Feature( + geometry: MultiLineString.fromJson({ + 'coordinates': [ + [ + [10, 10], + [50, 30], + [30, 40] + ], + [ + [-10, -10], + [-50, -30], + [-30, -40] + ] + ] + }), + ); + // Each Iterators + // meta.segmentEach has been purposely excluded from this list + // TODO fill out this list will all 'each' iterators + + // Meta Each function should only a value of 1 after returning `false` + // FeatureCollection + var count = 0; + lines.geomEachImpl2(( + GeometryObject? currentGeometry, + int? featureIndex, + Map? featureProperties, + BBox? featureBBox, + dynamic featureId, + ) { + count += 1; + return false; + }); + expect(count, 1, reason: 'FeatureCollection.geomEach'); + // Multi Geometry + var multiCount = 0; + multiLine.geomEachImpl2(( + GeometryObject? currentGeometry, + int? featureIndex, + Map? featureProperties, + BBox? featureBBox, + dynamic featureId, + ) { + multiCount += 1; + return false; + }); + expect(multiCount, 1, reason: 'Feature.geomEach'); + }); +} diff --git a/test/components/geomeach_class_test.dart b/test/components/geomeach_class_test.dart new file mode 100644 index 0000000..4ae73ab --- /dev/null +++ b/test/components/geomeach_class_test.dart @@ -0,0 +1,209 @@ +import 'package:test/test.dart'; +import 'package:turf/helpers.dart'; + +Feature pt = Feature( + geometry: Point.fromJson({ + 'coordinates': [0, 0], + }), + properties: { + 'a': 1, + }, +); +Feature line = Feature( + geometry: LineString.fromJson({ + 'coordinates': [ + [0, 0], + [1, 1], + ] + }), +); +Feature multiline = Feature( + geometry: MultiLineString.fromJson({ + 'coordinates': [ + [ + [0, 0], + [1, 1], + ], + [ + [3, 3], + [4, 4], + ], + ], + }), +); +Feature geomCollection = Feature( + geometry: GeometryCollection( + geometries: [ + pt.geometry!, + line.geometry!, + multiline.geometry!, + ], + ), +); + +List collection(Feature feature) { + FeatureCollection featureCollection = FeatureCollection( + features: [ + feature, + ], + ); + return [feature, featureCollection]; +} + +List featureAndCollection(GeometryObject geometry) { + Feature feature = Feature( + geometry: geometry, + properties: { + 'a': 1, + }, + ); + FeatureCollection featureCollection = FeatureCollection( + features: [ + feature, + ], + ); + return [geometry, feature, featureCollection]; +} + +main() { + test('geomEach -- GeometryCollection', () { + featureAndCollection(geomCollection.geometry!) + .forEach((GeoJSONObject input) { + List output = []; + input.geomEachImpl1((geom, i, props, bbox, id) { + output.add(geom!); + }); + expect(output, geomCollection.geometry!.geometries); + }); + }); + + test('geomEach -- bare-GeometryCollection', () { + List output = []; + geomCollection.geomEachImpl1((geom, i, props, bbox, id) { + output.add(geom!); + }); + expect(output, geomCollection.geometry!.geometries); + }); + + test('geomEach -- bare-pointGeometry', () { + List output = []; + pt.geometry!.geomEachImpl1((geom, i, props, bbox, id) { + output.add(geom!); + }); + expect(output, [pt.geometry]); + }); + + test('geomEach -- bare-pointFeature', () { + List output = []; + pt.geomEachImpl1((geom, i, props, bbox, id) { + output.add(geom!); + }); + expect(output, [pt.geometry]); + }); + + test('geomEach -- multiGeometryFeature-properties', () { + Map? lastProperties = {}; + geomCollection.geomEachImpl1((geom, i, props, bbox, id) { + lastProperties = props; + }); + expect(lastProperties, geomCollection.properties); + }); + + test('geomEach -- callback BBox & Id', () { + Map properties = {'foo': 'bar'}; + BBox bbox = BBox.fromJson([0, 0, 0, 0, 0, 0]); + String id = 'foo'; + Feature pt = Feature( + geometry: Point.fromJson({ + 'coordinates': [0, 0], + }), + properties: properties, + bbox: bbox, + id: id, + ); + pt.geomEachImpl1( + (GeometryObject? currentGeometry, + int? featureIndex, + Map? featureProperties, + BBox? featureBBox, + dynamic featureId) { + expect(featureIndex, 0, reason: 'featureIndex'); + expect(featureProperties, properties, reason: 'featureProperties'); + expect(featureBBox, bbox, reason: 'featureBBox'); + expect(featureId, id, reason: 'featureId'); + }, + ); + }); + + test('meta -- breaking of iterations', () { + FeatureCollection lines = FeatureCollection( + features: [ + Feature( + geometry: LineString.fromJson({ + 'coordinates': [ + [10, 10], + [50, 30], + [30, 40] + ] + }), + ), + Feature( + geometry: LineString.fromJson({ + 'coordinates': [ + [-10, -10], + [-50, -30], + [-30, -40] + ] + }), + ), + ], + ); + Feature multiLine = Feature( + geometry: MultiLineString.fromJson({ + 'coordinates': [ + [ + [10, 10], + [50, 30], + [30, 40] + ], + [ + [-10, -10], + [-50, -30], + [-30, -40] + ] + ] + }), + ); + // Each Iterators + // meta.segmentEach has been purposely excluded from this list + // TODO fill out this list will all 'each' iterators + + // Meta Each function should only a value of 1 after returning `false` + // FeatureCollection + var count = 0; + lines.geomEachImpl1(( + GeometryObject? currentGeometry, + int? featureIndex, + Map? featureProperties, + BBox? featureBBox, + dynamic featureId, + ) { + count += 1; + return false; + }); + expect(count, 1, reason: 'FeatureCollection.geomEach'); + // Multi Geometry + var multiCount = 0; + multiLine.geomEachImpl1(( + GeometryObject? currentGeometry, + int? featureIndex, + Map? featureProperties, + BBox? featureBBox, + dynamic featureId, + ) { + multiCount += 1; + return false; + }); + expect(multiCount, 1, reason: 'Feature.geomEach'); + }); +} From 32433250d1a4bb57d51cb8194f867985e4dbf88a Mon Sep 17 00:00:00 2001 From: Lukas Himsel Date: Thu, 16 Dec 2021 17:14:34 +0100 Subject: [PATCH 2/3] improve extensions --- lib/extensions.dart | 3 + lib/meta.dart | 2 +- lib/src/geojson.dart | 65 ------ lib/src/geomeach_extension.dart | 112 ---------- lib/src/meta.dart | 22 +- lib/src/meta_extensions.dart | 56 +++++ .../geomeach_class_extension_test.dart | 210 ------------------ ...ss_test.dart => meta_extensions_test.dart} | 17 +- 8 files changed, 79 insertions(+), 408 deletions(-) create mode 100644 lib/extensions.dart delete mode 100644 lib/src/geomeach_extension.dart create mode 100644 lib/src/meta_extensions.dart delete mode 100644 test/components/geomeach_class_extension_test.dart rename test/components/{geomeach_class_test.dart => meta_extensions_test.dart} (93%) diff --git a/lib/extensions.dart b/lib/extensions.dart new file mode 100644 index 0000000..b0022c4 --- /dev/null +++ b/lib/extensions.dart @@ -0,0 +1,3 @@ +library turf_extensions; + +export 'src/meta_extensions.dart'; diff --git a/lib/meta.dart b/lib/meta.dart index 1486f74..3be0a06 100644 --- a/lib/meta.dart +++ b/lib/meta.dart @@ -1,3 +1,3 @@ library turf_meta; -export 'src/meta.dart'; +export 'src/meta.dart' show geomEach, propEach, featureEach; diff --git a/lib/src/geojson.dart b/lib/src/geojson.dart index 2797b1e..516effc 100644 --- a/lib/src/geojson.dart +++ b/lib/src/geojson.dart @@ -1,5 +1,4 @@ import 'package:json_annotation/json_annotation.dart'; -import 'package:turf/meta.dart'; part 'geojson.g.dart'; @JsonEnum(alwaysCreate: true) @@ -64,8 +63,6 @@ abstract class GeoJSONObject { toJson(); GeoJSONObject clone(); - - void geomEachImpl1(GeomEachCallback callback); } /// Coordinate types, following https://tools.ietf.org/html/rfc7946#section-4 @@ -366,40 +363,11 @@ abstract class GeometryObject extends GeoJSONObject { ? GeometryCollection.fromJson(json) : GeometryType.deserialize(json); } - - @override - void geomEachImpl1( - GeomEachCallback callback, { - Map? featureProperties, - BBox? featureBBox, - dynamic featureId, - int? featureIndex, - }); } abstract class GeometryType extends GeometryObject { T coordinates; - @override - void geomEachImpl1( - GeomEachCallback callback, { - Map? featureProperties, - BBox? featureBBox, - dynamic featureId, - int? featureIndex, - }) { - if (callback( - this, - featureIndex, - featureProperties, - featureBBox, - featureId, - ) == - false) { - throw ShortCircuit(); - } - } - GeometryType.withType(this.coordinates, GeoJSONObjectType type, {BBox? bbox}) : super.withType(type, bbox: bbox); @@ -617,25 +585,6 @@ class GeometryCollection extends GeometryObject { geometries: geometries.map((e) => e.clone()).toList(), bbox: bbox?.clone(), ); - - @override - void geomEachImpl1( - GeomEachCallback callback, { - Map? featureProperties, - BBox? featureBBox, - featureId, - int? featureIndex, - }) { - for (var geom in geometries) { - geom.geomEachImpl1( - callback, - featureProperties: featureProperties, - featureBBox: featureBBox, - featureId: featureId, - featureIndex: featureIndex, - ); - } - } } /// Feature, as specified here https://tools.ietf.org/html/rfc7946#section-3.2 @@ -712,11 +661,6 @@ class Feature extends GeoJSONObject { properties: Map.of(properties ?? {}), id: id, ); - - @override - void geomEachImpl1(GeomEachCallback callback, {int? featureIndex}) { - geometry?.geomEachImpl1(callback); - } } /// FeatureCollection, as specified here https://tools.ietf.org/html/rfc7946#section-3.3 @@ -749,13 +693,4 @@ class FeatureCollection extends GeoJSONObject { features: features.map((e) => e.clone()).toList(), bbox: bbox?.clone(), ); - - @override - void geomEachImpl1(GeomEachCallback callback) { - int featuresLength = features.length; - for (int featureIndex = 0; featureIndex < featuresLength; featureIndex++) { - features[featureIndex] - .geomEachImpl1(callback, featureIndex: featureIndex); - } - } } diff --git a/lib/src/geomeach_extension.dart b/lib/src/geomeach_extension.dart deleted file mode 100644 index 8e80731..0000000 --- a/lib/src/geomeach_extension.dart +++ /dev/null @@ -1,112 +0,0 @@ -import 'package:turf/src/meta.dart'; - -import '../helpers.dart'; - -extension GeomEachGeoJSONObject on GeoJSONObject { - void geomEachImpl2(GeomEachCallback callback) { - if (this is GeometryObject) { - (this as GeometryObject).geomEachImpl2(callback); - } else if (this is Feature) { - (this as Feature).geomEachImpl2(callback); - } else if (this is FeatureCollection) { - (this as FeatureCollection).geomEachImpl2(callback); - } else { - throw Exception('Unknown GeoJSON Type'); - } - } -} - -extension GeomEachGeometryObject on GeometryObject { - void geomEachImpl2( - GeomEachCallback callback, { - Map? featureProperties, - BBox? featureBBox, - dynamic featureId, - int? featureIndex, - }) { - if (this is GeometryType) { - (this as GeometryType).geomEachImpl2( - callback, - featureBBox: featureBBox, - featureId: featureId, - featureIndex: featureIndex, - featureProperties: featureProperties, - ); - } else if (this is GeometryCollection) { - (this as GeometryCollection).geomEachImpl2( - callback, - featureBBox: featureBBox, - featureId: featureId, - featureIndex: featureIndex, - featureProperties: featureProperties, - ); - } else { - throw Exception('Unknown Geometry Type'); - } - } -} - -extension GeomEachGeometryType on GeometryType { - void geomEachImpl2( - GeomEachCallback callback, { - Map? featureProperties, - BBox? featureBBox, - dynamic featureId, - int? featureIndex, - }) { - if (callback( - this, - featureIndex, - featureProperties, - featureBBox, - featureId, - ) == - false) { - throw ShortCircuit(); - } - } -} - -extension GeomEachGeometryCollection on GeometryCollection { - void geomEachImpl2( - GeomEachCallback callback, { - Map? featureProperties, - BBox? featureBBox, - featureId, - int? featureIndex, - }) { - for (var geom in geometries) { - geom.geomEachImpl2( - callback, - featureProperties: featureProperties, - featureBBox: featureBBox, - featureId: featureId, - featureIndex: featureIndex, - ); - } - } -} - -extension GeomEachFeature on Feature { - void geomEachImpl2(GeomEachCallback callback, {int? featureIndex}) { - if (geometry != null) { - (geometry as GeometryObject).geomEachImpl2( - callback, - featureBBox: bbox, - featureId: id, - featureIndex: featureIndex, - featureProperties: properties, - ); - } - } -} - -extension GeomEachFeatureCollection on FeatureCollection { - void geomEachImpl2(GeomEachCallback callback) { - int featuresLength = features.length; - for (int featureIndex = 0; featureIndex < featuresLength; featureIndex++) { - features[featureIndex] - .geomEachImpl2(callback, featureIndex: featureIndex); - } - } -} diff --git a/lib/src/meta.dart b/lib/src/meta.dart index 5d26b0f..166e341 100644 --- a/lib/src/meta.dart +++ b/lib/src/meta.dart @@ -10,9 +10,7 @@ typedef GeomEachCallback = dynamic Function( /// A simple class to manage short circuiting from *Each functions while still /// allowing an Exception to be thrown and raised -class ShortCircuit { - ShortCircuit(); -} +class ShortCircuit {} /// Iterate over each geometry in [geoJSON], calling [callback] on each /// iteration. Similar to Array.forEach() @@ -34,11 +32,11 @@ class ShortCircuit { void geomEach(GeoJSONObject geoJSON, GeomEachCallback callback) { try { if (geoJSON is FeatureCollection) { - _forEachGeomInFeatureCollection(geoJSON, callback); + forEachGeomInFeatureCollection(geoJSON, callback); } else if (geoJSON is Feature) { - _forEachGeomInFeature(geoJSON, callback, 0); + forEachGeomInFeature(geoJSON, callback, 0); } else if (geoJSON is GeometryObject) { - _forEachGeomInGeometryObject(geoJSON, callback, {}, null, null, 0); + forEachGeomInGeometryObject(geoJSON, callback, {}, null, null, 0); } else { throw Exception('Unknown Geometry Type'); } @@ -47,22 +45,22 @@ void geomEach(GeoJSONObject geoJSON, GeomEachCallback callback) { } } -void _forEachGeomInFeatureCollection( +void forEachGeomInFeatureCollection( FeatureCollection featureCollection, GeomEachCallback callback) { int featuresLength = featureCollection.features.length; for (int featureIndex = 0; featureIndex < featuresLength; featureIndex++) { - _forEachGeomInFeature( + forEachGeomInFeature( featureCollection.features[featureIndex], callback, featureIndex); } } -void _forEachGeomInFeature(Feature feature, +void forEachGeomInFeature(Feature feature, GeomEachCallback callback, int featureIndex) { - _forEachGeomInGeometryObject(feature.geometry, callback, feature.properties, + forEachGeomInGeometryObject(feature.geometry, callback, feature.properties, feature.bbox, feature.id, featureIndex); } -void _forEachGeomInGeometryObject( +void forEachGeomInGeometryObject( GeometryObject? geometryObject, GeomEachCallback callback, Map? featureProperties, @@ -86,7 +84,7 @@ void _forEachGeomInGeometryObject( for (int geometryIndex = 0; geometryIndex < geometryCollectionLength; geometryIndex++) { - _forEachGeomInGeometryObject( + forEachGeomInGeometryObject( geometryObject.geometries[geometryIndex], callback, featureProperties, diff --git a/lib/src/meta_extensions.dart b/lib/src/meta_extensions.dart new file mode 100644 index 0000000..273c1bf --- /dev/null +++ b/lib/src/meta_extensions.dart @@ -0,0 +1,56 @@ +import 'package:turf/src/meta.dart' as meta; + +import '../helpers.dart'; + +extension GeomEachGeoJSONObject on GeoJSONObject { + void geomEach(meta.GeomEachCallback callback) { + meta.geomEach(this, callback); + } +} + +extension GeomEachGeometryObject on GeometryObject { + void geomEach( + meta.GeomEachCallback callback, { + Map? featureProperties, + BBox? featureBBox, + dynamic featureId, + int? featureIndex, + }) { + try { + meta.forEachGeomInGeometryObject( + this, + callback, + featureProperties, + featureBBox, + featureId, + featureIndex ?? 0, + ); + } on meta.ShortCircuit { + return; + } + } +} + +extension GeomEachFeature on Feature { + void geomEach(meta.GeomEachCallback callback, [int? featureIndex]) { + try { + meta.forEachGeomInFeature( + this, + callback, + featureIndex ?? 0, + ); + } on meta.ShortCircuit { + return; + } + } +} + +extension GeomEachFeatureCollection on FeatureCollection { + void geomEach(meta.GeomEachCallback callback) { + try { + meta.forEachGeomInFeatureCollection(this, callback); + } on meta.ShortCircuit { + return; + } + } +} diff --git a/test/components/geomeach_class_extension_test.dart b/test/components/geomeach_class_extension_test.dart deleted file mode 100644 index e0c19a6..0000000 --- a/test/components/geomeach_class_extension_test.dart +++ /dev/null @@ -1,210 +0,0 @@ -import 'package:test/test.dart'; -import 'package:turf/helpers.dart'; -import 'package:turf/src/geomeach_extension.dart'; - -Feature pt = Feature( - geometry: Point.fromJson({ - 'coordinates': [0, 0], - }), - properties: { - 'a': 1, - }, -); -Feature line = Feature( - geometry: LineString.fromJson({ - 'coordinates': [ - [0, 0], - [1, 1], - ] - }), -); -Feature multiline = Feature( - geometry: MultiLineString.fromJson({ - 'coordinates': [ - [ - [0, 0], - [1, 1], - ], - [ - [3, 3], - [4, 4], - ], - ], - }), -); -Feature geomCollection = Feature( - geometry: GeometryCollection( - geometries: [ - pt.geometry!, - line.geometry!, - multiline.geometry!, - ], - ), -); - -List collection(Feature feature) { - FeatureCollection featureCollection = FeatureCollection( - features: [ - feature, - ], - ); - return [feature, featureCollection]; -} - -List featureAndCollection(GeometryObject geometry) { - Feature feature = Feature( - geometry: geometry, - properties: { - 'a': 1, - }, - ); - FeatureCollection featureCollection = FeatureCollection( - features: [ - feature, - ], - ); - return [geometry, feature, featureCollection]; -} - -main() { - test('geomEach -- GeometryCollection', () { - featureAndCollection(geomCollection.geometry!) - .forEach((GeoJSONObject input) { - List output = []; - input.geomEachImpl2((geom, i, props, bbox, id) { - output.add(geom!); - }); - expect(output, geomCollection.geometry!.geometries); - }); - }); - - test('geomEach -- bare-GeometryCollection', () { - List output = []; - geomCollection.geomEachImpl2((geom, i, props, bbox, id) { - output.add(geom!); - }); - expect(output, geomCollection.geometry!.geometries); - }); - - test('geomEach -- bare-pointGeometry', () { - List output = []; - pt.geometry!.geomEachImpl2((geom, i, props, bbox, id) { - output.add(geom!); - }); - expect(output, [pt.geometry]); - }); - - test('geomEach -- bare-pointFeature', () { - List output = []; - pt.geomEachImpl2((geom, i, props, bbox, id) { - output.add(geom!); - }); - expect(output, [pt.geometry]); - }); - - test('geomEach -- multiGeometryFeature-properties', () { - Map? lastProperties = {}; - geomCollection.geomEachImpl2((geom, i, props, bbox, id) { - lastProperties = props; - }); - expect(lastProperties, geomCollection.properties); - }); - - test('geomEach -- callback BBox & Id', () { - Map properties = {'foo': 'bar'}; - BBox bbox = BBox.fromJson([0, 0, 0, 0, 0, 0]); - String id = 'foo'; - Feature pt = Feature( - geometry: Point.fromJson({ - 'coordinates': [0, 0], - }), - properties: properties, - bbox: bbox, - id: id, - ); - pt.geomEachImpl2( - (GeometryObject? currentGeometry, - int? featureIndex, - Map? featureProperties, - BBox? featureBBox, - dynamic featureId) { - expect(featureIndex, 0, reason: 'featureIndex'); - expect(featureProperties, properties, reason: 'featureProperties'); - expect(featureBBox, bbox, reason: 'featureBBox'); - expect(featureId, id, reason: 'featureId'); - }, - ); - }); - - test('meta -- breaking of iterations', () { - FeatureCollection lines = FeatureCollection( - features: [ - Feature( - geometry: LineString.fromJson({ - 'coordinates': [ - [10, 10], - [50, 30], - [30, 40] - ] - }), - ), - Feature( - geometry: LineString.fromJson({ - 'coordinates': [ - [-10, -10], - [-50, -30], - [-30, -40] - ] - }), - ), - ], - ); - Feature multiLine = Feature( - geometry: MultiLineString.fromJson({ - 'coordinates': [ - [ - [10, 10], - [50, 30], - [30, 40] - ], - [ - [-10, -10], - [-50, -30], - [-30, -40] - ] - ] - }), - ); - // Each Iterators - // meta.segmentEach has been purposely excluded from this list - // TODO fill out this list will all 'each' iterators - - // Meta Each function should only a value of 1 after returning `false` - // FeatureCollection - var count = 0; - lines.geomEachImpl2(( - GeometryObject? currentGeometry, - int? featureIndex, - Map? featureProperties, - BBox? featureBBox, - dynamic featureId, - ) { - count += 1; - return false; - }); - expect(count, 1, reason: 'FeatureCollection.geomEach'); - // Multi Geometry - var multiCount = 0; - multiLine.geomEachImpl2(( - GeometryObject? currentGeometry, - int? featureIndex, - Map? featureProperties, - BBox? featureBBox, - dynamic featureId, - ) { - multiCount += 1; - return false; - }); - expect(multiCount, 1, reason: 'Feature.geomEach'); - }); -} diff --git a/test/components/geomeach_class_test.dart b/test/components/meta_extensions_test.dart similarity index 93% rename from test/components/geomeach_class_test.dart rename to test/components/meta_extensions_test.dart index 4ae73ab..5d5a0b8 100644 --- a/test/components/geomeach_class_test.dart +++ b/test/components/meta_extensions_test.dart @@ -1,5 +1,6 @@ import 'package:test/test.dart'; import 'package:turf/helpers.dart'; +import 'package:turf/extensions.dart'; Feature pt = Feature( geometry: Point.fromJson({ @@ -70,7 +71,7 @@ main() { featureAndCollection(geomCollection.geometry!) .forEach((GeoJSONObject input) { List output = []; - input.geomEachImpl1((geom, i, props, bbox, id) { + input.geomEach((geom, i, props, bbox, id) { output.add(geom!); }); expect(output, geomCollection.geometry!.geometries); @@ -79,7 +80,7 @@ main() { test('geomEach -- bare-GeometryCollection', () { List output = []; - geomCollection.geomEachImpl1((geom, i, props, bbox, id) { + geomCollection.geomEach((geom, i, props, bbox, id) { output.add(geom!); }); expect(output, geomCollection.geometry!.geometries); @@ -87,7 +88,7 @@ main() { test('geomEach -- bare-pointGeometry', () { List output = []; - pt.geometry!.geomEachImpl1((geom, i, props, bbox, id) { + pt.geometry!.geomEach((geom, i, props, bbox, id) { output.add(geom!); }); expect(output, [pt.geometry]); @@ -95,7 +96,7 @@ main() { test('geomEach -- bare-pointFeature', () { List output = []; - pt.geomEachImpl1((geom, i, props, bbox, id) { + pt.geomEach((geom, i, props, bbox, id) { output.add(geom!); }); expect(output, [pt.geometry]); @@ -103,7 +104,7 @@ main() { test('geomEach -- multiGeometryFeature-properties', () { Map? lastProperties = {}; - geomCollection.geomEachImpl1((geom, i, props, bbox, id) { + geomCollection.geomEach((geom, i, props, bbox, id) { lastProperties = props; }); expect(lastProperties, geomCollection.properties); @@ -121,7 +122,7 @@ main() { bbox: bbox, id: id, ); - pt.geomEachImpl1( + pt.geomEach( (GeometryObject? currentGeometry, int? featureIndex, Map? featureProperties, @@ -181,7 +182,7 @@ main() { // Meta Each function should only a value of 1 after returning `false` // FeatureCollection var count = 0; - lines.geomEachImpl1(( + lines.geomEach(( GeometryObject? currentGeometry, int? featureIndex, Map? featureProperties, @@ -194,7 +195,7 @@ main() { expect(count, 1, reason: 'FeatureCollection.geomEach'); // Multi Geometry var multiCount = 0; - multiLine.geomEachImpl1(( + multiLine.geomEach(( GeometryObject? currentGeometry, int? featureIndex, Map? featureProperties, From d39a988aca377a8c61bacb1d08e1c77978bf8be9 Mon Sep 17 00:00:00 2001 From: Lukas Himsel Date: Mon, 20 Dec 2021 12:51:59 +0100 Subject: [PATCH 3/3] implemetation for propEach, featureEach, improve geomEach --- lib/meta.dart | 2 +- lib/src/meta.dart | 24 +-- lib/src/meta_extensions.dart | 49 +---- test/components/meta_extensions_test.dart | 210 ---------------------- 4 files changed, 18 insertions(+), 267 deletions(-) delete mode 100644 test/components/meta_extensions_test.dart diff --git a/lib/meta.dart b/lib/meta.dart index 3be0a06..1486f74 100644 --- a/lib/meta.dart +++ b/lib/meta.dart @@ -1,3 +1,3 @@ library turf_meta; -export 'src/meta.dart' show geomEach, propEach, featureEach; +export 'src/meta.dart'; diff --git a/lib/src/meta.dart b/lib/src/meta.dart index 166e341..cbcd67c 100644 --- a/lib/src/meta.dart +++ b/lib/src/meta.dart @@ -10,7 +10,7 @@ typedef GeomEachCallback = dynamic Function( /// A simple class to manage short circuiting from *Each functions while still /// allowing an Exception to be thrown and raised -class ShortCircuit {} +class _ShortCircuit {} /// Iterate over each geometry in [geoJSON], calling [callback] on each /// iteration. Similar to Array.forEach() @@ -32,35 +32,35 @@ class ShortCircuit {} void geomEach(GeoJSONObject geoJSON, GeomEachCallback callback) { try { if (geoJSON is FeatureCollection) { - forEachGeomInFeatureCollection(geoJSON, callback); + _forEachGeomInFeatureCollection(geoJSON, callback); } else if (geoJSON is Feature) { - forEachGeomInFeature(geoJSON, callback, 0); + _forEachGeomInFeature(geoJSON, callback, 0); } else if (geoJSON is GeometryObject) { - forEachGeomInGeometryObject(geoJSON, callback, {}, null, null, 0); + _forEachGeomInGeometryObject(geoJSON, callback, {}, null, null, 0); } else { throw Exception('Unknown Geometry Type'); } - } on ShortCircuit { + } on _ShortCircuit { return; } } -void forEachGeomInFeatureCollection( +void _forEachGeomInFeatureCollection( FeatureCollection featureCollection, GeomEachCallback callback) { int featuresLength = featureCollection.features.length; for (int featureIndex = 0; featureIndex < featuresLength; featureIndex++) { - forEachGeomInFeature( + _forEachGeomInFeature( featureCollection.features[featureIndex], callback, featureIndex); } } -void forEachGeomInFeature(Feature feature, +void _forEachGeomInFeature(Feature feature, GeomEachCallback callback, int featureIndex) { - forEachGeomInGeometryObject(feature.geometry, callback, feature.properties, + _forEachGeomInGeometryObject(feature.geometry, callback, feature.properties, feature.bbox, feature.id, featureIndex); } -void forEachGeomInGeometryObject( +void _forEachGeomInGeometryObject( GeometryObject? geometryObject, GeomEachCallback callback, Map? featureProperties, @@ -76,7 +76,7 @@ void forEachGeomInGeometryObject( featureId, ) == false) { - throw ShortCircuit(); + throw _ShortCircuit(); } } else if (geometryObject is GeometryCollection) { num geometryCollectionLength = geometryObject.geometries.length; @@ -84,7 +84,7 @@ void forEachGeomInGeometryObject( for (int geometryIndex = 0; geometryIndex < geometryCollectionLength; geometryIndex++) { - forEachGeomInGeometryObject( + _forEachGeomInGeometryObject( geometryObject.geometries[geometryIndex], callback, featureProperties, diff --git a/lib/src/meta_extensions.dart b/lib/src/meta_extensions.dart index 273c1bf..0872b04 100644 --- a/lib/src/meta_extensions.dart +++ b/lib/src/meta_extensions.dart @@ -2,55 +2,16 @@ import 'package:turf/src/meta.dart' as meta; import '../helpers.dart'; -extension GeomEachGeoJSONObject on GeoJSONObject { +extension GeoJSONObjectMetaExtension on GeoJSONObject { void geomEach(meta.GeomEachCallback callback) { meta.geomEach(this, callback); } -} - -extension GeomEachGeometryObject on GeometryObject { - void geomEach( - meta.GeomEachCallback callback, { - Map? featureProperties, - BBox? featureBBox, - dynamic featureId, - int? featureIndex, - }) { - try { - meta.forEachGeomInGeometryObject( - this, - callback, - featureProperties, - featureBBox, - featureId, - featureIndex ?? 0, - ); - } on meta.ShortCircuit { - return; - } - } -} -extension GeomEachFeature on Feature { - void geomEach(meta.GeomEachCallback callback, [int? featureIndex]) { - try { - meta.forEachGeomInFeature( - this, - callback, - featureIndex ?? 0, - ); - } on meta.ShortCircuit { - return; - } + void propEach(meta.PropEachCallback callback) { + meta.propEach(this, callback); } -} -extension GeomEachFeatureCollection on FeatureCollection { - void geomEach(meta.GeomEachCallback callback) { - try { - meta.forEachGeomInFeatureCollection(this, callback); - } on meta.ShortCircuit { - return; - } + void featureEach(meta.FeatureEachCallback callback) { + meta.featureEach(this, callback); } } diff --git a/test/components/meta_extensions_test.dart b/test/components/meta_extensions_test.dart deleted file mode 100644 index 5d5a0b8..0000000 --- a/test/components/meta_extensions_test.dart +++ /dev/null @@ -1,210 +0,0 @@ -import 'package:test/test.dart'; -import 'package:turf/helpers.dart'; -import 'package:turf/extensions.dart'; - -Feature pt = Feature( - geometry: Point.fromJson({ - 'coordinates': [0, 0], - }), - properties: { - 'a': 1, - }, -); -Feature line = Feature( - geometry: LineString.fromJson({ - 'coordinates': [ - [0, 0], - [1, 1], - ] - }), -); -Feature multiline = Feature( - geometry: MultiLineString.fromJson({ - 'coordinates': [ - [ - [0, 0], - [1, 1], - ], - [ - [3, 3], - [4, 4], - ], - ], - }), -); -Feature geomCollection = Feature( - geometry: GeometryCollection( - geometries: [ - pt.geometry!, - line.geometry!, - multiline.geometry!, - ], - ), -); - -List collection(Feature feature) { - FeatureCollection featureCollection = FeatureCollection( - features: [ - feature, - ], - ); - return [feature, featureCollection]; -} - -List featureAndCollection(GeometryObject geometry) { - Feature feature = Feature( - geometry: geometry, - properties: { - 'a': 1, - }, - ); - FeatureCollection featureCollection = FeatureCollection( - features: [ - feature, - ], - ); - return [geometry, feature, featureCollection]; -} - -main() { - test('geomEach -- GeometryCollection', () { - featureAndCollection(geomCollection.geometry!) - .forEach((GeoJSONObject input) { - List output = []; - input.geomEach((geom, i, props, bbox, id) { - output.add(geom!); - }); - expect(output, geomCollection.geometry!.geometries); - }); - }); - - test('geomEach -- bare-GeometryCollection', () { - List output = []; - geomCollection.geomEach((geom, i, props, bbox, id) { - output.add(geom!); - }); - expect(output, geomCollection.geometry!.geometries); - }); - - test('geomEach -- bare-pointGeometry', () { - List output = []; - pt.geometry!.geomEach((geom, i, props, bbox, id) { - output.add(geom!); - }); - expect(output, [pt.geometry]); - }); - - test('geomEach -- bare-pointFeature', () { - List output = []; - pt.geomEach((geom, i, props, bbox, id) { - output.add(geom!); - }); - expect(output, [pt.geometry]); - }); - - test('geomEach -- multiGeometryFeature-properties', () { - Map? lastProperties = {}; - geomCollection.geomEach((geom, i, props, bbox, id) { - lastProperties = props; - }); - expect(lastProperties, geomCollection.properties); - }); - - test('geomEach -- callback BBox & Id', () { - Map properties = {'foo': 'bar'}; - BBox bbox = BBox.fromJson([0, 0, 0, 0, 0, 0]); - String id = 'foo'; - Feature pt = Feature( - geometry: Point.fromJson({ - 'coordinates': [0, 0], - }), - properties: properties, - bbox: bbox, - id: id, - ); - pt.geomEach( - (GeometryObject? currentGeometry, - int? featureIndex, - Map? featureProperties, - BBox? featureBBox, - dynamic featureId) { - expect(featureIndex, 0, reason: 'featureIndex'); - expect(featureProperties, properties, reason: 'featureProperties'); - expect(featureBBox, bbox, reason: 'featureBBox'); - expect(featureId, id, reason: 'featureId'); - }, - ); - }); - - test('meta -- breaking of iterations', () { - FeatureCollection lines = FeatureCollection( - features: [ - Feature( - geometry: LineString.fromJson({ - 'coordinates': [ - [10, 10], - [50, 30], - [30, 40] - ] - }), - ), - Feature( - geometry: LineString.fromJson({ - 'coordinates': [ - [-10, -10], - [-50, -30], - [-30, -40] - ] - }), - ), - ], - ); - Feature multiLine = Feature( - geometry: MultiLineString.fromJson({ - 'coordinates': [ - [ - [10, 10], - [50, 30], - [30, 40] - ], - [ - [-10, -10], - [-50, -30], - [-30, -40] - ] - ] - }), - ); - // Each Iterators - // meta.segmentEach has been purposely excluded from this list - // TODO fill out this list will all 'each' iterators - - // Meta Each function should only a value of 1 after returning `false` - // FeatureCollection - var count = 0; - lines.geomEach(( - GeometryObject? currentGeometry, - int? featureIndex, - Map? featureProperties, - BBox? featureBBox, - dynamic featureId, - ) { - count += 1; - return false; - }); - expect(count, 1, reason: 'FeatureCollection.geomEach'); - // Multi Geometry - var multiCount = 0; - multiLine.geomEach(( - GeometryObject? currentGeometry, - int? featureIndex, - Map? featureProperties, - BBox? featureBBox, - dynamic featureId, - ) { - multiCount += 1; - return false; - }); - expect(multiCount, 1, reason: 'Feature.geomEach'); - }); -}