From 2288fa24c88c286cdfeff63fcfe16c1ae0d3a73b Mon Sep 17 00:00:00 2001 From: armantorkzaban Date: Mon, 11 Apr 2022 21:44:17 +0200 Subject: [PATCH 01/82] in process - early analysis of the work --- test/components/meta_test.dart | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/test/components/meta_test.dart b/test/components/meta_test.dart index 2fe18aef..c9c00fad 100644 --- a/test/components/meta_test.dart +++ b/test/components/meta_test.dart @@ -1,5 +1,3 @@ -import 'dart:math'; - import 'package:test/test.dart'; import 'package:turf/helpers.dart'; import 'package:turf/meta.dart'; @@ -663,7 +661,7 @@ main() { // Each Iterators // meta.segmentEach has been purposely excluded from this list - // TODO fill out this list will all 'each' iterators + // TODO fill out this list with all 'each' iterators test('geomEach', () { runBreakingIterationTest(geomEach, (geom, i, props, bbox, id) { iterationCount += 1; From f83a14a9df981521441647330a459dbc049b81d2 Mon Sep 17 00:00:00 2001 From: armantorkzaban Date: Tue, 12 Apr 2022 08:41:09 +0200 Subject: [PATCH 02/82] linked the meta functions in readme --- README.md | 46 ++++++++++++++++++++++++---------------------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index d12d5c19..a2854e4e 100644 --- a/README.md +++ b/README.md @@ -10,9 +10,6 @@ This includes a fully [RFC 7946](https://tools.ietf.org/html/rfc7946)-compliant Most of the implementation is a direct translation from [turf.js](https://github.com/Turfjs/turf). -## GeoJSON Object Model - -![polymorphism](https://user-images.githubusercontent.com/10634693/159876354-f9da2f37-02b3-4546-b32a-c0f82c372272.png) ## Notable Design Decisions - Nested `GeometryCollections` (as described in @@ -71,6 +68,7 @@ Any new benchmarks must be named `*_benchmark.dart` and reside in the - [ ] dissolve - [ ] intersect - [ ] lineOffset +- [ ] polygonSmooth - [ ] simplify - [ ] tesselate - [ ] transformRotate @@ -88,12 +86,13 @@ Any new benchmarks must be named `*_benchmark.dart` and reside in the - [ ] polygonToLine ### MISC +- [ ] ellipse - [ ] kinks - [ ] lineArc - [ ] lineChunk - [ ] lineIntersect - [ ] lineOverlap -- [x] lineSegment +- [ ] lineSegment - [ ] lineSlice - [ ] lineSliceAlong - [ ] lineSplit @@ -138,24 +137,25 @@ Any new benchmarks must be named `*_benchmark.dart` and reside in the - [ ] clustersKmeans ### META -- [x] coordAll -- [x] coordEach -- [x] coordReduce -- [x] [featureEach](https://github.com/dartclub/turf_dart/blob/main/lib/src/meta.dart#L157) -- [x] featureReduce -- [x] [flattenEach](https://github.com/dartclub/turf_dart/blob/main/lib/src/meta.dart#L181) -- [x] flattenReduce -- [x] getCoord -- [x] getCoords -- [x] [geomEach](https://github.com/dartclub/turf_dart/blob/main/lib/src/meta.dart#L34) -- [x] geomReduce -- [x] [propEach](https://github.com/dartclub/turf_dart/blob/main/lib/src/meta.dart#L124) -- [x] propReduce -- [x] segmentEach -- [x] segmentReduce -- [ ] getCluster -- [ ] clusterEach -- [ ] clusterReduce + +- [x] [coordAll](https://github.com/dartclub/turf_dart/blob/main/lib/src/meta/coord.dart) +- [x] [coordEach](https://github.com/dartclub/turf_dart/blob/main/lib/src/meta/coord.dart) +- [x] [coordReduce](https://github.com/dartclub/turf_dart/blob/main/lib/src/meta/coord.dart) +- [x] [featureEach](https://github.com/dartclub/turf_dart/blob/main/lib/src/meta/feature.dart) +- [x] [featureReduce](https://github.com/dartclub/turf_dart/blob/main/lib/src/meta/feature.dart) +- [x] [flattenEach](https://github.com/dartclub/turf_dart/blob/main/lib/src/meta/flatten.dart) +- [x] [flattenReduce](https://github.com/dartclub/turf_dart/blob/main/lib/src/meta/flatten.dart) +- [x] [getCoord](https://github.com/dartclub/turf_dart/blob/main/lib/src/meta/coord.dart) +- [x] [getCoords](https://github.com/dartclub/turf_dart/blob/main/lib/src/meta/coord.dart) +- [x] [geomEach](https://github.com/dartclub/turf_dart/blob/main/lib/src/meta/geom.dart) +- [x] [geomReduce](https://github.com/dartclub/turf_dart/blob/main/lib/src/meta/geom.dart) +- [x] [propEach](https://github.com/dartclub/turf_dart/blob/main/lib/src/meta/prop.dart) +- [x] [propReduce](https://github.com/dartclub/turf_dart/blob/main/lib/src/meta/prop.dart) +- [x] [segmentEach](https://github.com/dartclub/turf_dart/blob/main/lib/src/line_segment.dart) +- [x] [segmentReduce](https://github.com/dartclub/turf_dart/blob/main/lib/src/line_segment.dart) +- [x] [getCluster](https://github.com/dartclub/turf_dart/blob/main/lib/src/meta/cluster.dart) +- [x] [clusterEach](https://github.com/dartclub/turf_dart/blob/main/lib/src/meta/cluster.dart) +- [x] [clusterReduce](https://github.com/dartclub/turf_dart/blob/main/lib/src/meta/cluster.dart) ### Assertions - [ ] collectionOf @@ -165,10 +165,12 @@ Any new benchmarks must be named `*_benchmark.dart` and reside in the ### Booleans - [ ] booleanClockwise +- [ ] booleanConcave - [ ] booleanContains - [ ] booleanCrosses - [ ] booleanDisjoint - [ ] booleanEqual +- [ ] booleanIntersects - [ ] booleanOverlap - [ ] booleanParallel - [ ] booleanPointInPolygon From fe1c0441fc37b07d0f2095c2b79d7360e57a7376 Mon Sep 17 00:00:00 2001 From: armantorkzaban Date: Tue, 12 Apr 2022 11:27:09 +0200 Subject: [PATCH 03/82] CONTRIBUTING.md --- CONTRIBUTING.md | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..11b3130a --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,40 @@ +# Contributiung to Turf.dart + +Welcome and thank you for deciding to contribute to the project! + +Here is how cooperation works perfectly at [Turf Dart](https://github.com/dartclub/turf_dart) +#### Table of Contents + - [Code of Conduct](#code-of-conduct) + - [Get started](#get-started) + - [Implementation Process](#implementation-process) + - [Documentation](#documentation) + +## Code of conduct +By participating, you are expected to uphold international human rights and fundamental freedoms! +To put it simply, be kind to each other. + +## Get started +- Get the [tools](https://dart.dev/tools) +- Clone the repository: ```git clone git@github.com:dartclub/turf_dart.git``` +- Navigate to project's folder in terminal & get its dependencies: ```Dart pub get``` +- Go through [Implementation Process](#implementation-process) + +## Implementation process +- Check the Backlog/Issues for similar issues +- Create a new branch _feature-_ from _main_ +- Create a _draft Pull request_, mention in it the associated issues +- **Implement** + - Document everything [properly](#documentation) + - **Write tests** + - **Get benchmarks** +- commit +- Convert to real Pull request _ready for review_ +- Code review / mention a reviewer from [contributors list](https://github.com/dartclub/turf_dart/graphs/contributors) + + +## Documentation +We follow [Effective Dart](https://dart.dev/guides/language/effective-dart/documentation) guidelines for documentation. + +After going through the [Implementation Process](#implementation-process) mentione the made changes in [README.md](https://github.com/dartclub/turf_dart/blob/main/README.md) + +In order to add to this very documentation develop contributing.me in [documentation branch](https://github.com/dartclub/turf_dart/tree/documentation) From 501b3931ab5c3173c5f33b43c32139e535431d23 Mon Sep 17 00:00:00 2001 From: armantorkzaban Date: Tue, 12 Apr 2022 11:37:36 +0200 Subject: [PATCH 04/82] links to the sources --- CONTRIBUTING.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 11b3130a..dedd8f8b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -25,9 +25,11 @@ To put it simply, be kind to each other. - Create a _draft Pull request_, mention in it the associated issues - **Implement** - Document everything [properly](#documentation) - - **Write tests** - - **Get benchmarks** -- commit + - **Write [tests](https://dart.dev/guides/testing)**―Keep an eye on [Turfjs'](https://github.com/Turfjs/turf) implementation + - run the the test: ```dart test test/components/XXX.dart``` + - **Write [benchmarks](https://pub.dev/packages/benchmark)**―have a look at our [implementation](https://github.com/dartclub/turf_dart/tree/main/benchmark) + - run the benchmark: ```pub run benchmark``` +- Commit - Convert to real Pull request _ready for review_ - Code review / mention a reviewer from [contributors list](https://github.com/dartclub/turf_dart/graphs/contributors) From 15a6312ef0e98715d9d4500a7eac917d038c66db Mon Sep 17 00:00:00 2001 From: armantorkzaban Date: Tue, 12 Apr 2022 11:39:58 +0200 Subject: [PATCH 05/82] edited typos --- CONTRIBUTING.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index dedd8f8b..a526bbc5 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -37,6 +37,6 @@ To put it simply, be kind to each other. ## Documentation We follow [Effective Dart](https://dart.dev/guides/language/effective-dart/documentation) guidelines for documentation. -After going through the [Implementation Process](#implementation-process) mentione the made changes in [README.md](https://github.com/dartclub/turf_dart/blob/main/README.md) +After going through the [Implementation Process](#implementation-process), please mention the made changes in [README.md](https://github.com/dartclub/turf_dart/blob/main/README.md) -In order to add to this very documentation develop contributing.me in [documentation branch](https://github.com/dartclub/turf_dart/tree/documentation) +In order to add to this very documentation, please develop CONTRIBUTING.md in [documentation branch](https://github.com/dartclub/turf_dart/tree/documentation) From b2d66a6b132e1ac88722d1245f5941a3b02afda9 Mon Sep 17 00:00:00 2001 From: armantorkzaban Date: Thu, 14 Apr 2022 10:07:42 +0200 Subject: [PATCH 06/82] documentation work --- lib/src/bearing.dart | 20 ++++++++++++++++++++ lib/src/destination.dart | 19 +++++++++++++++++++ lib/src/distance.dart | 14 ++++++++++++++ lib/src/helpers.dart | 19 +++++++++++++++++++ lib/src/invariant.dart | 3 ++- lib/src/line_segment.dart | 4 +--- lib/src/meta/feature.dart | 1 - lib/src/midpoint.dart | 14 ++++++++++++++ lib/src/nearest_point.dart | 23 +++++++++++++++++++++++ lib/turf.dart | 3 --- test/components/meta_test.dart | 1 - 11 files changed, 112 insertions(+), 9 deletions(-) diff --git a/lib/src/bearing.dart b/lib/src/bearing.dart index 615a260e..f979375b 100644 --- a/lib/src/bearing.dart +++ b/lib/src/bearing.dart @@ -3,6 +3,9 @@ import 'dart:math'; import 'geojson.dart'; import 'helpers.dart'; +// http://en.wikipedia.org/wiki/Haversine_formula +// http://www.movable-type.co.uk/scripts/latlong.html + num bearingRaw(Position start, Position end, {bool calcFinal = false}) { // Reverse calculation if (calcFinal == true) { @@ -19,6 +22,22 @@ num bearingRaw(Position start, Position end, {bool calcFinal = false}) { return radiansToDegrees(atan2(a, b)); } +/// Takes two [Point]s and finds the geographic bearing between them, +/// i.e. the angle measured in degrees from the north line (0 degrees) +/// For example: +/// +/// ```dart +/// var point1 = Point(coordinates: Position(-75.343, 39.984)); +/// var point2 = Point(coordinates: Position((-75.543, 39.123)); +/// +/// var bearing = bearing(point1, point2); +/// //addToMap +/// var addToMap = [point1, point2] +/// point1.properties['marker-color'] = '#f00' +/// point2.properties['marker-color'] = '#0f0' +/// point1.properties.bearing = bearing +/// ``` + num bearing(Point start, Point end, {bool calcFinal = false}) => bearingRaw(start.coordinates, end.coordinates, calcFinal: calcFinal); @@ -28,5 +47,6 @@ num calculateFinalBearingRaw(Position start, Position end) { return reverseBearing.remainder(360); } +/// Calculates Final Bearing num calculateFinalBearing(Point start, Point end) => calculateFinalBearingRaw(start.coordinates, end.coordinates); diff --git a/lib/src/destination.dart b/lib/src/destination.dart index 78c805cc..48461b98 100644 --- a/lib/src/destination.dart +++ b/lib/src/destination.dart @@ -22,6 +22,25 @@ Position destinationRaw(Position origin, num distance, num bearing, ); } +/// Takes a [Point] and calculates the location of a destination point given a distance in +/// degrees, radians, miles, or kilometers; and bearing in degrees. +/// This uses the [Haversine formula](http://en.wikipedia.org/wiki/Haversine_formula) to account for global curvature. +/// For example: +/// +/// ```dart +/// var point = Point(coordinates: Position(-75.343, 39.984)); +/// var distance = 50; +/// var bearing = 90; +/// var options = Unit.miles; +/// +/// var destination = destination(point, distance, bearing, options); +/// +/// //addToMap +/// var addToMap = [point, destination] +/// destination.properties['marker-color'] = '#f00'; +/// point.properties['marker-color'] = '#0f0'; +/// ``` + Point destination(Point origin, num distance, num bearing, [Unit unit = Unit.kilometers]) => Point( diff --git a/lib/src/distance.dart b/lib/src/distance.dart index bfe11820..f8bd5267 100644 --- a/lib/src/distance.dart +++ b/lib/src/distance.dart @@ -3,6 +3,9 @@ import 'dart:math'; import 'geojson.dart'; import 'helpers.dart'; +//http://en.wikipedia.org/wiki/Haversine_formula +//http://www.movable-type.co.uk/scripts/latlong.html + num distanceRaw(Position from, Position to, [Unit unit = Unit.kilometers]) { var dLat = degreesToRadians((to.lat - from.lat)); var dLon = degreesToRadians((to.lng - from.lng)); @@ -14,5 +17,16 @@ num distanceRaw(Position from, Position to, [Unit unit = Unit.kilometers]) { return radiansToLength(2 * atan2(sqrt(a), sqrt(1 - a)), unit); } +/// Calculates the distance between two [Point]s in degrees, radians, miles, or kilometers. +/// This uses the [Haversine formula](http://en.wikipedia.org/wiki/Haversine_formula) to account for global curvature. +/// For example: +/// +/// ```dart +/// var from = Point(coordinates: Position(-75.343, 39.984)); +/// var to = Point(coordinates: Position(-75.443, 39.984)); +/// var options = Unit.miles; +/// +/// var distance = distance(from, to, options); +/// ``` num distance(Point from, Point to, [Unit unit = Unit.kilometers]) => distanceRaw(from.coordinates, to.coordinates, unit); diff --git a/lib/src/helpers.dart b/lib/src/helpers.dart index a2f6115d..f83f7212 100644 --- a/lib/src/helpers.dart +++ b/lib/src/helpers.dart @@ -30,8 +30,11 @@ enum Corner { centroid, } +/// Earth Radius used with the Harvesine formula and approximates using a spherical (non-ellipsoid) Earth. const earthRadius = 6371008.8; +/// Unit of measurement factors using a spherical (non-ellipsoid) earth radius. +/// Keys are the name of the unit, values are the number of that unit in a single radian const factors = { Unit.centimeters: earthRadius * 100, Unit.degrees: earthRadius / 111325, @@ -60,6 +63,7 @@ const unitsFactors = { Unit.yards: 1 / 1.0936, }; +/// Area of measurement factors based on 1 square meter. const areaFactors = { Unit.acres: 0.000247105, Unit.centimeters: 10000, @@ -72,6 +76,7 @@ const areaFactors = { Unit.yards: 1.195990046, }; +/// Round number to precision num round(num value, [num precision = 0]) { if (!(precision >= 0)) { throw Exception("precision must be a positive number"); @@ -81,6 +86,8 @@ num round(num value, [num precision = 0]) { return result.round() / multiplier; } +/// Convert a distance measurement (assuming a spherical Earth) from radians to a more friendly unit. +/// Valid units: miles, nauticalmiles, inches, yards, meters, metres, kilometers, centimeters, feet num radiansToLength(num radians, [Unit unit = Unit.kilometers]) { var factor = factors[unit]; if (factor == null) { @@ -89,6 +96,8 @@ num radiansToLength(num radians, [Unit unit = Unit.kilometers]) { return radians * factor; } +/// Convert a distance measurement (assuming a spherical Earth) from a real-world unit into radians +/// Valid units: miles, nauticalmiles, inches, yards, meters, metres, kilometers, centimeters, feet num lengthToRadians(num distance, [Unit unit = Unit.kilometers]) { num? factor = factors[unit]; if (factor == null) { @@ -97,10 +106,14 @@ num lengthToRadians(num distance, [Unit unit = Unit.kilometers]) { return distance / factor; } +/// Convert a distance measurement (assuming a spherical Earth) from a real-world unit into degrees +/// Valid units: miles, nauticalmiles, inches, yards, meters, metres, centimeters, kilometres, feet num lengthToDegrees(num distance, [Unit unit = Unit.kilometers]) { return radiansToDegrees(lengthToRadians(distance, unit)); } +/// Converts any bearing angle from the north line direction (positive clockwise) +/// and returns an angle between 0-360 degrees (positive clockwise), 0 being the north line num bearingToAzimuth(num bearing) { num angle = bearing.remainder(360); if (angle < 0) { @@ -109,16 +122,20 @@ num bearingToAzimuth(num bearing) { return angle; } +/// Converts an angle in radians to degrees num radiansToDegrees(num radians) { num degrees = radians.remainder(2 * pi); return degrees * 180 / pi; } +/// Converts an angle in degrees to radians num degreesToRadians(num degrees) { num radians = degrees.remainder(360); return radians * pi / 180; } +/// Converts a length to the requested unit. +/// Valid units: miles, nauticalmiles, inches, yards, meters, metres, kilometers, centimeters, feet num convertLength( num length, [ Unit originalUnit = Unit.kilometers, @@ -130,6 +147,8 @@ num convertLength( return radiansToLength(lengthToRadians(length, originalUnit), finalUnit); } +/// Converts a area to the requested unit. +/// Valid units: kilometers, kilometres, meters, metres, centimetres, millimeters, acres, miles, yards, feet, inches, hectares num convertArea(num area, [originalUnit = Unit.meters, finalUnit = Unit.kilometers]) { if (area < 0) { diff --git a/lib/src/invariant.dart b/lib/src/invariant.dart index 2cf0859e..3303e25d 100644 --- a/lib/src/invariant.dart +++ b/lib/src/invariant.dart @@ -26,11 +26,12 @@ Position getCoord(dynamic coord) { throw Exception("coord must be GeoJSON Point or Position"); } -/// Unwrap coordinates from a [Feature], [GeometryObject] or a [List] +/// Unwraps coordinates from a [Feature], [GeometryObject] or a [List] /// /// Gets a [List], [GeometryObject] or a [Feature] or a [List] and /// returns [List]. /// For example: +/// /// ```dart /// var polygon = Polygon(coordinates: [ /// [ diff --git a/lib/src/line_segment.dart b/lib/src/line_segment.dart index 75523238..c9db26a3 100644 --- a/lib/src/line_segment.dart +++ b/lib/src/line_segment.dart @@ -3,8 +3,6 @@ import 'package:turf/src/meta/flatten.dart'; import 'geojson.dart'; -// export default lineSegment; - /// Creates a [FeatureCollection] of 2-vertex [LineString] segments from a /// [LineString] or [MultiLineString] or [Polygon] and [MultiPolygon] /// Returns [FeatureCollection] 2-vertex line segments @@ -210,7 +208,7 @@ typedef T? SegmentReduceCallback( int segmentIndex, ); -/// Reduce 2-vertex line segment in any GeoJSON object, similar to [Iterable.reduce]() +/// Reduces 2-vertex line segment in any GeoJSON object, similar to [Iterable.reduce]() /// (Multi)Point geometries do not contain segments therefore they are ignored during this operation. /// /// Takes [FeatureCollection], [Feature], [GeoJSONObject], a diff --git a/lib/src/meta/feature.dart b/lib/src/meta/feature.dart index 46aa79b5..c1b033c0 100644 --- a/lib/src/meta/feature.dart +++ b/lib/src/meta/feature.dart @@ -8,7 +8,6 @@ typedef FeatureEachCallback = dynamic Function( /// Iterates over features in any [geoJSONObject], calling [callback] on each /// iteration. Similar to [Iterable.forEach]. -/// /// For example: /// /// ```dart diff --git a/lib/src/midpoint.dart b/lib/src/midpoint.dart index ec6aef1f..71764572 100644 --- a/lib/src/midpoint.dart +++ b/lib/src/midpoint.dart @@ -11,6 +11,20 @@ Position midpointRaw(Position point1, Position point2) { return midpoint; } +/// Takes two [Point]s and returns a point midway between them. +/// The midpoint is calculated geodesically, meaning the curvature of the earth is taken into account. +/// For example: +/// +/// ``` +/// var point1 = Point(coordinates: Position(-75.343, 39.984)); +/// var point2 = Point(coordinates: Position((-75.543, 39.123)); +/// +/// var midpoint = midpoint(point1, point2); +/// +/// //addToMap +/// var addToMap = [point1, point2, midpoint]; +/// midpoint.properties['marker-color'] = '#f00'; +/// ``` Point midpoint(Point point1, Point point2) => Point( coordinates: midpointRaw(point1.coordinates, point2.coordinates), ); diff --git a/lib/src/nearest_point.dart b/lib/src/nearest_point.dart index 00e94288..afd1b94b 100644 --- a/lib/src/nearest_point.dart +++ b/lib/src/nearest_point.dart @@ -1,6 +1,29 @@ import 'distance.dart'; import 'geojson.dart'; +/// Takes a reference [Point] and a FeatureCollection of Features +/// with Point geometries and returns the +/// point from the FeatureCollection closest to the reference. This calculation +/// is geodesic. For example: +/// +/// ```dart +/// var targetPoint = Point(coordinates: Position(-75.943, 39.984)); +/// Feature feature = +/// Feature(geometry: targetPoint, properties: {"marker-color": "#0F0"}); +/// FeatureCollection points = FeatureCollection(features: [ +/// Feature(geometry: Point(coordinates: Position(-75.343, 39.984))), +/// Feature(geometry: Point(coordinates: Position(-75.443, 39.984))), +/// Feature(geometry: Point(coordinates: Position(-75.543, 39.984))), +/// Feature(geometry: Point(coordinates: Position(-75.643, 39.984))), +/// ]); +/// +/// var nearest = nearestPoint(targetPoint, points); +/// +/// //addToMap +/// var addToMap = [targetPoint, points, nearest]; +/// nearest.properties['marker-color'] = '#F00'; +/// ``` + Feature nearestPoint( Feature targetPoint, FeatureCollection points) { Feature nearest; diff --git a/lib/turf.dart b/lib/turf.dart index 03e8c952..380b60ec 100644 --- a/lib/turf.dart +++ b/lib/turf.dart @@ -1,6 +1,3 @@ -/// Support for doing something awesome. -/// -/// More dartdocs go here. library turf; export 'src/bearing.dart'; diff --git a/test/components/meta_test.dart b/test/components/meta_test.dart index 42be76b1..551fe426 100644 --- a/test/components/meta_test.dart +++ b/test/components/meta_test.dart @@ -665,7 +665,6 @@ main() { // Each Iterators // meta.segmentEach has been purposely excluded from this list - // TODO fill out this list with all 'each' iterators test('geomEach', () { runBreakingIterationTest(geomEach, (geom, i, props, bbox, id) { iterationCount += 1; From e3ed8d22ad0259de588be7849c5c5ddc8f7cef7b Mon Sep 17 00:00:00 2001 From: armantorkzaban Date: Thu, 14 Apr 2022 11:02:10 +0200 Subject: [PATCH 07/82] closes #77, closes #16 --- CONTRIBUTING.md | 47 +++++++++ test/components/meta_test.dart | 185 +++++++++++++++------------------ 2 files changed, 133 insertions(+), 99 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a526bbc5..ed4cc3fa 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -6,6 +6,7 @@ Here is how cooperation works perfectly at [Turf Dart](https://github.com/dartcl #### Table of Contents - [Code of Conduct](#code-of-conduct) - [Get started](#get-started) + - [Structure of modules](#structure-of-modules) - [Implementation Process](#implementation-process) - [Documentation](#documentation) @@ -18,7 +19,52 @@ To put it simply, be kind to each other. - Clone the repository: ```git clone git@github.com:dartclub/turf_dart.git``` - Navigate to project's folder in terminal & get its dependencies: ```Dart pub get``` - Go through [Implementation Process](#implementation-process) +- Import the library in your code and use it. For example: +```dart +import 'package:turf/helpers.dart'; +import 'package:turf/src/line_segment.dart'; + Feature poly = Feature( + geometry: Polygon(coordinates: [ + [ + Position.of([0, 0]), + Position.of([2, 2]), + Position.of([0, 1]), + Position.of([0, 0]), + ], + [ + Position.of([0, 0]), + Position.of([1, 1]), + Position.of([0, 1]), + Position.of([0, 0]), + ], + ]), + ); + +var total = segmentReduce(poly, (previousValue, + currentSegment, + initialValue, + featureIndex, + multiFeatureIndex, + geometryIndex, + segmentIndex) { + if (previousValue != null) { + previousValue++; + } + return previousValue; + }, 0, combineNestedGeometries: false); +// total.length == 6 +``` +## Structure of modules +``` +TURF_DART/lib/.dart // public facing API, exports the implementation + │ │ + │ └───src/.dart // the implementation + │ + └───benchmark/_benchmark.dart + │ + └───test/components/_test.dart // all the related tests +``` ## Implementation process - Check the Backlog/Issues for similar issues - Create a new branch _feature-_ from _main_ @@ -27,6 +73,7 @@ To put it simply, be kind to each other. - Document everything [properly](#documentation) - **Write [tests](https://dart.dev/guides/testing)**―Keep an eye on [Turfjs'](https://github.com/Turfjs/turf) implementation - run the the test: ```dart test test/components/XXX.dart``` + - if you are importing tests from [Turfjs'](https://github.com/Turfjs/turf) please make sure you refactor it so it conforms with Dart syntax. - **Write [benchmarks](https://pub.dev/packages/benchmark)**―have a look at our [implementation](https://github.com/dartclub/turf_dart/tree/main/benchmark) - run the benchmark: ```pub run benchmark``` - Commit diff --git a/test/components/meta_test.dart b/test/components/meta_test.dart index 551fe426..102bdbab 100644 --- a/test/components/meta_test.dart +++ b/test/components/meta_test.dart @@ -7,107 +7,96 @@ import 'package:turf/src/meta/geom.dart'; import 'package:turf/src/meta/prop.dart'; Feature pt = Feature( - geometry: Point.fromJson({ - 'coordinates': [0, 0], - }), + geometry: Point(coordinates: Position(0, 0)), properties: { 'a': 1, }, ); Feature pt2 = Feature( - geometry: Point.fromJson({ - 'coordinates': [1, 1], - }), + geometry: Point(coordinates: Position(1, 1)), ); Feature line = Feature( - geometry: LineString.fromJson({ - 'coordinates': [ - [0, 0], - [1, 1], - ] - }), + geometry: LineString(coordinates: [ + Position(0, 0), + Position(1, 1), + ]), ); Feature poly = Feature( - geometry: Polygon.fromJson({ - 'coordinates': [ - [ - [0, 0], - [1, 1], - [0, 1], - [0, 0], - ], - ] - }), + geometry: Polygon(coordinates: [ + [ + Position(0, 0), + Position(1, 1), + Position(0, 1), + Position(0, 0), + ], + ]), ); Feature polyWithHole = Feature( - geometry: Polygon.fromJson({ - '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], - ], - ] - }), + geometry: Polygon(coordinates: [ + [ + Position(100.0, 0.0), + Position(101.0, 0.0), + Position(101.0, 1.0), + Position(100.0, 1.0), + Position(100.0, 0.0), + ], + [ + Position(100.2, 0.2), + Position(100.8, 0.2), + Position(100.8, 0.8), + Position(100.2, 0.8), + Position(100.2, 0.2), + ], + ]), ); Feature multiline = Feature( - geometry: MultiLineString.fromJson({ - 'coordinates': [ + geometry: MultiLineString( + coordinates: [ [ - [0, 0], - [1, 1], + Position(0, 0), + Position(1, 1), ], [ - [3, 3], - [4, 4], + Position(3, 3), + Position(4, 4), ], ], - }), + ), ); Feature multiPoint = Feature( - geometry: MultiPoint.fromJson({ - 'coordinates': [ - [0, 0], - [1, 1], - ], -})); + geometry: MultiPoint( + coordinates: [ + Position(0, 0), + Position(1, 1), + ], + ), +); Feature multiPoly = Feature( - geometry: MultiPolygon.fromJson({ - 'coordinates': [ + geometry: MultiPolygon(coordinates: [ + [ [ - [ - [0, 0], - [1, 1], - [0, 1], - [0, 0], - ], + Position(0, 0), + Position(1, 1), + Position(0, 1), + Position(0, 0), ], + ], + [ [ - [ - [3, 3], - [2, 2], - [1, 2], - [3, 3], - ], + Position(3, 3), + Position(2, 2), + Position(1, 2), + Position(3, 3), ], - ] - }), + ], + ]), ); Feature geomCollection = Feature( @@ -120,38 +109,36 @@ Feature geomCollection = Feature( ), ); -FeatureCollection fcMixed = FeatureCollection(features: [ - Feature( - geometry: Point.fromJson( - { - 'coordinates': [0, 0], - }, +FeatureCollection fcMixed = FeatureCollection( + features: [ + Feature( + geometry: Point( + coordinates: Position(0, 0), + ), + properties: {'foo': 'bar'}, ), - properties: {'foo': 'bar'}, - ), - Feature( - geometry: LineString.fromJson({ - 'coordinates': [ - [1, 1], - [2, 2], - ] - }), - properties: {'foo': 'buz'}), - Feature( - geometry: MultiLineString.fromJson({ - 'coordinates': [ - [ - [1, 1], - [0, 0], - ], - [ - [4, 4], - [5, 5], + Feature( + geometry: LineString(coordinates: [ + Position(1, 1), + Position(2, 2), + ]), + properties: {'foo': 'buz'}), + Feature( + geometry: MultiLineString( + coordinates: [ + [ + Position(0, 0), + Position(1, 1), + ], + [ + Position(4, 4), + Position(5, 5), + ], ], - ], - }), - properties: {'foo': 'qux'}), -]); + ), + properties: {'foo': 'qux'}), + ], +); List collection(Feature feature) { FeatureCollection featureCollection = FeatureCollection( From a0dfba4df600fb377d3135563247592b48490e1f Mon Sep 17 00:00:00 2001 From: armantorkzaban Date: Thu, 14 Apr 2022 11:05:55 +0200 Subject: [PATCH 08/82] proofread --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ed4cc3fa..fad77748 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -71,9 +71,9 @@ TURF_DART/lib/.dart // public facing API, exports the implementatio - Create a _draft Pull request_, mention in it the associated issues - **Implement** - Document everything [properly](#documentation) + - If you are importing tests, comments etc. from [Turfjs](https://github.com/Turfjs/turf), please make sure you refactor it so it conforms with Dart syntax. - **Write [tests](https://dart.dev/guides/testing)**―Keep an eye on [Turfjs'](https://github.com/Turfjs/turf) implementation - run the the test: ```dart test test/components/XXX.dart``` - - if you are importing tests from [Turfjs'](https://github.com/Turfjs/turf) please make sure you refactor it so it conforms with Dart syntax. - **Write [benchmarks](https://pub.dev/packages/benchmark)**―have a look at our [implementation](https://github.com/dartclub/turf_dart/tree/main/benchmark) - run the benchmark: ```pub run benchmark``` - Commit From c301657273fe4a16d89e5fc91aa15c0e6cbef7fc Mon Sep 17 00:00:00 2001 From: armantorkzaban Date: Thu, 14 Apr 2022 11:36:19 +0200 Subject: [PATCH 09/82] improves pub.dev score, closes #79, #78, #75 --- CONTRIBUTING.md | 16 +-- benchmark/cluster_benchmark.dart | 2 - lib/src/meta/extensions.dart | 14 +-- test/components/geojson_test.dart | 190 +++++++++++++++--------------- 4 files changed, 112 insertions(+), 110 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index fad77748..29d6f290 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -27,16 +27,16 @@ import 'package:turf/src/line_segment.dart'; Feature poly = Feature( geometry: Polygon(coordinates: [ [ - Position.of([0, 0]), - Position.of([2, 2]), - Position.of([0, 1]), - Position.of([0, 0]), + Position(0, 0), + Position(2, 2), + Position(0, 1), + Position(0, 0), ], [ - Position.of([0, 0]), - Position.of([1, 1]), - Position.of([0, 1]), - Position.of([0, 0]), + Position(0, 0), + Position(1, 1), + Position(0, 1), + Position(0, 0), ], ]), ); diff --git a/benchmark/cluster_benchmark.dart b/benchmark/cluster_benchmark.dart index e2966a53..b3d0ca57 100644 --- a/benchmark/cluster_benchmark.dart +++ b/benchmark/cluster_benchmark.dart @@ -27,10 +27,8 @@ void main() { benchmark('clusterEach', () { List clusters = []; - int total = 0; clusterEach(featureCollection, "cluster", (cluster, clusterValue, currentIndex) { - total += cluster!.features.length; clusters.add(cluster); }); }); diff --git a/lib/src/meta/extensions.dart b/lib/src/meta/extensions.dart index 4bda2783..af809c4e 100644 --- a/lib/src/meta/extensions.dart +++ b/lib/src/meta/extensions.dart @@ -7,7 +7,7 @@ extension GeoJSONObjectMetaExtension on GeoJSONObject { } T? geomReduce(meta.GeomReduceCallback callback, T? initialValue) { - meta.geomReduce( + return meta.geomReduce( this, callback, initialValue, @@ -22,7 +22,7 @@ extension GeoJSONObjectMetaExtension on GeoJSONObject { meta.PropReduceCallback callback, T? initialValue, ) { - meta.propReduce( + return meta.propReduce( this, callback, initialValue, @@ -37,7 +37,7 @@ extension GeoJSONObjectMetaExtension on GeoJSONObject { meta.FeatureReduceCallback callback, T? initialValue, ) { - meta.featureReduce( + return meta.featureReduce( this, callback, initialValue, @@ -53,7 +53,7 @@ extension GeoJSONObjectMetaExtension on GeoJSONObject { T? initialValue, [ bool excludeWrapCoord = false, ]) { - meta.coordReduce( + return meta.coordReduce( this, callback, initialValue, @@ -73,7 +73,7 @@ extension GeoJSONObjectMetaExtension on GeoJSONObject { meta.FlattenReduceCallback callback, T? initialValue, ) { - meta.flattenReduce( + return meta.flattenReduce( this, callback, initialValue, @@ -89,7 +89,7 @@ extension GeoJSONObjectMetaExtension on GeoJSONObject { T? initialValue, { bool combineNestedGeometries = true, }) { - meta.segmentReduce( + return meta.segmentReduce( this, callback, initialValue, @@ -115,7 +115,7 @@ extension FeatureCollectionMetaExtension on FeatureCollection { meta.ClusterReduceCallback callback, dynamic initialValue, ) { - meta.clusterReduce( + return meta.clusterReduce( this, property, callback, diff --git a/test/components/geojson_test.dart b/test/components/geojson_test.dart index 0485e4aa..957c730e 100644 --- a/test/components/geojson_test.dart +++ b/test/components/geojson_test.dart @@ -309,107 +309,111 @@ main() { expect(() => GeometryType.deserialize(geoJSON3), throwsA(isA())); }); - test('.clone()', () { - final coll = FeatureCollection( - bbox: BBox(100, 0, 101, 1), - features: [ - Feature( - bbox: BBox(100, 0, 101, 1), - geometry: GeometryCollection( + test( + '.clone()', + () { + final coll = FeatureCollection( + bbox: BBox(100, 0, 101, 1), + features: [ + Feature( bbox: BBox(100, 0, 101, 1), - geometries: [ - LineString( - bbox: BBox(100, 0, 101, 1), - coordinates: [Position(100, 0), Position(101, 1)], - ), - MultiLineString.fromLineStrings( - bbox: BBox(100, 0, 101, 1), - lineStrings: [ - LineString( - bbox: BBox(100, 0, 101, 1), - coordinates: [Position(100, 0), Position(101, 1)], - ), - LineString( - bbox: BBox(100, 0, 101, 1), - coordinates: [Position(100, 1), Position(101, 0)], - ), - ], - ), - MultiPoint.fromPoints( - bbox: BBox(100, 0, 101, 1), - points: [ - Point(coordinates: Position(100, 0)), - Point(coordinates: Position(100.5, 0.5)), - Point(coordinates: Position(101, 1)), - ], - ), - Polygon( - bbox: BBox(100, 0, 101, 1), - coordinates: [ - [ - Position(100, 0), - Position(100, 1), - Position(101, 0), - ] - ], - ), - MultiPolygon.fromPolygons( - bbox: BBox(100, 0, 101, 1), - polygons: [ - Polygon(coordinates: [ + geometry: GeometryCollection( + bbox: BBox(100, 0, 101, 1), + geometries: [ + LineString( + bbox: BBox(100, 0, 101, 1), + coordinates: [Position(100, 0), Position(101, 1)], + ), + MultiLineString.fromLineStrings( + bbox: BBox(100, 0, 101, 1), + lineStrings: [ + LineString( + bbox: BBox(100, 0, 101, 1), + coordinates: [Position(100, 0), Position(101, 1)], + ), + LineString( + bbox: BBox(100, 0, 101, 1), + coordinates: [Position(100, 1), Position(101, 0)], + ), + ], + ), + MultiPoint.fromPoints( + bbox: BBox(100, 0, 101, 1), + points: [ + Point(coordinates: Position(100, 0)), + Point(coordinates: Position(100.5, 0.5)), + Point(coordinates: Position(101, 1)), + ], + ), + Polygon( + bbox: BBox(100, 0, 101, 1), + coordinates: [ [ Position(100, 0), Position(100, 1), Position(101, 0), ] - ]), - Polygon(coordinates: [ - [ - Position(100, 0), - Position(100, 1), - Position(101, 0), - ] - ]) - ], - ), - ], - ), - id: 1, - properties: {"key": "val"}), - ], - ); - final cloned = coll.clone(); - final feat = cloned.features.first; - final bbox = BBox(100, 0, 101, 1); - expect(cloned.bbox, bbox); - expect(feat.id, 1); - expect(feat.bbox, bbox); - expect(feat.properties!.keys.first, "key"); - expect(feat.properties!.values.first, "val"); - expect(feat.geometry!, isA()); - final geomColl = feat.geometry!; - expect(geomColl.geometries.length, - coll.features.first.geometry!.geometries.length); - for (var geom in geomColl.geometries) { - expect(geom.bbox, isNotNull); - expect(geom.coordinates, isNotEmpty); - - _expandRecursively(List inner) { - if (inner is List) { - return inner; - } else { - return inner.expand((el) => el is List ? _expandRecursively(el) : el); + ], + ), + MultiPolygon.fromPolygons( + bbox: BBox(100, 0, 101, 1), + polygons: [ + Polygon(coordinates: [ + [ + Position(100, 0), + Position(100, 1), + Position(101, 0), + ] + ]), + Polygon(coordinates: [ + [ + Position(100, 0), + Position(100, 1), + Position(101, 0), + ] + ]) + ], + ), + ], + ), + id: 1, + properties: {"key": "val"}), + ], + ); + final cloned = coll.clone(); + final feat = cloned.features.first; + final bbox = BBox(100, 0, 101, 1); + expect(cloned.bbox, bbox); + expect(feat.id, 1); + expect(feat.bbox, bbox); + expect(feat.properties!.keys.first, "key"); + expect(feat.properties!.values.first, "val"); + expect(feat.geometry!, isA()); + final geomColl = feat.geometry!; + expect(geomColl.geometries.length, + coll.features.first.geometry!.geometries.length); + for (var geom in geomColl.geometries) { + expect(geom.bbox, isNotNull); + expect(geom.coordinates, isNotEmpty); + + _expandRecursively(List inner) { + if (inner is List) { + return inner; + } else { + return inner + .expand((el) => el is List ? _expandRecursively(el) : el); + } } - } - var expanded = _expandRecursively(geom.coordinates); - expect( - expanded.first, - Position(100, 0), - ); - } - // TODO refine tests - }); + var expanded = _expandRecursively(geom.coordinates); + expect( + expanded.first, + Position(100, 0), + ); + } + // TODO refine tests + }, + ); final points = [ Point(coordinates: Position(1, 2, 3)), From a3b3d033f30f34d517bdf766ccbc49072b9e7a4c Mon Sep 17 00:00:00 2001 From: armantorkzaban Date: Thu, 14 Apr 2022 16:41:54 +0200 Subject: [PATCH 10/82] Added deleted model, complemented contributing.md --- CONTRIBUTING.md | 11 ++++++++--- README.md | 3 +++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 29d6f290..251280ee 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -9,15 +9,16 @@ Here is how cooperation works perfectly at [Turf Dart](https://github.com/dartcl - [Structure of modules](#structure-of-modules) - [Implementation Process](#implementation-process) - [Documentation](#documentation) + - [GeoJSON object model](#GeoJSON-object-model) ## Code of conduct By participating, you are expected to uphold international human rights and fundamental freedoms! To put it simply, be kind to each other. ## Get started -- Get the [tools](https://dart.dev/tools) +- Get the [Dart tools](https://dart.dev/tools) - Clone the repository: ```git clone git@github.com:dartclub/turf_dart.git``` -- Navigate to project's folder in terminal & get its dependencies: ```Dart pub get``` +- Navigate to project's folder in terminal & get its dependencies: ```dart pub get``` - Go through [Implementation Process](#implementation-process) - Import the library in your code and use it. For example: ```dart @@ -75,7 +76,7 @@ TURF_DART/lib/.dart // public facing API, exports the implementatio - **Write [tests](https://dart.dev/guides/testing)**―Keep an eye on [Turfjs'](https://github.com/Turfjs/turf) implementation - run the the test: ```dart test test/components/XXX.dart``` - **Write [benchmarks](https://pub.dev/packages/benchmark)**―have a look at our [implementation](https://github.com/dartclub/turf_dart/tree/main/benchmark) - - run the benchmark: ```pub run benchmark``` + - run the benchmark: ```dart pub run benchmark``` - Commit - Convert to real Pull request _ready for review_ - Code review / mention a reviewer from [contributors list](https://github.com/dartclub/turf_dart/graphs/contributors) @@ -87,3 +88,7 @@ We follow [Effective Dart](https://dart.dev/guides/language/effective-dart/docum After going through the [Implementation Process](#implementation-process), please mention the made changes in [README.md](https://github.com/dartclub/turf_dart/blob/main/README.md) In order to add to this very documentation, please develop CONTRIBUTING.md in [documentation branch](https://github.com/dartclub/turf_dart/tree/documentation) + +## GeoJSON Object Model +If you have not read our [README.md](https://github.com/dartclub/turf_dart/blob/main/README.md) this diagram will give you a lot of information. Please consider looking our [notable design decisions](https://github.com/dartclub/turf_dart/blob/main/README.md#notable-design-decisions). +![polymorphism](https://user-images.githubusercontent.com/10634693/159876354-f9da2f37-02b3-4546-b32a-c0f82c372272.png) \ No newline at end of file diff --git a/README.md b/README.md index 3c41eed9..b220c7ae 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,9 @@ This includes a fully [RFC 7946](https://tools.ietf.org/html/rfc7946)-compliant Most of the implementation is a direct translation from [turf.js](https://github.com/Turfjs/turf). +## GeoJSON Object Model + +![polymorphism](https://user-images.githubusercontent.com/10634693/159876354-f9da2f37-02b3-4546-b32a-c0f82c372272.png) ## Notable Design Decisions - Nested `GeometryCollections` (as described in From 820a4917347047a6f02f5e7a6011d36bf5594e3c Mon Sep 17 00:00:00 2001 From: armantorkzaban Date: Tue, 7 Jun 2022 09:15:35 +0200 Subject: [PATCH 11/82] booleans init --- lib/src/booleans/boolean_clockwise.dart | 70 ++++ lib/src/booleans/boolean_concave.dart | 77 ++++ lib/src/booleans/boolean_contains.dart | 512 ++++++++++++++++++++++++ lib/src/invariant.dart | 26 ++ 4 files changed, 685 insertions(+) create mode 100644 lib/src/booleans/boolean_clockwise.dart create mode 100644 lib/src/booleans/boolean_concave.dart create mode 100644 lib/src/booleans/boolean_contains.dart diff --git a/lib/src/booleans/boolean_clockwise.dart b/lib/src/booleans/boolean_clockwise.dart new file mode 100644 index 00000000..c2c4392e --- /dev/null +++ b/lib/src/booleans/boolean_clockwise.dart @@ -0,0 +1,70 @@ +import 'package:turf/src/invariant.dart'; + +/** + * Takes a ring and return true or false whether or not the ring is clockwise or counter-clockwise. + * + * @name booleanClockwise + * @param {Feature|LineString|Array>} line to be evaluated + * @returns {boolean} true/false + * @example + * var clockwiseRing = turf.lineString([[0,0],[1,1],[1,0],[0,0]]); + * var counterClockwiseRing = turf.lineString([[0,0],[1,0],[1,1],[0,0]]); + * + * turf.booleanClockwise(clockwiseRing) + * //=true + * turf.booleanClockwise(counterClockwiseRing) + * //=false + */ + +bool booleanClockwise(dynamic line) { + var ring = getCoords(line); + num sum = 0; + var i = 1; + var prev; + var cur; + + while (i < ring.length) { + prev = cur ?? ring[0]; + cur = ring[i]; + sum += (cur[0] - prev[0]) * (cur[1] + prev[1]); + i++; + } + return sum > 0; +} + + +// import { Feature, LineString, Position } from "geojson"; +// import { getCoords } from "@turf/invariant"; + +// /** +// * Takes a ring and return true or false whether or not the ring is clockwise or counter-clockwise. +// * +// * @name booleanClockwise +// * @param {Feature|LineString|Array>} line to be evaluated +// * @returns {boolean} true/false +// * @example +// * var clockwiseRing = turf.lineString([[0,0],[1,1],[1,0],[0,0]]); +// * var counterClockwiseRing = turf.lineString([[0,0],[1,0],[1,1],[0,0]]); +// * +// * turf.booleanClockwise(clockwiseRing) +// * //=true +// * turf.booleanClockwise(counterClockwiseRing) +// * //=false +// */ +// export default function booleanClockwise( +// line: Feature | LineString | Position[] +// ): boolean { +// const ring = getCoords(line); +// let sum = 0; +// let i = 1; +// let prev; +// let cur; + +// while (i < ring.length) { +// prev = cur || ring[0]; +// cur = ring[i]; +// sum += (cur[0] - prev[0]) * (cur[1] + prev[1]); +// i++; +// } +// return sum > 0; +// } \ No newline at end of file diff --git a/lib/src/booleans/boolean_concave.dart b/lib/src/booleans/boolean_concave.dart new file mode 100644 index 00000000..cfc6b5c9 --- /dev/null +++ b/lib/src/booleans/boolean_concave.dart @@ -0,0 +1,77 @@ +import 'package:turf/helpers.dart'; +import '../invariant.dart'; + +/** + * Takes a polygon and return true or false as to whether it is concave or not. + * + * @name booleanConcave + * @param {Feature} polygon to be evaluated + * @returns {boolean} true/false + * @example + * var convexPolygon = turf.polygon([[[0,0],[0,1],[1,1],[1,0],[0,0]]]); + * + * turf.booleanConcave(convexPolygon) + * //=false + */ +booleanConcave(GeoJSONObject polygon) { + // Taken from https://stackoverflow.com/a/1881201 & https://stackoverflow.com/a/25304159 + var coords = getCoords(polygon); + if (coords[0].length <= 4) { + return false; + } + + var sign = false; + var n = coords[0].length - 1; + for (var i = 0; i < n; i++) { + var dx1 = coords[0][(i + 2) % n][0] - coords[0][(i + 1) % n][0]; + var dy1 = coords[0][(i + 2) % n][1] - coords[0][(i + 1) % n][1]; + var dx2 = coords[0][i][0] - coords[0][(i + 1) % n][0]; + var dy2 = coords[0][i][1] - coords[0][(i + 1) % n][1]; + var zcrossproduct = dx1 * dy2 - dy1 * dx2; + if (i == 0) { + sign = zcrossproduct > 0; + } else if (sign != zcrossproduct > 0) { + return true; + } + } + return false; +} + +/* import { Feature, Polygon } from "geojson"; +import { getGeom } from "@turf/invariant"; + +/** + * Takes a polygon and return true or false as to whether it is concave or not. + * + * @name booleanConcave + * @param {Feature} polygon to be evaluated + * @returns {boolean} true/false + * @example + * var convexPolygon = turf.polygon([[[0,0],[0,1],[1,1],[1,0],[0,0]]]); + * + * turf.booleanConcave(convexPolygon) + * //=false + */ +export default function booleanConcave(polygon: Feature | Polygon) { + // Taken from https://stackoverflow.com/a/1881201 & https://stackoverflow.com/a/25304159 + const coords = getGeom(polygon).coordinates; + if (coords[0].length <= 4) { + return false; + } + + let sign = false; + const n = coords[0].length - 1; + for (let i = 0; i < n; i++) { + const dx1 = coords[0][(i + 2) % n][0] - coords[0][(i + 1) % n][0]; + const dy1 = coords[0][(i + 2) % n][1] - coords[0][(i + 1) % n][1]; + const dx2 = coords[0][i][0] - coords[0][(i + 1) % n][0]; + const dy2 = coords[0][i][1] - coords[0][(i + 1) % n][1]; + const zcrossproduct = dx1 * dy2 - dy1 * dx2; + if (i === 0) { + sign = zcrossproduct > 0; + } else if (sign !== zcrossproduct > 0) { + return true; + } + } + return false; +} */ \ No newline at end of file diff --git a/lib/src/booleans/boolean_contains.dart b/lib/src/booleans/boolean_contains.dart new file mode 100644 index 00000000..b2f856ca --- /dev/null +++ b/lib/src/booleans/boolean_contains.dart @@ -0,0 +1,512 @@ +import '../../helpers.dart'; +import '../invariant.dart'; + +/** + * Boolean-contains returns True if the second geometry is completely contained by the first geometry. + * The interiors of both geometries must intersect and, the interior and boundary of the secondary (geometry b) + * must not intersect the exterior of the primary (geometry a). + * Boolean-contains returns the exact opposite result of the `@turf/boolean-within`. + * + * @name booleanContains + * @param {Geometry|Feature} feature1 GeoJSON Feature or Geometry + * @param {Geometry|Feature} feature2 GeoJSON Feature or Geometry + * @returns {boolean} true/false + * @example + * var line = turf.lineString([[1, 1], [1, 2], [1, 3], [1, 4]]); + * var point = turf.point([1, 2]); + * + * turf.booleanContains(line, point); + * //=true + */ +booleanContains(GeoJSONObjectType feature1, GeoJSONObjectType feature2) { + var geom1 = getGeom(feature1); + var geom2 = getGeom(feature2); + var type1 = geom1.runtimeType; + var type2 = geom2.runtimeType; + var coords1 = geom1.coordinates; + var coords2 = geom2.coordinates; + + switch (type1) { + case Point: + switch (type2) { + case Point: + return compareCoords(coords1, coords2); + default: + throw UnsupportedError( + "{feature2 $type2 geometry not supported}"); + } + case MultiPoint: + switch (type2) { + case Point: + return isPointInMultiPoint(geom1, geom2); + case MultiPoint: + return isMultiPointInMultiPoint(geom1, geom2); + default: + throw UnsupportedError( + "{feature2 $type2 geometry not supported}"); + } + case LineString: + switch (type2) { + case Point: + return isPointOnLine(geom2, geom1, {ignoreEndVertices: true}); + case LineString: + return isLineOnLine(geom1, geom2); + case MultiPoint: + return isMultiPointOnLine(geom1, geom2); + default: + throw UnsupportedError( + "{feature2 $type2 geometry not supported}"); + } + case Polygon: + switch (type2) { + case Point: + return booleanPointInPolygon(geom2, geom1, {ignoreBoundary: true}); + case LineString: + return isLineInPoly(geom1, geom2); + case Polygon: + return isPolyInPoly(geom1, geom2); + case MultiPoint: + return isMultiPointInPoly(geom1, geom2); + default: + throw UnsupportedError( + "{feature2 $type2 geometry not supported}"); + } + default: + throw UnsupportedError("feature1 $type1 geometry not supported"); + } +} + +isPointInMultiPoint(MultiPoint multiPoint, Point pt) { + int i; + var output = false; + for (i = 0; i < multiPoint.coordinates.length; i++) { + if (compareCoords(multiPoint.coordinates[i], pt.coordinates)) { + output = true; + break; + } + } + return output; +} + +isMultiPointInMultiPoint(MultiPoint multiPoint1, MultiPoint multiPoint2) { + for (var coord2 in multiPoint2.coordinates) { + var matchFound = false; + for (var coord1 in multiPoint1.coordinates) { + if (compareCoords(coord2, coord1)) { + matchFound = true; + break; + } + } + if (!matchFound) { + return false; + } + } + return true; +} + +isMultiPointOnLine(LineString lineString, MultiPoint multiPoint) { + var haveFoundInteriorPoint = false; + for (var coord in multiPoint.coordinates) { + if (isPointOnLine(coord, lineString, {ignoreEndVertices: true})) { + haveFoundInteriorPoint = true; + } + if (!isPointOnLine(coord, lineString)) { + return false; + } + } + if (haveFoundInteriorPoint) { + return true; + } + return false; +} + +isMultiPointInPoly(Polygon polygon, MultiPoint multiPoint) { + for (var coord in multiPoint.coordinates) { + if (!booleanPointInPolygon(coord, polygon, {ignoreBoundary: true})) { + return false; + } + } + return true; +} + +isLineOnLine(LineString lineString1, LineString lineString2) { + var haveFoundInteriorPoint = false; + for (var coords in lineString2.coordinates) { + if (isPointOnLine( + {type: Point, coordinates: coords}, + lineString1, + { + ignoreEndVertices: true, + })) { + haveFoundInteriorPoint = true; + } + if (!isPointOnLine( + {type: Point, coordinates: coords}, + lineString1, + { + ignoreEndVertices: false, + })) { + return false; + } + } + return haveFoundInteriorPoint; +} + +isLineInPoly(Polygon polygon, LineString linestring) { + var output = false; + var i = 0; + + const polyBbox = calcBbox(polygon); + const lineBbox = calcBbox(linestring); + if (!doBBoxOverlap(polyBbox, lineBbox)) { + return false; + } + for (i; i < linestring.coordinates.length - 1; i++) { + var midPoint = + getMidpoint(linestring.coordinates[i], linestring.coordinates[i + 1]); + if (booleanPointInPolygon( + {type: Point, coordinates: midPoint}, + polygon, + { + ignoreBoundary: true, + })) { + output = true; + break; + } + } + return output; +} + +/** + * Is Polygon2 in Polygon1 + * Only takes into account outer rings + * + * @private + * @param {Geometry|Feature} feature1 Polygon1 + * @param {Geometry|Feature} feature2 Polygon2 + * @returns {boolean} true/false + */ +isPolyInPoly(GeoJSONObjectType feature1, GeoJSONObjectType feature2) { + // Handle Nulls + if (feature1.runtimeType == Feature && + (feature1 as Feature).geometry == null) { + return false; + } + if (feature2.runtimeType == Feature && + (feature2 as Feature).geometry == null) { + return false; + } + + const poly1Bbox = calcBbox(feature1); + const poly2Bbox = calcBbox(feature2); + if (!doBBoxOverlap(poly1Bbox, poly2Bbox)) { + return false; + } + + var coords = getGeom(feature2).coordinates; + for (var ring in coords) { + for (var coord in ring) { + if (!booleanPointInPolygon(coord, feature1)) { + return false; + } + } + } + return true; +} + +doBBoxOverlap(BBox bbox1, BBox bbox2) { + if (bbox1[0]! > bbox2[0]!) { + return false; + } + if (bbox1[2]! < bbox2[2]!) { + return false; + } + if (bbox1[1]! > bbox2[1]!) { + return false; + } + if (bbox1[3]! < bbox2[3]!) { + return false; + } + return true; +} + +/** + * compareCoords + * + * @private + * @param {Position} pair1 point [x,y] + * @param {Position} pair2 point [x,y] + * @returns {boolean} true/false if coord pairs match + */ +compareCoords(List pair1, List pair2) { + return pair1[0] == pair2[0] && pair1[1] == pair2[1]; +} + +getMidpoint(List pair1, List pair2) { + return [(pair1[0] + pair2[0]) / 2, (pair1[1] + pair2[1]) / 2]; +} + +/* +import { + BBox, + Feature, + Geometry, + LineString, + MultiPoint, + Point, + Polygon, +} from "geojson"; +import calcBbox from "@turf/bbox"; +import booleanPointInPolygon from "@turf/boolean-point-in-polygon"; +import isPointOnLine from "@turf/boolean-point-on-line"; +import { getGeom } from "@turf/invariant"; + +/** + * Boolean-contains returns True if the second geometry is completely contained by the first geometry. + * The interiors of both geometries must intersect and, the interior and boundary of the secondary (geometry b) + * must not intersect the exterior of the primary (geometry a). + * Boolean-contains returns the exact opposite result of the `@turf/boolean-within`. + * + * @name booleanContains + * @param {Geometry|Feature} feature1 GeoJSON Feature or Geometry + * @param {Geometry|Feature} feature2 GeoJSON Feature or Geometry + * @returns {boolean} true/false + * @example + * var line = turf.lineString([[1, 1], [1, 2], [1, 3], [1, 4]]); + * var point = turf.point([1, 2]); + * + * turf.booleanContains(line, point); + * //=true + */ +export default function booleanContains( + feature1: Feature | Geometry, + feature2: Feature | Geometry +) { + const geom1 = getGeom(feature1); + const geom2 = getGeom(feature2); + const type1 = geom1.type; + const type2 = geom2.type; + const coords1 = geom1.coordinates; + const coords2 = geom2.coordinates; + + switch (type1) { + case "Point": + switch (type2) { + case "Point": + return compareCoords(coords1, coords2); + default: + throw new Error("feature2 " + type2 + " geometry not supported"); + } + case "MultiPoint": + switch (type2) { + case "Point": + return isPointInMultiPoint(geom1, geom2); + case "MultiPoint": + return isMultiPointInMultiPoint(geom1, geom2); + default: + throw new Error("feature2 " + type2 + " geometry not supported"); + } + case "LineString": + switch (type2) { + case "Point": + return isPointOnLine(geom2, geom1, { ignoreEndVertices: true }); + case "LineString": + return isLineOnLine(geom1, geom2); + case "MultiPoint": + return isMultiPointOnLine(geom1, geom2); + default: + throw new Error("feature2 " + type2 + " geometry not supported"); + } + case "Polygon": + switch (type2) { + case "Point": + return booleanPointInPolygon(geom2, geom1, { ignoreBoundary: true }); + case "LineString": + return isLineInPoly(geom1, geom2); + case "Polygon": + return isPolyInPoly(geom1, geom2); + case "MultiPoint": + return isMultiPointInPoly(geom1, geom2); + default: + throw new Error("feature2 " + type2 + " geometry not supported"); + } + default: + throw new Error("feature1 " + type1 + " geometry not supported"); + } +} + +export function isPointInMultiPoint(multiPoint: MultiPoint, pt: Point) { + let i; + let output = false; + for (i = 0; i < multiPoint.coordinates.length; i++) { + if (compareCoords(multiPoint.coordinates[i], pt.coordinates)) { + output = true; + break; + } + } + return output; +} + +export function isMultiPointInMultiPoint( + multiPoint1: MultiPoint, + multiPoint2: MultiPoint +) { + for (const coord2 of multiPoint2.coordinates) { + let matchFound = false; + for (const coord1 of multiPoint1.coordinates) { + if (compareCoords(coord2, coord1)) { + matchFound = true; + break; + } + } + if (!matchFound) { + return false; + } + } + return true; +} + +export function isMultiPointOnLine( + lineString: LineString, + multiPoint: MultiPoint +) { + let haveFoundInteriorPoint = false; + for (const coord of multiPoint.coordinates) { + if (isPointOnLine(coord, lineString, { ignoreEndVertices: true })) { + haveFoundInteriorPoint = true; + } + if (!isPointOnLine(coord, lineString)) { + return false; + } + } + if (haveFoundInteriorPoint) { + return true; + } + return false; +} + +export function isMultiPointInPoly(polygon: Polygon, multiPoint: MultiPoint) { + for (const coord of multiPoint.coordinates) { + if (!booleanPointInPolygon(coord, polygon, { ignoreBoundary: true })) { + return false; + } + } + return true; +} + +export function isLineOnLine(lineString1: LineString, lineString2: LineString) { + let haveFoundInteriorPoint = false; + for (const coords of lineString2.coordinates) { + if ( + isPointOnLine({ type: "Point", coordinates: coords }, lineString1, { + ignoreEndVertices: true, + }) + ) { + haveFoundInteriorPoint = true; + } + if ( + !isPointOnLine({ type: "Point", coordinates: coords }, lineString1, { + ignoreEndVertices: false, + }) + ) { + return false; + } + } + return haveFoundInteriorPoint; +} + +export function isLineInPoly(polygon: Polygon, linestring: LineString) { + let output = false; + let i = 0; + + const polyBbox = calcBbox(polygon); + const lineBbox = calcBbox(linestring); + if (!doBBoxOverlap(polyBbox, lineBbox)) { + return false; + } + for (i; i < linestring.coordinates.length - 1; i++) { + const midPoint = getMidpoint( + linestring.coordinates[i], + linestring.coordinates[i + 1] + ); + if ( + booleanPointInPolygon({ type: "Point", coordinates: midPoint }, polygon, { + ignoreBoundary: true, + }) + ) { + output = true; + break; + } + } + return output; +} + +/** + * Is Polygon2 in Polygon1 + * Only takes into account outer rings + * + * @private + * @param {Geometry|Feature} feature1 Polygon1 + * @param {Geometry|Feature} feature2 Polygon2 + * @returns {boolean} true/false + */ +export function isPolyInPoly( + feature1: Feature | Polygon, + feature2: Feature | Polygon +) { + // Handle Nulls + if (feature1.type === "Feature" && feature1.geometry === null) { + return false; + } + if (feature2.type === "Feature" && feature2.geometry === null) { + return false; + } + + const poly1Bbox = calcBbox(feature1); + const poly2Bbox = calcBbox(feature2); + if (!doBBoxOverlap(poly1Bbox, poly2Bbox)) { + return false; + } + + const coords = getGeom(feature2).coordinates; + for (const ring of coords) { + for (const coord of ring) { + if (!booleanPointInPolygon(coord, feature1)) { + return false; + } + } + } + return true; +} + +export function doBBoxOverlap(bbox1: BBox, bbox2: BBox) { + if (bbox1[0] > bbox2[0]) { + return false; + } + if (bbox1[2] < bbox2[2]) { + return false; + } + if (bbox1[1] > bbox2[1]) { + return false; + } + if (bbox1[3] < bbox2[3]) { + return false; + } + return true; +} + +/** + * compareCoords + * + * @private + * @param {Position} pair1 point [x,y] + * @param {Position} pair2 point [x,y] + * @returns {boolean} true/false if coord pairs match + */ +export function compareCoords(pair1: number[], pair2: number[]) { + return pair1[0] === pair2[0] && pair1[1] === pair2[1]; +} + +export function getMidpoint(pair1: number[], pair2: number[]) { + return [(pair1[0] + pair2[0]) / 2, (pair1[1] + pair2[1]) / 2]; +} */ \ No newline at end of file diff --git a/lib/src/invariant.dart b/lib/src/invariant.dart index 3303e25d..6e3da29d 100644 --- a/lib/src/invariant.dart +++ b/lib/src/invariant.dart @@ -76,3 +76,29 @@ _getCoordsForGeometry(GeometryObject geom) { return (geom as GeometryType).coordinates; } + +/** + * Get Geometry from Feature or Geometry Object + * + * @param {Feature|Geometry} geojson GeoJSON Feature or Geometry Object + * @returns {Geometry|null} GeoJSON Geometry Object + * @throws {Error} if geojson is not a Feature or Geometry Object + * @example + * var point = { + * "type": "Feature", + * "properties": {}, + * "geometry": { + * "type": "Point", + * "coordinates": [110, 40] + * } + * } + * var geom = turf.getGeom(point) + * //={"type": "Point", "coordinates": [110, 40]} + */ + +getGeom(GeoJSONObjectType geojson) { + if (geojson is Feature) { + return (geojson as Feature).geometry; + } + return geojson; +} From 0a53f8010a8c6806f65122fdfbf86cfe3e9fb913 Mon Sep 17 00:00:00 2001 From: armantorkzaban Date: Tue, 7 Jun 2022 21:19:29 +0200 Subject: [PATCH 12/82] initial import --- lib/src/booleans/boolean_crosses.dart | 385 ++++ lib/src/booleans/boolean_disjoint.dart | 173 ++ lib/src/booleans/boolean_equal.dart | 93 + lib/src/booleans/boolean_intersect.dart | 66 + lib/src/booleans/boolean_overlap.dart | 199 +++ lib/src/booleans/boolean_parallel.dart | 141 ++ .../booleans/boolean_point_in_polygon.dart | 169 ++ lib/src/booleans/boolean_point_on_line.dart | 232 +++ lib/src/booleans/boolean_touches.dart | 1582 +++++++++++++++++ lib/src/invariant.dart | 4 +- 10 files changed, 3042 insertions(+), 2 deletions(-) create mode 100644 lib/src/booleans/boolean_crosses.dart create mode 100644 lib/src/booleans/boolean_disjoint.dart create mode 100644 lib/src/booleans/boolean_equal.dart create mode 100644 lib/src/booleans/boolean_intersect.dart create mode 100644 lib/src/booleans/boolean_overlap.dart create mode 100644 lib/src/booleans/boolean_parallel.dart create mode 100644 lib/src/booleans/boolean_point_in_polygon.dart create mode 100644 lib/src/booleans/boolean_point_on_line.dart create mode 100644 lib/src/booleans/boolean_touches.dart diff --git a/lib/src/booleans/boolean_crosses.dart b/lib/src/booleans/boolean_crosses.dart new file mode 100644 index 00000000..293fa38d --- /dev/null +++ b/lib/src/booleans/boolean_crosses.dart @@ -0,0 +1,385 @@ +import 'dart:math'; + +import '../../helpers.dart'; +import '../invariant.dart'; +/** + * Boolean-Crosses returns True if the intersection results in a geometry whose dimension is one less than + * the maximum dimension of the two source geometries and the intersection set is interior to + * both source geometries. + * + * Boolean-Crosses returns t (TRUE) for only multipoint/polygon, multipoint/linestring, linestring/linestring, linestring/polygon, and linestring/multipolygon comparisons. + * Other comparisons are not supported as they are outside the OpenGIS Simple Features spec and may give unexpected results. + * + * @name booleanCrosses + * @param {Geometry|Feature} feature1 GeoJSON Feature or Geometry + * @param {Geometry|Feature} feature2 GeoJSON Feature or Geometry + * @returns {boolean} true/false + * @example + * var line1 = turf.lineString([[-2, 2], [4, 2]]); + * var line2 = turf.lineString([[1, 1], [1, 2], [1, 3], [1, 4]]); + * + * var cross = turf.booleanCrosses(line1, line2); + * //=true + */ + +bool booleanCrosses(GeoJSONObjectType feature1, GeoJSONObjectType feature2) { + var geom1 = getGeom(feature1); + var geom2 = getGeom(feature2); + var type1 = geom1.type; + var type2 = geom2.type; + + switch (type1) { + case MultiPoint: + switch (type2) { + case LineString: + return doMultiPointAndLineStringCross(geom1, geom2); + case Polygon: + return doesMultiPointCrossPoly(geom1, geom2); + default: + throw UnsupportedError("feature2 $type2 geometry not supported"); + } + case LineString: + switch (type2) { + case MultiPoint: // An inverse operation + return doMultiPointAndLineStringCross(geom2, geom1); + case LineString: + return doLineStringsCross(geom1, geom2); + case Polygon: + return doLineStringAndPolygonCross(geom1, geom2); + default: + throw UnsupportedError("feature2 $type2 geometry not supported"); + } + case Polygon: + switch (type2) { + case MultiPoint: // An inverse operation + return doesMultiPointCrossPoly(geom2, geom1); + case LineString: // An inverse operation + return doLineStringAndPolygonCross(geom2, geom1); + default: + throw UnsupportedError("feature2 $type2 geometry not supported"); + } + default: + throw UnsupportedError("feature1 $type1 geometry not supported"); + } +} + +doMultiPointAndLineStringCross(MultiPoint multiPoint, LineString lineString) { + var foundIntPoint = false; + var foundExtPoint = false; + var pointLength = multiPoint.coordinates.length; + var i = 0; + while (i < pointLength && !foundIntPoint && !foundExtPoint) { + for (var i2 = 0; i2 < lineString.coordinates.length - 1; i2++) { + var incEndVertices = true; + if (i2 == 0 || i2 == lineString.coordinates.length - 2) { + incEndVertices = false; + } + if (isPointOnLineSegment( + lineString.coordinates[i2], + lineString.coordinates[i2 + 1], + multiPoint.coordinates[i], + incEndVertices)) { + foundIntPoint = true; + } else { + foundExtPoint = true; + } + } + i++; + } + return foundIntPoint && foundExtPoint; +} + +doLineStringsCross(LineString lineString, LineString lineString) { + var doLinesIntersect = lineIntersect(lineString1, lineString2); + if (doLinesIntersect.features.length > 0) { + for (var i = 0; i < lineString1.coordinates.length - 1; i++) { + for (var i2 = 0; i2 < lineString2.coordinates.length - 1; i2++) { + var incEndVertices = true; + if (i2 == 0 || i2 == lineString2.coordinates.length - 2) { + incEndVertices = false; + } + if (isPointOnLineSegment( + lineString1.coordinates[i], + lineString1.coordinates[i + 1], + lineString2.coordinates[i2], + incEndVertices)) { + return true; + } + } + } + } + return false; +} + +doLineStringAndPolygonCross(LineString lineString, Polygon polygon) { + const LineString line = polygonToLine(polygon); + const doLinesIntersect = lineIntersect(lineString, line); + if (doLinesIntersect.features.length > 0) { + return true; + } + return false; +} + +doesMultiPointCrossPoly(MultiPoint multiPoint, Polygon polygon) { + var foundIntPoint = false; + var foundExtPoint = false; + var pointLength = multiPoint.coordinates.length; + for (var i = 0; i < pointLength && (!foundIntPoint || !foundExtPoint); i++) { + if (booleanPointInPolygon( + Point(coordinates: multiPoint.coordinates[i]), polygon)) { + foundIntPoint = true; + } else { + foundExtPoint = true; + } + } + + return foundExtPoint && foundIntPoint; +} + +/** + * Is a point on a line segment + * Only takes into account outer rings + * See http://stackoverflow.com/a/4833823/1979085 + * + * @private + * @param {number[]} lineSegmentStart coord pair of start of line + * @param {number[]} lineSegmentEnd coord pair of end of line + * @param {number[]} pt coord pair of point to check + * @param {boolean} incEnd whether the point is allowed to fall on the line ends + * @returns {boolean} true/false + */ + +isPointOnLineSegment(List lineSegmentStart, List lineSegmentEnd, + List pt, bool incEnd) { + var dxc = pt[0] - lineSegmentStart[0]; + var dyc = pt[1] - lineSegmentStart[1]; + var dxl = lineSegmentEnd[0] - lineSegmentStart[0]; + var dyl = lineSegmentEnd[1] - lineSegmentStart[1]; + var cross = dxc * dyl - dyc * dxl; + if (cross != 0) { + return false; + } + if (incEnd) { + if ((dxl).abs() >= (dyl).abs()) { + return dxl > 0 + ? lineSegmentStart[0] <= pt[0] && pt[0] <= lineSegmentEnd[0] + : lineSegmentEnd[0] <= pt[0] && pt[0] <= lineSegmentStart[0]; + } + return dyl > 0 + ? lineSegmentStart[1] <= pt[1] && pt[1] <= lineSegmentEnd[1] + : lineSegmentEnd[1] <= pt[1] && pt[1] <= lineSegmentStart[1]; + } else { + if ((dxl).abs() >= (dyl).abs()) { + return dxl > 0 + ? lineSegmentStart[0] < pt[0] && pt[0] < lineSegmentEnd[0] + : lineSegmentEnd[0] < pt[0] && pt[0] < lineSegmentStart[0]; + } + return dyl > 0 + ? lineSegmentStart[1] < pt[1] && pt[1] < lineSegmentEnd[1] + : lineSegmentEnd[1] < pt[1] && pt[1] < lineSegmentStart[1]; + } +} + + + +/** + * import { Feature, Geometry, Polygon, LineString, MultiPoint } from "geojson"; +import lineIntersect from "@turf/line-intersect"; +import { polygonToLine } from "@turf/polygon-to-line"; +import booleanPointInPolygon from "@turf/boolean-point-in-polygon"; +import { getGeom } from "@turf/invariant"; +import { point } from "@turf/helpers"; + +/** + * Boolean-Crosses returns True if the intersection results in a geometry whose dimension is one less than + * the maximum dimension of the two source geometries and the intersection set is interior to + * both source geometries. + * + * Boolean-Crosses returns t (TRUE) for only multipoint/polygon, multipoint/linestring, linestring/linestring, linestring/polygon, and linestring/multipolygon comparisons. + * Other comparisons are not supported as they are outside the OpenGIS Simple Features spec and may give unexpected results. + * + * @name booleanCrosses + * @param {Geometry|Feature} feature1 GeoJSON Feature or Geometry + * @param {Geometry|Feature} feature2 GeoJSON Feature or Geometry + * @returns {boolean} true/false + * @example + * var line1 = turf.lineString([[-2, 2], [4, 2]]); + * var line2 = turf.lineString([[1, 1], [1, 2], [1, 3], [1, 4]]); + * + * var cross = turf.booleanCrosses(line1, line2); + * //=true + */ +function booleanCrosses( + feature1: Feature | Geometry, + feature2: Feature | Geometry +): boolean { + var geom1 = getGeom(feature1); + var geom2 = getGeom(feature2); + var type1 = geom1.type; + var type2 = geom2.type; + + switch (type1) { + case "MultiPoint": + switch (type2) { + case "LineString": + return doMultiPointAndLineStringCross(geom1, geom2); + case "Polygon": + return doesMultiPointCrossPoly(geom1, geom2); + default: + throw new Error("feature2 " + type2 + " geometry not supported"); + } + case "LineString": + switch (type2) { + case "MultiPoint": // An inverse operation + return doMultiPointAndLineStringCross(geom2, geom1); + case "LineString": + return doLineStringsCross(geom1, geom2); + case "Polygon": + return doLineStringAndPolygonCross(geom1, geom2); + default: + throw new Error("feature2 " + type2 + " geometry not supported"); + } + case "Polygon": + switch (type2) { + case "MultiPoint": // An inverse operation + return doesMultiPointCrossPoly(geom2, geom1); + case "LineString": // An inverse operation + return doLineStringAndPolygonCross(geom2, geom1); + default: + throw new Error("feature2 " + type2 + " geometry not supported"); + } + default: + throw new Error("feature1 " + type1 + " geometry not supported"); + } +} + +function doMultiPointAndLineStringCross( + multiPoint: MultiPoint, + lineString: LineString +) { + var foundIntPoint = false; + var foundExtPoint = false; + var pointLength = multiPoint.coordinates.length; + var i = 0; + while (i < pointLength && !foundIntPoint && !foundExtPoint) { + for (var i2 = 0; i2 < lineString.coordinates.length - 1; i2++) { + var incEndVertices = true; + if (i2 === 0 || i2 === lineString.coordinates.length - 2) { + incEndVertices = false; + } + if ( + isPointOnLineSegment( + lineString.coordinates[i2], + lineString.coordinates[i2 + 1], + multiPoint.coordinates[i], + incEndVertices + ) + ) { + foundIntPoint = true; + } else { + foundExtPoint = true; + } + } + i++; + } + return foundIntPoint && foundExtPoint; +} + +function doLineStringsCross(lineString1: LineString, lineString2: LineString) { + var doLinesIntersect = lineIntersect(lineString1, lineString2); + if (doLinesIntersect.features.length > 0) { + for (var i = 0; i < lineString1.coordinates.length - 1; i++) { + for (var i2 = 0; i2 < lineString2.coordinates.length - 1; i2++) { + var incEndVertices = true; + if (i2 === 0 || i2 === lineString2.coordinates.length - 2) { + incEndVertices = false; + } + if ( + isPointOnLineSegment( + lineString1.coordinates[i], + lineString1.coordinates[i + 1], + lineString2.coordinates[i2], + incEndVertices + ) + ) { + return true; + } + } + } + } + return false; +} + +function doLineStringAndPolygonCross(lineString: LineString, polygon: Polygon) { + const line: any = polygonToLine(polygon); + const doLinesIntersect = lineIntersect(lineString, line); + if (doLinesIntersect.features.length > 0) { + return true; + } + return false; +} + +function doesMultiPointCrossPoly(multiPoint: MultiPoint, polygon: Polygon) { + var foundIntPoint = false; + var foundExtPoint = false; + var pointLength = multiPoint.coordinates.length; + for (let i = 0; i < pointLength && (!foundIntPoint || !foundExtPoint); i++) { + if (booleanPointInPolygon(point(multiPoint.coordinates[i]), polygon)) { + foundIntPoint = true; + } else { + foundExtPoint = true; + } + } + + return foundExtPoint && foundIntPoint; +} + +/** + * Is a point on a line segment + * Only takes into account outer rings + * See http://stackoverflow.com/a/4833823/1979085 + * + * @private + * @param {number[]} lineSegmentStart coord pair of start of line + * @param {number[]} lineSegmentEnd coord pair of end of line + * @param {number[]} pt coord pair of point to check + * @param {boolean} incEnd whether the point is allowed to fall on the line ends + * @returns {boolean} true/false + */ +function isPointOnLineSegment( + lineSegmentStart: number[], + lineSegmentEnd: number[], + pt: number[], + incEnd: boolean +) { + var dxc = pt[0] - lineSegmentStart[0]; + var dyc = pt[1] - lineSegmentStart[1]; + var dxl = lineSegmentEnd[0] - lineSegmentStart[0]; + var dyl = lineSegmentEnd[1] - lineSegmentStart[1]; + var cross = dxc * dyl - dyc * dxl; + if (cross !== 0) { + return false; + } + if (incEnd) { + if (Math.abs(dxl) >= Math.abs(dyl)) { + return dxl > 0 + ? lineSegmentStart[0] <= pt[0] && pt[0] <= lineSegmentEnd[0] + : lineSegmentEnd[0] <= pt[0] && pt[0] <= lineSegmentStart[0]; + } + return dyl > 0 + ? lineSegmentStart[1] <= pt[1] && pt[1] <= lineSegmentEnd[1] + : lineSegmentEnd[1] <= pt[1] && pt[1] <= lineSegmentStart[1]; + } else { + if (Math.abs(dxl) >= Math.abs(dyl)) { + return dxl > 0 + ? lineSegmentStart[0] < pt[0] && pt[0] < lineSegmentEnd[0] + : lineSegmentEnd[0] < pt[0] && pt[0] < lineSegmentStart[0]; + } + return dyl > 0 + ? lineSegmentStart[1] < pt[1] && pt[1] < lineSegmentEnd[1] + : lineSegmentEnd[1] < pt[1] && pt[1] < lineSegmentStart[1]; + } +} + +export default booleanCrosses; + */ \ No newline at end of file diff --git a/lib/src/booleans/boolean_disjoint.dart b/lib/src/booleans/boolean_disjoint.dart new file mode 100644 index 00000000..9df83759 --- /dev/null +++ b/lib/src/booleans/boolean_disjoint.dart @@ -0,0 +1,173 @@ +import '../../helpers.dart'; +import '../../meta.dart'; + +/** + * Boolean-disjoint returns (TRUE) if the intersection of the two geometries is an empty set. + * + * @name booleanDisjoint + * @param {Geometry|Feature} feature1 GeoJSON Feature or Geometry + * @param {Geometry|Feature} feature2 GeoJSON Feature or Geometry + * @returns {boolean} true/false + * @example + * var point = turf.point([2, 2]); + * var line = turf.lineString([[1, 1], [1, 2], [1, 3], [1, 4]]); + * + * turf.booleanDisjoint(line, point); + * //=true + */ +bool booleanDisjoint(GeoJSONObject feature1, GeoJSONObject feature2) { + var bool = true; + flattenEach(feature1, (flatten1, featureIndex, multiFeatureIndex) { + flattenEach(feature2, (flatten2, featureIndex, multiFeatureIndex) { + if (bool == false) { + return false; + } + bool = disjoint(flatten1.geometry!, flatten2.geometry!); + }); + }); + return bool; +} + +/** + * Disjoint operation for simple Geometries (Point/LineString/Polygon) + * + * @private + * @param {Geometry} geom1 GeoJSON Geometry + * @param {Geometry} geom2 GeoJSON Geometry + * @returns {boolean} true/false + */ +disjoint(GeometryType geom1, GeometryType geom2) { + switch (geom1.runtimeType) { + case Point: + switch (geom2.runtimeType) { + case Point: + return !compareCoords(geom1.coordinates, geom2.coordinates); + case LineString: + return !isPointOnLine(geom2 as LineString, geom1 as Point); + case Polygon: + return !booleanPointInPolygon(geom1, geom2); + } + /* istanbul ignore next */ + break; + case LineString: + switch (geom2.runtimeType) { + case Point: + return !isPointOnLine(geom1 as LineString, geom2 as Point); + case LineString: + return !isLineOnLine(geom1 as LineString, geom2 as LineString); + case Polygon: + return !isLineInPoly(geom2 as Polygon, geom1 as LineString); + } + /* istanbul ignore next */ + break; + case Polygon: + switch (geom2.runtimeType) { + case Point: + return !booleanPointInPolygon(geom2, geom1); + case LineString: + return !isLineInPoly(geom1 as Polygon, geom2 as LineString); + case Polygon: + return !isPolyInPoly(geom2 as Polygon, geom1 as Polygon); + } + } + return false; +} + +// http://stackoverflow.com/a/11908158/1979085 +isPointOnLine(LineString lineString, Point pt) { + for (var i = 0; i < lineString.coordinates.length - 1; i++) { + if (isPointOnLineSegment(lineString.coordinates[i], + lineString.coordinates[i + 1], pt.coordinates)) { + return true; + } + } + return false; +} + +isLineOnLine(LineString lineString1, LineString lineString2) { + var doLinesIntersect = lineIntersect(lineString1, lineString2); + if (doLinesIntersect.features.length > 0) { + return true; + } + return false; +} + +isLineInPoly(Polygon polygon, LineString lineString) { + for (var coord in lineString.coordinates) { + if (booleanPointInPolygon(coord, polygon)) { + return true; + } + } + const doLinesIntersect = lineIntersect(lineString, polygonToLine(polygon)); + if (doLinesIntersect.features.length > 0) { + return true; + } + return false; +} + +/** + * Is Polygon (geom1) in Polygon (geom2) + * Only takes into account outer rings + * See http://stackoverflow.com/a/4833823/1979085 + * + * @private + * @param {Geometry|Feature} feature1 Polygon1 + * @param {Geometry|Feature} feature2 Polygon2 + * @returns {boolean} true/false + */ +isPolyInPoly(Polygon feature1, Polygon feature2) { + for (var coord1 in feature1.coordinates[0]) { + if (booleanPointInPolygon(coord1, feature2)) { + return true; + } + } + for (var coord2 in feature2.coordinates[0]) { + if (booleanPointInPolygon(coord2, feature1)) { + return true; + } + } + const doLinesIntersect = + lineIntersect(polygonToLine(feature1), polygonToLine(feature2)); + if (doLinesIntersect.features.length > 0) { + return true; + } + return false; +} + +isPointOnLineSegment(Point lineSegmentStart, Point lineSegmentEnd, Point pt) { + var dxc = pt.coordinates[0]! - lineSegmentStart.coordinates[0]!; + var dyc = pt.coordinates[1]! - lineSegmentStart.coordinates[1]!; + var dxl = lineSegmentEnd.coordinates[0]! - lineSegmentStart.coordinates[0]!; + var dyl = lineSegmentEnd.coordinates[1]! - lineSegmentStart.coordinates[1]!; + var cross = dxc * dyl - dyc * dxl; + if (cross != 0) { + return false; + } + if ((dxl).abs() >= (dyl).abs()) { + if (dxl > 0) { + return lineSegmentStart.coordinates[0]! <= pt.coordinates[0]! && + pt.coordinates[0]! <= lineSegmentEnd.coordinates[0]!; + } else { + return lineSegmentEnd.coordinates[0]! <= pt.coordinates[0]! && + pt.coordinates[0]! <= lineSegmentStart.coordinates[0]!; + } + } else if (dyl > 0) { + return lineSegmentStart.coordinates[1]! <= pt.coordinates[1]! && + pt.coordinates[1]! <= lineSegmentEnd.coordinates[1]!; + } else { + return lineSegmentEnd.coordinates[1]! <= pt.coordinates[1]! && + pt.coordinates[1]! <= lineSegmentStart.coordinates[1]!; + } +} + +/** + * compareCoords + * + * @private + * @param {Position} pair1 point [x,y] + * @param {Position} pair2 point [x,y] + * @returns {boolean} true/false if coord pairs match + */ +compareCoords(Position pair1, Position pair2) { + return pair1[0] == pair2[0] && pair1[1] == pair2[1]; +} diff --git a/lib/src/booleans/boolean_equal.dart b/lib/src/booleans/boolean_equal.dart new file mode 100644 index 00000000..329c7468 --- /dev/null +++ b/lib/src/booleans/boolean_equal.dart @@ -0,0 +1,93 @@ +import '../../helpers.dart'; +import '../invariant.dart'; + +/** + * Determine whether two geometries of the same type have identical X,Y coordinate values. + * See http://edndoc.esri.com/arcsde/9.0/general_topics/understand_spatial_relations.htm + * + * @name booleanEqual + * @param {Geometry|Feature} feature1 GeoJSON input + * @param {Geometry|Feature} feature2 GeoJSON input + * @param {Object} [options={}] Optional parameters + * @param {number} [options.precision=6] decimal precision to use when comparing coordinates + * @returns {boolean} true if the objects are equal, false otherwise + * @example + * var pt1 = turf.point([0, 0]); + * var pt2 = turf.point([0, 0]); + * var pt3 = turf.point([1, 1]); + * + * turf.booleanEqual(pt1, pt2); + * //= true + * turf.booleanEqual(pt2, pt3); + * //= false + */ +bool booleanEqual(GeoJSONObject feature1, GeoJSONObject feature2, + {num? precision}) { + precision = precision ?? 6; + + if (!(precision >= 0)) { + throw Exception("precision must be a positive number"); + } + + var type1 = getGeom(feature1).runtimeType; + var type2 = getGeom(feature2).runtimeType; + if (type1 != type2) return false; + + const equality = GeojsonEquality({precision: precision}); + return equality.compare(cleanCoords(feature1), cleanCoords(feature2)); +} + + + +/** import { Feature, Geometry } from "geojson"; +import GeojsonEquality from "geojson-equality"; +import cleanCoords from "@turf/clean-coords"; +import { getGeom } from "@turf/invariant"; + +/** + * Determine whether two geometries of the same type have identical X,Y coordinate values. + * See http://edndoc.esri.com/arcsde/9.0/general_topics/understand_spatial_relations.htm + * + * @name booleanEqual + * @param {Geometry|Feature} feature1 GeoJSON input + * @param {Geometry|Feature} feature2 GeoJSON input + * @param {Object} [options={}] Optional parameters + * @param {number} [options.precision=6] decimal precision to use when comparing coordinates + * @returns {boolean} true if the objects are equal, false otherwise + * @example + * var pt1 = turf.point([0, 0]); + * var pt2 = turf.point([0, 0]); + * var pt3 = turf.point([1, 1]); + * + * turf.booleanEqual(pt1, pt2); + * //= true + * turf.booleanEqual(pt2, pt3); + * //= false + */ + booleanEqual( + feature1: Feature | Geometry, + feature2: Feature | Geometry, + options: { + precision?: number; + } = {} +): boolean { + let precision = options.precision; + + precision = + precision === undefined || precision === null || isNaN(precision) + ? 6 + : precision; + + if (typeof precision !== "number" || !(precision >= 0)) { + throw new Error("precision must be a positive number"); + } + + const type1 = getGeom(feature1).type; + const type2 = getGeom(feature2).type; + if (type1 !== type2) return false; + + const equality = new GeojsonEquality({ precision: precision }); + return equality.compare(cleanCoords(feature1), cleanCoords(feature2)); +} + +export default booleanEqual; */ \ No newline at end of file diff --git a/lib/src/booleans/boolean_intersect.dart b/lib/src/booleans/boolean_intersect.dart new file mode 100644 index 00000000..682ea6f2 --- /dev/null +++ b/lib/src/booleans/boolean_intersect.dart @@ -0,0 +1,66 @@ +import '../../helpers.dart'; +import '../../meta.dart'; +import 'boolean_disjoint.dart'; + +/** + * Boolean-intersects returns (TRUE) two geometries intersect. + * + * @name booleanIntersects + * @param {Geometry|Feature} feature1 GeoJSON Feature or Geometry + * @param {Geometry|Feature} feature2 GeoJSON Feature or Geometry + * @returns {boolean} true/false + * @example + * var point = turf.point([2, 2]); + * var line = turf.lineString([[1, 1], [1, 2], [1, 3], [1, 4]]); + * + * turf.booleanIntersects(line, point); + * //=true + */ +booleanIntersects(GeoJSONObject feature1, GeoJSONObject feature2) { + var bool = false; + flattenEach(feature1, (flatten1, featureIndex, multiFeatureIndex) { + flattenEach(feature2, (flatten2, featureIndex, multiFeatureIndex) { + if (bool == true) { + return true; + } + bool = !booleanDisjoint(flatten1, flatten2); + }); + }); + return bool; +} + +/** + * import { Feature, Geometry } from "geojson"; +import booleanDisjoint from "@turf/boolean-disjoint"; +import { flattenEach } from "@turf/meta"; + +/** + * Boolean-intersects returns (TRUE) two geometries intersect. + * + * @name booleanIntersects + * @param {Geometry|Feature} feature1 GeoJSON Feature or Geometry + * @param {Geometry|Feature} feature2 GeoJSON Feature or Geometry + * @returns {boolean} true/false + * @example + * var point = turf.point([2, 2]); + * var line = turf.lineString([[1, 1], [1, 2], [1, 3], [1, 4]]); + * + * turf.booleanIntersects(line, point); + * //=true + */ +export default function booleanIntersects( + feature1: Feature | Geometry, + feature2: Feature | Geometry +) { + let bool = false; + flattenEach(feature1, (flatten1) => { + flattenEach(feature2, (flatten2) => { + if (bool === true) { + return true; + } + bool = !booleanDisjoint(flatten1.geometry, flatten2.geometry); + }); + }); + return bool; +} + */ \ No newline at end of file diff --git a/lib/src/booleans/boolean_overlap.dart b/lib/src/booleans/boolean_overlap.dart new file mode 100644 index 00000000..88d6d576 --- /dev/null +++ b/lib/src/booleans/boolean_overlap.dart @@ -0,0 +1,199 @@ +import { Feature, Geometry, MultiPoint } from "geojson"; +import { segmentEach } from "@turf/meta"; +import { getGeom } from "@turf/invariant"; +import lineOverlap from "@turf/line-overlap"; +import lineIntersect from "@turf/line-intersect"; +import +import '../../helpers.dart'; +import '../../line_segment.dart'; +import '../invariant.dart';GeojsonEquality from "geojson-equality"; + +/** + * Compares two geometries of the same dimension and returns true if their intersection set results in a geometry + * different from both but of the same dimension. It applies to Polygon/Polygon, LineString/LineString, + * Multipoint/Multipoint, MultiLineString/MultiLineString and MultiPolygon/MultiPolygon. + * + * In other words, it returns true if the two geometries overlap, provided that neither completely contains the other. + * + * @name booleanOverlap + * @param {Geometry|Feature} feature1 input + * @param {Geometry|Feature} feature2 input + * @returns {boolean} true/false + * @example + * var poly1 = turf.polygon([[[0,0],[0,5],[5,5],[5,0],[0,0]]]); + * var poly2 = turf.polygon([[[1,1],[1,6],[6,6],[6,1],[1,1]]]); + * var poly3 = turf.polygon([[[10,10],[10,15],[15,15],[15,10],[10,10]]]); + * + * turf.booleanOverlap(poly1, poly2) + * //=true + * turf.booleanOverlap(poly2, poly3) + * //=false + */ + booleanOverlap( + GeometryObject feature1, + GeometryObject feature2 +) { + var geom1 = getGeom(feature1); + var geom2 = getGeom(feature2); + var type1 = geom1.type; + var type2 = geom2.type; + + if ( + (type1 == MultiPoint && type2 != MultiPoint) || + ((type1 == LineString || type1 == MultiLineString) && + type2 != LineString && + type2 != MultiLineString) || + ((type1 == Polygon || type1 == MultiPolygon) && + type2 != Polygon && + type2 != MultiPolygon) + ) { + throw Exception("features must be of the same type"); + } + if (type1 == Point) throw Exception("Point geometry not supported"); + + // features must be not equal + const equality = new GeojsonEquality({ precision: 6 }); + if (equality.compare(feature1 as any, feature2 as any)) return false; + + var overlap = 0; + + switch (type1) { + case MultiPoint: + for (var i = 0; i < (geom1 as MultiPoint).coordinates.length; i++) { + for (var j = 0; j < (geom2 as MultiPoint).coordinates.length; j++) { + var coord1 = geom1.coordinates[i]; + var coord2 = geom2.coordinates[j]; + if (coord1[0] == coord2[0] && coord1[1] == coord2[1]) { + return true; + } + } + } + return false; + + case LineString: + case MultiLineString: + segmentEach(feature1, (segment1, + featureIndex, + multiFeatureIndex, + geometryIndex, + segmentIndex,) { + segmentEach(feature2, (segment2, featureIndex, + multiFeatureIndex, + geometryIndex, + segmentIndex,) { + if (lineOverlap(segment1, segment2).features.length) overlap++; + }); + }); + break; + + case Polygon: + case MultiPolygon: + segmentEach(feature1, (segment1, featureIndex, + multiFeatureIndex, + geometryIndex, + segmentIndex,) { + segmentEach(feature2, (segment2, featureIndex, + multiFeatureIndex, + geometryIndex, + segmentIndex,) { + if (lineIntersect(segment1, segment2).features.length) overlap++; + }); + }); + break; + } + + return overlap > 0; +} + +/** + * import { Feature, Geometry, MultiPoint } from "geojson"; +import { segmentEach } from "@turf/meta"; +import { getGeom } from "@turf/invariant"; +import lineOverlap from "@turf/line-overlap"; +import lineIntersect from "@turf/line-intersect"; +import GeojsonEquality from "geojson-equality"; + +/** + * Compares two geometries of the same dimension and returns true if their intersection set results in a geometry + * different from both but of the same dimension. It applies to Polygon/Polygon, LineString/LineString, + * Multipoint/Multipoint, MultiLineString/MultiLineString and MultiPolygon/MultiPolygon. + * + * In other words, it returns true if the two geometries overlap, provided that neither completely contains the other. + * + * @name booleanOverlap + * @param {Geometry|Feature} feature1 input + * @param {Geometry|Feature} feature2 input + * @returns {boolean} true/false + * @example + * var poly1 = turf.polygon([[[0,0],[0,5],[5,5],[5,0],[0,0]]]); + * var poly2 = turf.polygon([[[1,1],[1,6],[6,6],[6,1],[1,1]]]); + * var poly3 = turf.polygon([[[10,10],[10,15],[15,15],[15,10],[10,10]]]); + * + * turf.booleanOverlap(poly1, poly2) + * //=true + * turf.booleanOverlap(poly2, poly3) + * //=false + */ +export default function booleanOverlap( + feature1: Feature | Geometry, + feature2: Feature | Geometry +): boolean { + const geom1 = getGeom(feature1); + const geom2 = getGeom(feature2); + const type1 = geom1.type; + const type2 = geom2.type; + + if ( + (type1 == "MultiPoint" && type2 !== "MultiPoint") || + ((type1 === "LineString" || type1 === "MultiLineString") && + type2 !== "LineString" && + type2 !== "MultiLineString") || + ((type1 === "Polygon" || type1 === "MultiPolygon") && + type2 !== "Polygon" && + type2 !== "MultiPolygon") + ) { + throw new Error("features must be of the same type"); + } + if (type1 === "Point") throw new Error("Point geometry not supported"); + + // features must be not equal + const equality = new GeojsonEquality({ precision: 6 }); + if (equality.compare(feature1 as any, feature2 as any)) return false; + + let overlap = 0; + + switch (type1) { + case "MultiPoint": + for (var i = 0; i < (geom1 as MultiPoint).coordinates.length; i++) { + for (var j = 0; j < (geom2 as MultiPoint).coordinates.length; j++) { + var coord1 = geom1.coordinates[i]; + var coord2 = geom2.coordinates[j]; + if (coord1[0] === coord2[0] && coord1[1] === coord2[1]) { + return true; + } + } + } + return false; + + case "LineString": + case "MultiLineString": + segmentEach(feature1, (segment1) => { + segmentEach(feature2, (segment2) => { + if (lineOverlap(segment1!, segment2!).features.length) overlap++; + }); + }); + break; + + case "Polygon": + case "MultiPolygon": + segmentEach(feature1, (segment1) => { + segmentEach(feature2, (segment2) => { + if (lineIntersect(segment1!, segment2!).features.length) overlap++; + }); + }); + break; + } + + return overlap > 0; +} + */ \ No newline at end of file diff --git a/lib/src/booleans/boolean_parallel.dart b/lib/src/booleans/boolean_parallel.dart new file mode 100644 index 00000000..09eab5d7 --- /dev/null +++ b/lib/src/booleans/boolean_parallel.dart @@ -0,0 +1,141 @@ +import '../../helpers.dart'; +import '../../line_segment.dart'; + +/** + * Boolean-Parallel returns True if each segment of `line1` is parallel to the correspondent segment of `line2` + * + * @name booleanParallel + * @param {Geometry|Feature} line1 GeoJSON Feature or Geometry + * @param {Geometry|Feature} line2 GeoJSON Feature or Geometry + * @returns {boolean} true/false if the lines are parallel + * @example + * var line1 = turf.lineString([[0, 0], [0, 1]]); + * var line2 = turf.lineString([[1, 0], [1, 1]]); + * + * turf.booleanParallel(line1, line2); + * //=true + */ +bool booleanParallel(GeoJSONObject line1, GeoJSONObject line2) { + var type1 = getType(line1, "line1"); + if (type1 != "LineString") throw Exception("line1 must be a LineString"); + var type2 = getType(line2, "line2"); + if (type2 != "LineString") throw Exception("line2 must be a LineString"); + + var segments1 = lineSegment(cleanCoords(line1)).features; + var segments2 = lineSegment(cleanCoords(line2)).features; + + for (var i = 0; i < segments1.length; i++) { + var segment1 = segments1[i].geometry!.coordinates; + if (!segments2[i]) break; + var segment2 = segments2[i].geometry!.coordinates; + if (!isParallel(segment1, segment2)) return false; + } + return true; +} + +/** + * Compares slopes and return result + * + * @private + * @param {Geometry|Feature} segment1 Geometry or Feature + * @param {Geometry|Feature} segment2 Geometry or Feature + * @returns {boolean} if slopes are equal + */ +isParallel(List segment1, List segment2) { + var slope1 = bearingToAzimuth(rhumbBearing(segment1[0], segment1[1])); + var slope2 = bearingToAzimuth(rhumbBearing(segment2[0], segment2[1])); + return slope1 == slope2; +} + +/** + * Returns Feature's type + * + * @private + * @param {Geometry|Feature} geojson Geometry or Feature + * @param {string} name of the variable + * @returns {string} Feature's type + */ +getType(GeoJSONObject geojson, String name) { + if ((geojson as Feature).geometry != null) { + return geojson.geometry.runtimeType; + } + if (geojson.runtimeType is GeometryType) + return geojson.type; // if GeoJSON geometry + throw Exception("Invalid GeoJSON object for $name"); +} + + +/**import { Feature, Geometry, LineString, Position } from "geojson"; +import cleanCoords from "@turf/clean-coords"; +import lineSegment from "@turf/line-segment"; +import rhumbBearing from "@turf/rhumb-bearing"; +import { bearingToAzimuth } from "@turf/helpers"; + +/** + * Boolean-Parallel returns True if each segment of `line1` is parallel to the correspondent segment of `line2` + * + * @name booleanParallel + * @param {Geometry|Feature} line1 GeoJSON Feature or Geometry + * @param {Geometry|Feature} line2 GeoJSON Feature or Geometry + * @returns {boolean} true/false if the lines are parallel + * @example + * var line1 = turf.lineString([[0, 0], [0, 1]]); + * var line2 = turf.lineString([[1, 0], [1, 1]]); + * + * turf.booleanParallel(line1, line2); + * //=true + */ + booleanParallel( + line1: Feature | LineString, + line2: Feature | LineString +): boolean { + // validation + if (!line1) throw new Error("line1 is required"); + if (!line2) throw new Error("line2 is required"); + var type1 = getType(line1, "line1"); + if (type1 !== "LineString") throw new Error("line1 must be a LineString"); + var type2 = getType(line2, "line2"); + if (type2 !== "LineString") throw new Error("line2 must be a LineString"); + + var segments1 = lineSegment(cleanCoords(line1)).features; + var segments2 = lineSegment(cleanCoords(line2)).features; + + for (var i = 0; i < segments1.length; i++) { + var segment1 = segments1[i].geometry.coordinates; + if (!segments2[i]) break; + var segment2 = segments2[i].geometry.coordinates; + if (!isParallel(segment1, segment2)) return false; + } + return true; +} + +/** + * Compares slopes and return result + * + * @private + * @param {Geometry|Feature} segment1 Geometry or Feature + * @param {Geometry|Feature} segment2 Geometry or Feature + * @returns {boolean} if slopes are equal + */ +function isParallel(segment1: Position[], segment2: Position[]) { + var slope1 = bearingToAzimuth(rhumbBearing(segment1[0], segment1[1])); + var slope2 = bearingToAzimuth(rhumbBearing(segment2[0], segment2[1])); + return slope1 === slope2; +} + +/** + * Returns Feature's type + * + * @private + * @param {Geometry|Feature} geojson Geometry or Feature + * @param {string} name of the variable + * @returns {string} Feature's type + */ +function getType(geojson: Geometry | Feature, name: string) { + if ((geojson as Feature).geometry && (geojson as Feature).geometry.type) + return (geojson as Feature).geometry.type; + if (geojson.type) return geojson.type; // if GeoJSON geometry + throw new Error("Invalid GeoJSON object for " + name); +} + +export default booleanParallel; */ \ No newline at end of file diff --git a/lib/src/booleans/boolean_point_in_polygon.dart b/lib/src/booleans/boolean_point_in_polygon.dart new file mode 100644 index 00000000..75588531 --- /dev/null +++ b/lib/src/booleans/boolean_point_in_polygon.dart @@ -0,0 +1,169 @@ +// http://en.wikipedia.org/wiki/Even%E2%80%93odd_rule +// modified from: https://github.com/substack/point-in-polygon/blob/master/index.js +// which was modified from http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html +import '../../helpers.dart'; +import '../invariant.dart'; + +/** + * Takes a {@link Point} and a {@link Polygon} or {@link MultiPolygon} and determines if the point + * resides inside the polygon. The polygon can be convex or concave. The function accounts for holes. + * + * @name booleanPointInPolygon + * @param {Coord} point input point + * @param {Feature} polygon input polygon or multipolygon + * @param {Object} [options={}] Optional parameters + * @param {boolean} [options.ignoreBoundary=false] True if polygon boundary should be ignored when determining if + * the point is inside the polygon otherwise false. + * @returns {boolean} `true` if the Point is inside the Polygon; `false` if the Point is not inside the Polygon + * @example + * var pt = turf.point([-77, 44]); + * var poly = turf.polygon([[ + * [-81, 41], + * [-81, 47], + * [-72, 47], + * [-72, 41], + * [-81, 41] + * ]]); + * + * turf.booleanPointInPolygon(pt, poly); + * //= true + */ +booleanPointInPolygon(Point point, GeometryObject polygon, + {bool? ignoreBoundary}) { + var pt = getCoord(point); + var geom = getGeom(polygon); + var type = geom.type; + var bbox = polygon.bbox; + var polys = geom.coordinates; + + // Quick elimination if point is not inside bbox + if (bbox != null && inBBox(pt, bbox) == false) { + return false; + } + + if (type == "Polygon") { + polys = [polys]; + } + var result = false; + for (var i = 0; i < polys.length; ++i) { + const polyResult = pip(pt, polys[i]); + if (polyResult == 0) { + return ignoreBoundary == null ? false : true; + } else if (polyResult) { + result = true; + } + } + + return result; +} + +/** + * inBBox + * + * @private + * @param {Position} pt point [x,y] + * @param {BBox} bbox BBox [west, south, east, north] + * @returns {boolean} true/false if point is inside BBox + */ +inBBox(Position pt, BBox bbox) { + return (bbox[0]! <= pt[0]! && + bbox[1]! <= pt[1]! && + bbox[2]! >= pt[0]! && + bbox[3]! >= pt[1]!); +} + +/** + * import pip from "point-in-polygon-hao"; +import { + BBox, + Feature, + MultiPolygon, + Polygon, + GeoJsonProperties, +} from "geojson"; +import { Coord } from "@turf/helpers"; +import { getCoord, getGeom } from "@turf/invariant"; + +// http://en.wikipedia.org/wiki/Even%E2%80%93odd_rule +// modified from: https://github.com/substack/point-in-polygon/blob/master/index.js +// which was modified from http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html +/** + * Takes a {@link Point} and a {@link Polygon} or {@link MultiPolygon} and determines if the point + * resides inside the polygon. The polygon can be convex or concave. The function accounts for holes. + * + * @name booleanPointInPolygon + * @param {Coord} point input point + * @param {Feature} polygon input polygon or multipolygon + * @param {Object} [options={}] Optional parameters + * @param {boolean} [options.ignoreBoundary=false] True if polygon boundary should be ignored when determining if + * the point is inside the polygon otherwise false. + * @returns {boolean} `true` if the Point is inside the Polygon; `false` if the Point is not inside the Polygon + * @example + * var pt = turf.point([-77, 44]); + * var poly = turf.polygon([[ + * [-81, 41], + * [-81, 47], + * [-72, 47], + * [-72, 41], + * [-81, 41] + * ]]); + * + * turf.booleanPointInPolygon(pt, poly); + * //= true + */ +export default function booleanPointInPolygon< + G extends Polygon | MultiPolygon, + P = GeoJsonProperties +>( + point: Coord, + polygon: Feature | G, + options: { + ignoreBoundary?: boolean; + } = {} +) { + // validation + if (!point) { + throw new Error("point is required"); + } + if (!polygon) { + throw new Error("polygon is required"); + } + + const pt = getCoord(point); + const geom = getGeom(polygon); + const type = geom.type; + const bbox = polygon.bbox; + let polys: any[] = geom.coordinates; + + // Quick elimination if point is not inside bbox + if (bbox && inBBox(pt, bbox) === false) { + return false; + } + + if (type === "Polygon") { + polys = [polys]; + } + let result = false; + for (var i = 0; i < polys.length; ++i) { + const polyResult = pip(pt, polys[i]); + if (polyResult === 0) return options.ignoreBoundary ? false : true; + else if (polyResult) result = true; + } + + return result; +} + +/** + * inBBox + * + * @private + * @param {Position} pt point [x,y] + * @param {BBox} bbox BBox [west, south, east, north] + * @returns {boolean} true/false if point is inside BBox + */ +function inBBox(pt: number[], bbox: BBox) { + return ( + bbox[0] <= pt[0] && bbox[1] <= pt[1] && bbox[2] >= pt[0] && bbox[3] >= pt[1] + ); +} + */ \ No newline at end of file diff --git a/lib/src/booleans/boolean_point_on_line.dart b/lib/src/booleans/boolean_point_on_line.dart new file mode 100644 index 00000000..739d2a1a --- /dev/null +++ b/lib/src/booleans/boolean_point_on_line.dart @@ -0,0 +1,232 @@ +import 'package:turf/helpers.dart'; + +import '../invariant.dart'; + +/** + * Returns true if a point is on a line. Accepts a optional parameter to ignore the + * start and end vertices of the linestring. + * + * @name booleanPointOnLine + * @param {Coord} pt GeoJSON Point + * @param {Feature} line GeoJSON LineString + * @param {Object} [options={}] Optional parameters + * @param {boolean} [options.ignoreEndVertices=false] whether to ignore the start and end vertices. + * @param {number} [options.epsilon] Fractional number to compare with the cross product result. Useful for dealing with floating points such as lng/lat points + * @returns {boolean} true/false + * @example + * var pt = turf.point([0, 0]); + * var line = turf.lineString([[-1, -1],[1, 1],[1.5, 2.2]]); + * var isPointOnLine = turf.booleanPointOnLine(pt, line); + * //=true + */ +bool booleanPointOnLine(Point pt, LineString line, + {bool? ignoreEndVertices, num? epsilon}) { + // Normalize inputs + var ptCoords = getCoord(pt); + var lineCoords = getCoords(line); + + // Main + for (var i = 0; i < lineCoords.length - 1; i++) { + dynamic ignoreBoundary = false; + if (ignoreEndVertices != null && ignoreEndVertices) { + if (i == 0) { + ignoreBoundary = "start"; + } + if (i == lineCoords.length - 2) { + ignoreBoundary = "end"; + } + if (i == 0 && i + 1 == lineCoords.length - 1) { + ignoreBoundary = "both"; + } + } + if (isPointOnLineSegment( + lineCoords[i], lineCoords[i + 1], ptCoords, ignoreBoundary, epsilon)) { + return true; + } + } + return false; +} + +// See http://stackoverflow.com/a/4833823/1979085 +// See https://stackoverflow.com/a/328122/1048847 +/** + * @private + * @param {Position} lineSegmentStart coord pair of start of line + * @param {Position} lineSegmentEnd coord pair of end of line + * @param {Position} pt coord pair of point to check + * @param {boolean|string} excludeBoundary whether the point is allowed to fall on the line ends. + * @param {number} epsilon Fractional number to compare with the cross product result. Useful for dealing with floating points such as lng/lat points + * If true which end to ignore. + * @returns {boolean} true/false + */ +bool isPointOnLineSegment(Point lineSegmentStart, Point lineSegmentEnd, + Position pt, dynamic excludeBoundary, num? epsilon) { + var x = pt[0]!; + var y = pt[1]!; + var x1 = lineSegmentStart.coordinates[0]; + var y1 = lineSegmentStart.coordinates[1]; + var x2 = lineSegmentEnd.coordinates[0]; + var y2 = lineSegmentEnd.coordinates[1]; + var dxc = pt[0]! - x1!; + var dyc = pt[1]! - y1!; + var dxl = x2! - x1; + var dyl = y2! - y1; + var cross = dxc * dyl - dyc * dxl; + if (epsilon != null) { + if ((cross).abs() > epsilon) { + return false; + } + } else if (cross != 0) { + return false; + } + if (!excludeBoundary) { + if ((dxl).abs() >= (dyl).abs()) { + return dxl > 0 ? x1 <= x && x <= x2 : x2 <= x && x <= x1; + } + return dyl > 0 ? y1 <= y && y <= y2 : y2 <= y && y <= y1; + } else if (excludeBoundary == "start") { + if ((dxl).abs() >= (dyl).abs()) { + return dxl > 0 ? x1 < x && x <= x2 : x2 <= x && x < x1; + } + return dyl > 0 ? y1 < y && y <= y2 : y2 <= y && y < y1; + } else if (excludeBoundary == "end") { + if ((dxl).abs() >= (dyl).abs()) { + return dxl > 0 ? x1 <= x && x < x2 : x2 < x && x <= x1; + } + return dyl > 0 ? y1 <= y && y < y2 : y2 < y && y <= y1; + } else if (excludeBoundary == "both") { + if ((dxl).abs() >= (dyl).abs()) { + return dxl > 0 ? x1 < x && x < x2 : x2 < x && x < x1; + } + return dyl > 0 ? y1 < y && y < y2 : y2 < y && y < y1; + } + return false; +} + + +/** + * import { Feature, LineString } from "geojson"; +import { Coord } from "@turf/helpers"; +import { getCoord, getCoords } from "@turf/invariant"; + +/** + * Returns true if a point is on a line. Accepts a optional parameter to ignore the + * start and end vertices of the linestring. + * + * @name booleanPointOnLine + * @param {Coord} pt GeoJSON Point + * @param {Feature} line GeoJSON LineString + * @param {Object} [options={}] Optional parameters + * @param {boolean} [options.ignoreEndVertices=false] whether to ignore the start and end vertices. + * @param {number} [options.epsilon] Fractional number to compare with the cross product result. Useful for dealing with floating points such as lng/lat points + * @returns {boolean} true/false + * @example + * var pt = turf.point([0, 0]); + * var line = turf.lineString([[-1, -1],[1, 1],[1.5, 2.2]]); + * var isPointOnLine = turf.booleanPointOnLine(pt, line); + * //=true + */ +function booleanPointOnLine( + pt: Coord, + line: Feature | LineString, + options: { + ignoreEndVertices?: boolean; + epsilon?: number; + } = {} +): boolean { + // Normalize inputs + const ptCoords = getCoord(pt); + const lineCoords = getCoords(line); + + // Main + for (let i = 0; i < lineCoords.length - 1; i++) { + let ignoreBoundary: boolean | string = false; + if (options.ignoreEndVertices) { + if (i == 0) { + ignoreBoundary = "start"; + } + if (i === lineCoords.length - 2) { + ignoreBoundary = "end"; + } + if (i === 0 && i + 1 === lineCoords.length - 1) { + ignoreBoundary = "both"; + } + } + if ( + isPointOnLineSegment( + lineCoords[i], + lineCoords[i + 1], + ptCoords, + ignoreBoundary, + typeof options.epsilon === "undefined" ? null : options.epsilon + ) + ) { + return true; + } + } + return false; +} + +// See http://stackoverflow.com/a/4833823/1979085 +// See https://stackoverflow.com/a/328122/1048847 +/** + * @private + * @param {Position} lineSegmentStart coord pair of start of line + * @param {Position} lineSegmentEnd coord pair of end of line + * @param {Position} pt coord pair of point to check + * @param {boolean|string} excludeBoundary whether the point is allowed to fall on the line ends. + * @param {number} epsilon Fractional number to compare with the cross product result. Useful for dealing with floating points such as lng/lat points + * If true which end to ignore. + * @returns {boolean} true/false + */ +function isPointOnLineSegment( + lineSegmentStart: number[], + lineSegmentEnd: number[], + pt: number[], + excludeBoundary: string | boolean, + epsilon: number | null +): boolean { + const x = pt[0]; + const y = pt[1]; + const x1 = lineSegmentStart[0]; + const y1 = lineSegmentStart[1]; + const x2 = lineSegmentEnd[0]; + const y2 = lineSegmentEnd[1]; + const dxc = pt[0] - x1; + const dyc = pt[1] - y1; + const dxl = x2 - x1; + const dyl = y2 - y1; + const cross = dxc * dyl - dyc * dxl; + if (epsilon !== null) { + if (Math.abs(cross) > epsilon) { + return false; + } + } else if (cross !== 0) { + return false; + } + if (!excludeBoundary) { + if (Math.abs(dxl) >= Math.abs(dyl)) { + return dxl > 0 ? x1 <= x && x <= x2 : x2 <= x && x <= x1; + } + return dyl > 0 ? y1 <= y && y <= y2 : y2 <= y && y <= y1; + } else if (excludeBoundary === "start") { + if (Math.abs(dxl) >= Math.abs(dyl)) { + return dxl > 0 ? x1 < x && x <= x2 : x2 <= x && x < x1; + } + return dyl > 0 ? y1 < y && y <= y2 : y2 <= y && y < y1; + } else if (excludeBoundary === "end") { + if (Math.abs(dxl) >= Math.abs(dyl)) { + return dxl > 0 ? x1 <= x && x < x2 : x2 < x && x <= x1; + } + return dyl > 0 ? y1 <= y && y < y2 : y2 < y && y <= y1; + } else if (excludeBoundary === "both") { + if (Math.abs(dxl) >= Math.abs(dyl)) { + return dxl > 0 ? x1 < x && x < x2 : x2 < x && x < x1; + } + return dyl > 0 ? y1 < y && y < y2 : y2 < y && y < y1; + } + return false; +} + +export default booleanPointOnLine; + */ \ No newline at end of file diff --git a/lib/src/booleans/boolean_touches.dart b/lib/src/booleans/boolean_touches.dart new file mode 100644 index 00000000..9c6374dc --- /dev/null +++ b/lib/src/booleans/boolean_touches.dart @@ -0,0 +1,1582 @@ + +/** + * Boolean-touches true if none of the points common to both geometries + * intersect the interiors of both geometries. + * @name booleanTouches + * @param {Geometry|Feature} feature1 GeoJSON Feature or Geometry + * @param {Geometry|Feature} feature2 GeoJSON Feature or Geometry + * @returns {boolean} true/false + * @example + * var line = turf.lineString([[1, 1], [1, 2], [1, 3], [1, 4]]); + * var point = turf.point([1, 1]); + * + * turf.booleanTouches(point, line); + * //=true + */ + booleanTouches( + feature1: Feature | Geometry, + feature2: Feature | Geometry +): boolean { + var geom1 = getGeom(feature1); + var geom2 = getGeom(feature2); + var type1 = geom1.type; + var type2 = geom2.type; + + switch (type1) { + case "Point": + switch (type2) { + case "LineString": + return isPointOnLineEnd(geom1, geom2); + case "MultiLineString": + var foundTouchingPoint = false; + for (var ii = 0; ii < geom2.coordinates.length; ii++) { + if ( + isPointOnLineEnd(geom1, { + type: "LineString", + coordinates: geom2.coordinates[ii], + }) + ) + foundTouchingPoint = true; + } + return foundTouchingPoint; + case "Polygon": + for (var i = 0; i < geom2.coordinates.length; i++) { + if ( + booleanPointOnLine(geom1, { + type: "LineString", + coordinates: geom2.coordinates[i], + }) + ) + return true; + } + return false; + case "MultiPolygon": + for (var i = 0; i < geom2.coordinates.length; i++) { + for (var ii = 0; ii < geom2.coordinates[i].length; ii++) { + if ( + booleanPointOnLine(geom1, { + type: "LineString", + coordinates: geom2.coordinates[i][ii], + }) + ) + return true; + } + } + return false; + default: + throw new Error("feature2 " + type2 + " geometry not supported"); + } + case "MultiPoint": + switch (type2) { + case "LineString": + var foundTouchingPoint = false; + for (var i = 0; i < geom1.coordinates.length; i++) { + if (!foundTouchingPoint) { + if ( + isPointOnLineEnd( + { type: "Point", coordinates: geom1.coordinates[i] }, + geom2 + ) + ) + foundTouchingPoint = true; + } + if ( + booleanPointOnLine( + { type: "Point", coordinates: geom1.coordinates[i] }, + geom2, + { ignoreEndVertices: true } + ) + ) + return false; + } + return foundTouchingPoint; + case "MultiLineString": + var foundTouchingPoint = false; + for (var i = 0; i < geom1.coordinates.length; i++) { + for (var ii = 0; ii < geom2.coordinates.length; ii++) { + if (!foundTouchingPoint) { + if ( + isPointOnLineEnd( + { type: "Point", coordinates: geom1.coordinates[i] }, + { type: "LineString", coordinates: geom2.coordinates[ii] } + ) + ) + foundTouchingPoint = true; + } + if ( + booleanPointOnLine( + { type: "Point", coordinates: geom1.coordinates[i] }, + { type: "LineString", coordinates: geom2.coordinates[ii] }, + { ignoreEndVertices: true } + ) + ) + return false; + } + } + return foundTouchingPoint; + case "Polygon": + var foundTouchingPoint = false; + for (var i = 0; i < geom1.coordinates.length; i++) { + if (!foundTouchingPoint) { + if ( + booleanPointOnLine( + { type: "Point", coordinates: geom1.coordinates[i] }, + { type: "LineString", coordinates: geom2.coordinates[0] } + ) + ) + foundTouchingPoint = true; + } + if ( + booleanPointInPolygon( + { type: "Point", coordinates: geom1.coordinates[i] }, + geom2, + { ignoreBoundary: true } + ) + ) + return false; + } + return foundTouchingPoint; + case "MultiPolygon": + var foundTouchingPoint = false; + for (var i = 0; i < geom1.coordinates.length; i++) { + for (var ii = 0; ii < geom2.coordinates.length; ii++) { + if (!foundTouchingPoint) { + if ( + booleanPointOnLine( + { type: "Point", coordinates: geom1.coordinates[i] }, + { + type: "LineString", + coordinates: geom2.coordinates[ii][0], + } + ) + ) + foundTouchingPoint = true; + } + if ( + booleanPointInPolygon( + { type: "Point", coordinates: geom1.coordinates[i] }, + { type: "Polygon", coordinates: geom2.coordinates[ii] }, + { ignoreBoundary: true } + ) + ) + return false; + } + } + return foundTouchingPoint; + default: + throw new Error("feature2 " + type2 + " geometry not supported"); + } + case "LineString": + switch (type2) { + case "Point": + return isPointOnLineEnd(geom2, geom1); + case "MultiPoint": + var foundTouchingPoint = false; + for (var i = 0; i < geom2.coordinates.length; i++) { + if (!foundTouchingPoint) { + if ( + isPointOnLineEnd( + { type: "Point", coordinates: geom2.coordinates[i] }, + geom1 + ) + ) + foundTouchingPoint = true; + } + if ( + booleanPointOnLine( + { type: "Point", coordinates: geom2.coordinates[i] }, + geom1, + { ignoreEndVertices: true } + ) + ) + return false; + } + return foundTouchingPoint; + case "LineString": + var endMatch = false; + if ( + isPointOnLineEnd( + { type: "Point", coordinates: geom1.coordinates[0] }, + geom2 + ) + ) + endMatch = true; + if ( + isPointOnLineEnd( + { + type: "Point", + coordinates: geom1.coordinates[geom1.coordinates.length - 1], + }, + geom2 + ) + ) + endMatch = true; + if (endMatch == false) return false; + for (var i = 0; i < geom1.coordinates.length; i++) { + if ( + booleanPointOnLine( + { type: "Point", coordinates: geom1.coordinates[i] }, + geom2, + { ignoreEndVertices: true } + ) + ) + return false; + } + return endMatch; + case "MultiLineString": + var endMatch = false; + for (var i = 0; i < geom2.coordinates.length; i++) { + if ( + isPointOnLineEnd( + { type: "Point", coordinates: geom1.coordinates[0] }, + { type: "LineString", coordinates: geom2.coordinates[i] } + ) + ) + endMatch = true; + if ( + isPointOnLineEnd( + { + type: "Point", + coordinates: geom1.coordinates[geom1.coordinates.length - 1], + }, + { type: "LineString", coordinates: geom2.coordinates[i] } + ) + ) + endMatch = true; + for (var ii = 0; ii < geom1.coordinates[i].length; ii++) { + if ( + booleanPointOnLine( + { type: "Point", coordinates: geom1.coordinates[ii] }, + { type: "LineString", coordinates: geom2.coordinates[i] }, + { ignoreEndVertices: true } + ) + ) + return false; + } + } + return endMatch; + case "Polygon": + var foundTouchingPoint = false; + for (var i = 0; i < geom1.coordinates.length; i++) { + if (!foundTouchingPoint) { + if ( + booleanPointOnLine( + { type: "Point", coordinates: geom1.coordinates[i] }, + { type: "LineString", coordinates: geom2.coordinates[0] } + ) + ) + foundTouchingPoint = true; + } + if ( + booleanPointInPolygon( + { type: "Point", coordinates: geom1.coordinates[i] }, + geom2, + { ignoreBoundary: true } + ) + ) + return false; + } + return foundTouchingPoint; + case "MultiPolygon": + var foundTouchingPoint = false; + for (var i = 0; i < geom1.coordinates.length; i++) { + for (var ii = 0; ii < geom2.coordinates.length; ii++) { + if (!foundTouchingPoint) { + if ( + booleanPointOnLine( + { type: "Point", coordinates: geom1.coordinates[i] }, + { + type: "LineString", + coordinates: geom2.coordinates[ii][0], + } + ) + ) + foundTouchingPoint = true; + } + } + if ( + booleanPointInPolygon( + { type: "Point", coordinates: geom1.coordinates[i] }, + geom2, + { ignoreBoundary: true } + ) + ) + return false; + } + return foundTouchingPoint; + default: + throw new Error("feature2 " + type2 + " geometry not supported"); + } + case "MultiLineString": + switch (type2) { + case "Point": + for (var i = 0; i < geom1.coordinates.length; i++) { + if ( + isPointOnLineEnd(geom2, { + type: "LineString", + coordinates: geom1.coordinates[i], + }) + ) + return true; + } + return false; + case "MultiPoint": + var foundTouchingPoint = false; + for (var i = 0; i < geom1.coordinates.length; i++) { + for (var ii = 0; ii < geom2.coordinates.length; ii++) { + if (!foundTouchingPoint) { + if ( + isPointOnLineEnd( + { type: "Point", coordinates: geom2.coordinates[ii] }, + { type: "LineString", coordinates: geom1.coordinates[ii] } + ) + ) + foundTouchingPoint = true; + } + if ( + booleanPointOnLine( + { type: "Point", coordinates: geom2.coordinates[ii] }, + { type: "LineString", coordinates: geom1.coordinates[ii] }, + { ignoreEndVertices: true } + ) + ) + return false; + } + } + return foundTouchingPoint; + case "LineString": + var endMatch = false; + for (var i = 0; i < geom1.coordinates.length; i++) { + if ( + isPointOnLineEnd( + { type: "Point", coordinates: geom1.coordinates[i][0] }, + geom2 + ) + ) + endMatch = true; + if ( + isPointOnLineEnd( + { + type: "Point", + coordinates: + geom1.coordinates[i][geom1.coordinates[i].length - 1], + }, + geom2 + ) + ) + endMatch = true; + for (var ii = 0; ii < geom2.coordinates.length; ii++) { + if ( + booleanPointOnLine( + { type: "Point", coordinates: geom2.coordinates[ii] }, + { type: "LineString", coordinates: geom1.coordinates[i] }, + { ignoreEndVertices: true } + ) + ) + return false; + } + } + return endMatch; + case "MultiLineString": + var endMatch = false; + for (var i = 0; i < geom1.coordinates.length; i++) { + for (var ii = 0; ii < geom2.coordinates.length; ii++) { + if ( + isPointOnLineEnd( + { type: "Point", coordinates: geom1.coordinates[i][0] }, + { type: "LineString", coordinates: geom2.coordinates[ii] } + ) + ) + endMatch = true; + if ( + isPointOnLineEnd( + { + type: "Point", + coordinates: + geom1.coordinates[i][geom1.coordinates[i].length - 1], + }, + { type: "LineString", coordinates: geom2.coordinates[ii] } + ) + ) + endMatch = true; + for (var iii = 0; iii < geom1.coordinates[i].length; iii++) { + if ( + booleanPointOnLine( + { type: "Point", coordinates: geom1.coordinates[i][iii] }, + { type: "LineString", coordinates: geom2.coordinates[ii] }, + { ignoreEndVertices: true } + ) + ) + return false; + } + } + } + return endMatch; + case "Polygon": + var foundTouchingPoint = false; + for (var i = 0; i < geom1.coordinates.length; i++) { + for (var ii = 0; ii < geom1.coordinates.length; ii++) { + if (!foundTouchingPoint) { + if ( + booleanPointOnLine( + { type: "Point", coordinates: geom1.coordinates[i][ii] }, + { type: "LineString", coordinates: geom2.coordinates[0] } + ) + ) + foundTouchingPoint = true; + } + if ( + booleanPointInPolygon( + { type: "Point", coordinates: geom1.coordinates[i][ii] }, + geom2, + { ignoreBoundary: true } + ) + ) + return false; + } + } + return foundTouchingPoint; + case "MultiPolygon": + var foundTouchingPoint = false; + for (var i = 0; i < geom2.coordinates[0].length; i++) { + for (var ii = 0; ii < geom1.coordinates.length; ii++) { + for (var iii = 0; iii < geom1.coordinates[ii].length; iii++) { + if (!foundTouchingPoint) { + if ( + booleanPointOnLine( + { + type: "Point", + coordinates: geom1.coordinates[ii][iii], + }, + { + type: "LineString", + coordinates: geom2.coordinates[0][i], + } + ) + ) + foundTouchingPoint = true; + } + if ( + booleanPointInPolygon( + { type: "Point", coordinates: geom1.coordinates[ii][iii] }, + { type: "Polygon", coordinates: [geom2.coordinates[0][i]] }, + { ignoreBoundary: true } + ) + ) + return false; + } + } + } + return foundTouchingPoint; + default: + throw new Error("feature2 " + type2 + " geometry not supported"); + } + case "Polygon": + switch (type2) { + case "Point": + for (var i = 0; i < geom1.coordinates.length; i++) { + if ( + booleanPointOnLine(geom2, { + type: "LineString", + coordinates: geom1.coordinates[i], + }) + ) + return true; + } + return false; + case "MultiPoint": + var foundTouchingPoint = false; + for (var i = 0; i < geom2.coordinates.length; i++) { + if (!foundTouchingPoint) { + if ( + booleanPointOnLine( + { type: "Point", coordinates: geom2.coordinates[i] }, + { type: "LineString", coordinates: geom1.coordinates[0] } + ) + ) + foundTouchingPoint = true; + } + if ( + booleanPointInPolygon( + { type: "Point", coordinates: geom2.coordinates[i] }, + geom1, + { ignoreBoundary: true } + ) + ) + return false; + } + return foundTouchingPoint; + case "LineString": + var foundTouchingPoint = false; + for (var i = 0; i < geom2.coordinates.length; i++) { + if (!foundTouchingPoint) { + if ( + booleanPointOnLine( + { type: "Point", coordinates: geom2.coordinates[i] }, + { type: "LineString", coordinates: geom1.coordinates[0] } + ) + ) + foundTouchingPoint = true; + } + if ( + booleanPointInPolygon( + { type: "Point", coordinates: geom2.coordinates[i] }, + geom1, + { ignoreBoundary: true } + ) + ) + return false; + } + return foundTouchingPoint; + case "MultiLineString": + var foundTouchingPoint = false; + for (var i = 0; i < geom2.coordinates.length; i++) { + for (var ii = 0; ii < geom2.coordinates[i].length; ii++) { + if (!foundTouchingPoint) { + if ( + booleanPointOnLine( + { type: "Point", coordinates: geom2.coordinates[i][ii] }, + { type: "LineString", coordinates: geom1.coordinates[0] } + ) + ) + foundTouchingPoint = true; + } + if ( + booleanPointInPolygon( + { type: "Point", coordinates: geom2.coordinates[i][ii] }, + geom1, + { ignoreBoundary: true } + ) + ) + return false; + } + } + return foundTouchingPoint; + case "Polygon": + var foundTouchingPoint = false; + for (var i = 0; i < geom1.coordinates[0].length; i++) { + if (!foundTouchingPoint) { + if ( + booleanPointOnLine( + { type: "Point", coordinates: geom1.coordinates[0][i] }, + { type: "LineString", coordinates: geom2.coordinates[0] } + ) + ) + foundTouchingPoint = true; + } + if ( + booleanPointInPolygon( + { type: "Point", coordinates: geom1.coordinates[0][i] }, + geom2, + { ignoreBoundary: true } + ) + ) + return false; + } + return foundTouchingPoint; + case "MultiPolygon": + var foundTouchingPoint = false; + for (var i = 0; i < geom2.coordinates[0].length; i++) { + for (var ii = 0; ii < geom1.coordinates[0].length; ii++) { + if (!foundTouchingPoint) { + if ( + booleanPointOnLine( + { type: "Point", coordinates: geom1.coordinates[0][ii] }, + { type: "LineString", coordinates: geom2.coordinates[0][i] } + ) + ) + foundTouchingPoint = true; + } + if ( + booleanPointInPolygon( + { type: "Point", coordinates: geom1.coordinates[0][ii] }, + { type: "Polygon", coordinates: geom2.coordinates[0][i] }, + { ignoreBoundary: true } + ) + ) + return false; + } + } + return foundTouchingPoint; + default: + throw new Error("feature2 " + type2 + " geometry not supported"); + } + case "MultiPolygon": + switch (type2) { + case "Point": + for (var i = 0; i < geom1.coordinates[0].length; i++) { + if ( + booleanPointOnLine(geom2, { + type: "LineString", + coordinates: geom1.coordinates[0][i], + }) + ) + return true; + } + return false; + case "MultiPoint": + var foundTouchingPoint = false; + for (var i = 0; i < geom1.coordinates[0].length; i++) { + for (var ii = 0; ii < geom2.coordinates.length; ii++) { + if (!foundTouchingPoint) { + if ( + booleanPointOnLine( + { type: "Point", coordinates: geom2.coordinates[ii] }, + { type: "LineString", coordinates: geom1.coordinates[0][i] } + ) + ) + foundTouchingPoint = true; + } + if ( + booleanPointInPolygon( + { type: "Point", coordinates: geom2.coordinates[ii] }, + { type: "Polygon", coordinates: geom1.coordinates[0][i] }, + { ignoreBoundary: true } + ) + ) + return false; + } + } + return foundTouchingPoint; + case "LineString": + var foundTouchingPoint = false; + for (var i = 0; i < geom1.coordinates[0].length; i++) { + for (var ii = 0; ii < geom2.coordinates.length; ii++) { + if (!foundTouchingPoint) { + if ( + booleanPointOnLine( + { type: "Point", coordinates: geom2.coordinates[ii] }, + { type: "LineString", coordinates: geom1.coordinates[0][i] } + ) + ) + foundTouchingPoint = true; + } + if ( + booleanPointInPolygon( + { type: "Point", coordinates: geom2.coordinates[ii] }, + { type: "Polygon", coordinates: geom1.coordinates[0][i] }, + { ignoreBoundary: true } + ) + ) + return false; + } + } + return foundTouchingPoint; + case "MultiLineString": + var foundTouchingPoint = false; + for (var i = 0; i < geom1.coordinates.length; i++) { + for (var ii = 0; ii < geom2.coordinates.length; ii++) { + for (var iii = 0; iii < geom2.coordinates[ii].length; iii++) { + if (!foundTouchingPoint) { + if ( + booleanPointOnLine( + { + type: "Point", + coordinates: geom2.coordinates[ii][iii], + }, + { + type: "LineString", + coordinates: geom1.coordinates[i][0], + } + ) + ) + foundTouchingPoint = true; + } + if ( + booleanPointInPolygon( + { type: "Point", coordinates: geom2.coordinates[ii][iii] }, + { type: "Polygon", coordinates: [geom1.coordinates[i][0]] }, + { ignoreBoundary: true } + ) + ) + return false; + } + } + } + + return foundTouchingPoint; + case "Polygon": + var foundTouchingPoint = false; + for (var i = 0; i < geom1.coordinates[0].length; i++) { + for (var ii = 0; ii < geom1.coordinates[0][i].length; ii++) { + if (!foundTouchingPoint) { + if ( + booleanPointOnLine( + { type: "Point", coordinates: geom1.coordinates[0][i][ii] }, + { type: "LineString", coordinates: geom2.coordinates[0] } + ) + ) + foundTouchingPoint = true; + } + if ( + booleanPointInPolygon( + { type: "Point", coordinates: geom1.coordinates[0][i][ii] }, + geom2, + { ignoreBoundary: true } + ) + ) + return false; + } + } + return foundTouchingPoint; + case "MultiPolygon": + var foundTouchingPoint = false; + for (var i = 0; i < geom1.coordinates[0].length; i++) { + for (var ii = 0; ii < geom2.coordinates[0].length; ii++) { + for (var iii = 0; iii < geom1.coordinates[0].length; iii++) { + if (!foundTouchingPoint) { + if ( + booleanPointOnLine( + { + type: "Point", + coordinates: geom1.coordinates[0][i][iii], + }, + { + type: "LineString", + coordinates: geom2.coordinates[0][ii], + } + ) + ) + foundTouchingPoint = true; + } + if ( + booleanPointInPolygon( + { + type: "Point", + coordinates: geom1.coordinates[0][i][iii], + }, + { type: "Polygon", coordinates: geom2.coordinates[0][ii] }, + { ignoreBoundary: true } + ) + ) + return false; + } + } + } + return foundTouchingPoint; + default: + throw new Error("feature2 " + type2 + " geometry not supported"); + } + default: + throw new Error("feature1 " + type1 + " geometry not supported"); + } +} + + isPointOnLineEnd(point: Point, line: LineString) { + if (compareCoords(line.coordinates[0], point.coordinates)) return true; + if ( + compareCoords( + line.coordinates[line.coordinates.length - 1], + point.coordinates + ) + ) + return true; + return false; +} + +/** + * compareCoords + * + * @private + * @param {Position} pair1 point [x,y] + * @param {Position} pair2 point [x,y] + * @returns {boolean} true/false if coord pairs match + */ + compareCoords(pair1: number[], pair2: number[]) { + return pair1[0] == pair2[0] && pair1[1] == pair2[1]; +} + + +/** import { Feature, Geometry, LineString, Point } from "geojson"; +import booleanPointOnLine from "@turf/boolean-point-on-line"; +import booleanPointInPolygon from "@turf/boolean-point-in-polygon"; +import { getGeom } from "@turf/invariant"; + +/** + * Boolean-touches true if none of the points common to both geometries + * intersect the interiors of both geometries. + * @name booleanTouches + * @param {Geometry|Feature} feature1 GeoJSON Feature or Geometry + * @param {Geometry|Feature} feature2 GeoJSON Feature or Geometry + * @returns {boolean} true/false + * @example + * var line = turf.lineString([[1, 1], [1, 2], [1, 3], [1, 4]]); + * var point = turf.point([1, 1]); + * + * turf.booleanTouches(point, line); + * //=true + */ +function booleanTouches( + feature1: Feature | Geometry, + feature2: Feature | Geometry +): boolean { + var geom1 = getGeom(feature1); + var geom2 = getGeom(feature2); + var type1 = geom1.type; + var type2 = geom2.type; + + switch (type1) { + case "Point": + switch (type2) { + case "LineString": + return isPointOnLineEnd(geom1, geom2); + case "MultiLineString": + var foundTouchingPoint = false; + for (var ii = 0; ii < geom2.coordinates.length; ii++) { + if ( + isPointOnLineEnd(geom1, { + type: "LineString", + coordinates: geom2.coordinates[ii], + }) + ) + foundTouchingPoint = true; + } + return foundTouchingPoint; + case "Polygon": + for (var i = 0; i < geom2.coordinates.length; i++) { + if ( + booleanPointOnLine(geom1, { + type: "LineString", + coordinates: geom2.coordinates[i], + }) + ) + return true; + } + return false; + case "MultiPolygon": + for (var i = 0; i < geom2.coordinates.length; i++) { + for (var ii = 0; ii < geom2.coordinates[i].length; ii++) { + if ( + booleanPointOnLine(geom1, { + type: "LineString", + coordinates: geom2.coordinates[i][ii], + }) + ) + return true; + } + } + return false; + default: + throw new Error("feature2 " + type2 + " geometry not supported"); + } + case "MultiPoint": + switch (type2) { + case "LineString": + var foundTouchingPoint = false; + for (var i = 0; i < geom1.coordinates.length; i++) { + if (!foundTouchingPoint) { + if ( + isPointOnLineEnd( + { type: "Point", coordinates: geom1.coordinates[i] }, + geom2 + ) + ) + foundTouchingPoint = true; + } + if ( + booleanPointOnLine( + { type: "Point", coordinates: geom1.coordinates[i] }, + geom2, + { ignoreEndVertices: true } + ) + ) + return false; + } + return foundTouchingPoint; + case "MultiLineString": + var foundTouchingPoint = false; + for (var i = 0; i < geom1.coordinates.length; i++) { + for (var ii = 0; ii < geom2.coordinates.length; ii++) { + if (!foundTouchingPoint) { + if ( + isPointOnLineEnd( + { type: "Point", coordinates: geom1.coordinates[i] }, + { type: "LineString", coordinates: geom2.coordinates[ii] } + ) + ) + foundTouchingPoint = true; + } + if ( + booleanPointOnLine( + { type: "Point", coordinates: geom1.coordinates[i] }, + { type: "LineString", coordinates: geom2.coordinates[ii] }, + { ignoreEndVertices: true } + ) + ) + return false; + } + } + return foundTouchingPoint; + case "Polygon": + var foundTouchingPoint = false; + for (var i = 0; i < geom1.coordinates.length; i++) { + if (!foundTouchingPoint) { + if ( + booleanPointOnLine( + { type: "Point", coordinates: geom1.coordinates[i] }, + { type: "LineString", coordinates: geom2.coordinates[0] } + ) + ) + foundTouchingPoint = true; + } + if ( + booleanPointInPolygon( + { type: "Point", coordinates: geom1.coordinates[i] }, + geom2, + { ignoreBoundary: true } + ) + ) + return false; + } + return foundTouchingPoint; + case "MultiPolygon": + var foundTouchingPoint = false; + for (var i = 0; i < geom1.coordinates.length; i++) { + for (var ii = 0; ii < geom2.coordinates.length; ii++) { + if (!foundTouchingPoint) { + if ( + booleanPointOnLine( + { type: "Point", coordinates: geom1.coordinates[i] }, + { + type: "LineString", + coordinates: geom2.coordinates[ii][0], + } + ) + ) + foundTouchingPoint = true; + } + if ( + booleanPointInPolygon( + { type: "Point", coordinates: geom1.coordinates[i] }, + { type: "Polygon", coordinates: geom2.coordinates[ii] }, + { ignoreBoundary: true } + ) + ) + return false; + } + } + return foundTouchingPoint; + default: + throw new Error("feature2 " + type2 + " geometry not supported"); + } + case "LineString": + switch (type2) { + case "Point": + return isPointOnLineEnd(geom2, geom1); + case "MultiPoint": + var foundTouchingPoint = false; + for (var i = 0; i < geom2.coordinates.length; i++) { + if (!foundTouchingPoint) { + if ( + isPointOnLineEnd( + { type: "Point", coordinates: geom2.coordinates[i] }, + geom1 + ) + ) + foundTouchingPoint = true; + } + if ( + booleanPointOnLine( + { type: "Point", coordinates: geom2.coordinates[i] }, + geom1, + { ignoreEndVertices: true } + ) + ) + return false; + } + return foundTouchingPoint; + case "LineString": + var endMatch = false; + if ( + isPointOnLineEnd( + { type: "Point", coordinates: geom1.coordinates[0] }, + geom2 + ) + ) + endMatch = true; + if ( + isPointOnLineEnd( + { + type: "Point", + coordinates: geom1.coordinates[geom1.coordinates.length - 1], + }, + geom2 + ) + ) + endMatch = true; + if (endMatch == false) return false; + for (var i = 0; i < geom1.coordinates.length; i++) { + if ( + booleanPointOnLine( + { type: "Point", coordinates: geom1.coordinates[i] }, + geom2, + { ignoreEndVertices: true } + ) + ) + return false; + } + return endMatch; + case "MultiLineString": + var endMatch = false; + for (var i = 0; i < geom2.coordinates.length; i++) { + if ( + isPointOnLineEnd( + { type: "Point", coordinates: geom1.coordinates[0] }, + { type: "LineString", coordinates: geom2.coordinates[i] } + ) + ) + endMatch = true; + if ( + isPointOnLineEnd( + { + type: "Point", + coordinates: geom1.coordinates[geom1.coordinates.length - 1], + }, + { type: "LineString", coordinates: geom2.coordinates[i] } + ) + ) + endMatch = true; + for (var ii = 0; ii < geom1.coordinates[i].length; ii++) { + if ( + booleanPointOnLine( + { type: "Point", coordinates: geom1.coordinates[ii] }, + { type: "LineString", coordinates: geom2.coordinates[i] }, + { ignoreEndVertices: true } + ) + ) + return false; + } + } + return endMatch; + case "Polygon": + var foundTouchingPoint = false; + for (var i = 0; i < geom1.coordinates.length; i++) { + if (!foundTouchingPoint) { + if ( + booleanPointOnLine( + { type: "Point", coordinates: geom1.coordinates[i] }, + { type: "LineString", coordinates: geom2.coordinates[0] } + ) + ) + foundTouchingPoint = true; + } + if ( + booleanPointInPolygon( + { type: "Point", coordinates: geom1.coordinates[i] }, + geom2, + { ignoreBoundary: true } + ) + ) + return false; + } + return foundTouchingPoint; + case "MultiPolygon": + var foundTouchingPoint = false; + for (var i = 0; i < geom1.coordinates.length; i++) { + for (var ii = 0; ii < geom2.coordinates.length; ii++) { + if (!foundTouchingPoint) { + if ( + booleanPointOnLine( + { type: "Point", coordinates: geom1.coordinates[i] }, + { + type: "LineString", + coordinates: geom2.coordinates[ii][0], + } + ) + ) + foundTouchingPoint = true; + } + } + if ( + booleanPointInPolygon( + { type: "Point", coordinates: geom1.coordinates[i] }, + geom2, + { ignoreBoundary: true } + ) + ) + return false; + } + return foundTouchingPoint; + default: + throw new Error("feature2 " + type2 + " geometry not supported"); + } + case "MultiLineString": + switch (type2) { + case "Point": + for (var i = 0; i < geom1.coordinates.length; i++) { + if ( + isPointOnLineEnd(geom2, { + type: "LineString", + coordinates: geom1.coordinates[i], + }) + ) + return true; + } + return false; + case "MultiPoint": + var foundTouchingPoint = false; + for (var i = 0; i < geom1.coordinates.length; i++) { + for (var ii = 0; ii < geom2.coordinates.length; ii++) { + if (!foundTouchingPoint) { + if ( + isPointOnLineEnd( + { type: "Point", coordinates: geom2.coordinates[ii] }, + { type: "LineString", coordinates: geom1.coordinates[ii] } + ) + ) + foundTouchingPoint = true; + } + if ( + booleanPointOnLine( + { type: "Point", coordinates: geom2.coordinates[ii] }, + { type: "LineString", coordinates: geom1.coordinates[ii] }, + { ignoreEndVertices: true } + ) + ) + return false; + } + } + return foundTouchingPoint; + case "LineString": + var endMatch = false; + for (var i = 0; i < geom1.coordinates.length; i++) { + if ( + isPointOnLineEnd( + { type: "Point", coordinates: geom1.coordinates[i][0] }, + geom2 + ) + ) + endMatch = true; + if ( + isPointOnLineEnd( + { + type: "Point", + coordinates: + geom1.coordinates[i][geom1.coordinates[i].length - 1], + }, + geom2 + ) + ) + endMatch = true; + for (var ii = 0; ii < geom2.coordinates.length; ii++) { + if ( + booleanPointOnLine( + { type: "Point", coordinates: geom2.coordinates[ii] }, + { type: "LineString", coordinates: geom1.coordinates[i] }, + { ignoreEndVertices: true } + ) + ) + return false; + } + } + return endMatch; + case "MultiLineString": + var endMatch = false; + for (var i = 0; i < geom1.coordinates.length; i++) { + for (var ii = 0; ii < geom2.coordinates.length; ii++) { + if ( + isPointOnLineEnd( + { type: "Point", coordinates: geom1.coordinates[i][0] }, + { type: "LineString", coordinates: geom2.coordinates[ii] } + ) + ) + endMatch = true; + if ( + isPointOnLineEnd( + { + type: "Point", + coordinates: + geom1.coordinates[i][geom1.coordinates[i].length - 1], + }, + { type: "LineString", coordinates: geom2.coordinates[ii] } + ) + ) + endMatch = true; + for (var iii = 0; iii < geom1.coordinates[i].length; iii++) { + if ( + booleanPointOnLine( + { type: "Point", coordinates: geom1.coordinates[i][iii] }, + { type: "LineString", coordinates: geom2.coordinates[ii] }, + { ignoreEndVertices: true } + ) + ) + return false; + } + } + } + return endMatch; + case "Polygon": + var foundTouchingPoint = false; + for (var i = 0; i < geom1.coordinates.length; i++) { + for (var ii = 0; ii < geom1.coordinates.length; ii++) { + if (!foundTouchingPoint) { + if ( + booleanPointOnLine( + { type: "Point", coordinates: geom1.coordinates[i][ii] }, + { type: "LineString", coordinates: geom2.coordinates[0] } + ) + ) + foundTouchingPoint = true; + } + if ( + booleanPointInPolygon( + { type: "Point", coordinates: geom1.coordinates[i][ii] }, + geom2, + { ignoreBoundary: true } + ) + ) + return false; + } + } + return foundTouchingPoint; + case "MultiPolygon": + var foundTouchingPoint = false; + for (var i = 0; i < geom2.coordinates[0].length; i++) { + for (var ii = 0; ii < geom1.coordinates.length; ii++) { + for (var iii = 0; iii < geom1.coordinates[ii].length; iii++) { + if (!foundTouchingPoint) { + if ( + booleanPointOnLine( + { + type: "Point", + coordinates: geom1.coordinates[ii][iii], + }, + { + type: "LineString", + coordinates: geom2.coordinates[0][i], + } + ) + ) + foundTouchingPoint = true; + } + if ( + booleanPointInPolygon( + { type: "Point", coordinates: geom1.coordinates[ii][iii] }, + { type: "Polygon", coordinates: [geom2.coordinates[0][i]] }, + { ignoreBoundary: true } + ) + ) + return false; + } + } + } + return foundTouchingPoint; + default: + throw new Error("feature2 " + type2 + " geometry not supported"); + } + case "Polygon": + switch (type2) { + case "Point": + for (var i = 0; i < geom1.coordinates.length; i++) { + if ( + booleanPointOnLine(geom2, { + type: "LineString", + coordinates: geom1.coordinates[i], + }) + ) + return true; + } + return false; + case "MultiPoint": + var foundTouchingPoint = false; + for (var i = 0; i < geom2.coordinates.length; i++) { + if (!foundTouchingPoint) { + if ( + booleanPointOnLine( + { type: "Point", coordinates: geom2.coordinates[i] }, + { type: "LineString", coordinates: geom1.coordinates[0] } + ) + ) + foundTouchingPoint = true; + } + if ( + booleanPointInPolygon( + { type: "Point", coordinates: geom2.coordinates[i] }, + geom1, + { ignoreBoundary: true } + ) + ) + return false; + } + return foundTouchingPoint; + case "LineString": + var foundTouchingPoint = false; + for (var i = 0; i < geom2.coordinates.length; i++) { + if (!foundTouchingPoint) { + if ( + booleanPointOnLine( + { type: "Point", coordinates: geom2.coordinates[i] }, + { type: "LineString", coordinates: geom1.coordinates[0] } + ) + ) + foundTouchingPoint = true; + } + if ( + booleanPointInPolygon( + { type: "Point", coordinates: geom2.coordinates[i] }, + geom1, + { ignoreBoundary: true } + ) + ) + return false; + } + return foundTouchingPoint; + case "MultiLineString": + var foundTouchingPoint = false; + for (var i = 0; i < geom2.coordinates.length; i++) { + for (var ii = 0; ii < geom2.coordinates[i].length; ii++) { + if (!foundTouchingPoint) { + if ( + booleanPointOnLine( + { type: "Point", coordinates: geom2.coordinates[i][ii] }, + { type: "LineString", coordinates: geom1.coordinates[0] } + ) + ) + foundTouchingPoint = true; + } + if ( + booleanPointInPolygon( + { type: "Point", coordinates: geom2.coordinates[i][ii] }, + geom1, + { ignoreBoundary: true } + ) + ) + return false; + } + } + return foundTouchingPoint; + case "Polygon": + var foundTouchingPoint = false; + for (var i = 0; i < geom1.coordinates[0].length; i++) { + if (!foundTouchingPoint) { + if ( + booleanPointOnLine( + { type: "Point", coordinates: geom1.coordinates[0][i] }, + { type: "LineString", coordinates: geom2.coordinates[0] } + ) + ) + foundTouchingPoint = true; + } + if ( + booleanPointInPolygon( + { type: "Point", coordinates: geom1.coordinates[0][i] }, + geom2, + { ignoreBoundary: true } + ) + ) + return false; + } + return foundTouchingPoint; + case "MultiPolygon": + var foundTouchingPoint = false; + for (var i = 0; i < geom2.coordinates[0].length; i++) { + for (var ii = 0; ii < geom1.coordinates[0].length; ii++) { + if (!foundTouchingPoint) { + if ( + booleanPointOnLine( + { type: "Point", coordinates: geom1.coordinates[0][ii] }, + { type: "LineString", coordinates: geom2.coordinates[0][i] } + ) + ) + foundTouchingPoint = true; + } + if ( + booleanPointInPolygon( + { type: "Point", coordinates: geom1.coordinates[0][ii] }, + { type: "Polygon", coordinates: geom2.coordinates[0][i] }, + { ignoreBoundary: true } + ) + ) + return false; + } + } + return foundTouchingPoint; + default: + throw new Error("feature2 " + type2 + " geometry not supported"); + } + case "MultiPolygon": + switch (type2) { + case "Point": + for (var i = 0; i < geom1.coordinates[0].length; i++) { + if ( + booleanPointOnLine(geom2, { + type: "LineString", + coordinates: geom1.coordinates[0][i], + }) + ) + return true; + } + return false; + case "MultiPoint": + var foundTouchingPoint = false; + for (var i = 0; i < geom1.coordinates[0].length; i++) { + for (var ii = 0; ii < geom2.coordinates.length; ii++) { + if (!foundTouchingPoint) { + if ( + booleanPointOnLine( + { type: "Point", coordinates: geom2.coordinates[ii] }, + { type: "LineString", coordinates: geom1.coordinates[0][i] } + ) + ) + foundTouchingPoint = true; + } + if ( + booleanPointInPolygon( + { type: "Point", coordinates: geom2.coordinates[ii] }, + { type: "Polygon", coordinates: geom1.coordinates[0][i] }, + { ignoreBoundary: true } + ) + ) + return false; + } + } + return foundTouchingPoint; + case "LineString": + var foundTouchingPoint = false; + for (var i = 0; i < geom1.coordinates[0].length; i++) { + for (var ii = 0; ii < geom2.coordinates.length; ii++) { + if (!foundTouchingPoint) { + if ( + booleanPointOnLine( + { type: "Point", coordinates: geom2.coordinates[ii] }, + { type: "LineString", coordinates: geom1.coordinates[0][i] } + ) + ) + foundTouchingPoint = true; + } + if ( + booleanPointInPolygon( + { type: "Point", coordinates: geom2.coordinates[ii] }, + { type: "Polygon", coordinates: geom1.coordinates[0][i] }, + { ignoreBoundary: true } + ) + ) + return false; + } + } + return foundTouchingPoint; + case "MultiLineString": + var foundTouchingPoint = false; + for (var i = 0; i < geom1.coordinates.length; i++) { + for (var ii = 0; ii < geom2.coordinates.length; ii++) { + for (var iii = 0; iii < geom2.coordinates[ii].length; iii++) { + if (!foundTouchingPoint) { + if ( + booleanPointOnLine( + { + type: "Point", + coordinates: geom2.coordinates[ii][iii], + }, + { + type: "LineString", + coordinates: geom1.coordinates[i][0], + } + ) + ) + foundTouchingPoint = true; + } + if ( + booleanPointInPolygon( + { type: "Point", coordinates: geom2.coordinates[ii][iii] }, + { type: "Polygon", coordinates: [geom1.coordinates[i][0]] }, + { ignoreBoundary: true } + ) + ) + return false; + } + } + } + + return foundTouchingPoint; + case "Polygon": + var foundTouchingPoint = false; + for (var i = 0; i < geom1.coordinates[0].length; i++) { + for (var ii = 0; ii < geom1.coordinates[0][i].length; ii++) { + if (!foundTouchingPoint) { + if ( + booleanPointOnLine( + { type: "Point", coordinates: geom1.coordinates[0][i][ii] }, + { type: "LineString", coordinates: geom2.coordinates[0] } + ) + ) + foundTouchingPoint = true; + } + if ( + booleanPointInPolygon( + { type: "Point", coordinates: geom1.coordinates[0][i][ii] }, + geom2, + { ignoreBoundary: true } + ) + ) + return false; + } + } + return foundTouchingPoint; + case "MultiPolygon": + var foundTouchingPoint = false; + for (var i = 0; i < geom1.coordinates[0].length; i++) { + for (var ii = 0; ii < geom2.coordinates[0].length; ii++) { + for (var iii = 0; iii < geom1.coordinates[0].length; iii++) { + if (!foundTouchingPoint) { + if ( + booleanPointOnLine( + { + type: "Point", + coordinates: geom1.coordinates[0][i][iii], + }, + { + type: "LineString", + coordinates: geom2.coordinates[0][ii], + } + ) + ) + foundTouchingPoint = true; + } + if ( + booleanPointInPolygon( + { + type: "Point", + coordinates: geom1.coordinates[0][i][iii], + }, + { type: "Polygon", coordinates: geom2.coordinates[0][ii] }, + { ignoreBoundary: true } + ) + ) + return false; + } + } + } + return foundTouchingPoint; + default: + throw new Error("feature2 " + type2 + " geometry not supported"); + } + default: + throw new Error("feature1 " + type1 + " geometry not supported"); + } +} + +function isPointOnLineEnd(point: Point, line: LineString) { + if (compareCoords(line.coordinates[0], point.coordinates)) return true; + if ( + compareCoords( + line.coordinates[line.coordinates.length - 1], + point.coordinates + ) + ) + return true; + return false; +} + +/** + * compareCoords + * + * @private + * @param {Position} pair1 point [x,y] + * @param {Position} pair2 point [x,y] + * @returns {boolean} true/false if coord pairs match + */ +function compareCoords(pair1: number[], pair2: number[]) { + return pair1[0] == pair2[0] && pair1[1] == pair2[1]; +} + +export default booleanTouches; */ \ No newline at end of file diff --git a/lib/src/invariant.dart b/lib/src/invariant.dart index 6e3da29d..1f8219c9 100644 --- a/lib/src/invariant.dart +++ b/lib/src/invariant.dart @@ -96,9 +96,9 @@ _getCoordsForGeometry(GeometryObject geom) { * //={"type": "Point", "coordinates": [110, 40]} */ -getGeom(GeoJSONObjectType geojson) { +getGeom(GeoJSONObject geojson) { if (geojson is Feature) { - return (geojson as Feature).geometry; + return (geojson).geometry; } return geojson; } From ce7a52272be57d493cf17b492a8c4aeedb671dfb Mon Sep 17 00:00:00 2001 From: armantorkzaban Date: Tue, 7 Jun 2022 22:14:34 +0200 Subject: [PATCH 13/82] boolean_touches --- lib/src/booleans/boolean_touches.dart | 1128 +++++++++++-------------- 1 file changed, 477 insertions(+), 651 deletions(-) diff --git a/lib/src/booleans/boolean_touches.dart b/lib/src/booleans/boolean_touches.dart index 9c6374dc..e50bda04 100644 --- a/lib/src/booleans/boolean_touches.dart +++ b/lib/src/booleans/boolean_touches.dart @@ -1,3 +1,7 @@ +import '../../helpers.dart'; +import '../invariant.dart'; +import 'boolean_point_in_polygon.dart'; +import 'boolean_point_on_line.dart'; /** * Boolean-touches true if none of the points common to both geometries @@ -13,764 +17,605 @@ * turf.booleanTouches(point, line); * //=true */ - booleanTouches( - feature1: Feature | Geometry, - feature2: Feature | Geometry -): boolean { +bool booleanTouches(GeoJSONObject feature1, GeoJSONObject feature2) { var geom1 = getGeom(feature1); var geom2 = getGeom(feature2); var type1 = geom1.type; var type2 = geom2.type; switch (type1) { - case "Point": + case Point: switch (type2) { - case "LineString": + case LineString: return isPointOnLineEnd(geom1, geom2); - case "MultiLineString": + case MultiLineString: var foundTouchingPoint = false; for (var ii = 0; ii < geom2.coordinates.length; ii++) { - if ( - isPointOnLineEnd(geom1, { - type: "LineString", - coordinates: geom2.coordinates[ii], - }) - ) + if (isPointOnLineEnd( + geom1, + LineString( + coordinates: geom2.coordinates[ii], + ))) { foundTouchingPoint = true; + } } return foundTouchingPoint; - case "Polygon": + case Polygon: for (var i = 0; i < geom2.coordinates.length; i++) { - if ( - booleanPointOnLine(geom1, { - type: "LineString", - coordinates: geom2.coordinates[i], - }) - ) + if (booleanPointOnLine( + geom1, + LineString( + coordinates: geom2.coordinates[i], + ))) { return true; + } } return false; - case "MultiPolygon": + case MultiPolygon: for (var i = 0; i < geom2.coordinates.length; i++) { for (var ii = 0; ii < geom2.coordinates[i].length; ii++) { - if ( - booleanPointOnLine(geom1, { - type: "LineString", - coordinates: geom2.coordinates[i][ii], - }) - ) + if (booleanPointOnLine( + geom1, + LineString( + coordinates: geom2.coordinates[i][ii], + ))) { return true; + } } } return false; default: - throw new Error("feature2 " + type2 + " geometry not supported"); + throw Exception("feature2 " + type2 + " geometry not supported"); } - case "MultiPoint": + case MultiPoint: switch (type2) { - case "LineString": + case LineString: var foundTouchingPoint = false; for (var i = 0; i < geom1.coordinates.length; i++) { if (!foundTouchingPoint) { - if ( - isPointOnLineEnd( - { type: "Point", coordinates: geom1.coordinates[i] }, - geom2 - ) - ) + if (isPointOnLineEnd( + Point(coordinates: geom1.coordinates[i]), geom2)) foundTouchingPoint = true; } - if ( - booleanPointOnLine( - { type: "Point", coordinates: geom1.coordinates[i] }, - geom2, - { ignoreEndVertices: true } - ) - ) - return false; + if (booleanPointOnLine( + Point(coordinates: geom1.coordinates[i]), geom2, + ignoreEndVertices: true)) return false; } return foundTouchingPoint; - case "MultiLineString": + case MultiLineString: var foundTouchingPoint = false; for (var i = 0; i < geom1.coordinates.length; i++) { for (var ii = 0; ii < geom2.coordinates.length; ii++) { if (!foundTouchingPoint) { - if ( - isPointOnLineEnd( - { type: "Point", coordinates: geom1.coordinates[i] }, - { type: "LineString", coordinates: geom2.coordinates[ii] } - ) - ) + if (isPointOnLineEnd(Point(coordinates: geom1.coordinates[i]), + LineString(coordinates: geom2.coordinates[ii]))) foundTouchingPoint = true; } - if ( - booleanPointOnLine( - { type: "Point", coordinates: geom1.coordinates[i] }, - { type: "LineString", coordinates: geom2.coordinates[ii] }, - { ignoreEndVertices: true } - ) - ) + if (booleanPointOnLine(Point(coordinates: geom1.coordinates[i]), + LineString(coordinates: geom2.coordinates[ii]), + ignoreEndVertices: true)) { return false; + } } } return foundTouchingPoint; - case "Polygon": + case Polygon: var foundTouchingPoint = false; for (var i = 0; i < geom1.coordinates.length; i++) { if (!foundTouchingPoint) { - if ( - booleanPointOnLine( - { type: "Point", coordinates: geom1.coordinates[i] }, - { type: "LineString", coordinates: geom2.coordinates[0] } - ) - ) + if (booleanPointOnLine(Point(coordinates: geom1.coordinates[i]), + LineString(coordinates: geom2.coordinates[0]))) { foundTouchingPoint = true; + } } - if ( - booleanPointInPolygon( - { type: "Point", coordinates: geom1.coordinates[i] }, - geom2, - { ignoreBoundary: true } - ) - ) + if (booleanPointInPolygon( + Point(coordinates: geom1.coordinates[i]), geom2, + ignoreBoundary: true)) { return false; + } } return foundTouchingPoint; - case "MultiPolygon": + case MultiPolygon: var foundTouchingPoint = false; for (var i = 0; i < geom1.coordinates.length; i++) { for (var ii = 0; ii < geom2.coordinates.length; ii++) { if (!foundTouchingPoint) { - if ( - booleanPointOnLine( - { type: "Point", coordinates: geom1.coordinates[i] }, - { - type: "LineString", + if (booleanPointOnLine( + Point(coordinates: geom1.coordinates[i]), + LineString( coordinates: geom2.coordinates[ii][0], - } - ) - ) + ))) { foundTouchingPoint = true; + } } - if ( - booleanPointInPolygon( - { type: "Point", coordinates: geom1.coordinates[i] }, - { type: "Polygon", coordinates: geom2.coordinates[ii] }, - { ignoreBoundary: true } - ) - ) + if (booleanPointInPolygon( + Point(coordinates: geom1.coordinates[i]), + Polygon(coordinates: geom2.coordinates[ii]), + ignoreBoundary: true)) { return false; + } } } return foundTouchingPoint; default: - throw new Error("feature2 " + type2 + " geometry not supported"); + throw Exception("feature2 " + type2 + " geometry not supported"); } - case "LineString": + case LineString: switch (type2) { - case "Point": + case Point: return isPointOnLineEnd(geom2, geom1); - case "MultiPoint": + case MultiPoint: var foundTouchingPoint = false; for (var i = 0; i < geom2.coordinates.length; i++) { if (!foundTouchingPoint) { - if ( - isPointOnLineEnd( - { type: "Point", coordinates: geom2.coordinates[i] }, - geom1 - ) - ) + if (isPointOnLineEnd( + Point(coordinates: geom2.coordinates[i]), geom1)) { foundTouchingPoint = true; + } } - if ( - booleanPointOnLine( - { type: "Point", coordinates: geom2.coordinates[i] }, - geom1, - { ignoreEndVertices: true } - ) - ) + if (booleanPointOnLine( + Point(coordinates: geom2.coordinates[i]), geom1, + ignoreEndVertices: true)) { return false; + } } return foundTouchingPoint; - case "LineString": + case LineString: var endMatch = false; - if ( - isPointOnLineEnd( - { type: "Point", coordinates: geom1.coordinates[0] }, - geom2 - ) - ) + if (isPointOnLineEnd( + Point(coordinates: geom1.coordinates[0]), geom2)) { endMatch = true; - if ( - isPointOnLineEnd( - { - type: "Point", + } + if (isPointOnLineEnd( + Point( coordinates: geom1.coordinates[geom1.coordinates.length - 1], - }, - geom2 - ) - ) - endMatch = true; + ), + geom2)) endMatch = true; if (endMatch == false) return false; for (var i = 0; i < geom1.coordinates.length; i++) { - if ( - booleanPointOnLine( - { type: "Point", coordinates: geom1.coordinates[i] }, - geom2, - { ignoreEndVertices: true } - ) - ) + if (booleanPointOnLine( + Point(coordinates: geom1.coordinates[i]), geom2, + ignoreEndVertices: true)) { return false; + } } return endMatch; - case "MultiLineString": + case MultiLineString: var endMatch = false; for (var i = 0; i < geom2.coordinates.length; i++) { - if ( - isPointOnLineEnd( - { type: "Point", coordinates: geom1.coordinates[0] }, - { type: "LineString", coordinates: geom2.coordinates[i] } - ) - ) + if (isPointOnLineEnd(Point(coordinates: geom1.coordinates[0]), + LineString(coordinates: geom2.coordinates[i]))) { endMatch = true; - if ( - isPointOnLineEnd( - { - type: "Point", + } + if (isPointOnLineEnd( + Point( coordinates: geom1.coordinates[geom1.coordinates.length - 1], - }, - { type: "LineString", coordinates: geom2.coordinates[i] } - ) - ) + ), + LineString(coordinates: geom2.coordinates[i]))) { endMatch = true; + } for (var ii = 0; ii < geom1.coordinates[i].length; ii++) { - if ( - booleanPointOnLine( - { type: "Point", coordinates: geom1.coordinates[ii] }, - { type: "LineString", coordinates: geom2.coordinates[i] }, - { ignoreEndVertices: true } - ) - ) + if (booleanPointOnLine(Point(coordinates: geom1.coordinates[ii]), + LineString(coordinates: geom2.coordinates[i]), + ignoreEndVertices: true)) { return false; + } } } return endMatch; - case "Polygon": + case Polygon: var foundTouchingPoint = false; for (var i = 0; i < geom1.coordinates.length; i++) { if (!foundTouchingPoint) { - if ( - booleanPointOnLine( - { type: "Point", coordinates: geom1.coordinates[i] }, - { type: "LineString", coordinates: geom2.coordinates[0] } - ) - ) + if (booleanPointOnLine(Point(coordinates: geom1.coordinates[i]), + LineString(coordinates: geom2.coordinates[0]))) { foundTouchingPoint = true; + } } - if ( - booleanPointInPolygon( - { type: "Point", coordinates: geom1.coordinates[i] }, - geom2, - { ignoreBoundary: true } - ) - ) + if (booleanPointInPolygon( + Point(coordinates: geom1.coordinates[i]), geom2, + ignoreBoundary: true)) { return false; + } } return foundTouchingPoint; - case "MultiPolygon": + case MultiPolygon: var foundTouchingPoint = false; for (var i = 0; i < geom1.coordinates.length; i++) { for (var ii = 0; ii < geom2.coordinates.length; ii++) { if (!foundTouchingPoint) { - if ( - booleanPointOnLine( - { type: "Point", coordinates: geom1.coordinates[i] }, - { - type: "LineString", + if (booleanPointOnLine( + Point(coordinates: geom1.coordinates[i]), + LineString( coordinates: geom2.coordinates[ii][0], - } - ) - ) + ))) { foundTouchingPoint = true; + } } } - if ( - booleanPointInPolygon( - { type: "Point", coordinates: geom1.coordinates[i] }, - geom2, - { ignoreBoundary: true } - ) - ) + if (booleanPointInPolygon( + Point(coordinates: geom1.coordinates[i]), geom2, + ignoreBoundary: true)) { return false; + } } return foundTouchingPoint; default: - throw new Error("feature2 " + type2 + " geometry not supported"); + throw Exception("feature2 " + type2 + " geometry not supported"); } - case "MultiLineString": + case MultiLineString: switch (type2) { - case "Point": + case Point: for (var i = 0; i < geom1.coordinates.length; i++) { - if ( - isPointOnLineEnd(geom2, { - type: "LineString", - coordinates: geom1.coordinates[i], - }) - ) + if (isPointOnLineEnd( + geom2, + LineString( + coordinates: geom1.coordinates[i], + ))) { return true; + } } return false; - case "MultiPoint": + case MultiPoint: var foundTouchingPoint = false; for (var i = 0; i < geom1.coordinates.length; i++) { for (var ii = 0; ii < geom2.coordinates.length; ii++) { if (!foundTouchingPoint) { - if ( - isPointOnLineEnd( - { type: "Point", coordinates: geom2.coordinates[ii] }, - { type: "LineString", coordinates: geom1.coordinates[ii] } - ) - ) + if (isPointOnLineEnd(Point(coordinates: geom2.coordinates[ii]), + LineString(coordinates: geom1.coordinates[ii]))) { foundTouchingPoint = true; + } } - if ( - booleanPointOnLine( - { type: "Point", coordinates: geom2.coordinates[ii] }, - { type: "LineString", coordinates: geom1.coordinates[ii] }, - { ignoreEndVertices: true } - ) - ) + if (booleanPointOnLine(Point(coordinates: geom2.coordinates[ii]), + LineString(coordinates: geom1.coordinates[ii]), + ignoreEndVertices: true)) { return false; + } } } return foundTouchingPoint; - case "LineString": + case LineString: var endMatch = false; for (var i = 0; i < geom1.coordinates.length; i++) { - if ( - isPointOnLineEnd( - { type: "Point", coordinates: geom1.coordinates[i][0] }, - geom2 - ) - ) + if (isPointOnLineEnd( + Point(coordinates: geom1.coordinates[i][0]), geom2)) { endMatch = true; - if ( - isPointOnLineEnd( - { - type: "Point", - coordinates: - geom1.coordinates[i][geom1.coordinates[i].length - 1], - }, - geom2 - ) - ) + } + if (isPointOnLineEnd( + Point( + coordinates: geom1.coordinates[i] + [geom1.coordinates[i].length - 1], + ), + geom2)) { endMatch = true; + } for (var ii = 0; ii < geom2.coordinates.length; ii++) { - if ( - booleanPointOnLine( - { type: "Point", coordinates: geom2.coordinates[ii] }, - { type: "LineString", coordinates: geom1.coordinates[i] }, - { ignoreEndVertices: true } - ) - ) + if (booleanPointOnLine(Point(coordinates: geom2.coordinates[ii]), + LineString(coordinates: geom1.coordinates[i]), + ignoreEndVertices: true)) { return false; + } } } return endMatch; - case "MultiLineString": + case MultiLineString: var endMatch = false; for (var i = 0; i < geom1.coordinates.length; i++) { for (var ii = 0; ii < geom2.coordinates.length; ii++) { - if ( - isPointOnLineEnd( - { type: "Point", coordinates: geom1.coordinates[i][0] }, - { type: "LineString", coordinates: geom2.coordinates[ii] } - ) - ) + if (isPointOnLineEnd(Point(coordinates: geom1.coordinates[i][0]), + LineString(coordinates: geom2.coordinates[ii]))) { endMatch = true; - if ( - isPointOnLineEnd( - { - type: "Point", - coordinates: - geom1.coordinates[i][geom1.coordinates[i].length - 1], - }, - { type: "LineString", coordinates: geom2.coordinates[ii] } - ) - ) + } + if (isPointOnLineEnd( + Point( + coordinates: geom1.coordinates[i] + [geom1.coordinates[i].length - 1], + ), + LineString(coordinates: geom2.coordinates[ii]))) { endMatch = true; + } for (var iii = 0; iii < geom1.coordinates[i].length; iii++) { - if ( - booleanPointOnLine( - { type: "Point", coordinates: geom1.coordinates[i][iii] }, - { type: "LineString", coordinates: geom2.coordinates[ii] }, - { ignoreEndVertices: true } - ) - ) + if (booleanPointOnLine( + Point(coordinates: geom1.coordinates[i][iii]), + LineString(coordinates: geom2.coordinates[ii]), + ignoreEndVertices: true)) { return false; + } } } } return endMatch; - case "Polygon": + case Polygon: var foundTouchingPoint = false; for (var i = 0; i < geom1.coordinates.length; i++) { for (var ii = 0; ii < geom1.coordinates.length; ii++) { if (!foundTouchingPoint) { - if ( - booleanPointOnLine( - { type: "Point", coordinates: geom1.coordinates[i][ii] }, - { type: "LineString", coordinates: geom2.coordinates[0] } - ) - ) + if (booleanPointOnLine( + Point(coordinates: geom1.coordinates[i][ii]), + LineString(coordinates: geom2.coordinates[0]))) { foundTouchingPoint = true; + } } - if ( - booleanPointInPolygon( - { type: "Point", coordinates: geom1.coordinates[i][ii] }, - geom2, - { ignoreBoundary: true } - ) - ) + if (booleanPointInPolygon( + Point(coordinates: geom1.coordinates[i][ii]), geom2, + ignoreBoundary: true)) { return false; + } } } return foundTouchingPoint; - case "MultiPolygon": + case MultiPolygon: var foundTouchingPoint = false; for (var i = 0; i < geom2.coordinates[0].length; i++) { for (var ii = 0; ii < geom1.coordinates.length; ii++) { for (var iii = 0; iii < geom1.coordinates[ii].length; iii++) { if (!foundTouchingPoint) { - if ( - booleanPointOnLine( - { - type: "Point", + if (booleanPointOnLine( + Point( coordinates: geom1.coordinates[ii][iii], - }, - { - type: "LineString", + ), + LineString( coordinates: geom2.coordinates[0][i], - } - ) - ) + ))) { foundTouchingPoint = true; + } } - if ( - booleanPointInPolygon( - { type: "Point", coordinates: geom1.coordinates[ii][iii] }, - { type: "Polygon", coordinates: [geom2.coordinates[0][i]] }, - { ignoreBoundary: true } - ) - ) + if (booleanPointInPolygon( + Point(coordinates: geom1.coordinates[ii][iii]), + Polygon(coordinates: [geom2.coordinates[0][i]]), + ignoreBoundary: true)) { return false; + } } } } return foundTouchingPoint; default: - throw new Error("feature2 " + type2 + " geometry not supported"); + throw Exception("feature2 " + type2 + " geometry not supported"); } - case "Polygon": + case Polygon: switch (type2) { - case "Point": + case Point: for (var i = 0; i < geom1.coordinates.length; i++) { - if ( - booleanPointOnLine(geom2, { - type: "LineString", - coordinates: geom1.coordinates[i], - }) - ) + if (booleanPointOnLine( + geom2, + LineString( + coordinates: geom1.coordinates[i], + ))) { return true; + } } return false; - case "MultiPoint": + case MultiPoint: var foundTouchingPoint = false; for (var i = 0; i < geom2.coordinates.length; i++) { if (!foundTouchingPoint) { - if ( - booleanPointOnLine( - { type: "Point", coordinates: geom2.coordinates[i] }, - { type: "LineString", coordinates: geom1.coordinates[0] } - ) - ) + if (booleanPointOnLine(Point(coordinates: geom2.coordinates[i]), + LineString(coordinates: geom1.coordinates[0]))) { foundTouchingPoint = true; + } } - if ( - booleanPointInPolygon( - { type: "Point", coordinates: geom2.coordinates[i] }, - geom1, - { ignoreBoundary: true } - ) - ) - return false; + if (booleanPointInPolygon( + Point(coordinates: geom2.coordinates[i]), geom1, + ignoreBoundary: true)) return false; } return foundTouchingPoint; - case "LineString": + case LineString: var foundTouchingPoint = false; for (var i = 0; i < geom2.coordinates.length; i++) { if (!foundTouchingPoint) { - if ( - booleanPointOnLine( - { type: "Point", coordinates: geom2.coordinates[i] }, - { type: "LineString", coordinates: geom1.coordinates[0] } - ) - ) + if (booleanPointOnLine(Point(coordinates: geom2.coordinates[i]), + LineString(coordinates: geom1.coordinates[0]))) { foundTouchingPoint = true; + } } - if ( - booleanPointInPolygon( - { type: "Point", coordinates: geom2.coordinates[i] }, - geom1, - { ignoreBoundary: true } - ) - ) + if (booleanPointInPolygon( + Point(coordinates: geom2.coordinates[i]), geom1, + ignoreBoundary: true)) { return false; + } } return foundTouchingPoint; - case "MultiLineString": + case MultiLineString: var foundTouchingPoint = false; for (var i = 0; i < geom2.coordinates.length; i++) { for (var ii = 0; ii < geom2.coordinates[i].length; ii++) { if (!foundTouchingPoint) { - if ( - booleanPointOnLine( - { type: "Point", coordinates: geom2.coordinates[i][ii] }, - { type: "LineString", coordinates: geom1.coordinates[0] } - ) - ) + if (booleanPointOnLine( + Point(coordinates: geom2.coordinates[i][ii]), + LineString(coordinates: geom1.coordinates[0]))) { foundTouchingPoint = true; + } } - if ( - booleanPointInPolygon( - { type: "Point", coordinates: geom2.coordinates[i][ii] }, - geom1, - { ignoreBoundary: true } - ) - ) + if (booleanPointInPolygon( + Point(coordinates: geom2.coordinates[i][ii]), geom1, + ignoreBoundary: true)) { return false; + } } } return foundTouchingPoint; - case "Polygon": + case Polygon: var foundTouchingPoint = false; for (var i = 0; i < geom1.coordinates[0].length; i++) { if (!foundTouchingPoint) { - if ( - booleanPointOnLine( - { type: "Point", coordinates: geom1.coordinates[0][i] }, - { type: "LineString", coordinates: geom2.coordinates[0] } - ) - ) + if (booleanPointOnLine( + Point(coordinates: geom1.coordinates[0][i]), + LineString(coordinates: geom2.coordinates[0]))) { foundTouchingPoint = true; + } } - if ( - booleanPointInPolygon( - { type: "Point", coordinates: geom1.coordinates[0][i] }, - geom2, - { ignoreBoundary: true } - ) - ) + if (booleanPointInPolygon( + Point(coordinates: geom1.coordinates[0][i]), geom2, + ignoreBoundary: true)) { return false; + } } return foundTouchingPoint; - case "MultiPolygon": + case MultiPolygon: var foundTouchingPoint = false; for (var i = 0; i < geom2.coordinates[0].length; i++) { for (var ii = 0; ii < geom1.coordinates[0].length; ii++) { if (!foundTouchingPoint) { - if ( - booleanPointOnLine( - { type: "Point", coordinates: geom1.coordinates[0][ii] }, - { type: "LineString", coordinates: geom2.coordinates[0][i] } - ) - ) + if (booleanPointOnLine( + Point(coordinates: geom1.coordinates[0][ii]), + LineString(coordinates: geom2.coordinates[0][i]))) { foundTouchingPoint = true; + } } - if ( - booleanPointInPolygon( - { type: "Point", coordinates: geom1.coordinates[0][ii] }, - { type: "Polygon", coordinates: geom2.coordinates[0][i] }, - { ignoreBoundary: true } - ) - ) + if (booleanPointInPolygon( + Point(coordinates: geom1.coordinates[0][ii]), + Polygon(coordinates: geom2.coordinates[0][i]), + ignoreBoundary: true)) { return false; + } } } return foundTouchingPoint; default: - throw new Error("feature2 " + type2 + " geometry not supported"); + throw Exception("feature2 " + type2 + " geometry not supported"); } - case "MultiPolygon": + case MultiPolygon: switch (type2) { - case "Point": + case Point: for (var i = 0; i < geom1.coordinates[0].length; i++) { - if ( - booleanPointOnLine(geom2, { - type: "LineString", - coordinates: geom1.coordinates[0][i], - }) - ) + if (booleanPointOnLine( + geom2, + LineString( + coordinates: geom1.coordinates[0][i], + ))) { return true; + } } return false; - case "MultiPoint": + case MultiPoint: var foundTouchingPoint = false; for (var i = 0; i < geom1.coordinates[0].length; i++) { for (var ii = 0; ii < geom2.coordinates.length; ii++) { if (!foundTouchingPoint) { - if ( - booleanPointOnLine( - { type: "Point", coordinates: geom2.coordinates[ii] }, - { type: "LineString", coordinates: geom1.coordinates[0][i] } - ) - ) + if (booleanPointOnLine( + Point(coordinates: geom2.coordinates[ii]), + LineString(coordinates: geom1.coordinates[0][i]))) { foundTouchingPoint = true; + } } - if ( - booleanPointInPolygon( - { type: "Point", coordinates: geom2.coordinates[ii] }, - { type: "Polygon", coordinates: geom1.coordinates[0][i] }, - { ignoreBoundary: true } - ) - ) + if (booleanPointInPolygon( + Point(coordinates: geom2.coordinates[ii]), + Polygon(coordinates: geom1.coordinates[0][i]), + ignoreBoundary: true)) { return false; + } } } return foundTouchingPoint; - case "LineString": + case LineString: var foundTouchingPoint = false; for (var i = 0; i < geom1.coordinates[0].length; i++) { for (var ii = 0; ii < geom2.coordinates.length; ii++) { if (!foundTouchingPoint) { - if ( - booleanPointOnLine( - { type: "Point", coordinates: geom2.coordinates[ii] }, - { type: "LineString", coordinates: geom1.coordinates[0][i] } - ) - ) + if (booleanPointOnLine( + Point(coordinates: geom2.coordinates[ii]), + LineString(coordinates: geom1.coordinates[0][i]))) { foundTouchingPoint = true; + } } - if ( - booleanPointInPolygon( - { type: "Point", coordinates: geom2.coordinates[ii] }, - { type: "Polygon", coordinates: geom1.coordinates[0][i] }, - { ignoreBoundary: true } - ) - ) + if (booleanPointInPolygon( + Point(coordinates: geom2.coordinates[ii]), + Polygon(coordinates: geom1.coordinates[0][i]), + ignoreBoundary: true)) { return false; + } } } return foundTouchingPoint; - case "MultiLineString": + case MultiLineString: var foundTouchingPoint = false; for (var i = 0; i < geom1.coordinates.length; i++) { for (var ii = 0; ii < geom2.coordinates.length; ii++) { for (var iii = 0; iii < geom2.coordinates[ii].length; iii++) { if (!foundTouchingPoint) { - if ( - booleanPointOnLine( - { - type: "Point", + if (booleanPointOnLine( + Point( coordinates: geom2.coordinates[ii][iii], - }, - { - type: "LineString", + ), + LineString( coordinates: geom1.coordinates[i][0], - } - ) - ) + ))) { foundTouchingPoint = true; + } } - if ( - booleanPointInPolygon( - { type: "Point", coordinates: geom2.coordinates[ii][iii] }, - { type: "Polygon", coordinates: [geom1.coordinates[i][0]] }, - { ignoreBoundary: true } - ) - ) + if (booleanPointInPolygon( + Point(coordinates: geom2.coordinates[ii][iii]), + Polygon(coordinates: [geom1.coordinates[i][0]]), + ignoreBoundary: true)) { return false; + } } } } return foundTouchingPoint; - case "Polygon": + case Polygon: var foundTouchingPoint = false; for (var i = 0; i < geom1.coordinates[0].length; i++) { for (var ii = 0; ii < geom1.coordinates[0][i].length; ii++) { if (!foundTouchingPoint) { - if ( - booleanPointOnLine( - { type: "Point", coordinates: geom1.coordinates[0][i][ii] }, - { type: "LineString", coordinates: geom2.coordinates[0] } - ) - ) + if (booleanPointOnLine( + Point(coordinates: geom1.coordinates[0][i][ii]), + LineString(coordinates: geom2.coordinates[0]))) { foundTouchingPoint = true; + } } - if ( - booleanPointInPolygon( - { type: "Point", coordinates: geom1.coordinates[0][i][ii] }, - geom2, - { ignoreBoundary: true } - ) - ) + if (booleanPointInPolygon( + Point(coordinates: geom1.coordinates[0][i][ii]), geom2, + ignoreBoundary: true)) { return false; + } } } return foundTouchingPoint; - case "MultiPolygon": + case MultiPolygon: var foundTouchingPoint = false; for (var i = 0; i < geom1.coordinates[0].length; i++) { for (var ii = 0; ii < geom2.coordinates[0].length; ii++) { for (var iii = 0; iii < geom1.coordinates[0].length; iii++) { if (!foundTouchingPoint) { - if ( - booleanPointOnLine( - { - type: "Point", + if (booleanPointOnLine( + Point( coordinates: geom1.coordinates[0][i][iii], - }, - { - type: "LineString", + ), + LineString( coordinates: geom2.coordinates[0][ii], - } - ) - ) + ))) { foundTouchingPoint = true; + } } - if ( - booleanPointInPolygon( - { - type: "Point", + if (booleanPointInPolygon( + Point( coordinates: geom1.coordinates[0][i][iii], - }, - { type: "Polygon", coordinates: geom2.coordinates[0][ii] }, - { ignoreBoundary: true } - ) - ) + ), + Polygon(coordinates: geom2.coordinates[0][ii]), + ignoreBoundary: true)) { return false; + } } } } return foundTouchingPoint; default: - throw new Error("feature2 " + type2 + " geometry not supported"); + throw Exception("feature2 " + type2 + " geometry not supported"); } default: - throw new Error("feature1 " + type1 + " geometry not supported"); + throw Exception("feature1 " + type1 + " geometry not supported"); } } - isPointOnLineEnd(point: Point, line: LineString) { +isPointOnLineEnd(Point point, LineString line) { if (compareCoords(line.coordinates[0], point.coordinates)) return true; - if ( - compareCoords( - line.coordinates[line.coordinates.length - 1], - point.coordinates - ) - ) + if (compareCoords( + line.coordinates[line.coordinates.length - 1], point.coordinates)) { return true; + } return false; } @@ -782,12 +627,12 @@ * @param {Position} pair2 point [x,y] * @returns {boolean} true/false if coord pairs match */ - compareCoords(pair1: number[], pair2: number[]) { +compareCoords(Position pair1, Position pair2) { return pair1[0] == pair2[0] && pair1[1] == pair2[1]; } -/** import { Feature, Geometry, LineString, Point } from "geojson"; +/** import { Feature, Geometry, LineString(Point } from "geojson"; import booleanPointOnLine from "@turf/boolean-point-on-line"; import booleanPointInPolygon from "@turf/boolean-point-in-polygon"; import { getGeom } from "@turf/invariant"; @@ -816,39 +661,36 @@ function booleanTouches( var type2 = geom2.type; switch (type1) { - case "Point": + case Point: switch (type2) { - case "LineString": + case LineString: return isPointOnLineEnd(geom1, geom2); - case "MultiLineString": + case MultiLineString: var foundTouchingPoint = false; for (var ii = 0; ii < geom2.coordinates.length; ii++) { if ( - isPointOnLineEnd(geom1, { - type: "LineString", + isPointOnLineEnd(geom1, LineString( coordinates: geom2.coordinates[ii], }) ) foundTouchingPoint = true; } return foundTouchingPoint; - case "Polygon": + case Polygon: for (var i = 0; i < geom2.coordinates.length; i++) { if ( - booleanPointOnLine(geom1, { - type: "LineString", + booleanPointOnLine(geom1, LineString( coordinates: geom2.coordinates[i], - }) + )) ) return true; } return false; - case "MultiPolygon": + case MultiPolygon: for (var i = 0; i < geom2.coordinates.length; i++) { for (var ii = 0; ii < geom2.coordinates[i].length; ii++) { if ( - booleanPointOnLine(geom1, { - type: "LineString", + booleanPointOnLine(geom1,LineString( coordinates: geom2.coordinates[i][ii], }) ) @@ -857,17 +699,17 @@ function booleanTouches( } return false; default: - throw new Error("feature2 " + type2 + " geometry not supported"); + throw Exception("feature2 " + type2 + " geometry not supported"); } - case "MultiPoint": + case MultiPoint: switch (type2) { - case "LineString": + case LineString: var foundTouchingPoint = false; for (var i = 0; i < geom1.coordinates.length; i++) { if (!foundTouchingPoint) { if ( isPointOnLineEnd( - { type: "Point", coordinates: geom1.coordinates[i] }, + Point(coordinates: geom1.coordinates[i]), geom2 ) ) @@ -875,81 +717,80 @@ function booleanTouches( } if ( booleanPointOnLine( - { type: "Point", coordinates: geom1.coordinates[i] }, + Point(coordinates: geom1.coordinates[i]), geom2, - { ignoreEndVertices: true } + ignoreEndVertices: true ) ) return false; } return foundTouchingPoint; - case "MultiLineString": + case MultiLineString: var foundTouchingPoint = false; for (var i = 0; i < geom1.coordinates.length; i++) { for (var ii = 0; ii < geom2.coordinates.length; ii++) { if (!foundTouchingPoint) { if ( isPointOnLineEnd( - { type: "Point", coordinates: geom1.coordinates[i] }, - { type: "LineString", coordinates: geom2.coordinates[ii] } + Point(coordinates: geom1.coordinates[i]), + LineString( coordinates: geom2.coordinates[ii] ) ) ) foundTouchingPoint = true; } if ( booleanPointOnLine( - { type: "Point", coordinates: geom1.coordinates[i] }, - { type: "LineString", coordinates: geom2.coordinates[ii] }, - { ignoreEndVertices: true } + Point(coordinates: geom1.coordinates[i]), + LineString( coordinates: geom2.coordinates[ii] ), + ignoreEndVertices: true ) ) return false; } } return foundTouchingPoint; - case "Polygon": + case Polygon: var foundTouchingPoint = false; for (var i = 0; i < geom1.coordinates.length; i++) { if (!foundTouchingPoint) { if ( booleanPointOnLine( - { type: "Point", coordinates: geom1.coordinates[i] }, - { type: "LineString", coordinates: geom2.coordinates[0] } + Point(coordinates: geom1.coordinates[i]), + LineString(coordinates: geom2.coordinates[0] ) ) ) foundTouchingPoint = true; } if ( booleanPointInPolygon( - { type: "Point", coordinates: geom1.coordinates[i] }, + Point(coordinates: geom1.coordinates[i]), geom2, - { ignoreBoundary: true } + ignoreBoundary: true ) ) return false; } return foundTouchingPoint; - case "MultiPolygon": + case MultiPolygon: var foundTouchingPoint = false; for (var i = 0; i < geom1.coordinates.length; i++) { for (var ii = 0; ii < geom2.coordinates.length; ii++) { if (!foundTouchingPoint) { if ( booleanPointOnLine( - { type: "Point", coordinates: geom1.coordinates[i] }, - { - type: "LineString", + Point(coordinates: geom1.coordinates[i]), +LineString( coordinates: geom2.coordinates[ii][0], - } + ) ) ) foundTouchingPoint = true; } if ( booleanPointInPolygon( - { type: "Point", coordinates: geom1.coordinates[i] }, - { type: "Polygon", coordinates: geom2.coordinates[ii] }, - { ignoreBoundary: true } + Point(coordinates: geom1.coordinates[i]), + Polygon( coordinates: geom2.coordinates[ii] ), + ignoreBoundary: true ) ) return false; @@ -957,19 +798,19 @@ function booleanTouches( } return foundTouchingPoint; default: - throw new Error("feature2 " + type2 + " geometry not supported"); + throw Exception("feature2 " + type2 + " geometry not supported"); } - case "LineString": + case LineString: switch (type2) { - case "Point": + case Point: return isPointOnLineEnd(geom2, geom1); - case "MultiPoint": + case MultiPoint: var foundTouchingPoint = false; for (var i = 0; i < geom2.coordinates.length; i++) { if (!foundTouchingPoint) { if ( isPointOnLineEnd( - { type: "Point", coordinates: geom2.coordinates[i] }, + Point(coordinates: geom2.coordinates[i] ), geom1 ) ) @@ -977,27 +818,26 @@ function booleanTouches( } if ( booleanPointOnLine( - { type: "Point", coordinates: geom2.coordinates[i] }, + Point(coordinates: geom2.coordinates[i] ), geom1, - { ignoreEndVertices: true } + ignoreEndVertices: true ) ) return false; } return foundTouchingPoint; - case "LineString": + case LineString: var endMatch = false; if ( isPointOnLineEnd( - { type: "Point", coordinates: geom1.coordinates[0] }, + Point(coordinates: geom1.coordinates[0] ), geom2 ) ) endMatch = true; if ( isPointOnLineEnd( - { - type: "Point", + Point( coordinates: geom1.coordinates[geom1.coordinates.length - 1], }, geom2 @@ -1008,80 +848,78 @@ function booleanTouches( for (var i = 0; i < geom1.coordinates.length; i++) { if ( booleanPointOnLine( - { type: "Point", coordinates: geom1.coordinates[i] }, + Point(coordinates: geom1.coordinates[i]), geom2, - { ignoreEndVertices: true } + ignoreEndVertices: true ) ) return false; } return endMatch; - case "MultiLineString": + case MultiLineString: var endMatch = false; for (var i = 0; i < geom2.coordinates.length; i++) { if ( isPointOnLineEnd( - { type: "Point", coordinates: geom1.coordinates[0] }, - { type: "LineString", coordinates: geom2.coordinates[i] } + Point(coordinates: geom1.coordinates[0] ), + LineString(coordinates: geom2.coordinates[i] ) ) ) endMatch = true; if ( isPointOnLineEnd( - { - type: "Point", + Point( coordinates: geom1.coordinates[geom1.coordinates.length - 1], - }, - { type: "LineString", coordinates: geom2.coordinates[i] } + ), + LineString(coordinates: geom2.coordinates[i] ) ) ) endMatch = true; for (var ii = 0; ii < geom1.coordinates[i].length; ii++) { if ( booleanPointOnLine( - { type: "Point", coordinates: geom1.coordinates[ii] }, - { type: "LineString", coordinates: geom2.coordinates[i] }, - { ignoreEndVertices: true } + Point(coordinates: geom1.coordinates[ii] ), + LineString(coordinates: geom2.coordinates[i] ), + ignoreEndVertices: true ) ) return false; } } return endMatch; - case "Polygon": + case Polygon: var foundTouchingPoint = false; for (var i = 0; i < geom1.coordinates.length; i++) { if (!foundTouchingPoint) { if ( booleanPointOnLine( - { type: "Point", coordinates: geom1.coordinates[i] }, - { type: "LineString", coordinates: geom2.coordinates[0] } + Point(coordinates: geom1.coordinates[i]), + LineString(coordinates: geom2.coordinates[0] ) ) ) foundTouchingPoint = true; } if ( booleanPointInPolygon( - { type: "Point", coordinates: geom1.coordinates[i] }, + Point(coordinates: geom1.coordinates[i]), geom2, - { ignoreBoundary: true } + ignoreBoundary: true ) ) return false; } return foundTouchingPoint; - case "MultiPolygon": + case MultiPolygon: var foundTouchingPoint = false; for (var i = 0; i < geom1.coordinates.length; i++) { for (var ii = 0; ii < geom2.coordinates.length; ii++) { if (!foundTouchingPoint) { if ( booleanPointOnLine( - { type: "Point", coordinates: geom1.coordinates[i] }, - { - type: "LineString", + Point(coordinates: geom1.coordinates[i]), +LineString( coordinates: geom2.coordinates[ii][0], - } + ) ) ) foundTouchingPoint = true; @@ -1089,68 +927,66 @@ function booleanTouches( } if ( booleanPointInPolygon( - { type: "Point", coordinates: geom1.coordinates[i] }, + Point(coordinates: geom1.coordinates[i]), geom2, - { ignoreBoundary: true } + ignoreBoundary: true ) ) return false; } return foundTouchingPoint; default: - throw new Error("feature2 " + type2 + " geometry not supported"); + throw Exception("feature2 " + type2 + " geometry not supported"); } - case "MultiLineString": + case MultiLineString: switch (type2) { - case "Point": + case Point: for (var i = 0; i < geom1.coordinates.length; i++) { if ( - isPointOnLineEnd(geom2, { - type: "LineString", + isPointOnLineEnd(geom2, LineString( coordinates: geom1.coordinates[i], - }) + )) ) return true; } return false; - case "MultiPoint": + case MultiPoint: var foundTouchingPoint = false; for (var i = 0; i < geom1.coordinates.length; i++) { for (var ii = 0; ii < geom2.coordinates.length; ii++) { if (!foundTouchingPoint) { if ( isPointOnLineEnd( - { type: "Point", coordinates: geom2.coordinates[ii] }, - { type: "LineString", coordinates: geom1.coordinates[ii] } + Point(coordinates: geom2.coordinates[ii] ), + LineString(coordinates: geom1.coordinates[ii] ) ) ) foundTouchingPoint = true; } if ( booleanPointOnLine( - { type: "Point", coordinates: geom2.coordinates[ii] }, - { type: "LineString", coordinates: geom1.coordinates[ii] }, - { ignoreEndVertices: true } + Point(coordinates: geom2.coordinates[ii] ), + LineString(coordinates: geom1.coordinates[ii] ), + ignoreEndVertices: true ) ) return false; } } return foundTouchingPoint; - case "LineString": + case LineString: var endMatch = false; for (var i = 0; i < geom1.coordinates.length; i++) { if ( isPointOnLineEnd( - { type: "Point", coordinates: geom1.coordinates[i][0] }, + Point(coordinates: geom1.coordinates[i][0] ), geom2 ) ) endMatch = true; if ( isPointOnLineEnd( - { - type: "Point", + Point( coordinates: geom1.coordinates[i][geom1.coordinates[i].length - 1], }, @@ -1161,43 +997,42 @@ function booleanTouches( for (var ii = 0; ii < geom2.coordinates.length; ii++) { if ( booleanPointOnLine( - { type: "Point", coordinates: geom2.coordinates[ii] }, - { type: "LineString", coordinates: geom1.coordinates[i] }, - { ignoreEndVertices: true } + Point(coordinates: geom2.coordinates[ii] ), + LineString(coordinates: geom1.coordinates[i] ), + ignoreEndVertices: true ) ) return false; } } return endMatch; - case "MultiLineString": + case MultiLineString: var endMatch = false; for (var i = 0; i < geom1.coordinates.length; i++) { for (var ii = 0; ii < geom2.coordinates.length; ii++) { if ( isPointOnLineEnd( - { type: "Point", coordinates: geom1.coordinates[i][0] }, - { type: "LineString", coordinates: geom2.coordinates[ii] } + Point(coordinates: geom1.coordinates[i][0] ), + LineString( coordinates: geom2.coordinates[ii] ) ) ) endMatch = true; if ( isPointOnLineEnd( - { - type: "Point", + Point( coordinates: geom1.coordinates[i][geom1.coordinates[i].length - 1], }, - { type: "LineString", coordinates: geom2.coordinates[ii] } + LineString( coordinates: geom2.coordinates[ii] ) ) ) endMatch = true; for (var iii = 0; iii < geom1.coordinates[i].length; iii++) { if ( booleanPointOnLine( - { type: "Point", coordinates: geom1.coordinates[i][iii] }, - { type: "LineString", coordinates: geom2.coordinates[ii] }, - { ignoreEndVertices: true } + Point(coordinates: geom1.coordinates[i][iii] }, + LineString( coordinates: geom2.coordinates[ii] ), + ignoreEndVertices: true ) ) return false; @@ -1205,31 +1040,31 @@ function booleanTouches( } } return endMatch; - case "Polygon": + case Polygon: var foundTouchingPoint = false; for (var i = 0; i < geom1.coordinates.length; i++) { for (var ii = 0; ii < geom1.coordinates.length; ii++) { if (!foundTouchingPoint) { if ( booleanPointOnLine( - { type: "Point", coordinates: geom1.coordinates[i][ii] }, - { type: "LineString", coordinates: geom2.coordinates[0] } + Point(coordinates: geom1.coordinates[i][ii] ), + LineString(coordinates: geom2.coordinates[0] ) ) ) foundTouchingPoint = true; } if ( booleanPointInPolygon( - { type: "Point", coordinates: geom1.coordinates[i][ii] }, + Point(coordinates: geom1.coordinates[i][ii] ), geom2, - { ignoreBoundary: true } + ignoreBoundary: true ) ) return false; } } return foundTouchingPoint; - case "MultiPolygon": + case MultiPolygon: var foundTouchingPoint = false; for (var i = 0; i < geom2.coordinates[0].length; i++) { for (var ii = 0; ii < geom1.coordinates.length; ii++) { @@ -1237,12 +1072,10 @@ function booleanTouches( if (!foundTouchingPoint) { if ( booleanPointOnLine( - { - type: "Point", + Point( coordinates: geom1.coordinates[ii][iii], }, - { - type: "LineString", + LineString( coordinates: geom2.coordinates[0][i], } ) @@ -1251,9 +1084,9 @@ function booleanTouches( } if ( booleanPointInPolygon( - { type: "Point", coordinates: geom1.coordinates[ii][iii] }, - { type: "Polygon", coordinates: [geom2.coordinates[0][i]] }, - { ignoreBoundary: true } + Point(coordinates: geom1.coordinates[ii][iii] }, + Polygon( coordinates: [geom2.coordinates[0][i]] }, + ignoreBoundary: true ) ) return false; @@ -1262,129 +1095,128 @@ function booleanTouches( } return foundTouchingPoint; default: - throw new Error("feature2 " + type2 + " geometry not supported"); + throw Exception("feature2 " + type2 + " geometry not supported"); } - case "Polygon": + case Polygon: switch (type2) { - case "Point": + case Point: for (var i = 0; i < geom1.coordinates.length; i++) { if ( - booleanPointOnLine(geom2, { - type: "LineString", + booleanPointOnLine(geom2, LineString( coordinates: geom1.coordinates[i], - }) + )) ) return true; } return false; - case "MultiPoint": + case MultiPoint: var foundTouchingPoint = false; for (var i = 0; i < geom2.coordinates.length; i++) { if (!foundTouchingPoint) { if ( booleanPointOnLine( - { type: "Point", coordinates: geom2.coordinates[i] }, - { type: "LineString", coordinates: geom1.coordinates[0] } + Point(coordinates: geom2.coordinates[i] ), + LineString(coordinates: geom1.coordinates[0] ) ) ) foundTouchingPoint = true; } if ( booleanPointInPolygon( - { type: "Point", coordinates: geom2.coordinates[i] }, + Point(coordinates: geom2.coordinates[i] ), geom1, - { ignoreBoundary: true } + ignoreBoundary: true ) ) return false; } return foundTouchingPoint; - case "LineString": + case LineString: var foundTouchingPoint = false; for (var i = 0; i < geom2.coordinates.length; i++) { if (!foundTouchingPoint) { if ( booleanPointOnLine( - { type: "Point", coordinates: geom2.coordinates[i] }, - { type: "LineString", coordinates: geom1.coordinates[0] } + Point(coordinates: geom2.coordinates[i] ), + LineString(coordinates: geom1.coordinates[0] ) ) ) foundTouchingPoint = true; } if ( booleanPointInPolygon( - { type: "Point", coordinates: geom2.coordinates[i] }, + Point(coordinates: geom2.coordinates[i] ), geom1, - { ignoreBoundary: true } + ignoreBoundary: true ) ) return false; } return foundTouchingPoint; - case "MultiLineString": + case MultiLineString: var foundTouchingPoint = false; for (var i = 0; i < geom2.coordinates.length; i++) { for (var ii = 0; ii < geom2.coordinates[i].length; ii++) { if (!foundTouchingPoint) { if ( booleanPointOnLine( - { type: "Point", coordinates: geom2.coordinates[i][ii] }, - { type: "LineString", coordinates: geom1.coordinates[0] } + Point(coordinates: geom2.coordinates[i][ii] ), + LineString(coordinates: geom1.coordinates[0] ) ) ) foundTouchingPoint = true; } if ( booleanPointInPolygon( - { type: "Point", coordinates: geom2.coordinates[i][ii] }, + Point(coordinates: geom2.coordinates[i][ii] ), geom1, - { ignoreBoundary: true } + ignoreBoundary: true ) ) return false; } } return foundTouchingPoint; - case "Polygon": + case Polygon: var foundTouchingPoint = false; for (var i = 0; i < geom1.coordinates[0].length; i++) { if (!foundTouchingPoint) { if ( booleanPointOnLine( - { type: "Point", coordinates: geom1.coordinates[0][i] }, - { type: "LineString", coordinates: geom2.coordinates[0] } + Point(coordinates: geom1.coordinates[0][i] ), + LineString(coordinates: geom2.coordinates[0] ) ) ) foundTouchingPoint = true; } if ( booleanPointInPolygon( - { type: "Point", coordinates: geom1.coordinates[0][i] }, + Point(coordinates: geom1.coordinates[0][i] ), geom2, - { ignoreBoundary: true } + ignoreBoundary: true ) ) return false; } return foundTouchingPoint; - case "MultiPolygon": + case MultiPolygon: var foundTouchingPoint = false; for (var i = 0; i < geom2.coordinates[0].length; i++) { for (var ii = 0; ii < geom1.coordinates[0].length; ii++) { if (!foundTouchingPoint) { if ( booleanPointOnLine( - { type: "Point", coordinates: geom1.coordinates[0][ii] }, - { type: "LineString", coordinates: geom2.coordinates[0][i] } + Point(coordinates: geom1.coordinates[0][ii] ), + LineString(coordinates: geom2.coordinates[0][i] ) ) ) foundTouchingPoint = true; } if ( booleanPointInPolygon( - { type: "Point", coordinates: geom1.coordinates[0][ii] }, - { type: "Polygon", coordinates: geom2.coordinates[0][i] }, - { ignoreBoundary: true } + Point(coordinates: geom1.coordinates[0][ii] ), + Polygon( coordinates: geom2.coordinates[0][i] ), + ignoreBoundary: true ) ) return false; @@ -1392,70 +1224,69 @@ function booleanTouches( } return foundTouchingPoint; default: - throw new Error("feature2 " + type2 + " geometry not supported"); + throw Exception("feature2 " + type2 + " geometry not supported"); } - case "MultiPolygon": + case MultiPolygon: switch (type2) { - case "Point": + case Point: for (var i = 0; i < geom1.coordinates[0].length; i++) { if ( - booleanPointOnLine(geom2, { - type: "LineString", + booleanPointOnLine(geom2, LineString( coordinates: geom1.coordinates[0][i], - }) + )) ) return true; } return false; - case "MultiPoint": + case MultiPoint: var foundTouchingPoint = false; for (var i = 0; i < geom1.coordinates[0].length; i++) { for (var ii = 0; ii < geom2.coordinates.length; ii++) { if (!foundTouchingPoint) { if ( booleanPointOnLine( - { type: "Point", coordinates: geom2.coordinates[ii] }, - { type: "LineString", coordinates: geom1.coordinates[0][i] } + Point(coordinates: geom2.coordinates[ii] ), + LineString(coordinates: geom1.coordinates[0][i] ) ) ) foundTouchingPoint = true; } if ( booleanPointInPolygon( - { type: "Point", coordinates: geom2.coordinates[ii] }, - { type: "Polygon", coordinates: geom1.coordinates[0][i] }, - { ignoreBoundary: true } + Point(coordinates: geom2.coordinates[ii] ), + Polygon( coordinates: geom1.coordinates[0][i] ), + ignoreBoundary: true ) ) return false; } } return foundTouchingPoint; - case "LineString": + case LineString: var foundTouchingPoint = false; for (var i = 0; i < geom1.coordinates[0].length; i++) { for (var ii = 0; ii < geom2.coordinates.length; ii++) { if (!foundTouchingPoint) { if ( booleanPointOnLine( - { type: "Point", coordinates: geom2.coordinates[ii] }, - { type: "LineString", coordinates: geom1.coordinates[0][i] } + Point(coordinates: geom2.coordinates[ii] ), + LineString(coordinates: geom1.coordinates[0][i] ) ) ) foundTouchingPoint = true; } if ( booleanPointInPolygon( - { type: "Point", coordinates: geom2.coordinates[ii] }, - { type: "Polygon", coordinates: geom1.coordinates[0][i] }, - { ignoreBoundary: true } + Point(coordinates: geom2.coordinates[ii] ), + Polygon( coordinates: geom1.coordinates[0][i] ), + ignoreBoundary: true ) ) return false; } } return foundTouchingPoint; - case "MultiLineString": + case MultiLineString: var foundTouchingPoint = false; for (var i = 0; i < geom1.coordinates.length; i++) { for (var ii = 0; ii < geom2.coordinates.length; ii++) { @@ -1463,12 +1294,10 @@ function booleanTouches( if (!foundTouchingPoint) { if ( booleanPointOnLine( - { - type: "Point", + Point( coordinates: geom2.coordinates[ii][iii], }, - { - type: "LineString", + LineString( coordinates: geom1.coordinates[i][0], } ) @@ -1477,9 +1306,9 @@ function booleanTouches( } if ( booleanPointInPolygon( - { type: "Point", coordinates: geom2.coordinates[ii][iii] }, - { type: "Polygon", coordinates: [geom1.coordinates[i][0]] }, - { ignoreBoundary: true } + Point(coordinates: geom2.coordinates[ii][iii] }, + Polygon( coordinates: [geom1.coordinates[i][0]] }, + ignoreBoundary: true ) ) return false; @@ -1488,31 +1317,31 @@ function booleanTouches( } return foundTouchingPoint; - case "Polygon": + case Polygon: var foundTouchingPoint = false; for (var i = 0; i < geom1.coordinates[0].length; i++) { for (var ii = 0; ii < geom1.coordinates[0][i].length; ii++) { if (!foundTouchingPoint) { if ( booleanPointOnLine( - { type: "Point", coordinates: geom1.coordinates[0][i][ii] }, - { type: "LineString", coordinates: geom2.coordinates[0] } + Point(coordinates: geom1.coordinates[0][i][ii] }, + LineString(coordinates: geom2.coordinates[0] ) ) ) foundTouchingPoint = true; } if ( booleanPointInPolygon( - { type: "Point", coordinates: geom1.coordinates[0][i][ii] }, + Point(coordinates: geom1.coordinates[0][i][ii] }, geom2, - { ignoreBoundary: true } + ignoreBoundary: true ) ) return false; } } return foundTouchingPoint; - case "MultiPolygon": + case MultiPolygon: var foundTouchingPoint = false; for (var i = 0; i < geom1.coordinates[0].length; i++) { for (var ii = 0; ii < geom2.coordinates[0].length; ii++) { @@ -1520,12 +1349,10 @@ function booleanTouches( if (!foundTouchingPoint) { if ( booleanPointOnLine( - { - type: "Point", + Point( coordinates: geom1.coordinates[0][i][iii], }, - { - type: "LineString", + LineString( coordinates: geom2.coordinates[0][ii], } ) @@ -1534,12 +1361,11 @@ function booleanTouches( } if ( booleanPointInPolygon( - { - type: "Point", + Point( coordinates: geom1.coordinates[0][i][iii], }, - { type: "Polygon", coordinates: geom2.coordinates[0][ii] }, - { ignoreBoundary: true } + Polygon( coordinates: geom2.coordinates[0][ii] ), + ignoreBoundary: true ) ) return false; @@ -1548,14 +1374,14 @@ function booleanTouches( } return foundTouchingPoint; default: - throw new Error("feature2 " + type2 + " geometry not supported"); + throw Exception("feature2 " + type2 + " geometry not supported"); } default: - throw new Error("feature1 " + type1 + " geometry not supported"); + throw Exception("feature1 " + type1 + " geometry not supported"); } } -function isPointOnLineEnd(point: Point, line: LineString) { +function isPointOnLineEnd(point: Point( line: LineString) { if (compareCoords(line.coordinates[0], point.coordinates)) return true; if ( compareCoords( From da256175857e493fe20963ac6d35c6eeb43f9858 Mon Sep 17 00:00:00 2001 From: armantorkzaban Date: Wed, 8 Jun 2022 23:14:57 +0200 Subject: [PATCH 14/82] valid - wip --- lib/src/booleans/boolean_crosses.dart | 33 ++-- lib/src/booleans/boolean_disjoint.dart | 192 ++++++++++++++++++++ lib/src/booleans/boolean_valid.dart | 238 +++++++++++++++++++++++++ lib/src/line_intersect.dart | 167 +++++++++++++++++ 4 files changed, 613 insertions(+), 17 deletions(-) create mode 100644 lib/src/booleans/boolean_valid.dart create mode 100644 lib/src/line_intersect.dart diff --git a/lib/src/booleans/boolean_crosses.dart b/lib/src/booleans/boolean_crosses.dart index 293fa38d..9e42a97a 100644 --- a/lib/src/booleans/boolean_crosses.dart +++ b/lib/src/booleans/boolean_crosses.dart @@ -1,7 +1,6 @@ -import 'dart:math'; - import '../../helpers.dart'; import '../invariant.dart'; +import 'boolean_point_in_polygon.dart'; /** * Boolean-Crosses returns True if the intersection results in a geometry whose dimension is one less than * the maximum dimension of the two source geometries and the intersection set is interior to @@ -22,7 +21,7 @@ import '../invariant.dart'; * //=true */ -bool booleanCrosses(GeoJSONObjectType feature1, GeoJSONObjectType feature2) { +bool booleanCrosses(GeometryObject feature1, GeometryObject feature2) { var geom1 = getGeom(feature1); var geom2 = getGeom(feature2); var type1 = geom1.type; @@ -149,12 +148,12 @@ doesMultiPointCrossPoly(MultiPoint multiPoint, Polygon polygon) { * @returns {boolean} true/false */ -isPointOnLineSegment(List lineSegmentStart, List lineSegmentEnd, - List pt, bool incEnd) { - var dxc = pt[0] - lineSegmentStart[0]; - var dyc = pt[1] - lineSegmentStart[1]; - var dxl = lineSegmentEnd[0] - lineSegmentStart[0]; - var dyl = lineSegmentEnd[1] - lineSegmentStart[1]; +isPointOnLineSegment(Position lineSegmentStart, Position lineSegmentEnd, + Position pt, bool incEnd) { + var dxc = pt[0]! - lineSegmentStart[0]!; + var dyc = pt[1]! - lineSegmentStart[1]!; + var dxl = lineSegmentEnd[0]! - lineSegmentStart[0]!; + var dyl = lineSegmentEnd[1]! - lineSegmentStart[1]!; var cross = dxc * dyl - dyc * dxl; if (cross != 0) { return false; @@ -162,21 +161,21 @@ isPointOnLineSegment(List lineSegmentStart, List lineSegmentEnd, if (incEnd) { if ((dxl).abs() >= (dyl).abs()) { return dxl > 0 - ? lineSegmentStart[0] <= pt[0] && pt[0] <= lineSegmentEnd[0] - : lineSegmentEnd[0] <= pt[0] && pt[0] <= lineSegmentStart[0]; + ? lineSegmentStart[0]! <= pt[0]! && pt[0]! <= lineSegmentEnd[0]! + : lineSegmentEnd[0]! <= pt[0]! && pt[0]! <= lineSegmentStart[0]!; } return dyl > 0 - ? lineSegmentStart[1] <= pt[1] && pt[1] <= lineSegmentEnd[1] - : lineSegmentEnd[1] <= pt[1] && pt[1] <= lineSegmentStart[1]; + ? lineSegmentStart[1]! <= pt[1]! && pt[1]! <= lineSegmentEnd[1]! + : lineSegmentEnd[1]! <= pt[1]! && pt[1]! <= lineSegmentStart[1]!; } else { if ((dxl).abs() >= (dyl).abs()) { return dxl > 0 - ? lineSegmentStart[0] < pt[0] && pt[0] < lineSegmentEnd[0] - : lineSegmentEnd[0] < pt[0] && pt[0] < lineSegmentStart[0]; + ? lineSegmentStart[0]! < pt[0]! && pt[0]! < lineSegmentEnd[0]! + : lineSegmentEnd[0]! < pt[0]! && pt[0]! < lineSegmentStart[0]!; } return dyl > 0 - ? lineSegmentStart[1] < pt[1] && pt[1] < lineSegmentEnd[1] - : lineSegmentEnd[1] < pt[1] && pt[1] < lineSegmentStart[1]; + ? lineSegmentStart[1]! < pt[1]! && pt[1]! < lineSegmentEnd[1]! + : lineSegmentEnd[1]! < pt[1]! && pt[1]! < lineSegmentStart[1]!; } } diff --git a/lib/src/booleans/boolean_disjoint.dart b/lib/src/booleans/boolean_disjoint.dart index 9df83759..c44dba1a 100644 --- a/lib/src/booleans/boolean_disjoint.dart +++ b/lib/src/booleans/boolean_disjoint.dart @@ -171,3 +171,195 @@ isPointOnLineSegment(Point lineSegmentStart, Point lineSegmentEnd, Point pt) { compareCoords(Position pair1, Position pair2) { return pair1[0] == pair2[0] && pair1[1] == pair2[1]; } + + +/** + * import { Feature, Geometry, LineString, Point, Polygon } from "geojson"; +import booleanPointInPolygon from "@turf/boolean-point-in-polygon"; +import lineIntersect from "@turf/line-intersect"; +import { flattenEach } from "@turf/meta"; +import polygonToLine from "@turf/polygon-to-line"; + +/** + * Boolean-disjoint returns (TRUE) if the intersection of the two geometries is an empty set. + * + * @name booleanDisjoint + * @param {Geometry|Feature} feature1 GeoJSON Feature or Geometry + * @param {Geometry|Feature} feature2 GeoJSON Feature or Geometry + * @returns {boolean} true/false + * @example + * var point = turf.point([2, 2]); + * var line = turf.lineString([[1, 1], [1, 2], [1, 3], [1, 4]]); + * + * turf.booleanDisjoint(line, point); + * //=true + */ +function booleanDisjoint( + feature1: Feature | Geometry, + feature2: Feature | Geometry +): boolean { + let bool = true; + flattenEach(feature1, (flatten1) => { + flattenEach(feature2, (flatten2) => { + if (bool === false) { + return false; + } + bool = disjoint(flatten1.geometry, flatten2.geometry); + }); + }); + return bool; +} + +/** + * Disjoint operation for simple Geometries (Point/LineString/Polygon) + * + * @private + * @param {Geometry} geom1 GeoJSON Geometry + * @param {Geometry} geom2 GeoJSON Geometry + * @returns {boolean} true/false + */ +function disjoint(geom1: any, geom2: any) { + switch (geom1.type) { + case "Point": + switch (geom2.type) { + case "Point": + return !compareCoords(geom1.coordinates, geom2.coordinates); + case "LineString": + return !isPointOnLine(geom2, geom1); + case "Polygon": + return !booleanPointInPolygon(geom1, geom2); + } + /* istanbul ignore next */ + break; + case "LineString": + switch (geom2.type) { + case "Point": + return !isPointOnLine(geom1, geom2); + case "LineString": + return !isLineOnLine(geom1, geom2); + case "Polygon": + return !isLineInPoly(geom2, geom1); + } + /* istanbul ignore next */ + break; + case "Polygon": + switch (geom2.type) { + case "Point": + return !booleanPointInPolygon(geom2, geom1); + case "LineString": + return !isLineInPoly(geom1, geom2); + case "Polygon": + return !isPolyInPoly(geom2, geom1); + } + } + return false; +} + +// http://stackoverflow.com/a/11908158/1979085 +function isPointOnLine(lineString: LineString, pt: Point) { + for (let i = 0; i < lineString.coordinates.length - 1; i++) { + if ( + isPointOnLineSegment( + lineString.coordinates[i], + lineString.coordinates[i + 1], + pt.coordinates + ) + ) { + return true; + } + } + return false; +} + +function isLineOnLine(lineString1: LineString, lineString2: LineString) { + const doLinesIntersect = lineIntersect(lineString1, lineString2); + if (doLinesIntersect.features.length > 0) { + return true; + } + return false; +} + +function isLineInPoly(polygon: Polygon, lineString: LineString) { + for (const coord of lineString.coordinates) { + if (booleanPointInPolygon(coord, polygon)) { + return true; + } + } + const doLinesIntersect = lineIntersect(lineString, polygonToLine(polygon)); + if (doLinesIntersect.features.length > 0) { + return true; + } + return false; +} + +/** + * Is Polygon (geom1) in Polygon (geom2) + * Only takes into account outer rings + * See http://stackoverflow.com/a/4833823/1979085 + * + * @private + * @param {Geometry|Feature} feature1 Polygon1 + * @param {Geometry|Feature} feature2 Polygon2 + * @returns {boolean} true/false + */ +function isPolyInPoly(feature1: Polygon, feature2: Polygon) { + for (const coord1 of feature1.coordinates[0]) { + if (booleanPointInPolygon(coord1, feature2)) { + return true; + } + } + for (const coord2 of feature2.coordinates[0]) { + if (booleanPointInPolygon(coord2, feature1)) { + return true; + } + } + const doLinesIntersect = lineIntersect( + polygonToLine(feature1), + polygonToLine(feature2) + ); + if (doLinesIntersect.features.length > 0) { + return true; + } + return false; +} + +function isPointOnLineSegment( + lineSegmentStart: number[], + lineSegmentEnd: number[], + pt: number[] +) { + const dxc = pt[0] - lineSegmentStart[0]; + const dyc = pt[1] - lineSegmentStart[1]; + const dxl = lineSegmentEnd[0] - lineSegmentStart[0]; + const dyl = lineSegmentEnd[1] - lineSegmentStart[1]; + const cross = dxc * dyl - dyc * dxl; + if (cross !== 0) { + return false; + } + if (Math.abs(dxl) >= Math.abs(dyl)) { + if (dxl > 0) { + return lineSegmentStart[0] <= pt[0] && pt[0] <= lineSegmentEnd[0]; + } else { + return lineSegmentEnd[0] <= pt[0] && pt[0] <= lineSegmentStart[0]; + } + } else if (dyl > 0) { + return lineSegmentStart[1] <= pt[1] && pt[1] <= lineSegmentEnd[1]; + } else { + return lineSegmentEnd[1] <= pt[1] && pt[1] <= lineSegmentStart[1]; + } +} + +/** + * compareCoords + * + * @private + * @param {Position} pair1 point [x,y] + * @param {Position} pair2 point [x,y] + * @returns {boolean} true/false if coord pairs match + */ +function compareCoords(pair1: number[], pair2: number[]) { + return pair1[0] === pair2[0] && pair1[1] === pair2[1]; +} + +export default booleanDisjoint; + */ \ No newline at end of file diff --git a/lib/src/booleans/boolean_valid.dart b/lib/src/booleans/boolean_valid.dart new file mode 100644 index 00000000..79aec7b0 --- /dev/null +++ b/lib/src/booleans/boolean_valid.dart @@ -0,0 +1,238 @@ +import '../../helpers.dart'; +import '../invariant.dart'; +import 'boolean_crosses.dart'; +import 'boolean_disjoint.dart'; + +/** + * booleanValid checks if the geometry is a valid according to the OGC Simple Feature Specification. + * + * @name booleanValid + * @param {Geometry|Feature} feature GeoJSON Feature or Geometry + * @returns {boolean} true/false + * @example + * var line = turf.lineString([[1, 1], [1, 2], [1, 3], [1, 4]]); + * + * turf.booleanValid(line); // => true + * turf.booleanValid({foo: "bar"}); // => false + */ + +booleanValid(GeoJSONObject feature) { + // // Automatic False + // if (!feature.type) return false; + + // Parse GeoJSON + var geom = getGeom(feature); + var type = geom.type; + var coords = geom.coordinates; + + switch (type) { + case Point: + return coords.length > 1; + case MultiPoint: + for (var i = 0; i < coords.length; i++) { + if (coords[i].length < 2) return false; + } + return true; + case LineString: + if (coords.length < 2) return false; + for (var i = 0; i < coords.length; i++) { + if (coords[i].length < 2) return false; + } + return true; + case MultiLineString: + if (coords.length < 2) return false; + for (var i = 0; i < coords.length; i++) { + if (coords[i].length < 2) return false; + } + return true; + case Polygon: + for (var i = 0; i < geom.coordinates.length; i++) { + if (coords[i].length < 4) return false; + if (!checkRingsClose(coords[i])) return false; + if (checkRingsForSpikesPunctures(coords[i])) return false; + if (i > 0) { + if (lineIntersect(Polygon(coordinates: [coords[0]]), + Polygon(coordinates: [coords[i]])).features.length > + 1) return false; + } + } + return true; + case MultiPolygon: + for (var i = 0; i < geom.coordinates.length; i++) { + var poly = geom.coordinates[i]; + + for (var ii = 0; ii < poly.length; ii++) { + if (poly[ii].length < 4) return false; + if (!checkRingsClose(poly[ii])) return false; + if (checkRingsForSpikesPunctures(poly[ii])) return false; + if (ii == 0) { + if (!checkPolygonAgainstOthers(poly, geom.coordinates, i)) { + return false; + } + } + if (ii > 0) { + if (lineIntersect(Polygon(coordinates: [poly[0]]), + Polygon(coordinates: [poly[ii]])).features.length > + 1) { + return false; + } + } + } + } + return true; + default: + return false; + } +} + +checkRingsClose(List geom) { + return (geom[0][0] == geom[geom.length - 1][0] || + geom[0][1] == geom[geom.length - 1][1]); +} + +checkRingsForSpikesPunctures(List geom) { + for (var i = 0; i < geom.length - 1; i++) { + var point = Point(coordinates: geom[i]); + for (var ii = i + 1; ii < geom.length - 2; ii++) { + var seg = [geom[ii], geom[ii + 1]]; + if (isPointOnLine(LineString(coordinates: seg), point)) return true; + } + } + return false; +} + +checkPolygonAgainstOthers( + List> poly, List>> geom, int index) { + var polyToCheck = Polygon(coordinates: poly); + for (var i = index + 1; i < geom.length; i++) { + if (!booleanDisjoint(polyToCheck, Polygon(coordinates: geom[i]))) { + if (booleanCrosses(polyToCheck, LineString(coordinates: geom[i][0]))) + return false; + } + } + return true; +} + +/** + * import { Feature, Geometry, Position } from "geojson"; +import { getGeom } from "@turf/invariant"; +import { polygon, lineString } from "@turf/helpers"; +import booleanDisjoint from "@turf/boolean-disjoint"; +import booleanCrosses from "@turf/boolean-crosses"; +import lineIntersect from "@turf/line-intersect"; +import isPointOnLine from "@turf/boolean-point-on-line"; + +/** + * booleanValid checks if the geometry is a valid according to the OGC Simple Feature Specification. + * + * @name booleanValid + * @param {Geometry|Feature} feature GeoJSON Feature or Geometry + * @returns {boolean} true/false + * @example + * var line = turf.lineString([[1, 1], [1, 2], [1, 3], [1, 4]]); + * + * turf.booleanValid(line); // => true + * turf.booleanValid({foo: "bar"}); // => false + */ +export default function booleanValid(feature: Feature | Geometry) { + // Automatic False + if (!feature.type) return false; + + // Parse GeoJSON + const geom = getGeom(feature); + const type = geom.type; + const coords = geom.coordinates; + + switch (type) { + case Point: + return coords.length > 1; + case MultiPoint: + for (var i = 0; i < coords.length; i++) { + if (coords[i].length < 2) return false; + } + return true; + case LineString: + if (coords.length < 2) return false; + for (var i = 0; i < coords.length; i++) { + if (coords[i].length < 2) return false; + } + return true; + case MultiLineString: + if (coords.length < 2) return false; + for (var i = 0; i < coords.length; i++) { + if (coords[i].length < 2) return false; + } + return true; + case Polygon: + for (var i = 0; i < geom.coordinates.length; i++) { + if (coords[i].length < 4) return false; + if (!checkRingsClose(coords[i])) return false; + if (checkRingsForSpikesPunctures(coords[i])) return false; + if (i > 0) { + if ( + lineIntersect(polygon([coords[0]]), polygon([coords[i]])).features + .length > 1 + ) + return false; + } + } + return true; + case MultiPolygon: + for (var i = 0; i < geom.coordinates.length; i++) { + var poly: any = geom.coordinates[i]; + + for (var ii = 0; ii < poly.length; ii++) { + if (poly[ii].length < 4) return false; + if (!checkRingsClose(poly[ii])) return false; + if (checkRingsForSpikesPunctures(poly[ii])) return false; + if (ii === 0) { + if (!checkPolygonAgainstOthers(poly, geom.coordinates, i)) + return false; + } + if (ii > 0) { + if ( + lineIntersect(polygon([poly[0]]), polygon([poly[ii]])).features + .length > 1 + ) + return false; + } + } + } + return true; + default: + return false; + } +} + +function checkRingsClose(geom: Position[]) { + return ( + geom[0][0] === geom[geom.length - 1][0] || + geom[0][1] === geom[geom.length - 1][1] + ); +} + +function checkRingsForSpikesPunctures(geom: Position[]) { + for (var i = 0; i < geom.length - 1; i++) { + var point = geom[i]; + for (var ii = i + 1; ii < geom.length - 2; ii++) { + var seg = [geom[ii], geom[ii + 1]]; + if (isPointOnLine(point, lineString(seg))) return true; + } + } + return false; +} + +function checkPolygonAgainstOthers( + poly: Position[][], + geom: Position[][][], + index: number +) { + var polyToCheck = polygon(poly); + for (var i = index + 1; i < geom.length; i++) { + if (!booleanDisjoint(polyToCheck, polygon(geom[i]))) { + if (booleanCrosses(polyToCheck, lineString(geom[i][0]))) return false; + } + } + return true; +} + */ \ No newline at end of file diff --git a/lib/src/line_intersect.dart b/lib/src/line_intersect.dart new file mode 100644 index 00000000..a82fcbe2 --- /dev/null +++ b/lib/src/line_intersect.dart @@ -0,0 +1,167 @@ + +import '../helpers.dart'; + +/** + * Takes any LineString or Polygon GeoJSON and returns the intersecting point(s). + * + * @name lineIntersect + * @param {GeoJSON} line1 any LineString or Polygon + * @param {GeoJSON} line2 any LineString or Polygon + * @param {Object} [options={}] Optional parameters + * @param {boolean} [options.removeDuplicates=true] remove duplicate intersections + * @param {boolean} [options.ignoreSelfIntersections=false] ignores self-intersections on input features + * @returns {FeatureCollection} point(s) that intersect both + * @example + * var line1 = turf.lineString([[126, -11], [129, -21]]); + * var line2 = turf.lineString([[123, -18], [131, -14]]); + * var intersects = turf.lineIntersect(line1, line2); + * + * //addToMap + * var addToMap = [line1, line2, intersects] + */ +FeatureCollection lineIntersect( + GeoJSONObject line1, + GeoJSONObject line2, +{ + bool removeDuplicates = true, + bool ignoreSelfIntersections = false + } +){ + var features= []; + if (line1.runtimeType == FeatureCollection) +{ features = features..addAll((line1 as FeatureCollection).features); +} else if (line1 is Feature) {features.add(line1);} + else if ( + line1.runtimeType == LineString || + line1.runtimeType == Polygon || + line1.runtimeType == MultiLineString || + line1.runtimeType == MultiPolygon + ) { + features.add(Feature(geometry: line1 as GeometryObject)); + } + + if (line2 is FeatureCollection) + {features = features..addAll(line2.features);} + else if (line2 is Feature) {features.add(line2);} + else if ( + line2 is LineString || + line2 is Polygon || + line2 is MultiLineString || + line2 is MultiPolygon + ) { + features.add(Feature(geometry: line2 as GeometryObject)); + } + + const intersections = findIntersections( + FeatureCollection(features: features), + ignoreSelfIntersections + ); + + var results: Intersection[] = []; + if (removeDuplicates) { + const unique: Record = {}; + intersections.forEach((intersection) => { + var key = intersection.join(","); + if (!unique[key]) { + unique[key] = true; + results.push(intersection); + } + }); + } else { + results = intersections; + } + return FeatureCollection(features: results.map((r) => Feature(geometry: Point(coordinates:r)))); +} + + +/** + * import { feature, featureCollection, point } from "@turf/helpers"; +import { + Feature, + FeatureCollection, + LineString, + MultiLineString, + MultiPolygon, + Point, + Polygon, +} from "geojson"; +import findIntersections, { Intersection } from "sweepline-intersections"; + +/** + * Takes any LineString or Polygon GeoJSON and returns the intersecting point(s). + * + * @name lineIntersect + * @param {GeoJSON} line1 any LineString or Polygon + * @param {GeoJSON} line2 any LineString or Polygon + * @param {Object} [options={}] Optional parameters + * @param {boolean} [options.removeDuplicates=true] remove duplicate intersections + * @param {boolean} [options.ignoreSelfIntersections=false] ignores self-intersections on input features + * @returns {FeatureCollection} point(s) that intersect both + * @example + * var line1 = turf.lineString([[126, -11], [129, -21]]); + * var line2 = turf.lineString([[123, -18], [131, -14]]); + * var intersects = turf.lineIntersect(line1, line2); + * + * //addToMap + * var addToMap = [line1, line2, intersects] + */ +function lineIntersect< + G1 extends LineString | MultiLineString | Polygon | MultiPolygon, + G2 extends LineString | MultiLineString | Polygon | MultiPolygon +>( + line1: FeatureCollection | Feature | G1, + line2: FeatureCollection | Feature | G2, + options: { + removeDuplicates?: boolean; + ignoreSelfIntersections?: boolean; + } = {} +): FeatureCollection { + const { removeDuplicates = true, ignoreSelfIntersections = false } = options; + let features: Feature[] = []; + if (line1.type === "FeatureCollection") + features = features.concat(line1.features); + else if (line1.type === "Feature") features.push(line1); + else if ( + line1.type === "LineString" || + line1.type === "Polygon" || + line1.type === "MultiLineString" || + line1.type === "MultiPolygon" + ) { + features.push(feature(line1)); + } + + if (line2.type === "FeatureCollection") + features = features.concat(line2.features); + else if (line2.type === "Feature") features.push(line2); + else if ( + line2.type === "LineString" || + line2.type === "Polygon" || + line2.type === "MultiLineString" || + line2.type === "MultiPolygon" + ) { + features.push(feature(line2)); + } + + const intersections = findIntersections( + featureCollection(features), + ignoreSelfIntersections + ); + + let results: Intersection[] = []; + if (removeDuplicates) { + const unique: Record = {}; + intersections.forEach((intersection) => { + const key = intersection.join(","); + if (!unique[key]) { + unique[key] = true; + results.push(intersection); + } + }); + } else { + results = intersections; + } + return featureCollection(results.map((r) => point(r))); +} + +export default lineIntersect; + */ \ No newline at end of file From a15a417b51a269e1e9925dcbf77d9617ada3077d Mon Sep 17 00:00:00 2001 From: armantorkzaban Date: Wed, 8 Jun 2022 23:26:22 +0200 Subject: [PATCH 15/82] within - init --- lib/src/booleans/boolean_within.dart | 487 +++++++++++++++++++++++++++ 1 file changed, 487 insertions(+) create mode 100644 lib/src/booleans/boolean_within.dart diff --git a/lib/src/booleans/boolean_within.dart b/lib/src/booleans/boolean_within.dart new file mode 100644 index 00000000..8f801871 --- /dev/null +++ b/lib/src/booleans/boolean_within.dart @@ -0,0 +1,487 @@ +import '../../helpers.dart'; +import '../invariant.dart'; +import 'boolean_point_in_polygon.dart'; +import 'boolean_point_on_line.dart'; + +/** + * Boolean-within returns true if the first geometry is completely within the second geometry. + * The interiors of both geometries must intersect and, the interior and boundary of the primary (geometry a) + * must not intersect the exterior of the secondary (geometry b). + * Boolean-within returns the exact opposite result of the `@turf/boolean-contains`. + * + * @name booleanWithin + * @param {Geometry|Feature} feature1 GeoJSON Feature or Geometry + * @param {Geometry|Feature} feature2 GeoJSON Feature or Geometry + * @returns {boolean} true/false + * @example + * var line = turf.lineString([[1, 1], [1, 2], [1, 3], [1, 4]]); + * var point = turf.point([1, 2]); + * + * turf.booleanWithin(point, line); + * //=true + */ +bool booleanWithin(GeoJSONObject feature1, GeoJSONObject feature2) { + var geom1 = getGeom(feature1); + var geom2 = getGeom(feature2); + var type1 = geom1.type; + var type2 = geom2.type; + + switch (type1) { + case "Point": + switch (type2) { + case "MultiPoint": + return isPointInMultiPoint(geom1, geom2); + case "LineString": + return booleanPointOnLine(geom1, geom2, ignoreEndVertices: true); + case "Polygon": + case "MultiPolygon": + return booleanPointInPolygon(geom1, geom2, ignoreBoundary: true); + default: + throw Exception("feature2 " + type2 + " geometry not supported"); + } + case "MultiPoint": + switch (type2) { + case "MultiPoint": + return isMultiPointInMultiPoint(geom1, geom2); + case "LineString": + return isMultiPointOnLine(geom1, geom2); + case "Polygon": + case "MultiPolygon": + return isMultiPointInPoly(geom1, geom2); + default: + throw Exception("feature2 " + type2 + " geometry not supported"); + } + case "LineString": + switch (type2) { + case "LineString": + return isLineOnLine(geom1, geom2); + case "Polygon": + case "MultiPolygon": + return isLineInPoly(geom1, geom2); + default: + throw Exception("feature2 " + type2 + " geometry not supported"); + } + case "Polygon": + switch (type2) { + case "Polygon": + case "MultiPolygon": + return isPolyInPoly(geom1, geom2); + default: + throw Exception("feature2 " + type2 + " geometry not supported"); + } + default: + throw Exception("feature1 " + type1 + " geometry not supported"); + } +} + +isPointInMultiPoint(Point point, MultiPoint multiPoint) { + var i; + var output = false; + for (i = 0; i < multiPoint.coordinates.length; i++) { + if (compareCoords(multiPoint.coordinates[i], point.coordinates)) { + output = true; + break; + } + } + return output; +} + +isMultiPointInMultiPoint(MultiPoint multiPoint1, MultiPoint multiPoint2) { + for (var i = 0; i < multiPoint1.coordinates.length; i++) { + var anyMatch = false; + for (var i2 = 0; i2 < multiPoint2.coordinates.length; i2++) { + if (compareCoords( + multiPoint1.coordinates[i], multiPoint2.coordinates[i2])) { + anyMatch = true; + } + } + if (!anyMatch) { + return false; + } + } + return true; +} + +isMultiPointOnLine(MultiPoint multiPoint, LineString lineString) { + var foundInsidePoint = false; + + for (var i = 0; i < multiPoint.coordinates.length; i++) { + if (!booleanPointOnLine(multiPoint.coordinates[i], lineString)) { + return false; + } + if (!foundInsidePoint) { + foundInsidePoint = booleanPointOnLine( + multiPoint.coordinates[i], lineString, {ignoreEndVertices: true}); + } + } + return foundInsidePoint; +} + +isMultiPointInPoly(MultiPoint multiPoint, Polygon polygon) { + var output = true; + var oneInside = false; + var isInside = false; + for (var i = 0; i < multiPoint.coordinates.length; i++) { + isInside = booleanPointInPolygon(multiPoint.coordinates[i], polygon); + if (!isInside) { + output = false; + break; + } + if (!oneInside) { + isInside = booleanPointInPolygon(multiPoint.coordinates[i], polygon, { + ignoreBoundary: true, + }); + } + } + return output && isInside; +} + +isLineOnLine(LineString lineString1, LineString lineString2) { + for (var i = 0; i < lineString1.coordinates.length; i++) { + if (!booleanPointOnLine(lineString1.coordinates[i], lineString2)) { + return false; + } + } + return true; +} + +isLineInPoly(LineString linestring, Polygon polygon) { + var polyBbox = calcBbox(polygon); + var lineBbox = calcBbox(linestring); + if (!doBBoxOverlap(polyBbox, lineBbox)) { + return false; + } + var foundInsidePoint = false; + + for (var i = 0; i < linestring.coordinates.length - 1; i++) { + if (!booleanPointInPolygon(linestring.coordinates[i], polygon)) { + return false; + } + if (!foundInsidePoint) { + foundInsidePoint = booleanPointInPolygon( + linestring.coordinates[i], polygon, {ignoreBoundary: true}); + } + if (!foundInsidePoint) { + var midpoint = + getMidpoint(linestring.coordinates[i], linestring.coordinates[i + 1]); + foundInsidePoint = booleanPointInPolygon(midpoint, polygon, { + ignoreBoundary: true, + }); + } + } + return foundInsidePoint; +} + +/** + * Is Polygon2 in Polygon1 + * Only takes into account outer rings + * + * @private + * @param {Polygon} geometry1 + * @param {Polygon|MultiPolygon} geometry2 + * @returns {boolean} true/false + */ +isPolyInPoly(Polygon geometry1, GeometryObject geometry2) { + var poly1Bbox = calcBbox(geometry1); + var poly2Bbox = calcBbox(geometry2); + if (!doBBoxOverlap(poly2Bbox, poly1Bbox)) { + return false; + } + for (var i = 0; i < geometry1.coordinates[0].length; i++) { + if (!booleanPointInPolygon(geometry1.coordinates[0][i], geometry2)) { + return false; + } + } + return true; +} + +doBBoxOverlap(BBox bbox1, BBox bbox2) { + if (bbox1[0]! > bbox2[0]!) return false; + if (bbox1[2]! < bbox2[2]!) return false; + if (bbox1[1]! > bbox2[1]!) return false; + if (bbox1[3]! < bbox2[3]!) return false; + return true; +} + +/** + * compareCoords + * + * @private + * @param {Position} pair1 point [x,y] + * @param {Position} pair2 point [x,y] + * @returns {boolean} true/false if coord pairs match + */ +compareCoords(Position pair1, Position pair2) { + return pair1[0] == pair2[0] && pair1[1] == pair2[1]; +} + +/** + * getMidpoint + * + * @private + * @param {Position} pair1 point [x,y] + * @param {Position} pair2 point [x,y] + * @returns {Position} midpoint of pair1 and pair2 + */ +getMidpoint(Position pair1, Position pair2) { + return [(pair1[0]! + pair2[0]!) / 2, (pair1[1]! + pair2[1]!) / 2]; +} + + + +/* +import { + BBox, + Feature, + Geometry, + LineString, + MultiPoint, + MultiPolygon, + Point, + Polygon, +} from "geojson"; +import calcBbox from "@turf/bbox"; +import booleanPointOnLine from "@turf/boolean-point-on-line"; +import booleanPointInPolygon from "@turf/boolean-point-in-polygon"; +import { getGeom } from "@turf/invariant"; + +/** + * Boolean-within returns true if the first geometry is completely within the second geometry. + * The interiors of both geometries must intersect and, the interior and boundary of the primary (geometry a) + * must not intersect the exterior of the secondary (geometry b). + * Boolean-within returns the exact opposite result of the `@turf/boolean-contains`. + * + * @name booleanWithin + * @param {Geometry|Feature} feature1 GeoJSON Feature or Geometry + * @param {Geometry|Feature} feature2 GeoJSON Feature or Geometry + * @returns {boolean} true/false + * @example + * var line = turf.lineString([[1, 1], [1, 2], [1, 3], [1, 4]]); + * var point = turf.point([1, 2]); + * + * turf.booleanWithin(point, line); + * //=true + */ +function booleanWithin( + feature1: Feature | Geometry, + feature2: Feature | Geometry +): boolean { + var geom1 = getGeom(feature1); + var geom2 = getGeom(feature2); + var type1 = geom1.type; + var type2 = geom2.type; + + switch (type1) { + case "Point": + switch (type2) { + case "MultiPoint": + return isPointInMultiPoint(geom1, geom2); + case "LineString": + return booleanPointOnLine(geom1, geom2, { ignoreEndVertices: true }); + case "Polygon": + case "MultiPolygon": + return booleanPointInPolygon(geom1, geom2, { ignoreBoundary: true }); + default: + throw Exception("feature2 " + type2 + " geometry not supported"); + } + case "MultiPoint": + switch (type2) { + case "MultiPoint": + return isMultiPointInMultiPoint(geom1, geom2); + case "LineString": + return isMultiPointOnLine(geom1, geom2); + case "Polygon": + case "MultiPolygon": + return isMultiPointInPoly(geom1, geom2); + default: + throw Exception("feature2 " + type2 + " geometry not supported"); + } + case "LineString": + switch (type2) { + case "LineString": + return isLineOnLine(geom1, geom2); + case "Polygon": + case "MultiPolygon": + return isLineInPoly(geom1, geom2); + default: + throw Exception("feature2 " + type2 + " geometry not supported"); + } + case "Polygon": + switch (type2) { + case "Polygon": + case "MultiPolygon": + return isPolyInPoly(geom1, geom2); + default: + throw Exception("feature2 " + type2 + " geometry not supported"); + } + default: + throw Exception("feature1 " + type1 + " geometry not supported"); + } +} + +function isPointInMultiPoint(point: Point, multiPoint: MultiPoint) { + var i; + var output = false; + for (i = 0; i < multiPoint.coordinates.length; i++) { + if (compareCoords(multiPoint.coordinates[i], point.coordinates)) { + output = true; + break; + } + } + return output; +} + +function isMultiPointInMultiPoint( + multiPoint1: MultiPoint, + multiPoint2: MultiPoint +) { + for (var i = 0; i < multiPoint1.coordinates.length; i++) { + var anyMatch = false; + for (var i2 = 0; i2 < multiPoint2.coordinates.length; i2++) { + if ( + compareCoords(multiPoint1.coordinates[i], multiPoint2.coordinates[i2]) + ) { + anyMatch = true; + } + } + if (!anyMatch) { + return false; + } + } + return true; +} + +function isMultiPointOnLine(multiPoint: MultiPoint, lineString: LineString) { + var foundInsidePoint = false; + + for (var i = 0; i < multiPoint.coordinates.length; i++) { + if (!booleanPointOnLine(multiPoint.coordinates[i], lineString)) { + return false; + } + if (!foundInsidePoint) { + foundInsidePoint = booleanPointOnLine( + multiPoint.coordinates[i], + lineString, + { ignoreEndVertices: true } + ); + } + } + return foundInsidePoint; +} + +function isMultiPointInPoly(multiPoint: MultiPoint, polygon: Polygon) { + var output = true; + var oneInside = false; + var isInside = false; + for (var i = 0; i < multiPoint.coordinates.length; i++) { + isInside = booleanPointInPolygon(multiPoint.coordinates[i], polygon); + if (!isInside) { + output = false; + break; + } + if (!oneInside) { + isInside = booleanPointInPolygon(multiPoint.coordinates[i], polygon, { + ignoreBoundary: true, + }); + } + } + return output && isInside; +} + +function isLineOnLine(LineString lineString1, LineString lineString2) { + for (var i = 0; i < lineString1.coordinates.length; i++) { + if (!booleanPointOnLine(lineString1.coordinates[i], lineString2)) { + return false; + } + } + return true; +} + +function isLineInPoly(linestring: LineString, polygon: Polygon) { + var polyBbox = calcBbox(polygon); + var lineBbox = calcBbox(linestring); + if (!doBBoxOverlap(polyBbox, lineBbox)) { + return false; + } + var foundInsidePoint = false; + + for (var i = 0; i < linestring.coordinates.length - 1; i++) { + if (!booleanPointInPolygon(linestring.coordinates[i], polygon)) { + return false; + } + if (!foundInsidePoint) { + foundInsidePoint = booleanPointInPolygon( + linestring.coordinates[i], + polygon, + { ignoreBoundary: true } + ); + } + if (!foundInsidePoint) { + var midpoint = getMidpoint( + linestring.coordinates[i], + linestring.coordinates[i + 1] + ); + foundInsidePoint = booleanPointInPolygon(midpoint, polygon, { + ignoreBoundary: true, + }); + } + } + return foundInsidePoint; +} + +/** + * Is Polygon2 in Polygon1 + * Only takes into account outer rings + * + * @private + * @param {Polygon} geometry1 + * @param {Polygon|MultiPolygon} geometry2 + * @returns {boolean} true/false + */ +function isPolyInPoly(geometry1: Polygon, geometry2: Polygon | MultiPolygon) { + var poly1Bbox = calcBbox(geometry1); + var poly2Bbox = calcBbox(geometry2); + if (!doBBoxOverlap(poly2Bbox, poly1Bbox)) { + return false; + } + for (var i = 0; i < geometry1.coordinates[0].length; i++) { + if (!booleanPointInPolygon(geometry1.coordinates[0][i], geometry2)) { + return false; + } + } + return true; +} + +function doBBoxOverlap(bbox1: BBox, bbox2: BBox) { + if (bbox1[0] > bbox2[0]) return false; + if (bbox1[2] < bbox2[2]) return false; + if (bbox1[1] > bbox2[1]) return false; + if (bbox1[3] < bbox2[3]) return false; + return true; +} + +/** + * compareCoords + * + * @private + * @param {Position} pair1 point [x,y] + * @param {Position} pair2 point [x,y] + * @returns {boolean} true/false if coord pairs match + */ +function compareCoords(Position pair1, Position pair2) { + return pair1[0] == pair2[0] && pair1[1] == pair2[1]; +} + +/** + * getMidpoint + * + * @private + * @param {Position} pair1 point [x,y] + * @param {Position} pair2 point [x,y] + * @returns {Position} midpoint of pair1 and pair2 + */ +function getMidpoint(Position pair1, Position pair2) { + return [(pair1[0] + pair2[0]) / 2, (pair1[1] + pair2[1]) / 2]; +} + +export default booleanWithin;*/ \ No newline at end of file From e43824137ed8f3c271b9ee08079506298a20f127 Mon Sep 17 00:00:00 2001 From: armantorkzaban Date: Thu, 9 Jun 2022 08:54:34 +0200 Subject: [PATCH 16/82] rewiring the translated code --- lib/src/booleans/boolean_contains.dart | 6 +- lib/src/booleans/boolean_disjoint.dart | 37 +- lib/src/booleans/boolean_overlap.dart | 17 +- lib/src/booleans/boolean_parallel.dart | 6 +- .../booleans/boolean_point_in_polygon.dart | 2 +- lib/src/clean_coords.dart | 400 ++++++++++++++++++ 6 files changed, 434 insertions(+), 34 deletions(-) create mode 100644 lib/src/clean_coords.dart diff --git a/lib/src/booleans/boolean_contains.dart b/lib/src/booleans/boolean_contains.dart index b2f856ca..e8d5f468 100644 --- a/lib/src/booleans/boolean_contains.dart +++ b/lib/src/booleans/boolean_contains.dart @@ -1,5 +1,7 @@ import '../../helpers.dart'; import '../invariant.dart'; +import 'boolean_disjoint.dart'; +import 'boolean_point_in_polygon.dart'; /** * Boolean-contains returns True if the second geometry is completely contained by the first geometry. @@ -18,7 +20,7 @@ import '../invariant.dart'; * turf.booleanContains(line, point); * //=true */ -booleanContains(GeoJSONObjectType feature1, GeoJSONObjectType feature2) { +booleanContains(GeoJSONObject feature1, GeoJSONObject feature2) { var geom1 = getGeom(feature1); var geom2 = getGeom(feature2); var type1 = geom1.runtimeType; @@ -48,7 +50,7 @@ booleanContains(GeoJSONObjectType feature1, GeoJSONObjectType feature2) { case LineString: switch (type2) { case Point: - return isPointOnLine(geom2, geom1, {ignoreEndVertices: true}); + return isPointOnLine(geom2, geom1, ignoreEndVertices: true); case LineString: return isLineOnLine(geom1, geom2); case MultiPoint: diff --git a/lib/src/booleans/boolean_disjoint.dart b/lib/src/booleans/boolean_disjoint.dart index c44dba1a..1dcf0a4f 100644 --- a/lib/src/booleans/boolean_disjoint.dart +++ b/lib/src/booleans/boolean_disjoint.dart @@ -1,5 +1,7 @@ import '../../helpers.dart'; import '../../meta.dart'; +import '../line_intersect.dart'; +import 'boolean_point_in_polygon.dart'; /** * Boolean-disjoint returns (TRUE) if the intersection of the two geometries is an empty set. @@ -45,7 +47,7 @@ disjoint(GeometryType geom1, GeometryType geom2) { case LineString: return !isPointOnLine(geom2 as LineString, geom1 as Point); case Polygon: - return !booleanPointInPolygon(geom1, geom2); + return !booleanPointInPolygon((geom1 as Point).coordinates, geom2); } /* istanbul ignore next */ break; @@ -63,7 +65,7 @@ disjoint(GeometryType geom1, GeometryType geom2) { case Polygon: switch (geom2.runtimeType) { case Point: - return !booleanPointInPolygon(geom2, geom1); + return !booleanPointInPolygon((geom2 as Point).coordinates, geom1); case LineString: return !isLineInPoly(geom1 as Polygon, geom2 as LineString); case Polygon: @@ -86,7 +88,7 @@ isPointOnLine(LineString lineString, Point pt) { isLineOnLine(LineString lineString1, LineString lineString2) { var doLinesIntersect = lineIntersect(lineString1, lineString2); - if (doLinesIntersect.features.length > 0) { + if (doLinesIntersect.features.isNotEmpty) { return true; } return false; @@ -98,8 +100,8 @@ isLineInPoly(Polygon polygon, LineString lineString) { return true; } } - const doLinesIntersect = lineIntersect(lineString, polygonToLine(polygon)); - if (doLinesIntersect.features.length > 0) { + var doLinesIntersect = lineIntersect(lineString, polygonToLine(polygon)); + if (doLinesIntersect.features.isNotEmpty) { return true; } return false; @@ -126,7 +128,7 @@ isPolyInPoly(Polygon feature1, Polygon feature2) { return true; } } - const doLinesIntersect = + var doLinesIntersect = lineIntersect(polygonToLine(feature1), polygonToLine(feature2)); if (doLinesIntersect.features.length > 0) { return true; @@ -134,29 +136,26 @@ isPolyInPoly(Polygon feature1, Polygon feature2) { return false; } -isPointOnLineSegment(Point lineSegmentStart, Point lineSegmentEnd, Point pt) { - var dxc = pt.coordinates[0]! - lineSegmentStart.coordinates[0]!; - var dyc = pt.coordinates[1]! - lineSegmentStart.coordinates[1]!; - var dxl = lineSegmentEnd.coordinates[0]! - lineSegmentStart.coordinates[0]!; - var dyl = lineSegmentEnd.coordinates[1]! - lineSegmentStart.coordinates[1]!; +isPointOnLineSegment( + Position lineSegmentStart, Position lineSegmentEnd, Position pt) { + var dxc = pt[0]! - lineSegmentStart[0]!; + var dyc = pt[1]! - lineSegmentStart[1]!; + var dxl = lineSegmentEnd[0]! - lineSegmentStart[0]!; + var dyl = lineSegmentEnd[1]! - lineSegmentStart[1]!; var cross = dxc * dyl - dyc * dxl; if (cross != 0) { return false; } if ((dxl).abs() >= (dyl).abs()) { if (dxl > 0) { - return lineSegmentStart.coordinates[0]! <= pt.coordinates[0]! && - pt.coordinates[0]! <= lineSegmentEnd.coordinates[0]!; + return lineSegmentStart[0]! <= pt[0]! && pt[0]! <= lineSegmentEnd[0]!; } else { - return lineSegmentEnd.coordinates[0]! <= pt.coordinates[0]! && - pt.coordinates[0]! <= lineSegmentStart.coordinates[0]!; + return lineSegmentEnd[0]! <= pt[0]! && pt[0]! <= lineSegmentStart[0]!; } } else if (dyl > 0) { - return lineSegmentStart.coordinates[1]! <= pt.coordinates[1]! && - pt.coordinates[1]! <= lineSegmentEnd.coordinates[1]!; + return lineSegmentStart[1]! <= pt[1]! && pt[1]! <= lineSegmentEnd[1]!; } else { - return lineSegmentEnd.coordinates[1]! <= pt.coordinates[1]! && - pt.coordinates[1]! <= lineSegmentStart.coordinates[1]!; + return lineSegmentEnd[1]! <= pt[1]! && pt[1]! <= lineSegmentStart[1]!; } } diff --git a/lib/src/booleans/boolean_overlap.dart b/lib/src/booleans/boolean_overlap.dart index 88d6d576..ab4862ad 100644 --- a/lib/src/booleans/boolean_overlap.dart +++ b/lib/src/booleans/boolean_overlap.dart @@ -1,12 +1,9 @@ -import { Feature, Geometry, MultiPoint } from "geojson"; -import { segmentEach } from "@turf/meta"; -import { getGeom } from "@turf/invariant"; -import lineOverlap from "@turf/line-overlap"; -import lineIntersect from "@turf/line-intersect"; -import + import '../../helpers.dart'; import '../../line_segment.dart'; -import '../invariant.dart';GeojsonEquality from "geojson-equality"; +import '../invariant.dart'; +import '../line_intersect.dart'; +GeojsonEquality from "geojson-equality"; /** * Compares two geometries of the same dimension and returns true if their intersection set results in a geometry @@ -52,8 +49,8 @@ import '../invariant.dart';GeojsonEquality from "geojson-equality"; if (type1 == Point) throw Exception("Point geometry not supported"); // features must be not equal - const equality = new GeojsonEquality({ precision: 6 }); - if (equality.compare(feature1 as any, feature2 as any)) return false; + const equality = GeojsonEquality({ precision: 6 }); + if (equality.compare(feature1, feature2)) return false; var overlap = 0; @@ -96,7 +93,7 @@ import '../invariant.dart';GeojsonEquality from "geojson-equality"; multiFeatureIndex, geometryIndex, segmentIndex,) { - if (lineIntersect(segment1, segment2).features.length) overlap++; + if (lineIntersect(segment1, segment2).features.isNotEmpty) overlap++; }); }); break; diff --git a/lib/src/booleans/boolean_parallel.dart b/lib/src/booleans/boolean_parallel.dart index 09eab5d7..aeaa12b2 100644 --- a/lib/src/booleans/boolean_parallel.dart +++ b/lib/src/booleans/boolean_parallel.dart @@ -1,5 +1,6 @@ import '../../helpers.dart'; import '../../line_segment.dart'; +import '../clean_coords.dart'; /** * Boolean-Parallel returns True if each segment of `line1` is parallel to the correspondent segment of `line2` @@ -59,8 +60,9 @@ getType(GeoJSONObject geojson, String name) { if ((geojson as Feature).geometry != null) { return geojson.geometry.runtimeType; } - if (geojson.runtimeType is GeometryType) - return geojson.type; // if GeoJSON geometry + if (geojson.runtimeType is GeometryType) { + return geojson.type; + } // if GeoJSON geometry throw Exception("Invalid GeoJSON object for $name"); } diff --git a/lib/src/booleans/boolean_point_in_polygon.dart b/lib/src/booleans/boolean_point_in_polygon.dart index 75588531..49b59988 100644 --- a/lib/src/booleans/boolean_point_in_polygon.dart +++ b/lib/src/booleans/boolean_point_in_polygon.dart @@ -28,7 +28,7 @@ import '../invariant.dart'; * turf.booleanPointInPolygon(pt, poly); * //= true */ -booleanPointInPolygon(Point point, GeometryObject polygon, +booleanPointInPolygon(Position point, GeometryObject polygon, {bool? ignoreBoundary}) { var pt = getCoord(point); var geom = getGeom(polygon); diff --git a/lib/src/clean_coords.dart b/lib/src/clean_coords.dart new file mode 100644 index 00000000..cde99903 --- /dev/null +++ b/lib/src/clean_coords.dart @@ -0,0 +1,400 @@ + + +// To-Do => Improve Typescript GeoJSON handling + +import '../helpers.dart'; +import 'invariant.dart'; + +/** + * Removes redundant coordinates from any GeoJSON Geometry. + * + * @name cleanCoords + * @param {Geometry|Feature} geojson Feature or Geometry + * @param {Object} [options={}] Optional parameters + * @param {boolean} [options.mutate=false] allows GeoJSON input to be mutated + * @returns {Geometry|Feature} the cleaned input Feature/Geometry + * @example + * var line = turf.lineString([[0, 0], [0, 2], [0, 5], [0, 8], [0, 8], [0, 10]]); + * var multiPoint = turf.multiPoint([[0, 0], [0, 0], [2, 2]]); + * + * turf.cleanCoords(line).geometry.coordinates; + * //= [[0, 0], [0, 10]] + * + * turf.cleanCoords(multiPoint).geometry.coordinates; + * //= [[0, 0], [2, 2]] + */ + cleanCoords( + GeoJSONObject geojson, + { + bool mutate, + } +) { + // // Backwards compatible with v4.0 + // var mutate = typeof options == "object" ? options.mutate : options; + // if (!geojson) throw Exception("geojson is required"); + var type = (geojson.runtimeType); + + // Store new "clean" points in this Array + var newCoords = []; + + switch (type) { + case LineString: + newCoords = cleanLine(geojson as LineString, type); + break; + case MultiLineString: + case Polygon: + getCoords(geojson).forEach( (line) { + newCoords.add(cleanLine(line, type)); + }); + break; + case MultiPolygon: + getCoords(geojson).forEach( (polygons: any) { + var polyPoints: Position[] = []; + polygons.forEach( (ring: Position[]) { + polyPoints.add(cleanLine(ring, type)); + }); + newCoords.add(polyPoints); + }); + break; + case Point: + return geojson; + case MultiPoint: + var existing: Record = {}; + getCoords(geojson).forEach( (coord: any) { + var key = coord.join("-"); + if (!Object.prototype.hasOwnProperty.call(existing, key)) { + newCoords.add(coord); + existing[key] = true; + } + }); + break; + default: + throw new Error(type + " geometry not supported"); + } + + // Support input mutation + if (geojson.coordinates) { + if (mutate == true) { + geojson.coordinates = newCoords; + return geojson; + } + return { type: type, coordinates: newCoords }; + } else { + if (mutate == true) { + geojson.geometry.coordinates = newCoords; + return geojson; + } + return feature({ type: type, coordinates: newCoords }, geojson.properties, { + bbox: geojson.bbox, + id: geojson.id, + }); + } +} + +/** + * Clean Coords + * + * @private + * @param {Array|LineString} line Line + * @param {string} type Type of geometry + * @returns {Array} Cleaned coordinates + */ + cleanLine(dynamic line, GeoJSONObjectType type) { + var points = getCoords(line); + // handle "clean" segment + if (points.length == 2 && !equals(points[0], points[1])) return points; + + var newPoints = []; + var secondToLast = points.length - 1; + var newPointsLength = newPoints.length; + + newPoints.add(points[0]); + for (var i = 1; i < secondToLast; i++) { + var prevAddedPoint = newPoints[newPoints.length - 1]; + if ( + points[i][0] == prevAddedPoint[0] && + points[i][1] == prevAddedPoint[1] + ) +{ continue; +} else { + newPoints.add(points[i]); + newPointsLength = newPoints.length; + if (newPointsLength > 2) { + if ( + isPointOnLineSegment( + newPoints[newPointsLength - 3], + newPoints[newPointsLength - 1], + newPoints[newPointsLength - 2] + ) + ) +{ newPoints.removeAt(newPoints.length - 2); +} } + } + } + newPoints.add(points[points.length - 1]); + newPointsLength = newPoints.length; + + // (Multi)Polygons must have at least 4 points, but a closed LineString with only 3 points is acceptable + if ( + (type is Polygon || type is MultiPolygon) && + equals(points[0], points[points.length - 1]) && + newPointsLength < 4 + ) { + throw Exception("invalid polygon"); + } + + if ( + isPointOnLineSegment( + newPoints[newPointsLength - 3], + newPoints[newPointsLength - 1], + newPoints[newPointsLength - 2] + ) + ) +{ newPoints.removeAt(newPoints.length - 2); +} + return newPoints; +} + +/** + * Compares two points and returns if they are equals + * + * @private + * @param {Position} pt1 point + * @param {Position} pt2 point + * @returns {boolean} true if they are equals + */ + equals(Position pt1 , Position pt2 ) { + return pt1[0] == pt2[0] && pt1[1] == pt2[1]; +} + +/** + * Returns if `point` is on the segment between `start` and `end`. + * Borrowed from `@turf/boolean-point-on-line` to speed up the evaluation (instead of using the module as dependency) + * + * @private + * @param {Position} start coord pair of start of line + * @param {Position} end coord pair of end of line + * @param {Position} point coord pair of point to check + * @returns {boolean} true/false + */ + isPointOnLineSegment(Position start , Position end , Position point ) { + var x = point[0], + y = point[1]; + var startX = start[0], + startY = start[1]; + var endX = end[0], + endY = end[1]; + + var dxc = x! - startX!; + var dyc = y! - startY!; + var dxl = endX! - startX; + var dyl = endY! - startY; + var cross = dxc * dyl - dyc * dxl; + + if (cross != 0){ return false;} + else if ((dxl).abs() >= (dyl).abs()) +{ return dxl > 0 ? startX <= x && x <= endX : endX <= x && x <= startX; +} else {return dyl > 0 ? startY <= y && y <= endY : endY <= y && y <= startY;} +} + +/** + * import { Position } from "geojson"; +import { feature } from "@turf/helpers"; +import { getCoords, getType } from "@turf/invariant"; + +// To-Do => Improve Typescript GeoJSON handling + +/** + * Removes redundant coordinates from any GeoJSON Geometry. + * + * @name cleanCoords + * @param {Geometry|Feature} geojson Feature or Geometry + * @param {Object} [options={}] Optional parameters + * @param {boolean} [options.mutate=false] allows GeoJSON input to be mutated + * @returns {Geometry|Feature} the cleaned input Feature/Geometry + * @example + * var line = turf.lineString([[0, 0], [0, 2], [0, 5], [0, 8], [0, 8], [0, 10]]); + * var multiPoint = turf.multiPoint([[0, 0], [0, 0], [2, 2]]); + * + * turf.cleanCoords(line).geometry.coordinates; + * //= [[0, 0], [0, 10]] + * + * turf.cleanCoords(multiPoint).geometry.coordinates; + * //= [[0, 0], [2, 2]] + */ + cleanCoords( + geojson: any, + options: { + mutate?: boolean; + } = {} +) { + // Backwards compatible with v4.0 + var mutate = typeof options == "object" ? options.mutate : options; + if (!geojson) throw new Error("geojson is required"); + var type = getType(geojson); + + // Store new "clean" points in this Array + var newCoords = []; + + switch (type) { + case "LineString": + newCoords = cleanLine(geojson, type); + break; + case "MultiLineString": + case "Polygon": + getCoords(geojson).forEach(function (line) { + newCoords.push(cleanLine(line, type)); + }); + break; + case "MultiPolygon": + getCoords(geojson).forEach(function (polygons: any) { + var polyPoints: Position[] = []; + polygons.forEach(function (ring: Position[]) { + polyPoints.push(cleanLine(ring, type)); + }); + newCoords.push(polyPoints); + }); + break; + case "Point": + return geojson; + case "MultiPoint": + var existing: Record = {}; + getCoords(geojson).forEach(function (coord: any) { + var key = coord.join("-"); + if (!Object.prototype.hasOwnProperty.call(existing, key)) { + newCoords.push(coord); + existing[key] = true; + } + }); + break; + default: + throw new Error(type + " geometry not supported"); + } + + // Support input mutation + if (geojson.coordinates) { + if (mutate == true) { + geojson.coordinates = newCoords; + return geojson; + } + return { type: type, coordinates: newCoords }; + } else { + if (mutate == true) { + geojson.geometry.coordinates = newCoords; + return geojson; + } + return feature({ type: type, coordinates: newCoords }, geojson.properties, { + bbox: geojson.bbox, + id: geojson.id, + }); + } +} + +/** + * Clean Coords + * + * @private + * @param {Array|LineString} line Line + * @param {string} type Type of geometry + * @returns {Array} Cleaned coordinates + */ +function cleanLine(line: Position[], type: string) { + var points = getCoords(line); + // handle "clean" segment + if (points.length == 2 && !equals(points[0], points[1])) return points; + + var newPoints = []; + var secondToLast = points.length - 1; + var newPointsLength = newPoints.length; + + newPoints.push(points[0]); + for (var i = 1; i < secondToLast; i++) { + var prevAddedPoint = newPoints[newPoints.length - 1]; + if ( + points[i][0] == prevAddedPoint[0] && + points[i][1] == prevAddedPoint[1] + ) + continue; + else { + newPoints.push(points[i]); + newPointsLength = newPoints.length; + if (newPointsLength > 2) { + if ( + isPointOnLineSegment( + newPoints[newPointsLength - 3], + newPoints[newPointsLength - 1], + newPoints[newPointsLength - 2] + ) + ) + newPoints.splice(newPoints.length - 2, 1); + } + } + } + newPoints.push(points[points.length - 1]); + newPointsLength = newPoints.length; + + // (Multi)Polygons must have at least 4 points, but a closed LineString with only 3 points is acceptable + if ( + (type == "Polygon" || type == "MultiPolygon") && + equals(points[0], points[points.length - 1]) && + newPointsLength < 4 + ) { + throw new Error("invalid polygon"); + } + + if ( + isPointOnLineSegment( + newPoints[newPointsLength - 3], + newPoints[newPointsLength - 1], + newPoints[newPointsLength - 2] + ) + ) + newPoints.splice(newPoints.length - 2, 1); + + return newPoints; +} + +/** + * Compares two points and returns if they are equals + * + * @private + * @param {Position} pt1 point + * @param {Position} pt2 point + * @returns {boolean} true if they are equals + */ +function equals(pt1: Position, pt2: Position) { + return pt1[0] == pt2[0] && pt1[1] == pt2[1]; +} + +/** + * Returns if `point` is on the segment between `start` and `end`. + * Borrowed from `@turf/boolean-point-on-line` to speed up the evaluation (instead of using the module as dependency) + * + * @private + * @param {Position} start coord pair of start of line + * @param {Position} end coord pair of end of line + * @param {Position} point coord pair of point to check + * @returns {boolean} true/false + */ +function isPointOnLineSegment(start: Position, end: Position, point: Position) { + var x = point[0], + y = point[1]; + var startX = start[0], + startY = start[1]; + var endX = end[0], + endY = end[1]; + + var dxc = x - startX; + var dyc = y - startY; + var dxl = endX - startX; + var dyl = endY - startY; + var cross = dxc * dyl - dyc * dxl; + + if (cross !== 0) return false; + else if (Math.abs(dxl) >= Math.abs(dyl)) + return dxl > 0 ? startX <= x && x <= endX : endX <= x && x <= startX; + else return dyl > 0 ? startY <= y && y <= endY : endY <= y && y <= startY; +} + +export default cleanCoords; + */ \ No newline at end of file From 6efe633002036ef63f2e3ce566217c8074374bd0 Mon Sep 17 00:00:00 2001 From: armantorkzaban Date: Thu, 9 Jun 2022 16:49:48 +0200 Subject: [PATCH 17/82] contains etc. --- lib/src/booleans/boolean_contains.dart | 49 +++++++++---------- .../booleans/boolean_point_in_polygon.dart | 3 +- 2 files changed, 25 insertions(+), 27 deletions(-) diff --git a/lib/src/booleans/boolean_contains.dart b/lib/src/booleans/boolean_contains.dart index e8d5f468..b143c4f8 100644 --- a/lib/src/booleans/boolean_contains.dart +++ b/lib/src/booleans/boolean_contains.dart @@ -62,7 +62,7 @@ booleanContains(GeoJSONObject feature1, GeoJSONObject feature2) { case Polygon: switch (type2) { case Point: - return booleanPointInPolygon(geom2, geom1, {ignoreBoundary: true}); + return booleanPointInPolygon(geom2, geom1, ignoreBoundary: true); case LineString: return isLineInPoly(geom1, geom2); case Polygon: @@ -109,10 +109,11 @@ isMultiPointInMultiPoint(MultiPoint multiPoint1, MultiPoint multiPoint2) { isMultiPointOnLine(LineString lineString, MultiPoint multiPoint) { var haveFoundInteriorPoint = false; for (var coord in multiPoint.coordinates) { - if (isPointOnLine(coord, lineString, {ignoreEndVertices: true})) { + if (isPointOnLine(lineString, Point(coordinates: coord), + ignoreEndVertices: true)) { haveFoundInteriorPoint = true; } - if (!isPointOnLine(coord, lineString)) { + if (!isPointOnLine(lineString, Point(coordinates: coord))) { return false; } } @@ -124,7 +125,8 @@ isMultiPointOnLine(LineString lineString, MultiPoint multiPoint) { isMultiPointInPoly(Polygon polygon, MultiPoint multiPoint) { for (var coord in multiPoint.coordinates) { - if (!booleanPointInPolygon(coord, polygon, {ignoreBoundary: true})) { + if (!booleanPointInPolygon(coord, Feature(geometry: polygon), + ignoreBoundary: true)) { return false; } } @@ -135,19 +137,17 @@ isLineOnLine(LineString lineString1, LineString lineString2) { var haveFoundInteriorPoint = false; for (var coords in lineString2.coordinates) { if (isPointOnLine( - {type: Point, coordinates: coords}, - lineString1, - { - ignoreEndVertices: true, - })) { + lineString1, + Point(coordinates: coords), + ignoreEndVertices: true, + )) { haveFoundInteriorPoint = true; } if (!isPointOnLine( - {type: Point, coordinates: coords}, - lineString1, - { - ignoreEndVertices: false, - })) { + lineString1, + Point(coordinates: coords), + ignoreEndVertices: false, + )) { return false; } } @@ -167,11 +167,10 @@ isLineInPoly(Polygon polygon, LineString linestring) { var midPoint = getMidpoint(linestring.coordinates[i], linestring.coordinates[i + 1]); if (booleanPointInPolygon( - {type: Point, coordinates: midPoint}, - polygon, - { - ignoreBoundary: true, - })) { + Position.of(midPoint), + Feature(geometry: polygon), + ignoreBoundary: true, + )) { output = true; break; } @@ -188,7 +187,7 @@ isLineInPoly(Polygon polygon, LineString linestring) { * @param {Geometry|Feature} feature2 Polygon2 * @returns {boolean} true/false */ -isPolyInPoly(GeoJSONObjectType feature1, GeoJSONObjectType feature2) { +isPolyInPoly(GeoJSONObject feature1, GeoJSONObjectType feature2) { // Handle Nulls if (feature1.runtimeType == Feature && (feature1 as Feature).geometry == null) { @@ -205,10 +204,10 @@ isPolyInPoly(GeoJSONObjectType feature1, GeoJSONObjectType feature2) { return false; } - var coords = getGeom(feature2).coordinates; + var coords = (feature2 as Feature).geometry!.coordinates; for (var ring in coords) { for (var coord in ring) { - if (!booleanPointInPolygon(coord, feature1)) { + if (!booleanPointInPolygon(coord, feature1 as Feature)) { return false; } } @@ -240,12 +239,12 @@ doBBoxOverlap(BBox bbox1, BBox bbox2) { * @param {Position} pair2 point [x,y] * @returns {boolean} true/false if coord pairs match */ -compareCoords(List pair1, List pair2) { +compareCoords(Position pair1, Position pair2) { return pair1[0] == pair2[0] && pair1[1] == pair2[1]; } -getMidpoint(List pair1, List pair2) { - return [(pair1[0] + pair2[0]) / 2, (pair1[1] + pair2[1]) / 2]; +getMidpoint(Position pair1, Position pair2) { + return [(pair1[0]! + pair2[0]!) / 2, (pair1[1]! + pair2[1]!) / 2]; } /* diff --git a/lib/src/booleans/boolean_point_in_polygon.dart b/lib/src/booleans/boolean_point_in_polygon.dart index 49b59988..128d6775 100644 --- a/lib/src/booleans/boolean_point_in_polygon.dart +++ b/lib/src/booleans/boolean_point_in_polygon.dart @@ -28,8 +28,7 @@ import '../invariant.dart'; * turf.booleanPointInPolygon(pt, poly); * //= true */ -booleanPointInPolygon(Position point, GeometryObject polygon, - {bool? ignoreBoundary}) { +booleanPointInPolygon(Position point, Feature polygon, {bool? ignoreBoundary}) { var pt = getCoord(point); var geom = getGeom(polygon); var type = geom.type; From 5f91040b82bc9ab665194c0409f10397adda16a9 Mon Sep 17 00:00:00 2001 From: armantorkzaban Date: Thu, 9 Jun 2022 17:10:25 +0200 Subject: [PATCH 18/82] touches --- lib/src/booleans/boolean_contains.dart | 5 +- lib/src/booleans/boolean_crosses.dart | 12 +- lib/src/booleans/boolean_equal.dart | 1 + lib/src/booleans/boolean_overlap.dart | 70 ++-- .../booleans/boolean_point_in_polygon.dart | 3 +- lib/src/booleans/boolean_touches.dart | 66 ++-- lib/src/line_overlap.dart | 324 ++++++++++++++++++ lib/src/polygon_to_line.dart | 206 +++++++++++ 8 files changed, 601 insertions(+), 86 deletions(-) create mode 100644 lib/src/line_overlap.dart create mode 100644 lib/src/polygon_to_line.dart diff --git a/lib/src/booleans/boolean_contains.dart b/lib/src/booleans/boolean_contains.dart index b143c4f8..e39b9228 100644 --- a/lib/src/booleans/boolean_contains.dart +++ b/lib/src/booleans/boolean_contains.dart @@ -125,8 +125,7 @@ isMultiPointOnLine(LineString lineString, MultiPoint multiPoint) { isMultiPointInPoly(Polygon polygon, MultiPoint multiPoint) { for (var coord in multiPoint.coordinates) { - if (!booleanPointInPolygon(coord, Feature(geometry: polygon), - ignoreBoundary: true)) { + if (!booleanPointInPolygon(coord, polygon, ignoreBoundary: true)) { return false; } } @@ -168,7 +167,7 @@ isLineInPoly(Polygon polygon, LineString linestring) { getMidpoint(linestring.coordinates[i], linestring.coordinates[i + 1]); if (booleanPointInPolygon( Position.of(midPoint), - Feature(geometry: polygon), + polygon, ignoreBoundary: true, )) { output = true; diff --git a/lib/src/booleans/boolean_crosses.dart b/lib/src/booleans/boolean_crosses.dart index 9e42a97a..2795bffe 100644 --- a/lib/src/booleans/boolean_crosses.dart +++ b/lib/src/booleans/boolean_crosses.dart @@ -1,5 +1,6 @@ import '../../helpers.dart'; import '../invariant.dart'; +import '../line_intersect.dart'; import 'boolean_point_in_polygon.dart'; /** * Boolean-Crosses returns True if the intersection results in a geometry whose dimension is one less than @@ -88,9 +89,9 @@ doMultiPointAndLineStringCross(MultiPoint multiPoint, LineString lineString) { return foundIntPoint && foundExtPoint; } -doLineStringsCross(LineString lineString, LineString lineString) { +doLineStringsCross(LineString lineString1, LineString lineString2) { var doLinesIntersect = lineIntersect(lineString1, lineString2); - if (doLinesIntersect.features.length > 0) { + if (doLinesIntersect.features.isNotEmpty) { for (var i = 0; i < lineString1.coordinates.length - 1; i++) { for (var i2 = 0; i2 < lineString2.coordinates.length - 1; i2++) { var incEndVertices = true; @@ -112,8 +113,8 @@ doLineStringsCross(LineString lineString, LineString lineString) { doLineStringAndPolygonCross(LineString lineString, Polygon polygon) { const LineString line = polygonToLine(polygon); - const doLinesIntersect = lineIntersect(lineString, line); - if (doLinesIntersect.features.length > 0) { + var doLinesIntersect = lineIntersect(lineString, line); + if (doLinesIntersect.features.isNotEmpty) { return true; } return false; @@ -124,8 +125,7 @@ doesMultiPointCrossPoly(MultiPoint multiPoint, Polygon polygon) { var foundExtPoint = false; var pointLength = multiPoint.coordinates.length; for (var i = 0; i < pointLength && (!foundIntPoint || !foundExtPoint); i++) { - if (booleanPointInPolygon( - Point(coordinates: multiPoint.coordinates[i]), polygon)) { + if (booleanPointInPolygon(multiPoint.coordinates[i], polygon)) { foundIntPoint = true; } else { foundExtPoint = true; diff --git a/lib/src/booleans/boolean_equal.dart b/lib/src/booleans/boolean_equal.dart index 329c7468..12a81ab0 100644 --- a/lib/src/booleans/boolean_equal.dart +++ b/lib/src/booleans/boolean_equal.dart @@ -1,4 +1,5 @@ import '../../helpers.dart'; +import '../clean_coords.dart'; import '../invariant.dart'; /** diff --git a/lib/src/booleans/boolean_overlap.dart b/lib/src/booleans/boolean_overlap.dart index ab4862ad..7ffa0c25 100644 --- a/lib/src/booleans/boolean_overlap.dart +++ b/lib/src/booleans/boolean_overlap.dart @@ -1,9 +1,7 @@ - import '../../helpers.dart'; import '../../line_segment.dart'; import '../invariant.dart'; import '../line_intersect.dart'; -GeojsonEquality from "geojson-equality"; /** * Compares two geometries of the same dimension and returns true if their intersection set results in a geometry @@ -26,30 +24,25 @@ GeojsonEquality from "geojson-equality"; * turf.booleanOverlap(poly2, poly3) * //=false */ - booleanOverlap( - GeometryObject feature1, - GeometryObject feature2 -) { +booleanOverlap(GeometryObject feature1, GeometryObject feature2) { var geom1 = getGeom(feature1); var geom2 = getGeom(feature2); var type1 = geom1.type; var type2 = geom2.type; - if ( - (type1 == MultiPoint && type2 != MultiPoint) || - ((type1 == LineString || type1 == MultiLineString) && - type2 != LineString && - type2 != MultiLineString) || - ((type1 == Polygon || type1 == MultiPolygon) && - type2 != Polygon && - type2 != MultiPolygon) - ) { + if ((type1 == MultiPoint && type2 != MultiPoint) || + ((type1 == LineString || type1 == MultiLineString) && + type2 != LineString && + type2 != MultiLineString) || + ((type1 == Polygon || type1 == MultiPolygon) && + type2 != Polygon && + type2 != MultiPolygon)) { throw Exception("features must be of the same type"); } if (type1 == Point) throw Exception("Point geometry not supported"); // features must be not equal - const equality = GeojsonEquality({ precision: 6 }); + const equality = GeojsonEquality({precision: 6}); if (equality.compare(feature1, feature2)) return false; var overlap = 0; @@ -69,15 +62,20 @@ GeojsonEquality from "geojson-equality"; case LineString: case MultiLineString: - segmentEach(feature1, (segment1, - featureIndex, - multiFeatureIndex, - geometryIndex, - segmentIndex,) { - segmentEach(feature2, (segment2, featureIndex, - multiFeatureIndex, - geometryIndex, - segmentIndex,) { + segmentEach(feature1, ( + segment1, + featureIndex, + multiFeatureIndex, + geometryIndex, + segmentIndex, + ) { + segmentEach(feature2, ( + segment2, + featureIndex, + multiFeatureIndex, + geometryIndex, + segmentIndex, + ) { if (lineOverlap(segment1, segment2).features.length) overlap++; }); }); @@ -85,14 +83,20 @@ GeojsonEquality from "geojson-equality"; case Polygon: case MultiPolygon: - segmentEach(feature1, (segment1, featureIndex, - multiFeatureIndex, - geometryIndex, - segmentIndex,) { - segmentEach(feature2, (segment2, featureIndex, - multiFeatureIndex, - geometryIndex, - segmentIndex,) { + segmentEach(feature1, ( + segment1, + featureIndex, + multiFeatureIndex, + geometryIndex, + segmentIndex, + ) { + segmentEach(feature2, ( + segment2, + featureIndex, + multiFeatureIndex, + geometryIndex, + segmentIndex, + ) { if (lineIntersect(segment1, segment2).features.isNotEmpty) overlap++; }); }); diff --git a/lib/src/booleans/boolean_point_in_polygon.dart b/lib/src/booleans/boolean_point_in_polygon.dart index 128d6775..b9345a95 100644 --- a/lib/src/booleans/boolean_point_in_polygon.dart +++ b/lib/src/booleans/boolean_point_in_polygon.dart @@ -28,7 +28,8 @@ import '../invariant.dart'; * turf.booleanPointInPolygon(pt, poly); * //= true */ -booleanPointInPolygon(Position point, Feature polygon, {bool? ignoreBoundary}) { +booleanPointInPolygon(Position point, GeoJSONObject polygon, + {bool? ignoreBoundary}) { var pt = getCoord(point); var geom = getGeom(polygon); var type = geom.type; diff --git a/lib/src/booleans/boolean_touches.dart b/lib/src/booleans/boolean_touches.dart index e50bda04..3a6f8986 100644 --- a/lib/src/booleans/boolean_touches.dart +++ b/lib/src/booleans/boolean_touches.dart @@ -88,8 +88,9 @@ bool booleanTouches(GeoJSONObject feature1, GeoJSONObject feature2) { for (var ii = 0; ii < geom2.coordinates.length; ii++) { if (!foundTouchingPoint) { if (isPointOnLineEnd(Point(coordinates: geom1.coordinates[i]), - LineString(coordinates: geom2.coordinates[ii]))) + LineString(coordinates: geom2.coordinates[ii]))) { foundTouchingPoint = true; + } } if (booleanPointOnLine(Point(coordinates: geom1.coordinates[i]), LineString(coordinates: geom2.coordinates[ii]), @@ -108,8 +109,7 @@ bool booleanTouches(GeoJSONObject feature1, GeoJSONObject feature2) { foundTouchingPoint = true; } } - if (booleanPointInPolygon( - Point(coordinates: geom1.coordinates[i]), geom2, + if (booleanPointInPolygon(geom1.coordinates[i], geom2, ignoreBoundary: true)) { return false; } @@ -128,8 +128,7 @@ bool booleanTouches(GeoJSONObject feature1, GeoJSONObject feature2) { foundTouchingPoint = true; } } - if (booleanPointInPolygon( - Point(coordinates: geom1.coordinates[i]), + if (booleanPointInPolygon(geom1.coordinates[i], Polygon(coordinates: geom2.coordinates[ii]), ignoreBoundary: true)) { return false; @@ -148,13 +147,11 @@ bool booleanTouches(GeoJSONObject feature1, GeoJSONObject feature2) { var foundTouchingPoint = false; for (var i = 0; i < geom2.coordinates.length; i++) { if (!foundTouchingPoint) { - if (isPointOnLineEnd( - Point(coordinates: geom2.coordinates[i]), geom1)) { + if (isPointOnLineEnd(geom2.coordinates[i], geom1)) { foundTouchingPoint = true; } } - if (booleanPointOnLine( - Point(coordinates: geom2.coordinates[i]), geom1, + if (booleanPointOnLine(geom2.coordinates[i], geom1, ignoreEndVertices: true)) { return false; } @@ -212,8 +209,7 @@ bool booleanTouches(GeoJSONObject feature1, GeoJSONObject feature2) { foundTouchingPoint = true; } } - if (booleanPointInPolygon( - Point(coordinates: geom1.coordinates[i]), geom2, + if (booleanPointInPolygon(geom1.coordinates[i], geom2, ignoreBoundary: true)) { return false; } @@ -233,8 +229,7 @@ bool booleanTouches(GeoJSONObject feature1, GeoJSONObject feature2) { } } } - if (booleanPointInPolygon( - Point(coordinates: geom1.coordinates[i]), geom2, + if (booleanPointInPolygon(geom1.coordinates[i], geom2, ignoreBoundary: true)) { return false; } @@ -336,8 +331,7 @@ bool booleanTouches(GeoJSONObject feature1, GeoJSONObject feature2) { foundTouchingPoint = true; } } - if (booleanPointInPolygon( - Point(coordinates: geom1.coordinates[i][ii]), geom2, + if (booleanPointInPolygon(geom1.coordinates[i][ii], geom2, ignoreBoundary: true)) { return false; } @@ -360,8 +354,7 @@ bool booleanTouches(GeoJSONObject feature1, GeoJSONObject feature2) { foundTouchingPoint = true; } } - if (booleanPointInPolygon( - Point(coordinates: geom1.coordinates[ii][iii]), + if (booleanPointInPolygon(geom1.coordinates[ii][iii], Polygon(coordinates: [geom2.coordinates[0][i]]), ignoreBoundary: true)) { return false; @@ -390,13 +383,12 @@ bool booleanTouches(GeoJSONObject feature1, GeoJSONObject feature2) { var foundTouchingPoint = false; for (var i = 0; i < geom2.coordinates.length; i++) { if (!foundTouchingPoint) { - if (booleanPointOnLine(Point(coordinates: geom2.coordinates[i]), + if (booleanPointOnLine(geom2.coordinates[i], LineString(coordinates: geom1.coordinates[0]))) { foundTouchingPoint = true; } } - if (booleanPointInPolygon( - Point(coordinates: geom2.coordinates[i]), geom1, + if (booleanPointInPolygon(geom2.coordinates[i], geom1, ignoreBoundary: true)) return false; } return foundTouchingPoint; @@ -404,13 +396,12 @@ bool booleanTouches(GeoJSONObject feature1, GeoJSONObject feature2) { var foundTouchingPoint = false; for (var i = 0; i < geom2.coordinates.length; i++) { if (!foundTouchingPoint) { - if (booleanPointOnLine(Point(coordinates: geom2.coordinates[i]), + if (booleanPointOnLine(geom2.coordinates[i], LineString(coordinates: geom1.coordinates[0]))) { foundTouchingPoint = true; } } - if (booleanPointInPolygon( - Point(coordinates: geom2.coordinates[i]), geom1, + if (booleanPointInPolygon(geom2.coordinates[i], geom1, ignoreBoundary: true)) { return false; } @@ -421,14 +412,12 @@ bool booleanTouches(GeoJSONObject feature1, GeoJSONObject feature2) { for (var i = 0; i < geom2.coordinates.length; i++) { for (var ii = 0; ii < geom2.coordinates[i].length; ii++) { if (!foundTouchingPoint) { - if (booleanPointOnLine( - Point(coordinates: geom2.coordinates[i][ii]), + if (booleanPointOnLine(geom2.coordinates[i][ii], LineString(coordinates: geom1.coordinates[0]))) { foundTouchingPoint = true; } } - if (booleanPointInPolygon( - Point(coordinates: geom2.coordinates[i][ii]), geom1, + if (booleanPointInPolygon(geom2.coordinates[i][ii], geom1, ignoreBoundary: true)) { return false; } @@ -445,8 +434,7 @@ bool booleanTouches(GeoJSONObject feature1, GeoJSONObject feature2) { foundTouchingPoint = true; } } - if (booleanPointInPolygon( - Point(coordinates: geom1.coordinates[0][i]), geom2, + if (booleanPointInPolygon(geom1.coordinates[0][i], geom2, ignoreBoundary: true)) { return false; } @@ -463,8 +451,7 @@ bool booleanTouches(GeoJSONObject feature1, GeoJSONObject feature2) { foundTouchingPoint = true; } } - if (booleanPointInPolygon( - Point(coordinates: geom1.coordinates[0][ii]), + if (booleanPointInPolygon(geom1.coordinates[0][ii], Polygon(coordinates: geom2.coordinates[0][i]), ignoreBoundary: true)) { return false; @@ -499,8 +486,7 @@ bool booleanTouches(GeoJSONObject feature1, GeoJSONObject feature2) { foundTouchingPoint = true; } } - if (booleanPointInPolygon( - Point(coordinates: geom2.coordinates[ii]), + if (booleanPointInPolygon(geom2.coordinates[ii], Polygon(coordinates: geom1.coordinates[0][i]), ignoreBoundary: true)) { return false; @@ -519,8 +505,7 @@ bool booleanTouches(GeoJSONObject feature1, GeoJSONObject feature2) { foundTouchingPoint = true; } } - if (booleanPointInPolygon( - Point(coordinates: geom2.coordinates[ii]), + if (booleanPointInPolygon(geom2.coordinates[ii], Polygon(coordinates: geom1.coordinates[0][i]), ignoreBoundary: true)) { return false; @@ -544,8 +529,7 @@ bool booleanTouches(GeoJSONObject feature1, GeoJSONObject feature2) { foundTouchingPoint = true; } } - if (booleanPointInPolygon( - Point(coordinates: geom2.coordinates[ii][iii]), + if (booleanPointInPolygon(geom2.coordinates[ii][iii], Polygon(coordinates: [geom1.coordinates[i][0]]), ignoreBoundary: true)) { return false; @@ -566,8 +550,7 @@ bool booleanTouches(GeoJSONObject feature1, GeoJSONObject feature2) { foundTouchingPoint = true; } } - if (booleanPointInPolygon( - Point(coordinates: geom1.coordinates[0][i][ii]), geom2, + if (booleanPointInPolygon(geom1.coordinates[0][i][ii], geom2, ignoreBoundary: true)) { return false; } @@ -590,10 +573,7 @@ bool booleanTouches(GeoJSONObject feature1, GeoJSONObject feature2) { foundTouchingPoint = true; } } - if (booleanPointInPolygon( - Point( - coordinates: geom1.coordinates[0][i][iii], - ), + if (booleanPointInPolygon(geom1.coordinates[0][i][iii], Polygon(coordinates: geom2.coordinates[0][ii]), ignoreBoundary: true)) { return false; diff --git a/lib/src/line_overlap.dart b/lib/src/line_overlap.dart new file mode 100644 index 00000000..75b8d6b1 --- /dev/null +++ b/lib/src/line_overlap.dart @@ -0,0 +1,324 @@ +/** + * Takes any LineString or Polygon and returns the overlapping lines between both features. + * + * @name lineOverlap + * @param {Geometry|Feature} line1 any LineString or Polygon + * @param {Geometry|Feature} line2 any LineString or Polygon + * @param {Object} [options={}] Optional parameters + * @param {number} [options.tolerance=0] Tolerance distance to match overlapping line segments (in kilometers) + * @returns {FeatureCollection} lines(s) that are overlapping between both features + * @example + * var line1 = turf.lineString([[115, -35], [125, -30], [135, -30], [145, -35]]); + * var line2 = turf.lineString([[115, -25], [125, -30], [135, -30], [145, -25]]); + * + * var overlapping = turf.lineOverlap(line1, line2); + * + * //addToMap + * var addToMap = [line1, line2, overlapping] + */ + lineOverlap< + G1 extends LineString | MultiLineString | Polygon | MultiPolygon, + G2 extends LineString | MultiLineString | Polygon | MultiPolygon +>( + line1: Feature | G1, + line2: Feature | G2, + options: { tolerance?: number } = {} +): FeatureCollection { + // Optional parameters + + + options = options || {}; + if (!isObject(options)) throw new Error("options is invalid"); + var tolerance = options.tolerance || 0; + + + // Containers + var features: Feature[] = []; + + // Create Spatial Index + var tree = rbush(); + + // To-Do -- HACK way to support typescript + const line: any = lineSegment(line1); + tree.load(line); + var overlapSegment: Feature | undefined; + let additionalSegments: Feature[] = []; + + // Line Intersection + + // Iterate over line segments + segmentEach(line2, function (segment) { + var doesOverlaps = false; + + if (!segment) { + return; + } + + // Iterate over each segments which falls within the same bounds + featureEach(tree.search(segment), function (match) { + if (doesOverlaps === false) { + var coordsSegment = getCoords(segment).sort(); + var coordsMatch: any = getCoords(match).sort(); + + // Segment overlaps feature + if (equal(coordsSegment, coordsMatch)) { + doesOverlaps = true; + // Overlaps already exists - only append last coordinate of segment + if (overlapSegment) { + overlapSegment = + concatSegment(overlapSegment, segment) || overlapSegment; + } else overlapSegment = segment; + // Match segments which don't share nodes (Issue #901) + } else if ( + tolerance === 0 + ? booleanPointOnLine(coordsSegment[0], match) && + booleanPointOnLine(coordsSegment[1], match) + : nearestPointOnLine(match, coordsSegment[0]).properties.dist! <= + tolerance && + nearestPointOnLine(match, coordsSegment[1]).properties.dist! <= + tolerance + ) { + doesOverlaps = true; + if (overlapSegment) { + overlapSegment = + concatSegment(overlapSegment, segment) || overlapSegment; + } else overlapSegment = segment; + } else if ( + tolerance === 0 + ? booleanPointOnLine(coordsMatch[0], segment) && + booleanPointOnLine(coordsMatch[1], segment) + : nearestPointOnLine(segment, coordsMatch[0]).properties.dist! <= + tolerance && + nearestPointOnLine(segment, coordsMatch[1]).properties.dist! <= + tolerance + ) { + // Do not define (doesOverlap = true) since more matches can occur within the same segment + // doesOverlaps = true; + if (overlapSegment) { + const combinedSegment = concatSegment(overlapSegment, match); + if (combinedSegment) { + overlapSegment = combinedSegment; + } else { + additionalSegments.push(match); + } + } else overlapSegment = match; + } + } + }); + + // Segment doesn't overlap - add overlaps to results & reset + if (doesOverlaps === false && overlapSegment) { + features.push(overlapSegment); + if (additionalSegments.length) { + features = features.concat(additionalSegments); + additionalSegments = []; + } + overlapSegment = undefined; + } + }); + // Add last segment if exists + if (overlapSegment) features.push(overlapSegment); + + return featureCollection(features); +} + +/** + * Concat Segment + * + * @private + * @param {Feature} line LineString + * @param {Feature} segment 2-vertex LineString + * @returns {Feature} concat linestring + */ +function concatSegment( + line: Feature, + segment: Feature +) { + var coords = getCoords(segment); + var lineCoords = getCoords(line); + var start = lineCoords[0]; + var end = lineCoords[lineCoords.length - 1]; + var geom = line.geometry.coordinates; + + if (equal(coords[0], start)) geom.unshift(coords[1]); + else if (equal(coords[0], end)) geom.push(coords[1]); + else if (equal(coords[1], start)) geom.unshift(coords[0]); + else if (equal(coords[1], end)) geom.push(coords[0]); + else return; // If the overlap leaves the segment unchanged, return undefined so that this can be identified. + + // Otherwise return the mutated line. + return line; +} + +export default lineOverlap; + +/** + * import rbush from "@turf/geojson-rbush"; +import lineSegment from "@turf/line-segment"; +import nearestPointOnLine from "@turf/nearest-point-on-line"; +import booleanPointOnLine from "@turf/boolean-point-on-line"; +import { getCoords } from "@turf/invariant"; +import { featureEach, segmentEach } from "@turf/meta"; +import { + FeatureCollection, + Feature, + LineString, + MultiLineString, + Polygon, + MultiPolygon, + GeoJsonProperties, +} from "geojson"; +import { featureCollection, isObject } from "@turf/helpers"; +import equal from "deep-equal"; + +/** + * Takes any LineString or Polygon and returns the overlapping lines between both features. + * + * @name lineOverlap + * @param {Geometry|Feature} line1 any LineString or Polygon + * @param {Geometry|Feature} line2 any LineString or Polygon + * @param {Object} [options={}] Optional parameters + * @param {number} [options.tolerance=0] Tolerance distance to match overlapping line segments (in kilometers) + * @returns {FeatureCollection} lines(s) that are overlapping between both features + * @example + * var line1 = turf.lineString([[115, -35], [125, -30], [135, -30], [145, -35]]); + * var line2 = turf.lineString([[115, -25], [125, -30], [135, -30], [145, -25]]); + * + * var overlapping = turf.lineOverlap(line1, line2); + * + * //addToMap + * var addToMap = [line1, line2, overlapping] + */ +function lineOverlap< + G1 extends LineString | MultiLineString | Polygon | MultiPolygon, + G2 extends LineString | MultiLineString | Polygon | MultiPolygon +>( + line1: Feature | G1, + line2: Feature | G2, + options: { tolerance?: number } = {} +): FeatureCollection { + // Optional parameters + options = options || {}; + if (!isObject(options)) throw new Error("options is invalid"); + var tolerance = options.tolerance || 0; + + // Containers + var features: Feature[] = []; + + // Create Spatial Index + var tree = rbush(); + + // To-Do -- HACK way to support typescript + const line: any = lineSegment(line1); + tree.load(line); + var overlapSegment: Feature | undefined; + let additionalSegments: Feature[] = []; + + // Line Intersection + + // Iterate over line segments + segmentEach(line2, function (segment) { + var doesOverlaps = false; + + if (!segment) { + return; + } + + // Iterate over each segments which falls within the same bounds + featureEach(tree.search(segment), function (match) { + if (doesOverlaps === false) { + var coordsSegment = getCoords(segment).sort(); + var coordsMatch: any = getCoords(match).sort(); + + // Segment overlaps feature + if (equal(coordsSegment, coordsMatch)) { + doesOverlaps = true; + // Overlaps already exists - only append last coordinate of segment + if (overlapSegment) { + overlapSegment = + concatSegment(overlapSegment, segment) || overlapSegment; + } else overlapSegment = segment; + // Match segments which don't share nodes (Issue #901) + } else if ( + tolerance === 0 + ? booleanPointOnLine(coordsSegment[0], match) && + booleanPointOnLine(coordsSegment[1], match) + : nearestPointOnLine(match, coordsSegment[0]).properties.dist! <= + tolerance && + nearestPointOnLine(match, coordsSegment[1]).properties.dist! <= + tolerance + ) { + doesOverlaps = true; + if (overlapSegment) { + overlapSegment = + concatSegment(overlapSegment, segment) || overlapSegment; + } else overlapSegment = segment; + } else if ( + tolerance === 0 + ? booleanPointOnLine(coordsMatch[0], segment) && + booleanPointOnLine(coordsMatch[1], segment) + : nearestPointOnLine(segment, coordsMatch[0]).properties.dist! <= + tolerance && + nearestPointOnLine(segment, coordsMatch[1]).properties.dist! <= + tolerance + ) { + // Do not define (doesOverlap = true) since more matches can occur within the same segment + // doesOverlaps = true; + if (overlapSegment) { + const combinedSegment = concatSegment(overlapSegment, match); + if (combinedSegment) { + overlapSegment = combinedSegment; + } else { + additionalSegments.push(match); + } + } else overlapSegment = match; + } + } + }); + + // Segment doesn't overlap - add overlaps to results & reset + if (doesOverlaps === false && overlapSegment) { + features.push(overlapSegment); + if (additionalSegments.length) { + features = features.concat(additionalSegments); + additionalSegments = []; + } + overlapSegment = undefined; + } + }); + // Add last segment if exists + if (overlapSegment) features.push(overlapSegment); + + return featureCollection(features); +} + +/** + * Concat Segment + * + * @private + * @param {Feature} line LineString + * @param {Feature} segment 2-vertex LineString + * @returns {Feature} concat linestring + */ +function concatSegment( + line: Feature, + segment: Feature +) { + var coords = getCoords(segment); + var lineCoords = getCoords(line); + var start = lineCoords[0]; + var end = lineCoords[lineCoords.length - 1]; + var geom = line.geometry.coordinates; + + if (equal(coords[0], start)) geom.unshift(coords[1]); + else if (equal(coords[0], end)) geom.push(coords[1]); + else if (equal(coords[1], start)) geom.unshift(coords[0]); + else if (equal(coords[1], end)) geom.push(coords[0]); + else return; // If the overlap leaves the segment unchanged, return undefined so that this can be identified. + + // Otherwise return the mutated line. + return line; +} + +export default lineOverlap; + */ \ No newline at end of file diff --git a/lib/src/polygon_to_line.dart b/lib/src/polygon_to_line.dart new file mode 100644 index 00000000..fd5e554d --- /dev/null +++ b/lib/src/polygon_to_line.dart @@ -0,0 +1,206 @@ + +/** + * Converts a {@link Polygon} to {@link LineString|(Multi)LineString} or {@link MultiPolygon} to a + * {@link FeatureCollection} of {@link LineString|(Multi)LineString}. + * + * @name polygonToLine + * @param {Feature} poly Feature to convert + * @param {Object} [options={}] Optional parameters + * @param {Object} [options.properties={}] translates GeoJSON properties to Feature + * @returns {FeatureCollection|Feature} converted (Multi)Polygon to (Multi)LineString + * @example + * var poly = turf.polygon([[[125, -30], [145, -30], [145, -20], [125, -20], [125, -30]]]); + * + * var line = turf.polygonToLine(poly); + * + * //addToMap + * var addToMap = [line]; + */ +export default function < + G extends Polygon | MultiPolygon, + P = GeoJsonProperties +>( + poly: Feature | G, + options: { properties?: any } = {} +): + | Feature + | FeatureCollection { + const geom: any = getGeom(poly); + if (!options.properties && poly.type === "Feature") { + options.properties = poly.properties; + } + switch (geom.type) { + case "Polygon": + return polygonToLine(geom, options); + case "MultiPolygon": + return multiPolygonToLine(geom, options); + default: + throw new Error("invalid poly"); + } +} + +/** + * @private + */ +export function polygonToLine( + poly: Feature | G, + options: { properties?: any } = {} +): Feature { + const geom = getGeom(poly); + const coords: any[] = geom.coordinates; + const properties: any = options.properties + ? options.properties + : poly.type === "Feature" + ? poly.properties + : {}; + + return coordsToLine(coords, properties); +} + +/** + * @private + */ +export function multiPolygonToLine< + G extends MultiPolygon, + P = GeoJsonProperties +>( + multiPoly: Feature | G, + options: { properties?: P } = {} +): FeatureCollection { + const geom = getGeom(multiPoly); + const coords: any[] = geom.coordinates; + const properties: any = options.properties + ? options.properties + : multiPoly.type === "Feature" + ? multiPoly.properties + : {}; + + const lines: Array> = []; + coords.forEach((coord) => { + lines.push(coordsToLine(coord, properties)); + }); + return featureCollection(lines); +} + +/** + * @private + */ +export function coordsToLine

( + coords: number[][][], + properties: P +): Feature { + if (coords.length > 1) { + return multiLineString(coords, properties); + } + return lineString(coords[0], properties); +} + +/** + * import { featureCollection, lineString, multiLineString } from "@turf/helpers"; +import { + Feature, + FeatureCollection, + LineString, + MultiLineString, + MultiPolygon, + Polygon, + GeoJsonProperties, +} from "geojson"; +import { getGeom } from "@turf/invariant"; + +/** + * Converts a {@link Polygon} to {@link LineString|(Multi)LineString} or {@link MultiPolygon} to a + * {@link FeatureCollection} of {@link LineString|(Multi)LineString}. + * + * @name polygonToLine + * @param {Feature} poly Feature to convert + * @param {Object} [options={}] Optional parameters + * @param {Object} [options.properties={}] translates GeoJSON properties to Feature + * @returns {FeatureCollection|Feature} converted (Multi)Polygon to (Multi)LineString + * @example + * var poly = turf.polygon([[[125, -30], [145, -30], [145, -20], [125, -20], [125, -30]]]); + * + * var line = turf.polygonToLine(poly); + * + * //addToMap + * var addToMap = [line]; + */ +export default function < + G extends Polygon | MultiPolygon, + P = GeoJsonProperties +>( + poly: Feature | G, + options: { properties?: any } = {} +): + | Feature + | FeatureCollection { + const geom: any = getGeom(poly); + if (!options.properties && poly.type === "Feature") { + options.properties = poly.properties; + } + switch (geom.type) { + case "Polygon": + return polygonToLine(geom, options); + case "MultiPolygon": + return multiPolygonToLine(geom, options); + default: + throw new Error("invalid poly"); + } +} + +/** + * @private + */ +export function polygonToLine( + poly: Feature | G, + options: { properties?: any } = {} +): Feature { + const geom = getGeom(poly); + const coords: any[] = geom.coordinates; + const properties: any = options.properties + ? options.properties + : poly.type === "Feature" + ? poly.properties + : {}; + + return coordsToLine(coords, properties); +} + +/** + * @private + */ +export function multiPolygonToLine< + G extends MultiPolygon, + P = GeoJsonProperties +>( + multiPoly: Feature | G, + options: { properties?: P } = {} +): FeatureCollection { + const geom = getGeom(multiPoly); + const coords: any[] = geom.coordinates; + const properties: any = options.properties + ? options.properties + : multiPoly.type === "Feature" + ? multiPoly.properties + : {}; + + const lines: Array> = []; + coords.forEach((coord) => { + lines.push(coordsToLine(coord, properties)); + }); + return featureCollection(lines); +} + +/** + * @private + */ +export function coordsToLine

( + coords: number[][][], + properties: P +): Feature { + if (coords.length > 1) { + return multiLineString(coords, properties); + } + return lineString(coords[0], properties); +} + */ \ No newline at end of file From 56c6d93d33e1e808e7f2b02390fa552ddec805fb Mon Sep 17 00:00:00 2001 From: armantorkzaban Date: Thu, 9 Jun 2022 17:13:50 +0200 Subject: [PATCH 19/82] valid --- lib/src/booleans/boolean_valid.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/src/booleans/boolean_valid.dart b/lib/src/booleans/boolean_valid.dart index 79aec7b0..d30f0edd 100644 --- a/lib/src/booleans/boolean_valid.dart +++ b/lib/src/booleans/boolean_valid.dart @@ -1,5 +1,6 @@ import '../../helpers.dart'; import '../invariant.dart'; +import '../line_intersect.dart'; import 'boolean_crosses.dart'; import 'boolean_disjoint.dart'; From afcc3a3b5cd74d13faf04713e0fab8c1c8dfbd91 Mon Sep 17 00:00:00 2001 From: armantorkzaban Date: Thu, 9 Jun 2022 17:32:34 +0200 Subject: [PATCH 20/82] dependencies imported --- lib/src/booleans/boolean_overlap.dart | 1 + lib/src/booleans/boolean_within.dart | 24 ++-- lib/src/clean_coords.dart | 10 +- lib/src/rhumb_bearing.dart | 166 ++++++++++++++++++++++++++ 4 files changed, 188 insertions(+), 13 deletions(-) create mode 100644 lib/src/rhumb_bearing.dart diff --git a/lib/src/booleans/boolean_overlap.dart b/lib/src/booleans/boolean_overlap.dart index 7ffa0c25..5b6f0430 100644 --- a/lib/src/booleans/boolean_overlap.dart +++ b/lib/src/booleans/boolean_overlap.dart @@ -2,6 +2,7 @@ import '../../helpers.dart'; import '../../line_segment.dart'; import '../invariant.dart'; import '../line_intersect.dart'; +import '../line_overlap.dart'; /** * Compares two geometries of the same dimension and returns true if their intersection set results in a geometry diff --git a/lib/src/booleans/boolean_within.dart b/lib/src/booleans/boolean_within.dart index 8f801871..12fa39c7 100644 --- a/lib/src/booleans/boolean_within.dart +++ b/lib/src/booleans/boolean_within.dart @@ -106,12 +106,14 @@ isMultiPointOnLine(MultiPoint multiPoint, LineString lineString) { var foundInsidePoint = false; for (var i = 0; i < multiPoint.coordinates.length; i++) { - if (!booleanPointOnLine(multiPoint.coordinates[i], lineString)) { + if (!booleanPointOnLine( + Point(coordinates: multiPoint.coordinates[i]), lineString)) { return false; } if (!foundInsidePoint) { foundInsidePoint = booleanPointOnLine( - multiPoint.coordinates[i], lineString, {ignoreEndVertices: true}); + Point(coordinates: multiPoint.coordinates[i]), lineString, + ignoreEndVertices: true); } } return foundInsidePoint; @@ -128,9 +130,11 @@ isMultiPointInPoly(MultiPoint multiPoint, Polygon polygon) { break; } if (!oneInside) { - isInside = booleanPointInPolygon(multiPoint.coordinates[i], polygon, { + isInside = booleanPointInPolygon( + multiPoint.coordinates[i], + polygon, ignoreBoundary: true, - }); + ); } } return output && isInside; @@ -138,7 +142,8 @@ isMultiPointInPoly(MultiPoint multiPoint, Polygon polygon) { isLineOnLine(LineString lineString1, LineString lineString2) { for (var i = 0; i < lineString1.coordinates.length; i++) { - if (!booleanPointOnLine(lineString1.coordinates[i], lineString2)) { + if (!booleanPointOnLine( + Point(coordinates: lineString1.coordinates[i]), lineString2)) { return false; } } @@ -159,14 +164,17 @@ isLineInPoly(LineString linestring, Polygon polygon) { } if (!foundInsidePoint) { foundInsidePoint = booleanPointInPolygon( - linestring.coordinates[i], polygon, {ignoreBoundary: true}); + linestring.coordinates[i], polygon, + ignoreBoundary: true); } if (!foundInsidePoint) { var midpoint = getMidpoint(linestring.coordinates[i], linestring.coordinates[i + 1]); - foundInsidePoint = booleanPointInPolygon(midpoint, polygon, { + foundInsidePoint = booleanPointInPolygon( + midpoint, + polygon, ignoreBoundary: true, - }); + ); } } return foundInsidePoint; diff --git a/lib/src/clean_coords.dart b/lib/src/clean_coords.dart index cde99903..b48f4adb 100644 --- a/lib/src/clean_coords.dart +++ b/lib/src/clean_coords.dart @@ -48,9 +48,9 @@ import 'invariant.dart'; }); break; case MultiPolygon: - getCoords(geojson).forEach( (polygons: any) { - var polyPoints: Position[] = []; - polygons.forEach( (ring: Position[]) { + getCoords(geojson).forEach( (polygons) { + var polyPoints = []; + polygons.forEach( (List ring) { polyPoints.add(cleanLine(ring, type)); }); newCoords.add(polyPoints); @@ -59,7 +59,7 @@ import 'invariant.dart'; case Point: return geojson; case MultiPoint: - var existing: Record = {}; + var Record existing: = {}; getCoords(geojson).forEach( (coord: any) { var key = coord.join("-"); if (!Object.prototype.hasOwnProperty.call(existing, key)) { @@ -69,7 +69,7 @@ import 'invariant.dart'; }); break; default: - throw new Error(type + " geometry not supported"); + throw Exception(type + " geometry not supported"); } // Support input mutation diff --git a/lib/src/rhumb_bearing.dart b/lib/src/rhumb_bearing.dart new file mode 100644 index 00000000..28de3887 --- /dev/null +++ b/lib/src/rhumb_bearing.dart @@ -0,0 +1,166 @@ +// https://en.wikipedia.org/wiki/Rhumb_line +import 'package:turf/src/invariant.dart'; + +import '../helpers.dart'; + + +/** + * Takes two {@link Point|points} and finds the bearing angle between them along a Rhumb line + * i.e. the angle measured in degrees start the north line (0 degrees) + * + * @name rhumbBearing + * @param {Coord} start starting Point + * @param {Coord} end ending Point + * @param {Object} [options] Optional parameters + * @param {boolean} [options.final=false] calculates the final bearing if true + * @returns {number} bearing from north in decimal degrees, between -180 and 180 degrees (positive clockwise) + * @example + * var point1 = turf.point([-75.343, 39.984], {"marker-color": "#F00"}); + * var point2 = turf.point([-75.534, 39.123], {"marker-color": "#00F"}); + * + * var bearing = turf.rhumbBearing(point1, point2); + * + * //addToMap + * var addToMap = [point1, point2]; + * point1.properties.bearing = bearing; + * point2.properties.bearing = bearing; + */ + num rhumbBearing( + Position start, + Position end, + { final?: boolean } +{ var bear360; + if (options.final) { + bear360 = calculateRhumbBearing(getCoord(end), getCoord(start)); + } else { + bear360 = calculateRhumbBearing(getCoord(start), getCoord(end)); + } + + const bear180 = bear360 > 180 ? -(360 - bear360) : bear360; + + return bear180; +} + +/** + * Returns the bearing from ‘this’ point to destination point along a rhumb line. + * Adapted from Geodesy: https://github.com/chrisveness/geodesy/blob/master/latlon-spherical.js + * + * @private + * @param {Array} from - origin point. + * @param {Array} to - destination point. + * @returns {number} Bearing in degrees from north. + * @example + * var p1 = new LatLon(51.127, 1.338); + * var p2 = new LatLon(50.964, 1.853); + * var d = p1.rhumbBearingTo(p2); // 116.7 m + */ + calculateRhumbBearing(Position from, Position to) { + // φ => phi + // Δλ => deltaLambda + // Δψ => deltaPsi + // θ => theta + const phi1 = degreesToRadians(from[1]); + const phi2 = degreesToRadians(to[1]); + let deltaLambda = degreesToRadians(to[0] - from[0]); + // if deltaLambdaon over 180° take shorter rhumb line across the anti-meridian: + if (deltaLambda > Math.PI) { + deltaLambda -= 2 * Math.PI; + } + if (deltaLambda < -Math.PI) { + deltaLambda += 2 * Math.PI; + } + + const deltaPsi = Math.log( + Math.tan(phi2 / 2 + Math.PI / 4) / Math.tan(phi1 / 2 + Math.PI / 4) + ); + + const theta = Math.atan2(deltaLambda, deltaPsi); + + return (radiansToDegrees(theta) + 360) % 360; +} + + + +/** + * // https://en.wikipedia.org/wiki/Rhumb_line +import { Coord, degreesToRadians, radiansToDegrees } from "@turf/helpers"; +import { getCoord } from "@turf/invariant"; + +/** + * Takes two {@link Point|points} and finds the bearing angle between them along a Rhumb line + * i.e. the angle measured in degrees start the north line (0 degrees) + * + * @name rhumbBearing + * @param {Coord} start starting Point + * @param {Coord} end ending Point + * @param {Object} [options] Optional parameters + * @param {boolean} [options.final=false] calculates the final bearing if true + * @returns {number} bearing from north in decimal degrees, between -180 and 180 degrees (positive clockwise) + * @example + * var point1 = turf.point([-75.343, 39.984], {"marker-color": "#F00"}); + * var point2 = turf.point([-75.534, 39.123], {"marker-color": "#00F"}); + * + * var bearing = turf.rhumbBearing(point1, point2); + * + * //addToMap + * var addToMap = [point1, point2]; + * point1.properties.bearing = bearing; + * point2.properties.bearing = bearing; + */ +function rhumbBearing( + start: Coord, + end: Coord, + options: { final?: boolean } = {} +): number { + let bear360; + if (options.final) { + bear360 = calculateRhumbBearing(getCoord(end), getCoord(start)); + } else { + bear360 = calculateRhumbBearing(getCoord(start), getCoord(end)); + } + + const bear180 = bear360 > 180 ? -(360 - bear360) : bear360; + + return bear180; +} + +/** + * Returns the bearing from ‘this’ point to destination point along a rhumb line. + * Adapted from Geodesy: https://github.com/chrisveness/geodesy/blob/master/latlon-spherical.js + * + * @private + * @param {Array} from - origin point. + * @param {Array} to - destination point. + * @returns {number} Bearing in degrees from north. + * @example + * var p1 = new LatLon(51.127, 1.338); + * var p2 = new LatLon(50.964, 1.853); + * var d = p1.rhumbBearingTo(p2); // 116.7 m + */ +function calculateRhumbBearing(from: number[], to: number[]) { + // φ => phi + // Δλ => deltaLambda + // Δψ => deltaPsi + // θ => theta + const phi1 = degreesToRadians(from[1]); + const phi2 = degreesToRadians(to[1]); + let deltaLambda = degreesToRadians(to[0] - from[0]); + // if deltaLambdaon over 180° take shorter rhumb line across the anti-meridian: + if (deltaLambda > Math.PI) { + deltaLambda -= 2 * Math.PI; + } + if (deltaLambda < -Math.PI) { + deltaLambda += 2 * Math.PI; + } + + const deltaPsi = Math.log( + Math.tan(phi2 / 2 + Math.PI / 4) / Math.tan(phi1 / 2 + Math.PI / 4) + ); + + const theta = Math.atan2(deltaLambda, deltaPsi); + + return (radiansToDegrees(theta) + 360) % 360; +} + +export default rhumbBearing; + */ \ No newline at end of file From 54eb36e9e110763753fde163b12816be409635b5 Mon Sep 17 00:00:00 2001 From: Lukas Himsel Date: Thu, 9 Jun 2022 17:54:05 +0200 Subject: [PATCH 21/82] Update CONTRIBUTING.md --- CONTRIBUTING.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 508a6d2a..a78adf91 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -20,7 +20,6 @@ To put it simply, be kind to each other. - Clone the repository: ```git clone git@github.com:dartclub/turf_dart.git``` - Navigate to project's folder in terminal & get its dependencies: ```dart pub get``` - Go through [Implementation Process](#implementation-process) -<<<<<<< HEAD - Import the library in your code and use it. For example: ```dart import 'package:turf/helpers.dart'; @@ -57,9 +56,7 @@ var total = segmentReduce(poly, (previousValue, }, 0, combineNestedGeometries: false); // total.length == 6 ``` -======= ->>>>>>> main ## Structure of modules ``` TURF_DART/lib/.dart // public facing API, exports the implementation @@ -95,4 +92,4 @@ In order to add to this very documentation, please develop CONTRIBUTING.md in [d ## GeoJSON Object Model If you have not read our [README.md](https://github.com/dartclub/turf_dart/blob/main/README.md) this diagram will give you a lot of information. Please consider looking our [notable design decisions](https://github.com/dartclub/turf_dart/blob/main/README.md#notable-design-decisions). -![polymorphism](https://user-images.githubusercontent.com/10634693/159876354-f9da2f37-02b3-4546-b32a-c0f82c372272.png) \ No newline at end of file +![polymorphism](https://user-images.githubusercontent.com/10634693/159876354-f9da2f37-02b3-4546-b32a-c0f82c372272.png) From a5d67bd6f535f6d61eb908e1646590162dcadc33 Mon Sep 17 00:00:00 2001 From: armantorkzaban Date: Tue, 14 Jun 2022 19:41:14 +0200 Subject: [PATCH 22/82] clockwise test --- test/booleans/clockwise_test.dart | 73 +++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 test/booleans/clockwise_test.dart diff --git a/test/booleans/clockwise_test.dart b/test/booleans/clockwise_test.dart new file mode 100644 index 00000000..7a895732 --- /dev/null +++ b/test/booleans/clockwise_test.dart @@ -0,0 +1,73 @@ +import 'package:test/test.dart'; +import 'package:turf/helpers.dart'; +import 'package:turf/src/booleans/boolean_clockwise.dart'; + +main() { + // test("isClockwise#fixtures", () { + // // True Fixtures + // glob + // .sync(path.join(__dirname, "test", "true", "*.geojson")) + // .forEach((filepath) => { + // const name = path.parse(filepath).name; + // const geojson = load.sync(filepath); + // const feature = geojson.features[0]; + // t.true(isClockwise(feature), "[true] " + name); + // }); + // // False Fixtures + // glob + // .sync(path.join(__dirname, "test", "false", "*.geojson")) + // .forEach((filepath) => { + // const name = path.parse(filepath).name; + // const geojson = load.sync(filepath); + // const feature = geojson.features[0]; + // t.false(isClockwise(feature), "[false] " + name); + // }); + // t.end(); + // }); + + test("isClockwise", () { + const cwArray = [ + [0, 0], + [1, 1], + [1, 0], + [0, 0], + ]; + const ccwArray = [ + [0, 0], + [1, 0], + [1, 1], + [0, 0], + ]; + + expect( + booleanClockwise(cwArray), + equals( + true, + ), + ); + + expect( + booleanClockwise(ccwArray), + equals(false), + ); + }); + + test("isClockwise -- Geometry types", () { + LineString line = LineString(coordinates: [ + Position.of([0, 0]), + Position.of([1, 1]), + Position.of([1, 0]), + Position.of([0, 0]), + ]); + + expect(booleanClockwise(line), equals(true)); + expect(booleanClockwise(line.coordinates), equals(true)); + }); + +// test('isClockwise -- throws', t => { +// const pt = point([-10, -33]); +// t.throws(() => isClockwise(pt), 'feature geometry not supported'); + +// t.end(); +// }); +} From 5dbe443a9d27d0df9d6190d72a7fde948bc5e576 Mon Sep 17 00:00:00 2001 From: armantorkzaban Date: Tue, 14 Jun 2022 20:00:13 +0200 Subject: [PATCH 23/82] concave test --- test/booleans/concave_test.dart | 64 +++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 test/booleans/concave_test.dart diff --git a/test/booleans/concave_test.dart b/test/booleans/concave_test.dart new file mode 100644 index 00000000..e2743ac3 --- /dev/null +++ b/test/booleans/concave_test.dart @@ -0,0 +1,64 @@ +import 'package:test/test.dart'; +import 'package:turf/helpers.dart'; +import 'package:turf/src/booleans/boolean_concave.dart'; + +main() { +// test("isConcave#fixtures", (t) => { +// // True Fixtures +// glob +// .sync(path.join(__dirname, "test", "true", "*.geojson")) +// .forEach((filepath) => { +// const name = path.parse(filepath).name; +// const geojson = load.sync(filepath); +// const feature = geojson.features[0]; +// t.true(isConcave(feature), "[true] " + name); +// }); +// // False Fixtures +// glob +// .sync(path.join(__dirname, "test", "false", "*.geojson")) +// .forEach((filepath) => { +// const name = path.parse(filepath).name; +// const geojson = load.sync(filepath); +// const feature = geojson.features[0]; +// t.false(isConcave(feature), "[false] " + name); +// }); +// t.end(); +// }); + + test("isConcave -- Geometry types", () { + var featureCollection = FeatureCollection(features: [ + Feature( + properties: {}, + geometry: Polygon(coordinates: [ + [ + Position.of([0.85418701171875, 1.06286628163273]), + Position.of([0.46966552734375, 0.7909904981540058]), + Position.of([0.6619262695312499, 0.5712795966325395]), + Position.of([0.77178955078125, 0.856901647439813]), + Position.of([0.736083984375, 0.8514090937773031]), + Position.of([0.6591796875, 0.8129610018708315]), + Position.of([0.6921386718749999, 0.884364296613886]), + Position.of([0.9173583984375001, 0.8898568022677679]), + Position.of([1.07391357421875, 0.8129610018708315]), + Position.of([1.0876464843749998, 0.9392889790847924]), + Position.of([1.0052490234375, 1.0271666545523288]), + Position.of([0.85418701171875, 1.06286628163273]), + ] + ])) + ]); + + Polygon poly = Polygon(coordinates: [ + [ + Position.of([0, 0]), + Position.of([0, 1]), + Position.of([1, 1]), + Position.of([1, 0]), + Position.of([0, 0]), + ], + ]); + + expect(booleanConcave(poly), equals(false)); + expect(booleanConcave(featureCollection.features.first.geometry!), + equals(true)); + }); +} From 43e372a1d28c06b98ec89707028d4b9b8977d02c Mon Sep 17 00:00:00 2001 From: armantorkzaban Date: Tue, 14 Jun 2022 23:06:37 +0200 Subject: [PATCH 24/82] intersect test --- lib/src/booleans/boolean_disjoint.dart | 1 + test/booleans/intersect_test.dart | 90 ++++++++++++++++++++++++++ 2 files changed, 91 insertions(+) create mode 100644 test/booleans/intersect_test.dart diff --git a/lib/src/booleans/boolean_disjoint.dart b/lib/src/booleans/boolean_disjoint.dart index 1dcf0a4f..6fa952ad 100644 --- a/lib/src/booleans/boolean_disjoint.dart +++ b/lib/src/booleans/boolean_disjoint.dart @@ -1,6 +1,7 @@ import '../../helpers.dart'; import '../../meta.dart'; import '../line_intersect.dart'; +import '../polygon_to_line.dart'; import 'boolean_point_in_polygon.dart'; /** diff --git a/test/booleans/intersect_test.dart b/test/booleans/intersect_test.dart new file mode 100644 index 00000000..35e0e15f --- /dev/null +++ b/test/booleans/intersect_test.dart @@ -0,0 +1,90 @@ +import 'package:test/test.dart'; +import 'package:turf/helpers.dart'; +import 'package:turf/src/booleans/boolean_intersect.dart'; + +main() { + var featureCollection = FeatureCollection(features: [ + Feature( + properties: {"fill": "#ff0000"}, + geometry: MultiPolygon(coordinates: [ + [ + [ + Position.of([122.6953125, -19.186677697957833]), + Position.of([128.759765625, -19.186677697957833]), + Position.of([128.759765625, -15.28418511407642]), + Position.of([122.6953125, -15.28418511407642]), + Position.of([122.6953125, -19.186677697957833]) + ] + ], + [ + [ + Position.of([123.74999999999999, -25.918526162075153]), + Position.of([130.25390625, -25.918526162075153]), + Position.of([130.25390625, -20.715015145512087]), + Position.of([123.74999999999999, -20.715015145512087]), + Position.of([123.74999999999999, -25.918526162075153]), + ] + ] + ])), + Feature( + properties: {"fill": "#0000ff"}, + geometry: Polygon(coordinates: [ + [ + Position.of([119.20166015624999, -22.776181505086495]), + Position.of([125.09033203124999, -22.776181505086495]), + Position.of([125.09033203124999, -18.417078658661257]), + Position.of([119.20166015624999, -18.417078658661257]), + Position.of([119.20166015624999, -22.776181505086495]) + ] + ])) + ]); + + var featureCollection1 = FeatureCollection(features: [ + Feature( + properties: {"fill": "#ff0000"}, + geometry: MultiPolygon(coordinates: [ + [ + [ + Position.of([122.6953125, -19.186677697957833]), + Position.of([128.759765625, -19.186677697957833]), + Position.of([128.759765625, -15.28418511407642]), + Position.of([122.6953125, -15.28418511407642]), + Position.of([122.6953125, -19.186677697957833]) + ] + ], + [ + [ + Position.of([123.74999999999999, -25.918526162075153]), + Position.of([130.25390625, -25.918526162075153]), + Position.of([130.25390625, -20.715015145512087]), + Position.of([123.74999999999999, -20.715015145512087]), + Position.of([123.74999999999999, -25.918526162075153]) + ] + ] + ])), + Feature( + properties: {"fill": "#0000ff"}, + geometry: Polygon(coordinates: [ + [ + Position.of([116.98242187499999, -24.647017162630352]), + Position.of([122.87109375, -24.647017162630352]), + Position.of([122.87109375, -20.34462694382967]), + Position.of([116.98242187499999, -20.34462694382967]), + Position.of([116.98242187499999, -24.647017162630352]) + ] + ])) + ]); + test("turf-boolean-intersects", () { + // True Fixtures + + var feature1 = featureCollection.features[0]; + var feature2 = featureCollection.features[1]; + + expect(booleanIntersects(feature1, feature2), equals(true)); + + // False Fixtures + var feature3 = featureCollection1.features[0]; + var feature4 = featureCollection1.features[1]; + expect(booleanIntersects(feature3, feature4), equals(false)); + }); +} From 698fe6161fa68295da0e765c061dfac71862eda1 Mon Sep 17 00:00:00 2001 From: armantorkzaban Date: Wed, 15 Jun 2022 01:45:02 +0200 Subject: [PATCH 25/82] pointOnLine test --- lib/src/booleans/boolean_point_on_line.dart | 10 +- lib/src/line_intersect.dart | 2 +- lib/src/polygon_to_line.dart | 104 ++++++++------------ test/booleans/point_on_line_test.dart | 63 ++++++++++++ 4 files changed, 111 insertions(+), 68 deletions(-) create mode 100644 test/booleans/point_on_line_test.dart diff --git a/lib/src/booleans/boolean_point_on_line.dart b/lib/src/booleans/boolean_point_on_line.dart index 739d2a1a..522ef2bb 100644 --- a/lib/src/booleans/boolean_point_on_line.dart +++ b/lib/src/booleans/boolean_point_on_line.dart @@ -59,14 +59,14 @@ bool booleanPointOnLine(Point pt, LineString line, * If true which end to ignore. * @returns {boolean} true/false */ -bool isPointOnLineSegment(Point lineSegmentStart, Point lineSegmentEnd, +bool isPointOnLineSegment(Position lineSegmentStart, Position lineSegmentEnd, Position pt, dynamic excludeBoundary, num? epsilon) { var x = pt[0]!; var y = pt[1]!; - var x1 = lineSegmentStart.coordinates[0]; - var y1 = lineSegmentStart.coordinates[1]; - var x2 = lineSegmentEnd.coordinates[0]; - var y2 = lineSegmentEnd.coordinates[1]; + var x1 = lineSegmentStart[0]; + var y1 = lineSegmentStart[1]; + var x2 = lineSegmentEnd[0]; + var y2 = lineSegmentEnd[1]; var dxc = pt[0]! - x1!; var dyc = pt[1]! - y1!; var dxl = x2! - x1; diff --git a/lib/src/line_intersect.dart b/lib/src/line_intersect.dart index a82fcbe2..3c022b68 100644 --- a/lib/src/line_intersect.dart +++ b/lib/src/line_intersect.dart @@ -52,7 +52,7 @@ FeatureCollection lineIntersect( features.add(Feature(geometry: line2 as GeometryObject)); } - const intersections = findIntersections( + var intersections = findIntersections( FeatureCollection(features: features), ignoreSelfIntersections ); diff --git a/lib/src/polygon_to_line.dart b/lib/src/polygon_to_line.dart index fd5e554d..b30d181e 100644 --- a/lib/src/polygon_to_line.dart +++ b/lib/src/polygon_to_line.dart @@ -1,3 +1,7 @@ +import 'package:turf/helpers.dart'; + +import '../helpers.dart'; +import 'invariant.dart'; /** * Converts a {@link Polygon} to {@link LineString|(Multi)LineString} or {@link MultiPolygon} to a @@ -16,83 +20,59 @@ * //addToMap * var addToMap = [line]; */ -export default function < - G extends Polygon | MultiPolygon, - P = GeoJsonProperties ->( - poly: Feature | G, - options: { properties?: any } = {} -): - | Feature - | FeatureCollection { - const geom: any = getGeom(poly); - if (!options.properties && poly.type === "Feature") { - options.properties = poly.properties; + +polygonToLine(GeoJSONObject poly, {Map? properties}) { + var geom = getGeom(poly); + if (properties == null && poly is Feature) { + properties = poly.properties; } switch (geom.type) { - case "Polygon": - return polygonToLine(geom, options); - case "MultiPolygon": - return multiPolygonToLine(geom, options); + case Polygon: + return _polygonToLine(geom, properties: properties); + case MultiPolygon: + return _multiPolygonToLine(geom, properties: properties); default: - throw new Error("invalid poly"); + throw Exception("invalid poly"); } } -/** - * @private - */ -export function polygonToLine( - poly: Feature | G, - options: { properties?: any } = {} -): Feature { - const geom = getGeom(poly); - const coords: any[] = geom.coordinates; - const properties: any = options.properties - ? options.properties - : poly.type === "Feature" - ? poly.properties - : {}; +_polygonToLine(GeoJSONObject poly, + {Map? properties}) { + GeometryType geom = getGeom(poly); + var coords = geom.coordinates; + properties = properties != null + ? (poly is Feature) + ? poly.properties + : {} + : properties; - return coordsToLine(coords, properties); + return _coordsToLine(coords, properties!); } -/** - * @private - */ -export function multiPolygonToLine< - G extends MultiPolygon, - P = GeoJsonProperties ->( - multiPoly: Feature | G, - options: { properties?: P } = {} -): FeatureCollection { - const geom = getGeom(multiPoly); - const coords: any[] = geom.coordinates; - const properties: any = options.properties - ? options.properties - : multiPoly.type === "Feature" - ? multiPoly.properties - : {}; +_multiPolygonToLine(GeoJSONObject multiPoly, + {Map? properties}) { + var geom = getGeom(multiPoly); + var coords = geom.coordinates; + properties = properties != null + ? (multiPoly is Feature) + ? multiPoly.properties + : {} + : properties; - const lines: Array> = []; - coords.forEach((coord) => { - lines.push(coordsToLine(coord, properties)); + const lines = >[]; + coords.forEach((coord) { + lines.add(_coordsToLine(coord, properties!)); }); - return featureCollection(lines); + return FeatureCollection(features: lines); } -/** - * @private - */ -export function coordsToLine

( - coords: number[][][], - properties: P -): Feature { +_coordsToLine(List> coords, Map properties) { if (coords.length > 1) { - return multiLineString(coords, properties); + return Feature( + properties: properties, geometry: MultiLineString(coordinates: coords)); } - return lineString(coords[0], properties); + return Feature( + geometry: LineString(coordinates: coords[0]), properties: properties); } /** diff --git a/test/booleans/point_on_line_test.dart b/test/booleans/point_on_line_test.dart new file mode 100644 index 00000000..5a6b9aad --- /dev/null +++ b/test/booleans/point_on_line_test.dart @@ -0,0 +1,63 @@ +import 'dart:math'; + +import 'package:test/test.dart'; +import 'package:turf/helpers.dart'; +import 'package:turf/src/booleans/boolean_point_on_line.dart'; + +main() { + // False Fixtures + test( + "turf-boolean-point-on-line", + () { + var featureCollection = FeatureCollection( + features: [ + Feature( + properties: {}, + geometry: Point( + coordinates: + Position.of([-75.25737143565107, 39.99673377198139]))), + Feature( + properties: {}, + geometry: LineString( + coordinates: [ + Position.of([-75.2580499870244, 40.00180204907801]), + Position.of([-75.25676601413157, 39.992211720827044]), + ], + ), + ) + ], + ); + + var options = {"epsilon": 10e-18}; + + var feature1 = featureCollection.features[0].geometry; + var feature2 = featureCollection.features[1].geometry; + expect( + booleanPointOnLine(feature1 as Point, feature2 as LineString, + epsilon: options["epsilon"]), + equals(false)); + // True Fixtures + var featureCollection1 = FeatureCollection(features: [ + Feature( + properties: {}, geometry: Point(coordinates: Position.of([2, 2]))), + Feature( + properties: {}, + geometry: LineString( + coordinates: [ + Position.of([0, 0]), + Position.of([3, 3]), + Position.of([38.3203125, 5.965753671065536]) + ], + ), + ) + ]); + + feature1 = featureCollection1.features[0].geometry; + feature2 = featureCollection1.features[1].geometry; + expect( + booleanPointOnLine(feature1 as Point, feature2 as LineString, + epsilon: options["epsilon"]), + equals(true)); + }, + ); +} From c54a2d7ecc156cd7ab30d6c4dd26a5e3d3a856b4 Mon Sep 17 00:00:00 2001 From: armantorkzaban Date: Wed, 15 Jun 2022 02:01:55 +0200 Subject: [PATCH 26/82] contains --- lib/src/booleans/boolean_contains.dart | 18 ++++++++------ lib/src/booleans/boolean_disjoint.dart | 2 +- lib/src/booleans/boolean_within.dart | 34 +++++++++++++------------- 3 files changed, 28 insertions(+), 26 deletions(-) diff --git a/lib/src/booleans/boolean_contains.dart b/lib/src/booleans/boolean_contains.dart index e39b9228..80c70fca 100644 --- a/lib/src/booleans/boolean_contains.dart +++ b/lib/src/booleans/boolean_contains.dart @@ -1,7 +1,9 @@ +import 'package:turf/src/booleans/boolean_disjoint.dart'; + import '../../helpers.dart'; import '../invariant.dart'; -import 'boolean_disjoint.dart'; import 'boolean_point_in_polygon.dart'; +import 'boolean_point_on_line.dart'; /** * Boolean-contains returns True if the second geometry is completely contained by the first geometry. @@ -50,7 +52,7 @@ booleanContains(GeoJSONObject feature1, GeoJSONObject feature2) { case LineString: switch (type2) { case Point: - return isPointOnLine(geom2, geom1, ignoreEndVertices: true); + return booleanPointOnLine(geom2, geom1, ignoreEndVertices: true); case LineString: return isLineOnLine(geom1, geom2); case MultiPoint: @@ -109,11 +111,11 @@ isMultiPointInMultiPoint(MultiPoint multiPoint1, MultiPoint multiPoint2) { isMultiPointOnLine(LineString lineString, MultiPoint multiPoint) { var haveFoundInteriorPoint = false; for (var coord in multiPoint.coordinates) { - if (isPointOnLine(lineString, Point(coordinates: coord), + if (booleanPointOnLine(Point(coordinates: coord), lineString, ignoreEndVertices: true)) { haveFoundInteriorPoint = true; } - if (!isPointOnLine(lineString, Point(coordinates: coord))) { + if (!booleanPointOnLine(Point(coordinates: coord), lineString)) { return false; } } @@ -135,16 +137,16 @@ isMultiPointInPoly(Polygon polygon, MultiPoint multiPoint) { isLineOnLine(LineString lineString1, LineString lineString2) { var haveFoundInteriorPoint = false; for (var coords in lineString2.coordinates) { - if (isPointOnLine( - lineString1, + if (booleanPointOnLine( Point(coordinates: coords), + lineString1, ignoreEndVertices: true, )) { haveFoundInteriorPoint = true; } - if (!isPointOnLine( - lineString1, + if (!booleanPointOnLine( Point(coordinates: coords), + lineString1, ignoreEndVertices: false, )) { return false; diff --git a/lib/src/booleans/boolean_disjoint.dart b/lib/src/booleans/boolean_disjoint.dart index 6fa952ad..68bb9c6c 100644 --- a/lib/src/booleans/boolean_disjoint.dart +++ b/lib/src/booleans/boolean_disjoint.dart @@ -131,7 +131,7 @@ isPolyInPoly(Polygon feature1, Polygon feature2) { } var doLinesIntersect = lineIntersect(polygonToLine(feature1), polygonToLine(feature2)); - if (doLinesIntersect.features.length > 0) { + if (doLinesIntersect.features.isNotEmpty) { return true; } return false; diff --git a/lib/src/booleans/boolean_within.dart b/lib/src/booleans/boolean_within.dart index 12fa39c7..b7deb2dc 100644 --- a/lib/src/booleans/boolean_within.dart +++ b/lib/src/booleans/boolean_within.dart @@ -27,44 +27,44 @@ bool booleanWithin(GeoJSONObject feature1, GeoJSONObject feature2) { var type2 = geom2.type; switch (type1) { - case "Point": + case Point: switch (type2) { - case "MultiPoint": + case MultiPoint: return isPointInMultiPoint(geom1, geom2); - case "LineString": + case LineString: return booleanPointOnLine(geom1, geom2, ignoreEndVertices: true); - case "Polygon": - case "MultiPolygon": + case Polygon: + case MultiPolygon: return booleanPointInPolygon(geom1, geom2, ignoreBoundary: true); default: throw Exception("feature2 " + type2 + " geometry not supported"); } - case "MultiPoint": + case MultiPoint: switch (type2) { - case "MultiPoint": + case MultiPoint: return isMultiPointInMultiPoint(geom1, geom2); - case "LineString": + case LineString: return isMultiPointOnLine(geom1, geom2); - case "Polygon": - case "MultiPolygon": + case Polygon: + case MultiPolygon: return isMultiPointInPoly(geom1, geom2); default: throw Exception("feature2 " + type2 + " geometry not supported"); } - case "LineString": + case LineString: switch (type2) { - case "LineString": + case LineString: return isLineOnLine(geom1, geom2); - case "Polygon": - case "MultiPolygon": + case Polygon: + case MultiPolygon: return isLineInPoly(geom1, geom2); default: throw Exception("feature2 " + type2 + " geometry not supported"); } - case "Polygon": + case Polygon: switch (type2) { - case "Polygon": - case "MultiPolygon": + case Polygon: + case MultiPolygon: return isPolyInPoly(geom1, geom2); default: throw Exception("feature2 " + type2 + " geometry not supported"); From 6ec1db057b1ce45cbba17b70c4d09b31ec46e8b2 Mon Sep 17 00:00:00 2001 From: armantorkzaban Date: Wed, 15 Jun 2022 02:23:42 +0200 Subject: [PATCH 27/82] crosses_test - blocked by findIntersections --- lib/src/booleans/boolean_crosses.dart | 3 +- test/booleans/crosses_test.dart | 59 +++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 1 deletion(-) create mode 100644 test/booleans/crosses_test.dart diff --git a/lib/src/booleans/boolean_crosses.dart b/lib/src/booleans/boolean_crosses.dart index 2795bffe..d9a1af6a 100644 --- a/lib/src/booleans/boolean_crosses.dart +++ b/lib/src/booleans/boolean_crosses.dart @@ -1,6 +1,7 @@ import '../../helpers.dart'; import '../invariant.dart'; import '../line_intersect.dart'; +import '../polygon_to_line.dart'; import 'boolean_point_in_polygon.dart'; /** * Boolean-Crosses returns True if the intersection results in a geometry whose dimension is one less than @@ -112,7 +113,7 @@ doLineStringsCross(LineString lineString1, LineString lineString2) { } doLineStringAndPolygonCross(LineString lineString, Polygon polygon) { - const LineString line = polygonToLine(polygon); + LineString line = polygonToLine(polygon); var doLinesIntersect = lineIntersect(lineString, line); if (doLinesIntersect.features.isNotEmpty) { return true; diff --git a/test/booleans/crosses_test.dart b/test/booleans/crosses_test.dart new file mode 100644 index 00000000..ba8d749e --- /dev/null +++ b/test/booleans/crosses_test.dart @@ -0,0 +1,59 @@ +import 'package:test/test.dart'; +import 'package:turf/helpers.dart'; +import 'package:turf/src/booleans/boolean_crosses.dart'; + +main() { + test("turf-boolean-crosses", () { + // True Fixtures + var featureCollection = FeatureCollection(features: [ + Feature( + properties: {}, + geometry: MultiPoint(coordinates: [ + Position.of([3, 3]), + Position.of([1, 1]) + ])), + Feature( + properties: {}, + geometry: Polygon(coordinates: [ + [ + Position.of([0, 2]), + Position.of([2, 2]), + Position.of([2, 0]), + Position.of([0, 0]), + Position.of([0, 2]) + ] + ])) + ]); + + var feature1 = featureCollection.features[0]; + var feature2 = featureCollection.features[1]; + expect( + booleanCrosses(feature1.geometry!, feature2.geometry!), equals(true)); + + // False Fixtures + var featureCollection1 = FeatureCollection(features: [ + Feature( + properties: {}, + geometry: MultiPoint(coordinates: [ + Position.of([3, 3]), + Position.of([1, 1]) + ])), + Feature( + properties: {}, + geometry: Polygon(coordinates: [ + [ + Position.of([0, 2]), + Position.of([2, 2]), + Position.of([2, 0]), + Position.of([0, 0]), + Position.of([0, 2]) + ] + ])) + ]); + + feature1 = featureCollection1.features[0]; + feature2 = featureCollection1.features[1]; + expect( + booleanCrosses(feature1.geometry!, feature2.geometry!), equals(false)); + }); +} From 5fe7e1d3343805e1fb4185794fbb6ed5c8ba8935 Mon Sep 17 00:00:00 2001 From: armantorkzaban Date: Sun, 19 Jun 2022 21:17:13 +0200 Subject: [PATCH 28/82] boolean_contain --- lib/src/booleans/boolean_contains.dart | 19 ++++++-------- lib/src/booleans/boolean_overlap.dart | 34 +++++++++++++++++--------- 2 files changed, 30 insertions(+), 23 deletions(-) diff --git a/lib/src/booleans/boolean_contains.dart b/lib/src/booleans/boolean_contains.dart index 80c70fca..f4899bbc 100644 --- a/lib/src/booleans/boolean_contains.dart +++ b/lib/src/booleans/boolean_contains.dart @@ -1,6 +1,5 @@ -import 'package:turf/src/booleans/boolean_disjoint.dart'; +import 'package:turf/turf.dart'; -import '../../helpers.dart'; import '../invariant.dart'; import 'boolean_point_in_polygon.dart'; import 'boolean_point_on_line.dart'; @@ -159,8 +158,8 @@ isLineInPoly(Polygon polygon, LineString linestring) { var output = false; var i = 0; - const polyBbox = calcBbox(polygon); - const lineBbox = calcBbox(linestring); + var polyBbox = bbox(polygon); + var lineBbox = bbox(linestring); if (!doBBoxOverlap(polyBbox, lineBbox)) { return false; } @@ -188,19 +187,17 @@ isLineInPoly(Polygon polygon, LineString linestring) { * @param {Geometry|Feature} feature2 Polygon2 * @returns {boolean} true/false */ -isPolyInPoly(GeoJSONObject feature1, GeoJSONObjectType feature2) { +isPolyInPoly(GeoJSONObject feature1, GeoJSONObject feature2) { // Handle Nulls - if (feature1.runtimeType == Feature && - (feature1 as Feature).geometry == null) { + if (feature1 is Feature && feature1.geometry == null) { return false; } - if (feature2.runtimeType == Feature && - (feature2 as Feature).geometry == null) { + if (feature2 is Feature && feature2.geometry == null) { return false; } - const poly1Bbox = calcBbox(feature1); - const poly2Bbox = calcBbox(feature2); + var poly1Bbox = bbox(feature1); + var poly2Bbox = bbox(feature2); if (!doBBoxOverlap(poly1Bbox, poly2Bbox)) { return false; } diff --git a/lib/src/booleans/boolean_overlap.dart b/lib/src/booleans/boolean_overlap.dart index 5b6f0430..ef7a71de 100644 --- a/lib/src/booleans/boolean_overlap.dart +++ b/lib/src/booleans/boolean_overlap.dart @@ -63,23 +63,33 @@ booleanOverlap(GeometryObject feature1, GeometryObject feature2) { case LineString: case MultiLineString: - segmentEach(feature1, ( - segment1, - featureIndex, - multiFeatureIndex, - geometryIndex, - segmentIndex, - ) { - segmentEach(feature2, ( - segment2, + segmentEach( + feature1, + ( + segment1, featureIndex, multiFeatureIndex, geometryIndex, segmentIndex, ) { - if (lineOverlap(segment1, segment2).features.length) overlap++; - }); - }); + segmentEach( + feature2, + ( + segment2, + featureIndex, + multiFeatureIndex, + geometryIndex, + segmentIndex, + ) { + if (lineOverlap(line1: segment1, line2: segment2) + .features + .length) { + overlap++; + } + }, + ); + }, + ); break; case Polygon: From 453bab2a0c3e4a5d68862f75eee7ff67635d192f Mon Sep 17 00:00:00 2001 From: armantorkzaban Date: Sun, 19 Jun 2022 21:18:57 +0200 Subject: [PATCH 29/82] boolean_within --- lib/src/booleans/boolean_within.dart | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/src/booleans/boolean_within.dart b/lib/src/booleans/boolean_within.dart index b7deb2dc..fdc40d9e 100644 --- a/lib/src/booleans/boolean_within.dart +++ b/lib/src/booleans/boolean_within.dart @@ -1,3 +1,5 @@ +import 'package:turf/bbox.dart'; + import '../../helpers.dart'; import '../invariant.dart'; import 'boolean_point_in_polygon.dart'; @@ -151,8 +153,8 @@ isLineOnLine(LineString lineString1, LineString lineString2) { } isLineInPoly(LineString linestring, Polygon polygon) { - var polyBbox = calcBbox(polygon); - var lineBbox = calcBbox(linestring); + var polyBbox = bbox(polygon); + var lineBbox = bbox(linestring); if (!doBBoxOverlap(polyBbox, lineBbox)) { return false; } @@ -190,8 +192,8 @@ isLineInPoly(LineString linestring, Polygon polygon) { * @returns {boolean} true/false */ isPolyInPoly(Polygon geometry1, GeometryObject geometry2) { - var poly1Bbox = calcBbox(geometry1); - var poly2Bbox = calcBbox(geometry2); + var poly1Bbox = bbox(geometry1); + var poly2Bbox = bbox(geometry2); if (!doBBoxOverlap(poly2Bbox, poly1Bbox)) { return false; } From e648af74be7adc5f516d1449661c84068c54fe28 Mon Sep 17 00:00:00 2001 From: armantorkzaban Date: Sat, 25 Jun 2022 21:26:39 +0200 Subject: [PATCH 30/82] rhumb_bearing --- lib/src/rhumb_bearing.dart | 180 +++++------------------- test/components/rhumb_bearing_test.dart | 1 + 2 files changed, 40 insertions(+), 141 deletions(-) create mode 100644 test/components/rhumb_bearing_test.dart diff --git a/lib/src/rhumb_bearing.dart b/lib/src/rhumb_bearing.dart index 28de3887..968cb3a7 100644 --- a/lib/src/rhumb_bearing.dart +++ b/lib/src/rhumb_bearing.dart @@ -1,166 +1,64 @@ // https://en.wikipedia.org/wiki/Rhumb_line import 'package:turf/src/invariant.dart'; - +import 'dart:math' as math; import '../helpers.dart'; - -/** - * Takes two {@link Point|points} and finds the bearing angle between them along a Rhumb line - * i.e. the angle measured in degrees start the north line (0 degrees) - * - * @name rhumbBearing - * @param {Coord} start starting Point - * @param {Coord} end ending Point - * @param {Object} [options] Optional parameters - * @param {boolean} [options.final=false] calculates the final bearing if true - * @returns {number} bearing from north in decimal degrees, between -180 and 180 degrees (positive clockwise) - * @example - * var point1 = turf.point([-75.343, 39.984], {"marker-color": "#F00"}); - * var point2 = turf.point([-75.534, 39.123], {"marker-color": "#00F"}); - * - * var bearing = turf.rhumbBearing(point1, point2); - * - * //addToMap - * var addToMap = [point1, point2]; - * point1.properties.bearing = bearing; - * point2.properties.bearing = bearing; - */ - num rhumbBearing( - Position start, - Position end, - { final?: boolean } -{ var bear360; - if (options.final) { - bear360 = calculateRhumbBearing(getCoord(end), getCoord(start)); - } else { - bear360 = calculateRhumbBearing(getCoord(start), getCoord(end)); - } - - const bear180 = bear360 > 180 ? -(360 - bear360) : bear360; - - return bear180; -} - -/** - * Returns the bearing from ‘this’ point to destination point along a rhumb line. - * Adapted from Geodesy: https://github.com/chrisveness/geodesy/blob/master/latlon-spherical.js - * - * @private - * @param {Array} from - origin point. - * @param {Array} to - destination point. - * @returns {number} Bearing in degrees from north. - * @example - * var p1 = new LatLon(51.127, 1.338); - * var p2 = new LatLon(50.964, 1.853); - * var d = p1.rhumbBearingTo(p2); // 116.7 m - */ - calculateRhumbBearing(Position from, Position to) { - // φ => phi - // Δλ => deltaLambda - // Δψ => deltaPsi - // θ => theta - const phi1 = degreesToRadians(from[1]); - const phi2 = degreesToRadians(to[1]); - let deltaLambda = degreesToRadians(to[0] - from[0]); - // if deltaLambdaon over 180° take shorter rhumb line across the anti-meridian: - if (deltaLambda > Math.PI) { - deltaLambda -= 2 * Math.PI; - } - if (deltaLambda < -Math.PI) { - deltaLambda += 2 * Math.PI; - } - - const deltaPsi = Math.log( - Math.tan(phi2 / 2 + Math.PI / 4) / Math.tan(phi1 / 2 + Math.PI / 4) - ); - - const theta = Math.atan2(deltaLambda, deltaPsi); - - return (radiansToDegrees(theta) + 360) % 360; -} - - - -/** - * // https://en.wikipedia.org/wiki/Rhumb_line -import { Coord, degreesToRadians, radiansToDegrees } from "@turf/helpers"; -import { getCoord } from "@turf/invariant"; - -/** - * Takes two {@link Point|points} and finds the bearing angle between them along a Rhumb line - * i.e. the angle measured in degrees start the north line (0 degrees) - * - * @name rhumbBearing - * @param {Coord} start starting Point - * @param {Coord} end ending Point - * @param {Object} [options] Optional parameters - * @param {boolean} [options.final=false] calculates the final bearing if true - * @returns {number} bearing from north in decimal degrees, between -180 and 180 degrees (positive clockwise) - * @example - * var point1 = turf.point([-75.343, 39.984], {"marker-color": "#F00"}); - * var point2 = turf.point([-75.534, 39.123], {"marker-color": "#00F"}); - * - * var bearing = turf.rhumbBearing(point1, point2); - * - * //addToMap - * var addToMap = [point1, point2]; - * point1.properties.bearing = bearing; - * point2.properties.bearing = bearing; - */ -function rhumbBearing( - start: Coord, - end: Coord, - options: { final?: boolean } = {} -): number { - let bear360; - if (options.final) { +/// Takes two [Point] and finds the bearing angle between them along a Rhumb line +/// i.e. the angle measured in degrees start the north line (0 degrees) +/// [kFinal] calculates the final bearing if true +/// Returns bearing from north in decimal degrees, between -180 and 180 degrees (positive clockwise) +/// example: +/// ```dart +/// var point1 = Feature(geometry: Point(coordinates: Position.of([-75.343, 39.984])), properties: {"marker-color": "#F00"}); +/// var point2 = Feature(geometry: Point(coordinates: Position.of([-75.534, 39.123])), properties: {"marker-color": "#00F"}); +/// var bearing = rhumbBearing(point1.geometry, point2.geometry); +/// //addToMap +/// var addToMap = [point1, point2]; +/// point1.properties['bearing'] = bearing; +/// point2.properties['bearing'] = bearing; +/// ``` +num rhumbBearing(Point start, Point end, {bool? kFinal}) { + num bear360; + if (kFinal != null) { bear360 = calculateRhumbBearing(getCoord(end), getCoord(start)); } else { bear360 = calculateRhumbBearing(getCoord(start), getCoord(end)); } - const bear180 = bear360 > 180 ? -(360 - bear360) : bear360; + var bear180 = bear360 > 180 ? -(360 - bear360) : bear360; return bear180; } -/** - * Returns the bearing from ‘this’ point to destination point along a rhumb line. - * Adapted from Geodesy: https://github.com/chrisveness/geodesy/blob/master/latlon-spherical.js - * - * @private - * @param {Array} from - origin point. - * @param {Array} to - destination point. - * @returns {number} Bearing in degrees from north. - * @example - * var p1 = new LatLon(51.127, 1.338); - * var p2 = new LatLon(50.964, 1.853); - * var d = p1.rhumbBearingTo(p2); // 116.7 m - */ -function calculateRhumbBearing(from: number[], to: number[]) { +/// Returns the bearing from ‘this’ [Point] to destination [Point] along a rhumb line. +/// Adapted from Geodesy: https://github.com/chrisveness/geodesy/blob/master/latlon-spherical.js +/// Returns Bearing in degrees from north. +/// example +/// ```dart +/// var p1 = Position.named(lng: 51.127, lat: 1.338); +/// var p2 = Position.named(lng: 50.964, lat: 1.853); +/// var d = p1.rhumbBearingTo(p2); // 116.7 m +/// ``` +num calculateRhumbBearing(Position from, Position to) { // φ => phi // Δλ => deltaLambda // Δψ => deltaPsi // θ => theta - const phi1 = degreesToRadians(from[1]); - const phi2 = degreesToRadians(to[1]); - let deltaLambda = degreesToRadians(to[0] - from[0]); + num phi1 = degreesToRadians(from.lat); + num phi2 = degreesToRadians(to.lng); + num deltaLambda = degreesToRadians(to.lat - from.lat); // if deltaLambdaon over 180° take shorter rhumb line across the anti-meridian: - if (deltaLambda > Math.PI) { - deltaLambda -= 2 * Math.PI; + if (deltaLambda > math.pi) { + deltaLambda -= 2 * math.pi; } - if (deltaLambda < -Math.PI) { - deltaLambda += 2 * Math.PI; + if (deltaLambda < -math.pi) { + deltaLambda += 2 * math.pi; } - const deltaPsi = Math.log( - Math.tan(phi2 / 2 + Math.PI / 4) / Math.tan(phi1 / 2 + Math.PI / 4) - ); + double deltaPsi = math + .log(math.tan(phi2 / 2 + math.pi / 4) / math.tan(phi1 / 2 + math.pi / 4)); - const theta = Math.atan2(deltaLambda, deltaPsi); + double theta = math.atan2(deltaLambda, deltaPsi); return (radiansToDegrees(theta) + 360) % 360; } - -export default rhumbBearing; - */ \ No newline at end of file diff --git a/test/components/rhumb_bearing_test.dart b/test/components/rhumb_bearing_test.dart new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/test/components/rhumb_bearing_test.dart @@ -0,0 +1 @@ + From d2cd51d993620bca8a759e1b2d8ad9bcde0d7515 Mon Sep 17 00:00:00 2001 From: armantorkzaban Date: Sat, 25 Jun 2022 22:45:14 +0200 Subject: [PATCH 31/82] rhumb_bearing\'s test - incomplete --- test/components/rhumb_bearing_test.dart | 45 ++++++++++++++++ test/examples/rhumb_bearing/in/pair1.geojson | 25 +++++++++ test/examples/rhumb_bearing/out/pair1.geojson | 53 +++++++++++++++++++ test/examples/rhumb_bearing/out/pair1.json | 4 ++ 4 files changed, 127 insertions(+) create mode 100644 test/examples/rhumb_bearing/in/pair1.geojson create mode 100644 test/examples/rhumb_bearing/out/pair1.geojson create mode 100644 test/examples/rhumb_bearing/out/pair1.json diff --git a/test/components/rhumb_bearing_test.dart b/test/components/rhumb_bearing_test.dart index 8b137891..84c9b929 100644 --- a/test/components/rhumb_bearing_test.dart +++ b/test/components/rhumb_bearing_test.dart @@ -1 +1,46 @@ +import 'dart:convert'; +import 'dart:io'; +import 'package:test/test.dart'; +import 'package:turf/helpers.dart'; +import 'package:turf/src/rhumb_bearing.dart'; + +main() { + group( + '', + () { + Directory inDir = Directory('./test/examples/rhumb_bearing/in'); + for (var file in inDir.listSync(recursive: true)) { + if (file is File && file.path.endsWith('.geojson')) { + test( + file.path, + () { + var inSource = file.readAsStringSync(); + var inGeom = GeoJSONObject.fromJson(jsonDecode(inSource)); + + var start = (inGeom as FeatureCollection).features[0]; + var end = inGeom.features[1]; + var initialBearing = + rhumbBearing(start.geometry as Point, end.geometry as Point); + var finalBearing = rhumbBearing( + start.geometry as Point, end.geometry as Point, + kFinal: true); + var result = { + "initialBearing": initialBearing, + "finalBearing": finalBearing, + }; + Directory outDir = Directory('./test/examples/rhumb_bearing/out'); + + for (var file in outDir.listSync(recursive: true)) { + if (file is File && file.path.endsWith('.json')) { + var outSource = jsonDecode(file.readAsStringSync()); + // expect(result, outSource); + } + } + }, + ); + } + } + }, + ); +} diff --git a/test/examples/rhumb_bearing/in/pair1.geojson b/test/examples/rhumb_bearing/in/pair1.geojson new file mode 100644 index 00000000..501a6042 --- /dev/null +++ b/test/examples/rhumb_bearing/in/pair1.geojson @@ -0,0 +1,25 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": { + "marker-color": "#F00" + }, + "geometry": { + "type": "Point", + "coordinates": [-75, 45] + } + }, + { + "type": "Feature", + "properties": { + "marker-color": "#00F" + }, + "geometry": { + "type": "Point", + "coordinates": [20, 60] + } + } + ] +} diff --git a/test/examples/rhumb_bearing/out/pair1.geojson b/test/examples/rhumb_bearing/out/pair1.geojson new file mode 100644 index 00000000..e349a60d --- /dev/null +++ b/test/examples/rhumb_bearing/out/pair1.geojson @@ -0,0 +1,53 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": { + "marker-color": "#F00" + }, + "geometry": { + "type": "Point", + "coordinates": [-75, 45] + } + }, + { + "type": "Feature", + "properties": { + "marker-color": "#00F" + }, + "geometry": { + "type": "Point", + "coordinates": [20, 60] + } + }, + { + "type": "Feature", + "properties": { + "stroke": "#F00", + "stroke-width": 6 + }, + "geometry": { + "type": "LineString", + "coordinates": [ + [-75, 45], + [-66.10068737769872, 51.79325008492101] + ] + } + }, + { + "type": "Feature", + "properties": { + "stroke": "#00F", + "stroke-width": 6 + }, + "geometry": { + "type": "LineString", + "coordinates": [ + [20, 60], + [2.3844816279733956, 63.440396381483744] + ] + } + } + ] +} diff --git a/test/examples/rhumb_bearing/out/pair1.json b/test/examples/rhumb_bearing/out/pair1.json new file mode 100644 index 00000000..cb787128 --- /dev/null +++ b/test/examples/rhumb_bearing/out/pair1.json @@ -0,0 +1,4 @@ +{ + "initialBearing": 75.28061364784332, + "finalBearing": -104.7193863521567 +} From a6d91b0af9f105cafe47834245b15ec233a5504d Mon Sep 17 00:00:00 2001 From: armantorkzaban Date: Sun, 26 Jun 2022 22:27:19 +0200 Subject: [PATCH 32/82] rhumb_bearing's test - done, added to lib/bearing --- lib/bearing.dart | 1 + lib/src/rhumb_bearing.dart | 96 +++++++++++++++++++++++-- test/components/rhumb_bearing_test.dart | 56 +++++++++++++-- 3 files changed, 143 insertions(+), 10 deletions(-) diff --git a/lib/bearing.dart b/lib/bearing.dart index 9b3eeee4..64c1d498 100644 --- a/lib/bearing.dart +++ b/lib/bearing.dart @@ -1,3 +1,4 @@ library turf_bearing; export 'src/bearing.dart'; +export 'src/rhumb_bearing.dart'; diff --git a/lib/src/rhumb_bearing.dart b/lib/src/rhumb_bearing.dart index 968cb3a7..7cfee509 100644 --- a/lib/src/rhumb_bearing.dart +++ b/lib/src/rhumb_bearing.dart @@ -5,7 +5,7 @@ import '../helpers.dart'; /// Takes two [Point] and finds the bearing angle between them along a Rhumb line /// i.e. the angle measured in degrees start the north line (0 degrees) -/// [kFinal] calculates the final bearing if true +/// [kFinal] calculates the final bearing if true. /// Returns bearing from north in decimal degrees, between -180 and 180 degrees (positive clockwise) /// example: /// ```dart @@ -17,9 +17,9 @@ import '../helpers.dart'; /// point1.properties['bearing'] = bearing; /// point2.properties['bearing'] = bearing; /// ``` -num rhumbBearing(Point start, Point end, {bool? kFinal}) { +num rhumbBearing(Point start, Point end, {bool kFinal = false}) { num bear360; - if (kFinal != null) { + if (kFinal) { bear360 = calculateRhumbBearing(getCoord(end), getCoord(start)); } else { bear360 = calculateRhumbBearing(getCoord(start), getCoord(end)); @@ -45,9 +45,9 @@ num calculateRhumbBearing(Position from, Position to) { // Δψ => deltaPsi // θ => theta num phi1 = degreesToRadians(from.lat); - num phi2 = degreesToRadians(to.lng); - num deltaLambda = degreesToRadians(to.lat - from.lat); - // if deltaLambdaon over 180° take shorter rhumb line across the anti-meridian: + num phi2 = degreesToRadians(to.lat); + num deltaLambda = degreesToRadians(to.lng - from.lng); + // if deltaLambda over 180° take shorter rhumb line across the anti-meridian: if (deltaLambda > math.pi) { deltaLambda -= 2 * math.pi; } @@ -62,3 +62,87 @@ num calculateRhumbBearing(Position from, Position to) { return (radiansToDegrees(theta) + 360) % 360; } + +/** + * // https://en.wikipedia.org/wiki/Rhumb_line +import { Coord, degreesToRadians, radiansToDegrees } from "@turf/helpers"; +import { getCoord } from "@turf/invariant"; + +/** + * Takes two {@link Point|points} and finds the bearing angle between them along a Rhumb line + * i.e. the angle measured in degrees start the north line (0 degrees) + * + * @name rhumbBearing + * @param {Coord} start starting Point + * @param {Coord} end ending Point + * @param {Object} [options] Optional parameters + * @param {boolean} [options.final=false] calculates the final bearing if true + * @returns {number} bearing from north in decimal degrees, between -180 and 180 degrees (positive clockwise) + * @example + * var point1 = turf.point([-75.343, 39.984], {"marker-color": "#F00"}); + * var point2 = turf.point([-75.534, 39.123], {"marker-color": "#00F"}); + * + * var bearing = turf.rhumbBearing(point1, point2); + * + * //addToMap + * var addToMap = [point1, point2]; + * point1.properties.bearing = bearing; + * point2.properties.bearing = bearing; + */ +function rhumbBearing( + start: Coord, + end: Coord, + options: { final?: boolean } = {} +): number { + let bear360; + if (options.final) { + bear360 = calculateRhumbBearing(getCoord(end), getCoord(start)); + } else { + bear360 = calculateRhumbBearing(getCoord(start), getCoord(end)); + } + + const bear180 = bear360 > 180 ? -(360 - bear360) : bear360; + + return bear180; +} + +/** + * Returns the bearing from ‘this’ point to destination point along a rhumb line. + * Adapted from Geodesy: https://github.com/chrisveness/geodesy/blob/master/latlon-spherical.js + * + * @private + * @param {Array} from - origin point. + * @param {Array} to - destination point. + * @returns {number} Bearing in degrees from north. + * @example + * var p1 = new LatLon(51.127, 1.338); + * var p2 = new LatLon(50.964, 1.853); + * var d = p1.rhumbBearingTo(p2); // 116.7 m + */ +function calculateRhumbBearing(from: number[], to: number[]) { + // φ => phi + // Δλ => deltaLambda + // Δψ => deltaPsi + // θ => theta + const phi1 = degreesToRadians(from[1]); + const phi2 = degreesToRadians(to[1]); + let deltaLambda = degreesToRadians(to[0] - from[0]); + // if deltaLambdaon over 180° take shorter rhumb line across the anti-meridian: + if (deltaLambda > Math.PI) { + deltaLambda -= 2 * Math.PI; + } + if (deltaLambda < -Math.PI) { + deltaLambda += 2 * Math.PI; + } + + const deltaPsi = Math.log( + Math.tan(phi2 / 2 + Math.PI / 4) / Math.tan(phi1 / 2 + Math.PI / 4) + ); + + const theta = Math.atan2(deltaLambda, deltaPsi); + + return (radiansToDegrees(theta) + 360) % 360; +} + +export default rhumbBearing; + */ \ No newline at end of file diff --git a/test/components/rhumb_bearing_test.dart b/test/components/rhumb_bearing_test.dart index 84c9b929..6b3e17e5 100644 --- a/test/components/rhumb_bearing_test.dart +++ b/test/components/rhumb_bearing_test.dart @@ -26,15 +26,15 @@ main() { start.geometry as Point, end.geometry as Point, kFinal: true); var result = { - "initialBearing": initialBearing, - "finalBearing": finalBearing, + 'initialBearing': initialBearing, + 'finalBearing': finalBearing, }; - Directory outDir = Directory('./test/examples/rhumb_bearing/out'); + Directory outDir = Directory('./test/examples/rhumb_bearing/out'); for (var file in outDir.listSync(recursive: true)) { if (file is File && file.path.endsWith('.json')) { var outSource = jsonDecode(file.readAsStringSync()); - // expect(result, outSource); + expect(result, outSource); } } }, @@ -44,3 +44,51 @@ main() { }, ); } + +/* +const fs = require("fs"); +const path = require("path"); +const test = require("tape"); +const load = require("load-json-file"); +const write = require("write-json-file"); +const { point } = require("@turf/helpers"); +const rhumbBearing = require("./index").default; + +const directories = { + in: path.join(__dirname, "test", "in") + path.sep, + out: path.join(__dirname, "test", "out") + path.sep, +}; + +let fixtures = fs.readdirSync(directories.in).map((filename) => { + return { + filename, + name: path.parse(filename).name, + geojson: load.sync(directories.in + filename), + }; +}); + +test("bearing", (t) => { + fixtures.forEach((fixture) => { + const name = fixture.name; + const geojson = fixture.geojson; + + const start = geojson.features[0]; + const end = geojson.features[1]; + + const initialBearing = rhumbBearing(start, end); + const finalBearing = rhumbBearing(start, end, { final: true }); + + const result = { + initialBearing: initialBearing, + finalBearing: finalBearing, + }; + if (process.env.REGEN) write.sync(directories.out + name + ".json", result); + t.deepEqual(load.sync(directories.out + name + ".json"), result, name); + }); + + t.throws(() => { + rhumbBearing(point([12, -54]), "point"); + }, "invalid point"); + t.end(); +}); +*/ \ No newline at end of file From ace18bcb5139dca1af88f05a5f96def99eb76334 Mon Sep 17 00:00:00 2001 From: armantorkzaban Date: Sun, 26 Jun 2022 23:17:27 +0200 Subject: [PATCH 33/82] boolean_contains, boolean_parallel, IP --- lib/src/booleans/boolean_contains.dart | 92 +++++++++++++------------- lib/src/booleans/boolean_parallel.dart | 83 ++++++++++------------- 2 files changed, 82 insertions(+), 93 deletions(-) diff --git a/lib/src/booleans/boolean_contains.dart b/lib/src/booleans/boolean_contains.dart index f4899bbc..832511da 100644 --- a/lib/src/booleans/boolean_contains.dart +++ b/lib/src/booleans/boolean_contains.dart @@ -1,75 +1,75 @@ import 'package:turf/turf.dart'; -import '../invariant.dart'; import 'boolean_point_in_polygon.dart'; import 'boolean_point_on_line.dart'; -/** - * Boolean-contains returns True if the second geometry is completely contained by the first geometry. - * The interiors of both geometries must intersect and, the interior and boundary of the secondary (geometry b) - * must not intersect the exterior of the primary (geometry a). - * Boolean-contains returns the exact opposite result of the `@turf/boolean-within`. - * - * @name booleanContains - * @param {Geometry|Feature} feature1 GeoJSON Feature or Geometry - * @param {Geometry|Feature} feature2 GeoJSON Feature or Geometry - * @returns {boolean} true/false - * @example - * var line = turf.lineString([[1, 1], [1, 2], [1, 3], [1, 4]]); - * var point = turf.point([1, 2]); - * - * turf.booleanContains(line, point); - * //=true - */ +/// Boolean-contains returns True if the second geometry is completely contained by the first geometry. +/// The interiors of both geometries must intersect and, the interior and boundary of the secondary (geometry b) +/// must not intersect the exterior of the primary (geometry a). +/// Boolean-contains returns the exact opposite result of the `@turf/boolean-within`. +/// @name booleanContains +/// @param {Geometry|Feature} feature1 GeoJSON Feature or Geometry +/// @param {Geometry|Feature} feature2 GeoJSON Feature or Geometry +/// @returns {boolean} true/false +/// example: +/// ```dart +/// var line = turf.lineString([[1, 1], [1, 2], [1, 3], [1, 4]]); +/// var point = turf.point([1, 2]); +/// turf.booleanContains(line, point); +/// //=true +/// ``` booleanContains(GeoJSONObject feature1, GeoJSONObject feature2) { - var geom1 = getGeom(feature1); - var geom2 = getGeom(feature2); - var type1 = geom1.runtimeType; - var type2 = geom2.runtimeType; - var coords1 = geom1.coordinates; - var coords2 = geom2.coordinates; + var geom1 = feature1 is Feature ? feature1.geometry : feature1; + var geom2 = feature2 is Feature ? feature2.geometry : feature2; + var type1 = geom1!.type; + var type2 = geom2!.type; + var coords1 = (geom1 as GeometryType).coordinates; + var coords2 = (geom2 as GeometryType).coordinates; switch (type1) { - case Point: + case GeoJSONObjectType.point: switch (type2) { - case Point: + case GeoJSONObjectType.point: return compareCoords(coords1, coords2); default: throw UnsupportedError( "{feature2 $type2 geometry not supported}"); } - case MultiPoint: + case GeoJSONObjectType.multiPoint: switch (type2) { - case Point: - return isPointInMultiPoint(geom1, geom2); - case MultiPoint: - return isMultiPointInMultiPoint(geom1, geom2); + case GeoJSONObjectType.point: + return isPointInMultiPoint(geom1 as MultiPoint, geom2 as Point); + case GeoJSONObjectType.multiPoint: + return isMultiPointInMultiPoint( + geom1 as MultiPoint, geom2 as MultiPoint); default: throw UnsupportedError( "{feature2 $type2 geometry not supported}"); } - case LineString: + case GeoJSONObjectType.lineString: switch (type2) { - case Point: - return booleanPointOnLine(geom2, geom1, ignoreEndVertices: true); - case LineString: - return isLineOnLine(geom1, geom2); - case MultiPoint: - return isMultiPointOnLine(geom1, geom2); + case GeoJSONObjectType.point: + return booleanPointOnLine(geom2 as Point, geom1 as LineString, + ignoreEndVertices: true); + case GeoJSONObjectType.lineString: + return isLineOnLine(geom1 as LineString, geom2 as LineString); + case GeoJSONObjectType.multiPoint: + return isMultiPointOnLine(geom1 as LineString, geom2 as MultiPoint); default: throw UnsupportedError( "{feature2 $type2 geometry not supported}"); } - case Polygon: + case GeoJSONObjectType.polygon: switch (type2) { - case Point: - return booleanPointInPolygon(geom2, geom1, ignoreBoundary: true); - case LineString: - return isLineInPoly(geom1, geom2); - case Polygon: + case GeoJSONObjectType.point: + return booleanPointInPolygon((geom2 as Point).coordinates, geom1, + ignoreBoundary: true); + case GeoJSONObjectType.lineString: + return isLineInPoly(geom1 as Polygon, geom2 as LineString); + case GeoJSONObjectType.polygon: return isPolyInPoly(geom1, geom2); - case MultiPoint: - return isMultiPointInPoly(geom1, geom2); + case GeoJSONObjectType.multiPoint: + return isMultiPointInPoly(geom1 as Polygon, geom2 as MultiPoint); default: throw UnsupportedError( "{feature2 $type2 geometry not supported}"); diff --git a/lib/src/booleans/boolean_parallel.dart b/lib/src/booleans/boolean_parallel.dart index aeaa12b2..4783f4a4 100644 --- a/lib/src/booleans/boolean_parallel.dart +++ b/lib/src/booleans/boolean_parallel.dart @@ -1,64 +1,53 @@ +import 'package:turf/src/rhumb_bearing.dart'; + import '../../helpers.dart'; import '../../line_segment.dart'; import '../clean_coords.dart'; -/** - * Boolean-Parallel returns True if each segment of `line1` is parallel to the correspondent segment of `line2` - * - * @name booleanParallel - * @param {Geometry|Feature} line1 GeoJSON Feature or Geometry - * @param {Geometry|Feature} line2 GeoJSON Feature or Geometry - * @returns {boolean} true/false if the lines are parallel - * @example - * var line1 = turf.lineString([[0, 0], [0, 1]]); - * var line2 = turf.lineString([[1, 0], [1, 1]]); - * - * turf.booleanParallel(line1, line2); - * //=true - */ +/// Returns True if each segment of `line1` is parallel to the correspondent segment of `line2` +/// example: +/// ```dart +/// var line1 = LineString(coordinates:[Position.of([0, 0]), Position.of([0, 1])]); +/// var line2 = LineString(coordinates:[Position.of([1, 0]), Position.of([1, 1])]); +/// booleanParallel(line1, line2); +/// //=true bool booleanParallel(GeoJSONObject line1, GeoJSONObject line2) { - var type1 = getType(line1, "line1"); - if (type1 != "LineString") throw Exception("line1 must be a LineString"); - var type2 = getType(line2, "line2"); - if (type2 != "LineString") throw Exception("line2 must be a LineString"); - - var segments1 = lineSegment(cleanCoords(line1)).features; - var segments2 = lineSegment(cleanCoords(line2)).features; + var type1 = _getType(line1, "line1"); + if (type1 != GeoJSONObjectType.lineString) { + throw Exception("line1 must be a LineString"); + } + var type2 = _getType(line2, "line2"); + if (type2 != GeoJSONObjectType.lineString) { + throw Exception("line2 must be a LineString"); + } + FeatureCollection segments1 = lineSegment(cleanCoords(line1)); + FeatureCollection segments2 = lineSegment(cleanCoords(line2)); - for (var i = 0; i < segments1.length; i++) { - var segment1 = segments1[i].geometry!.coordinates; - if (!segments2[i]) break; - var segment2 = segments2[i].geometry!.coordinates; - if (!isParallel(segment1, segment2)) return false; + for (var i = 0; i < segments1.features.length; i++) { + var segment1 = segments1.features[i].geometry!.coordinates; + var seg2i = segments2.features.elementAt(i); + if (seg2i is RangeError) break; + var segment2 = segments2.features[i].geometry!.coordinates; + if (!_isParallel(segment1, segment2)) return false; } return true; } -/** - * Compares slopes and return result - * - * @private - * @param {Geometry|Feature} segment1 Geometry or Feature - * @param {Geometry|Feature} segment2 Geometry or Feature - * @returns {boolean} if slopes are equal - */ -isParallel(List segment1, List segment2) { - var slope1 = bearingToAzimuth(rhumbBearing(segment1[0], segment1[1])); - var slope2 = bearingToAzimuth(rhumbBearing(segment2[0], segment2[1])); +/// Compares slopes and returns result +/// @param {Geometry|Feature} segment1 Geometry or Feature +/// @param {Geometry|Feature} segment2 Geometry or Feature +bool _isParallel(List segment1, List segment2) { + var slope1 = bearingToAzimuth(rhumbBearing( + Point(coordinates: segment1[0]), Point(coordinates: segment1[1]))); + var slope2 = bearingToAzimuth(rhumbBearing( + Point(coordinates: segment2[0]), Point(coordinates: segment2[1]))); return slope1 == slope2; } -/** - * Returns Feature's type - * - * @private - * @param {Geometry|Feature} geojson Geometry or Feature - * @param {string} name of the variable - * @returns {string} Feature's type - */ -getType(GeoJSONObject geojson, String name) { +/// Returns Feature's type +GeoJSONObjectType _getType(GeoJSONObject geojson, String name) { if ((geojson as Feature).geometry != null) { - return geojson.geometry.runtimeType; + return geojson.geometry!.type; } if (geojson.runtimeType is GeometryType) { return geojson.type; From ed2ec1a0ec3b49f08ba3ee4a7e2bfeb118714be1 Mon Sep 17 00:00:00 2001 From: armantorkzaban Date: Fri, 1 Jul 2022 21:59:46 +0200 Subject: [PATCH 34/82] working on contain - removed usages of runtimeType --- lib/src/booleans/boolean_contains.dart | 79 ++++++------------ lib/src/booleans/boolean_disjoint.dart | 32 +++---- lib/src/booleans/boolean_equal.dart | 47 +++++------ lib/src/booleans/boolean_overlap.dart | 4 +- lib/src/booleans/boolean_parallel.dart | 3 +- .../booleans/boolean_point_in_polygon.dart | 67 +++++++-------- lib/src/booleans/boolean_point_on_line.dart | 2 +- lib/src/clean_coords.dart | 51 ++++++----- lib/src/invariant.dart | 32 +++---- lib/src/line_intersect.dart | 10 +-- pubspec.yaml | 10 ++- test/booleans/contains_test.dart | 61 ++++++++++++++ .../diagrams/esri-contains.gif | Bin 0 -> 34103 bytes .../LineIsNotContainedByLine.geojson | 30 +++++++ .../LineIsNotContainedByPolygon.geojson | 33 ++++++++ ...ineIsNotContainedByPolygonBoundary.geojson | 33 ++++++++ .../MultiPointsIsNotContainedByLine.geojson | 30 +++++++ ...intsOnLineEndsIsNotContainedByLine.geojson | 29 +++++++ ...ltiPointIsNotContainedByMultiPoint.geojson | 28 +++++++ ...lOnBoundaryIsNotContainedByPolygon.geojson | 32 +++++++ .../MultiPointIsNotContainedByPolygon.geojson | 33 ++++++++ .../PointIsNotContainedByLine.geojson | 26 ++++++ ...ntIsNotContainedByLineBecauseOnEnd.geojson | 26 ++++++ .../PointOnEndIsContainedByLinestring.geojson | 26 ++++++ .../PointIsNotContainedBYMultiPoint.geojson | 24 ++++++ .../PointIsNotContainedByPolygon.geojson | 29 +++++++ .../Polygon/PointOnPolygonBoundary.geojson | 29 +++++++ .../LineString/issue-#1201-false.geojson | 40 +++++++++ .../Polygon/Polygon/Polygon-Polygon.geojson | 37 ++++++++ .../Polygon/Polygon/Polygon-Polygon2.geojson | 47 +++++++++++ .../LineString/LineIsContainedByLine.geojson | 30 +++++++ .../LineString/LinesExactlySame.geojson | 31 +++++++ .../Polygon/LineIsContainedByPolygon.geojson | 33 ++++++++ ...nedByPolygonWithNoInternalVertices.geojson | 32 +++++++ .../MultipointsIsContainedByLine.geojson | 29 +++++++ .../MultiPointsContainedByMultiPoints.geojson | 28 +++++++ .../MultiPoint/MultiPointsEqual.geojson | 29 +++++++ ...iPointIsContainedByPolygonBoundary.geojson | 32 +++++++ .../LineString/PointIsContainedByLine.geojson | 26 ++++++ .../PointIsContainedByMultiPoint.geojson | 24 ++++++ .../PointInsidePolygonBoundary.geojson | 29 +++++++ .../LineString/issue-#1201-true.geojson | 40 +++++++++ .../Polygon/PolygonExactSameShape.geojson | 41 +++++++++ .../PolygonIsContainedByPolygon.geojson | 36 ++++++++ 44 files changed, 1178 insertions(+), 192 deletions(-) create mode 100644 test/booleans/contains_test.dart create mode 100644 test/examples/boolean_contains/diagrams/esri-contains.gif create mode 100644 test/examples/boolean_contains/test/false/LineString/LineString/LineIsNotContainedByLine.geojson create mode 100644 test/examples/boolean_contains/test/false/LineString/Polygon/LineIsNotContainedByPolygon.geojson create mode 100644 test/examples/boolean_contains/test/false/LineString/Polygon/LineIsNotContainedByPolygonBoundary.geojson create mode 100644 test/examples/boolean_contains/test/false/MultiPoint/LineString/MultiPointsIsNotContainedByLine.geojson create mode 100644 test/examples/boolean_contains/test/false/MultiPoint/LineString/MultiPointsOnLineEndsIsNotContainedByLine.geojson create mode 100644 test/examples/boolean_contains/test/false/MultiPoint/MultiPoint/MultiPointIsNotContainedByMultiPoint.geojson create mode 100644 test/examples/boolean_contains/test/false/MultiPoint/Polygon/MultiPointAllOnBoundaryIsNotContainedByPolygon.geojson create mode 100644 test/examples/boolean_contains/test/false/MultiPoint/Polygon/MultiPointIsNotContainedByPolygon.geojson create mode 100644 test/examples/boolean_contains/test/false/Point/LineString/PointIsNotContainedByLine.geojson create mode 100644 test/examples/boolean_contains/test/false/Point/LineString/PointIsNotContainedByLineBecauseOnEnd.geojson create mode 100644 test/examples/boolean_contains/test/false/Point/LineString/PointOnEndIsContainedByLinestring.geojson create mode 100644 test/examples/boolean_contains/test/false/Point/MultiPoint/PointIsNotContainedBYMultiPoint.geojson create mode 100644 test/examples/boolean_contains/test/false/Point/Polygon/PointIsNotContainedByPolygon.geojson create mode 100644 test/examples/boolean_contains/test/false/Point/Polygon/PointOnPolygonBoundary.geojson create mode 100644 test/examples/boolean_contains/test/false/Polygon/LineString/issue-#1201-false.geojson create mode 100644 test/examples/boolean_contains/test/false/Polygon/Polygon/Polygon-Polygon.geojson create mode 100644 test/examples/boolean_contains/test/false/Polygon/Polygon/Polygon-Polygon2.geojson create mode 100644 test/examples/boolean_contains/test/true/LineString/LineString/LineIsContainedByLine.geojson create mode 100644 test/examples/boolean_contains/test/true/LineString/LineString/LinesExactlySame.geojson create mode 100644 test/examples/boolean_contains/test/true/LineString/Polygon/LineIsContainedByPolygon.geojson create mode 100644 test/examples/boolean_contains/test/true/LineString/Polygon/LineIsContainedByPolygonWithNoInternalVertices.geojson create mode 100644 test/examples/boolean_contains/test/true/MultiPoint/LineString/MultipointsIsContainedByLine.geojson create mode 100644 test/examples/boolean_contains/test/true/MultiPoint/MultiPoint/MultiPointsContainedByMultiPoints.geojson create mode 100644 test/examples/boolean_contains/test/true/MultiPoint/MultiPoint/MultiPointsEqual.geojson create mode 100644 test/examples/boolean_contains/test/true/MultiPoint/Polygon/MultiPointIsContainedByPolygonBoundary.geojson create mode 100644 test/examples/boolean_contains/test/true/Point/LineString/PointIsContainedByLine.geojson create mode 100644 test/examples/boolean_contains/test/true/Point/MultiPoint/PointIsContainedByMultiPoint.geojson create mode 100644 test/examples/boolean_contains/test/true/Point/Polygon/PointInsidePolygonBoundary.geojson create mode 100644 test/examples/boolean_contains/test/true/Polygon/LineString/issue-#1201-true.geojson create mode 100644 test/examples/boolean_contains/test/true/Polygon/Polygon/PolygonExactSameShape.geojson create mode 100644 test/examples/boolean_contains/test/true/Polygon/Polygon/PolygonIsContainedByPolygon.geojson diff --git a/lib/src/booleans/boolean_contains.dart b/lib/src/booleans/boolean_contains.dart index 832511da..a2fe9e97 100644 --- a/lib/src/booleans/boolean_contains.dart +++ b/lib/src/booleans/boolean_contains.dart @@ -3,19 +3,16 @@ import 'package:turf/turf.dart'; import 'boolean_point_in_polygon.dart'; import 'boolean_point_on_line.dart'; -/// Boolean-contains returns True if the second geometry is completely contained by the first geometry. -/// The interiors of both geometries must intersect and, the interior and boundary of the secondary (geometry b) -/// must not intersect the exterior of the primary (geometry a). -/// Boolean-contains returns the exact opposite result of the `@turf/boolean-within`. -/// @name booleanContains -/// @param {Geometry|Feature} feature1 GeoJSON Feature or Geometry -/// @param {Geometry|Feature} feature2 GeoJSON Feature or Geometry -/// @returns {boolean} true/false +/// Boolean-contains returns True if the second geometry is completely contained +/// by the first geometry. +/// The interiors of both geometries must intersect and, the interior and +/// boundary of the secondary must not intersect the exterior of the primary. +/// Boolean-contains returns the exact opposite result of the `turf/boolean-within`. /// example: /// ```dart -/// var line = turf.lineString([[1, 1], [1, 2], [1, 3], [1, 4]]); -/// var point = turf.point([1, 2]); -/// turf.booleanContains(line, point); +/// var line = LineString(coordinates: [Position.of([1, 1]), Position.of([1, 2]), Position.of([1, 3]), Position.of([1, 4])]); +/// var point = Point(cooridantes:Position.of([1, 2])); +/// booleanContains(line, point); /// //=true /// ``` booleanContains(GeoJSONObject feature1, GeoJSONObject feature2) { @@ -25,7 +22,6 @@ booleanContains(GeoJSONObject feature1, GeoJSONObject feature2) { var type2 = geom2!.type; var coords1 = (geom1 as GeometryType).coordinates; var coords2 = (geom2 as GeometryType).coordinates; - switch (type1) { case GeoJSONObjectType.point: switch (type2) { @@ -79,7 +75,7 @@ booleanContains(GeoJSONObject feature1, GeoJSONObject feature2) { } } -isPointInMultiPoint(MultiPoint multiPoint, Point pt) { +bool isPointInMultiPoint(MultiPoint multiPoint, Point pt) { int i; var output = false; for (i = 0; i < multiPoint.coordinates.length; i++) { @@ -91,7 +87,7 @@ isPointInMultiPoint(MultiPoint multiPoint, Point pt) { return output; } -isMultiPointInMultiPoint(MultiPoint multiPoint1, MultiPoint multiPoint2) { +bool isMultiPointInMultiPoint(MultiPoint multiPoint1, MultiPoint multiPoint2) { for (var coord2 in multiPoint2.coordinates) { var matchFound = false; for (var coord1 in multiPoint1.coordinates) { @@ -107,7 +103,7 @@ isMultiPointInMultiPoint(MultiPoint multiPoint1, MultiPoint multiPoint2) { return true; } -isMultiPointOnLine(LineString lineString, MultiPoint multiPoint) { +bool isMultiPointOnLine(LineString lineString, MultiPoint multiPoint) { var haveFoundInteriorPoint = false; for (var coord in multiPoint.coordinates) { if (booleanPointOnLine(Point(coordinates: coord), lineString, @@ -124,7 +120,7 @@ isMultiPointOnLine(LineString lineString, MultiPoint multiPoint) { return false; } -isMultiPointInPoly(Polygon polygon, MultiPoint multiPoint) { +bool isMultiPointInPoly(Polygon polygon, MultiPoint multiPoint) { for (var coord in multiPoint.coordinates) { if (!booleanPointInPolygon(coord, polygon, ignoreBoundary: true)) { return false; @@ -133,7 +129,7 @@ isMultiPointInPoly(Polygon polygon, MultiPoint multiPoint) { return true; } -isLineOnLine(LineString lineString1, LineString lineString2) { +bool isLineOnLine(LineString lineString1, LineString lineString2) { var haveFoundInteriorPoint = false; for (var coords in lineString2.coordinates) { if (booleanPointOnLine( @@ -154,7 +150,7 @@ isLineOnLine(LineString lineString1, LineString lineString2) { return haveFoundInteriorPoint; } -isLineInPoly(Polygon polygon, LineString linestring) { +bool isLineInPoly(Polygon polygon, LineString linestring) { var output = false; var i = 0; @@ -167,7 +163,7 @@ isLineInPoly(Polygon polygon, LineString linestring) { var midPoint = getMidpoint(linestring.coordinates[i], linestring.coordinates[i + 1]); if (booleanPointInPolygon( - Position.of(midPoint), + midPoint, polygon, ignoreBoundary: true, )) { @@ -178,34 +174,18 @@ isLineInPoly(Polygon polygon, LineString linestring) { return output; } -/** - * Is Polygon2 in Polygon1 - * Only takes into account outer rings - * - * @private - * @param {Geometry|Feature} feature1 Polygon1 - * @param {Geometry|Feature} feature2 Polygon2 - * @returns {boolean} true/false - */ -isPolyInPoly(GeoJSONObject feature1, GeoJSONObject feature2) { - // Handle Nulls - if (feature1 is Feature && feature1.geometry == null) { - return false; - } - if (feature2 is Feature && feature2.geometry == null) { - return false; - } - - var poly1Bbox = bbox(feature1); - var poly2Bbox = bbox(feature2); +/// Is Polygon2 in Polygon1 +/// Only takes into account outer rings +bool isPolyInPoly(GeoJSONObject geom1, GeoJSONObject geom2) { + var poly1Bbox = bbox(geom1); + var poly2Bbox = bbox(geom2); if (!doBBoxOverlap(poly1Bbox, poly2Bbox)) { return false; } - var coords = (feature2 as Feature).geometry!.coordinates; - for (var ring in coords) { + for (var ring in (geom2 as GeometryType).coordinates) { for (var coord in ring) { - if (!booleanPointInPolygon(coord, feature1 as Feature)) { + if (!booleanPointInPolygon(coord, geom1)) { return false; } } @@ -229,20 +209,13 @@ doBBoxOverlap(BBox bbox1, BBox bbox2) { return true; } -/** - * compareCoords - * - * @private - * @param {Position} pair1 point [x,y] - * @param {Position} pair2 point [x,y] - * @returns {boolean} true/false if coord pairs match - */ -compareCoords(Position pair1, Position pair2) { +bool compareCoords(Position pair1, Position pair2) { return pair1[0] == pair2[0] && pair1[1] == pair2[1]; } -getMidpoint(Position pair1, Position pair2) { - return [(pair1[0]! + pair2[0]!) / 2, (pair1[1]! + pair2[1]!) / 2]; +Position getMidpoint(Position pair1, Position pair2) { + return Position.of( + [(pair1[0]! + pair2[0]!) / 2, (pair1[1]! + pair2[1]!) / 2]); } /* diff --git a/lib/src/booleans/boolean_disjoint.dart b/lib/src/booleans/boolean_disjoint.dart index 68bb9c6c..7e2f7b34 100644 --- a/lib/src/booleans/boolean_disjoint.dart +++ b/lib/src/booleans/boolean_disjoint.dart @@ -40,36 +40,36 @@ bool booleanDisjoint(GeoJSONObject feature1, GeoJSONObject feature2) { * @returns {boolean} true/false */ disjoint(GeometryType geom1, GeometryType geom2) { - switch (geom1.runtimeType) { - case Point: - switch (geom2.runtimeType) { - case Point: + switch (geom1.type) { + case GeoJSONObjectType.point: + switch (geom2.type) { + case GeoJSONObjectType.point: return !compareCoords(geom1.coordinates, geom2.coordinates); - case LineString: + case GeoJSONObjectType.lineString: return !isPointOnLine(geom2 as LineString, geom1 as Point); - case Polygon: + case GeoJSONObjectType.polygon: return !booleanPointInPolygon((geom1 as Point).coordinates, geom2); } /* istanbul ignore next */ break; - case LineString: - switch (geom2.runtimeType) { - case Point: + case GeoJSONObjectType.lineString: + switch (geom2.type) { + case GeoJSONObjectType.point: return !isPointOnLine(geom1 as LineString, geom2 as Point); - case LineString: + case GeoJSONObjectType.lineString: return !isLineOnLine(geom1 as LineString, geom2 as LineString); - case Polygon: + case GeoJSONObjectType.polygon: return !isLineInPoly(geom2 as Polygon, geom1 as LineString); } /* istanbul ignore next */ break; - case Polygon: - switch (geom2.runtimeType) { - case Point: + case GeoJSONObjectType.polygon: + switch (geom2.type) { + case GeoJSONObjectType.point: return !booleanPointInPolygon((geom2 as Point).coordinates, geom1); - case LineString: + case GeoJSONObjectType.lineString: return !isLineInPoly(geom1 as Polygon, geom2 as LineString); - case Polygon: + case GeoJSONObjectType.polygon: return !isPolyInPoly(geom2 as Polygon, geom1 as Polygon); } } diff --git a/lib/src/booleans/boolean_equal.dart b/lib/src/booleans/boolean_equal.dart index 12a81ab0..0c79d49b 100644 --- a/lib/src/booleans/boolean_equal.dart +++ b/lib/src/booleans/boolean_equal.dart @@ -1,40 +1,33 @@ +import 'package:geojson_equality/geojson_equality.dart'; + import '../../helpers.dart'; import '../clean_coords.dart'; -import '../invariant.dart'; -/** - * Determine whether two geometries of the same type have identical X,Y coordinate values. - * See http://edndoc.esri.com/arcsde/9.0/general_topics/understand_spatial_relations.htm - * - * @name booleanEqual - * @param {Geometry|Feature} feature1 GeoJSON input - * @param {Geometry|Feature} feature2 GeoJSON input - * @param {Object} [options={}] Optional parameters - * @param {number} [options.precision=6] decimal precision to use when comparing coordinates - * @returns {boolean} true if the objects are equal, false otherwise - * @example - * var pt1 = turf.point([0, 0]); - * var pt2 = turf.point([0, 0]); - * var pt3 = turf.point([1, 1]); - * - * turf.booleanEqual(pt1, pt2); - * //= true - * turf.booleanEqual(pt2, pt3); - * //= false - */ +/// Determine whether two geometries of the same type have identical X,Y coordinate values. +/// See http://edndoc.esri.com/arcsde/9.0/general_topics/understand_spatial_relations.htm +/// [precision]=6 sets decimal precision to use when comparing coordinates +/// Returns true if the objects are equal, false otherwise +/// example: +/// var pt1 = Point(coordinates: Position.of([0, 0])); +/// var pt2 = Point(coordinates: Position.of([0, 0])); +/// var pt3 = Point(coordinates: Position.of([1, 1])); +/// booleanEqual(pt1, pt2); +/// //= true +/// booleanEqual(pt2, pt3); +/// //= false bool booleanEqual(GeoJSONObject feature1, GeoJSONObject feature2, - {num? precision}) { - precision = precision ?? 6; - + {int precision = 6}) { if (!(precision >= 0)) { throw Exception("precision must be a positive number"); } + var geom = feature1 is Feature ? feature1.geometry : feature1; + var geom2 = feature2 is Feature ? feature2.geometry : feature2; - var type1 = getGeom(feature1).runtimeType; - var type2 = getGeom(feature2).runtimeType; + var type1 = geom!.type; + var type2 = geom2!.type; if (type1 != type2) return false; - const equality = GeojsonEquality({precision: precision}); + var equality = Equality(precision: precision); return equality.compare(cleanCoords(feature1), cleanCoords(feature2)); } diff --git a/lib/src/booleans/boolean_overlap.dart b/lib/src/booleans/boolean_overlap.dart index ef7a71de..43fbc143 100644 --- a/lib/src/booleans/boolean_overlap.dart +++ b/lib/src/booleans/boolean_overlap.dart @@ -1,3 +1,5 @@ +import 'package:geojson_equality/geojson_equality.dart'; + import '../../helpers.dart'; import '../../line_segment.dart'; import '../invariant.dart'; @@ -43,7 +45,7 @@ booleanOverlap(GeometryObject feature1, GeometryObject feature2) { if (type1 == Point) throw Exception("Point geometry not supported"); // features must be not equal - const equality = GeojsonEquality({precision: 6}); + var equality = Equality(precision: 6); if (equality.compare(feature1, feature2)) return false; var overlap = 0; diff --git a/lib/src/booleans/boolean_parallel.dart b/lib/src/booleans/boolean_parallel.dart index 4783f4a4..a921e1c0 100644 --- a/lib/src/booleans/boolean_parallel.dart +++ b/lib/src/booleans/boolean_parallel.dart @@ -22,7 +22,6 @@ bool booleanParallel(GeoJSONObject line1, GeoJSONObject line2) { } FeatureCollection segments1 = lineSegment(cleanCoords(line1)); FeatureCollection segments2 = lineSegment(cleanCoords(line2)); - for (var i = 0; i < segments1.features.length; i++) { var segment1 = segments1.features[i].geometry!.coordinates; var seg2i = segments2.features.elementAt(i); @@ -49,7 +48,7 @@ GeoJSONObjectType _getType(GeoJSONObject geojson, String name) { if ((geojson as Feature).geometry != null) { return geojson.geometry!.type; } - if (geojson.runtimeType is GeometryType) { + if (geojson is GeometryType) { return geojson.type; } // if GeoJSON geometry throw Exception("Invalid GeoJSON object for $name"); diff --git a/lib/src/booleans/boolean_point_in_polygon.dart b/lib/src/booleans/boolean_point_in_polygon.dart index b9345a95..8e2b2567 100644 --- a/lib/src/booleans/boolean_point_in_polygon.dart +++ b/lib/src/booleans/boolean_point_in_polygon.dart @@ -1,52 +1,49 @@ // http://en.wikipedia.org/wiki/Even%E2%80%93odd_rule // modified from: https://github.com/substack/point-in-polygon/blob/master/index.js // which was modified from http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html +import 'package:pip/pip.dart'; + import '../../helpers.dart'; import '../invariant.dart'; -/** - * Takes a {@link Point} and a {@link Polygon} or {@link MultiPolygon} and determines if the point - * resides inside the polygon. The polygon can be convex or concave. The function accounts for holes. - * - * @name booleanPointInPolygon - * @param {Coord} point input point - * @param {Feature} polygon input polygon or multipolygon - * @param {Object} [options={}] Optional parameters - * @param {boolean} [options.ignoreBoundary=false] True if polygon boundary should be ignored when determining if - * the point is inside the polygon otherwise false. - * @returns {boolean} `true` if the Point is inside the Polygon; `false` if the Point is not inside the Polygon - * @example - * var pt = turf.point([-77, 44]); - * var poly = turf.polygon([[ - * [-81, 41], - * [-81, 47], - * [-72, 47], - * [-72, 41], - * [-81, 41] - * ]]); - * - * turf.booleanPointInPolygon(pt, poly); - * //= true - */ -booleanPointInPolygon(Position point, GeoJSONObject polygon, +/// Takes a {@link Point} and a {@link Polygon} or {@link MultiPolygon} and +/// determines if the [Point] resides inside the [Polygon]. The polygon can be +/// convex or concave. The function accounts for holes. By taking a +/// [Feature]|[Feature].[ignoreBoundary=false] should be +/// set True if polygon boundary should be ignored when determining if the point +/// is inside the polygon otherwise false. +/// example: +/// ```dart +/// var pt = Point(coordinates: Position([-77, 44])); +/// var poly = Polygon(coordinates:[[ +/// Position.of([-81, 41]), +/// Position.of([-81, 47]), +/// Position.of([-72, 47]), +/// Position.of([-72, 41]), +/// Position.of([-81, 41]) +/// ]]); +/// turf.booleanPointInPolygon(pt, poly); +/// //= true +/// ``` +bool booleanPointInPolygon(Position point, GeoJSONObject polygon, {bool? ignoreBoundary}) { - var pt = getCoord(point); var geom = getGeom(polygon); var type = geom.type; var bbox = polygon.bbox; var polys = geom.coordinates; // Quick elimination if point is not inside bbox - if (bbox != null && inBBox(pt, bbox) == false) { + if (bbox != null && !_inBBox(point, bbox)) { return false; } - if (type == "Polygon") { + if (type == GeoJSONObjectType.polygon) { polys = [polys]; } var result = false; for (var i = 0; i < polys.length; ++i) { - const polyResult = pip(pt, polys[i]); + var polyResult = + pip(Point(coordinates: point), Polygon(coordinates: polys[i])); if (polyResult == 0) { return ignoreBoundary == null ? false : true; } else if (polyResult) { @@ -57,15 +54,7 @@ booleanPointInPolygon(Position point, GeoJSONObject polygon, return result; } -/** - * inBBox - * - * @private - * @param {Position} pt point [x,y] - * @param {BBox} bbox BBox [west, south, east, north] - * @returns {boolean} true/false if point is inside BBox - */ -inBBox(Position pt, BBox bbox) { +bool _inBBox(Position pt, BBox bbox) { return (bbox[0]! <= pt[0]! && bbox[1]! <= pt[1]! && bbox[2]! >= pt[0]! && @@ -166,4 +155,4 @@ function inBBox(pt: number[], bbox: BBox) { bbox[0] <= pt[0] && bbox[1] <= pt[1] && bbox[2] >= pt[0] && bbox[3] >= pt[1] ); } - */ \ No newline at end of file + */ diff --git a/lib/src/booleans/boolean_point_on_line.dart b/lib/src/booleans/boolean_point_on_line.dart index 522ef2bb..5a59159e 100644 --- a/lib/src/booleans/boolean_point_on_line.dart +++ b/lib/src/booleans/boolean_point_on_line.dart @@ -79,7 +79,7 @@ bool isPointOnLineSegment(Position lineSegmentStart, Position lineSegmentEnd, } else if (cross != 0) { return false; } - if (!excludeBoundary) { + if (excludeBoundary != null) { if ((dxl).abs() >= (dyl).abs()) { return dxl > 0 ? x1 <= x && x <= x2 : x2 <= x && x <= x1; } diff --git a/lib/src/clean_coords.dart b/lib/src/clean_coords.dart index b48f4adb..22549ef4 100644 --- a/lib/src/clean_coords.dart +++ b/lib/src/clean_coords.dart @@ -5,24 +5,21 @@ import '../helpers.dart'; import 'invariant.dart'; -/** - * Removes redundant coordinates from any GeoJSON Geometry. - * - * @name cleanCoords - * @param {Geometry|Feature} geojson Feature or Geometry - * @param {Object} [options={}] Optional parameters - * @param {boolean} [options.mutate=false] allows GeoJSON input to be mutated - * @returns {Geometry|Feature} the cleaned input Feature/Geometry - * @example - * var line = turf.lineString([[0, 0], [0, 2], [0, 5], [0, 8], [0, 8], [0, 10]]); - * var multiPoint = turf.multiPoint([[0, 0], [0, 0], [2, 2]]); - * - * turf.cleanCoords(line).geometry.coordinates; - * //= [[0, 0], [0, 10]] - * - * turf.cleanCoords(multiPoint).geometry.coordinates; - * //= [[0, 0], [2, 2]] - */ + +/// Removes redundant coordinates from any GeoJSON Geometry. +/// @name cleanCoords +/// @param {Geometry|Feature} geojson Feature or Geometry +/// @param {Object} [options={}] Optional parameters +/// @param {boolean} [options.mutate=false] allows GeoJSON input to be mutated +/// @returns {Geometry|Feature} the cleaned input Feature/Geometry +/// @example +/// var line = turf.lineString([[0, 0], [0, 2], [0, 5], [0, 8], [0, 8], [0, 10]]); +/// var multiPoint = turf.multiPoint([[0, 0], [0, 0], [2, 2]]); +/// turf.cleanCoords(line).geometry.coordinates; +/// //= [[0, 0], [0, 10]] +/// turf.cleanCoords(multiPoint).geometry.coordinates; +/// //= [[0, 0], [2, 2]] + cleanCoords( GeoJSONObject geojson, { @@ -32,22 +29,22 @@ import 'invariant.dart'; // // Backwards compatible with v4.0 // var mutate = typeof options == "object" ? options.mutate : options; // if (!geojson) throw Exception("geojson is required"); - var type = (geojson.runtimeType); + var type = (geojson.type); // Store new "clean" points in this Array var newCoords = []; switch (type) { - case LineString: + case GeoJSONObjectType.lineString: newCoords = cleanLine(geojson as LineString, type); break; - case MultiLineString: - case Polygon: + case GeoJSONObjectType.multiLineString: + case GeoJSONObjectType.polygon: getCoords(geojson).forEach( (line) { newCoords.add(cleanLine(line, type)); }); break; - case MultiPolygon: + case GeoJSONObjectType.multiPolygon: getCoords(geojson).forEach( (polygons) { var polyPoints = []; polygons.forEach( (List ring) { @@ -56,9 +53,9 @@ import 'invariant.dart'; newCoords.add(polyPoints); }); break; - case Point: + case GeoJSONObjectType.point: return geojson; - case MultiPoint: + case GeoJSONObjectType.multiPoint: var Record existing: = {}; getCoords(geojson).forEach( (coord: any) { var key = coord.join("-"); @@ -74,13 +71,13 @@ import 'invariant.dart'; // Support input mutation if (geojson.coordinates) { - if (mutate == true) { + if (mutate) { geojson.coordinates = newCoords; return geojson; } return { type: type, coordinates: newCoords }; } else { - if (mutate == true) { + if (mutate) { geojson.geometry.coordinates = newCoords; return geojson; } diff --git a/lib/src/invariant.dart b/lib/src/invariant.dart index 1f8219c9..b8b7aa41 100644 --- a/lib/src/invariant.dart +++ b/lib/src/invariant.dart @@ -77,28 +77,22 @@ _getCoordsForGeometry(GeometryObject geom) { return (geom as GeometryType).coordinates; } -/** - * Get Geometry from Feature or Geometry Object - * - * @param {Feature|Geometry} geojson GeoJSON Feature or Geometry Object - * @returns {Geometry|null} GeoJSON Geometry Object - * @throws {Error} if geojson is not a Feature or Geometry Object - * @example - * var point = { - * "type": "Feature", - * "properties": {}, - * "geometry": { - * "type": "Point", - * "coordinates": [110, 40] - * } - * } - * var geom = turf.getGeom(point) - * //={"type": "Point", "coordinates": [110, 40]} - */ - +/// Get Geometry or Geometries from [Feature] or [GeometryType] +/// Returns [List] in case geojson is a [GeometryCollection] and a +/// [GeometryType] if geojson is a simple [GeometryType]. +/// example: +/// ```dart +/// var feature = Feature( +/// geometry: Point( +/// coordinates: Position.of([110, 40]) +/// )); +/// var geom = getGeom(feature) +/// //= Point(coordinates: Position.of([110, 40])) getGeom(GeoJSONObject geojson) { if (geojson is Feature) { return (geojson).geometry; + } else if (geojson is GeometryCollection) { + return geojson.geometries; } return geojson; } diff --git a/lib/src/line_intersect.dart b/lib/src/line_intersect.dart index 3c022b68..c8c06bdd 100644 --- a/lib/src/line_intersect.dart +++ b/lib/src/line_intersect.dart @@ -28,14 +28,14 @@ FeatureCollection lineIntersect( } ){ var features= []; - if (line1.runtimeType == FeatureCollection) + if (line1 is FeatureCollection) { features = features..addAll((line1 as FeatureCollection).features); } else if (line1 is Feature) {features.add(line1);} else if ( - line1.runtimeType == LineString || - line1.runtimeType == Polygon || - line1.runtimeType == MultiLineString || - line1.runtimeType == MultiPolygon + line1 is LineString || + line1 is Polygon || + line1 is MultiLineString || + line1 is MultiPolygon ) { features.add(Feature(geometry: line1 as GeometryObject)); } diff --git a/pubspec.yaml b/pubspec.yaml index 3809d44e..282e57aa 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,13 +2,19 @@ name: turf description: A turf.js-like geospatial analysis library working with GeoJSON, written in pure Dart. version: 0.0.6+3 environment: - sdk: '>=2.12.0 <3.0.0' + sdk: ">=2.12.0 <3.0.0" homepage: https://github.com/dartclub/turf_dart repository: https://github.com/dartclub/turf_dart +publish_to: none dependencies: json_annotation: ^4.4.0 - + geojson_equality: + git: + url: https://github.com/dartclub/turf_equality.git + pip: + git: + url: https://github.com/dartclub/point_in_polygon.git dev_dependencies: dartclub_lint: ^0.4.2 test: ^1.19.3 diff --git a/test/booleans/contains_test.dart b/test/booleans/contains_test.dart new file mode 100644 index 00000000..4ac49384 --- /dev/null +++ b/test/booleans/contains_test.dart @@ -0,0 +1,61 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:test/test.dart'; +import 'package:turf/helpers.dart'; +import 'package:turf/src/booleans/boolean_contains.dart'; + +main() { + group( + 'contains', + () { + var inDir = Directory('./test/examples/boolean_contains/test/true'); + for (var file in inDir.listSync(recursive: true)) { + if (file is File && file.path.endsWith('.geojson')) { + test( + file.path, + () { + // True Fixtures + var inSource = file.readAsStringSync(); + var inGeom = GeoJSONObject.fromJson(jsonDecode(inSource)); + + var feature1 = (inGeom as FeatureCollection).features[0]; + var feature2 = inGeom.features[1]; + expect(booleanContains(feature1, feature2), true); + }, + ); + } + } + + var inDir1 = Directory('./test/examples/boolean_contains/test/false'); + for (var file in inDir1.listSync(recursive: true)) { + if (file is File && file.path.endsWith('.geojson')) { + test( + file.path, + () { + // False Fixtures + var inSource = file.readAsStringSync(); + var inGeom = GeoJSONObject.fromJson(jsonDecode(inSource)); + + var feature1 = (inGeom as FeatureCollection).features[0]; + var feature2 = inGeom.features[1]; + expect(booleanContains(feature1, feature2), false); + }, + ); + + test( + "turf-boolean-contains -- Geometry Objects", + () { + var pt1 = + Feature(geometry: Point(coordinates: Position.of([0, 0]))); + var pt2 = + Feature(geometry: Point(coordinates: Position.of([0, 0]))); + + expect(booleanContains(pt1.geometry!, pt2.geometry!), true); + }, + ); + } + } + }, + ); +} diff --git a/test/examples/boolean_contains/diagrams/esri-contains.gif b/test/examples/boolean_contains/diagrams/esri-contains.gif new file mode 100644 index 0000000000000000000000000000000000000000..6b219104cf3dc29ba48b6f73cd4119b592d92100 GIT binary patch literal 34103 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 literal 0 HcmV?d00001 diff --git a/test/examples/boolean_contains/test/false/LineString/LineString/LineIsNotContainedByLine.geojson b/test/examples/boolean_contains/test/false/LineString/LineString/LineIsNotContainedByLine.geojson new file mode 100644 index 00000000..9ad941da --- /dev/null +++ b/test/examples/boolean_contains/test/false/LineString/LineString/LineIsNotContainedByLine.geojson @@ -0,0 +1,30 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [1, 1], + [1, 2], + [1, 3], + [1, 4] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [1, 2], + [1, 3], + [1, 15.5] + ] + } + } + ] +} diff --git a/test/examples/boolean_contains/test/false/LineString/Polygon/LineIsNotContainedByPolygon.geojson b/test/examples/boolean_contains/test/false/LineString/Polygon/LineIsNotContainedByPolygon.geojson new file mode 100644 index 00000000..8e2caf0e --- /dev/null +++ b/test/examples/boolean_contains/test/false/LineString/Polygon/LineIsNotContainedByPolygon.geojson @@ -0,0 +1,33 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [1, 1], + [1, 10], + [10, 10], + [10, 1], + [1, 1] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [1, 2], + [1, 3], + [1, 15.5] + ] + } + } + ] +} diff --git a/test/examples/boolean_contains/test/false/LineString/Polygon/LineIsNotContainedByPolygonBoundary.geojson b/test/examples/boolean_contains/test/false/LineString/Polygon/LineIsNotContainedByPolygonBoundary.geojson new file mode 100644 index 00000000..b5a0114a --- /dev/null +++ b/test/examples/boolean_contains/test/false/LineString/Polygon/LineIsNotContainedByPolygonBoundary.geojson @@ -0,0 +1,33 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [1, 1], + [1, 10], + [10, 10], + [10, 1], + [1, 1] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [1, 2], + [1, 3], + [1, 3.5] + ] + } + } + ] +} diff --git a/test/examples/boolean_contains/test/false/MultiPoint/LineString/MultiPointsIsNotContainedByLine.geojson b/test/examples/boolean_contains/test/false/MultiPoint/LineString/MultiPointsIsNotContainedByLine.geojson new file mode 100644 index 00000000..496c3bf6 --- /dev/null +++ b/test/examples/boolean_contains/test/false/MultiPoint/LineString/MultiPointsIsNotContainedByLine.geojson @@ -0,0 +1,30 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [1, 1], + [1, 2], + [1, 3], + [1, 4] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPoint", + "coordinates": [ + [1, 1], + [12, 12], + [15, 15] + ] + } + } + ] +} diff --git a/test/examples/boolean_contains/test/false/MultiPoint/LineString/MultiPointsOnLineEndsIsNotContainedByLine.geojson b/test/examples/boolean_contains/test/false/MultiPoint/LineString/MultiPointsOnLineEndsIsNotContainedByLine.geojson new file mode 100644 index 00000000..88a1d75e --- /dev/null +++ b/test/examples/boolean_contains/test/false/MultiPoint/LineString/MultiPointsOnLineEndsIsNotContainedByLine.geojson @@ -0,0 +1,29 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [1, 1], + [1, 2], + [1, 3], + [1, 4] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPoint", + "coordinates": [ + [1, 1], + [1, 4] + ] + } + } + ] +} diff --git a/test/examples/boolean_contains/test/false/MultiPoint/MultiPoint/MultiPointIsNotContainedByMultiPoint.geojson b/test/examples/boolean_contains/test/false/MultiPoint/MultiPoint/MultiPointIsNotContainedByMultiPoint.geojson new file mode 100644 index 00000000..abe3550d --- /dev/null +++ b/test/examples/boolean_contains/test/false/MultiPoint/MultiPoint/MultiPointIsNotContainedByMultiPoint.geojson @@ -0,0 +1,28 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPoint", + "coordinates": [ + [1, 1], + [12, 12], + [15, 15] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPoint", + "coordinates": [ + [1, 1], + [1, 1.5] + ] + } + } + ] +} diff --git a/test/examples/boolean_contains/test/false/MultiPoint/Polygon/MultiPointAllOnBoundaryIsNotContainedByPolygon.geojson b/test/examples/boolean_contains/test/false/MultiPoint/Polygon/MultiPointAllOnBoundaryIsNotContainedByPolygon.geojson new file mode 100644 index 00000000..f9f55a6b --- /dev/null +++ b/test/examples/boolean_contains/test/false/MultiPoint/Polygon/MultiPointAllOnBoundaryIsNotContainedByPolygon.geojson @@ -0,0 +1,32 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [1, 1], + [1, 10], + [10, 10], + [10, 1], + [1, 1] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPoint", + "coordinates": [ + [1, 1], + [1, 10] + ] + } + } + ] +} diff --git a/test/examples/boolean_contains/test/false/MultiPoint/Polygon/MultiPointIsNotContainedByPolygon.geojson b/test/examples/boolean_contains/test/false/MultiPoint/Polygon/MultiPointIsNotContainedByPolygon.geojson new file mode 100644 index 00000000..b6cbb2b0 --- /dev/null +++ b/test/examples/boolean_contains/test/false/MultiPoint/Polygon/MultiPointIsNotContainedByPolygon.geojson @@ -0,0 +1,33 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [1, 1], + [1, 10], + [10, 10], + [10, 1], + [1, 1] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPoint", + "coordinates": [ + [1, 1], + [12, 12], + [15, 15] + ] + } + } + ] +} diff --git a/test/examples/boolean_contains/test/false/Point/LineString/PointIsNotContainedByLine.geojson b/test/examples/boolean_contains/test/false/Point/LineString/PointIsNotContainedByLine.geojson new file mode 100644 index 00000000..9342e2ee --- /dev/null +++ b/test/examples/boolean_contains/test/false/Point/LineString/PointIsNotContainedByLine.geojson @@ -0,0 +1,26 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [1, 1], + [1, 2], + [1, 3], + [1, 4] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [2, 2] + } + } + ] +} diff --git a/test/examples/boolean_contains/test/false/Point/LineString/PointIsNotContainedByLineBecauseOnEnd.geojson b/test/examples/boolean_contains/test/false/Point/LineString/PointIsNotContainedByLineBecauseOnEnd.geojson new file mode 100644 index 00000000..ae3cd8ad --- /dev/null +++ b/test/examples/boolean_contains/test/false/Point/LineString/PointIsNotContainedByLineBecauseOnEnd.geojson @@ -0,0 +1,26 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [1, 1], + [1, 2], + [1, 3], + [1, 4] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [1, 4] + } + } + ] +} diff --git a/test/examples/boolean_contains/test/false/Point/LineString/PointOnEndIsContainedByLinestring.geojson b/test/examples/boolean_contains/test/false/Point/LineString/PointOnEndIsContainedByLinestring.geojson new file mode 100644 index 00000000..39e7953d --- /dev/null +++ b/test/examples/boolean_contains/test/false/Point/LineString/PointOnEndIsContainedByLinestring.geojson @@ -0,0 +1,26 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [1, 1], + [1, 2], + [1, 3], + [1, 4] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [1, 1] + } + } + ] +} diff --git a/test/examples/boolean_contains/test/false/Point/MultiPoint/PointIsNotContainedBYMultiPoint.geojson b/test/examples/boolean_contains/test/false/Point/MultiPoint/PointIsNotContainedBYMultiPoint.geojson new file mode 100644 index 00000000..e67d5e0a --- /dev/null +++ b/test/examples/boolean_contains/test/false/Point/MultiPoint/PointIsNotContainedBYMultiPoint.geojson @@ -0,0 +1,24 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPoint", + "coordinates": [ + [1, 1], + [12, 12] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [1, 4] + } + } + ] +} diff --git a/test/examples/boolean_contains/test/false/Point/Polygon/PointIsNotContainedByPolygon.geojson b/test/examples/boolean_contains/test/false/Point/Polygon/PointIsNotContainedByPolygon.geojson new file mode 100644 index 00000000..09bb41c7 --- /dev/null +++ b/test/examples/boolean_contains/test/false/Point/Polygon/PointIsNotContainedByPolygon.geojson @@ -0,0 +1,29 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [1, 1], + [1, 10], + [10, 10], + [10, 1], + [1, 1] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [14, 14] + } + } + ] +} diff --git a/test/examples/boolean_contains/test/false/Point/Polygon/PointOnPolygonBoundary.geojson b/test/examples/boolean_contains/test/false/Point/Polygon/PointOnPolygonBoundary.geojson new file mode 100644 index 00000000..685a46d3 --- /dev/null +++ b/test/examples/boolean_contains/test/false/Point/Polygon/PointOnPolygonBoundary.geojson @@ -0,0 +1,29 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [1, 1], + [1, 10], + [10, 10], + [10, 1], + [1, 1] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [1, 1] + } + } + ] +} diff --git a/test/examples/boolean_contains/test/false/Polygon/LineString/issue-#1201-false.geojson b/test/examples/boolean_contains/test/false/Polygon/LineString/issue-#1201-false.geojson new file mode 100644 index 00000000..d0b6f5fc --- /dev/null +++ b/test/examples/boolean_contains/test/false/Polygon/LineString/issue-#1201-false.geojson @@ -0,0 +1,40 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": { + "stroke": "#0000ff", + "stroke-width": 6, + "stroke-opacity": 1, + "fill": "#0000ff", + "fill-opacity": 0.3 + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [98.8769531, 35.3173663], + [83.144531, 14.349547], + [111.621093, 14.8598504], + [98.8769531, 35.3173663] + ] + ] + } + }, + { + "type": "Feature", + "properties": { + "stroke": "#F00", + "stroke-width": 6 + }, + "geometry": { + "type": "LineString", + "coordinates": [ + [111.621093, 14.8598504], + [98.8769531, 35.3173663] + ] + } + } + ] +} diff --git a/test/examples/boolean_contains/test/false/Polygon/Polygon/Polygon-Polygon.geojson b/test/examples/boolean_contains/test/false/Polygon/Polygon/Polygon-Polygon.geojson new file mode 100644 index 00000000..505f22ed --- /dev/null +++ b/test/examples/boolean_contains/test/false/Polygon/Polygon/Polygon-Polygon.geojson @@ -0,0 +1,37 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [1, 1], + [1, 10], + [10, 10], + [10, 1], + [1, 1] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [1, 1], + [1, 20], + [1, 3], + [1, 4], + [1, 1] + ] + ] + } + } + ] +} diff --git a/test/examples/boolean_contains/test/false/Polygon/Polygon/Polygon-Polygon2.geojson b/test/examples/boolean_contains/test/false/Polygon/Polygon/Polygon-Polygon2.geojson new file mode 100644 index 00000000..88fbf6d5 --- /dev/null +++ b/test/examples/boolean_contains/test/false/Polygon/Polygon/Polygon-Polygon2.geojson @@ -0,0 +1,47 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": { + "stroke": "#ffa200", + "stroke-width": 2, + "stroke-opacity": 1, + "fill": "#d4c63b", + "fill-opacity": 0.5, + "description": "shape which was intersected with a longer pipe to produce the pipe shown" + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [3.1249679625034332, 50.90354450528237], + [3.1252093613147736, 50.90354957970863], + [3.1252361834049225, 50.90334491073787], + [3.125006854534149, 50.903344064996546], + [3.1248298287391663, 50.90339988389688], + [3.1249679625034332, 50.90354450528237] + ] + ] + } + }, + { + "type": "Feature", + "properties": { + "description": "output of an intersect call with a longer pipe and the other feature in this file" + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [3.124910769300162, 50.90341155120744], + [3.12484701356319, 50.90343165437331], + [3.124918293470778, 50.903431917293965], + [3.124982049176972, 50.90341181412811], + [3.124910769300162, 50.90341155120744] + ] + ] + } + } + ] +} diff --git a/test/examples/boolean_contains/test/true/LineString/LineString/LineIsContainedByLine.geojson b/test/examples/boolean_contains/test/true/LineString/LineString/LineIsContainedByLine.geojson new file mode 100644 index 00000000..0e96a0fe --- /dev/null +++ b/test/examples/boolean_contains/test/true/LineString/LineString/LineIsContainedByLine.geojson @@ -0,0 +1,30 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [1, 1], + [1, 2], + [1, 3], + [1, 4] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [1, 2], + [1, 3], + [1, 3.5] + ] + } + } + ] +} diff --git a/test/examples/boolean_contains/test/true/LineString/LineString/LinesExactlySame.geojson b/test/examples/boolean_contains/test/true/LineString/LineString/LinesExactlySame.geojson new file mode 100644 index 00000000..034737ba --- /dev/null +++ b/test/examples/boolean_contains/test/true/LineString/LineString/LinesExactlySame.geojson @@ -0,0 +1,31 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [1, 1], + [1, 2], + [1, 3], + [1, 4] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [1, 1], + [1, 2], + [1, 3], + [1, 4] + ] + } + } + ] +} diff --git a/test/examples/boolean_contains/test/true/LineString/Polygon/LineIsContainedByPolygon.geojson b/test/examples/boolean_contains/test/true/LineString/Polygon/LineIsContainedByPolygon.geojson new file mode 100644 index 00000000..fdbf01a4 --- /dev/null +++ b/test/examples/boolean_contains/test/true/LineString/Polygon/LineIsContainedByPolygon.geojson @@ -0,0 +1,33 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [1, 1], + [1, 10], + [10, 10], + [10, 1], + [1, 1] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [1, 1], + [2, 3], + [2, 3.5] + ] + } + } + ] +} diff --git a/test/examples/boolean_contains/test/true/LineString/Polygon/LineIsContainedByPolygonWithNoInternalVertices.geojson b/test/examples/boolean_contains/test/true/LineString/Polygon/LineIsContainedByPolygonWithNoInternalVertices.geojson new file mode 100644 index 00000000..458c29ba --- /dev/null +++ b/test/examples/boolean_contains/test/true/LineString/Polygon/LineIsContainedByPolygonWithNoInternalVertices.geojson @@ -0,0 +1,32 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [1, 1], + [1, 10], + [10, 10], + [10, 1], + [1, 1] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [1, 1], + [10, 10] + ] + } + } + ] +} diff --git a/test/examples/boolean_contains/test/true/MultiPoint/LineString/MultipointsIsContainedByLine.geojson b/test/examples/boolean_contains/test/true/MultiPoint/LineString/MultipointsIsContainedByLine.geojson new file mode 100644 index 00000000..867d63a7 --- /dev/null +++ b/test/examples/boolean_contains/test/true/MultiPoint/LineString/MultipointsIsContainedByLine.geojson @@ -0,0 +1,29 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [1, 1], + [1, 2], + [1, 3], + [1, 4] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPoint", + "coordinates": [ + [1, 1], + [1, 1.5] + ] + } + } + ] +} diff --git a/test/examples/boolean_contains/test/true/MultiPoint/MultiPoint/MultiPointsContainedByMultiPoints.geojson b/test/examples/boolean_contains/test/true/MultiPoint/MultiPoint/MultiPointsContainedByMultiPoints.geojson new file mode 100644 index 00000000..007ec9df --- /dev/null +++ b/test/examples/boolean_contains/test/true/MultiPoint/MultiPoint/MultiPointsContainedByMultiPoints.geojson @@ -0,0 +1,28 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPoint", + "coordinates": [ + [1, 1], + [12, 12], + [15, 15] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPoint", + "coordinates": [ + [1, 1], + [15, 15] + ] + } + } + ] +} diff --git a/test/examples/boolean_contains/test/true/MultiPoint/MultiPoint/MultiPointsEqual.geojson b/test/examples/boolean_contains/test/true/MultiPoint/MultiPoint/MultiPointsEqual.geojson new file mode 100644 index 00000000..8a0585fe --- /dev/null +++ b/test/examples/boolean_contains/test/true/MultiPoint/MultiPoint/MultiPointsEqual.geojson @@ -0,0 +1,29 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPoint", + "coordinates": [ + [1, 1], + [12, 12], + [15, 15] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPoint", + "coordinates": [ + [1, 1], + [12, 12], + [15, 15] + ] + } + } + ] +} diff --git a/test/examples/boolean_contains/test/true/MultiPoint/Polygon/MultiPointIsContainedByPolygonBoundary.geojson b/test/examples/boolean_contains/test/true/MultiPoint/Polygon/MultiPointIsContainedByPolygonBoundary.geojson new file mode 100644 index 00000000..321c7587 --- /dev/null +++ b/test/examples/boolean_contains/test/true/MultiPoint/Polygon/MultiPointIsContainedByPolygonBoundary.geojson @@ -0,0 +1,32 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [1, 1], + [1, 10], + [10, 10], + [10, 1], + [1, 1] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPoint", + "coordinates": [ + [2, 2], + [4, 4] + ] + } + } + ] +} diff --git a/test/examples/boolean_contains/test/true/Point/LineString/PointIsContainedByLine.geojson b/test/examples/boolean_contains/test/true/Point/LineString/PointIsContainedByLine.geojson new file mode 100644 index 00000000..cd6c19d0 --- /dev/null +++ b/test/examples/boolean_contains/test/true/Point/LineString/PointIsContainedByLine.geojson @@ -0,0 +1,26 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [1, 1], + [1, 2], + [1, 3], + [1, 4] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [1, 2] + } + } + ] +} diff --git a/test/examples/boolean_contains/test/true/Point/MultiPoint/PointIsContainedByMultiPoint.geojson b/test/examples/boolean_contains/test/true/Point/MultiPoint/PointIsContainedByMultiPoint.geojson new file mode 100644 index 00000000..ad874c8a --- /dev/null +++ b/test/examples/boolean_contains/test/true/Point/MultiPoint/PointIsContainedByMultiPoint.geojson @@ -0,0 +1,24 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPoint", + "coordinates": [ + [1, 1], + [12, 12] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [1, 1] + } + } + ] +} diff --git a/test/examples/boolean_contains/test/true/Point/Polygon/PointInsidePolygonBoundary.geojson b/test/examples/boolean_contains/test/true/Point/Polygon/PointInsidePolygonBoundary.geojson new file mode 100644 index 00000000..7914f4a2 --- /dev/null +++ b/test/examples/boolean_contains/test/true/Point/Polygon/PointInsidePolygonBoundary.geojson @@ -0,0 +1,29 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [1, 1], + [1, 10], + [10, 10], + [10, 1], + [1, 1] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [4, 4] + } + } + ] +} diff --git a/test/examples/boolean_contains/test/true/Polygon/LineString/issue-#1201-true.geojson b/test/examples/boolean_contains/test/true/Polygon/LineString/issue-#1201-true.geojson new file mode 100644 index 00000000..6c5dad23 --- /dev/null +++ b/test/examples/boolean_contains/test/true/Polygon/LineString/issue-#1201-true.geojson @@ -0,0 +1,40 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": { + "stroke": "#0000ff", + "stroke-width": 6, + "stroke-opacity": 1, + "fill": "#0000ff", + "fill-opacity": 0.3 + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [98.8769531, 35.3173663], + [83.144531, 14.349547], + [111.621093, 14.8598504], + [98.8769531, 35.3173663] + ] + ] + } + }, + { + "type": "Feature", + "properties": { + "stroke": "#F00", + "stroke-width": 6 + }, + "geometry": { + "type": "LineString", + "coordinates": [ + [111.621093, 14.8598504], + [98.8769531, 30.3173663] + ] + } + } + ] +} diff --git a/test/examples/boolean_contains/test/true/Polygon/Polygon/PolygonExactSameShape.geojson b/test/examples/boolean_contains/test/true/Polygon/Polygon/PolygonExactSameShape.geojson new file mode 100644 index 00000000..8bfd83da --- /dev/null +++ b/test/examples/boolean_contains/test/true/Polygon/Polygon/PolygonExactSameShape.geojson @@ -0,0 +1,41 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": { + "fill": "#F00" + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [-12.65625, 36.87962060502676], + [35.419921875, 36.38591277287651], + [37.79296875, 56.897003921272606], + [-12.12890625, 57.040729838360875], + [-12.65625, 36.87962060502676] + ] + ] + } + }, + { + "type": "Feature", + "properties": { + "fill": "#F00" + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [-12.65625, 36.87962060502676], + [35.419921875, 36.38591277287651], + [37.79296875, 56.897003921272606], + [-12.12890625, 57.040729838360875], + [-12.65625, 36.87962060502676] + ] + ] + } + } + ] +} diff --git a/test/examples/boolean_contains/test/true/Polygon/Polygon/PolygonIsContainedByPolygon.geojson b/test/examples/boolean_contains/test/true/Polygon/Polygon/PolygonIsContainedByPolygon.geojson new file mode 100644 index 00000000..afc9190b --- /dev/null +++ b/test/examples/boolean_contains/test/true/Polygon/Polygon/PolygonIsContainedByPolygon.geojson @@ -0,0 +1,36 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [1, 1], + [1, 10], + [10, 10], + [10, 1], + [1, 1] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [1, 1], + [2, 2], + [3, 2], + [1, 1] + ] + ] + } + } + ] +} From 8e9f058e80ea6fbc3b493315fd9a43af3c65c716 Mon Sep 17 00:00:00 2001 From: armantorkzaban Date: Fri, 1 Jul 2022 22:28:30 +0200 Subject: [PATCH 35/82] rewriting pointInLine --- lib/src/booleans/boolean_contains.dart | 5 +- .../booleans/boolean_point_in_polygon.dart | 16 ++-- lib/src/booleans/boolean_point_on_line.dart | 18 ++-- test/booleans/point_on_line_test.dart | 90 +++++++------------ 4 files changed, 47 insertions(+), 82 deletions(-) diff --git a/lib/src/booleans/boolean_contains.dart b/lib/src/booleans/boolean_contains.dart index a2fe9e97..181739ab 100644 --- a/lib/src/booleans/boolean_contains.dart +++ b/lib/src/booleans/boolean_contains.dart @@ -114,10 +114,7 @@ bool isMultiPointOnLine(LineString lineString, MultiPoint multiPoint) { return false; } } - if (haveFoundInteriorPoint) { - return true; - } - return false; + return haveFoundInteriorPoint; } bool isMultiPointInPoly(Polygon polygon, MultiPoint multiPoint) { diff --git a/lib/src/booleans/boolean_point_in_polygon.dart b/lib/src/booleans/boolean_point_in_polygon.dart index 8e2b2567..962c828f 100644 --- a/lib/src/booleans/boolean_point_in_polygon.dart +++ b/lib/src/booleans/boolean_point_in_polygon.dart @@ -6,12 +6,12 @@ import 'package:pip/pip.dart'; import '../../helpers.dart'; import '../invariant.dart'; -/// Takes a {@link Point} and a {@link Polygon} or {@link MultiPolygon} and -/// determines if the [Point] resides inside the [Polygon]. The polygon can be -/// convex or concave. The function accounts for holes. By taking a -/// [Feature]|[Feature].[ignoreBoundary=false] should be -/// set True if polygon boundary should be ignored when determining if the point -/// is inside the polygon otherwise false. +/// Takes a [Point] and a [Polygon] or [MultiPolygon]and determines if the +/// [Point] resides inside the [Polygon]. The polygon can be convex or concave. +/// The function accounts for holes. By taking a [Feature] or a +/// [Feature]. [ignoreBoundary=false] should be set [true] if polygon's +/// boundary should be ignored when determining if the [Point] is inside the +/// [Polygon] otherwise false. /// example: /// ```dart /// var pt = Point(coordinates: Position([-77, 44])); @@ -26,7 +26,7 @@ import '../invariant.dart'; /// //= true /// ``` bool booleanPointInPolygon(Position point, GeoJSONObject polygon, - {bool? ignoreBoundary}) { + {bool ignoreBoundary = false}) { var geom = getGeom(polygon); var type = geom.type; var bbox = polygon.bbox; @@ -45,7 +45,7 @@ bool booleanPointInPolygon(Position point, GeoJSONObject polygon, var polyResult = pip(Point(coordinates: point), Polygon(coordinates: polys[i])); if (polyResult == 0) { - return ignoreBoundary == null ? false : true; + return ignoreBoundary ? false : true; } else if (polyResult) { result = true; } diff --git a/lib/src/booleans/boolean_point_on_line.dart b/lib/src/booleans/boolean_point_on_line.dart index 5a59159e..33d20211 100644 --- a/lib/src/booleans/boolean_point_on_line.dart +++ b/lib/src/booleans/boolean_point_on_line.dart @@ -20,27 +20,23 @@ import '../invariant.dart'; * //=true */ bool booleanPointOnLine(Point pt, LineString line, - {bool? ignoreEndVertices, num? epsilon}) { - // Normalize inputs - var ptCoords = getCoord(pt); - var lineCoords = getCoords(line); - + {bool ignoreEndVertices = false, num? epsilon}) { // Main - for (var i = 0; i < lineCoords.length - 1; i++) { + for (var i = 0; i < line.coordinates.length - 1; i++) { dynamic ignoreBoundary = false; - if (ignoreEndVertices != null && ignoreEndVertices) { + if (ignoreEndVertices && ignoreEndVertices) { if (i == 0) { ignoreBoundary = "start"; } - if (i == lineCoords.length - 2) { + if (i == line.coordinates.length - 2) { ignoreBoundary = "end"; } - if (i == 0 && i + 1 == lineCoords.length - 1) { + if (i == 0 && i + 1 == line.coordinates.length - 1) { ignoreBoundary = "both"; } } - if (isPointOnLineSegment( - lineCoords[i], lineCoords[i + 1], ptCoords, ignoreBoundary, epsilon)) { + if (isPointOnLineSegment(line.coordinates[i], line.coordinates[i + 1], + pt.coordinates, ignoreBoundary, epsilon)) { return true; } } diff --git a/test/booleans/point_on_line_test.dart b/test/booleans/point_on_line_test.dart index 5a6b9aad..de59bc0c 100644 --- a/test/booleans/point_on_line_test.dart +++ b/test/booleans/point_on_line_test.dart @@ -1,63 +1,35 @@ -import 'dart:math'; +const glob = require("glob"); +const path = require("path"); +const test = require("tape"); +const load = require("load-json-file"); +const pointOnLine = require("./index").default; -import 'package:test/test.dart'; -import 'package:turf/helpers.dart'; -import 'package:turf/src/booleans/boolean_point_on_line.dart'; +test("turf-boolean-point-on-line", (t) => { + // True Fixtures + glob + .sync(path.join(__dirname, "test", "true", "**", "*.geojson")) + .forEach((filepath) => { + const name = path.parse(filepath).name; + const geojson = load.sync(filepath); + const options = geojson.properties; + const feature1 = geojson.features[0]; + const feature2 = geojson.features[1]; + const result = pointOnLine(feature1, feature2, options); -main() { + t.true(result, "[true] " + name); + }); // False Fixtures - test( - "turf-boolean-point-on-line", - () { - var featureCollection = FeatureCollection( - features: [ - Feature( - properties: {}, - geometry: Point( - coordinates: - Position.of([-75.25737143565107, 39.99673377198139]))), - Feature( - properties: {}, - geometry: LineString( - coordinates: [ - Position.of([-75.2580499870244, 40.00180204907801]), - Position.of([-75.25676601413157, 39.992211720827044]), - ], - ), - ) - ], - ); + glob + .sync(path.join(__dirname, "test", "false", "**", "*.geojson")) + .forEach((filepath) => { + const name = path.parse(filepath).name; + const geojson = load.sync(filepath); + const options = geojson.properties; + const feature1 = geojson.features[0]; + const feature2 = geojson.features[1]; + const result = pointOnLine(feature1, feature2, options); - var options = {"epsilon": 10e-18}; - - var feature1 = featureCollection.features[0].geometry; - var feature2 = featureCollection.features[1].geometry; - expect( - booleanPointOnLine(feature1 as Point, feature2 as LineString, - epsilon: options["epsilon"]), - equals(false)); - // True Fixtures - var featureCollection1 = FeatureCollection(features: [ - Feature( - properties: {}, geometry: Point(coordinates: Position.of([2, 2]))), - Feature( - properties: {}, - geometry: LineString( - coordinates: [ - Position.of([0, 0]), - Position.of([3, 3]), - Position.of([38.3203125, 5.965753671065536]) - ], - ), - ) - ]); - - feature1 = featureCollection1.features[0].geometry; - feature2 = featureCollection1.features[1].geometry; - expect( - booleanPointOnLine(feature1 as Point, feature2 as LineString, - epsilon: options["epsilon"]), - equals(true)); - }, - ); -} + t.false(result, "[false] " + name); + }); + t.end(); +}); \ No newline at end of file From 40a98475ddfe7dfd1c620291fdd61373bcc5d143 Mon Sep 17 00:00:00 2001 From: armantorkzaban Date: Sat, 2 Jul 2022 00:40:51 +0200 Subject: [PATCH 36/82] tests reverted to false/true folder style --- lib/src/booleans/boolean_point_on_line.dart | 61 +++++----- lib/src/line_intersect.dart | 34 +++--- test/.DS_Store | Bin 0 -> 6148 bytes test/booleans/clockwise_test.dart | 106 +++++++----------- test/booleans/concave_test.dart | 96 +++++++--------- test/booleans/contains_test.dart | 4 +- test/booleans/crosses_test.dart | 95 +++++++--------- test/booleans/point_on_line_test.dart | 88 +++++++++------ test/examples/.DS_Store | Bin 0 -> 8196 bytes test/examples/booleans/.DS_Store | Bin 0 -> 6148 bytes .../false/counter-clockwise-line.geojson | 18 +++ .../clockwise/true/clockwise-line.geojson | 18 +++ .../booleans/concave/false/3vertices.geojson | 20 ++++ .../booleans/concave/false/diamond.geojson | 22 ++++ .../booleans/concave/false/square.geojson | 21 ++++ .../booleans/concave/true/polygon.geojson | 22 ++++ .../booleans/concave/true/polygon2.geojson | 28 +++++ .../contains}/diagrams/esri-contains.gif | Bin .../LineIsNotContainedByLine.geojson | 0 .../LineIsNotContainedByPolygon.geojson | 0 ...ineIsNotContainedByPolygonBoundary.geojson | 0 .../MultiPointsIsNotContainedByLine.geojson | 0 ...intsOnLineEndsIsNotContainedByLine.geojson | 0 ...ltiPointIsNotContainedByMultiPoint.geojson | 0 ...lOnBoundaryIsNotContainedByPolygon.geojson | 0 .../MultiPointIsNotContainedByPolygon.geojson | 0 .../PointIsNotContainedByLine.geojson | 0 ...ntIsNotContainedByLineBecauseOnEnd.geojson | 0 .../PointOnEndIsContainedByLinestring.geojson | 0 .../PointIsNotContainedBYMultiPoint.geojson | 0 .../PointIsNotContainedByPolygon.geojson | 0 .../Polygon/PointOnPolygonBoundary.geojson | 0 .../LineString/issue-#1201-false.geojson | 0 .../Polygon/Polygon/Polygon-Polygon.geojson | 0 .../Polygon/Polygon/Polygon-Polygon2.geojson | 0 .../LineString/LineIsContainedByLine.geojson | 0 .../LineString/LinesExactlySame.geojson | 0 .../Polygon/LineIsContainedByPolygon.geojson | 0 ...nedByPolygonWithNoInternalVertices.geojson | 0 .../MultipointsIsContainedByLine.geojson | 0 .../MultiPointsContainedByMultiPoints.geojson | 0 .../MultiPoint/MultiPointsEqual.geojson | 0 ...iPointIsContainedByPolygonBoundary.geojson | 0 .../LineString/PointIsContainedByLine.geojson | 0 .../PointIsContainedByMultiPoint.geojson | 0 .../PointInsidePolygonBoundary.geojson | 0 .../LineString/issue-#1201-true.geojson | 0 .../Polygon/PolygonExactSameShape.geojson | 0 .../PolygonIsContainedByPolygon.geojson | 0 .../LineDoesNotCrossButTouches.geojson | 29 +++++ .../LineString/LineDoesNotCrossLine.geojson | 29 +++++ .../Polygon/LineDoesNotCrossPolygon.geojson | 32 ++++++ .../LineString/MultiPointNotCrossLine.geojson | 29 +++++ .../MultiPointNotCrossLineEnd.geojson | 29 +++++ .../Polygon/MultiPointNotCrossPolygon.geojson | 32 ++++++ .../LineString/LineCrossesLine.geojson | 29 +++++ .../Polygon/LineCrossesPolygon.geojson | 34 ++++++ .../Polygon/LineCrossesPolygonPartial.geojson | 32 ++++++ .../LineString/MultiPointsCrossLine.geojson | 29 +++++ .../Polygon/MultiPointsCrossPolygon.geojson | 32 ++++++ ...LineWithOnly1SegmentIgnoreBoundary.geojson | 27 +++++ ...eWithOnly1SegmentIgnoreBoundaryEnd.geojson | 27 +++++ ...nLineButFailsWithSmallEpsilonValue.geojson | 27 +++++ ...utEpsilonForBackwardsCompatibility.geojson | 24 ++++ ...PointOnEndFailsWhenIgnoreEndpoints.geojson | 28 +++++ ...intOnStartFailsWhenIgnoreEndpoints.geojson | 28 +++++ .../point_on_line/false/notOnLine.geojson | 28 +++++ .../true/LineWithOnly1Segment.geojson | 27 +++++ .../true/LineWithOnly1SegmentOnStart.geojson | 24 ++++ .../true/PointOnFirstSegment.geojson | 28 +++++ .../true/PointOnLastSegment.geojson | 28 +++++ .../point_on_line/true/PointOnLineEnd.geojson | 25 +++++ .../true/PointOnLineMidVertice.geojson | 28 +++++ .../true/PointOnLineMidpoint.geojson | 25 +++++ .../true/PointOnLineStart.geojson | 25 +++++ .../true/PointOnLineWithEpsilon.geojson | 27 +++++ 76 files changed, 1132 insertions(+), 263 deletions(-) create mode 100644 test/.DS_Store create mode 100644 test/examples/.DS_Store create mode 100644 test/examples/booleans/.DS_Store create mode 100644 test/examples/booleans/clockwise/false/counter-clockwise-line.geojson create mode 100644 test/examples/booleans/clockwise/true/clockwise-line.geojson create mode 100644 test/examples/booleans/concave/false/3vertices.geojson create mode 100644 test/examples/booleans/concave/false/diamond.geojson create mode 100644 test/examples/booleans/concave/false/square.geojson create mode 100644 test/examples/booleans/concave/true/polygon.geojson create mode 100644 test/examples/booleans/concave/true/polygon2.geojson rename test/examples/{boolean_contains => booleans/contains}/diagrams/esri-contains.gif (100%) rename test/examples/{boolean_contains => booleans/contains}/test/false/LineString/LineString/LineIsNotContainedByLine.geojson (100%) rename test/examples/{boolean_contains => booleans/contains}/test/false/LineString/Polygon/LineIsNotContainedByPolygon.geojson (100%) rename test/examples/{boolean_contains => booleans/contains}/test/false/LineString/Polygon/LineIsNotContainedByPolygonBoundary.geojson (100%) rename test/examples/{boolean_contains => booleans/contains}/test/false/MultiPoint/LineString/MultiPointsIsNotContainedByLine.geojson (100%) rename test/examples/{boolean_contains => booleans/contains}/test/false/MultiPoint/LineString/MultiPointsOnLineEndsIsNotContainedByLine.geojson (100%) rename test/examples/{boolean_contains => booleans/contains}/test/false/MultiPoint/MultiPoint/MultiPointIsNotContainedByMultiPoint.geojson (100%) rename test/examples/{boolean_contains => booleans/contains}/test/false/MultiPoint/Polygon/MultiPointAllOnBoundaryIsNotContainedByPolygon.geojson (100%) rename test/examples/{boolean_contains => booleans/contains}/test/false/MultiPoint/Polygon/MultiPointIsNotContainedByPolygon.geojson (100%) rename test/examples/{boolean_contains => booleans/contains}/test/false/Point/LineString/PointIsNotContainedByLine.geojson (100%) rename test/examples/{boolean_contains => booleans/contains}/test/false/Point/LineString/PointIsNotContainedByLineBecauseOnEnd.geojson (100%) rename test/examples/{boolean_contains => booleans/contains}/test/false/Point/LineString/PointOnEndIsContainedByLinestring.geojson (100%) rename test/examples/{boolean_contains => booleans/contains}/test/false/Point/MultiPoint/PointIsNotContainedBYMultiPoint.geojson (100%) rename test/examples/{boolean_contains => booleans/contains}/test/false/Point/Polygon/PointIsNotContainedByPolygon.geojson (100%) rename test/examples/{boolean_contains => booleans/contains}/test/false/Point/Polygon/PointOnPolygonBoundary.geojson (100%) rename test/examples/{boolean_contains => booleans/contains}/test/false/Polygon/LineString/issue-#1201-false.geojson (100%) rename test/examples/{boolean_contains => booleans/contains}/test/false/Polygon/Polygon/Polygon-Polygon.geojson (100%) rename test/examples/{boolean_contains => booleans/contains}/test/false/Polygon/Polygon/Polygon-Polygon2.geojson (100%) rename test/examples/{boolean_contains => booleans/contains}/test/true/LineString/LineString/LineIsContainedByLine.geojson (100%) rename test/examples/{boolean_contains => booleans/contains}/test/true/LineString/LineString/LinesExactlySame.geojson (100%) rename test/examples/{boolean_contains => booleans/contains}/test/true/LineString/Polygon/LineIsContainedByPolygon.geojson (100%) rename test/examples/{boolean_contains => booleans/contains}/test/true/LineString/Polygon/LineIsContainedByPolygonWithNoInternalVertices.geojson (100%) rename test/examples/{boolean_contains => booleans/contains}/test/true/MultiPoint/LineString/MultipointsIsContainedByLine.geojson (100%) rename test/examples/{boolean_contains => booleans/contains}/test/true/MultiPoint/MultiPoint/MultiPointsContainedByMultiPoints.geojson (100%) rename test/examples/{boolean_contains => booleans/contains}/test/true/MultiPoint/MultiPoint/MultiPointsEqual.geojson (100%) rename test/examples/{boolean_contains => booleans/contains}/test/true/MultiPoint/Polygon/MultiPointIsContainedByPolygonBoundary.geojson (100%) rename test/examples/{boolean_contains => booleans/contains}/test/true/Point/LineString/PointIsContainedByLine.geojson (100%) rename test/examples/{boolean_contains => booleans/contains}/test/true/Point/MultiPoint/PointIsContainedByMultiPoint.geojson (100%) rename test/examples/{boolean_contains => booleans/contains}/test/true/Point/Polygon/PointInsidePolygonBoundary.geojson (100%) rename test/examples/{boolean_contains => booleans/contains}/test/true/Polygon/LineString/issue-#1201-true.geojson (100%) rename test/examples/{boolean_contains => booleans/contains}/test/true/Polygon/Polygon/PolygonExactSameShape.geojson (100%) rename test/examples/{boolean_contains => booleans/contains}/test/true/Polygon/Polygon/PolygonIsContainedByPolygon.geojson (100%) create mode 100644 test/examples/booleans/crosses/false/LineString/LineString/LineDoesNotCrossButTouches.geojson create mode 100644 test/examples/booleans/crosses/false/LineString/LineString/LineDoesNotCrossLine.geojson create mode 100644 test/examples/booleans/crosses/false/LineString/Polygon/LineDoesNotCrossPolygon.geojson create mode 100644 test/examples/booleans/crosses/false/MultiPoint/LineString/MultiPointNotCrossLine.geojson create mode 100644 test/examples/booleans/crosses/false/MultiPoint/LineString/MultiPointNotCrossLineEnd.geojson create mode 100644 test/examples/booleans/crosses/false/MultiPoint/Polygon/MultiPointNotCrossPolygon.geojson create mode 100644 test/examples/booleans/crosses/true/LineString/LineString/LineCrossesLine.geojson create mode 100644 test/examples/booleans/crosses/true/LineString/Polygon/LineCrossesPolygon.geojson create mode 100644 test/examples/booleans/crosses/true/LineString/Polygon/LineCrossesPolygonPartial.geojson create mode 100644 test/examples/booleans/crosses/true/MultiPoint/LineString/MultiPointsCrossLine.geojson create mode 100644 test/examples/booleans/crosses/true/MultiPoint/Polygon/MultiPointsCrossPolygon.geojson create mode 100644 test/examples/booleans/point_on_line/false/LineWithOnly1SegmentIgnoreBoundary.geojson create mode 100644 test/examples/booleans/point_on_line/false/LineWithOnly1SegmentIgnoreBoundaryEnd.geojson create mode 100644 test/examples/booleans/point_on_line/false/PointIsOnLineButFailsWithSmallEpsilonValue.geojson create mode 100644 test/examples/booleans/point_on_line/false/PointIsOnLineButFailsWithoutEpsilonForBackwardsCompatibility.geojson create mode 100644 test/examples/booleans/point_on_line/false/PointOnEndFailsWhenIgnoreEndpoints.geojson create mode 100644 test/examples/booleans/point_on_line/false/PointOnStartFailsWhenIgnoreEndpoints.geojson create mode 100644 test/examples/booleans/point_on_line/false/notOnLine.geojson create mode 100644 test/examples/booleans/point_on_line/true/LineWithOnly1Segment.geojson create mode 100644 test/examples/booleans/point_on_line/true/LineWithOnly1SegmentOnStart.geojson create mode 100644 test/examples/booleans/point_on_line/true/PointOnFirstSegment.geojson create mode 100644 test/examples/booleans/point_on_line/true/PointOnLastSegment.geojson create mode 100644 test/examples/booleans/point_on_line/true/PointOnLineEnd.geojson create mode 100644 test/examples/booleans/point_on_line/true/PointOnLineMidVertice.geojson create mode 100644 test/examples/booleans/point_on_line/true/PointOnLineMidpoint.geojson create mode 100644 test/examples/booleans/point_on_line/true/PointOnLineStart.geojson create mode 100644 test/examples/booleans/point_on_line/true/PointOnLineWithEpsilon.geojson diff --git a/lib/src/booleans/boolean_point_on_line.dart b/lib/src/booleans/boolean_point_on_line.dart index 33d20211..186719b4 100644 --- a/lib/src/booleans/boolean_point_on_line.dart +++ b/lib/src/booleans/boolean_point_on_line.dart @@ -1,30 +1,26 @@ import 'package:turf/helpers.dart'; -import '../invariant.dart'; - -/** - * Returns true if a point is on a line. Accepts a optional parameter to ignore the - * start and end vertices of the linestring. - * - * @name booleanPointOnLine - * @param {Coord} pt GeoJSON Point - * @param {Feature} line GeoJSON LineString - * @param {Object} [options={}] Optional parameters - * @param {boolean} [options.ignoreEndVertices=false] whether to ignore the start and end vertices. - * @param {number} [options.epsilon] Fractional number to compare with the cross product result. Useful for dealing with floating points such as lng/lat points - * @returns {boolean} true/false - * @example - * var pt = turf.point([0, 0]); - * var line = turf.lineString([[-1, -1],[1, 1],[1.5, 2.2]]); - * var isPointOnLine = turf.booleanPointOnLine(pt, line); - * //=true - */ +/// Returns true if a point is on a line. Accepts an optional parameter to ignore the +/// start and end vertices of the [Linestring]. +/// The [ignoreEndVertices=false] controls whether to ignore the start and end vertices. +/// [epsilon] is the Fractional number to compare with the cross product result. +/// It's useful for dealing with floating points such as lng/lat points +/// example: +/// ```dart +/// var pt = Point(coordinates:Position.of([0, 0])); +/// var line = LineString(coordinates: [ +/// Position.of([-1, -1]), +/// Position.of([1, 1]), +/// Position.of([1.5, 2.2]), +/// ]); +/// var isPointOnLine = booleanPointOnLine(pt, line); +/// //=true +/// ``` bool booleanPointOnLine(Point pt, LineString line, {bool ignoreEndVertices = false, num? epsilon}) { - // Main for (var i = 0; i < line.coordinates.length - 1; i++) { dynamic ignoreBoundary = false; - if (ignoreEndVertices && ignoreEndVertices) { + if (ignoreEndVertices) { if (i == 0) { ignoreBoundary = "start"; } @@ -35,7 +31,7 @@ bool booleanPointOnLine(Point pt, LineString line, ignoreBoundary = "both"; } } - if (isPointOnLineSegment(line.coordinates[i], line.coordinates[i + 1], + if (_isPointOnLineSegment(line.coordinates[i], line.coordinates[i + 1], pt.coordinates, ignoreBoundary, epsilon)) { return true; } @@ -45,17 +41,11 @@ bool booleanPointOnLine(Point pt, LineString line, // See http://stackoverflow.com/a/4833823/1979085 // See https://stackoverflow.com/a/328122/1048847 -/** - * @private - * @param {Position} lineSegmentStart coord pair of start of line - * @param {Position} lineSegmentEnd coord pair of end of line - * @param {Position} pt coord pair of point to check - * @param {boolean|string} excludeBoundary whether the point is allowed to fall on the line ends. - * @param {number} epsilon Fractional number to compare with the cross product result. Useful for dealing with floating points such as lng/lat points - * If true which end to ignore. - * @returns {boolean} true/false - */ -bool isPointOnLineSegment(Position lineSegmentStart, Position lineSegmentEnd, +/// [pt] is the coord pair of the [Point] to check. +/// [excludeBoundary] controls whether the point is allowed to fall on the line ends. +/// [epsilon] is the Fractional number to compare with the cross product result. +/// Useful for dealing with floating points such as lng/lat points. +bool _isPointOnLineSegment(Position lineSegmentStart, Position lineSegmentEnd, Position pt, dynamic excludeBoundary, num? epsilon) { var x = pt[0]!; var y = pt[1]!; @@ -75,7 +65,7 @@ bool isPointOnLineSegment(Position lineSegmentStart, Position lineSegmentEnd, } else if (cross != 0) { return false; } - if (excludeBoundary != null) { + if (excludeBoundary is bool && !excludeBoundary) { if ((dxl).abs() >= (dyl).abs()) { return dxl > 0 ? x1 <= x && x <= x2 : x2 <= x && x <= x1; } @@ -99,7 +89,6 @@ bool isPointOnLineSegment(Position lineSegmentStart, Position lineSegmentEnd, return false; } - /** * import { Feature, LineString } from "geojson"; import { Coord } from "@turf/helpers"; @@ -225,4 +214,4 @@ function isPointOnLineSegment( } export default booleanPointOnLine; - */ \ No newline at end of file + */ diff --git a/lib/src/line_intersect.dart b/lib/src/line_intersect.dart index c8c06bdd..6bcb1de0 100644 --- a/lib/src/line_intersect.dart +++ b/lib/src/line_intersect.dart @@ -1,24 +1,22 @@ import '../helpers.dart'; -/** - * Takes any LineString or Polygon GeoJSON and returns the intersecting point(s). - * - * @name lineIntersect - * @param {GeoJSON} line1 any LineString or Polygon - * @param {GeoJSON} line2 any LineString or Polygon - * @param {Object} [options={}] Optional parameters - * @param {boolean} [options.removeDuplicates=true] remove duplicate intersections - * @param {boolean} [options.ignoreSelfIntersections=false] ignores self-intersections on input features - * @returns {FeatureCollection} point(s) that intersect both - * @example - * var line1 = turf.lineString([[126, -11], [129, -21]]); - * var line2 = turf.lineString([[123, -18], [131, -14]]); - * var intersects = turf.lineIntersect(line1, line2); - * - * //addToMap - * var addToMap = [line1, line2, intersects] - */ + +/// Takes any LineString or Polygon GeoJSON and returns the intersecting point(s). +/// @name lineIntersect +/// @param {GeoJSON} line1 any LineString or Polygon +/// @param {GeoJSON} line2 any LineString or Polygon +/// @param {Object} [options={}] Optional parameters +/// @param {boolean} [options.removeDuplicates=true] remove duplicate intersections +/// @param {boolean} [options.ignoreSelfIntersections=false] ignores self-intersections on input features +/// @returns {FeatureCollection} point(s) that intersect both +/// @example +/// var line1 = turf.lineString([[126, -11], [129, -21]]); +/// var line2 = turf.lineString([[123, -18], [131, -14]]); +/// var intersects = turf.lineIntersect(line1, line2); +/// //addToMap +/// var addToMap = [line1, line2, intersects] + FeatureCollection lineIntersect( GeoJSONObject line1, GeoJSONObject line2, diff --git a/test/.DS_Store b/test/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..62a28beec82e0e600297cf88246c0e6f48043a4d GIT binary patch literal 6148 zcmeHKL2uJA6n^f?<}e}kz@%M}EOD(y#t>4)C6sa4l^{3(D#=noL}ph_N+(s7a%Mkf zSAGe9XME50pratP3qq4$^!z>B?{k#Ti5(M>7|x1)q8<@RIAbS5@f+iQ_BHGHmQA3r zV~i;yP4!V_j@Pn7!~duN&z+>446ce+<}a^Ijy`@dp2GJotRW)0O~=SSp$SS2j;6-V z`3mR!7mh^UDc%ld@qO$&@-tuD`&)iKuO~kLYd)#Ux{2d&qO;MxwYep?!DFgU65hYCn#beYF@ojQeVEFjy`lxpV))lNX~;)rmG=SR8x`_!g|)@puVm2-bA? zoKAIR^au1YFM>iDmC$sL3Pe+C_-k5Gibq+U4OD{#1%d)Wfom$@*D1MuOmYY)eJt%ARYvvFSQ@COBf-HMURTk$U38rl^Hz{F$g5G}CqBVc6+MNr_MD)1dO C%z~2u literal 0 HcmV?d00001 diff --git a/test/booleans/clockwise_test.dart b/test/booleans/clockwise_test.dart index 7a895732..a9b9da9d 100644 --- a/test/booleans/clockwise_test.dart +++ b/test/booleans/clockwise_test.dart @@ -1,73 +1,45 @@ +import 'dart:convert'; +import 'dart:io'; + import 'package:test/test.dart'; import 'package:turf/helpers.dart'; import 'package:turf/src/booleans/boolean_clockwise.dart'; main() { - // test("isClockwise#fixtures", () { - // // True Fixtures - // glob - // .sync(path.join(__dirname, "test", "true", "*.geojson")) - // .forEach((filepath) => { - // const name = path.parse(filepath).name; - // const geojson = load.sync(filepath); - // const feature = geojson.features[0]; - // t.true(isClockwise(feature), "[true] " + name); - // }); - // // False Fixtures - // glob - // .sync(path.join(__dirname, "test", "false", "*.geojson")) - // .forEach((filepath) => { - // const name = path.parse(filepath).name; - // const geojson = load.sync(filepath); - // const feature = geojson.features[0]; - // t.false(isClockwise(feature), "[false] " + name); - // }); - // t.end(); - // }); - - test("isClockwise", () { - const cwArray = [ - [0, 0], - [1, 1], - [1, 0], - [0, 0], - ]; - const ccwArray = [ - [0, 0], - [1, 0], - [1, 1], - [0, 0], - ]; - - expect( - booleanClockwise(cwArray), - equals( - true, - ), - ); - - expect( - booleanClockwise(ccwArray), - equals(false), - ); - }); - - test("isClockwise -- Geometry types", () { - LineString line = LineString(coordinates: [ - Position.of([0, 0]), - Position.of([1, 1]), - Position.of([1, 0]), - Position.of([0, 0]), - ]); - - expect(booleanClockwise(line), equals(true)); - expect(booleanClockwise(line.coordinates), equals(true)); - }); - -// test('isClockwise -- throws', t => { -// const pt = point([-10, -33]); -// t.throws(() => isClockwise(pt), 'feature geometry not supported'); - -// t.end(); -// }); + group( + 'clockwise', + () { + var inDir = Directory('./test/examples/booleans/clockwise/true'); + for (var file in inDir.listSync(recursive: true)) { + if (file is File && file.path.endsWith('.geojson')) { + test(file.path, () { + // True Fixtures + var inSource = file.readAsStringSync(); + dynamic json = jsonDecode(inSource); + var inGeom = GeoJSONObject.fromJson(json); + var feature0 = (inGeom as FeatureCollection).features[0]; + + expect(booleanClockwise(feature0), true); + }); + } + } + + var inDir1 = Directory('./test/examples/booleans/clockwise/false'); + for (var file in inDir1.listSync(recursive: true)) { + if (file is File && file.path.endsWith('.geojson')) { + test( + file.path, + () { + // True Fixtures + var inSource = file.readAsStringSync(); + dynamic json = jsonDecode(inSource); + var inGeom = GeoJSONObject.fromJson(json); + var feature0 = (inGeom as FeatureCollection).features[0]; + expect(booleanClockwise(feature0), false); + }, + ); + } + } + }, + ); } diff --git a/test/booleans/concave_test.dart b/test/booleans/concave_test.dart index e2743ac3..1c55fe84 100644 --- a/test/booleans/concave_test.dart +++ b/test/booleans/concave_test.dart @@ -1,64 +1,48 @@ +import 'dart:convert'; +import 'dart:io'; + import 'package:test/test.dart'; import 'package:turf/helpers.dart'; import 'package:turf/src/booleans/boolean_concave.dart'; main() { -// test("isConcave#fixtures", (t) => { -// // True Fixtures -// glob -// .sync(path.join(__dirname, "test", "true", "*.geojson")) -// .forEach((filepath) => { -// const name = path.parse(filepath).name; -// const geojson = load.sync(filepath); -// const feature = geojson.features[0]; -// t.true(isConcave(feature), "[true] " + name); -// }); -// // False Fixtures -// glob -// .sync(path.join(__dirname, "test", "false", "*.geojson")) -// .forEach((filepath) => { -// const name = path.parse(filepath).name; -// const geojson = load.sync(filepath); -// const feature = geojson.features[0]; -// t.false(isConcave(feature), "[false] " + name); -// }); -// t.end(); -// }); - - test("isConcave -- Geometry types", () { - var featureCollection = FeatureCollection(features: [ - Feature( - properties: {}, - geometry: Polygon(coordinates: [ - [ - Position.of([0.85418701171875, 1.06286628163273]), - Position.of([0.46966552734375, 0.7909904981540058]), - Position.of([0.6619262695312499, 0.5712795966325395]), - Position.of([0.77178955078125, 0.856901647439813]), - Position.of([0.736083984375, 0.8514090937773031]), - Position.of([0.6591796875, 0.8129610018708315]), - Position.of([0.6921386718749999, 0.884364296613886]), - Position.of([0.9173583984375001, 0.8898568022677679]), - Position.of([1.07391357421875, 0.8129610018708315]), - Position.of([1.0876464843749998, 0.9392889790847924]), - Position.of([1.0052490234375, 1.0271666545523288]), - Position.of([0.85418701171875, 1.06286628163273]), - ] - ])) - ]); + group( + 'concave', + () { + var inDir = Directory('./test/examples/booleans/concave/true'); - Polygon poly = Polygon(coordinates: [ - [ - Position.of([0, 0]), - Position.of([0, 1]), - Position.of([1, 1]), - Position.of([1, 0]), - Position.of([0, 0]), - ], - ]); + for (var file in inDir.listSync(recursive: true)) { + if (file is File && file.path.endsWith('.geojson')) { + test( + file.path, + () { + // True Fixtures + var inSource = file.readAsStringSync(); + dynamic json = jsonDecode(inSource); + var inGeom = GeoJSONObject.fromJson(json); + var feature = (inGeom as FeatureCollection).features[0]; + expect(booleanConcave(feature), true); + }, + ); + } + } - expect(booleanConcave(poly), equals(false)); - expect(booleanConcave(featureCollection.features.first.geometry!), - equals(true)); - }); + var inDir1 = Directory('./test/examples/booleans/concave/false'); + for (var file in inDir1.listSync(recursive: true)) { + if (file is File && file.path.endsWith('.geojson')) { + test( + file.path, + () { + // False Fixtures + var inSource = file.readAsStringSync(); + dynamic json = jsonDecode(inSource); + var inGeom = GeoJSONObject.fromJson(json); + var feature = (inGeom as FeatureCollection).features[0]; + expect(booleanConcave(feature), false); + }, + ); + } + } + }, + ); } diff --git a/test/booleans/contains_test.dart b/test/booleans/contains_test.dart index 4ac49384..de9057af 100644 --- a/test/booleans/contains_test.dart +++ b/test/booleans/contains_test.dart @@ -9,7 +9,7 @@ main() { group( 'contains', () { - var inDir = Directory('./test/examples/boolean_contains/test/true'); + var inDir = Directory('./test/examples/booleans/contains/test/true'); for (var file in inDir.listSync(recursive: true)) { if (file is File && file.path.endsWith('.geojson')) { test( @@ -27,7 +27,7 @@ main() { } } - var inDir1 = Directory('./test/examples/boolean_contains/test/false'); + var inDir1 = Directory('./test/examples/booleans/contains/test/false'); for (var file in inDir1.listSync(recursive: true)) { if (file is File && file.path.endsWith('.geojson')) { test( diff --git a/test/booleans/crosses_test.dart b/test/booleans/crosses_test.dart index ba8d749e..7c9f57c0 100644 --- a/test/booleans/crosses_test.dart +++ b/test/booleans/crosses_test.dart @@ -1,59 +1,50 @@ +import 'dart:convert'; +import 'dart:io'; + import 'package:test/test.dart'; import 'package:turf/helpers.dart'; import 'package:turf/src/booleans/boolean_crosses.dart'; main() { - test("turf-boolean-crosses", () { - // True Fixtures - var featureCollection = FeatureCollection(features: [ - Feature( - properties: {}, - geometry: MultiPoint(coordinates: [ - Position.of([3, 3]), - Position.of([1, 1]) - ])), - Feature( - properties: {}, - geometry: Polygon(coordinates: [ - [ - Position.of([0, 2]), - Position.of([2, 2]), - Position.of([2, 0]), - Position.of([0, 0]), - Position.of([0, 2]) - ] - ])) - ]); - - var feature1 = featureCollection.features[0]; - var feature2 = featureCollection.features[1]; - expect( - booleanCrosses(feature1.geometry!, feature2.geometry!), equals(true)); - - // False Fixtures - var featureCollection1 = FeatureCollection(features: [ - Feature( - properties: {}, - geometry: MultiPoint(coordinates: [ - Position.of([3, 3]), - Position.of([1, 1]) - ])), - Feature( - properties: {}, - geometry: Polygon(coordinates: [ - [ - Position.of([0, 2]), - Position.of([2, 2]), - Position.of([2, 0]), - Position.of([0, 0]), - Position.of([0, 2]) - ] - ])) - ]); + group( + 'boolean_crosses', + () { + var inDir = Directory('./test/examples/booleans/crosses/true'); + for (var file in inDir.listSync(recursive: true)) { + if (file is File && file.path.endsWith('.geojson')) { + test( + file.path, + () { + // True Fixtures + var inSource = file.readAsStringSync(); + var inGeom = GeoJSONObject.fromJson(jsonDecode(inSource)); + var feature1 = (inGeom as FeatureCollection).features[0]; + var feature2 = inGeom.features[1]; - feature1 = featureCollection1.features[0]; - feature2 = featureCollection1.features[1]; - expect( - booleanCrosses(feature1.geometry!, feature2.geometry!), equals(false)); - }); + expect( + booleanCrosses(feature1.geometry!, feature2.geometry!), true); + }, + ); + } + } + // False Fixtures + var inDir1 = Directory('./test/examples/booleans/crosses/false'); + for (var file in inDir1.listSync(recursive: true)) { + if (file is File && file.path.endsWith('.geojson')) { + test( + file.path, + () { + // True Fixtures + var inSource = file.readAsStringSync(); + var inGeom = GeoJSONObject.fromJson(jsonDecode(inSource)); + var feature1 = (inGeom as FeatureCollection).features[0]; + var feature2 = inGeom.features[1]; + expect(booleanCrosses(feature1.geometry!, feature2.geometry!), + false); + }, + ); + } + } + }, + ); } diff --git a/test/booleans/point_on_line_test.dart b/test/booleans/point_on_line_test.dart index de59bc0c..c6177f66 100644 --- a/test/booleans/point_on_line_test.dart +++ b/test/booleans/point_on_line_test.dart @@ -1,35 +1,59 @@ -const glob = require("glob"); -const path = require("path"); -const test = require("tape"); -const load = require("load-json-file"); -const pointOnLine = require("./index").default; +import 'dart:convert'; +import 'dart:io'; -test("turf-boolean-point-on-line", (t) => { - // True Fixtures - glob - .sync(path.join(__dirname, "test", "true", "**", "*.geojson")) - .forEach((filepath) => { - const name = path.parse(filepath).name; - const geojson = load.sync(filepath); - const options = geojson.properties; - const feature1 = geojson.features[0]; - const feature2 = geojson.features[1]; - const result = pointOnLine(feature1, feature2, options); +import 'package:test/test.dart'; +import 'package:turf/helpers.dart'; +import 'package:turf/src/booleans/boolean_point_on_line.dart'; - t.true(result, "[true] " + name); - }); - // False Fixtures - glob - .sync(path.join(__dirname, "test", "false", "**", "*.geojson")) - .forEach((filepath) => { - const name = path.parse(filepath).name; - const geojson = load.sync(filepath); - const options = geojson.properties; - const feature1 = geojson.features[0]; - const feature2 = geojson.features[1]; - const result = pointOnLine(feature1, feature2, options); +main() { + group( + 'pointOnLine', + () { + var inDir = Directory('./test/examples/booleans/point_on_line/true'); + for (var file in inDir.listSync(recursive: true)) { + if (file is File && file.path.endsWith('.geojson')) { + test( + file.path, + () { + // True Fixtures + var inSource = file.readAsStringSync(); + dynamic json = jsonDecode(inSource); + var inGeom = GeoJSONObject.fromJson(jsonDecode(inSource)); + Map? properties = json['properties']; + var feature1 = (inGeom as FeatureCollection).features[0]; + var feature2 = inGeom.features[1]; + var result = booleanPointOnLine( + feature1.geometry as Point, feature2.geometry as LineString, + epsilon: properties?['epsilon'], + ignoreEndVertices: properties?['ignoreEndVertices'] ?? false); + expect(result, true); + }, + ); + } + } + // False Fixtures + var inDir1 = Directory('./test/examples/booleans/point_on_line/false'); + for (var file in inDir1.listSync(recursive: true)) { + if (file is File && file.path.endsWith('.geojson')) { + test( + file.path, + () { + var inSource = file.readAsStringSync(); + dynamic json = jsonDecode(inSource); + var inGeom = GeoJSONObject.fromJson(jsonDecode(inSource)); + Map? properties = json['properties']; + var feature1 = (inGeom as FeatureCollection).features[0]; + var feature2 = inGeom.features[1]; + var result = booleanPointOnLine( + feature1.geometry as Point, feature2.geometry as LineString, + epsilon: properties?['epsilon'], + ignoreEndVertices: properties?['ignoreEndVertices'] ?? false); - t.false(result, "[false] " + name); - }); - t.end(); -}); \ No newline at end of file + expect(result, false); + }, + ); + } + } + }, + ); +} diff --git a/test/examples/.DS_Store b/test/examples/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..8e8c309bc2f7d63be1bd9f75e580654135a625e9 GIT binary patch literal 8196 zcmeHM%Wl&^6upy%#!*!f2`Y6{$r550Abl%h6GB+9#RwLFj2)XMs^hWjq^VR@${PNF z1;4(CLl{jfrU{Tc0R5QmjbI&}E@7TF65wYeVSSMN~A`4kyWeLTM zB>F|3N(J3=3&_Byrx9=a5%*EAOj(--qkvJsC}0#Y3K#|c2LwHR8>|?mM+X$<*dK8?*DlWXhgqV(9enYVsGId`wePI3P`t5NvP#yH^~UM& zq0{&JgRJSLuSD%R=aGMM?fEad;n1zze$3;(*Nwwe61qVMlh-f1alnU7K8S-%avjxS zm94T{Sv@-1+}Wzy>$Tc()jq0k)T(xUvwnPBwpQ*uc=*iSk9skGujFI;5k$+Xep-IO z)f|nYy>+L}d&wzhE~Cd=Ev<{yySw}2+wNC!U*^oy_ zhKKawAzgS%mh+L%;CveMk(DWa0uK|+KDn+^B(osy$oM?xFfaY&ZEoY_ZPfqqvzS_zfNlWqkku literal 0 HcmV?d00001 diff --git a/test/examples/booleans/.DS_Store b/test/examples/booleans/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..5ef1b5e6c21e423a32abb67d75b4e17a0797c771 GIT binary patch literal 6148 zcmeHK!H&}~5FK|5b+lTk2axuH6p3pEg)X2Kmr#}iSAyUGC?wkoq78A?q?Bzc8L>-?5&L41mh6 zaYha0RMGrtvBQ?Yzo-D$E}&B?$e_JcKXaNDCc`X08js+&zFR|&XaKIE5^YN7T-FS#G79fKINFTD_3_>DC_I|n-)sVX{pRh5&yus^Luo!@2QY=-jI{%g z7r;C0XmB1c%fgiJFvD2~w17UWWlf2#M1l(PxKj)D4eZO6!%$2V5Cud5`%eNH^uA~z z3Wx%tKt}<7(+J^=k;m2{hd6Gp0Kh(v+0f?~M#j)% Date: Sun, 3 Jul 2022 16:38:52 +0200 Subject: [PATCH 37/82] restructuring, clean-up --- lib/src/booleans/boolean_crosses.dart | 5 +-- lib/src/booleans/boolean_disjoint.dart | 3 +- lib/src/booleans/boolean_equal.dart | 2 +- lib/src/booleans/boolean_intersect.dart | 25 +++++++------- lib/src/booleans/boolean_overlap.dart | 3 +- lib/src/booleans/boolean_parallel.dart | 2 +- .../booleans/boolean_point_in_polygon.dart | 4 +-- lib/src/booleans/boolean_point_on_line.dart | 3 +- lib/src/booleans/boolean_valid.dart | 3 +- lib/src/line_intersect.dart | 31 +++++++++--------- test/booleans/crosses_test.dart | 2 +- test/booleans/disjoint_test.dart | 1 + test/booleans/equal_test.dart | 1 + test/booleans/intersect_test.dart | 2 +- test/booleans/overlap_test.dart | 0 test/booleans/parallel_test.dart | 0 test/booleans/point_in_polygon_test.dart | 0 test/booleans/touches_test.dart | 0 test/booleans/valid_test.dart | 0 test/booleans/within_test.dart | 0 test/examples/.DS_Store | Bin 8196 -> 8196 bytes 21 files changed, 42 insertions(+), 45 deletions(-) create mode 100644 test/booleans/disjoint_test.dart create mode 100644 test/booleans/equal_test.dart create mode 100644 test/booleans/overlap_test.dart create mode 100644 test/booleans/parallel_test.dart create mode 100644 test/booleans/point_in_polygon_test.dart create mode 100644 test/booleans/touches_test.dart create mode 100644 test/booleans/valid_test.dart create mode 100644 test/booleans/within_test.dart diff --git a/lib/src/booleans/boolean_crosses.dart b/lib/src/booleans/boolean_crosses.dart index d9a1af6a..574f3363 100644 --- a/lib/src/booleans/boolean_crosses.dart +++ b/lib/src/booleans/boolean_crosses.dart @@ -3,8 +3,9 @@ import '../invariant.dart'; import '../line_intersect.dart'; import '../polygon_to_line.dart'; import 'boolean_point_in_polygon.dart'; -/** - * Boolean-Crosses returns True if the intersection results in a geometry whose dimension is one less than + + +Boolean-Crosses returns True if the intersection results in a geometry whose dimension is one less than * the maximum dimension of the two source geometries and the intersection set is interior to * both source geometries. * diff --git a/lib/src/booleans/boolean_disjoint.dart b/lib/src/booleans/boolean_disjoint.dart index 7e2f7b34..886e0d7c 100644 --- a/lib/src/booleans/boolean_disjoint.dart +++ b/lib/src/booleans/boolean_disjoint.dart @@ -4,8 +4,7 @@ import '../line_intersect.dart'; import '../polygon_to_line.dart'; import 'boolean_point_in_polygon.dart'; -/** - * Boolean-disjoint returns (TRUE) if the intersection of the two geometries is an empty set. + Boolean-disjoint returns (TRUE) if the intersection of the two geometries is an empty set. * * @name booleanDisjoint * @param {Geometry|Feature} feature1 GeoJSON Feature or Geometry diff --git a/lib/src/booleans/boolean_equal.dart b/lib/src/booleans/boolean_equal.dart index 0c79d49b..7e9db0a1 100644 --- a/lib/src/booleans/boolean_equal.dart +++ b/lib/src/booleans/boolean_equal.dart @@ -33,7 +33,7 @@ bool booleanEqual(GeoJSONObject feature1, GeoJSONObject feature2, -/** import { Feature, Geometry } from "geojson"; +import { Feature, Geometry } from "geojson"; import GeojsonEquality from "geojson-equality"; import cleanCoords from "@turf/clean-coords"; import { getGeom } from "@turf/invariant"; diff --git a/lib/src/booleans/boolean_intersect.dart b/lib/src/booleans/boolean_intersect.dart index 682ea6f2..9e230d6a 100644 --- a/lib/src/booleans/boolean_intersect.dart +++ b/lib/src/booleans/boolean_intersect.dart @@ -2,20 +2,17 @@ import '../../helpers.dart'; import '../../meta.dart'; import 'boolean_disjoint.dart'; -/** - * Boolean-intersects returns (TRUE) two geometries intersect. - * - * @name booleanIntersects - * @param {Geometry|Feature} feature1 GeoJSON Feature or Geometry - * @param {Geometry|Feature} feature2 GeoJSON Feature or Geometry - * @returns {boolean} true/false - * @example - * var point = turf.point([2, 2]); - * var line = turf.lineString([[1, 1], [1, 2], [1, 3], [1, 4]]); - * - * turf.booleanIntersects(line, point); - * //=true - */ + +Boolean-intersects returns (TRUE) two geometries intersect. +/// @name booleanIntersects +/// @param {Geometry|Feature} feature1 GeoJSON Feature or Geometry +/// @param {Geometry|Feature} feature2 GeoJSON Feature or Geometry +/// @returns {boolean} true/false +/// @example +/// var point = turf.point([2, 2]); +/// var line = turf.lineString([[1, 1], [1, 2], [1, 3], [1, 4]]); +/// turf.booleanIntersects(line, point); +//=true booleanIntersects(GeoJSONObject feature1, GeoJSONObject feature2) { var bool = false; flattenEach(feature1, (flatten1, featureIndex, multiFeatureIndex) { diff --git a/lib/src/booleans/boolean_overlap.dart b/lib/src/booleans/boolean_overlap.dart index 43fbc143..eb6295f5 100644 --- a/lib/src/booleans/boolean_overlap.dart +++ b/lib/src/booleans/boolean_overlap.dart @@ -6,8 +6,7 @@ import '../invariant.dart'; import '../line_intersect.dart'; import '../line_overlap.dart'; -/** - * Compares two geometries of the same dimension and returns true if their intersection set results in a geometry +Compares two geometries of the same dimension and returns true if their intersection set results in a geometry * different from both but of the same dimension. It applies to Polygon/Polygon, LineString/LineString, * Multipoint/Multipoint, MultiLineString/MultiLineString and MultiPolygon/MultiPolygon. * diff --git a/lib/src/booleans/boolean_parallel.dart b/lib/src/booleans/boolean_parallel.dart index a921e1c0..8153ebbd 100644 --- a/lib/src/booleans/boolean_parallel.dart +++ b/lib/src/booleans/boolean_parallel.dart @@ -55,7 +55,7 @@ GeoJSONObjectType _getType(GeoJSONObject geojson, String name) { } -/**import { Feature, Geometry, LineString, Position } from "geojson"; +{ Feature, Geometry, LineString, Position } from "geojson"; import cleanCoords from "@turf/clean-coords"; import lineSegment from "@turf/line-segment"; import rhumbBearing from "@turf/rhumb-bearing"; diff --git a/lib/src/booleans/boolean_point_in_polygon.dart b/lib/src/booleans/boolean_point_in_polygon.dart index 962c828f..d7aeed4e 100644 --- a/lib/src/booleans/boolean_point_in_polygon.dart +++ b/lib/src/booleans/boolean_point_in_polygon.dart @@ -61,8 +61,8 @@ bool _inBBox(Position pt, BBox bbox) { bbox[3]! >= pt[1]!); } -/** - * import pip from "point-in-polygon-hao"; + +import pip from "point-in-polygon-hao"; import { BBox, Feature, diff --git a/lib/src/booleans/boolean_point_on_line.dart b/lib/src/booleans/boolean_point_on_line.dart index 186719b4..f52d96e2 100644 --- a/lib/src/booleans/boolean_point_on_line.dart +++ b/lib/src/booleans/boolean_point_on_line.dart @@ -89,8 +89,7 @@ bool _isPointOnLineSegment(Position lineSegmentStart, Position lineSegmentEnd, return false; } -/** - * import { Feature, LineString } from "geojson"; +import { Feature, LineString } from "geojson"; import { Coord } from "@turf/helpers"; import { getCoord, getCoords } from "@turf/invariant"; diff --git a/lib/src/booleans/boolean_valid.dart b/lib/src/booleans/boolean_valid.dart index d30f0edd..20828cb2 100644 --- a/lib/src/booleans/boolean_valid.dart +++ b/lib/src/booleans/boolean_valid.dart @@ -4,8 +4,7 @@ import '../line_intersect.dart'; import 'boolean_crosses.dart'; import 'boolean_disjoint.dart'; -/** - * booleanValid checks if the geometry is a valid according to the OGC Simple Feature Specification. +booleanValid checks if the geometry is a valid according to the OGC Simple Feature Specification. * * @name booleanValid * @param {Geometry|Feature} feature GeoJSON Feature or Geometry diff --git a/lib/src/line_intersect.dart b/lib/src/line_intersect.dart index 6bcb1de0..48a84e77 100644 --- a/lib/src/line_intersect.dart +++ b/lib/src/line_intersect.dart @@ -1,22 +1,23 @@ import '../helpers.dart'; - -/// Takes any LineString or Polygon GeoJSON and returns the intersecting point(s). -/// @name lineIntersect -/// @param {GeoJSON} line1 any LineString or Polygon -/// @param {GeoJSON} line2 any LineString or Polygon -/// @param {Object} [options={}] Optional parameters -/// @param {boolean} [options.removeDuplicates=true] remove duplicate intersections -/// @param {boolean} [options.ignoreSelfIntersections=false] ignores self-intersections on input features -/// @returns {FeatureCollection} point(s) that intersect both -/// @example -/// var line1 = turf.lineString([[126, -11], [129, -21]]); -/// var line2 = turf.lineString([[123, -18], [131, -14]]); -/// var intersects = turf.lineIntersect(line1, line2); +/// Takes any [LineString] or [Polygon] and returns the intersecting [Point](s). +/// [removeDuplicates=true] removes duplicate intersections, +/// [ignoreSelfIntersections=false] ignores self-intersections on input features +/// Returns [FeatureCollection] point(s) that intersect both +/// example: +/// ```dart +/// var line1 = LineString(coordinates:[ +/// Position.of([126, -11]), +/// Position.of([129, -21]), +/// ]); +/// var line2 = LineString(coordinates:[ +/// Position.of([123, -18]), +/// Position.of([131, -14]), +/// ]); +/// var intersects = lineIntersect(line1, line2); /// //addToMap /// var addToMap = [line1, line2, intersects] - FeatureCollection lineIntersect( GeoJSONObject line1, GeoJSONObject line2, @@ -27,7 +28,7 @@ FeatureCollection lineIntersect( ){ var features= []; if (line1 is FeatureCollection) -{ features = features..addAll((line1 as FeatureCollection).features); +{ features = features..addAll(line1.features); } else if (line1 is Feature) {features.add(line1);} else if ( line1 is LineString || diff --git a/test/booleans/crosses_test.dart b/test/booleans/crosses_test.dart index 7c9f57c0..262ecacf 100644 --- a/test/booleans/crosses_test.dart +++ b/test/booleans/crosses_test.dart @@ -5,7 +5,7 @@ import 'package:test/test.dart'; import 'package:turf/helpers.dart'; import 'package:turf/src/booleans/boolean_crosses.dart'; -main() { +//main() { group( 'boolean_crosses', () { diff --git a/test/booleans/disjoint_test.dart b/test/booleans/disjoint_test.dart new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/test/booleans/disjoint_test.dart @@ -0,0 +1 @@ + diff --git a/test/booleans/equal_test.dart b/test/booleans/equal_test.dart new file mode 100644 index 00000000..1c8a0e79 --- /dev/null +++ b/test/booleans/equal_test.dart @@ -0,0 +1 @@ +; \ No newline at end of file diff --git a/test/booleans/intersect_test.dart b/test/booleans/intersect_test.dart index 35e0e15f..52e61b31 100644 --- a/test/booleans/intersect_test.dart +++ b/test/booleans/intersect_test.dart @@ -2,7 +2,7 @@ import 'package:test/test.dart'; import 'package:turf/helpers.dart'; import 'package:turf/src/booleans/boolean_intersect.dart'; -main() { +// main() { var featureCollection = FeatureCollection(features: [ Feature( properties: {"fill": "#ff0000"}, diff --git a/test/booleans/overlap_test.dart b/test/booleans/overlap_test.dart new file mode 100644 index 00000000..e69de29b diff --git a/test/booleans/parallel_test.dart b/test/booleans/parallel_test.dart new file mode 100644 index 00000000..e69de29b diff --git a/test/booleans/point_in_polygon_test.dart b/test/booleans/point_in_polygon_test.dart new file mode 100644 index 00000000..e69de29b diff --git a/test/booleans/touches_test.dart b/test/booleans/touches_test.dart new file mode 100644 index 00000000..e69de29b diff --git a/test/booleans/valid_test.dart b/test/booleans/valid_test.dart new file mode 100644 index 00000000..e69de29b diff --git a/test/booleans/within_test.dart b/test/booleans/within_test.dart new file mode 100644 index 00000000..e69de29b diff --git a/test/examples/.DS_Store b/test/examples/.DS_Store index 8e8c309bc2f7d63be1bd9f75e580654135a625e9..65a142cffd919c341efbaf565de247433f8dc309 100644 GIT binary patch delta 66 zcmV-I0KNZ&K!iY$PXQFMP`eKS6tfHv=mL`t6oC^tGb|uAH#B`LAbUA7Ff1T6Gd7bb Y5i_&n5=;cM2N?DQldBMFvyT*=0)_z-?*IS* delta 40 ycmV+@0N4M7K!iY$PXQCLP`eKS6SE8u=mN9M6FUTvfY`GK81@9S)fF-Vk$}}D@efe| From d3541b5ad00ed4975280e9bd3f7b34130ea25c30 Mon Sep 17 00:00:00 2001 From: armantorkzaban Date: Mon, 4 Jul 2022 09:33:07 +0200 Subject: [PATCH 38/82] clockwise and its test, documentation --- lib/src/booleans/boolean_clockwise.dart | 78 +++++++------------------ lib/src/invariant.dart | 1 + lib/src/line_overlap.dart | 53 ++++++++--------- lib/src/line_segment.dart | 8 --- test/booleans/clockwise_test.dart | 19 ++++++ 5 files changed, 65 insertions(+), 94 deletions(-) diff --git a/lib/src/booleans/boolean_clockwise.dart b/lib/src/booleans/boolean_clockwise.dart index c2c4392e..74efd4d7 100644 --- a/lib/src/booleans/boolean_clockwise.dart +++ b/lib/src/booleans/boolean_clockwise.dart @@ -1,70 +1,36 @@ import 'package:turf/src/invariant.dart'; -/** - * Takes a ring and return true or false whether or not the ring is clockwise or counter-clockwise. - * - * @name booleanClockwise - * @param {Feature|LineString|Array>} line to be evaluated - * @returns {boolean} true/false - * @example - * var clockwiseRing = turf.lineString([[0,0],[1,1],[1,0],[0,0]]); - * var counterClockwiseRing = turf.lineString([[0,0],[1,0],[1,1],[0,0]]); - * - * turf.booleanClockwise(clockwiseRing) - * //=true - * turf.booleanClockwise(counterClockwiseRing) - * //=false - */ +import '../../helpers.dart'; +/// Takes a ring and return true or false whether or not the ring is clockwise or counter-clockwise. +/// Takes a [Feature]or [LineString] or a [List] to be evaluated +/// example: +/// ```dart +/// var clockwiseRing = LineString(coordinates: [Position.of([0,0]),Position.of([1,1]),Position.of([1,0]),Position.of([0,0])]); +/// var counterClockwiseRing = LineString(coordinates: [Position.of([0,0]),Position.of([1,0]),Position.of([1,1]),Position.of([0,0])]); +/// +/// booleanClockwise(clockwiseRing) +/// //=true +/// booleanClockwise(counterClockwiseRing) +/// //=false +/// ``` bool booleanClockwise(dynamic line) { + if (line is List) { + if (line is! List) { + throw UnsupportedError(" type ${line.runtimeType} is not supperted"); + } + } var ring = getCoords(line); num sum = 0; - var i = 1; - var prev; - var cur; + int i = 1; + Position prev; + Position? cur; while (i < ring.length) { prev = cur ?? ring[0]; cur = ring[i]; - sum += (cur[0] - prev[0]) * (cur[1] + prev[1]); + sum += (cur![0]! - prev[0]!) * (cur[1]! + prev[1]!); i++; } return sum > 0; } - - -// import { Feature, LineString, Position } from "geojson"; -// import { getCoords } from "@turf/invariant"; - -// /** -// * Takes a ring and return true or false whether or not the ring is clockwise or counter-clockwise. -// * -// * @name booleanClockwise -// * @param {Feature|LineString|Array>} line to be evaluated -// * @returns {boolean} true/false -// * @example -// * var clockwiseRing = turf.lineString([[0,0],[1,1],[1,0],[0,0]]); -// * var counterClockwiseRing = turf.lineString([[0,0],[1,0],[1,1],[0,0]]); -// * -// * turf.booleanClockwise(clockwiseRing) -// * //=true -// * turf.booleanClockwise(counterClockwiseRing) -// * //=false -// */ -// export default function booleanClockwise( -// line: Feature | LineString | Position[] -// ): boolean { -// const ring = getCoords(line); -// let sum = 0; -// let i = 1; -// let prev; -// let cur; - -// while (i < ring.length) { -// prev = cur || ring[0]; -// cur = ring[i]; -// sum += (cur[0] - prev[0]) * (cur[1] + prev[1]); -// i++; -// } -// return sum > 0; -// } \ No newline at end of file diff --git a/lib/src/invariant.dart b/lib/src/invariant.dart index b8b7aa41..b3309747 100644 --- a/lib/src/invariant.dart +++ b/lib/src/invariant.dart @@ -77,6 +77,7 @@ _getCoordsForGeometry(GeometryObject geom) { return (geom as GeometryType).coordinates; } +// TODO /// Get Geometry or Geometries from [Feature] or [GeometryType] /// Returns [List] in case geojson is a [GeometryCollection] and a /// [GeometryType] if geojson is a simple [GeometryType]. diff --git a/lib/src/line_overlap.dart b/lib/src/line_overlap.dart index 75b8d6b1..6f957177 100644 --- a/lib/src/line_overlap.dart +++ b/lib/src/line_overlap.dart @@ -1,21 +1,17 @@ -/** - * Takes any LineString or Polygon and returns the overlapping lines between both features. - * - * @name lineOverlap - * @param {Geometry|Feature} line1 any LineString or Polygon - * @param {Geometry|Feature} line2 any LineString or Polygon - * @param {Object} [options={}] Optional parameters - * @param {number} [options.tolerance=0] Tolerance distance to match overlapping line segments (in kilometers) - * @returns {FeatureCollection} lines(s) that are overlapping between both features - * @example - * var line1 = turf.lineString([[115, -35], [125, -30], [135, -30], [145, -35]]); - * var line2 = turf.lineString([[115, -25], [125, -30], [135, -30], [145, -25]]); - * - * var overlapping = turf.lineOverlap(line1, line2); - * - * //addToMap - * var addToMap = [line1, line2, overlapping] - */ + +/// Takes any LineString or Polygon and returns the overlapping lines between both features. +/// @name lineOverlap +/// @param {Geometry|Feature} line1 any LineString or Polygon +/// @param {Geometry|Feature} line2 any LineString or Polygon +/// @param {Object} [options={}] Optional parameters +/// @param {number} [options.tolerance=0] Tolerance distance to match overlapping line segments (in kilometers) +/// @returns {FeatureCollection} lines(s) that are overlapping between both features +/// @example +/// var line1 = turf.lineString([[115, -35], [125, -30], [135, -30], [145, -35]]); +/// var line2 = turf.lineString([[115, -25], [125, -30], [135, -30], [145, -25]]); +/// var overlapping = turf.lineOverlap(line1, line2); +/// //addToMap +/// var addToMap = [line1, line2, overlapping] lineOverlap< G1 extends LineString | MultiLineString | Polygon | MultiPolygon, G2 extends LineString | MultiLineString | Polygon | MultiPolygon @@ -56,7 +52,7 @@ // Iterate over each segments which falls within the same bounds featureEach(tree.search(segment), function (match) { - if (doesOverlaps === false) { + if (doesOverlaps == false) { var coordsSegment = getCoords(segment).sort(); var coordsMatch: any = getCoords(match).sort(); @@ -70,7 +66,7 @@ } else overlapSegment = segment; // Match segments which don't share nodes (Issue #901) } else if ( - tolerance === 0 + tolerance == 0 ? booleanPointOnLine(coordsSegment[0], match) && booleanPointOnLine(coordsSegment[1], match) : nearestPointOnLine(match, coordsSegment[0]).properties.dist! <= @@ -84,7 +80,7 @@ concatSegment(overlapSegment, segment) || overlapSegment; } else overlapSegment = segment; } else if ( - tolerance === 0 + tolerance == 0 ? booleanPointOnLine(coordsMatch[0], segment) && booleanPointOnLine(coordsMatch[1], segment) : nearestPointOnLine(segment, coordsMatch[0]).properties.dist! <= @@ -122,15 +118,12 @@ return featureCollection(features); } -/** - * Concat Segment - * - * @private - * @param {Feature} line LineString - * @param {Feature} segment 2-vertex LineString - * @returns {Feature} concat linestring - */ -function concatSegment( +/// Concat Segment +/// /// @private +/// @param {Feature} line LineString +/// @param {Feature} segment 2-vertex LineString +/// @returns {Feature} concat linestring +concatSegment( line: Feature, segment: Feature ) { diff --git a/lib/src/line_segment.dart b/lib/src/line_segment.dart index c8218d6a..ba7dd164 100644 --- a/lib/src/line_segment.dart +++ b/lib/src/line_segment.dart @@ -7,7 +7,6 @@ import 'geojson.dart'; /// [LineString] or [MultiLineString] or [Polygon] and [MultiPolygon] /// Returns [FeatureCollection] 2-vertex line segments /// For example: -/// /// ```dart /// var polygon = Polygon.fromJson({ /// 'coordinates': [ @@ -21,7 +20,6 @@ import 'geojson.dart'; /// var segments = lineSegment(polygon); /// //addToMap /// var addToMap = [polygon, segments] - FeatureCollection lineSegment(GeoJSONObject geoJson, {bool combineGeometries = false}) { List> features = []; @@ -77,11 +75,6 @@ typedef SegmentEachCallback = dynamic Function( /// turf.segmentEach(polygon, function () { /// total++; /// }); -/// -/// -/// -/// - void segmentEach( GeoJSONObject geojson, SegmentEachCallback callback, { @@ -244,7 +237,6 @@ typedef SegmentReduceCallback = T? Function( /// return previousValue; /// }, 0); /// ``` - T? segmentReduce( GeoJSONObject geojson, SegmentReduceCallback callback, diff --git a/test/booleans/clockwise_test.dart b/test/booleans/clockwise_test.dart index a9b9da9d..1ed121e1 100644 --- a/test/booleans/clockwise_test.dart +++ b/test/booleans/clockwise_test.dart @@ -9,6 +9,25 @@ main() { group( 'clockwise', () { + test('', () { + var list = [ + Position.of([10, 10]), + Position.of([11, 10]), + Position.of([12, 10]), + Position.of([13, 10]), + ]; + expect(booleanClockwise(list), true); + }); + + test('', () { + var list = [ + [10, 10], + [11, 10], + [12, 10], + [13, 10], + ]; + expect(() => booleanClockwise(list), throwsA(isA())); + }); var inDir = Directory('./test/examples/booleans/clockwise/true'); for (var file in inDir.listSync(recursive: true)) { if (file is File && file.path.endsWith('.geojson')) { From 84b97f67404d20a6080af3eb36fc28f2851b6e63 Mon Sep 17 00:00:00 2001 From: armantorkzaban Date: Mon, 4 Jul 2022 10:49:22 +0200 Subject: [PATCH 39/82] concave finalized --- lib/src/booleans/boolean_concave.dart | 80 ++++++++------------------- test/booleans/concave_test.dart | 4 +- 2 files changed, 24 insertions(+), 60 deletions(-) diff --git a/lib/src/booleans/boolean_concave.dart b/lib/src/booleans/boolean_concave.dart index cfc6b5c9..b8ed1143 100644 --- a/lib/src/booleans/boolean_concave.dart +++ b/lib/src/booleans/boolean_concave.dart @@ -1,21 +1,24 @@ import 'package:turf/helpers.dart'; -import '../invariant.dart'; -/** - * Takes a polygon and return true or false as to whether it is concave or not. - * - * @name booleanConcave - * @param {Feature} polygon to be evaluated - * @returns {boolean} true/false - * @example - * var convexPolygon = turf.polygon([[[0,0],[0,1],[1,1],[1,0],[0,0]]]); - * - * turf.booleanConcave(convexPolygon) - * //=false - */ -booleanConcave(GeoJSONObject polygon) { +/// Takes a [Polygon] and returns true or false as to whether it is concave or not. +/// example: +/// ```dart +/// var convexPolygon = Polygon(coordinates: [ +/// [ +/// Position.of([0, 0]), +/// Position.of([0, 1]), +/// Position.of([1, 1]), +/// Position.of([1, 0]), +/// Position.of([0, 0]) +/// ] +/// ]); +/// booleanConcave(convexPolygon) +/// //=false +/// ``` +bool booleanConcave(Polygon polygon) { // Taken from https://stackoverflow.com/a/1881201 & https://stackoverflow.com/a/25304159 - var coords = getCoords(polygon); + List> coords = polygon.coordinates; + if (coords[0].length <= 4) { return false; } @@ -23,10 +26,10 @@ booleanConcave(GeoJSONObject polygon) { var sign = false; var n = coords[0].length - 1; for (var i = 0; i < n; i++) { - var dx1 = coords[0][(i + 2) % n][0] - coords[0][(i + 1) % n][0]; - var dy1 = coords[0][(i + 2) % n][1] - coords[0][(i + 1) % n][1]; - var dx2 = coords[0][i][0] - coords[0][(i + 1) % n][0]; - var dy2 = coords[0][i][1] - coords[0][(i + 1) % n][1]; + var dx1 = coords[0][(i + 2) % n][0]! - coords[0][(i + 1) % n][0]!; + var dy1 = coords[0][(i + 2) % n][1]! - coords[0][(i + 1) % n][1]!; + var dx2 = coords[0][i][0]! - coords[0][(i + 1) % n][0]!; + var dy2 = coords[0][i][1]! - coords[0][(i + 1) % n][1]!; var zcrossproduct = dx1 * dy2 - dy1 * dx2; if (i == 0) { sign = zcrossproduct > 0; @@ -36,42 +39,3 @@ booleanConcave(GeoJSONObject polygon) { } return false; } - -/* import { Feature, Polygon } from "geojson"; -import { getGeom } from "@turf/invariant"; - -/** - * Takes a polygon and return true or false as to whether it is concave or not. - * - * @name booleanConcave - * @param {Feature} polygon to be evaluated - * @returns {boolean} true/false - * @example - * var convexPolygon = turf.polygon([[[0,0],[0,1],[1,1],[1,0],[0,0]]]); - * - * turf.booleanConcave(convexPolygon) - * //=false - */ -export default function booleanConcave(polygon: Feature | Polygon) { - // Taken from https://stackoverflow.com/a/1881201 & https://stackoverflow.com/a/25304159 - const coords = getGeom(polygon).coordinates; - if (coords[0].length <= 4) { - return false; - } - - let sign = false; - const n = coords[0].length - 1; - for (let i = 0; i < n; i++) { - const dx1 = coords[0][(i + 2) % n][0] - coords[0][(i + 1) % n][0]; - const dy1 = coords[0][(i + 2) % n][1] - coords[0][(i + 1) % n][1]; - const dx2 = coords[0][i][0] - coords[0][(i + 1) % n][0]; - const dy2 = coords[0][i][1] - coords[0][(i + 1) % n][1]; - const zcrossproduct = dx1 * dy2 - dy1 * dx2; - if (i === 0) { - sign = zcrossproduct > 0; - } else if (sign !== zcrossproduct > 0) { - return true; - } - } - return false; -} */ \ No newline at end of file diff --git a/test/booleans/concave_test.dart b/test/booleans/concave_test.dart index 1c55fe84..0d736661 100644 --- a/test/booleans/concave_test.dart +++ b/test/booleans/concave_test.dart @@ -21,7 +21,7 @@ main() { dynamic json = jsonDecode(inSource); var inGeom = GeoJSONObject.fromJson(json); var feature = (inGeom as FeatureCollection).features[0]; - expect(booleanConcave(feature), true); + expect(booleanConcave(feature.geometry as Polygon), true); }, ); } @@ -38,7 +38,7 @@ main() { dynamic json = jsonDecode(inSource); var inGeom = GeoJSONObject.fromJson(json); var feature = (inGeom as FeatureCollection).features[0]; - expect(booleanConcave(feature), false); + expect(booleanConcave(feature.geometry as Polygon), false); }, ); } From e6d7580fd883d45aa8d5e67e0bfd70732360067c Mon Sep 17 00:00:00 2001 From: armantorkzaban Date: Mon, 4 Jul 2022 12:54:25 +0200 Subject: [PATCH 40/82] PointInPolygon plus test, dart format --- lib/src/booleans/boolean_contains.dart | 2 +- .../booleans/boolean_point_in_polygon.dart | 130 ++---- lib/src/booleans/boolean_point_on_line.dart | 126 ------ lib/src/booleans/boolean_touches.dart | 3 +- lib/src/booleans/boolean_within.dart | 4 +- lib/src/polygon_to_line.dart | 2 +- lib/src/rhumb_bearing.dart | 2 +- test/.DS_Store | Bin 6148 -> 6148 bytes test/booleans/overlap_test.dart | 1 + test/booleans/parallel_test.dart | 1 + test/booleans/point_in_polygon_test.dart | 398 ++++++++++++++++++ test/booleans/touches_test.dart | 1 + test/booleans/valid_test.dart | 1 + test/booleans/within_test.dart | 1 + test/components/rhumb_bearing_test.dart | 2 +- test/examples/.DS_Store | Bin 8196 -> 8196 bytes test/examples/booleans/.DS_Store | Bin 6148 -> 8196 bytes .../in/multipoly-with-hole.geojson | 43 ++ .../in/poly-with-hole.geojson | 32 ++ 19 files changed, 509 insertions(+), 240 deletions(-) create mode 100644 test/examples/booleans/point_in_polygon/in/multipoly-with-hole.geojson create mode 100644 test/examples/booleans/point_in_polygon/in/poly-with-hole.geojson diff --git a/lib/src/booleans/boolean_contains.dart b/lib/src/booleans/boolean_contains.dart index 181739ab..3dbdc4d4 100644 --- a/lib/src/booleans/boolean_contains.dart +++ b/lib/src/booleans/boolean_contains.dart @@ -478,4 +478,4 @@ export function compareCoords(pair1: number[], pair2: number[]) { export function getMidpoint(pair1: number[], pair2: number[]) { return [(pair1[0] + pair2[0]) / 2, (pair1[1] + pair2[1]) / 2]; -} */ \ No newline at end of file +} */ diff --git a/lib/src/booleans/boolean_point_in_polygon.dart b/lib/src/booleans/boolean_point_in_polygon.dart index d7aeed4e..cb0da21e 100644 --- a/lib/src/booleans/boolean_point_in_polygon.dart +++ b/lib/src/booleans/boolean_point_in_polygon.dart @@ -6,7 +6,7 @@ import 'package:pip/pip.dart'; import '../../helpers.dart'; import '../invariant.dart'; -/// Takes a [Point] and a [Polygon] or [MultiPolygon]and determines if the +/// Takes a [Point], and a [Polygon] or [MultiPolygon]and determines if the /// [Point] resides inside the [Polygon]. The polygon can be convex or concave. /// The function accounts for holes. By taking a [Feature] or a /// [Feature]. [ignoreBoundary=false] should be set [true] if polygon's @@ -27,21 +27,37 @@ import '../invariant.dart'; /// ``` bool booleanPointInPolygon(Position point, GeoJSONObject polygon, {bool ignoreBoundary = false}) { - var geom = getGeom(polygon); - var type = geom.type; - var bbox = polygon.bbox; - var polys = geom.coordinates; + GeometryType? geom; + List>>? polys; + BBox? bbox = polygon.bbox; + + Exception exception = Exception('${polygon.type} is not supported'); + + if (polygon is Feature) { + if (polygon.geometry is Polygon || polygon.geometry is MultiPolygon) { + return booleanPointInPolygon(point, polygon.geometry!); + } else { + throw exception; + } + } else if (polygon is GeometryType) { + if (polygon is Polygon && polygon.coordinates.isNotEmpty) { + geom = polygon; + polys = [geom.coordinates]; + } else if (polygon is MultiPolygon && polygon.coordinates.isNotEmpty) { + geom = polygon; + polys = geom.coordinates; + } + } else { + throw exception; + } // Quick elimination if point is not inside bbox if (bbox != null && !_inBBox(point, bbox)) { return false; } - if (type == GeoJSONObjectType.polygon) { - polys = [polys]; - } var result = false; - for (var i = 0; i < polys.length; ++i) { + for (var i = 0; i < polys!.length; ++i) { var polyResult = pip(Point(coordinates: point), Polygon(coordinates: polys[i])); if (polyResult == 0) { @@ -60,99 +76,3 @@ bool _inBBox(Position pt, BBox bbox) { bbox[2]! >= pt[0]! && bbox[3]! >= pt[1]!); } - - -import pip from "point-in-polygon-hao"; -import { - BBox, - Feature, - MultiPolygon, - Polygon, - GeoJsonProperties, -} from "geojson"; -import { Coord } from "@turf/helpers"; -import { getCoord, getGeom } from "@turf/invariant"; - -// http://en.wikipedia.org/wiki/Even%E2%80%93odd_rule -// modified from: https://github.com/substack/point-in-polygon/blob/master/index.js -// which was modified from http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html -/** - * Takes a {@link Point} and a {@link Polygon} or {@link MultiPolygon} and determines if the point - * resides inside the polygon. The polygon can be convex or concave. The function accounts for holes. - * - * @name booleanPointInPolygon - * @param {Coord} point input point - * @param {Feature} polygon input polygon or multipolygon - * @param {Object} [options={}] Optional parameters - * @param {boolean} [options.ignoreBoundary=false] True if polygon boundary should be ignored when determining if - * the point is inside the polygon otherwise false. - * @returns {boolean} `true` if the Point is inside the Polygon; `false` if the Point is not inside the Polygon - * @example - * var pt = turf.point([-77, 44]); - * var poly = turf.polygon([[ - * [-81, 41], - * [-81, 47], - * [-72, 47], - * [-72, 41], - * [-81, 41] - * ]]); - * - * turf.booleanPointInPolygon(pt, poly); - * //= true - */ -export default function booleanPointInPolygon< - G extends Polygon | MultiPolygon, - P = GeoJsonProperties ->( - point: Coord, - polygon: Feature | G, - options: { - ignoreBoundary?: boolean; - } = {} -) { - // validation - if (!point) { - throw new Error("point is required"); - } - if (!polygon) { - throw new Error("polygon is required"); - } - - const pt = getCoord(point); - const geom = getGeom(polygon); - const type = geom.type; - const bbox = polygon.bbox; - let polys: any[] = geom.coordinates; - - // Quick elimination if point is not inside bbox - if (bbox && inBBox(pt, bbox) === false) { - return false; - } - - if (type === "Polygon") { - polys = [polys]; - } - let result = false; - for (var i = 0; i < polys.length; ++i) { - const polyResult = pip(pt, polys[i]); - if (polyResult === 0) return options.ignoreBoundary ? false : true; - else if (polyResult) result = true; - } - - return result; -} - -/** - * inBBox - * - * @private - * @param {Position} pt point [x,y] - * @param {BBox} bbox BBox [west, south, east, north] - * @returns {boolean} true/false if point is inside BBox - */ -function inBBox(pt: number[], bbox: BBox) { - return ( - bbox[0] <= pt[0] && bbox[1] <= pt[1] && bbox[2] >= pt[0] && bbox[3] >= pt[1] - ); -} - */ diff --git a/lib/src/booleans/boolean_point_on_line.dart b/lib/src/booleans/boolean_point_on_line.dart index f52d96e2..76ab207b 100644 --- a/lib/src/booleans/boolean_point_on_line.dart +++ b/lib/src/booleans/boolean_point_on_line.dart @@ -88,129 +88,3 @@ bool _isPointOnLineSegment(Position lineSegmentStart, Position lineSegmentEnd, } return false; } - -import { Feature, LineString } from "geojson"; -import { Coord } from "@turf/helpers"; -import { getCoord, getCoords } from "@turf/invariant"; - -/** - * Returns true if a point is on a line. Accepts a optional parameter to ignore the - * start and end vertices of the linestring. - * - * @name booleanPointOnLine - * @param {Coord} pt GeoJSON Point - * @param {Feature} line GeoJSON LineString - * @param {Object} [options={}] Optional parameters - * @param {boolean} [options.ignoreEndVertices=false] whether to ignore the start and end vertices. - * @param {number} [options.epsilon] Fractional number to compare with the cross product result. Useful for dealing with floating points such as lng/lat points - * @returns {boolean} true/false - * @example - * var pt = turf.point([0, 0]); - * var line = turf.lineString([[-1, -1],[1, 1],[1.5, 2.2]]); - * var isPointOnLine = turf.booleanPointOnLine(pt, line); - * //=true - */ -function booleanPointOnLine( - pt: Coord, - line: Feature | LineString, - options: { - ignoreEndVertices?: boolean; - epsilon?: number; - } = {} -): boolean { - // Normalize inputs - const ptCoords = getCoord(pt); - const lineCoords = getCoords(line); - - // Main - for (let i = 0; i < lineCoords.length - 1; i++) { - let ignoreBoundary: boolean | string = false; - if (options.ignoreEndVertices) { - if (i == 0) { - ignoreBoundary = "start"; - } - if (i === lineCoords.length - 2) { - ignoreBoundary = "end"; - } - if (i === 0 && i + 1 === lineCoords.length - 1) { - ignoreBoundary = "both"; - } - } - if ( - isPointOnLineSegment( - lineCoords[i], - lineCoords[i + 1], - ptCoords, - ignoreBoundary, - typeof options.epsilon === "undefined" ? null : options.epsilon - ) - ) { - return true; - } - } - return false; -} - -// See http://stackoverflow.com/a/4833823/1979085 -// See https://stackoverflow.com/a/328122/1048847 -/** - * @private - * @param {Position} lineSegmentStart coord pair of start of line - * @param {Position} lineSegmentEnd coord pair of end of line - * @param {Position} pt coord pair of point to check - * @param {boolean|string} excludeBoundary whether the point is allowed to fall on the line ends. - * @param {number} epsilon Fractional number to compare with the cross product result. Useful for dealing with floating points such as lng/lat points - * If true which end to ignore. - * @returns {boolean} true/false - */ -function isPointOnLineSegment( - lineSegmentStart: number[], - lineSegmentEnd: number[], - pt: number[], - excludeBoundary: string | boolean, - epsilon: number | null -): boolean { - const x = pt[0]; - const y = pt[1]; - const x1 = lineSegmentStart[0]; - const y1 = lineSegmentStart[1]; - const x2 = lineSegmentEnd[0]; - const y2 = lineSegmentEnd[1]; - const dxc = pt[0] - x1; - const dyc = pt[1] - y1; - const dxl = x2 - x1; - const dyl = y2 - y1; - const cross = dxc * dyl - dyc * dxl; - if (epsilon !== null) { - if (Math.abs(cross) > epsilon) { - return false; - } - } else if (cross !== 0) { - return false; - } - if (!excludeBoundary) { - if (Math.abs(dxl) >= Math.abs(dyl)) { - return dxl > 0 ? x1 <= x && x <= x2 : x2 <= x && x <= x1; - } - return dyl > 0 ? y1 <= y && y <= y2 : y2 <= y && y <= y1; - } else if (excludeBoundary === "start") { - if (Math.abs(dxl) >= Math.abs(dyl)) { - return dxl > 0 ? x1 < x && x <= x2 : x2 <= x && x < x1; - } - return dyl > 0 ? y1 < y && y <= y2 : y2 <= y && y < y1; - } else if (excludeBoundary === "end") { - if (Math.abs(dxl) >= Math.abs(dyl)) { - return dxl > 0 ? x1 <= x && x < x2 : x2 < x && x <= x1; - } - return dyl > 0 ? y1 <= y && y < y2 : y2 < y && y <= y1; - } else if (excludeBoundary === "both") { - if (Math.abs(dxl) >= Math.abs(dyl)) { - return dxl > 0 ? x1 < x && x < x2 : x2 < x && x < x1; - } - return dyl > 0 ? y1 < y && y < y2 : y2 < y && y < y1; - } - return false; -} - -export default booleanPointOnLine; - */ diff --git a/lib/src/booleans/boolean_touches.dart b/lib/src/booleans/boolean_touches.dart index 3a6f8986..41f602c3 100644 --- a/lib/src/booleans/boolean_touches.dart +++ b/lib/src/booleans/boolean_touches.dart @@ -611,7 +611,6 @@ compareCoords(Position pair1, Position pair2) { return pair1[0] == pair2[0] && pair1[1] == pair2[1]; } - /** import { Feature, Geometry, LineString(Point } from "geojson"; import booleanPointOnLine from "@turf/boolean-point-on-line"; import booleanPointInPolygon from "@turf/boolean-point-in-polygon"; @@ -1385,4 +1384,4 @@ function compareCoords(pair1: number[], pair2: number[]) { return pair1[0] == pair2[0] && pair1[1] == pair2[1]; } -export default booleanTouches; */ \ No newline at end of file +export default booleanTouches; */ diff --git a/lib/src/booleans/boolean_within.dart b/lib/src/booleans/boolean_within.dart index fdc40d9e..d38013a4 100644 --- a/lib/src/booleans/boolean_within.dart +++ b/lib/src/booleans/boolean_within.dart @@ -237,8 +237,6 @@ getMidpoint(Position pair1, Position pair2) { return [(pair1[0]! + pair2[0]!) / 2, (pair1[1]! + pair2[1]!) / 2]; } - - /* import { BBox, @@ -494,4 +492,4 @@ function getMidpoint(Position pair1, Position pair2) { return [(pair1[0] + pair2[0]) / 2, (pair1[1] + pair2[1]) / 2]; } -export default booleanWithin;*/ \ No newline at end of file +export default booleanWithin;*/ diff --git a/lib/src/polygon_to_line.dart b/lib/src/polygon_to_line.dart index b30d181e..18a1742e 100644 --- a/lib/src/polygon_to_line.dart +++ b/lib/src/polygon_to_line.dart @@ -183,4 +183,4 @@ export function coordsToLine

( } return lineString(coords[0], properties); } - */ \ No newline at end of file + */ diff --git a/lib/src/rhumb_bearing.dart b/lib/src/rhumb_bearing.dart index 7cfee509..155cc433 100644 --- a/lib/src/rhumb_bearing.dart +++ b/lib/src/rhumb_bearing.dart @@ -145,4 +145,4 @@ function calculateRhumbBearing(from: number[], to: number[]) { } export default rhumbBearing; - */ \ No newline at end of file + */ diff --git a/test/.DS_Store b/test/.DS_Store index 62a28beec82e0e600297cf88246c0e6f48043a4d..8dca1b0c6041d6f51c12453d5fe1b56c21e4e4b4 100644 GIT binary patch delta 140 zcmZoMXfc=|#>B!ku~2NHo+2a1#(>?7iytsEP1IwXEXbtC&%uzykPn184540)3` zF*UOro9ZYS8d*-ZVRn>8k!2_@3ogpb$urgpOp^JT`(>>T_YK)W_y ZWd6=PnP0?_gOP!O38<7|bA-qmW&p@JA`$=q delta 83 zcmZoMXfc=|#>B)qu~2NHo+2aL#(>?7jBJy6Sd1r|vwmYYGtp5nG%%QagT--kDcdB* mjSWATHnVf^a{#q$7UcNOJegm_k%IvU7#SE?Hb;o8VFm!JSrp;` diff --git a/test/booleans/overlap_test.dart b/test/booleans/overlap_test.dart index e69de29b..8b137891 100644 --- a/test/booleans/overlap_test.dart +++ b/test/booleans/overlap_test.dart @@ -0,0 +1 @@ + diff --git a/test/booleans/parallel_test.dart b/test/booleans/parallel_test.dart index e69de29b..8b137891 100644 --- a/test/booleans/parallel_test.dart +++ b/test/booleans/parallel_test.dart @@ -0,0 +1 @@ + diff --git a/test/booleans/point_in_polygon_test.dart b/test/booleans/point_in_polygon_test.dart index e69de29b..08dc6cd3 100644 --- a/test/booleans/point_in_polygon_test.dart +++ b/test/booleans/point_in_polygon_test.dart @@ -0,0 +1,398 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:test/test.dart'; +import 'package:turf/helpers.dart'; +import 'package:turf/src/booleans/boolean_point_in_polygon.dart'; + +main() { + group( + '', + () { + test("boolean-point-in-polygon -- featureCollection", () { + // test for a simple polygon + var poly = Polygon(coordinates: [ + [ + Position.of([0, 0]), + Position.of([0, 100]), + Position.of([100, 100]), + Position.of([100, 0]), + Position.of([0, 0]), + ], + ]); + var ptIn = Point(coordinates: (Position.of([50, 50]))); + var ptOut = Point(coordinates: (Position.of([140, 150]))); +// "point inside simple polygon" + expect(booleanPointInPolygon(ptIn.coordinates, poly), true); + // "point outside simple polygon" + expect(booleanPointInPolygon(ptOut.coordinates, poly), false); + + // test for a concave polygon + var concavePoly = Polygon(coordinates: [ + [ + Position.of([0, 0]), + Position.of([50, 50]), + Position.of([0, 100]), + Position.of([100, 100]), + Position.of([100, 0]), + Position.of([0, 0]), + ], + ]); + var ptConcaveIn = Point(coordinates: (Position.of([75, 75]))); + var ptConcaveOut = Point(coordinates: (Position.of([25, 50]))); + +// "point inside concave polygon" + expect( + booleanPointInPolygon(ptConcaveIn.coordinates, concavePoly), true); + // "point outside concave polygon" + + expect(booleanPointInPolygon(ptConcaveOut.coordinates, concavePoly), + false); + }); + + test("boolean-point-in-polygon -- poly with hole", () { + var ptInHole = Point( + coordinates: + (Position.of([-86.69208526611328, 36.20373274711739]))); + var ptInPoly = Point( + coordinates: + (Position.of([-86.72229766845702, 36.20258997094334]))); + var ptOutsidePoly = Point( + coordinates: + (Position.of([-86.75079345703125, 36.18527313913089]))); + + var inFile = File( + './test/examples/booleans/point_in_polygon/in/poly-with-hole.geojson'); + + var polyHole = + GeoJSONObject.fromJson(jsonDecode(inFile.readAsStringSync())); + + expect(booleanPointInPolygon(ptInHole.coordinates, polyHole), false); + expect(booleanPointInPolygon(ptInPoly.coordinates, polyHole), true); + expect( + booleanPointInPolygon(ptOutsidePoly.coordinates, polyHole), false); + }); + + test("boolean-point-in-polygon -- multipolygon with hole", () { + var ptInHole = Point( + coordinates: + (Position.of([-86.69208526611328, 36.20373274711739]))); + var ptInPoly = Point( + coordinates: + (Position.of([-86.72229766845702, 36.20258997094334]))); + var ptInPoly2 = Point( + coordinates: + (Position.of([-86.75079345703125, 36.18527313913089]))); + var ptOutsidePoly = Point( + coordinates: + (Position.of([-86.75302505493164, 36.23015046460186]))); + + var inFile = File( + './test/examples/booleans/point_in_polygon/in/multipoly-with-hole.geojson'); + + var multiPolyHole = + GeoJSONObject.fromJson(jsonDecode(inFile.readAsStringSync())); + + expect( + booleanPointInPolygon(ptInHole.coordinates, multiPolyHole), false); + expect( + booleanPointInPolygon(ptInPoly.coordinates, multiPolyHole), true); + expect( + booleanPointInPolygon(ptInPoly2.coordinates, multiPolyHole), true); + expect( + booleanPointInPolygon(ptInPoly.coordinates, multiPolyHole), true); + expect(booleanPointInPolygon(ptOutsidePoly.coordinates, multiPolyHole), + false); + }); + + test( + 'boolean-point-in-polygon -- Boundary test', + () { + var poly1 = Polygon(coordinates: [ + [ + Position.of([10, 10]), + Position.of([30, 20]), + Position.of([50, 10]), + Position.of([30, 0]), + Position.of([10, 10]), + ], + ]); + var poly2 = Polygon(coordinates: [ + [ + Position.of([10, 0]), + Position.of([30, 20]), + Position.of([50, 0]), + Position.of([30, 10]), + Position.of([10, 0]), + ], + ]); + var poly3 = Polygon(coordinates: [ + [ + Position.of([10, 0]), + Position.of([30, 20]), + Position.of([50, 0]), + Position.of([30, -20]), + Position.of([10, 0]), + ], + ]); + var poly4 = Polygon(coordinates: [ + [ + Position.of([0, 0]), + Position.of([0, 20]), + Position.of([50, 20]), + Position.of([50, 0]), + Position.of([40, 0]), + Position.of([30, 10]), + Position.of([30, 0]), + Position.of([20, 10]), + Position.of([10, 10]), + Position.of([10, 0]), + Position.of([0, 0]), + ], + ]); + var poly5 = Polygon(coordinates: [ + [ + Position.of([0, 20]), + Position.of([20, 40]), + Position.of([40, 20]), + Position.of([20, 0]), + Position.of([0, 20]), + ], + [ + Position.of([10, 20]), + Position.of([20, 30]), + Position.of([30, 20]), + Position.of([20, 10]), + Position.of([10, 20]), + ], + ]); + + runTest(bool ignoreBoundary) { + var isBoundaryIncluded = ignoreBoundary == false; + var tests = [ + [ + poly1, + Point(coordinates: (Position.of([10, 10]))), + isBoundaryIncluded + ], //0 + [ + poly1, + Point(coordinates: (Position.of([30, 20]))), + isBoundaryIncluded + ], + [ + poly1, + Point(coordinates: (Position.of([50, 10]))), + isBoundaryIncluded + ], + [ + poly1, + Point(coordinates: (Position.of([30, 10]))), + true + ], + [ + poly1, + Point(coordinates: (Position.of([0, 10]))), + false + ], + [ + poly1, + Point(coordinates: (Position.of([60, 10]))), + false + ], + [ + poly1, + Point(coordinates: (Position.of([30, -10]))), + false + ], + [ + poly1, + Point(coordinates: (Position.of([30, 30]))), + false + ], + [ + poly2, + Point(coordinates: (Position.of([30, 0]))), + false + ], + [ + poly2, + Point(coordinates: (Position.of([0, 0]))), + false + ], + [ + poly2, + Point(coordinates: (Position.of([60, 0]))), + false + ], //10 + [ + poly3, + Point(coordinates: (Position.of([30, 0]))), + true + ], + [ + poly3, + Point(coordinates: (Position.of([0, 0]))), + false + ], + [ + poly3, + Point(coordinates: (Position.of([60, 0]))), + false + ], + [ + poly4, + Point(coordinates: (Position.of([0, 20]))), + isBoundaryIncluded + ], + [ + poly4, + Point(coordinates: (Position.of([10, 20]))), + isBoundaryIncluded + ], + [ + poly4, + Point(coordinates: (Position.of([50, 20]))), + isBoundaryIncluded + ], + [ + poly4, + Point(coordinates: (Position.of([0, 10]))), + isBoundaryIncluded + ], + [ + poly4, + Point(coordinates: (Position.of([5, 10]))), + true + ], + [ + poly4, + Point(coordinates: (Position.of([25, 10]))), + true + ], + [ + poly4, + Point(coordinates: (Position.of([35, 10]))), + true + ], //20 + [ + poly4, + Point(coordinates: (Position.of([0, 0]))), + isBoundaryIncluded + ], + [ + poly4, + Point(coordinates: (Position.of([20, 0]))), + false + ], + [ + poly4, + Point(coordinates: (Position.of([35, 0]))), + false + ], + [ + poly4, + Point(coordinates: (Position.of([50, 0]))), + isBoundaryIncluded + ], + [ + poly4, + Point(coordinates: (Position.of([50, 10]))), + isBoundaryIncluded + ], + [ + poly4, + Point(coordinates: (Position.of([5, 0]))), + isBoundaryIncluded + ], + [ + poly4, + Point(coordinates: (Position.of([10, 0]))), + isBoundaryIncluded + ], + [ + poly5, + Point(coordinates: (Position.of([20, 30]))), + isBoundaryIncluded + ], + [ + poly5, + Point(coordinates: (Position.of([25, 25]))), + isBoundaryIncluded + ], + [ + poly5, + Point(coordinates: (Position.of([30, 20]))), + isBoundaryIncluded + ], //30 + [ + poly5, + Point(coordinates: (Position.of([25, 15]))), + isBoundaryIncluded + ], + [ + poly5, + Point(coordinates: (Position.of([20, 10]))), + isBoundaryIncluded + ], + [ + poly5, + Point(coordinates: (Position.of([15, 15]))), + isBoundaryIncluded + ], + [ + poly5, + Point(coordinates: (Position.of([10, 20]))), + isBoundaryIncluded + ], + [ + poly5, + Point(coordinates: (Position.of([15, 25]))), + isBoundaryIncluded + ], + [ + poly5, + Point(coordinates: (Position.of([20, 20]))), + false + ], + ]; + + for (var i = 0; i < tests.length; i++) { + var item = tests[i]; + expect( + booleanPointInPolygon( + (item[1] as Point).coordinates, + item[0] as Polygon, + ignoreBoundary: ignoreBoundary, + ) == + item[2], + true); + } + } + + runTest(false); + runTest(true); + }, + ); + +// https://github.com/Turfjs/turf-inside/issues/15 + test( + "boolean-point-in-polygon -- issue #15", + () { + var pt1 = Point(coordinates: (Position.of([-9.9964077, 53.8040989]))); + var poly = Polygon(coordinates: [ + [ + Position.of([5.080336744095521, 67.89398938540765]), + Position.of([0.35070899909145403, 69.32470003971179]), + Position.of([-24.453622256504122, 41.146696777884564]), + Position.of([-21.6445524714804, 40.43225902006474]), + Position.of([5.080336744095521, 67.89398938540765]), + ], + ]); + + expect(booleanPointInPolygon(pt1.coordinates, poly), true); + }, + ); + }, + ); +} diff --git a/test/booleans/touches_test.dart b/test/booleans/touches_test.dart index e69de29b..8b137891 100644 --- a/test/booleans/touches_test.dart +++ b/test/booleans/touches_test.dart @@ -0,0 +1 @@ + diff --git a/test/booleans/valid_test.dart b/test/booleans/valid_test.dart index e69de29b..8b137891 100644 --- a/test/booleans/valid_test.dart +++ b/test/booleans/valid_test.dart @@ -0,0 +1 @@ + diff --git a/test/booleans/within_test.dart b/test/booleans/within_test.dart index e69de29b..8b137891 100644 --- a/test/booleans/within_test.dart +++ b/test/booleans/within_test.dart @@ -0,0 +1 @@ + diff --git a/test/components/rhumb_bearing_test.dart b/test/components/rhumb_bearing_test.dart index 6b3e17e5..dc426920 100644 --- a/test/components/rhumb_bearing_test.dart +++ b/test/components/rhumb_bearing_test.dart @@ -91,4 +91,4 @@ test("bearing", (t) => { }, "invalid point"); t.end(); }); -*/ \ No newline at end of file +*/ diff --git a/test/examples/.DS_Store b/test/examples/.DS_Store index 65a142cffd919c341efbaf565de247433f8dc309..f9e888949e877f1da28cb86bb5403362c56c9e86 100644 GIT binary patch delta 50 zcmV-20L}k|K!iY$PXQINP`eKS6|)Qw=mL{^5+9S}5|Wc=6-KkW6C4Dy2N?DQldlyS Iv*r};0>4udKL7v# delta 68 zcmV-K0K5N$K!iY$PXQFMP`eKS6tfHv=mL`@6M+*sGb|uAH#B`LAbUA7Ff1T6Gd7c| a6*IHz6C4DQfH1QM81@9SEfv}Vk$^3``V|HM diff --git a/test/examples/booleans/.DS_Store b/test/examples/booleans/.DS_Store index 5ef1b5e6c21e423a32abb67d75b4e17a0797c771..f424fef32216d6b513b266dd05335fcb7665fd3c 100644 GIT binary patch delta 494 zcmZoMXmOBWU|?W$DortDU;r^WfEYvza8E20o2aMA$hR?IH{)gn4tAE!0xVw{7qfG4 zOl)9b$w@i+NgyMEcrOsI z`VR&`7D$YM{>gWk8ikEbbrcMZENgWXsx6HSbQCO&EhiT+8`l%mos(`DoSdIq0JaN4 z5Y&^K@8SY=F^9P3{~v{xM;x)cv>w%~x%nwXYDCpnkU_d5%YuvYawczQcG;}W^O%`S kf*a^US5T~NW@P!!Jegm_ak4v)00$!^LK!y4^UPre0N Date: Mon, 4 Jul 2022 13:24:48 +0200 Subject: [PATCH 41/82] removed the commented JS lines --- lib/src/booleans/boolean_clockwise.dart | 2 +- lib/src/booleans/boolean_contains.dart | 359 +++--------------------- 2 files changed, 43 insertions(+), 318 deletions(-) diff --git a/lib/src/booleans/boolean_clockwise.dart b/lib/src/booleans/boolean_clockwise.dart index 74efd4d7..cb9aeb52 100644 --- a/lib/src/booleans/boolean_clockwise.dart +++ b/lib/src/booleans/boolean_clockwise.dart @@ -17,7 +17,7 @@ import '../../helpers.dart'; bool booleanClockwise(dynamic line) { if (line is List) { if (line is! List) { - throw UnsupportedError(" type ${line.runtimeType} is not supperted"); + throw UnsupportedError(" type $line is not supperted"); } } var ring = getCoords(line); diff --git a/lib/src/booleans/boolean_contains.dart b/lib/src/booleans/boolean_contains.dart index 3dbdc4d4..468b3091 100644 --- a/lib/src/booleans/boolean_contains.dart +++ b/lib/src/booleans/boolean_contains.dart @@ -18,60 +18,50 @@ import 'boolean_point_on_line.dart'; booleanContains(GeoJSONObject feature1, GeoJSONObject feature2) { var geom1 = feature1 is Feature ? feature1.geometry : feature1; var geom2 = feature2 is Feature ? feature2.geometry : feature2; - var type1 = geom1!.type; - var type2 = geom2!.type; + var coords1 = (geom1 as GeometryType).coordinates; var coords2 = (geom2 as GeometryType).coordinates; - switch (type1) { - case GeoJSONObjectType.point: - switch (type2) { - case GeoJSONObjectType.point: - return compareCoords(coords1, coords2); - default: - throw UnsupportedError( - "{feature2 $type2 geometry not supported}"); - } - case GeoJSONObjectType.multiPoint: - switch (type2) { - case GeoJSONObjectType.point: - return isPointInMultiPoint(geom1 as MultiPoint, geom2 as Point); - case GeoJSONObjectType.multiPoint: - return isMultiPointInMultiPoint( - geom1 as MultiPoint, geom2 as MultiPoint); - default: - throw UnsupportedError( - "{feature2 $type2 geometry not supported}"); - } - case GeoJSONObjectType.lineString: - switch (type2) { - case GeoJSONObjectType.point: - return booleanPointOnLine(geom2 as Point, geom1 as LineString, - ignoreEndVertices: true); - case GeoJSONObjectType.lineString: - return isLineOnLine(geom1 as LineString, geom2 as LineString); - case GeoJSONObjectType.multiPoint: - return isMultiPointOnLine(geom1 as LineString, geom2 as MultiPoint); - default: - throw UnsupportedError( - "{feature2 $type2 geometry not supported}"); - } - case GeoJSONObjectType.polygon: - switch (type2) { - case GeoJSONObjectType.point: - return booleanPointInPolygon((geom2 as Point).coordinates, geom1, - ignoreBoundary: true); - case GeoJSONObjectType.lineString: - return isLineInPoly(geom1 as Polygon, geom2 as LineString); - case GeoJSONObjectType.polygon: - return isPolyInPoly(geom1, geom2); - case GeoJSONObjectType.multiPoint: - return isMultiPointInPoly(geom1 as Polygon, geom2 as MultiPoint); - default: - throw UnsupportedError( - "{feature2 $type2 geometry not supported}"); - } - default: - throw UnsupportedError("feature1 $type1 geometry not supported"); + Exception exception() => + Exception("{feature2 $geom2 geometry not supported}"); + if (geom1 is Point) { + if (geom2 is Point) { + return compareCoords(coords1, coords2); + } else { + throw exception(); + } + } else if (geom1 is MultiPoint) { + if (geom2 is Point) { + return isPointInMultiPoint(geom1, geom2); + } else if (geom2 is MultiPoint) { + return isMultiPointInMultiPoint(geom1, geom2); + } else { + throw exception(); + } + } else if (geom1 is LineString) { + if (geom2 is Point) { + return booleanPointOnLine(geom2, geom1, ignoreEndVertices: true); + } else if (geom2 is LineString) { + return isLineOnLine(geom1, geom2); + } else if (geom2 is MultiPoint) { + return isMultiPointOnLine(geom1, geom2); + } else { + throw exception(); + } + } else if (geom1 is Polygon) { + if (geom2 is Point) { + return booleanPointInPolygon((geom2).coordinates, geom1, + ignoreBoundary: true); + } else if (geom2 is LineString) { + return isLineInPoly(geom1, geom2); + } else if (geom2 is Polygon) { + return isPolyInPoly(geom1, geom2); + } else if (geom2 is MultiPoint) { + return isMultiPointInPoly(geom1, geom2); + } else { + throw exception(); + } + } else { + throw exception(); } } @@ -214,268 +204,3 @@ Position getMidpoint(Position pair1, Position pair2) { return Position.of( [(pair1[0]! + pair2[0]!) / 2, (pair1[1]! + pair2[1]!) / 2]); } - -/* -import { - BBox, - Feature, - Geometry, - LineString, - MultiPoint, - Point, - Polygon, -} from "geojson"; -import calcBbox from "@turf/bbox"; -import booleanPointInPolygon from "@turf/boolean-point-in-polygon"; -import isPointOnLine from "@turf/boolean-point-on-line"; -import { getGeom } from "@turf/invariant"; - -/** - * Boolean-contains returns True if the second geometry is completely contained by the first geometry. - * The interiors of both geometries must intersect and, the interior and boundary of the secondary (geometry b) - * must not intersect the exterior of the primary (geometry a). - * Boolean-contains returns the exact opposite result of the `@turf/boolean-within`. - * - * @name booleanContains - * @param {Geometry|Feature} feature1 GeoJSON Feature or Geometry - * @param {Geometry|Feature} feature2 GeoJSON Feature or Geometry - * @returns {boolean} true/false - * @example - * var line = turf.lineString([[1, 1], [1, 2], [1, 3], [1, 4]]); - * var point = turf.point([1, 2]); - * - * turf.booleanContains(line, point); - * //=true - */ -export default function booleanContains( - feature1: Feature | Geometry, - feature2: Feature | Geometry -) { - const geom1 = getGeom(feature1); - const geom2 = getGeom(feature2); - const type1 = geom1.type; - const type2 = geom2.type; - const coords1 = geom1.coordinates; - const coords2 = geom2.coordinates; - - switch (type1) { - case "Point": - switch (type2) { - case "Point": - return compareCoords(coords1, coords2); - default: - throw new Error("feature2 " + type2 + " geometry not supported"); - } - case "MultiPoint": - switch (type2) { - case "Point": - return isPointInMultiPoint(geom1, geom2); - case "MultiPoint": - return isMultiPointInMultiPoint(geom1, geom2); - default: - throw new Error("feature2 " + type2 + " geometry not supported"); - } - case "LineString": - switch (type2) { - case "Point": - return isPointOnLine(geom2, geom1, { ignoreEndVertices: true }); - case "LineString": - return isLineOnLine(geom1, geom2); - case "MultiPoint": - return isMultiPointOnLine(geom1, geom2); - default: - throw new Error("feature2 " + type2 + " geometry not supported"); - } - case "Polygon": - switch (type2) { - case "Point": - return booleanPointInPolygon(geom2, geom1, { ignoreBoundary: true }); - case "LineString": - return isLineInPoly(geom1, geom2); - case "Polygon": - return isPolyInPoly(geom1, geom2); - case "MultiPoint": - return isMultiPointInPoly(geom1, geom2); - default: - throw new Error("feature2 " + type2 + " geometry not supported"); - } - default: - throw new Error("feature1 " + type1 + " geometry not supported"); - } -} - -export function isPointInMultiPoint(multiPoint: MultiPoint, pt: Point) { - let i; - let output = false; - for (i = 0; i < multiPoint.coordinates.length; i++) { - if (compareCoords(multiPoint.coordinates[i], pt.coordinates)) { - output = true; - break; - } - } - return output; -} - -export function isMultiPointInMultiPoint( - multiPoint1: MultiPoint, - multiPoint2: MultiPoint -) { - for (const coord2 of multiPoint2.coordinates) { - let matchFound = false; - for (const coord1 of multiPoint1.coordinates) { - if (compareCoords(coord2, coord1)) { - matchFound = true; - break; - } - } - if (!matchFound) { - return false; - } - } - return true; -} - -export function isMultiPointOnLine( - lineString: LineString, - multiPoint: MultiPoint -) { - let haveFoundInteriorPoint = false; - for (const coord of multiPoint.coordinates) { - if (isPointOnLine(coord, lineString, { ignoreEndVertices: true })) { - haveFoundInteriorPoint = true; - } - if (!isPointOnLine(coord, lineString)) { - return false; - } - } - if (haveFoundInteriorPoint) { - return true; - } - return false; -} - -export function isMultiPointInPoly(polygon: Polygon, multiPoint: MultiPoint) { - for (const coord of multiPoint.coordinates) { - if (!booleanPointInPolygon(coord, polygon, { ignoreBoundary: true })) { - return false; - } - } - return true; -} - -export function isLineOnLine(lineString1: LineString, lineString2: LineString) { - let haveFoundInteriorPoint = false; - for (const coords of lineString2.coordinates) { - if ( - isPointOnLine({ type: "Point", coordinates: coords }, lineString1, { - ignoreEndVertices: true, - }) - ) { - haveFoundInteriorPoint = true; - } - if ( - !isPointOnLine({ type: "Point", coordinates: coords }, lineString1, { - ignoreEndVertices: false, - }) - ) { - return false; - } - } - return haveFoundInteriorPoint; -} - -export function isLineInPoly(polygon: Polygon, linestring: LineString) { - let output = false; - let i = 0; - - const polyBbox = calcBbox(polygon); - const lineBbox = calcBbox(linestring); - if (!doBBoxOverlap(polyBbox, lineBbox)) { - return false; - } - for (i; i < linestring.coordinates.length - 1; i++) { - const midPoint = getMidpoint( - linestring.coordinates[i], - linestring.coordinates[i + 1] - ); - if ( - booleanPointInPolygon({ type: "Point", coordinates: midPoint }, polygon, { - ignoreBoundary: true, - }) - ) { - output = true; - break; - } - } - return output; -} - -/** - * Is Polygon2 in Polygon1 - * Only takes into account outer rings - * - * @private - * @param {Geometry|Feature} feature1 Polygon1 - * @param {Geometry|Feature} feature2 Polygon2 - * @returns {boolean} true/false - */ -export function isPolyInPoly( - feature1: Feature | Polygon, - feature2: Feature | Polygon -) { - // Handle Nulls - if (feature1.type === "Feature" && feature1.geometry === null) { - return false; - } - if (feature2.type === "Feature" && feature2.geometry === null) { - return false; - } - - const poly1Bbox = calcBbox(feature1); - const poly2Bbox = calcBbox(feature2); - if (!doBBoxOverlap(poly1Bbox, poly2Bbox)) { - return false; - } - - const coords = getGeom(feature2).coordinates; - for (const ring of coords) { - for (const coord of ring) { - if (!booleanPointInPolygon(coord, feature1)) { - return false; - } - } - } - return true; -} - -export function doBBoxOverlap(bbox1: BBox, bbox2: BBox) { - if (bbox1[0] > bbox2[0]) { - return false; - } - if (bbox1[2] < bbox2[2]) { - return false; - } - if (bbox1[1] > bbox2[1]) { - return false; - } - if (bbox1[3] < bbox2[3]) { - return false; - } - return true; -} - -/** - * compareCoords - * - * @private - * @param {Position} pair1 point [x,y] - * @param {Position} pair2 point [x,y] - * @returns {boolean} true/false if coord pairs match - */ -export function compareCoords(pair1: number[], pair2: number[]) { - return pair1[0] === pair2[0] && pair1[1] === pair2[1]; -} - -export function getMidpoint(pair1: number[], pair2: number[]) { - return [(pair1[0] + pair2[0]) / 2, (pair1[1] + pair2[1]) / 2]; -} */ From a7b1ca79093a011322be6b3c1a97ef2ea4395e36 Mon Sep 17 00:00:00 2001 From: armantorkzaban Date: Mon, 4 Jul 2022 13:27:15 +0200 Subject: [PATCH 42/82] return type added --- lib/src/booleans/boolean_contains.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/src/booleans/boolean_contains.dart b/lib/src/booleans/boolean_contains.dart index 468b3091..3d764fcf 100644 --- a/lib/src/booleans/boolean_contains.dart +++ b/lib/src/booleans/boolean_contains.dart @@ -15,7 +15,7 @@ import 'boolean_point_on_line.dart'; /// booleanContains(line, point); /// //=true /// ``` -booleanContains(GeoJSONObject feature1, GeoJSONObject feature2) { +bool booleanContains(GeoJSONObject feature1, GeoJSONObject feature2) { var geom1 = feature1 is Feature ? feature1.geometry : feature1; var geom2 = feature2 is Feature ? feature2.geometry : feature2; @@ -180,7 +180,7 @@ bool isPolyInPoly(GeoJSONObject geom1, GeoJSONObject geom2) { return true; } -doBBoxOverlap(BBox bbox1, BBox bbox2) { +bool doBBoxOverlap(BBox bbox1, BBox bbox2) { if (bbox1[0]! > bbox2[0]!) { return false; } From d11ff4ac8b069127edc4a21748c4abdab2e8a07b Mon Sep 17 00:00:00 2001 From: armantorkzaban Date: Mon, 4 Jul 2022 14:35:47 +0200 Subject: [PATCH 43/82] disjoint and test - not done, depends on sweepline --- lib/src/booleans/boolean_crosses.dart | 360 ++++-------------- lib/src/booleans/boolean_disjoint.dart | 346 ++++------------- test/booleans/crosses_test.dart | 2 +- test/booleans/disjoint_test.dart | 51 +++ test/components/bearing_test.dart | 21 +- test/examples/booleans/.DS_Store | Bin 8196 -> 8196 bytes test/examples/booleans/disjoint/.DS_Store | Bin 0 -> 6148 bytes .../disjoint/diagrams/esri-disjoint.gif | Bin 0 -> 31587 bytes .../LineString/LineString-LineString.geojson | 31 ++ .../Point/LineString-Point-1.geojson | 26 ++ .../Point/LineString-Point-2.geojson | 26 ++ .../Polygon/LineString-In-Polygon.geojson | 32 ++ .../Polygon/LineString-Polygon.geojson | 34 ++ .../LineString/MultiPoint-LineString.geojson | 29 ++ .../MultiPoint/MultiPoint-MultiPoint.geojson | 27 ++ .../Polygon/MultiPoint-Polygon.geojson | 32 ++ .../Polygon/MultiPolygon-Polygon.geojson | 52 +++ .../LineString/Point-LineString-1.geojson | 26 ++ .../LineString/Point-LineString-2.geojson | 26 ++ .../LineString/Point-LineString-3.geojson | 26 ++ .../LineString/Point-LineString-4.geojson | 26 ++ .../Point/MultiPoint/Point-MultiPoint.geojson | 24 ++ .../false/Point/Point/Point-Point.geojson | 21 + .../Point/Polygon/Point-Polygon-1.geojson | 29 ++ .../Point/Polygon/Point-Polygon-2.geojson | 29 ++ .../Polygon-Containing-Linestring.geojson | 32 ++ .../LineString/Polygon-LineString.geojson | 34 ++ .../MultiPolygon/Polygon-MultiPolygon.geojson | 52 +++ .../false/Polygon/Point/Polygon-Point.geojson | 29 ++ .../Polygon/Large-Inside-Small.geojson | 39 ++ .../Polygon/Polygon/Polygon-Polygon.geojson | 37 ++ .../Polygon/Small-Inside-Large.geojson | 39 ++ .../false/Polygon/Polygon/issue-1216.geojson | 49 +++ .../LineString/LineString-LineString.geojson | 31 ++ .../LineString/Point/LineString-Point.geojson | 26 ++ .../Polygon/LineString-Polygon.geojson | 34 ++ .../LineString/MultiPoint-LineString.geojson | 29 ++ .../MultiPoint/MultiPoint-MultiPoint.geojson | 27 ++ .../MultiPoint/Point/MultiPoint-Point.geojson | 24 ++ .../Polygon/MultiPoint-Polygon.geojson | 32 ++ .../Polygon/MultiPolygon-Polygon.geojson | 52 +++ .../Point/LineString/Point-LineString.geojson | 26 ++ .../Point/MultiPoint/Point-Multipoint.geojson | 24 ++ .../test/true/Point/Point/Point-Point.geojson | 21 + .../true/Point/Polygon/Point-Polygon.geojson | 29 ++ .../LineString/Polygon-LineString.geojson | 34 ++ .../MultiPolygon/Polygon-MultiPolygon.geojson | 52 +++ .../true/Polygon/Point/Polygon-Point.geojson | 29 ++ .../Polygon/Polygon/Polygon-Polygon.geojson | 37 ++ 49 files changed, 1522 insertions(+), 572 deletions(-) create mode 100644 test/examples/booleans/disjoint/.DS_Store create mode 100644 test/examples/booleans/disjoint/diagrams/esri-disjoint.gif create mode 100644 test/examples/booleans/disjoint/test/false/LineString/LineString/LineString-LineString.geojson create mode 100644 test/examples/booleans/disjoint/test/false/LineString/Point/LineString-Point-1.geojson create mode 100644 test/examples/booleans/disjoint/test/false/LineString/Point/LineString-Point-2.geojson create mode 100644 test/examples/booleans/disjoint/test/false/LineString/Polygon/LineString-In-Polygon.geojson create mode 100644 test/examples/booleans/disjoint/test/false/LineString/Polygon/LineString-Polygon.geojson create mode 100644 test/examples/booleans/disjoint/test/false/MultiPoint/LineString/MultiPoint-LineString.geojson create mode 100644 test/examples/booleans/disjoint/test/false/MultiPoint/MultiPoint/MultiPoint-MultiPoint.geojson create mode 100644 test/examples/booleans/disjoint/test/false/MultiPoint/Polygon/MultiPoint-Polygon.geojson create mode 100644 test/examples/booleans/disjoint/test/false/MultiPolygon/Polygon/MultiPolygon-Polygon.geojson create mode 100644 test/examples/booleans/disjoint/test/false/Point/LineString/Point-LineString-1.geojson create mode 100644 test/examples/booleans/disjoint/test/false/Point/LineString/Point-LineString-2.geojson create mode 100644 test/examples/booleans/disjoint/test/false/Point/LineString/Point-LineString-3.geojson create mode 100644 test/examples/booleans/disjoint/test/false/Point/LineString/Point-LineString-4.geojson create mode 100644 test/examples/booleans/disjoint/test/false/Point/MultiPoint/Point-MultiPoint.geojson create mode 100644 test/examples/booleans/disjoint/test/false/Point/Point/Point-Point.geojson create mode 100644 test/examples/booleans/disjoint/test/false/Point/Polygon/Point-Polygon-1.geojson create mode 100644 test/examples/booleans/disjoint/test/false/Point/Polygon/Point-Polygon-2.geojson create mode 100644 test/examples/booleans/disjoint/test/false/Polygon/LineString/Polygon-Containing-Linestring.geojson create mode 100644 test/examples/booleans/disjoint/test/false/Polygon/LineString/Polygon-LineString.geojson create mode 100644 test/examples/booleans/disjoint/test/false/Polygon/MultiPolygon/Polygon-MultiPolygon.geojson create mode 100644 test/examples/booleans/disjoint/test/false/Polygon/Point/Polygon-Point.geojson create mode 100644 test/examples/booleans/disjoint/test/false/Polygon/Polygon/Large-Inside-Small.geojson create mode 100644 test/examples/booleans/disjoint/test/false/Polygon/Polygon/Polygon-Polygon.geojson create mode 100644 test/examples/booleans/disjoint/test/false/Polygon/Polygon/Small-Inside-Large.geojson create mode 100644 test/examples/booleans/disjoint/test/false/Polygon/Polygon/issue-1216.geojson create mode 100644 test/examples/booleans/disjoint/test/true/LineString/LineString/LineString-LineString.geojson create mode 100644 test/examples/booleans/disjoint/test/true/LineString/Point/LineString-Point.geojson create mode 100644 test/examples/booleans/disjoint/test/true/LineString/Polygon/LineString-Polygon.geojson create mode 100644 test/examples/booleans/disjoint/test/true/MultiPoint/LineString/MultiPoint-LineString.geojson create mode 100644 test/examples/booleans/disjoint/test/true/MultiPoint/MultiPoint/MultiPoint-MultiPoint.geojson create mode 100644 test/examples/booleans/disjoint/test/true/MultiPoint/Point/MultiPoint-Point.geojson create mode 100644 test/examples/booleans/disjoint/test/true/MultiPoint/Polygon/MultiPoint-Polygon.geojson create mode 100644 test/examples/booleans/disjoint/test/true/MultiPolygon/Polygon/MultiPolygon-Polygon.geojson create mode 100644 test/examples/booleans/disjoint/test/true/Point/LineString/Point-LineString.geojson create mode 100644 test/examples/booleans/disjoint/test/true/Point/MultiPoint/Point-Multipoint.geojson create mode 100644 test/examples/booleans/disjoint/test/true/Point/Point/Point-Point.geojson create mode 100644 test/examples/booleans/disjoint/test/true/Point/Polygon/Point-Polygon.geojson create mode 100644 test/examples/booleans/disjoint/test/true/Polygon/LineString/Polygon-LineString.geojson create mode 100644 test/examples/booleans/disjoint/test/true/Polygon/MultiPolygon/Polygon-MultiPolygon.geojson create mode 100644 test/examples/booleans/disjoint/test/true/Polygon/Point/Polygon-Point.geojson create mode 100644 test/examples/booleans/disjoint/test/true/Polygon/Polygon/Polygon-Polygon.geojson diff --git a/lib/src/booleans/boolean_crosses.dart b/lib/src/booleans/boolean_crosses.dart index 574f3363..e51e4215 100644 --- a/lib/src/booleans/boolean_crosses.dart +++ b/lib/src/booleans/boolean_crosses.dart @@ -4,68 +4,69 @@ import '../line_intersect.dart'; import '../polygon_to_line.dart'; import 'boolean_point_in_polygon.dart'; - -Boolean-Crosses returns True if the intersection results in a geometry whose dimension is one less than - * the maximum dimension of the two source geometries and the intersection set is interior to - * both source geometries. - * - * Boolean-Crosses returns t (TRUE) for only multipoint/polygon, multipoint/linestring, linestring/linestring, linestring/polygon, and linestring/multipolygon comparisons. - * Other comparisons are not supported as they are outside the OpenGIS Simple Features spec and may give unexpected results. - * - * @name booleanCrosses - * @param {Geometry|Feature} feature1 GeoJSON Feature or Geometry - * @param {Geometry|Feature} feature2 GeoJSON Feature or Geometry - * @returns {boolean} true/false - * @example - * var line1 = turf.lineString([[-2, 2], [4, 2]]); - * var line2 = turf.lineString([[1, 1], [1, 2], [1, 3], [1, 4]]); - * - * var cross = turf.booleanCrosses(line1, line2); - * //=true - */ - -bool booleanCrosses(GeometryObject feature1, GeometryObject feature2) { - var geom1 = getGeom(feature1); - var geom2 = getGeom(feature2); - var type1 = geom1.type; - var type2 = geom2.type; - - switch (type1) { - case MultiPoint: - switch (type2) { - case LineString: - return doMultiPointAndLineStringCross(geom1, geom2); - case Polygon: - return doesMultiPointCrossPoly(geom1, geom2); - default: - throw UnsupportedError("feature2 $type2 geometry not supported"); - } - case LineString: - switch (type2) { - case MultiPoint: // An inverse operation - return doMultiPointAndLineStringCross(geom2, geom1); - case LineString: - return doLineStringsCross(geom1, geom2); - case Polygon: - return doLineStringAndPolygonCross(geom1, geom2); - default: - throw UnsupportedError("feature2 $type2 geometry not supported"); - } - case Polygon: - switch (type2) { - case MultiPoint: // An inverse operation - return doesMultiPointCrossPoly(geom2, geom1); - case LineString: // An inverse operation - return doLineStringAndPolygonCross(geom2, geom1); - default: - throw UnsupportedError("feature2 $type2 geometry not supported"); - } - default: - throw UnsupportedError("feature1 $type1 geometry not supported"); +/// Boolean-Crosses returns True if the intersection results in a geometry whose +/// dimension is one less than the maximum dimension of the two source geometries +/// and the intersection set is interior to both source geometries. +/// Boolean-Crosses returns [true] for only [MultiPoint]/[Polygon], [MultiPoint]/[Linestring], +/// [Linestring]/[Linestring], [Linestring]/[Polygon], and [Linestring]/[multiPolygon] comparisons. +/// Other comparisons are not supported as they are outside the OpenGIS Simple +/// [Feature]s spec and may give unexpected results. +/// example: +/// ```dart +/// var line1 = LineString(coordinates: [ +/// Position.of([-2, 2]), +/// Position.of([4, 2]) +/// ]); +/// var line2 = LineString(coordinates: [ +/// Position.of([1, 1]), +/// Position.of([1, 2]), +/// Position.of([1, 3]), +/// Position.of([1, 4]) +/// ]); +/// var cross = booleanCrosses(line1, line2); +/// //=true +/// ``` +bool booleanCrosses(GeoJSONObject feature1, GeoJSONObject feature2) { + var geom1 = feature1 is Feature ? feature1.geometry : feature1; + var geom2 = feature2 is Feature ? feature2.geometry : feature2; + + Exception exception() => Exception("$geom2 is not supperted"); + if (geom1 is MultiPoint) { + if (geom2 is LineString) { + return doMultiPointAndLineStringCross(geom1, geom2); + } else if (geom2 is Polygon) { + return doesMultiPointCrossPoly(geom1, geom2); + } else { + throw exception(); + } + } else if (geom1 is LineString) { + if (geom2 is MultiPoint) { + // An inverse operation + return doMultiPointAndLineStringCross(geom2, geom1); + } else if (geom2 is LineString) { + return doLineStringsCross(geom1, geom2); + } else if (geom2 is Polygon) { + return doLineStringAndPolygonCross(geom1, geom2); + } else { + throw exception(); + } + } else if (geom1 is Polygon) { + if (geom2 is MultiPoint) { + // An inverse operation + return doesMultiPointCrossPoly(geom2, geom1); + } else if (geom2 is LineString) { + // An inverse operation + return doLineStringAndPolygonCross(geom2, geom1); + } else { + throw exception(); + } + } else { + throw exception(); } } -doMultiPointAndLineStringCross(MultiPoint multiPoint, LineString lineString) { +bool doMultiPointAndLineStringCross( + MultiPoint multiPoint, LineString lineString) { var foundIntPoint = false; var foundExtPoint = false; var pointLength = multiPoint.coordinates.length; @@ -76,7 +77,7 @@ doMultiPointAndLineStringCross(MultiPoint multiPoint, LineString lineString) { if (i2 == 0 || i2 == lineString.coordinates.length - 2) { incEndVertices = false; } - if (isPointOnLineSegment( + if (_isPointOnLineSegment( lineString.coordinates[i2], lineString.coordinates[i2 + 1], multiPoint.coordinates[i], @@ -91,7 +92,7 @@ doMultiPointAndLineStringCross(MultiPoint multiPoint, LineString lineString) { return foundIntPoint && foundExtPoint; } -doLineStringsCross(LineString lineString1, LineString lineString2) { +bool doLineStringsCross(LineString lineString1, LineString lineString2) { var doLinesIntersect = lineIntersect(lineString1, lineString2); if (doLinesIntersect.features.isNotEmpty) { for (var i = 0; i < lineString1.coordinates.length - 1; i++) { @@ -100,7 +101,7 @@ doLineStringsCross(LineString lineString1, LineString lineString2) { if (i2 == 0 || i2 == lineString2.coordinates.length - 2) { incEndVertices = false; } - if (isPointOnLineSegment( + if (_isPointOnLineSegment( lineString1.coordinates[i], lineString1.coordinates[i + 1], lineString2.coordinates[i2], @@ -113,7 +114,7 @@ doLineStringsCross(LineString lineString1, LineString lineString2) { return false; } -doLineStringAndPolygonCross(LineString lineString, Polygon polygon) { +bool doLineStringAndPolygonCross(LineString lineString, Polygon polygon) { LineString line = polygonToLine(polygon); var doLinesIntersect = lineIntersect(lineString, line); if (doLinesIntersect.features.isNotEmpty) { @@ -122,7 +123,7 @@ doLineStringAndPolygonCross(LineString lineString, Polygon polygon) { return false; } -doesMultiPointCrossPoly(MultiPoint multiPoint, Polygon polygon) { +bool doesMultiPointCrossPoly(MultiPoint multiPoint, Polygon polygon) { var foundIntPoint = false; var foundExtPoint = false; var pointLength = multiPoint.coordinates.length; @@ -137,21 +138,18 @@ doesMultiPointCrossPoly(MultiPoint multiPoint, Polygon polygon) { return foundExtPoint && foundIntPoint; } -/** - * Is a point on a line segment - * Only takes into account outer rings - * See http://stackoverflow.com/a/4833823/1979085 - * - * @private - * @param {number[]} lineSegmentStart coord pair of start of line - * @param {number[]} lineSegmentEnd coord pair of end of line - * @param {number[]} pt coord pair of point to check - * @param {boolean} incEnd whether the point is allowed to fall on the line ends - * @returns {boolean} true/false - */ - -isPointOnLineSegment(Position lineSegmentStart, Position lineSegmentEnd, - Position pt, bool incEnd) { +/// Only takes into account outer rings +/// See http://stackoverflow.com/a/4833823/1979085 +/// lineSegmentStart [Position] of start of line +/// lineSegmentEnd [Position] of end of line +/// pt [Position] of point to check +/// [incEnd] controls whether the [Point] is allowed to fall on the line ends +bool _isPointOnLineSegment( + Position lineSegmentStart, + Position lineSegmentEnd, + Position pt, + bool incEnd, +) { var dxc = pt[0]! - lineSegmentStart[0]!; var dyc = pt[1]! - lineSegmentStart[1]!; var dxl = lineSegmentEnd[0]! - lineSegmentStart[0]!; @@ -180,207 +178,3 @@ isPointOnLineSegment(Position lineSegmentStart, Position lineSegmentEnd, : lineSegmentEnd[1]! < pt[1]! && pt[1]! < lineSegmentStart[1]!; } } - - - -/** - * import { Feature, Geometry, Polygon, LineString, MultiPoint } from "geojson"; -import lineIntersect from "@turf/line-intersect"; -import { polygonToLine } from "@turf/polygon-to-line"; -import booleanPointInPolygon from "@turf/boolean-point-in-polygon"; -import { getGeom } from "@turf/invariant"; -import { point } from "@turf/helpers"; - -/** - * Boolean-Crosses returns True if the intersection results in a geometry whose dimension is one less than - * the maximum dimension of the two source geometries and the intersection set is interior to - * both source geometries. - * - * Boolean-Crosses returns t (TRUE) for only multipoint/polygon, multipoint/linestring, linestring/linestring, linestring/polygon, and linestring/multipolygon comparisons. - * Other comparisons are not supported as they are outside the OpenGIS Simple Features spec and may give unexpected results. - * - * @name booleanCrosses - * @param {Geometry|Feature} feature1 GeoJSON Feature or Geometry - * @param {Geometry|Feature} feature2 GeoJSON Feature or Geometry - * @returns {boolean} true/false - * @example - * var line1 = turf.lineString([[-2, 2], [4, 2]]); - * var line2 = turf.lineString([[1, 1], [1, 2], [1, 3], [1, 4]]); - * - * var cross = turf.booleanCrosses(line1, line2); - * //=true - */ -function booleanCrosses( - feature1: Feature | Geometry, - feature2: Feature | Geometry -): boolean { - var geom1 = getGeom(feature1); - var geom2 = getGeom(feature2); - var type1 = geom1.type; - var type2 = geom2.type; - - switch (type1) { - case "MultiPoint": - switch (type2) { - case "LineString": - return doMultiPointAndLineStringCross(geom1, geom2); - case "Polygon": - return doesMultiPointCrossPoly(geom1, geom2); - default: - throw new Error("feature2 " + type2 + " geometry not supported"); - } - case "LineString": - switch (type2) { - case "MultiPoint": // An inverse operation - return doMultiPointAndLineStringCross(geom2, geom1); - case "LineString": - return doLineStringsCross(geom1, geom2); - case "Polygon": - return doLineStringAndPolygonCross(geom1, geom2); - default: - throw new Error("feature2 " + type2 + " geometry not supported"); - } - case "Polygon": - switch (type2) { - case "MultiPoint": // An inverse operation - return doesMultiPointCrossPoly(geom2, geom1); - case "LineString": // An inverse operation - return doLineStringAndPolygonCross(geom2, geom1); - default: - throw new Error("feature2 " + type2 + " geometry not supported"); - } - default: - throw new Error("feature1 " + type1 + " geometry not supported"); - } -} - -function doMultiPointAndLineStringCross( - multiPoint: MultiPoint, - lineString: LineString -) { - var foundIntPoint = false; - var foundExtPoint = false; - var pointLength = multiPoint.coordinates.length; - var i = 0; - while (i < pointLength && !foundIntPoint && !foundExtPoint) { - for (var i2 = 0; i2 < lineString.coordinates.length - 1; i2++) { - var incEndVertices = true; - if (i2 === 0 || i2 === lineString.coordinates.length - 2) { - incEndVertices = false; - } - if ( - isPointOnLineSegment( - lineString.coordinates[i2], - lineString.coordinates[i2 + 1], - multiPoint.coordinates[i], - incEndVertices - ) - ) { - foundIntPoint = true; - } else { - foundExtPoint = true; - } - } - i++; - } - return foundIntPoint && foundExtPoint; -} - -function doLineStringsCross(lineString1: LineString, lineString2: LineString) { - var doLinesIntersect = lineIntersect(lineString1, lineString2); - if (doLinesIntersect.features.length > 0) { - for (var i = 0; i < lineString1.coordinates.length - 1; i++) { - for (var i2 = 0; i2 < lineString2.coordinates.length - 1; i2++) { - var incEndVertices = true; - if (i2 === 0 || i2 === lineString2.coordinates.length - 2) { - incEndVertices = false; - } - if ( - isPointOnLineSegment( - lineString1.coordinates[i], - lineString1.coordinates[i + 1], - lineString2.coordinates[i2], - incEndVertices - ) - ) { - return true; - } - } - } - } - return false; -} - -function doLineStringAndPolygonCross(lineString: LineString, polygon: Polygon) { - const line: any = polygonToLine(polygon); - const doLinesIntersect = lineIntersect(lineString, line); - if (doLinesIntersect.features.length > 0) { - return true; - } - return false; -} - -function doesMultiPointCrossPoly(multiPoint: MultiPoint, polygon: Polygon) { - var foundIntPoint = false; - var foundExtPoint = false; - var pointLength = multiPoint.coordinates.length; - for (let i = 0; i < pointLength && (!foundIntPoint || !foundExtPoint); i++) { - if (booleanPointInPolygon(point(multiPoint.coordinates[i]), polygon)) { - foundIntPoint = true; - } else { - foundExtPoint = true; - } - } - - return foundExtPoint && foundIntPoint; -} - -/** - * Is a point on a line segment - * Only takes into account outer rings - * See http://stackoverflow.com/a/4833823/1979085 - * - * @private - * @param {number[]} lineSegmentStart coord pair of start of line - * @param {number[]} lineSegmentEnd coord pair of end of line - * @param {number[]} pt coord pair of point to check - * @param {boolean} incEnd whether the point is allowed to fall on the line ends - * @returns {boolean} true/false - */ -function isPointOnLineSegment( - lineSegmentStart: number[], - lineSegmentEnd: number[], - pt: number[], - incEnd: boolean -) { - var dxc = pt[0] - lineSegmentStart[0]; - var dyc = pt[1] - lineSegmentStart[1]; - var dxl = lineSegmentEnd[0] - lineSegmentStart[0]; - var dyl = lineSegmentEnd[1] - lineSegmentStart[1]; - var cross = dxc * dyl - dyc * dxl; - if (cross !== 0) { - return false; - } - if (incEnd) { - if (Math.abs(dxl) >= Math.abs(dyl)) { - return dxl > 0 - ? lineSegmentStart[0] <= pt[0] && pt[0] <= lineSegmentEnd[0] - : lineSegmentEnd[0] <= pt[0] && pt[0] <= lineSegmentStart[0]; - } - return dyl > 0 - ? lineSegmentStart[1] <= pt[1] && pt[1] <= lineSegmentEnd[1] - : lineSegmentEnd[1] <= pt[1] && pt[1] <= lineSegmentStart[1]; - } else { - if (Math.abs(dxl) >= Math.abs(dyl)) { - return dxl > 0 - ? lineSegmentStart[0] < pt[0] && pt[0] < lineSegmentEnd[0] - : lineSegmentEnd[0] < pt[0] && pt[0] < lineSegmentStart[0]; - } - return dyl > 0 - ? lineSegmentStart[1] < pt[1] && pt[1] < lineSegmentEnd[1] - : lineSegmentEnd[1] < pt[1] && pt[1] < lineSegmentStart[1]; - } -} - -export default booleanCrosses; - */ \ No newline at end of file diff --git a/lib/src/booleans/boolean_disjoint.dart b/lib/src/booleans/boolean_disjoint.dart index 886e0d7c..80342b32 100644 --- a/lib/src/booleans/boolean_disjoint.dart +++ b/lib/src/booleans/boolean_disjoint.dart @@ -4,79 +4,73 @@ import '../line_intersect.dart'; import '../polygon_to_line.dart'; import 'boolean_point_in_polygon.dart'; - Boolean-disjoint returns (TRUE) if the intersection of the two geometries is an empty set. - * - * @name booleanDisjoint - * @param {Geometry|Feature} feature1 GeoJSON Feature or Geometry - * @param {Geometry|Feature} feature2 GeoJSON Feature or Geometry - * @returns {boolean} true/false - * @example - * var point = turf.point([2, 2]); - * var line = turf.lineString([[1, 1], [1, 2], [1, 3], [1, 4]]); - * - * turf.booleanDisjoint(line, point); - * //=true - */ +/// Returns (TRUE) if the intersection of the two geometries is an empty set. +/// example: +/// ```dart +/// var point = Point(coordinates: Position.of([2, 2])); +/// var line = LineString( +/// coordinates: [ +/// Position.of([1, 1]), +/// Position.of([1, 2]), +/// Position.of([1, 3]), +/// Position.of([1, 4]) +/// ], +/// ); +/// booleanDisjoint(line, point); +/// //=true +/// ``` bool booleanDisjoint(GeoJSONObject feature1, GeoJSONObject feature2) { var bool = true; - flattenEach(feature1, (flatten1, featureIndex, multiFeatureIndex) { - flattenEach(feature2, (flatten2, featureIndex, multiFeatureIndex) { - if (bool == false) { - return false; - } - bool = disjoint(flatten1.geometry!, flatten2.geometry!); - }); - }); + flattenEach( + feature1, + (flatten1, featureIndex, multiFeatureIndex) { + flattenEach( + feature2, + (flatten2, featureIndex, multiFeatureIndex) { + if (bool == false) { + return false; + } + bool = _disjoint(flatten1.geometry!, flatten2.geometry!); + }, + ); + }, + ); return bool; } -/** - * Disjoint operation for simple Geometries (Point/LineString/Polygon) - * - * @private - * @param {Geometry} geom1 GeoJSON Geometry - * @param {Geometry} geom2 GeoJSON Geometry - * @returns {boolean} true/false - */ -disjoint(GeometryType geom1, GeometryType geom2) { - switch (geom1.type) { - case GeoJSONObjectType.point: - switch (geom2.type) { - case GeoJSONObjectType.point: - return !compareCoords(geom1.coordinates, geom2.coordinates); - case GeoJSONObjectType.lineString: - return !isPointOnLine(geom2 as LineString, geom1 as Point); - case GeoJSONObjectType.polygon: - return !booleanPointInPolygon((geom1 as Point).coordinates, geom2); - } - /* istanbul ignore next */ - break; - case GeoJSONObjectType.lineString: - switch (geom2.type) { - case GeoJSONObjectType.point: - return !isPointOnLine(geom1 as LineString, geom2 as Point); - case GeoJSONObjectType.lineString: - return !isLineOnLine(geom1 as LineString, geom2 as LineString); - case GeoJSONObjectType.polygon: - return !isLineInPoly(geom2 as Polygon, geom1 as LineString); - } - /* istanbul ignore next */ - break; - case GeoJSONObjectType.polygon: - switch (geom2.type) { - case GeoJSONObjectType.point: - return !booleanPointInPolygon((geom2 as Point).coordinates, geom1); - case GeoJSONObjectType.lineString: - return !isLineInPoly(geom1 as Polygon, geom2 as LineString); - case GeoJSONObjectType.polygon: - return !isPolyInPoly(geom2 as Polygon, geom1 as Polygon); - } +/// Disjoint operation for simple Geometries (Point/LineString/Polygon) +_disjoint(GeometryType geom1, GeometryType geom2) { + if (geom1 is Point) { + if (geom2 is Point) { + return !_compareCoords(geom1.coordinates, geom2.coordinates); + } else if (geom2 is LineString) { + return !isPointOnLine(geom2, geom1); + } else if (geom2 is Polygon) { + return !booleanPointInPolygon((geom1).coordinates, geom2); + } + } else if (geom1 is LineString) { + if (geom2 is Point) { + return !isPointOnLine(geom1, geom2); + } else if (geom2 is LineString) { + return !isLineOnLine(geom1, geom2); + } else if (geom2 is Polygon) { + return !isLineInPoly(geom2, geom1); + } + } else if (geom1 is Polygon) { + if (geom2 is Point) { + return !booleanPointInPolygon((geom2).coordinates, geom1); + } else if (geom2 is LineString) { + return !isLineInPoly(geom1, geom2); + } else if (geom2 is Polygon) { + return !_isPolyInPoly(geom2, geom1); + } + } else { + return false; } - return false; } // http://stackoverflow.com/a/11908158/1979085 -isPointOnLine(LineString lineString, Point pt) { +bool isPointOnLine(LineString lineString, Point pt) { for (var i = 0; i < lineString.coordinates.length - 1; i++) { if (isPointOnLineSegment(lineString.coordinates[i], lineString.coordinates[i + 1], pt.coordinates)) { @@ -86,7 +80,7 @@ isPointOnLine(LineString lineString, Point pt) { return false; } -isLineOnLine(LineString lineString1, LineString lineString2) { +bool isLineOnLine(LineString lineString1, LineString lineString2) { var doLinesIntersect = lineIntersect(lineString1, lineString2); if (doLinesIntersect.features.isNotEmpty) { return true; @@ -94,7 +88,7 @@ isLineOnLine(LineString lineString1, LineString lineString2) { return false; } -isLineInPoly(Polygon polygon, LineString lineString) { +bool isLineInPoly(Polygon polygon, LineString lineString) { for (var coord in lineString.coordinates) { if (booleanPointInPolygon(coord, polygon)) { return true; @@ -107,17 +101,10 @@ isLineInPoly(Polygon polygon, LineString lineString) { return false; } -/** - * Is Polygon (geom1) in Polygon (geom2) - * Only takes into account outer rings - * See http://stackoverflow.com/a/4833823/1979085 - * - * @private - * @param {Geometry|Feature} feature1 Polygon1 - * @param {Geometry|Feature} feature2 Polygon2 - * @returns {boolean} true/false - */ -isPolyInPoly(Polygon feature1, Polygon feature2) { +/// Is Polygon (geom1) in Polygon (geom2) +/// Only takes into account outer rings +/// See http://stackoverflow.com/a/4833823/1979085 +_isPolyInPoly(Polygon feature1, Polygon feature2) { for (var coord1 in feature1.coordinates[0]) { if (booleanPointInPolygon(coord1, feature2)) { return true; @@ -136,7 +123,7 @@ isPolyInPoly(Polygon feature1, Polygon feature2) { return false; } -isPointOnLineSegment( +bool isPointOnLineSegment( Position lineSegmentStart, Position lineSegmentEnd, Position pt) { var dxc = pt[0]! - lineSegmentStart[0]!; var dyc = pt[1]! - lineSegmentStart[1]!; @@ -159,206 +146,7 @@ isPointOnLineSegment( } } -/** - * compareCoords - * - * @private - * @param {Position} pair1 point [x,y] - * @param {Position} pair2 point [x,y] - * @returns {boolean} true/false if coord pairs match - */ -compareCoords(Position pair1, Position pair2) { +/// Returns true/false if coord pairs match +bool _compareCoords(Position pair1, Position pair2) { return pair1[0] == pair2[0] && pair1[1] == pair2[1]; } - - -/** - * import { Feature, Geometry, LineString, Point, Polygon } from "geojson"; -import booleanPointInPolygon from "@turf/boolean-point-in-polygon"; -import lineIntersect from "@turf/line-intersect"; -import { flattenEach } from "@turf/meta"; -import polygonToLine from "@turf/polygon-to-line"; - -/** - * Boolean-disjoint returns (TRUE) if the intersection of the two geometries is an empty set. - * - * @name booleanDisjoint - * @param {Geometry|Feature} feature1 GeoJSON Feature or Geometry - * @param {Geometry|Feature} feature2 GeoJSON Feature or Geometry - * @returns {boolean} true/false - * @example - * var point = turf.point([2, 2]); - * var line = turf.lineString([[1, 1], [1, 2], [1, 3], [1, 4]]); - * - * turf.booleanDisjoint(line, point); - * //=true - */ -function booleanDisjoint( - feature1: Feature | Geometry, - feature2: Feature | Geometry -): boolean { - let bool = true; - flattenEach(feature1, (flatten1) => { - flattenEach(feature2, (flatten2) => { - if (bool === false) { - return false; - } - bool = disjoint(flatten1.geometry, flatten2.geometry); - }); - }); - return bool; -} - -/** - * Disjoint operation for simple Geometries (Point/LineString/Polygon) - * - * @private - * @param {Geometry} geom1 GeoJSON Geometry - * @param {Geometry} geom2 GeoJSON Geometry - * @returns {boolean} true/false - */ -function disjoint(geom1: any, geom2: any) { - switch (geom1.type) { - case "Point": - switch (geom2.type) { - case "Point": - return !compareCoords(geom1.coordinates, geom2.coordinates); - case "LineString": - return !isPointOnLine(geom2, geom1); - case "Polygon": - return !booleanPointInPolygon(geom1, geom2); - } - /* istanbul ignore next */ - break; - case "LineString": - switch (geom2.type) { - case "Point": - return !isPointOnLine(geom1, geom2); - case "LineString": - return !isLineOnLine(geom1, geom2); - case "Polygon": - return !isLineInPoly(geom2, geom1); - } - /* istanbul ignore next */ - break; - case "Polygon": - switch (geom2.type) { - case "Point": - return !booleanPointInPolygon(geom2, geom1); - case "LineString": - return !isLineInPoly(geom1, geom2); - case "Polygon": - return !isPolyInPoly(geom2, geom1); - } - } - return false; -} - -// http://stackoverflow.com/a/11908158/1979085 -function isPointOnLine(lineString: LineString, pt: Point) { - for (let i = 0; i < lineString.coordinates.length - 1; i++) { - if ( - isPointOnLineSegment( - lineString.coordinates[i], - lineString.coordinates[i + 1], - pt.coordinates - ) - ) { - return true; - } - } - return false; -} - -function isLineOnLine(lineString1: LineString, lineString2: LineString) { - const doLinesIntersect = lineIntersect(lineString1, lineString2); - if (doLinesIntersect.features.length > 0) { - return true; - } - return false; -} - -function isLineInPoly(polygon: Polygon, lineString: LineString) { - for (const coord of lineString.coordinates) { - if (booleanPointInPolygon(coord, polygon)) { - return true; - } - } - const doLinesIntersect = lineIntersect(lineString, polygonToLine(polygon)); - if (doLinesIntersect.features.length > 0) { - return true; - } - return false; -} - -/** - * Is Polygon (geom1) in Polygon (geom2) - * Only takes into account outer rings - * See http://stackoverflow.com/a/4833823/1979085 - * - * @private - * @param {Geometry|Feature} feature1 Polygon1 - * @param {Geometry|Feature} feature2 Polygon2 - * @returns {boolean} true/false - */ -function isPolyInPoly(feature1: Polygon, feature2: Polygon) { - for (const coord1 of feature1.coordinates[0]) { - if (booleanPointInPolygon(coord1, feature2)) { - return true; - } - } - for (const coord2 of feature2.coordinates[0]) { - if (booleanPointInPolygon(coord2, feature1)) { - return true; - } - } - const doLinesIntersect = lineIntersect( - polygonToLine(feature1), - polygonToLine(feature2) - ); - if (doLinesIntersect.features.length > 0) { - return true; - } - return false; -} - -function isPointOnLineSegment( - lineSegmentStart: number[], - lineSegmentEnd: number[], - pt: number[] -) { - const dxc = pt[0] - lineSegmentStart[0]; - const dyc = pt[1] - lineSegmentStart[1]; - const dxl = lineSegmentEnd[0] - lineSegmentStart[0]; - const dyl = lineSegmentEnd[1] - lineSegmentStart[1]; - const cross = dxc * dyl - dyc * dxl; - if (cross !== 0) { - return false; - } - if (Math.abs(dxl) >= Math.abs(dyl)) { - if (dxl > 0) { - return lineSegmentStart[0] <= pt[0] && pt[0] <= lineSegmentEnd[0]; - } else { - return lineSegmentEnd[0] <= pt[0] && pt[0] <= lineSegmentStart[0]; - } - } else if (dyl > 0) { - return lineSegmentStart[1] <= pt[1] && pt[1] <= lineSegmentEnd[1]; - } else { - return lineSegmentEnd[1] <= pt[1] && pt[1] <= lineSegmentStart[1]; - } -} - -/** - * compareCoords - * - * @private - * @param {Position} pair1 point [x,y] - * @param {Position} pair2 point [x,y] - * @returns {boolean} true/false if coord pairs match - */ -function compareCoords(pair1: number[], pair2: number[]) { - return pair1[0] === pair2[0] && pair1[1] === pair2[1]; -} - -export default booleanDisjoint; - */ \ No newline at end of file diff --git a/test/booleans/crosses_test.dart b/test/booleans/crosses_test.dart index 262ecacf..7c9f57c0 100644 --- a/test/booleans/crosses_test.dart +++ b/test/booleans/crosses_test.dart @@ -5,7 +5,7 @@ import 'package:test/test.dart'; import 'package:turf/helpers.dart'; import 'package:turf/src/booleans/boolean_crosses.dart'; -//main() { +main() { group( 'boolean_crosses', () { diff --git a/test/booleans/disjoint_test.dart b/test/booleans/disjoint_test.dart index 8b137891..369df336 100644 --- a/test/booleans/disjoint_test.dart +++ b/test/booleans/disjoint_test.dart @@ -1 +1,52 @@ +import 'dart:convert'; +import 'dart:io'; +import 'package:test/test.dart'; +import 'package:turf/helpers.dart'; +import 'package:turf/src/booleans/boolean_disjoint.dart'; + +main() { + group( + 'boolean_crosses', + () { + var inDir = Directory('./test/examples/booleans/disjoint/true'); + for (var file in inDir.listSync(recursive: true)) { + if (file is File && file.path.endsWith('.geojson')) { + test( + file.path, + () { + // True Fixtures + var inSource = file.readAsStringSync(); + var inGeom = GeoJSONObject.fromJson(jsonDecode(inSource)); + + var feature1 = (inGeom as FeatureCollection).features[0]; + var feature2 = inGeom.features[1]; + var result = booleanDisjoint(feature1, feature2); + expect(result, true); + }, + ); + // False Fixtures + var inDir1 = Directory('./test/examples/booleans/disjoint/false'); + for (var file in inDir1.listSync(recursive: true)) { + if (file is File && file.path.endsWith('.geojson')) { + test( + file.path, + () { + // True Fixtures + var inSource = file.readAsStringSync(); + var inGeom = GeoJSONObject.fromJson(jsonDecode(inSource)); + + var feature1 = (inGeom as FeatureCollection).features[0]; + var feature2 = inGeom.features[1]; + var result = booleanDisjoint(feature1, feature2); + + expect(result, false); + }, + ); + } + } + } + } + }, + ); +} diff --git a/test/components/bearing_test.dart b/test/components/bearing_test.dart index 9f2ac72e..8a550ba5 100644 --- a/test/components/bearing_test.dart +++ b/test/components/bearing_test.dart @@ -3,15 +3,18 @@ import 'package:turf/bearing.dart'; import 'package:turf/helpers.dart'; main() { - test('bearing', () { - var start = Point(coordinates: Position.of([-75, 45])); - var end = Point(coordinates: Position.of([20, 60])); + test( + 'bearing', + () { + var start = Point(coordinates: Position.of([-75, 45])); + var end = Point(coordinates: Position.of([20, 60])); - var initialBearing = bearing(start, end); - expect(initialBearing.toStringAsFixed(2), '37.75'); + var initialBearing = bearing(start, end); + expect(initialBearing.toStringAsFixed(2), '37.75'); - var finalBearing = bearing(start, end, calcFinal: true); - expect(finalBearing.toStringAsFixed(2), '120.01'); - expect(finalBearing, calculateFinalBearing(start, end)); - }); + var finalBearing = bearing(start, end, calcFinal: true); + expect(finalBearing.toStringAsFixed(2), '120.01'); + expect(finalBearing, calculateFinalBearing(start, end)); + }, + ); } diff --git a/test/examples/booleans/.DS_Store b/test/examples/booleans/.DS_Store index f424fef32216d6b513b266dd05335fcb7665fd3c..03ba999d6278055db46349dc83a4f6ab4abda0a2 100644 GIT binary patch delta 133 zcmZp1XmOa}&nUPtU^hRb;AS3yt&ENw3@Hqm48;st4EaDhkD-`4LZhaa-3!n@+bRdJA)_EfC?Wee~pFO#_ z_wXr+v%Fsa5T%9k;?lBQmMikwzt?>~5At5t3c8onJJUJ|M|KdN$DMw=x^}43Jc!dy z*CfPI2Sctd;xy9zmhPodW^#QyAS<%cu5Jtl&Ar{4+G`AJYS7%>si{W2-W(1qa(#1q z|Fr#(Jf`}^%nStn$3|8ij^GuI@w}h?Zkp)y4t=BeQ5+*Pzzi@0e}MtFcgdB%@Ui@j z%m6bmR|aT*P^g5S!@{E3I3Ds{XhQs{y&|>J!XIz_*V>w z@{xbk!YR4hIx{({wF>nHm4xC7i{lhDOew}#D#aV9M$oUwK=d3I7SV&k2LVF^H_X6X G8TbOms$y{f literal 0 HcmV?d00001 diff --git a/test/examples/booleans/disjoint/diagrams/esri-disjoint.gif b/test/examples/booleans/disjoint/diagrams/esri-disjoint.gif new file mode 100644 index 0000000000000000000000000000000000000000..fef0a5f7286f8788e59d9ff0c91b011583a58e14 GIT binary patch literal 31587 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 X&omzV)ksme6l8TNWZ07q0NegQ|Gu+x literal 0 HcmV?d00001 diff --git a/test/examples/booleans/disjoint/test/false/LineString/LineString/LineString-LineString.geojson b/test/examples/booleans/disjoint/test/false/LineString/LineString/LineString-LineString.geojson new file mode 100644 index 00000000..5ad6f986 --- /dev/null +++ b/test/examples/booleans/disjoint/test/false/LineString/LineString/LineString-LineString.geojson @@ -0,0 +1,31 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [0, 2], + [12, 2], + [12, 3], + [12, 4] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [1, 1], + [1, 2], + [1, 3], + [1, 4] + ] + } + } + ] +} diff --git a/test/examples/booleans/disjoint/test/false/LineString/Point/LineString-Point-1.geojson b/test/examples/booleans/disjoint/test/false/LineString/Point/LineString-Point-1.geojson new file mode 100644 index 00000000..39e7953d --- /dev/null +++ b/test/examples/booleans/disjoint/test/false/LineString/Point/LineString-Point-1.geojson @@ -0,0 +1,26 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [1, 1], + [1, 2], + [1, 3], + [1, 4] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [1, 1] + } + } + ] +} diff --git a/test/examples/booleans/disjoint/test/false/LineString/Point/LineString-Point-2.geojson b/test/examples/booleans/disjoint/test/false/LineString/Point/LineString-Point-2.geojson new file mode 100644 index 00000000..323ca4e1 --- /dev/null +++ b/test/examples/booleans/disjoint/test/false/LineString/Point/LineString-Point-2.geojson @@ -0,0 +1,26 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [1, 1], + [1, 2], + [1, 3], + [1, 4] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [1, 1.5] + } + } + ] +} diff --git a/test/examples/booleans/disjoint/test/false/LineString/Polygon/LineString-In-Polygon.geojson b/test/examples/booleans/disjoint/test/false/LineString/Polygon/LineString-In-Polygon.geojson new file mode 100644 index 00000000..62d55b65 --- /dev/null +++ b/test/examples/booleans/disjoint/test/false/LineString/Polygon/LineString-In-Polygon.geojson @@ -0,0 +1,32 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [1, 2.5], + [2, 2.5] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [-1, 2], + [3, 2], + [3, 3], + [-1, 3], + [-1, 2] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/disjoint/test/false/LineString/Polygon/LineString-Polygon.geojson b/test/examples/booleans/disjoint/test/false/LineString/Polygon/LineString-Polygon.geojson new file mode 100644 index 00000000..be2b9688 --- /dev/null +++ b/test/examples/booleans/disjoint/test/false/LineString/Polygon/LineString-Polygon.geojson @@ -0,0 +1,34 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [0, 2], + [12, 2], + [12, 3], + [12, 4] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [-1, 2], + [3, 2], + [3, 3], + [-1, 3], + [-1, 2] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/disjoint/test/false/MultiPoint/LineString/MultiPoint-LineString.geojson b/test/examples/booleans/disjoint/test/false/MultiPoint/LineString/MultiPoint-LineString.geojson new file mode 100644 index 00000000..f7bc3dd8 --- /dev/null +++ b/test/examples/booleans/disjoint/test/false/MultiPoint/LineString/MultiPoint-LineString.geojson @@ -0,0 +1,29 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPoint", + "coordinates": [ + [1, 1], + [0, 0] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [1, 1], + [1, 2], + [1, 3], + [1, 4] + ] + } + } + ] +} diff --git a/test/examples/booleans/disjoint/test/false/MultiPoint/MultiPoint/MultiPoint-MultiPoint.geojson b/test/examples/booleans/disjoint/test/false/MultiPoint/MultiPoint/MultiPoint-MultiPoint.geojson new file mode 100644 index 00000000..85a8e2cd --- /dev/null +++ b/test/examples/booleans/disjoint/test/false/MultiPoint/MultiPoint/MultiPoint-MultiPoint.geojson @@ -0,0 +1,27 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPoint", + "coordinates": [ + [0, 0], + [12, 12] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPoint", + "coordinates": [ + [1, 1], + [12, 12] + ] + } + } + ] +} diff --git a/test/examples/booleans/disjoint/test/false/MultiPoint/Polygon/MultiPoint-Polygon.geojson b/test/examples/booleans/disjoint/test/false/MultiPoint/Polygon/MultiPoint-Polygon.geojson new file mode 100644 index 00000000..da402f37 --- /dev/null +++ b/test/examples/booleans/disjoint/test/false/MultiPoint/Polygon/MultiPoint-Polygon.geojson @@ -0,0 +1,32 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPoint", + "coordinates": [ + [-1, 2], + [-2, -2] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [-1, 2], + [3, 2], + [3, 3], + [-1, 3], + [-1, 2] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/disjoint/test/false/MultiPolygon/Polygon/MultiPolygon-Polygon.geojson b/test/examples/booleans/disjoint/test/false/MultiPolygon/Polygon/MultiPolygon-Polygon.geojson new file mode 100644 index 00000000..706074d3 --- /dev/null +++ b/test/examples/booleans/disjoint/test/false/MultiPolygon/Polygon/MultiPolygon-Polygon.geojson @@ -0,0 +1,52 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": { + "fill": "#ff0000" + }, + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + [ + [ + [122.6953125, -19.186677697957833], + [128.759765625, -19.186677697957833], + [128.759765625, -15.28418511407642], + [122.6953125, -15.28418511407642], + [122.6953125, -19.186677697957833] + ] + ], + [ + [ + [123.74999999999999, -25.918526162075153], + [130.25390625, -25.918526162075153], + [130.25390625, -20.715015145512087], + [123.74999999999999, -20.715015145512087], + [123.74999999999999, -25.918526162075153] + ] + ] + ] + } + }, + { + "type": "Feature", + "properties": { + "fill": "#0000ff" + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [119.20166015624999, -22.776181505086495], + [125.09033203124999, -22.776181505086495], + [125.09033203124999, -18.417078658661257], + [119.20166015624999, -18.417078658661257], + [119.20166015624999, -22.776181505086495] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/disjoint/test/false/Point/LineString/Point-LineString-1.geojson b/test/examples/booleans/disjoint/test/false/Point/LineString/Point-LineString-1.geojson new file mode 100644 index 00000000..b84728a8 --- /dev/null +++ b/test/examples/booleans/disjoint/test/false/Point/LineString/Point-LineString-1.geojson @@ -0,0 +1,26 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [1, 1] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [1, 1], + [1, 2], + [1, 3], + [1, 4] + ] + } + } + ] +} diff --git a/test/examples/booleans/disjoint/test/false/Point/LineString/Point-LineString-2.geojson b/test/examples/booleans/disjoint/test/false/Point/LineString/Point-LineString-2.geojson new file mode 100644 index 00000000..a937db0c --- /dev/null +++ b/test/examples/booleans/disjoint/test/false/Point/LineString/Point-LineString-2.geojson @@ -0,0 +1,26 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [1, 1.5] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [1, 1], + [1, 2], + [1, 3], + [1, 4] + ] + } + } + ] +} diff --git a/test/examples/booleans/disjoint/test/false/Point/LineString/Point-LineString-3.geojson b/test/examples/booleans/disjoint/test/false/Point/LineString/Point-LineString-3.geojson new file mode 100644 index 00000000..46d35691 --- /dev/null +++ b/test/examples/booleans/disjoint/test/false/Point/LineString/Point-LineString-3.geojson @@ -0,0 +1,26 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [2.5, 1] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [1, 1], + [2, 1], + [3, 1], + [4, 1] + ] + } + } + ] +} diff --git a/test/examples/booleans/disjoint/test/false/Point/LineString/Point-LineString-4.geojson b/test/examples/booleans/disjoint/test/false/Point/LineString/Point-LineString-4.geojson new file mode 100644 index 00000000..cf348f68 --- /dev/null +++ b/test/examples/booleans/disjoint/test/false/Point/LineString/Point-LineString-4.geojson @@ -0,0 +1,26 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [2.5, 2.5] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [1, 1], + [2, 2], + [3, 3], + [4, 4] + ] + } + } + ] +} diff --git a/test/examples/booleans/disjoint/test/false/Point/MultiPoint/Point-MultiPoint.geojson b/test/examples/booleans/disjoint/test/false/Point/MultiPoint/Point-MultiPoint.geojson new file mode 100644 index 00000000..f958a470 --- /dev/null +++ b/test/examples/booleans/disjoint/test/false/Point/MultiPoint/Point-MultiPoint.geojson @@ -0,0 +1,24 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [1, 1] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPoint", + "coordinates": [ + [1, 1], + [12, 12] + ] + } + } + ] +} diff --git a/test/examples/booleans/disjoint/test/false/Point/Point/Point-Point.geojson b/test/examples/booleans/disjoint/test/false/Point/Point/Point-Point.geojson new file mode 100644 index 00000000..15b60d6f --- /dev/null +++ b/test/examples/booleans/disjoint/test/false/Point/Point/Point-Point.geojson @@ -0,0 +1,21 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [0, 0] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [0, 0] + } + } + ] +} diff --git a/test/examples/booleans/disjoint/test/false/Point/Polygon/Point-Polygon-1.geojson b/test/examples/booleans/disjoint/test/false/Point/Polygon/Point-Polygon-1.geojson new file mode 100644 index 00000000..5ef704e8 --- /dev/null +++ b/test/examples/booleans/disjoint/test/false/Point/Polygon/Point-Polygon-1.geojson @@ -0,0 +1,29 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [1, 2.5] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [-1, 2], + [3, 2], + [3, 3], + [-1, 3], + [-1, 2] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/disjoint/test/false/Point/Polygon/Point-Polygon-2.geojson b/test/examples/booleans/disjoint/test/false/Point/Polygon/Point-Polygon-2.geojson new file mode 100644 index 00000000..b3a139a5 --- /dev/null +++ b/test/examples/booleans/disjoint/test/false/Point/Polygon/Point-Polygon-2.geojson @@ -0,0 +1,29 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [-1, 2] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [-1, 2], + [3, 2], + [3, 3], + [-1, 3], + [-1, 2] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/disjoint/test/false/Polygon/LineString/Polygon-Containing-Linestring.geojson b/test/examples/booleans/disjoint/test/false/Polygon/LineString/Polygon-Containing-Linestring.geojson new file mode 100644 index 00000000..a840dc09 --- /dev/null +++ b/test/examples/booleans/disjoint/test/false/Polygon/LineString/Polygon-Containing-Linestring.geojson @@ -0,0 +1,32 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [-1, 2], + [3, 2], + [3, 3], + [-1, 3], + [-1, 2] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [1, 2.5], + [2, 2.5] + ] + } + } + ] +} diff --git a/test/examples/booleans/disjoint/test/false/Polygon/LineString/Polygon-LineString.geojson b/test/examples/booleans/disjoint/test/false/Polygon/LineString/Polygon-LineString.geojson new file mode 100644 index 00000000..83323524 --- /dev/null +++ b/test/examples/booleans/disjoint/test/false/Polygon/LineString/Polygon-LineString.geojson @@ -0,0 +1,34 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [-1, 2], + [3, 2], + [3, 3], + [-1, 3], + [-1, 2] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [0, 2], + [12, 2], + [12, 3], + [12, 4] + ] + } + } + ] +} diff --git a/test/examples/booleans/disjoint/test/false/Polygon/MultiPolygon/Polygon-MultiPolygon.geojson b/test/examples/booleans/disjoint/test/false/Polygon/MultiPolygon/Polygon-MultiPolygon.geojson new file mode 100644 index 00000000..59b2a579 --- /dev/null +++ b/test/examples/booleans/disjoint/test/false/Polygon/MultiPolygon/Polygon-MultiPolygon.geojson @@ -0,0 +1,52 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": { + "fill": "#0000ff" + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [119.20166015624999, -22.776181505086495], + [125.09033203124999, -22.776181505086495], + [125.09033203124999, -18.417078658661257], + [119.20166015624999, -18.417078658661257], + [119.20166015624999, -22.776181505086495] + ] + ] + } + }, + { + "type": "Feature", + "properties": { + "fill": "#ff0000" + }, + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + [ + [ + [122.6953125, -19.186677697957833], + [128.759765625, -19.186677697957833], + [128.759765625, -15.28418511407642], + [122.6953125, -15.28418511407642], + [122.6953125, -19.186677697957833] + ] + ], + [ + [ + [123.74999999999999, -25.918526162075153], + [130.25390625, -25.918526162075153], + [130.25390625, -20.715015145512087], + [123.74999999999999, -20.715015145512087], + [123.74999999999999, -25.918526162075153] + ] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/disjoint/test/false/Polygon/Point/Polygon-Point.geojson b/test/examples/booleans/disjoint/test/false/Polygon/Point/Polygon-Point.geojson new file mode 100644 index 00000000..c2131b4a --- /dev/null +++ b/test/examples/booleans/disjoint/test/false/Polygon/Point/Polygon-Point.geojson @@ -0,0 +1,29 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [-1, 2], + [3, 2], + [3, 3], + [-1, 3], + [-1, 2] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [1, 2.5] + } + } + ] +} diff --git a/test/examples/booleans/disjoint/test/false/Polygon/Polygon/Large-Inside-Small.geojson b/test/examples/booleans/disjoint/test/false/Polygon/Polygon/Large-Inside-Small.geojson new file mode 100644 index 00000000..9a52b0dd --- /dev/null +++ b/test/examples/booleans/disjoint/test/false/Polygon/Polygon/Large-Inside-Small.geojson @@ -0,0 +1,39 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [19.6875, 34.016241889667015], + [14.765625, 26.745610382199022], + [19.6875, 23.563987128451217], + [23.203125, 26.43122806450644], + [22.148437499999996, 30.44867367928756], + [19.6875, 34.016241889667015] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [18.984375, 40.44694705960048], + [7.03125, 25.48295117535531], + [19.335937499999996, 18.979025953255267], + [31.640625, 24.206889622398023], + [24.960937499999996, 34.88593094075317], + [18.984375, 40.44694705960048] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/disjoint/test/false/Polygon/Polygon/Polygon-Polygon.geojson b/test/examples/booleans/disjoint/test/false/Polygon/Polygon/Polygon-Polygon.geojson new file mode 100644 index 00000000..70b69b88 --- /dev/null +++ b/test/examples/booleans/disjoint/test/false/Polygon/Polygon/Polygon-Polygon.geojson @@ -0,0 +1,37 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [-1, 2], + [-13, -12], + [-13, -13], + [-11, -13], + [-1, 2] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [-1, 2], + [3, 2], + [3, 3], + [-1, 3], + [-1, 2] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/disjoint/test/false/Polygon/Polygon/Small-Inside-Large.geojson b/test/examples/booleans/disjoint/test/false/Polygon/Polygon/Small-Inside-Large.geojson new file mode 100644 index 00000000..15e635f5 --- /dev/null +++ b/test/examples/booleans/disjoint/test/false/Polygon/Polygon/Small-Inside-Large.geojson @@ -0,0 +1,39 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [18.984375, 40.44694705960048], + [7.03125, 25.48295117535531], + [19.335937499999996, 18.979025953255267], + [31.640625, 24.206889622398023], + [24.960937499999996, 34.88593094075317], + [18.984375, 40.44694705960048] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [19.6875, 34.016241889667015], + [14.765625, 26.745610382199022], + [19.6875, 23.563987128451217], + [23.203125, 26.43122806450644], + [22.148437499999996, 30.44867367928756], + [19.6875, 34.016241889667015] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/disjoint/test/false/Polygon/Polygon/issue-1216.geojson b/test/examples/booleans/disjoint/test/false/Polygon/Polygon/issue-1216.geojson new file mode 100644 index 00000000..41157c99 --- /dev/null +++ b/test/examples/booleans/disjoint/test/false/Polygon/Polygon/issue-1216.geojson @@ -0,0 +1,49 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [6.638240782825051, 46.513552354874435], + [6.638240782825051, 46.52452567471025], + [6.632039186485088, 46.52452567471025], + [6.632039186485088, 46.513552354874435], + [6.638240782825051, 46.513552354874435] + ] + ] + }, + "bbox": [ + 6.632039186485088, + 46.513552354874435, + 6.638240782825051, + 46.52452567471025 + ] + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [6.645459572232596, 46.51709747623775], + [6.645459572232596, 46.52102619404951], + [6.626132904233913, 46.52102619404951], + [6.626132904233913, 46.51709747623775], + [6.645459572232596, 46.51709747623775] + ] + ] + }, + "bbox": [ + 6.626132904233913, + 46.51709747623775, + 6.645459572232596, + 46.52102619404951 + ] + } + ] +} diff --git a/test/examples/booleans/disjoint/test/true/LineString/LineString/LineString-LineString.geojson b/test/examples/booleans/disjoint/test/true/LineString/LineString/LineString-LineString.geojson new file mode 100644 index 00000000..6c774ab5 --- /dev/null +++ b/test/examples/booleans/disjoint/test/true/LineString/LineString/LineString-LineString.geojson @@ -0,0 +1,31 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [0, 0], + [12, 2], + [12, 3], + [12, 4] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [1, 1], + [1, 2], + [1, 3], + [1, 4] + ] + } + } + ] +} diff --git a/test/examples/booleans/disjoint/test/true/LineString/Point/LineString-Point.geojson b/test/examples/booleans/disjoint/test/true/LineString/Point/LineString-Point.geojson new file mode 100644 index 00000000..e327ba98 --- /dev/null +++ b/test/examples/booleans/disjoint/test/true/LineString/Point/LineString-Point.geojson @@ -0,0 +1,26 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [1, 1], + [1, 2], + [1, 3], + [1, 4] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [0, 0] + } + } + ] +} diff --git a/test/examples/booleans/disjoint/test/true/LineString/Polygon/LineString-Polygon.geojson b/test/examples/booleans/disjoint/test/true/LineString/Polygon/LineString-Polygon.geojson new file mode 100644 index 00000000..d34e7dce --- /dev/null +++ b/test/examples/booleans/disjoint/test/true/LineString/Polygon/LineString-Polygon.geojson @@ -0,0 +1,34 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [0, 0], + [12, 2], + [12, 3], + [12, 4] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [-1, 2], + [3, 2], + [3, 3], + [-1, 3], + [-1, 2] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/disjoint/test/true/MultiPoint/LineString/MultiPoint-LineString.geojson b/test/examples/booleans/disjoint/test/true/MultiPoint/LineString/MultiPoint-LineString.geojson new file mode 100644 index 00000000..77b1b718 --- /dev/null +++ b/test/examples/booleans/disjoint/test/true/MultiPoint/LineString/MultiPoint-LineString.geojson @@ -0,0 +1,29 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPoint", + "coordinates": [ + [2, 2], + [0, 0] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [1, 1], + [1, 2], + [1, 3], + [1, 4] + ] + } + } + ] +} diff --git a/test/examples/booleans/disjoint/test/true/MultiPoint/MultiPoint/MultiPoint-MultiPoint.geojson b/test/examples/booleans/disjoint/test/true/MultiPoint/MultiPoint/MultiPoint-MultiPoint.geojson new file mode 100644 index 00000000..7e3143af --- /dev/null +++ b/test/examples/booleans/disjoint/test/true/MultiPoint/MultiPoint/MultiPoint-MultiPoint.geojson @@ -0,0 +1,27 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPoint", + "coordinates": [ + [0, 0], + [13, 13] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPoint", + "coordinates": [ + [1, 1], + [12, 12] + ] + } + } + ] +} diff --git a/test/examples/booleans/disjoint/test/true/MultiPoint/Point/MultiPoint-Point.geojson b/test/examples/booleans/disjoint/test/true/MultiPoint/Point/MultiPoint-Point.geojson new file mode 100644 index 00000000..eb6182a3 --- /dev/null +++ b/test/examples/booleans/disjoint/test/true/MultiPoint/Point/MultiPoint-Point.geojson @@ -0,0 +1,24 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPoint", + "coordinates": [ + [1, 1], + [12, 12] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [0, 0] + } + } + ] +} diff --git a/test/examples/booleans/disjoint/test/true/MultiPoint/Polygon/MultiPoint-Polygon.geojson b/test/examples/booleans/disjoint/test/true/MultiPoint/Polygon/MultiPoint-Polygon.geojson new file mode 100644 index 00000000..469de623 --- /dev/null +++ b/test/examples/booleans/disjoint/test/true/MultiPoint/Polygon/MultiPoint-Polygon.geojson @@ -0,0 +1,32 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPoint", + "coordinates": [ + [-3, -3], + [-2, -2] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [-1, 2], + [3, 2], + [3, 3], + [-1, 3], + [-1, 2] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/disjoint/test/true/MultiPolygon/Polygon/MultiPolygon-Polygon.geojson b/test/examples/booleans/disjoint/test/true/MultiPolygon/Polygon/MultiPolygon-Polygon.geojson new file mode 100644 index 00000000..3b2ea41f --- /dev/null +++ b/test/examples/booleans/disjoint/test/true/MultiPolygon/Polygon/MultiPolygon-Polygon.geojson @@ -0,0 +1,52 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": { + "fill": "#ff0000" + }, + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + [ + [ + [122.6953125, -19.186677697957833], + [128.759765625, -19.186677697957833], + [128.759765625, -15.28418511407642], + [122.6953125, -15.28418511407642], + [122.6953125, -19.186677697957833] + ] + ], + [ + [ + [123.74999999999999, -25.918526162075153], + [130.25390625, -25.918526162075153], + [130.25390625, -20.715015145512087], + [123.74999999999999, -20.715015145512087], + [123.74999999999999, -25.918526162075153] + ] + ] + ] + } + }, + { + "type": "Feature", + "properties": { + "fill": "#0000ff" + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [116.98242187499999, -24.647017162630352], + [122.87109375, -24.647017162630352], + [122.87109375, -20.34462694382967], + [116.98242187499999, -20.34462694382967], + [116.98242187499999, -24.647017162630352] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/disjoint/test/true/Point/LineString/Point-LineString.geojson b/test/examples/booleans/disjoint/test/true/Point/LineString/Point-LineString.geojson new file mode 100644 index 00000000..be635169 --- /dev/null +++ b/test/examples/booleans/disjoint/test/true/Point/LineString/Point-LineString.geojson @@ -0,0 +1,26 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [0, 0] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [1, 1], + [1, 2], + [1, 3], + [1, 4] + ] + } + } + ] +} diff --git a/test/examples/booleans/disjoint/test/true/Point/MultiPoint/Point-Multipoint.geojson b/test/examples/booleans/disjoint/test/true/Point/MultiPoint/Point-Multipoint.geojson new file mode 100644 index 00000000..542362e8 --- /dev/null +++ b/test/examples/booleans/disjoint/test/true/Point/MultiPoint/Point-Multipoint.geojson @@ -0,0 +1,24 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [0, 0] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPoint", + "coordinates": [ + [1, 1], + [12, 12] + ] + } + } + ] +} diff --git a/test/examples/booleans/disjoint/test/true/Point/Point/Point-Point.geojson b/test/examples/booleans/disjoint/test/true/Point/Point/Point-Point.geojson new file mode 100644 index 00000000..6d022c5e --- /dev/null +++ b/test/examples/booleans/disjoint/test/true/Point/Point/Point-Point.geojson @@ -0,0 +1,21 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [0, 0] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [0, 1] + } + } + ] +} diff --git a/test/examples/booleans/disjoint/test/true/Point/Polygon/Point-Polygon.geojson b/test/examples/booleans/disjoint/test/true/Point/Polygon/Point-Polygon.geojson new file mode 100644 index 00000000..c3d4c6de --- /dev/null +++ b/test/examples/booleans/disjoint/test/true/Point/Polygon/Point-Polygon.geojson @@ -0,0 +1,29 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [1, 1] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [-1, 2], + [3, 2], + [3, 3], + [-1, 3], + [-1, 2] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/disjoint/test/true/Polygon/LineString/Polygon-LineString.geojson b/test/examples/booleans/disjoint/test/true/Polygon/LineString/Polygon-LineString.geojson new file mode 100644 index 00000000..52b4a494 --- /dev/null +++ b/test/examples/booleans/disjoint/test/true/Polygon/LineString/Polygon-LineString.geojson @@ -0,0 +1,34 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [-1, 2], + [3, 2], + [3, 3], + [-1, 3], + [-1, 2] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [0, 0], + [12, 2], + [12, 3], + [12, 4] + ] + } + } + ] +} diff --git a/test/examples/booleans/disjoint/test/true/Polygon/MultiPolygon/Polygon-MultiPolygon.geojson b/test/examples/booleans/disjoint/test/true/Polygon/MultiPolygon/Polygon-MultiPolygon.geojson new file mode 100644 index 00000000..d165d17b --- /dev/null +++ b/test/examples/booleans/disjoint/test/true/Polygon/MultiPolygon/Polygon-MultiPolygon.geojson @@ -0,0 +1,52 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": { + "fill": "#0000ff" + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [116.98242187499999, -24.647017162630352], + [122.87109375, -24.647017162630352], + [122.87109375, -20.34462694382967], + [116.98242187499999, -20.34462694382967], + [116.98242187499999, -24.647017162630352] + ] + ] + } + }, + { + "type": "Feature", + "properties": { + "fill": "#ff0000" + }, + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + [ + [ + [122.6953125, -19.186677697957833], + [128.759765625, -19.186677697957833], + [128.759765625, -15.28418511407642], + [122.6953125, -15.28418511407642], + [122.6953125, -19.186677697957833] + ] + ], + [ + [ + [123.74999999999999, -25.918526162075153], + [130.25390625, -25.918526162075153], + [130.25390625, -20.715015145512087], + [123.74999999999999, -20.715015145512087], + [123.74999999999999, -25.918526162075153] + ] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/disjoint/test/true/Polygon/Point/Polygon-Point.geojson b/test/examples/booleans/disjoint/test/true/Polygon/Point/Polygon-Point.geojson new file mode 100644 index 00000000..557d45be --- /dev/null +++ b/test/examples/booleans/disjoint/test/true/Polygon/Point/Polygon-Point.geojson @@ -0,0 +1,29 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [-1, 2], + [3, 2], + [3, 3], + [-1, 3], + [-1, 2] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [1, 1] + } + } + ] +} diff --git a/test/examples/booleans/disjoint/test/true/Polygon/Polygon/Polygon-Polygon.geojson b/test/examples/booleans/disjoint/test/true/Polygon/Polygon/Polygon-Polygon.geojson new file mode 100644 index 00000000..66d7ab57 --- /dev/null +++ b/test/examples/booleans/disjoint/test/true/Polygon/Polygon/Polygon-Polygon.geojson @@ -0,0 +1,37 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [-11, -12], + [-13, -12], + [-13, -13], + [-11, -13], + [-11, -12] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [-1, 2], + [3, 2], + [3, 3], + [-1, 3], + [-1, 2] + ] + ] + } + } + ] +} From 93a51ca8c5df2d886a60a9eb60091ac7d4a05714 Mon Sep 17 00:00:00 2001 From: armantorkzaban Date: Mon, 4 Jul 2022 15:00:25 +0200 Subject: [PATCH 44/82] equal implement, test, has dependencies --- lib/src/booleans/boolean_equal.dart | 55 -------- lib/src/clean_coords.dart | 1 - test/booleans/equal_test.dart | 132 +++++++++++++++++- test/examples/booleans/.DS_Store | Bin 8196 -> 8196 bytes .../booleans/equal/diagrams/esri-equals.gif | Bin 0 -> 22932 bytes .../equal/test/false/linear-rings.geojson | 31 ++++ .../booleans/equal/test/false/lines.geojson | 31 ++++ .../equal/test/false/multipoints.geojson | 33 +++++ .../booleans/equal/test/false/points.geojson | 21 +++ .../equal/test/false/polygons.geojson | 35 +++++ .../test/false/precision-default.geojson | 21 +++ .../test/false/precision-options.geojson | 24 ++++ .../test/true/different-initials-poly.geojson | 35 +++++ .../equal/test/true/linear-rings.geojson | 31 ++++ .../test/true/lines-extra-vertices.geojson | 28 ++++ .../equal/test/true/lines-reverse.geojson | 29 ++++ .../booleans/equal/test/true/lines.geojson | 31 ++++ .../equal/test/true/multipoints.geojson | 33 +++++ .../booleans/equal/test/true/points.geojson | 21 +++ .../booleans/equal/test/true/polygons.geojson | 35 +++++ .../equal/test/true/precision-default.geojson | 21 +++ .../equal/test/true/precision-options.geojson | 24 ++++ .../equal/test/true/reverse-lines.geojson | 31 ++++ .../equal/test/true/reverse-polygons.geojson | 35 +++++ 24 files changed, 681 insertions(+), 57 deletions(-) create mode 100644 test/examples/booleans/equal/diagrams/esri-equals.gif create mode 100644 test/examples/booleans/equal/test/false/linear-rings.geojson create mode 100644 test/examples/booleans/equal/test/false/lines.geojson create mode 100644 test/examples/booleans/equal/test/false/multipoints.geojson create mode 100644 test/examples/booleans/equal/test/false/points.geojson create mode 100644 test/examples/booleans/equal/test/false/polygons.geojson create mode 100644 test/examples/booleans/equal/test/false/precision-default.geojson create mode 100644 test/examples/booleans/equal/test/false/precision-options.geojson create mode 100644 test/examples/booleans/equal/test/true/different-initials-poly.geojson create mode 100644 test/examples/booleans/equal/test/true/linear-rings.geojson create mode 100644 test/examples/booleans/equal/test/true/lines-extra-vertices.geojson create mode 100644 test/examples/booleans/equal/test/true/lines-reverse.geojson create mode 100644 test/examples/booleans/equal/test/true/lines.geojson create mode 100644 test/examples/booleans/equal/test/true/multipoints.geojson create mode 100644 test/examples/booleans/equal/test/true/points.geojson create mode 100644 test/examples/booleans/equal/test/true/polygons.geojson create mode 100644 test/examples/booleans/equal/test/true/precision-default.geojson create mode 100644 test/examples/booleans/equal/test/true/precision-options.geojson create mode 100644 test/examples/booleans/equal/test/true/reverse-lines.geojson create mode 100644 test/examples/booleans/equal/test/true/reverse-polygons.geojson diff --git a/lib/src/booleans/boolean_equal.dart b/lib/src/booleans/boolean_equal.dart index 7e9db0a1..a1894b88 100644 --- a/lib/src/booleans/boolean_equal.dart +++ b/lib/src/booleans/boolean_equal.dart @@ -30,58 +30,3 @@ bool booleanEqual(GeoJSONObject feature1, GeoJSONObject feature2, var equality = Equality(precision: precision); return equality.compare(cleanCoords(feature1), cleanCoords(feature2)); } - - - -import { Feature, Geometry } from "geojson"; -import GeojsonEquality from "geojson-equality"; -import cleanCoords from "@turf/clean-coords"; -import { getGeom } from "@turf/invariant"; - -/** - * Determine whether two geometries of the same type have identical X,Y coordinate values. - * See http://edndoc.esri.com/arcsde/9.0/general_topics/understand_spatial_relations.htm - * - * @name booleanEqual - * @param {Geometry|Feature} feature1 GeoJSON input - * @param {Geometry|Feature} feature2 GeoJSON input - * @param {Object} [options={}] Optional parameters - * @param {number} [options.precision=6] decimal precision to use when comparing coordinates - * @returns {boolean} true if the objects are equal, false otherwise - * @example - * var pt1 = turf.point([0, 0]); - * var pt2 = turf.point([0, 0]); - * var pt3 = turf.point([1, 1]); - * - * turf.booleanEqual(pt1, pt2); - * //= true - * turf.booleanEqual(pt2, pt3); - * //= false - */ - booleanEqual( - feature1: Feature | Geometry, - feature2: Feature | Geometry, - options: { - precision?: number; - } = {} -): boolean { - let precision = options.precision; - - precision = - precision === undefined || precision === null || isNaN(precision) - ? 6 - : precision; - - if (typeof precision !== "number" || !(precision >= 0)) { - throw new Error("precision must be a positive number"); - } - - const type1 = getGeom(feature1).type; - const type2 = getGeom(feature2).type; - if (type1 !== type2) return false; - - const equality = new GeojsonEquality({ precision: precision }); - return equality.compare(cleanCoords(feature1), cleanCoords(feature2)); -} - -export default booleanEqual; */ \ No newline at end of file diff --git a/lib/src/clean_coords.dart b/lib/src/clean_coords.dart index 22549ef4..f9269cad 100644 --- a/lib/src/clean_coords.dart +++ b/lib/src/clean_coords.dart @@ -19,7 +19,6 @@ import 'invariant.dart'; /// //= [[0, 0], [0, 10]] /// turf.cleanCoords(multiPoint).geometry.coordinates; /// //= [[0, 0], [2, 2]] - cleanCoords( GeoJSONObject geojson, { diff --git a/test/booleans/equal_test.dart b/test/booleans/equal_test.dart index 1c8a0e79..707dbfc9 100644 --- a/test/booleans/equal_test.dart +++ b/test/booleans/equal_test.dart @@ -1 +1,131 @@ -; \ No newline at end of file +import 'dart:convert'; +import 'dart:io'; + +import 'package:test/test.dart'; +import 'package:turf/helpers.dart'; +import 'package:turf/src/booleans/boolean_equal.dart'; + +main() { + group('boolean_crosses', () { + var inDir = Directory('./test/examples/booleans/equal/true'); + for (var file in inDir.listSync(recursive: true)) { + if (file is File && file.path.endsWith('.geojson')) { + test(file.path, () { + // True Fixtures + var inSource = file.readAsStringSync(); + var inGeom = GeoJSONObject.fromJson(jsonDecode(inSource)); + + var feature1 = (inGeom as FeatureCollection).features[0]; + var feature2 = inGeom.features[1]; + Map json = jsonDecode(inSource); + var options = json['properties']; + var result = + booleanEqual(feature1, feature2, precision: options['precision']); + + expect(result, true); + }); + // False Fixtures + var inDir = Directory('./test/examples/booleans/equal/false'); + for (var file in inDir.listSync(recursive: true)) { + if (file is File && file.path.endsWith('.geojson')) { + test(file.path, () { + // True Fixtures + var inSource = file.readAsStringSync(); + var inGeom = GeoJSONObject.fromJson(jsonDecode(inSource)); + + var feature1 = (inGeom as FeatureCollection).features[0]; + var feature2 = inGeom.features[1]; + + Map json = jsonDecode(inSource); + var options = json['properties']; + var result = booleanEqual(feature1, feature2, + precision: options['precision']); + + expect(result, true); + }); + + var pt = Point(coordinates: Position.of([9, 50])); + var line1 = Feature( + geometry: LineString(coordinates: [ + Position.of([7, 50]), + Position.of([8, 50]), + Position.of([9, 50]), + ]), + ); + var line2 = Feature( + geometry: LineString(coordinates: [ + Position.of([7, 50]), + Position.of([8, 50]), + Position.of([9, 50]), + ]), + ); + var poly1 = Feature( + geometry: Polygon(coordinates: [ + [ + Position.of([8.5, 50]), + Position.of([9.5, 50]), + Position.of([9.5, 49]), + Position.of([8.5, 49]), + Position.of([8.5, 50]), + ], + ]), + ); + var poly2 = Feature( + geometry: Polygon(coordinates: [ + [ + Position.of([8.5, 50]), + Position.of([9.5, 50]), + Position.of([9.5, 49]), + Position.of([8.5, 49]), + Position.of([8.5, 50]), + ], + ]), + ); + var poly3 = Feature( + geometry: Polygon(coordinates: [ + [ + Position.of([10, 50]), + Position.of([10.5, 50]), + Position.of([10.5, 49]), + Position.of([10, 49]), + Position.of([10, 50]), + ], + ]), + ); + + test("turf-boolean-equal -- geometries", () { + // "[true] LineString geometry" + expect(booleanEqual(line1.geometry!, line2.geometry!), true); + + // "[true] Polygon geometry" + expect(booleanEqual(poly1.geometry!, poly2.geometry!), true); + + // "[false] Polygon geometry" + expect(booleanEqual(poly1.geometry!, poly3.geometry!), false); + + // "[false] different types" + expect(booleanEqual(pt, line1), false); + }); + + test("turf-boolean-equal -- throws", () { + //t.throws(() => equal(null, line1), /feature1 is required/, 'missing feature1'); + //t.throws(() => equal(line1, null), /feature2 is required/, 'missing feature2'); + + // "precision must be a number" + + expect( + () => booleanEqual(line1.geometry!, line2.geometry!, + precision: 1), + throwsA(isA())); + //"precision must be positive" + expect( + () => booleanEqual(line1.geometry!, line2.geometry!, + precision: -1), + throwsA(isA())); + }); + } + } + } + } + }); +} diff --git a/test/examples/booleans/.DS_Store b/test/examples/booleans/.DS_Store index 03ba999d6278055db46349dc83a4f6ab4abda0a2..f22ab7845a312896a98a008477a7717105e622ec 100644 GIT binary patch delta 120 zcmZp1XmOa}&nU7nU^hRb$YvgayG*9645H+`AG~63<5yx2*mUL zg8`7mz<{K3@*ROjb~6(l1w#Xa$z4MB+(>epZwZOBY-X4E#xi-nkk)2Fk-JO)1fn7s delta 42 ycmZp1XmOa}&nUPtU^hRb;AS3yyG)z^3v;k+Y!GAI%r5bbWwWr@7sibZ!i)ehjSc_+ diff --git a/test/examples/booleans/equal/diagrams/esri-equals.gif b/test/examples/booleans/equal/diagrams/esri-equals.gif new file mode 100644 index 0000000000000000000000000000000000000000..79fa2f816ed0bc442a50f6a106056ffd6b10cb24 GIT binary patch literal 22932 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 literal 0 HcmV?d00001 diff --git a/test/examples/booleans/equal/test/false/linear-rings.geojson b/test/examples/booleans/equal/test/false/linear-rings.geojson new file mode 100644 index 00000000..a0809033 --- /dev/null +++ b/test/examples/booleans/equal/test/false/linear-rings.geojson @@ -0,0 +1,31 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [-53.674866943359375, 28.30135788537988], + [-53.337249755859375, 28.47412369059679], + [-53.524017333984375, 28.17492820114568], + [-53.674866943359375, 28.30135788537988] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [-55.674866943359375, 28.30135788537988], + [-55.337249755859375, 28.47412369059679], + [-55.524017333984375, 28.17492820114568], + [-55.674866943359375, 28.30135788537988] + ] + } + } + ] +} diff --git a/test/examples/booleans/equal/test/false/lines.geojson b/test/examples/booleans/equal/test/false/lines.geojson new file mode 100644 index 00000000..1ba5e7fb --- /dev/null +++ b/test/examples/booleans/equal/test/false/lines.geojson @@ -0,0 +1,31 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [0, 0], + [0, 5], + [5, 5], + [5, 0] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [1, 0], + [1, 5], + [6, 5], + [6, 0] + ] + } + } + ] +} diff --git a/test/examples/booleans/equal/test/false/multipoints.geojson b/test/examples/booleans/equal/test/false/multipoints.geojson new file mode 100644 index 00000000..a3a50a8f --- /dev/null +++ b/test/examples/booleans/equal/test/false/multipoints.geojson @@ -0,0 +1,33 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPoint", + "coordinates": [ + [-35.5638671875, 27.254629577800063], + [-35.6462646484375, 26.86328062676624], + [-35, 26], + [-35.1001953125, 26.12091815959972], + [-34.8969482421875, 26.455820238459893] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPoint", + "coordinates": [ + [-35.5638671875, 27.254629577800063], + [-35.6462646484375, 26.86328062676624], + [-35.4924560546875, 26.504988828743404], + [-35.1001953125, 26.12091815959972], + [-34.8969482421875, 26.455820238459893] + ] + } + } + ] +} diff --git a/test/examples/booleans/equal/test/false/points.geojson b/test/examples/booleans/equal/test/false/points.geojson new file mode 100644 index 00000000..9bb831e0 --- /dev/null +++ b/test/examples/booleans/equal/test/false/points.geojson @@ -0,0 +1,21 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [0, 0] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [1, 0] + } + } + ] +} diff --git a/test/examples/booleans/equal/test/false/polygons.geojson b/test/examples/booleans/equal/test/false/polygons.geojson new file mode 100644 index 00000000..55e49e19 --- /dev/null +++ b/test/examples/booleans/equal/test/false/polygons.geojson @@ -0,0 +1,35 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [-53, 28.287451910503744], + [-53.33038330078125, 28.29228897739706], + [-53.34136962890625, 28.430052892335723], + [-53, 28.287451910503744] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [-53.57208251953125, 28.287451910503744], + [-53.33038330078125, 28.29228897739706], + [-53.34136962890625, 28.430052892335723], + [-53.57208251953125, 28.287451910503744] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/equal/test/false/precision-default.geojson b/test/examples/booleans/equal/test/false/precision-default.geojson new file mode 100644 index 00000000..7f793b80 --- /dev/null +++ b/test/examples/booleans/equal/test/false/precision-default.geojson @@ -0,0 +1,21 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [0.123456, 0] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [0.123451, 0] + } + } + ] +} diff --git a/test/examples/booleans/equal/test/false/precision-options.geojson b/test/examples/booleans/equal/test/false/precision-options.geojson new file mode 100644 index 00000000..fcb8ee25 --- /dev/null +++ b/test/examples/booleans/equal/test/false/precision-options.geojson @@ -0,0 +1,24 @@ +{ + "type": "FeatureCollection", + "properties": { + "precision": 17 + }, + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [0.12345678901234561, 0] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [0.12345678901234564, 0] + } + } + ] +} diff --git a/test/examples/booleans/equal/test/true/different-initials-poly.geojson b/test/examples/booleans/equal/test/true/different-initials-poly.geojson new file mode 100644 index 00000000..fcd1cdb4 --- /dev/null +++ b/test/examples/booleans/equal/test/true/different-initials-poly.geojson @@ -0,0 +1,35 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [1, 1], + [1, 0], + [0, 0], + [1, 1] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [0, 0], + [1, 1], + [1, 0], + [0, 0] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/equal/test/true/linear-rings.geojson b/test/examples/booleans/equal/test/true/linear-rings.geojson new file mode 100644 index 00000000..67dfae71 --- /dev/null +++ b/test/examples/booleans/equal/test/true/linear-rings.geojson @@ -0,0 +1,31 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [-53.674866943359375, 28.30135788537988], + [-53.337249755859375, 28.47412369059679], + [-53.524017333984375, 28.17492820114568], + [-53.674866943359375, 28.30135788537988] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [-53.674866943359375, 28.30135788537988], + [-53.337249755859375, 28.47412369059679], + [-53.524017333984375, 28.17492820114568], + [-53.674866943359375, 28.30135788537988] + ] + } + } + ] +} diff --git a/test/examples/booleans/equal/test/true/lines-extra-vertices.geojson b/test/examples/booleans/equal/test/true/lines-extra-vertices.geojson new file mode 100644 index 00000000..51a06197 --- /dev/null +++ b/test/examples/booleans/equal/test/true/lines-extra-vertices.geojson @@ -0,0 +1,28 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [0, 0], + [2, 2] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [0, 0], + [1, 1], + [2, 2] + ] + } + } + ] +} diff --git a/test/examples/booleans/equal/test/true/lines-reverse.geojson b/test/examples/booleans/equal/test/true/lines-reverse.geojson new file mode 100644 index 00000000..9aa67775 --- /dev/null +++ b/test/examples/booleans/equal/test/true/lines-reverse.geojson @@ -0,0 +1,29 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [2, 2], + [1, 1], + [0, 0] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [0, 0], + [1, 1], + [2, 2] + ] + } + } + ] +} diff --git a/test/examples/booleans/equal/test/true/lines.geojson b/test/examples/booleans/equal/test/true/lines.geojson new file mode 100644 index 00000000..8bd4188d --- /dev/null +++ b/test/examples/booleans/equal/test/true/lines.geojson @@ -0,0 +1,31 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [0, 0], + [0, 5], + [5, 5], + [5, 0] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [0, 0], + [0, 5], + [5, 5], + [5, 0] + ] + } + } + ] +} diff --git a/test/examples/booleans/equal/test/true/multipoints.geojson b/test/examples/booleans/equal/test/true/multipoints.geojson new file mode 100644 index 00000000..22aa40ad --- /dev/null +++ b/test/examples/booleans/equal/test/true/multipoints.geojson @@ -0,0 +1,33 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPoint", + "coordinates": [ + [-35.5638671875, 27.254629577800063], + [-35.6462646484375, 26.86328062676624], + [-35.4924560546875, 26.504988828743404], + [-35.1001953125, 26.12091815959972], + [-34.8969482421875, 26.455820238459893] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPoint", + "coordinates": [ + [-35.5638671875, 27.254629577800063], + [-35.6462646484375, 26.86328062676624], + [-35.4924560546875, 26.504988828743404], + [-35.1001953125, 26.12091815959972], + [-34.8969482421875, 26.455820238459893] + ] + } + } + ] +} diff --git a/test/examples/booleans/equal/test/true/points.geojson b/test/examples/booleans/equal/test/true/points.geojson new file mode 100644 index 00000000..15b60d6f --- /dev/null +++ b/test/examples/booleans/equal/test/true/points.geojson @@ -0,0 +1,21 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [0, 0] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [0, 0] + } + } + ] +} diff --git a/test/examples/booleans/equal/test/true/polygons.geojson b/test/examples/booleans/equal/test/true/polygons.geojson new file mode 100644 index 00000000..b6077107 --- /dev/null +++ b/test/examples/booleans/equal/test/true/polygons.geojson @@ -0,0 +1,35 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [-53.57208251953125, 28.287451910503744], + [-53.33038330078125, 28.29228897739706], + [-53.34136962890625, 28.430052892335723], + [-53.57208251953125, 28.287451910503744] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [-53.57208251953125, 28.287451910503744], + [-53.33038330078125, 28.29228897739706], + [-53.34136962890625, 28.430052892335723], + [-53.57208251953125, 28.287451910503744] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/equal/test/true/precision-default.geojson b/test/examples/booleans/equal/test/true/precision-default.geojson new file mode 100644 index 00000000..cca64ff4 --- /dev/null +++ b/test/examples/booleans/equal/test/true/precision-default.geojson @@ -0,0 +1,21 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [0.1234567, 0] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [0.1234569, 0] + } + } + ] +} diff --git a/test/examples/booleans/equal/test/true/precision-options.geojson b/test/examples/booleans/equal/test/true/precision-options.geojson new file mode 100644 index 00000000..5e5ab8dd --- /dev/null +++ b/test/examples/booleans/equal/test/true/precision-options.geojson @@ -0,0 +1,24 @@ +{ + "type": "FeatureCollection", + "properties": { + "precision": 16 + }, + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [0.12345678901234567, 0] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [0.12345678901234569, 0] + } + } + ] +} diff --git a/test/examples/booleans/equal/test/true/reverse-lines.geojson b/test/examples/booleans/equal/test/true/reverse-lines.geojson new file mode 100644 index 00000000..4c6e1810 --- /dev/null +++ b/test/examples/booleans/equal/test/true/reverse-lines.geojson @@ -0,0 +1,31 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [0, 0], + [0, 5], + [5, 5], + [5, 0] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [5, 0], + [5, 5], + [0, 5], + [0, 0] + ] + } + } + ] +} diff --git a/test/examples/booleans/equal/test/true/reverse-polygons.geojson b/test/examples/booleans/equal/test/true/reverse-polygons.geojson new file mode 100644 index 00000000..6f8b9a9d --- /dev/null +++ b/test/examples/booleans/equal/test/true/reverse-polygons.geojson @@ -0,0 +1,35 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [-53.57, 28.28], + [-53.33, 28.29], + [-53.34, 28.43], + [-53.57, 28.28] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [-53.57, 28.28], + [-53.34, 28.43], + [-53.33, 28.29], + [-53.57, 28.28] + ] + ] + } + } + ] +} From e2b8a1fbb71d510ef69e41617d0c8510297eb3bc Mon Sep 17 00:00:00 2001 From: armantorkzaban Date: Mon, 4 Jul 2022 15:06:55 +0200 Subject: [PATCH 45/82] moving on --- test/booleans/intersect_test.dart | 23 +++++++++++++---------- test/booleans/overlap_test.dart | 1 + test/booleans/parallel_test.dart | 1 + test/booleans/touches_test.dart | 1 + test/booleans/valid_test.dart | 1 + test/booleans/within_test.dart | 1 + 6 files changed, 18 insertions(+), 10 deletions(-) diff --git a/test/booleans/intersect_test.dart b/test/booleans/intersect_test.dart index 52e61b31..4540ac40 100644 --- a/test/booleans/intersect_test.dart +++ b/test/booleans/intersect_test.dart @@ -74,17 +74,20 @@ import 'package:turf/src/booleans/boolean_intersect.dart'; ] ])) ]); - test("turf-boolean-intersects", () { - // True Fixtures + test( + "turf-boolean-intersects", + () { + // True Fixtures - var feature1 = featureCollection.features[0]; - var feature2 = featureCollection.features[1]; + var feature1 = featureCollection.features[0]; + var feature2 = featureCollection.features[1]; - expect(booleanIntersects(feature1, feature2), equals(true)); + expect(booleanIntersects(feature1, feature2), equals(true)); - // False Fixtures - var feature3 = featureCollection1.features[0]; - var feature4 = featureCollection1.features[1]; - expect(booleanIntersects(feature3, feature4), equals(false)); - }); + // False Fixtures + var feature3 = featureCollection1.features[0]; + var feature4 = featureCollection1.features[1]; + expect(booleanIntersects(feature3, feature4), equals(false)); + }, + ); } diff --git a/test/booleans/overlap_test.dart b/test/booleans/overlap_test.dart index 8b137891..45518ca5 100644 --- a/test/booleans/overlap_test.dart +++ b/test/booleans/overlap_test.dart @@ -1 +1,2 @@ +/ \ No newline at end of file diff --git a/test/booleans/parallel_test.dart b/test/booleans/parallel_test.dart index 8b137891..45518ca5 100644 --- a/test/booleans/parallel_test.dart +++ b/test/booleans/parallel_test.dart @@ -1 +1,2 @@ +/ \ No newline at end of file diff --git a/test/booleans/touches_test.dart b/test/booleans/touches_test.dart index 8b137891..45518ca5 100644 --- a/test/booleans/touches_test.dart +++ b/test/booleans/touches_test.dart @@ -1 +1,2 @@ +/ \ No newline at end of file diff --git a/test/booleans/valid_test.dart b/test/booleans/valid_test.dart index 8b137891..45518ca5 100644 --- a/test/booleans/valid_test.dart +++ b/test/booleans/valid_test.dart @@ -1 +1,2 @@ +/ \ No newline at end of file diff --git a/test/booleans/within_test.dart b/test/booleans/within_test.dart index 8b137891..45518ca5 100644 --- a/test/booleans/within_test.dart +++ b/test/booleans/within_test.dart @@ -1 +1,2 @@ +/ \ No newline at end of file From 454c10217def9bf535a338de5d4dcde55c63e924 Mon Sep 17 00:00:00 2001 From: armantorkzaban Date: Mon, 4 Jul 2022 16:53:19 +0200 Subject: [PATCH 46/82] clean coords init --- lib/src/clean_coords.dart | 197 ++++++++++++++++---------------------- 1 file changed, 85 insertions(+), 112 deletions(-) diff --git a/lib/src/clean_coords.dart b/lib/src/clean_coords.dart index f9269cad..7f3ce947 100644 --- a/lib/src/clean_coords.dart +++ b/lib/src/clean_coords.dart @@ -1,71 +1,61 @@ - - // To-Do => Improve Typescript GeoJSON handling +import 'package:turf/src/booleans/boolean_overlap.dart'; + import '../helpers.dart'; import 'invariant.dart'; - /// Removes redundant coordinates from any GeoJSON Geometry. -/// @name cleanCoords -/// @param {Geometry|Feature} geojson Feature or Geometry -/// @param {Object} [options={}] Optional parameters -/// @param {boolean} [options.mutate=false] allows GeoJSON input to be mutated -/// @returns {Geometry|Feature} the cleaned input Feature/Geometry -/// @example -/// var line = turf.lineString([[0, 0], [0, 2], [0, 5], [0, 8], [0, 8], [0, 10]]); -/// var multiPoint = turf.multiPoint([[0, 0], [0, 0], [2, 2]]); -/// turf.cleanCoords(line).geometry.coordinates; +/// Takes geojson Feature or Geometry +/// [options.mutate=false] allows GeoJSON input to be mutated +/// Returnsthe cleaned input Feature/Geometry +/// example: +/// ```dart +/// var line = LineString(coordinates:[Position.of([0, 0]), Position.of([0, 2]), Position.of([0, 5]), Position.of([0, 8]), Position.of([0, 8]), Position.of([0, 10])]); +/// var multiPoint = MultiPoint(coordinates:[Position.of([0, 0]), Position.of([0, 0]), Position.of([2, 2])]); +/// cleanCoords(line).geometry.coordinates; /// //= [[0, 0], [0, 10]] -/// turf.cleanCoords(multiPoint).geometry.coordinates; +/// cleanCoords(multiPoint).geometry.coordinates; /// //= [[0, 0], [2, 2]] - cleanCoords( - GeoJSONObject geojson, - { - bool mutate, - } -) { - // // Backwards compatible with v4.0 - // var mutate = typeof options == "object" ? options.mutate : options; - // if (!geojson) throw Exception("geojson is required"); - var type = (geojson.type); - - // Store new "clean" points in this Array +cleanCoords( + GeoJSONObject geojson, { + bool mutate = false, +}) { + // Store new "clean" points in this List var newCoords = []; - switch (type) { - case GeoJSONObjectType.lineString: - newCoords = cleanLine(geojson as LineString, type); - break; - case GeoJSONObjectType.multiLineString: - case GeoJSONObjectType.polygon: - getCoords(geojson).forEach( (line) { - newCoords.add(cleanLine(line, type)); + if (geojson is LineString) { + newCoords = _cleanLine(geojson); + } else if (geojson is MultiLineString || geojson is Polygon) { + getCoords(geojson).forEach( + (geojson) { + newCoords.add(_cleanLine(geojson)); + }, + ); + } else if (geojson is MultiPolygon) { + getCoords(geojson).forEach((polygons) { + var polyPoints = []; + polygons.forEach((List ring) { + polyPoints.add(_cleanLine(ring)); }); - break; - case GeoJSONObjectType.multiPolygon: - getCoords(geojson).forEach( (polygons) { - var polyPoints = []; - polygons.forEach( (List ring) { - polyPoints.add(cleanLine(ring, type)); - }); - newCoords.add(polyPoints); - }); - break; - case GeoJSONObjectType.point: - return geojson; - case GeoJSONObjectType.multiPoint: - var Record existing: = {}; - getCoords(geojson).forEach( (coord: any) { + newCoords.add(polyPoints); + }); + } else if (geojson is Point) { + return geojson; + } else if (geojson is MultiPoint) { + Map existing = {}; + + getCoords(geojson).forEach( + (coord) { var key = coord.join("-"); if (!Object.prototype.hasOwnProperty.call(existing, key)) { newCoords.add(coord); existing[key] = true; } - }); - break; - default: - throw Exception(type + " geometry not supported"); + }, + ); + } else { + throw Exception("$geojson is not supported"); } // Support input mutation @@ -74,80 +64,63 @@ import 'invariant.dart'; geojson.coordinates = newCoords; return geojson; } - return { type: type, coordinates: newCoords }; + return {type: type, coordinates: newCoords}; } else { if (mutate) { geojson.geometry.coordinates = newCoords; return geojson; } - return feature({ type: type, coordinates: newCoords }, geojson.properties, { - bbox: geojson.bbox, - id: geojson.id, - }); + return feature( + {type: type, coordinates: newCoords}, + geojson.properties, + { + bbox: geojson.bbox, + id: geojson.id, + }); } } -/** - * Clean Coords - * - * @private - * @param {Array|LineString} line Line - * @param {string} type Type of geometry - * @returns {Array} Cleaned coordinates - */ - cleanLine(dynamic line, GeoJSONObjectType type) { - var points = getCoords(line); +List _cleanLine(List coords) { + var points = getCoords(coords); // handle "clean" segment - if (points.length == 2 && !equals(points[0], points[1])) return points; + if (points.length == 2 && !equals(points[0], points[1])) { + return points; + } var newPoints = []; - var secondToLast = points.length - 1; - var newPointsLength = newPoints.length; + int secondToLast = points.length - 1; + int newPointsLength = newPoints.length; newPoints.add(points[0]); - for (var i = 1; i < secondToLast; i++) { + for (int i = 1; i < secondToLast; i++) { var prevAddedPoint = newPoints[newPoints.length - 1]; - if ( - points[i][0] == prevAddedPoint[0] && - points[i][1] == prevAddedPoint[1] - ) -{ continue; -} else { + if (points[i] == prevAddedPoint) { + continue; + } else { newPoints.add(points[i]); newPointsLength = newPoints.length; if (newPointsLength > 2) { - if ( - isPointOnLineSegment( - newPoints[newPointsLength - 3], - newPoints[newPointsLength - 1], - newPoints[newPointsLength - 2] - ) - ) -{ newPoints.removeAt(newPoints.length - 2); -} } + if (isPointOnLineSegment(newPoints[newPointsLength - 3], + newPoints[newPointsLength - 1], newPoints[newPointsLength - 2])) { + newPoints.removeAt(newPoints.length - 2); + } + } } } newPoints.add(points[points.length - 1]); newPointsLength = newPoints.length; // (Multi)Polygons must have at least 4 points, but a closed LineString with only 3 points is acceptable - if ( - (type is Polygon || type is MultiPolygon) && - equals(points[0], points[points.length - 1]) && - newPointsLength < 4 - ) { + if ((geojson is Polygon || geojson is MultiPolygon) && + equals(points[0], points[points.length - 1]) && + newPointsLength < 4) { throw Exception("invalid polygon"); } - if ( - isPointOnLineSegment( - newPoints[newPointsLength - 3], - newPoints[newPointsLength - 1], - newPoints[newPointsLength - 2] - ) - ) -{ newPoints.removeAt(newPoints.length - 2); -} + if (isPointOnLineSegment(newPoints[newPointsLength - 3], + newPoints[newPointsLength - 1], newPoints[newPointsLength - 2])) { + newPoints.removeAt(newPoints.length - 2); + } return newPoints; } @@ -159,7 +132,7 @@ import 'invariant.dart'; * @param {Position} pt2 point * @returns {boolean} true if they are equals */ - equals(Position pt1 , Position pt2 ) { +equals(Position pt1, Position pt2) { return pt1[0] == pt2[0] && pt1[1] == pt2[1]; } @@ -173,13 +146,10 @@ import 'invariant.dart'; * @param {Position} point coord pair of point to check * @returns {boolean} true/false */ - isPointOnLineSegment(Position start , Position end , Position point ) { - var x = point[0], - y = point[1]; - var startX = start[0], - startY = start[1]; - var endX = end[0], - endY = end[1]; +isPointOnLineSegment(Position start, Position end, Position point) { + var x = point[0], y = point[1]; + var startX = start[0], startY = start[1]; + var endX = end[0], endY = end[1]; var dxc = x! - startX!; var dyc = y! - startY!; @@ -187,10 +157,13 @@ import 'invariant.dart'; var dyl = endY! - startY; var cross = dxc * dyl - dyc * dxl; - if (cross != 0){ return false;} - else if ((dxl).abs() >= (dyl).abs()) -{ return dxl > 0 ? startX <= x && x <= endX : endX <= x && x <= startX; -} else {return dyl > 0 ? startY <= y && y <= endY : endY <= y && y <= startY;} + if (cross != 0) { + return false; + } else if ((dxl).abs() >= (dyl).abs()) { + return dxl > 0 ? startX <= x && x <= endX : endX <= x && x <= startX; + } else { + return dyl > 0 ? startY <= y && y <= endY : endY <= y && y <= startY; + } } /** From b64d644b2b391cd12a83ea02bf4e6fa34c025903 Mon Sep 17 00:00:00 2001 From: armantorkzaban Date: Tue, 5 Jul 2022 11:38:44 +0200 Subject: [PATCH 47/82] cleanCoord implemented, going to new branch --- lib/src/clean_coords.dart | 100 ++++++++++++++++---------------------- 1 file changed, 43 insertions(+), 57 deletions(-) diff --git a/lib/src/clean_coords.dart b/lib/src/clean_coords.dart index 7f3ce947..39034a78 100644 --- a/lib/src/clean_coords.dart +++ b/lib/src/clean_coords.dart @@ -1,7 +1,5 @@ // To-Do => Improve Typescript GeoJSON handling -import 'package:turf/src/booleans/boolean_overlap.dart'; - import '../helpers.dart'; import 'invariant.dart'; @@ -23,71 +21,71 @@ cleanCoords( }) { // Store new "clean" points in this List var newCoords = []; - - if (geojson is LineString) { - newCoords = _cleanLine(geojson); - } else if (geojson is MultiLineString || geojson is Polygon) { - getCoords(geojson).forEach( - (geojson) { - newCoords.add(_cleanLine(geojson)); + var geom = geojson is Feature ? geojson.geometry : geojson; + if (geom is LineString) { + newCoords = _cleanLine(geom.coordinates, geojson); + } else if (geom is MultiLineString || geom is Polygon) { + (getCoords(geom) as List>).forEach( + (List coord) { + newCoords.add(_cleanLine(coord, geojson)); }, ); - } else if (geojson is MultiPolygon) { - getCoords(geojson).forEach((polygons) { + } else if (geom is MultiPolygon) { + (getCoords(geom) as List>>) + .forEach((List> polygonCoords) { var polyPoints = []; - polygons.forEach((List ring) { - polyPoints.add(_cleanLine(ring)); + polygonCoords.forEach((List ring) { + polyPoints = _cleanLine(ring, geojson) as List; }); newCoords.add(polyPoints); }); - } else if (geojson is Point) { - return geojson; - } else if (geojson is MultiPoint) { - Map existing = {}; - - getCoords(geojson).forEach( - (coord) { - var key = coord.join("-"); - if (!Object.prototype.hasOwnProperty.call(existing, key)) { - newCoords.add(coord); - existing[key] = true; + } else if (geom is Point) { + return geom; + } else if (geom is MultiPoint) { + Set set = {}; + var list = getCoords(geom).length as List; + list.forEach( + (element) { + if (!set.contains([element.alt, element.lat, element.lng].join('-'))) { + newCoords.add(element.clone()); } + set.add([element.alt, element.lat, element.lng].join('-')); }, ); } else { - throw Exception("$geojson is not supported"); + throw Exception("$geom is not supported"); } // Support input mutation - if (geojson.coordinates) { + if (geojson is GeometryType) { if (mutate) { geojson.coordinates = newCoords; return geojson; } - return {type: type, coordinates: newCoords}; - } else { + geojson.coordinates = newCoords; + return geojson; + } else if (geojson is Feature) { if (mutate) { - geojson.geometry.coordinates = newCoords; + (geojson.geometry as GeometryType).coordinates = newCoords; return geojson; } - return feature( - {type: type, coordinates: newCoords}, - geojson.properties, - { - bbox: geojson.bbox, - id: geojson.id, - }); + return Feature( + geometry: (geom as GeometryType)..coordinates = newCoords, + properties: geojson.properties, + bbox: geojson.bbox, + id: geojson.id, + ); } } -List _cleanLine(List coords) { - var points = getCoords(coords); +List _cleanLine(List coords, GeoJSONObject geojson) { + var points = getCoords(coords) as List; // handle "clean" segment if (points.length == 2 && !equals(points[0], points[1])) { return points; } - var newPoints = []; + var newPoints = []; int secondToLast = points.length - 1; int newPointsLength = newPoints.length; @@ -124,28 +122,16 @@ List _cleanLine(List coords) { return newPoints; } -/** - * Compares two points and returns if they are equals - * - * @private - * @param {Position} pt1 point - * @param {Position} pt2 point - * @returns {boolean} true if they are equals - */ +/// Compares two points and returns if they are equals equals(Position pt1, Position pt2) { return pt1[0] == pt2[0] && pt1[1] == pt2[1]; } -/** - * Returns if `point` is on the segment between `start` and `end`. - * Borrowed from `@turf/boolean-point-on-line` to speed up the evaluation (instead of using the module as dependency) - * - * @private - * @param {Position} start coord pair of start of line - * @param {Position} end coord pair of end of line - * @param {Position} point coord pair of point to check - * @returns {boolean} true/false - */ +/// Returns if `point` is on the segment between `start` and `end`. +/// Borrowed from `@turf/boolean-point-on-line` to speed up the evaluation (instead of using the module as dependency) +/// [start] is the coord pair of start of line +/// [end] is the coord pair of end of line +/// [point] is the coord pair of point to check isPointOnLineSegment(Position start, Position end, Position point) { var x = point[0], y = point[1]; var startX = start[0], startY = start[1]; From 3b2722aa7b173540080533a2b901303cedb6ffd5 Mon Sep 17 00:00:00 2001 From: armantorkzaban Date: Thu, 7 Jul 2022 16:26:50 +0200 Subject: [PATCH 48/82] moving on with equal --- test/booleans/equal_test.dart | 220 +++++++++++++++++----------------- 1 file changed, 108 insertions(+), 112 deletions(-) diff --git a/test/booleans/equal_test.dart b/test/booleans/equal_test.dart index 707dbfc9..d8e7a0f1 100644 --- a/test/booleans/equal_test.dart +++ b/test/booleans/equal_test.dart @@ -6,126 +6,122 @@ import 'package:turf/helpers.dart'; import 'package:turf/src/booleans/boolean_equal.dart'; main() { - group('boolean_crosses', () { - var inDir = Directory('./test/examples/booleans/equal/true'); - for (var file in inDir.listSync(recursive: true)) { - if (file is File && file.path.endsWith('.geojson')) { - test(file.path, () { - // True Fixtures - var inSource = file.readAsStringSync(); - var inGeom = GeoJSONObject.fromJson(jsonDecode(inSource)); + group( + 'boolean_crosses', + () { + var inDir = Directory('./test/examples/booleans/equal/test/true'); + for (var file in inDir.listSync(recursive: true)) { + if (file is File && file.path.endsWith('.geojson')) { + test(file.path, () { + // True Fixtures + var inSource = file.readAsStringSync(); + var inGeom = GeoJSONObject.fromJson(jsonDecode(inSource)); - var feature1 = (inGeom as FeatureCollection).features[0]; - var feature2 = inGeom.features[1]; - Map json = jsonDecode(inSource); - var options = json['properties']; - var result = - booleanEqual(feature1, feature2, precision: options['precision']); + var feature1 = (inGeom as FeatureCollection).features[0]; + var feature2 = inGeom.features[1]; + Map json = jsonDecode(inSource); + var options = json['properties']; + var result = booleanEqual(feature1, feature2, + precision: options?['precision'] ?? 6); - expect(result, true); - }); - // False Fixtures - var inDir = Directory('./test/examples/booleans/equal/false'); - for (var file in inDir.listSync(recursive: true)) { - if (file is File && file.path.endsWith('.geojson')) { - test(file.path, () { - // True Fixtures - var inSource = file.readAsStringSync(); - var inGeom = GeoJSONObject.fromJson(jsonDecode(inSource)); - - var feature1 = (inGeom as FeatureCollection).features[0]; - var feature2 = inGeom.features[1]; - - Map json = jsonDecode(inSource); - var options = json['properties']; - var result = booleanEqual(feature1, feature2, - precision: options['precision']); - - expect(result, true); - }); + expect(result, true); + }); + } + } + // False Fixtures + var inDir1 = Directory('./test/examples/booleans/equal/test/false'); + for (var file in inDir1.listSync(recursive: true)) { + if (file is File && file.path.endsWith('.geojson')) { + test(file.path, () { + // True Fixtures + var inSource = file.readAsStringSync(); + var inGeom = GeoJSONObject.fromJson(jsonDecode(inSource)); - var pt = Point(coordinates: Position.of([9, 50])); - var line1 = Feature( - geometry: LineString(coordinates: [ - Position.of([7, 50]), - Position.of([8, 50]), - Position.of([9, 50]), - ]), - ); - var line2 = Feature( - geometry: LineString(coordinates: [ - Position.of([7, 50]), - Position.of([8, 50]), - Position.of([9, 50]), - ]), - ); - var poly1 = Feature( - geometry: Polygon(coordinates: [ - [ - Position.of([8.5, 50]), - Position.of([9.5, 50]), - Position.of([9.5, 49]), - Position.of([8.5, 49]), - Position.of([8.5, 50]), - ], - ]), - ); - var poly2 = Feature( - geometry: Polygon(coordinates: [ - [ - Position.of([8.5, 50]), - Position.of([9.5, 50]), - Position.of([9.5, 49]), - Position.of([8.5, 49]), - Position.of([8.5, 50]), - ], - ]), - ); - var poly3 = Feature( - geometry: Polygon(coordinates: [ - [ - Position.of([10, 50]), - Position.of([10.5, 50]), - Position.of([10.5, 49]), - Position.of([10, 49]), - Position.of([10, 50]), - ], - ]), - ); + var feature1 = (inGeom as FeatureCollection).features[0]; + var feature2 = inGeom.features[1]; - test("turf-boolean-equal -- geometries", () { - // "[true] LineString geometry" - expect(booleanEqual(line1.geometry!, line2.geometry!), true); + Map json = jsonDecode(inSource); + var options = json['properties']; + var result = booleanEqual(feature1, feature2, + precision: options?['precision'] ?? 6); - // "[true] Polygon geometry" - expect(booleanEqual(poly1.geometry!, poly2.geometry!), true); + expect(result, false); + }); + } + } + var pt = Point(coordinates: Position.of([9, 50])); + var line1 = Feature( + geometry: LineString(coordinates: [ + Position.of([7, 50]), + Position.of([8, 50]), + Position.of([9, 50]), + ]), + ); + var line2 = Feature( + geometry: LineString(coordinates: [ + Position.of([7, 50]), + Position.of([8, 50]), + Position.of([9, 50]), + ]), + ); + var poly1 = Feature( + geometry: Polygon(coordinates: [ + [ + Position.of([8.5, 50]), + Position.of([9.5, 50]), + Position.of([9.5, 49]), + Position.of([8.5, 49]), + Position.of([8.5, 50]), + ], + ]), + ); + var poly2 = Feature( + geometry: Polygon(coordinates: [ + [ + Position.of([8.5, 50]), + Position.of([9.5, 50]), + Position.of([9.5, 49]), + Position.of([8.5, 49]), + Position.of([8.5, 50]), + ], + ]), + ); + var poly3 = Feature( + geometry: Polygon(coordinates: [ + [ + Position.of([10, 50]), + Position.of([10.5, 50]), + Position.of([10.5, 49]), + Position.of([10, 49]), + Position.of([10, 50]), + ], + ]), + ); - // "[false] Polygon geometry" - expect(booleanEqual(poly1.geometry!, poly3.geometry!), false); + test("turf-boolean-equal -- geometries", () { + // "[true] LineString geometry" + expect(booleanEqual(line1.geometry!, line2.geometry!), true); - // "[false] different types" - expect(booleanEqual(pt, line1), false); - }); + // "[true] Polygon geometry" + expect(booleanEqual(poly1.geometry!, poly2.geometry!), true); - test("turf-boolean-equal -- throws", () { - //t.throws(() => equal(null, line1), /feature1 is required/, 'missing feature1'); - //t.throws(() => equal(line1, null), /feature2 is required/, 'missing feature2'); + // "[false] Polygon geometry" + expect(booleanEqual(poly1.geometry!, poly3.geometry!), false); - // "precision must be a number" + // "[false] different types" + expect(booleanEqual(pt, line1), false); + }); - expect( - () => booleanEqual(line1.geometry!, line2.geometry!, - precision: 1), - throwsA(isA())); - //"precision must be positive" - expect( - () => booleanEqual(line1.geometry!, line2.geometry!, - precision: -1), - throwsA(isA())); - }); - } - } - } - } - }); + test( + "turf-boolean-equal -- throws", + () { + // "precision must be positive" + expect( + () => + booleanEqual(line1.geometry!, line2.geometry!, precision: -1), + throwsA(isA())); + }, + ); + }, + ); } From 3ff9b3a2c1b791a6cde1c20378b0101682587be8 Mon Sep 17 00:00:00 2001 From: Lukas Himsel Date: Thu, 7 Jul 2022 16:29:33 +0200 Subject: [PATCH 49/82] update turf_equality dep --- lib/src/booleans/boolean_equal.dart | 2 +- lib/src/booleans/boolean_overlap.dart | 5 +++-- pubspec.yaml | 4 +--- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/lib/src/booleans/boolean_equal.dart b/lib/src/booleans/boolean_equal.dart index a1894b88..e9032050 100644 --- a/lib/src/booleans/boolean_equal.dart +++ b/lib/src/booleans/boolean_equal.dart @@ -1,4 +1,4 @@ -import 'package:geojson_equality/geojson_equality.dart'; +import 'package:turf_equality/turf_equality.dart'; import '../../helpers.dart'; import '../clean_coords.dart'; diff --git a/lib/src/booleans/boolean_overlap.dart b/lib/src/booleans/boolean_overlap.dart index eb6295f5..e9195943 100644 --- a/lib/src/booleans/boolean_overlap.dart +++ b/lib/src/booleans/boolean_overlap.dart @@ -1,4 +1,4 @@ -import 'package:geojson_equality/geojson_equality.dart'; +import 'package:turf_equality/turf_equality.dart'; import '../../helpers.dart'; import '../../line_segment.dart'; @@ -6,7 +6,8 @@ import '../invariant.dart'; import '../line_intersect.dart'; import '../line_overlap.dart'; -Compares two geometries of the same dimension and returns true if their intersection set results in a geometry +/* + * Compares two geometries of the same dimension and returns true if their intersection set results in a geometry * different from both but of the same dimension. It applies to Polygon/Polygon, LineString/LineString, * Multipoint/Multipoint, MultiLineString/MultiLineString and MultiPolygon/MultiPolygon. * diff --git a/pubspec.yaml b/pubspec.yaml index 282e57aa..4c328082 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -9,9 +9,7 @@ publish_to: none dependencies: json_annotation: ^4.4.0 - geojson_equality: - git: - url: https://github.com/dartclub/turf_equality.git + turf_equality: ^0.0.1 pip: git: url: https://github.com/dartclub/point_in_polygon.git From 5c863e05f5882b040bd4001a83cd096c7a3bacee Mon Sep 17 00:00:00 2001 From: armantorkzaban Date: Fri, 8 Jul 2022 01:28:25 +0200 Subject: [PATCH 50/82] moving forward --- lib/src/booleans/boolean_equal.dart | 20 +++++-- test/booleans/equal_test.dart | 58 +++++++++++-------- .../test/true/different-initials-poly.geojson | 48 +++++++++++---- .../equal/test/true/reverse-polygons.geojson | 47 ++++++++++++--- 4 files changed, 125 insertions(+), 48 deletions(-) diff --git a/lib/src/booleans/boolean_equal.dart b/lib/src/booleans/boolean_equal.dart index e9032050..f4612498 100644 --- a/lib/src/booleans/boolean_equal.dart +++ b/lib/src/booleans/boolean_equal.dart @@ -5,7 +5,11 @@ import '../clean_coords.dart'; /// Determine whether two geometries of the same type have identical X,Y coordinate values. /// See http://edndoc.esri.com/arcsde/9.0/general_topics/understand_spatial_relations.htm -/// [precision]=6 sets decimal precision to use when comparing coordinates +/// [precision]=6 sets decimal precision to use when comparing coordinates. +/// With [direction] set to true, even if the [LineStrings] are reverse versions +/// of each other but the have similar [Position]s, they will be considered the same. +/// If [shiftedPolygon] is true, two [Polygon]s with shifted [Position]s are +/// considered the same. /// Returns true if the objects are equal, false otherwise /// example: /// var pt1 = Point(coordinates: Position.of([0, 0])); @@ -15,8 +19,13 @@ import '../clean_coords.dart'; /// //= true /// booleanEqual(pt2, pt3); /// //= false -bool booleanEqual(GeoJSONObject feature1, GeoJSONObject feature2, - {int precision = 6}) { +bool booleanEqual( + GeoJSONObject feature1, + GeoJSONObject feature2, { + int precision = 6, + bool direction = false, + bool shiftedPolygon = false, +}) { if (!(precision >= 0)) { throw Exception("precision must be a positive number"); } @@ -27,6 +36,9 @@ bool booleanEqual(GeoJSONObject feature1, GeoJSONObject feature2, var type2 = geom2!.type; if (type1 != type2) return false; - var equality = Equality(precision: precision); + var equality = Equality( + precision: precision, + shiftedPolygon: shiftedPolygon, + direction: direction); return equality.compare(cleanCoords(feature1), cleanCoords(feature2)); } diff --git a/test/booleans/equal_test.dart b/test/booleans/equal_test.dart index d8e7a0f1..ad766a6a 100644 --- a/test/booleans/equal_test.dart +++ b/test/booleans/equal_test.dart @@ -12,41 +12,49 @@ main() { var inDir = Directory('./test/examples/booleans/equal/test/true'); for (var file in inDir.listSync(recursive: true)) { if (file is File && file.path.endsWith('.geojson')) { - test(file.path, () { - // True Fixtures - var inSource = file.readAsStringSync(); - var inGeom = GeoJSONObject.fromJson(jsonDecode(inSource)); + test( + file.path, + () { + // True Fixtures + var inSource = file.readAsStringSync(); + var inGeom = GeoJSONObject.fromJson(jsonDecode(inSource)); - var feature1 = (inGeom as FeatureCollection).features[0]; - var feature2 = inGeom.features[1]; - Map json = jsonDecode(inSource); - var options = json['properties']; - var result = booleanEqual(feature1, feature2, - precision: options?['precision'] ?? 6); - - expect(result, true); - }); + var feature1 = (inGeom as FeatureCollection).features[0]; + var feature2 = inGeom.features[1]; + Map json = jsonDecode(inSource); + var options = json['properties']; + print(json['properties']?['direction']); + var result = booleanEqual(feature1, feature2, + precision: options?['precision'] ?? 6, + shiftedPolygon: options?['shiftedPolygon'] ?? false, + direction: options?['direction'] ?? false); + expect(result, true); + }, + ); } } // False Fixtures var inDir1 = Directory('./test/examples/booleans/equal/test/false'); for (var file in inDir1.listSync(recursive: true)) { if (file is File && file.path.endsWith('.geojson')) { - test(file.path, () { - // True Fixtures - var inSource = file.readAsStringSync(); - var inGeom = GeoJSONObject.fromJson(jsonDecode(inSource)); + test( + file.path, + () { + // True Fixtures + var inSource = file.readAsStringSync(); + var inGeom = GeoJSONObject.fromJson(jsonDecode(inSource)); - var feature1 = (inGeom as FeatureCollection).features[0]; - var feature2 = inGeom.features[1]; + var feature1 = (inGeom as FeatureCollection).features[0]; + var feature2 = inGeom.features[1]; - Map json = jsonDecode(inSource); - var options = json['properties']; - var result = booleanEqual(feature1, feature2, - precision: options?['precision'] ?? 6); + Map json = jsonDecode(inSource); + var options = json['properties']; + var result = booleanEqual(feature1, feature2, + precision: options?['precision'] ?? 6); - expect(result, false); - }); + expect(result, false); + }, + ); } } var pt = Point(coordinates: Position.of([9, 50])); diff --git a/test/examples/booleans/equal/test/true/different-initials-poly.geojson b/test/examples/booleans/equal/test/true/different-initials-poly.geojson index fcd1cdb4..929e7f6b 100644 --- a/test/examples/booleans/equal/test/true/different-initials-poly.geojson +++ b/test/examples/booleans/equal/test/true/different-initials-poly.geojson @@ -1,17 +1,33 @@ { "type": "FeatureCollection", + "properties": { + "precision": 6, + "shiftedPolygon": true, + "direction": false + }, "features": [ { "type": "Feature", - "properties": {}, "geometry": { "type": "Polygon", "coordinates": [ [ - [1, 1], - [1, 0], - [0, 0], - [1, 1] + [ + 1, + 1 + ], + [ + 1, + 0 + ], + [ + 0, + 0 + ], + [ + 1, + 1 + ] ] ] } @@ -23,13 +39,25 @@ "type": "Polygon", "coordinates": [ [ - [0, 0], - [1, 1], - [1, 0], - [0, 0] + [ + 0, + 0 + ], + [ + 1, + 1 + ], + [ + 1, + 0 + ], + [ + 0, + 0 + ] ] ] } } ] -} +} \ No newline at end of file diff --git a/test/examples/booleans/equal/test/true/reverse-polygons.geojson b/test/examples/booleans/equal/test/true/reverse-polygons.geojson index 6f8b9a9d..8c7530df 100644 --- a/test/examples/booleans/equal/test/true/reverse-polygons.geojson +++ b/test/examples/booleans/equal/test/true/reverse-polygons.geojson @@ -1,5 +1,10 @@ { "type": "FeatureCollection", + "properties": { + "precision": 6, + "shiftedPolygon": true, + "direction": true + }, "features": [ { "type": "Feature", @@ -8,10 +13,22 @@ "type": "Polygon", "coordinates": [ [ - [-53.57, 28.28], - [-53.33, 28.29], - [-53.34, 28.43], - [-53.57, 28.28] + [ + -53.57, + 28.28 + ], + [ + -53.33, + 28.29 + ], + [ + -53.34, + 28.43 + ], + [ + -53.57, + 28.28 + ] ] ] } @@ -23,13 +40,25 @@ "type": "Polygon", "coordinates": [ [ - [-53.57, 28.28], - [-53.34, 28.43], - [-53.33, 28.29], - [-53.57, 28.28] + [ + -53.57, + 28.28 + ], + [ + -53.34, + 28.43 + ], + [ + -53.33, + 28.29 + ], + [ + -53.57, + 28.28 + ] ] ] } } ] -} +} \ No newline at end of file From 29ff2b8f44061f0cca9cb264567444e96f8d031c Mon Sep 17 00:00:00 2001 From: armantorkzaban Date: Fri, 8 Jul 2022 18:20:56 +0200 Subject: [PATCH 51/82] refactors boolean_equal --- lib/src/booleans/boolean_equal.dart | 6 ------ test/booleans/equal_test.dart | 3 +-- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/lib/src/booleans/boolean_equal.dart b/lib/src/booleans/boolean_equal.dart index f4612498..4f26bc7f 100644 --- a/lib/src/booleans/boolean_equal.dart +++ b/lib/src/booleans/boolean_equal.dart @@ -29,12 +29,6 @@ bool booleanEqual( if (!(precision >= 0)) { throw Exception("precision must be a positive number"); } - var geom = feature1 is Feature ? feature1.geometry : feature1; - var geom2 = feature2 is Feature ? feature2.geometry : feature2; - - var type1 = geom!.type; - var type2 = geom2!.type; - if (type1 != type2) return false; var equality = Equality( precision: precision, diff --git a/test/booleans/equal_test.dart b/test/booleans/equal_test.dart index ad766a6a..e6beb3f3 100644 --- a/test/booleans/equal_test.dart +++ b/test/booleans/equal_test.dart @@ -7,7 +7,7 @@ import 'package:turf/src/booleans/boolean_equal.dart'; main() { group( - 'boolean_crosses', + 'boolean_equal', () { var inDir = Directory('./test/examples/booleans/equal/test/true'); for (var file in inDir.listSync(recursive: true)) { @@ -23,7 +23,6 @@ main() { var feature2 = inGeom.features[1]; Map json = jsonDecode(inSource); var options = json['properties']; - print(json['properties']?['direction']); var result = booleanEqual(feature1, feature2, precision: options?['precision'] ?? 6, shiftedPolygon: options?['shiftedPolygon'] ?? false, From 65eddf84855180448453207687eb94f114b65e31 Mon Sep 17 00:00:00 2001 From: armantorkzaban Date: Tue, 30 Aug 2022 01:52:02 +0200 Subject: [PATCH 52/82] #88 crosses, disjoint, equal, intersects, pip @lukas-h --- lib/src/booleans/boolean_crosses.dart | 3 +- lib/src/booleans/boolean_disjoint.dart | 9 +-- lib/src/booleans/boolean_equal.dart | 4 +- lib/src/booleans/boolean_intersect.dart | 3 +- .../booleans/boolean_point_in_polygon.dart | 12 +-- lib/src/line_intersect.dart | 77 ++++++++----------- pubspec.yaml | 4 + test/booleans/disjoint_test.dart | 7 +- test/booleans/intersect_test.dart | 2 +- 9 files changed, 57 insertions(+), 64 deletions(-) diff --git a/lib/src/booleans/boolean_crosses.dart b/lib/src/booleans/boolean_crosses.dart index e51e4215..c7dc4064 100644 --- a/lib/src/booleans/boolean_crosses.dart +++ b/lib/src/booleans/boolean_crosses.dart @@ -1,5 +1,4 @@ import '../../helpers.dart'; -import '../invariant.dart'; import '../line_intersect.dart'; import '../polygon_to_line.dart'; import 'boolean_point_in_polygon.dart'; @@ -115,7 +114,7 @@ bool doLineStringsCross(LineString lineString1, LineString lineString2) { } bool doLineStringAndPolygonCross(LineString lineString, Polygon polygon) { - LineString line = polygonToLine(polygon); + Feature line = polygonToLine(polygon) as Feature; var doLinesIntersect = lineIntersect(lineString, line); if (doLinesIntersect.features.isNotEmpty) { return true; diff --git a/lib/src/booleans/boolean_disjoint.dart b/lib/src/booleans/boolean_disjoint.dart index 80342b32..f754618f 100644 --- a/lib/src/booleans/boolean_disjoint.dart +++ b/lib/src/booleans/boolean_disjoint.dart @@ -27,8 +27,8 @@ bool booleanDisjoint(GeoJSONObject feature1, GeoJSONObject feature2) { flattenEach( feature2, (flatten2, featureIndex, multiFeatureIndex) { - if (bool == false) { - return false; + if (!bool) { + return bool; } bool = _disjoint(flatten1.geometry!, flatten2.geometry!); }, @@ -39,7 +39,7 @@ bool booleanDisjoint(GeoJSONObject feature1, GeoJSONObject feature2) { } /// Disjoint operation for simple Geometries (Point/LineString/Polygon) -_disjoint(GeometryType geom1, GeometryType geom2) { +bool _disjoint(GeometryType geom1, GeometryType geom2) { if (geom1 is Point) { if (geom2 is Point) { return !_compareCoords(geom1.coordinates, geom2.coordinates); @@ -64,9 +64,8 @@ _disjoint(GeometryType geom1, GeometryType geom2) { } else if (geom2 is Polygon) { return !_isPolyInPoly(geom2, geom1); } - } else { - return false; } + return false; } // http://stackoverflow.com/a/11908158/1979085 diff --git a/lib/src/booleans/boolean_equal.dart b/lib/src/booleans/boolean_equal.dart index 4f26bc7f..283602ed 100644 --- a/lib/src/booleans/boolean_equal.dart +++ b/lib/src/booleans/boolean_equal.dart @@ -32,7 +32,7 @@ bool booleanEqual( var equality = Equality( precision: precision, - shiftedPolygon: shiftedPolygon, - direction: direction); + shiftedPolygons: shiftedPolygon, + reversedGeometries: direction); return equality.compare(cleanCoords(feature1), cleanCoords(feature2)); } diff --git a/lib/src/booleans/boolean_intersect.dart b/lib/src/booleans/boolean_intersect.dart index 9e230d6a..7a31cca1 100644 --- a/lib/src/booleans/boolean_intersect.dart +++ b/lib/src/booleans/boolean_intersect.dart @@ -2,8 +2,7 @@ import '../../helpers.dart'; import '../../meta.dart'; import 'boolean_disjoint.dart'; - -Boolean-intersects returns (TRUE) two geometries intersect. +/// returns (TRUE) when two geometries intersect. /// @name booleanIntersects /// @param {Geometry|Feature} feature1 GeoJSON Feature or Geometry /// @param {Geometry|Feature} feature2 GeoJSON Feature or Geometry diff --git a/lib/src/booleans/boolean_point_in_polygon.dart b/lib/src/booleans/boolean_point_in_polygon.dart index cb0da21e..d97576c9 100644 --- a/lib/src/booleans/boolean_point_in_polygon.dart +++ b/lib/src/booleans/boolean_point_in_polygon.dart @@ -1,10 +1,10 @@ // http://en.wikipedia.org/wiki/Even%E2%80%93odd_rule // modified from: https://github.com/substack/point-in-polygon/blob/master/index.js // which was modified from http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html -import 'package:pip/pip.dart'; + +import 'package:turf_pip/turf_pip.dart'; import '../../helpers.dart'; -import '../invariant.dart'; /// Takes a [Point], and a [Polygon] or [MultiPolygon]and determines if the /// [Point] resides inside the [Polygon]. The polygon can be convex or concave. @@ -58,11 +58,11 @@ bool booleanPointInPolygon(Position point, GeoJSONObject polygon, var result = false; for (var i = 0; i < polys!.length; ++i) { - var polyResult = - pip(Point(coordinates: point), Polygon(coordinates: polys[i])); - if (polyResult == 0) { + var polyResult = pointInPolygon( + Point(coordinates: point), Polygon(coordinates: polys[i])); + if (polyResult == PointInPolygonResult.isOnEdge) { return ignoreBoundary ? false : true; - } else if (polyResult) { + } else if (polyResult == PointInPolygonResult.isInside) { result = true; } } diff --git a/lib/src/line_intersect.dart b/lib/src/line_intersect.dart index 48a84e77..29f047d1 100644 --- a/lib/src/line_intersect.dart +++ b/lib/src/line_intersect.dart @@ -1,3 +1,4 @@ +import 'package:sweepline_intersections/sweepline_intersections.dart'; import '../helpers.dart'; @@ -8,71 +9,61 @@ import '../helpers.dart'; /// example: /// ```dart /// var line1 = LineString(coordinates:[ -/// Position.of([126, -11]), +/// Position.of([126, -11]), /// Position.of([129, -21]), /// ]); /// var line2 = LineString(coordinates:[ -/// Position.of([123, -18]), +/// Position.of([123, -18]), /// Position.of([131, -14]), /// ]); /// var intersects = lineIntersect(line1, line2); /// //addToMap /// var addToMap = [line1, line2, intersects] -FeatureCollection lineIntersect( - GeoJSONObject line1, - GeoJSONObject line2, -{ - bool removeDuplicates = true, - bool ignoreSelfIntersections = false - } -){ - var features= []; - if (line1 is FeatureCollection) -{ features = features..addAll(line1.features); -} else if (line1 is Feature) {features.add(line1);} - else if ( - line1 is LineString || - line1 is Polygon || - line1 is MultiLineString || - line1 is MultiPolygon - ) { +FeatureCollection lineIntersect(GeoJSONObject line1, GeoJSONObject line2, + {bool removeDuplicates = true, bool ignoreSelfIntersections = false}) { + var features = []; + if (line1 is FeatureCollection) { + features = features..addAll(line1.features); + } else if (line1 is Feature) { + features.add(line1); + } else if (line1 is LineString || + line1 is Polygon || + line1 is MultiLineString || + line1 is MultiPolygon) { features.add(Feature(geometry: line1 as GeometryObject)); } - if (line2 is FeatureCollection) - {features = features..addAll(line2.features);} - else if (line2 is Feature) {features.add(line2);} - else if ( - line2 is LineString || - line2 is Polygon || - line2 is MultiLineString || - line2 is MultiPolygon - ) { + if (line2 is FeatureCollection) { + features = features..addAll(line2.features); + } else if (line2 is Feature) { + features.add(line2); + } else if (line2 is LineString || + line2 is Polygon || + line2 is MultiLineString || + line2 is MultiPolygon) { features.add(Feature(geometry: line2 as GeometryObject)); } - var intersections = findIntersections( - FeatureCollection(features: features), - ignoreSelfIntersections - ); + var intersections = sweeplineIntersections( + FeatureCollection(features: features), ignoreSelfIntersections); - var results: Intersection[] = []; + var results = []; if (removeDuplicates) { - const unique: Record = {}; - intersections.forEach((intersection) => { - var key = intersection.join(","); - if (!unique[key]) { - unique[key] = true; - results.push(intersection); + Set unique = {}; + intersections.forEach((intersection) { + if (!unique.contains(intersection)) { + unique.add(intersection); + results.add(intersection); } }); } else { results = intersections; } - return FeatureCollection(features: results.map((r) => Feature(geometry: Point(coordinates:r)))); + return FeatureCollection( + features: results + .map((r) => Feature(geometry: Point(coordinates: r))) + .toList()); } - - /** * import { feature, featureCollection, point } from "@turf/helpers"; import { diff --git a/pubspec.yaml b/pubspec.yaml index 0529e9fe..3d3f0557 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -10,6 +10,10 @@ publish_to: none dependencies: json_annotation: ^4.4.0 turf_equality: ^0.0.1 + sweepline_intersections: + git: https://github.com/dartclub/sweepline_intersections.git + turf_pip: ^0.0.1+1 + dev_dependencies: dartclub_lint: ^0.4.2 test: ^1.19.3 diff --git a/test/booleans/disjoint_test.dart b/test/booleans/disjoint_test.dart index 369df336..df6c8087 100644 --- a/test/booleans/disjoint_test.dart +++ b/test/booleans/disjoint_test.dart @@ -7,9 +7,9 @@ import 'package:turf/src/booleans/boolean_disjoint.dart'; main() { group( - 'boolean_crosses', + 'boolean_disjoint', () { - var inDir = Directory('./test/examples/booleans/disjoint/true'); + var inDir = Directory('./test/examples/booleans/disjoint/test/true'); for (var file in inDir.listSync(recursive: true)) { if (file is File && file.path.endsWith('.geojson')) { test( @@ -26,7 +26,8 @@ main() { }, ); // False Fixtures - var inDir1 = Directory('./test/examples/booleans/disjoint/false'); + var inDir1 = + Directory('./test/examples/booleans/disjoint/test/false'); for (var file in inDir1.listSync(recursive: true)) { if (file is File && file.path.endsWith('.geojson')) { test( diff --git a/test/booleans/intersect_test.dart b/test/booleans/intersect_test.dart index 4540ac40..f062ff79 100644 --- a/test/booleans/intersect_test.dart +++ b/test/booleans/intersect_test.dart @@ -2,7 +2,7 @@ import 'package:test/test.dart'; import 'package:turf/helpers.dart'; import 'package:turf/src/booleans/boolean_intersect.dart'; -// main() { +main() { var featureCollection = FeatureCollection(features: [ Feature( properties: {"fill": "#ff0000"}, From 8c912f6509214687db22a9f610e912b07b83d9ca Mon Sep 17 00:00:00 2001 From: armantorkzaban Date: Tue, 30 Aug 2022 09:34:06 +0200 Subject: [PATCH 53/82] cleanup on #88 --- lib/src/booleans/boolean_crosses.dart | 4 +- lib/src/booleans/boolean_disjoint.dart | 6 +- lib/src/booleans/boolean_equal.dart | 10 +- lib/src/booleans/boolean_intersect.dart | 76 ++--- .../booleans/boolean_point_in_polygon.dart | 8 +- test/booleans/crosses_test.dart | 4 +- test/booleans/disjoint_test.dart | 76 ++--- test/booleans/equal_test.dart | 2 +- test/booleans/intersect_test.dart | 37 ++ test/booleans/point_in_polygon_test.dart | 319 ++++++++++-------- .../LineString/LineString-LineString.geojson | 31 ++ .../LineString/Point/LineString-Point.geojson | 26 ++ .../Polygon/LineString-Polygon.geojson | 34 ++ .../LineString/MultiPoint-LineString.geojson | 29 ++ .../MultiPoint/MultiPoint-MultiPoint.geojson | 27 ++ .../MultiPoint/Point/MultiPoint-Point.geojson | 24 ++ .../Polygon/MultiPoint-Polygon.geojson | 32 ++ .../Polygon/MultiPolygon-Polygon.geojson | 52 +++ .../Point/LineString/Point-LineString.geojson | 26 ++ .../Point/MultiPoint/Point-Multipoint.geojson | 24 ++ .../false/Point/Point/Point-Point.geojson | 21 ++ .../false/Point/Polygon/Point-Polygon.geojson | 29 ++ .../LineString/Polygon-LineString.geojson | 34 ++ .../MultiPolygon/Polygon-MultiPolygon.geojson | 52 +++ .../false/Polygon/Point/Polygon-Point.geojson | 29 ++ .../Polygon/Polygon/Polygon-Polygon.geojson | 37 ++ .../LineString/LineString-LineString.geojson | 31 ++ .../Point/LineString-Point-1.geojson | 26 ++ .../Point/LineString-Point-2.geojson | 26 ++ .../Polygon/LineString-In-Polygon.geojson | 32 ++ .../Polygon/LineString-Polygon.geojson | 34 ++ .../LineString/MultiPoint-LineString.geojson | 29 ++ .../MultiPoint/MultiPoint-MultiPoint.geojson | 27 ++ .../Polygon/MultiPoint-Polygon.geojson | 32 ++ .../Polygon/MultiPolygon-Polygon.geojson | 52 +++ .../LineString/Point-LineString-1.geojson | 26 ++ .../LineString/Point-LineString-2.geojson | 26 ++ .../LineString/Point-LineString-3.geojson | 26 ++ .../LineString/Point-LineString-4.geojson | 26 ++ .../Point/MultiPoint/Point-MultiPoint.geojson | 24 ++ .../true/Point/Point/Point-Point.geojson | 21 ++ .../Point/Polygon/Point-Polygon-1.geojson | 29 ++ .../Point/Polygon/Point-Polygon-2.geojson | 29 ++ .../Polygon-Containing-Linestring.geojson | 32 ++ .../LineString/Polygon-LineString.geojson | 34 ++ .../MultiPolygon/Polygon-MultiPolygon.geojson | 52 +++ .../true/Polygon/Point/Polygon-Point.geojson | 29 ++ .../Polygon/Large-Inside-Small.geojson | 39 +++ .../Polygon/Polygon/Polygon-Polygon.geojson | 37 ++ .../Polygon/Small-Inside-Large.geojson | 39 +++ .../true/Polygon/Polygon/issue-1216.geojson | 49 +++ 51 files changed, 1596 insertions(+), 260 deletions(-) create mode 100644 test/examples/booleans/intersects/false/LineString/LineString/LineString-LineString.geojson create mode 100644 test/examples/booleans/intersects/false/LineString/Point/LineString-Point.geojson create mode 100644 test/examples/booleans/intersects/false/LineString/Polygon/LineString-Polygon.geojson create mode 100644 test/examples/booleans/intersects/false/MultiPoint/LineString/MultiPoint-LineString.geojson create mode 100644 test/examples/booleans/intersects/false/MultiPoint/MultiPoint/MultiPoint-MultiPoint.geojson create mode 100644 test/examples/booleans/intersects/false/MultiPoint/Point/MultiPoint-Point.geojson create mode 100644 test/examples/booleans/intersects/false/MultiPoint/Polygon/MultiPoint-Polygon.geojson create mode 100644 test/examples/booleans/intersects/false/MultiPolygon/Polygon/MultiPolygon-Polygon.geojson create mode 100644 test/examples/booleans/intersects/false/Point/LineString/Point-LineString.geojson create mode 100644 test/examples/booleans/intersects/false/Point/MultiPoint/Point-Multipoint.geojson create mode 100644 test/examples/booleans/intersects/false/Point/Point/Point-Point.geojson create mode 100644 test/examples/booleans/intersects/false/Point/Polygon/Point-Polygon.geojson create mode 100644 test/examples/booleans/intersects/false/Polygon/LineString/Polygon-LineString.geojson create mode 100644 test/examples/booleans/intersects/false/Polygon/MultiPolygon/Polygon-MultiPolygon.geojson create mode 100644 test/examples/booleans/intersects/false/Polygon/Point/Polygon-Point.geojson create mode 100644 test/examples/booleans/intersects/false/Polygon/Polygon/Polygon-Polygon.geojson create mode 100644 test/examples/booleans/intersects/true/LineString/LineString/LineString-LineString.geojson create mode 100644 test/examples/booleans/intersects/true/LineString/Point/LineString-Point-1.geojson create mode 100644 test/examples/booleans/intersects/true/LineString/Point/LineString-Point-2.geojson create mode 100644 test/examples/booleans/intersects/true/LineString/Polygon/LineString-In-Polygon.geojson create mode 100644 test/examples/booleans/intersects/true/LineString/Polygon/LineString-Polygon.geojson create mode 100644 test/examples/booleans/intersects/true/MultiPoint/LineString/MultiPoint-LineString.geojson create mode 100644 test/examples/booleans/intersects/true/MultiPoint/MultiPoint/MultiPoint-MultiPoint.geojson create mode 100644 test/examples/booleans/intersects/true/MultiPoint/Polygon/MultiPoint-Polygon.geojson create mode 100644 test/examples/booleans/intersects/true/MultiPolygon/Polygon/MultiPolygon-Polygon.geojson create mode 100644 test/examples/booleans/intersects/true/Point/LineString/Point-LineString-1.geojson create mode 100644 test/examples/booleans/intersects/true/Point/LineString/Point-LineString-2.geojson create mode 100644 test/examples/booleans/intersects/true/Point/LineString/Point-LineString-3.geojson create mode 100644 test/examples/booleans/intersects/true/Point/LineString/Point-LineString-4.geojson create mode 100644 test/examples/booleans/intersects/true/Point/MultiPoint/Point-MultiPoint.geojson create mode 100644 test/examples/booleans/intersects/true/Point/Point/Point-Point.geojson create mode 100644 test/examples/booleans/intersects/true/Point/Polygon/Point-Polygon-1.geojson create mode 100644 test/examples/booleans/intersects/true/Point/Polygon/Point-Polygon-2.geojson create mode 100644 test/examples/booleans/intersects/true/Polygon/LineString/Polygon-Containing-Linestring.geojson create mode 100644 test/examples/booleans/intersects/true/Polygon/LineString/Polygon-LineString.geojson create mode 100644 test/examples/booleans/intersects/true/Polygon/MultiPolygon/Polygon-MultiPolygon.geojson create mode 100644 test/examples/booleans/intersects/true/Polygon/Point/Polygon-Point.geojson create mode 100644 test/examples/booleans/intersects/true/Polygon/Polygon/Large-Inside-Small.geojson create mode 100644 test/examples/booleans/intersects/true/Polygon/Polygon/Polygon-Polygon.geojson create mode 100644 test/examples/booleans/intersects/true/Polygon/Polygon/Small-Inside-Large.geojson create mode 100644 test/examples/booleans/intersects/true/Polygon/Polygon/issue-1216.geojson diff --git a/lib/src/booleans/boolean_crosses.dart b/lib/src/booleans/boolean_crosses.dart index c7dc4064..313ba67a 100644 --- a/lib/src/booleans/boolean_crosses.dart +++ b/lib/src/booleans/boolean_crosses.dart @@ -6,8 +6,8 @@ import 'boolean_point_in_polygon.dart'; /// Boolean-Crosses returns True if the intersection results in a geometry whose /// dimension is one less than the maximum dimension of the two source geometries /// and the intersection set is interior to both source geometries. -/// Boolean-Crosses returns [true] for only [MultiPoint]/[Polygon], [MultiPoint]/[Linestring], -/// [Linestring]/[Linestring], [Linestring]/[Polygon], and [Linestring]/[multiPolygon] comparisons. +/// Boolean-Crosses returns [true] for only [MultiPoint]/[Polygon], [MultiPoint]/[LineString], +/// [LineString]/[LineString], [LineString]/[Polygon], and [LineString]/[MultiPolygon] comparisons. /// Other comparisons are not supported as they are outside the OpenGIS Simple /// [Feature]s spec and may give unexpected results. /// example: diff --git a/lib/src/booleans/boolean_disjoint.dart b/lib/src/booleans/boolean_disjoint.dart index f754618f..d610d2d9 100644 --- a/lib/src/booleans/boolean_disjoint.dart +++ b/lib/src/booleans/boolean_disjoint.dart @@ -4,7 +4,7 @@ import '../line_intersect.dart'; import '../polygon_to_line.dart'; import 'boolean_point_in_polygon.dart'; -/// Returns (TRUE) if the intersection of the two geometries is an empty set. +/// Returns [true] if the intersection of the two geometries is an empty set. /// example: /// ```dart /// var point = Point(coordinates: Position.of([2, 2])); @@ -38,7 +38,7 @@ bool booleanDisjoint(GeoJSONObject feature1, GeoJSONObject feature2) { return bool; } -/// Disjoint operation for simple Geometries (Point/LineString/Polygon) +/// Disjoint operation for simple Geometries ([Point]/[LineString]/[Polygon]) bool _disjoint(GeometryType geom1, GeometryType geom2) { if (geom1 is Point) { if (geom2 is Point) { @@ -100,7 +100,7 @@ bool isLineInPoly(Polygon polygon, LineString lineString) { return false; } -/// Is Polygon (geom1) in Polygon (geom2) +/// Is [Polygon] (geom1) in [Polygon] (geom2) /// Only takes into account outer rings /// See http://stackoverflow.com/a/4833823/1979085 _isPolyInPoly(Polygon feature1, Polygon feature2) { diff --git a/lib/src/booleans/boolean_equal.dart b/lib/src/booleans/boolean_equal.dart index 283602ed..812d6200 100644 --- a/lib/src/booleans/boolean_equal.dart +++ b/lib/src/booleans/boolean_equal.dart @@ -6,11 +6,11 @@ import '../clean_coords.dart'; /// Determine whether two geometries of the same type have identical X,Y coordinate values. /// See http://edndoc.esri.com/arcsde/9.0/general_topics/understand_spatial_relations.htm /// [precision]=6 sets decimal precision to use when comparing coordinates. -/// With [direction] set to true, even if the [LineStrings] are reverse versions -/// of each other but the have similar [Position]s, they will be considered the same. -/// If [shiftedPolygon] is true, two [Polygon]s with shifted [Position]s are -/// considered the same. -/// Returns true if the objects are equal, false otherwise +/// With [direction] set to [true], even if the [LineString]s are reverse versions +/// of each other but they have similar [Position]s, they will be considered the +/// same. If [shiftedPolygon] is [true], two [Polygon]s with shifted [Position]s +/// are considered the same. +/// Returns [true] if the objects are equal, false otherwise /// example: /// var pt1 = Point(coordinates: Position.of([0, 0])); /// var pt2 = Point(coordinates: Position.of([0, 0])); diff --git a/lib/src/booleans/boolean_intersect.dart b/lib/src/booleans/boolean_intersect.dart index 7a31cca1..5b72b2bf 100644 --- a/lib/src/booleans/boolean_intersect.dart +++ b/lib/src/booleans/boolean_intersect.dart @@ -2,61 +2,31 @@ import '../../helpers.dart'; import '../../meta.dart'; import 'boolean_disjoint.dart'; -/// returns (TRUE) when two geometries intersect. -/// @name booleanIntersects -/// @param {Geometry|Feature} feature1 GeoJSON Feature or Geometry -/// @param {Geometry|Feature} feature2 GeoJSON Feature or Geometry -/// @returns {boolean} true/false -/// @example -/// var point = turf.point([2, 2]); -/// var line = turf.lineString([[1, 1], [1, 2], [1, 3], [1, 4]]); -/// turf.booleanIntersects(line, point); +/// returns [true] when two geometries intersect. +/// Takes a feature1 & feature2 parameters of type [GeoJSONObject] which can be +/// a [Feature] or [GeometryType]. +/// example +/// ```dart +/// var point = Point(coordinates:Position.of([2, 2])); +/// var line = LineString(coordinates:[Position.of([1, 1]), Position.of([1, 2]), Position.of([1, 3]), Position.of([1, 4]])); +/// booleanIntersects(line, point); +/// ``` //=true booleanIntersects(GeoJSONObject feature1, GeoJSONObject feature2) { var bool = false; - flattenEach(feature1, (flatten1, featureIndex, multiFeatureIndex) { - flattenEach(feature2, (flatten2, featureIndex, multiFeatureIndex) { - if (bool == true) { - return true; - } - bool = !booleanDisjoint(flatten1, flatten2); - }); - }); + flattenEach( + feature1, + (flatten1, featureIndex, multiFeatureIndex) { + flattenEach( + feature2, + (flatten2, featureIndex, multiFeatureIndex) { + if (bool) { + return true; + } + bool = !booleanDisjoint(flatten1, flatten2); + }, + ); + }, + ); return bool; } - -/** - * import { Feature, Geometry } from "geojson"; -import booleanDisjoint from "@turf/boolean-disjoint"; -import { flattenEach } from "@turf/meta"; - -/** - * Boolean-intersects returns (TRUE) two geometries intersect. - * - * @name booleanIntersects - * @param {Geometry|Feature} feature1 GeoJSON Feature or Geometry - * @param {Geometry|Feature} feature2 GeoJSON Feature or Geometry - * @returns {boolean} true/false - * @example - * var point = turf.point([2, 2]); - * var line = turf.lineString([[1, 1], [1, 2], [1, 3], [1, 4]]); - * - * turf.booleanIntersects(line, point); - * //=true - */ -export default function booleanIntersects( - feature1: Feature | Geometry, - feature2: Feature | Geometry -) { - let bool = false; - flattenEach(feature1, (flatten1) => { - flattenEach(feature2, (flatten2) => { - if (bool === true) { - return true; - } - bool = !booleanDisjoint(flatten1.geometry, flatten2.geometry); - }); - }); - return bool; -} - */ \ No newline at end of file diff --git a/lib/src/booleans/boolean_point_in_polygon.dart b/lib/src/booleans/boolean_point_in_polygon.dart index d97576c9..64f516f1 100644 --- a/lib/src/booleans/boolean_point_in_polygon.dart +++ b/lib/src/booleans/boolean_point_in_polygon.dart @@ -7,11 +7,11 @@ import 'package:turf_pip/turf_pip.dart'; import '../../helpers.dart'; /// Takes a [Point], and a [Polygon] or [MultiPolygon]and determines if the -/// [Point] resides inside the [Polygon]. The polygon can be convex or concave. +/// [Point] resides within the [Polygon]. The [polygon] can be convex or concave. /// The function accounts for holes. By taking a [Feature] or a -/// [Feature]. [ignoreBoundary=false] should be set [true] if polygon's -/// boundary should be ignored when determining if the [Point] is inside the -/// [Polygon] otherwise false. +/// [Feature]. [ignoreBoundary=false] should be set to [true] if +/// [Polygon]'s boundary should be ignored when determining if the [Point] is +/// inside the [Polygon], otherwise, false. /// example: /// ```dart /// var pt = Point(coordinates: Position([-77, 44])); diff --git a/test/booleans/crosses_test.dart b/test/booleans/crosses_test.dart index 7c9f57c0..25d8d9b5 100644 --- a/test/booleans/crosses_test.dart +++ b/test/booleans/crosses_test.dart @@ -9,18 +9,17 @@ main() { group( 'boolean_crosses', () { + // True Fixtures var inDir = Directory('./test/examples/booleans/crosses/true'); for (var file in inDir.listSync(recursive: true)) { if (file is File && file.path.endsWith('.geojson')) { test( file.path, () { - // True Fixtures var inSource = file.readAsStringSync(); var inGeom = GeoJSONObject.fromJson(jsonDecode(inSource)); var feature1 = (inGeom as FeatureCollection).features[0]; var feature2 = inGeom.features[1]; - expect( booleanCrosses(feature1.geometry!, feature2.geometry!), true); }, @@ -34,7 +33,6 @@ main() { test( file.path, () { - // True Fixtures var inSource = file.readAsStringSync(); var inGeom = GeoJSONObject.fromJson(jsonDecode(inSource)); var feature1 = (inGeom as FeatureCollection).features[0]; diff --git a/test/booleans/disjoint_test.dart b/test/booleans/disjoint_test.dart index df6c8087..74aa07ef 100644 --- a/test/booleans/disjoint_test.dart +++ b/test/booleans/disjoint_test.dart @@ -6,48 +6,44 @@ import 'package:turf/helpers.dart'; import 'package:turf/src/booleans/boolean_disjoint.dart'; main() { - group( - 'boolean_disjoint', - () { - var inDir = Directory('./test/examples/booleans/disjoint/test/true'); - for (var file in inDir.listSync(recursive: true)) { - if (file is File && file.path.endsWith('.geojson')) { - test( - file.path, - () { - // True Fixtures - var inSource = file.readAsStringSync(); - var inGeom = GeoJSONObject.fromJson(jsonDecode(inSource)); + group('boolean_disjoint', () { + // True Fixtures + var inDir = Directory('./test/examples/booleans/disjoint/test/true'); + for (var file in inDir.listSync(recursive: true)) { + if (file is File && file.path.endsWith('.geojson')) { + test( + file.path, + () { + var inSource = file.readAsStringSync(); + var inGeom = GeoJSONObject.fromJson(jsonDecode(inSource)); - var feature1 = (inGeom as FeatureCollection).features[0]; - var feature2 = inGeom.features[1]; - var result = booleanDisjoint(feature1, feature2); - expect(result, true); - }, - ); - // False Fixtures - var inDir1 = - Directory('./test/examples/booleans/disjoint/test/false'); - for (var file in inDir1.listSync(recursive: true)) { - if (file is File && file.path.endsWith('.geojson')) { - test( - file.path, - () { - // True Fixtures - var inSource = file.readAsStringSync(); - var inGeom = GeoJSONObject.fromJson(jsonDecode(inSource)); + var feature1 = (inGeom as FeatureCollection).features[0]; + var feature2 = inGeom.features[1]; + var result = booleanDisjoint(feature1, feature2); + expect(result, true); + }, + ); + } + } + // False Fixtures + var inDir1 = Directory('./test/examples/booleans/disjoint/test/false'); + for (var file in inDir1.listSync(recursive: true)) { + if (file is File && file.path.endsWith('.geojson')) { + test( + file.path, + () { + // True Fixtures + var inSource = file.readAsStringSync(); + var inGeom = GeoJSONObject.fromJson(jsonDecode(inSource)); - var feature1 = (inGeom as FeatureCollection).features[0]; - var feature2 = inGeom.features[1]; - var result = booleanDisjoint(feature1, feature2); + var feature1 = (inGeom as FeatureCollection).features[0]; + var feature2 = inGeom.features[1]; + var result = booleanDisjoint(feature1, feature2); - expect(result, false); - }, - ); - } - } - } + expect(result, false); + }, + ); } - }, - ); + } + }); } diff --git a/test/booleans/equal_test.dart b/test/booleans/equal_test.dart index e6beb3f3..cc82c985 100644 --- a/test/booleans/equal_test.dart +++ b/test/booleans/equal_test.dart @@ -9,13 +9,13 @@ main() { group( 'boolean_equal', () { + // True Fixtures var inDir = Directory('./test/examples/booleans/equal/test/true'); for (var file in inDir.listSync(recursive: true)) { if (file is File && file.path.endsWith('.geojson')) { test( file.path, () { - // True Fixtures var inSource = file.readAsStringSync(); var inGeom = GeoJSONObject.fromJson(jsonDecode(inSource)); diff --git a/test/booleans/intersect_test.dart b/test/booleans/intersect_test.dart index f062ff79..5d0b4c37 100644 --- a/test/booleans/intersect_test.dart +++ b/test/booleans/intersect_test.dart @@ -1,6 +1,10 @@ +import 'dart:convert'; +import 'dart:io'; + import 'package:test/test.dart'; import 'package:turf/helpers.dart'; import 'package:turf/src/booleans/boolean_intersect.dart'; +import 'package:turf/src/intersection.dart'; main() { var featureCollection = FeatureCollection(features: [ @@ -90,4 +94,37 @@ main() { expect(booleanIntersects(feature3, feature4), equals(false)); }, ); + test( + "turf-boolean-intersects", + () { + // True Fixtures + var inDir = Directory('./test/examples/booleans/intersects/true'); + for (var file in inDir.listSync(recursive: true)) { + if (file is File && file.path.endsWith('.geojson')) { + var inSource = file.readAsStringSync(); + var inGeom = GeoJSONObject.fromJson(jsonDecode(inSource)); + + var feature1 = (inGeom as FeatureCollection).features[0]; + var feature2 = inGeom.features[1]; + var result = booleanIntersects(feature1, feature2); + + expect(result, isTrue); + } + } + // False Fixtures + var inDir1 = Directory('./test/examples/booleans/intersects/false'); + for (var file in inDir1.listSync(recursive: true)) { + if (file is File && file.path.endsWith('.geojson')) { + var inSource = file.readAsStringSync(); + var inGeom = GeoJSONObject.fromJson(jsonDecode(inSource)); + + var feature1 = (inGeom as FeatureCollection).features[0]; + var feature2 = inGeom.features[1]; + var result = booleanIntersects(feature1, feature2); + + expect(result, isFalse); + } + } + }, + ); } diff --git a/test/booleans/point_in_polygon_test.dart b/test/booleans/point_in_polygon_test.dart index 08dc6cd3..ffdfc056 100644 --- a/test/booleans/point_in_polygon_test.dart +++ b/test/booleans/point_in_polygon_test.dart @@ -7,165 +7,184 @@ import 'package:turf/src/booleans/boolean_point_in_polygon.dart'; main() { group( - '', + 'pip', () { - test("boolean-point-in-polygon -- featureCollection", () { - // test for a simple polygon - var poly = Polygon(coordinates: [ - [ - Position.of([0, 0]), - Position.of([0, 100]), - Position.of([100, 100]), - Position.of([100, 0]), - Position.of([0, 0]), - ], - ]); - var ptIn = Point(coordinates: (Position.of([50, 50]))); - var ptOut = Point(coordinates: (Position.of([140, 150]))); -// "point inside simple polygon" - expect(booleanPointInPolygon(ptIn.coordinates, poly), true); - // "point outside simple polygon" - expect(booleanPointInPolygon(ptOut.coordinates, poly), false); - - // test for a concave polygon - var concavePoly = Polygon(coordinates: [ - [ - Position.of([0, 0]), - Position.of([50, 50]), - Position.of([0, 100]), - Position.of([100, 100]), - Position.of([100, 0]), - Position.of([0, 0]), - ], - ]); - var ptConcaveIn = Point(coordinates: (Position.of([75, 75]))); - var ptConcaveOut = Point(coordinates: (Position.of([25, 50]))); + test( + "boolean-point-in-polygon -- featureCollection", + () { + // test for a simple polygon + var poly = Polygon(coordinates: [ + [ + Position.of([0, 0]), + Position.of([0, 100]), + Position.of([100, 100]), + Position.of([100, 0]), + Position.of([0, 0]), + ], + ]); + var ptIn = Point(coordinates: (Position.of([50, 50]))); + var ptOut = Point(coordinates: (Position.of([140, 150]))); + // "point inside simple polygon" + expect(booleanPointInPolygon(ptIn.coordinates, poly), true); + // "point outside simple polygon" + expect(booleanPointInPolygon(ptOut.coordinates, poly), false); -// "point inside concave polygon" - expect( - booleanPointInPolygon(ptConcaveIn.coordinates, concavePoly), true); - // "point outside concave polygon" + // test for a concave polygon + var concavePoly = Polygon(coordinates: [ + [ + Position.of([0, 0]), + Position.of([50, 50]), + Position.of([0, 100]), + Position.of([100, 100]), + Position.of([100, 0]), + Position.of([0, 0]), + ], + ]); + var ptConcaveIn = Point(coordinates: (Position.of([75, 75]))); + var ptConcaveOut = Point(coordinates: (Position.of([25, 50]))); - expect(booleanPointInPolygon(ptConcaveOut.coordinates, concavePoly), - false); - }); + // "point inside concave polygon" + expect(booleanPointInPolygon(ptConcaveIn.coordinates, concavePoly), + true); + // "point outside concave polygon" + expect(booleanPointInPolygon(ptConcaveOut.coordinates, concavePoly), + false); + }, + ); - test("boolean-point-in-polygon -- poly with hole", () { - var ptInHole = Point( - coordinates: - (Position.of([-86.69208526611328, 36.20373274711739]))); - var ptInPoly = Point( - coordinates: - (Position.of([-86.72229766845702, 36.20258997094334]))); - var ptOutsidePoly = Point( - coordinates: - (Position.of([-86.75079345703125, 36.18527313913089]))); + test( + "boolean-point-in-polygon -- poly with hole", + () { + var ptInHole = Point( + coordinates: + (Position.of([-86.69208526611328, 36.20373274711739]))); + var ptInPoly = Point( + coordinates: + (Position.of([-86.72229766845702, 36.20258997094334]))); + var ptOutsidePoly = Point( + coordinates: + (Position.of([-86.75079345703125, 36.18527313913089]))); - var inFile = File( - './test/examples/booleans/point_in_polygon/in/poly-with-hole.geojson'); + var inFile = File( + './test/examples/booleans/point_in_polygon/in/poly-with-hole.geojson'); - var polyHole = - GeoJSONObject.fromJson(jsonDecode(inFile.readAsStringSync())); + var polyHole = + GeoJSONObject.fromJson(jsonDecode(inFile.readAsStringSync())); - expect(booleanPointInPolygon(ptInHole.coordinates, polyHole), false); - expect(booleanPointInPolygon(ptInPoly.coordinates, polyHole), true); - expect( - booleanPointInPolygon(ptOutsidePoly.coordinates, polyHole), false); - }); + expect(booleanPointInPolygon(ptInHole.coordinates, polyHole), false); + expect(booleanPointInPolygon(ptInPoly.coordinates, polyHole), true); + expect(booleanPointInPolygon(ptOutsidePoly.coordinates, polyHole), + false); + }, + ); - test("boolean-point-in-polygon -- multipolygon with hole", () { - var ptInHole = Point( - coordinates: - (Position.of([-86.69208526611328, 36.20373274711739]))); - var ptInPoly = Point( - coordinates: - (Position.of([-86.72229766845702, 36.20258997094334]))); - var ptInPoly2 = Point( - coordinates: - (Position.of([-86.75079345703125, 36.18527313913089]))); - var ptOutsidePoly = Point( - coordinates: - (Position.of([-86.75302505493164, 36.23015046460186]))); + test( + "boolean-point-in-polygon -- multipolygon with hole", + () { + var ptInHole = Point( + coordinates: + (Position.of([-86.69208526611328, 36.20373274711739]))); + var ptInPoly = Point( + coordinates: + (Position.of([-86.72229766845702, 36.20258997094334]))); + var ptInPoly2 = Point( + coordinates: + (Position.of([-86.75079345703125, 36.18527313913089]))); + var ptOutsidePoly = Point( + coordinates: + (Position.of([-86.75302505493164, 36.23015046460186]))); - var inFile = File( - './test/examples/booleans/point_in_polygon/in/multipoly-with-hole.geojson'); + var inFile = File( + './test/examples/booleans/point_in_polygon/in/multipoly-with-hole.geojson'); - var multiPolyHole = - GeoJSONObject.fromJson(jsonDecode(inFile.readAsStringSync())); + var multiPolyHole = + GeoJSONObject.fromJson(jsonDecode(inFile.readAsStringSync())); - expect( - booleanPointInPolygon(ptInHole.coordinates, multiPolyHole), false); - expect( - booleanPointInPolygon(ptInPoly.coordinates, multiPolyHole), true); - expect( - booleanPointInPolygon(ptInPoly2.coordinates, multiPolyHole), true); - expect( - booleanPointInPolygon(ptInPoly.coordinates, multiPolyHole), true); - expect(booleanPointInPolygon(ptOutsidePoly.coordinates, multiPolyHole), - false); - }); + expect(booleanPointInPolygon(ptInHole.coordinates, multiPolyHole), + false); + expect( + booleanPointInPolygon(ptInPoly.coordinates, multiPolyHole), true); + expect(booleanPointInPolygon(ptInPoly2.coordinates, multiPolyHole), + true); + expect( + booleanPointInPolygon(ptInPoly.coordinates, multiPolyHole), true); + expect( + booleanPointInPolygon(ptOutsidePoly.coordinates, multiPolyHole), + false); + }, + ); test( 'boolean-point-in-polygon -- Boundary test', () { - var poly1 = Polygon(coordinates: [ - [ - Position.of([10, 10]), - Position.of([30, 20]), - Position.of([50, 10]), - Position.of([30, 0]), - Position.of([10, 10]), - ], - ]); - var poly2 = Polygon(coordinates: [ - [ - Position.of([10, 0]), - Position.of([30, 20]), - Position.of([50, 0]), - Position.of([30, 10]), - Position.of([10, 0]), + var poly1 = Polygon( + coordinates: [ + [ + Position.of([10, 10]), + Position.of([30, 20]), + Position.of([50, 10]), + Position.of([30, 0]), + Position.of([10, 10]), + ], ], - ]); - var poly3 = Polygon(coordinates: [ - [ - Position.of([10, 0]), - Position.of([30, 20]), - Position.of([50, 0]), - Position.of([30, -20]), - Position.of([10, 0]), + ); + var poly2 = Polygon( + coordinates: [ + [ + Position.of([10, 0]), + Position.of([30, 20]), + Position.of([50, 0]), + Position.of([30, 10]), + Position.of([10, 0]), + ], ], - ]); - var poly4 = Polygon(coordinates: [ - [ - Position.of([0, 0]), - Position.of([0, 20]), - Position.of([50, 20]), - Position.of([50, 0]), - Position.of([40, 0]), - Position.of([30, 10]), - Position.of([30, 0]), - Position.of([20, 10]), - Position.of([10, 10]), - Position.of([10, 0]), - Position.of([0, 0]), + ); + var poly3 = Polygon( + coordinates: [ + [ + Position.of([10, 0]), + Position.of([30, 20]), + Position.of([50, 0]), + Position.of([30, -20]), + Position.of([10, 0]), + ], ], - ]); - var poly5 = Polygon(coordinates: [ - [ - Position.of([0, 20]), - Position.of([20, 40]), - Position.of([40, 20]), - Position.of([20, 0]), - Position.of([0, 20]), + ); + var poly4 = Polygon( + coordinates: [ + [ + Position.of([0, 0]), + Position.of([0, 20]), + Position.of([50, 20]), + Position.of([50, 0]), + Position.of([40, 0]), + Position.of([30, 10]), + Position.of([30, 0]), + Position.of([20, 10]), + Position.of([10, 10]), + Position.of([10, 0]), + Position.of([0, 0]), + ], ], - [ - Position.of([10, 20]), - Position.of([20, 30]), - Position.of([30, 20]), - Position.of([20, 10]), - Position.of([10, 20]), + ); + var poly5 = Polygon( + coordinates: [ + [ + Position.of([0, 20]), + Position.of([20, 40]), + Position.of([40, 20]), + Position.of([20, 0]), + Position.of([0, 20]), + ], + [ + Position.of([10, 20]), + Position.of([20, 30]), + Position.of([30, 20]), + Position.of([20, 10]), + Position.of([10, 20]), + ], ], - ]); + ); runTest(bool ignoreBoundary) { var isBoundaryIncluded = ignoreBoundary == false; @@ -357,7 +376,7 @@ main() { ], ]; - for (var i = 0; i < tests.length; i++) { + for (int i = 0; i < tests.length; i++) { var item = tests[i]; expect( booleanPointInPolygon( @@ -366,7 +385,7 @@ main() { ignoreBoundary: ignoreBoundary, ) == item[2], - true); + isTrue); } } @@ -380,15 +399,17 @@ main() { "boolean-point-in-polygon -- issue #15", () { var pt1 = Point(coordinates: (Position.of([-9.9964077, 53.8040989]))); - var poly = Polygon(coordinates: [ - [ - Position.of([5.080336744095521, 67.89398938540765]), - Position.of([0.35070899909145403, 69.32470003971179]), - Position.of([-24.453622256504122, 41.146696777884564]), - Position.of([-21.6445524714804, 40.43225902006474]), - Position.of([5.080336744095521, 67.89398938540765]), + var poly = Polygon( + coordinates: [ + [ + Position.of([5.080336744095521, 67.89398938540765]), + Position.of([0.35070899909145403, 69.32470003971179]), + Position.of([-24.453622256504122, 41.146696777884564]), + Position.of([-21.6445524714804, 40.43225902006474]), + Position.of([5.080336744095521, 67.89398938540765]), + ], ], - ]); + ); expect(booleanPointInPolygon(pt1.coordinates, poly), true); }, diff --git a/test/examples/booleans/intersects/false/LineString/LineString/LineString-LineString.geojson b/test/examples/booleans/intersects/false/LineString/LineString/LineString-LineString.geojson new file mode 100644 index 00000000..6c774ab5 --- /dev/null +++ b/test/examples/booleans/intersects/false/LineString/LineString/LineString-LineString.geojson @@ -0,0 +1,31 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [0, 0], + [12, 2], + [12, 3], + [12, 4] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [1, 1], + [1, 2], + [1, 3], + [1, 4] + ] + } + } + ] +} diff --git a/test/examples/booleans/intersects/false/LineString/Point/LineString-Point.geojson b/test/examples/booleans/intersects/false/LineString/Point/LineString-Point.geojson new file mode 100644 index 00000000..e327ba98 --- /dev/null +++ b/test/examples/booleans/intersects/false/LineString/Point/LineString-Point.geojson @@ -0,0 +1,26 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [1, 1], + [1, 2], + [1, 3], + [1, 4] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [0, 0] + } + } + ] +} diff --git a/test/examples/booleans/intersects/false/LineString/Polygon/LineString-Polygon.geojson b/test/examples/booleans/intersects/false/LineString/Polygon/LineString-Polygon.geojson new file mode 100644 index 00000000..d34e7dce --- /dev/null +++ b/test/examples/booleans/intersects/false/LineString/Polygon/LineString-Polygon.geojson @@ -0,0 +1,34 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [0, 0], + [12, 2], + [12, 3], + [12, 4] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [-1, 2], + [3, 2], + [3, 3], + [-1, 3], + [-1, 2] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/intersects/false/MultiPoint/LineString/MultiPoint-LineString.geojson b/test/examples/booleans/intersects/false/MultiPoint/LineString/MultiPoint-LineString.geojson new file mode 100644 index 00000000..77b1b718 --- /dev/null +++ b/test/examples/booleans/intersects/false/MultiPoint/LineString/MultiPoint-LineString.geojson @@ -0,0 +1,29 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPoint", + "coordinates": [ + [2, 2], + [0, 0] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [1, 1], + [1, 2], + [1, 3], + [1, 4] + ] + } + } + ] +} diff --git a/test/examples/booleans/intersects/false/MultiPoint/MultiPoint/MultiPoint-MultiPoint.geojson b/test/examples/booleans/intersects/false/MultiPoint/MultiPoint/MultiPoint-MultiPoint.geojson new file mode 100644 index 00000000..7e3143af --- /dev/null +++ b/test/examples/booleans/intersects/false/MultiPoint/MultiPoint/MultiPoint-MultiPoint.geojson @@ -0,0 +1,27 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPoint", + "coordinates": [ + [0, 0], + [13, 13] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPoint", + "coordinates": [ + [1, 1], + [12, 12] + ] + } + } + ] +} diff --git a/test/examples/booleans/intersects/false/MultiPoint/Point/MultiPoint-Point.geojson b/test/examples/booleans/intersects/false/MultiPoint/Point/MultiPoint-Point.geojson new file mode 100644 index 00000000..eb6182a3 --- /dev/null +++ b/test/examples/booleans/intersects/false/MultiPoint/Point/MultiPoint-Point.geojson @@ -0,0 +1,24 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPoint", + "coordinates": [ + [1, 1], + [12, 12] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [0, 0] + } + } + ] +} diff --git a/test/examples/booleans/intersects/false/MultiPoint/Polygon/MultiPoint-Polygon.geojson b/test/examples/booleans/intersects/false/MultiPoint/Polygon/MultiPoint-Polygon.geojson new file mode 100644 index 00000000..469de623 --- /dev/null +++ b/test/examples/booleans/intersects/false/MultiPoint/Polygon/MultiPoint-Polygon.geojson @@ -0,0 +1,32 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPoint", + "coordinates": [ + [-3, -3], + [-2, -2] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [-1, 2], + [3, 2], + [3, 3], + [-1, 3], + [-1, 2] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/intersects/false/MultiPolygon/Polygon/MultiPolygon-Polygon.geojson b/test/examples/booleans/intersects/false/MultiPolygon/Polygon/MultiPolygon-Polygon.geojson new file mode 100644 index 00000000..3b2ea41f --- /dev/null +++ b/test/examples/booleans/intersects/false/MultiPolygon/Polygon/MultiPolygon-Polygon.geojson @@ -0,0 +1,52 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": { + "fill": "#ff0000" + }, + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + [ + [ + [122.6953125, -19.186677697957833], + [128.759765625, -19.186677697957833], + [128.759765625, -15.28418511407642], + [122.6953125, -15.28418511407642], + [122.6953125, -19.186677697957833] + ] + ], + [ + [ + [123.74999999999999, -25.918526162075153], + [130.25390625, -25.918526162075153], + [130.25390625, -20.715015145512087], + [123.74999999999999, -20.715015145512087], + [123.74999999999999, -25.918526162075153] + ] + ] + ] + } + }, + { + "type": "Feature", + "properties": { + "fill": "#0000ff" + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [116.98242187499999, -24.647017162630352], + [122.87109375, -24.647017162630352], + [122.87109375, -20.34462694382967], + [116.98242187499999, -20.34462694382967], + [116.98242187499999, -24.647017162630352] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/intersects/false/Point/LineString/Point-LineString.geojson b/test/examples/booleans/intersects/false/Point/LineString/Point-LineString.geojson new file mode 100644 index 00000000..be635169 --- /dev/null +++ b/test/examples/booleans/intersects/false/Point/LineString/Point-LineString.geojson @@ -0,0 +1,26 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [0, 0] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [1, 1], + [1, 2], + [1, 3], + [1, 4] + ] + } + } + ] +} diff --git a/test/examples/booleans/intersects/false/Point/MultiPoint/Point-Multipoint.geojson b/test/examples/booleans/intersects/false/Point/MultiPoint/Point-Multipoint.geojson new file mode 100644 index 00000000..542362e8 --- /dev/null +++ b/test/examples/booleans/intersects/false/Point/MultiPoint/Point-Multipoint.geojson @@ -0,0 +1,24 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [0, 0] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPoint", + "coordinates": [ + [1, 1], + [12, 12] + ] + } + } + ] +} diff --git a/test/examples/booleans/intersects/false/Point/Point/Point-Point.geojson b/test/examples/booleans/intersects/false/Point/Point/Point-Point.geojson new file mode 100644 index 00000000..6d022c5e --- /dev/null +++ b/test/examples/booleans/intersects/false/Point/Point/Point-Point.geojson @@ -0,0 +1,21 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [0, 0] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [0, 1] + } + } + ] +} diff --git a/test/examples/booleans/intersects/false/Point/Polygon/Point-Polygon.geojson b/test/examples/booleans/intersects/false/Point/Polygon/Point-Polygon.geojson new file mode 100644 index 00000000..c3d4c6de --- /dev/null +++ b/test/examples/booleans/intersects/false/Point/Polygon/Point-Polygon.geojson @@ -0,0 +1,29 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [1, 1] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [-1, 2], + [3, 2], + [3, 3], + [-1, 3], + [-1, 2] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/intersects/false/Polygon/LineString/Polygon-LineString.geojson b/test/examples/booleans/intersects/false/Polygon/LineString/Polygon-LineString.geojson new file mode 100644 index 00000000..52b4a494 --- /dev/null +++ b/test/examples/booleans/intersects/false/Polygon/LineString/Polygon-LineString.geojson @@ -0,0 +1,34 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [-1, 2], + [3, 2], + [3, 3], + [-1, 3], + [-1, 2] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [0, 0], + [12, 2], + [12, 3], + [12, 4] + ] + } + } + ] +} diff --git a/test/examples/booleans/intersects/false/Polygon/MultiPolygon/Polygon-MultiPolygon.geojson b/test/examples/booleans/intersects/false/Polygon/MultiPolygon/Polygon-MultiPolygon.geojson new file mode 100644 index 00000000..d165d17b --- /dev/null +++ b/test/examples/booleans/intersects/false/Polygon/MultiPolygon/Polygon-MultiPolygon.geojson @@ -0,0 +1,52 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": { + "fill": "#0000ff" + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [116.98242187499999, -24.647017162630352], + [122.87109375, -24.647017162630352], + [122.87109375, -20.34462694382967], + [116.98242187499999, -20.34462694382967], + [116.98242187499999, -24.647017162630352] + ] + ] + } + }, + { + "type": "Feature", + "properties": { + "fill": "#ff0000" + }, + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + [ + [ + [122.6953125, -19.186677697957833], + [128.759765625, -19.186677697957833], + [128.759765625, -15.28418511407642], + [122.6953125, -15.28418511407642], + [122.6953125, -19.186677697957833] + ] + ], + [ + [ + [123.74999999999999, -25.918526162075153], + [130.25390625, -25.918526162075153], + [130.25390625, -20.715015145512087], + [123.74999999999999, -20.715015145512087], + [123.74999999999999, -25.918526162075153] + ] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/intersects/false/Polygon/Point/Polygon-Point.geojson b/test/examples/booleans/intersects/false/Polygon/Point/Polygon-Point.geojson new file mode 100644 index 00000000..557d45be --- /dev/null +++ b/test/examples/booleans/intersects/false/Polygon/Point/Polygon-Point.geojson @@ -0,0 +1,29 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [-1, 2], + [3, 2], + [3, 3], + [-1, 3], + [-1, 2] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [1, 1] + } + } + ] +} diff --git a/test/examples/booleans/intersects/false/Polygon/Polygon/Polygon-Polygon.geojson b/test/examples/booleans/intersects/false/Polygon/Polygon/Polygon-Polygon.geojson new file mode 100644 index 00000000..66d7ab57 --- /dev/null +++ b/test/examples/booleans/intersects/false/Polygon/Polygon/Polygon-Polygon.geojson @@ -0,0 +1,37 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [-11, -12], + [-13, -12], + [-13, -13], + [-11, -13], + [-11, -12] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [-1, 2], + [3, 2], + [3, 3], + [-1, 3], + [-1, 2] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/intersects/true/LineString/LineString/LineString-LineString.geojson b/test/examples/booleans/intersects/true/LineString/LineString/LineString-LineString.geojson new file mode 100644 index 00000000..5ad6f986 --- /dev/null +++ b/test/examples/booleans/intersects/true/LineString/LineString/LineString-LineString.geojson @@ -0,0 +1,31 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [0, 2], + [12, 2], + [12, 3], + [12, 4] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [1, 1], + [1, 2], + [1, 3], + [1, 4] + ] + } + } + ] +} diff --git a/test/examples/booleans/intersects/true/LineString/Point/LineString-Point-1.geojson b/test/examples/booleans/intersects/true/LineString/Point/LineString-Point-1.geojson new file mode 100644 index 00000000..39e7953d --- /dev/null +++ b/test/examples/booleans/intersects/true/LineString/Point/LineString-Point-1.geojson @@ -0,0 +1,26 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [1, 1], + [1, 2], + [1, 3], + [1, 4] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [1, 1] + } + } + ] +} diff --git a/test/examples/booleans/intersects/true/LineString/Point/LineString-Point-2.geojson b/test/examples/booleans/intersects/true/LineString/Point/LineString-Point-2.geojson new file mode 100644 index 00000000..323ca4e1 --- /dev/null +++ b/test/examples/booleans/intersects/true/LineString/Point/LineString-Point-2.geojson @@ -0,0 +1,26 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [1, 1], + [1, 2], + [1, 3], + [1, 4] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [1, 1.5] + } + } + ] +} diff --git a/test/examples/booleans/intersects/true/LineString/Polygon/LineString-In-Polygon.geojson b/test/examples/booleans/intersects/true/LineString/Polygon/LineString-In-Polygon.geojson new file mode 100644 index 00000000..62d55b65 --- /dev/null +++ b/test/examples/booleans/intersects/true/LineString/Polygon/LineString-In-Polygon.geojson @@ -0,0 +1,32 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [1, 2.5], + [2, 2.5] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [-1, 2], + [3, 2], + [3, 3], + [-1, 3], + [-1, 2] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/intersects/true/LineString/Polygon/LineString-Polygon.geojson b/test/examples/booleans/intersects/true/LineString/Polygon/LineString-Polygon.geojson new file mode 100644 index 00000000..be2b9688 --- /dev/null +++ b/test/examples/booleans/intersects/true/LineString/Polygon/LineString-Polygon.geojson @@ -0,0 +1,34 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [0, 2], + [12, 2], + [12, 3], + [12, 4] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [-1, 2], + [3, 2], + [3, 3], + [-1, 3], + [-1, 2] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/intersects/true/MultiPoint/LineString/MultiPoint-LineString.geojson b/test/examples/booleans/intersects/true/MultiPoint/LineString/MultiPoint-LineString.geojson new file mode 100644 index 00000000..f7bc3dd8 --- /dev/null +++ b/test/examples/booleans/intersects/true/MultiPoint/LineString/MultiPoint-LineString.geojson @@ -0,0 +1,29 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPoint", + "coordinates": [ + [1, 1], + [0, 0] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [1, 1], + [1, 2], + [1, 3], + [1, 4] + ] + } + } + ] +} diff --git a/test/examples/booleans/intersects/true/MultiPoint/MultiPoint/MultiPoint-MultiPoint.geojson b/test/examples/booleans/intersects/true/MultiPoint/MultiPoint/MultiPoint-MultiPoint.geojson new file mode 100644 index 00000000..85a8e2cd --- /dev/null +++ b/test/examples/booleans/intersects/true/MultiPoint/MultiPoint/MultiPoint-MultiPoint.geojson @@ -0,0 +1,27 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPoint", + "coordinates": [ + [0, 0], + [12, 12] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPoint", + "coordinates": [ + [1, 1], + [12, 12] + ] + } + } + ] +} diff --git a/test/examples/booleans/intersects/true/MultiPoint/Polygon/MultiPoint-Polygon.geojson b/test/examples/booleans/intersects/true/MultiPoint/Polygon/MultiPoint-Polygon.geojson new file mode 100644 index 00000000..da402f37 --- /dev/null +++ b/test/examples/booleans/intersects/true/MultiPoint/Polygon/MultiPoint-Polygon.geojson @@ -0,0 +1,32 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPoint", + "coordinates": [ + [-1, 2], + [-2, -2] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [-1, 2], + [3, 2], + [3, 3], + [-1, 3], + [-1, 2] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/intersects/true/MultiPolygon/Polygon/MultiPolygon-Polygon.geojson b/test/examples/booleans/intersects/true/MultiPolygon/Polygon/MultiPolygon-Polygon.geojson new file mode 100644 index 00000000..706074d3 --- /dev/null +++ b/test/examples/booleans/intersects/true/MultiPolygon/Polygon/MultiPolygon-Polygon.geojson @@ -0,0 +1,52 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": { + "fill": "#ff0000" + }, + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + [ + [ + [122.6953125, -19.186677697957833], + [128.759765625, -19.186677697957833], + [128.759765625, -15.28418511407642], + [122.6953125, -15.28418511407642], + [122.6953125, -19.186677697957833] + ] + ], + [ + [ + [123.74999999999999, -25.918526162075153], + [130.25390625, -25.918526162075153], + [130.25390625, -20.715015145512087], + [123.74999999999999, -20.715015145512087], + [123.74999999999999, -25.918526162075153] + ] + ] + ] + } + }, + { + "type": "Feature", + "properties": { + "fill": "#0000ff" + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [119.20166015624999, -22.776181505086495], + [125.09033203124999, -22.776181505086495], + [125.09033203124999, -18.417078658661257], + [119.20166015624999, -18.417078658661257], + [119.20166015624999, -22.776181505086495] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/intersects/true/Point/LineString/Point-LineString-1.geojson b/test/examples/booleans/intersects/true/Point/LineString/Point-LineString-1.geojson new file mode 100644 index 00000000..b84728a8 --- /dev/null +++ b/test/examples/booleans/intersects/true/Point/LineString/Point-LineString-1.geojson @@ -0,0 +1,26 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [1, 1] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [1, 1], + [1, 2], + [1, 3], + [1, 4] + ] + } + } + ] +} diff --git a/test/examples/booleans/intersects/true/Point/LineString/Point-LineString-2.geojson b/test/examples/booleans/intersects/true/Point/LineString/Point-LineString-2.geojson new file mode 100644 index 00000000..a937db0c --- /dev/null +++ b/test/examples/booleans/intersects/true/Point/LineString/Point-LineString-2.geojson @@ -0,0 +1,26 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [1, 1.5] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [1, 1], + [1, 2], + [1, 3], + [1, 4] + ] + } + } + ] +} diff --git a/test/examples/booleans/intersects/true/Point/LineString/Point-LineString-3.geojson b/test/examples/booleans/intersects/true/Point/LineString/Point-LineString-3.geojson new file mode 100644 index 00000000..46d35691 --- /dev/null +++ b/test/examples/booleans/intersects/true/Point/LineString/Point-LineString-3.geojson @@ -0,0 +1,26 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [2.5, 1] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [1, 1], + [2, 1], + [3, 1], + [4, 1] + ] + } + } + ] +} diff --git a/test/examples/booleans/intersects/true/Point/LineString/Point-LineString-4.geojson b/test/examples/booleans/intersects/true/Point/LineString/Point-LineString-4.geojson new file mode 100644 index 00000000..cf348f68 --- /dev/null +++ b/test/examples/booleans/intersects/true/Point/LineString/Point-LineString-4.geojson @@ -0,0 +1,26 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [2.5, 2.5] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [1, 1], + [2, 2], + [3, 3], + [4, 4] + ] + } + } + ] +} diff --git a/test/examples/booleans/intersects/true/Point/MultiPoint/Point-MultiPoint.geojson b/test/examples/booleans/intersects/true/Point/MultiPoint/Point-MultiPoint.geojson new file mode 100644 index 00000000..f958a470 --- /dev/null +++ b/test/examples/booleans/intersects/true/Point/MultiPoint/Point-MultiPoint.geojson @@ -0,0 +1,24 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [1, 1] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPoint", + "coordinates": [ + [1, 1], + [12, 12] + ] + } + } + ] +} diff --git a/test/examples/booleans/intersects/true/Point/Point/Point-Point.geojson b/test/examples/booleans/intersects/true/Point/Point/Point-Point.geojson new file mode 100644 index 00000000..15b60d6f --- /dev/null +++ b/test/examples/booleans/intersects/true/Point/Point/Point-Point.geojson @@ -0,0 +1,21 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [0, 0] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [0, 0] + } + } + ] +} diff --git a/test/examples/booleans/intersects/true/Point/Polygon/Point-Polygon-1.geojson b/test/examples/booleans/intersects/true/Point/Polygon/Point-Polygon-1.geojson new file mode 100644 index 00000000..5ef704e8 --- /dev/null +++ b/test/examples/booleans/intersects/true/Point/Polygon/Point-Polygon-1.geojson @@ -0,0 +1,29 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [1, 2.5] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [-1, 2], + [3, 2], + [3, 3], + [-1, 3], + [-1, 2] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/intersects/true/Point/Polygon/Point-Polygon-2.geojson b/test/examples/booleans/intersects/true/Point/Polygon/Point-Polygon-2.geojson new file mode 100644 index 00000000..b3a139a5 --- /dev/null +++ b/test/examples/booleans/intersects/true/Point/Polygon/Point-Polygon-2.geojson @@ -0,0 +1,29 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [-1, 2] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [-1, 2], + [3, 2], + [3, 3], + [-1, 3], + [-1, 2] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/intersects/true/Polygon/LineString/Polygon-Containing-Linestring.geojson b/test/examples/booleans/intersects/true/Polygon/LineString/Polygon-Containing-Linestring.geojson new file mode 100644 index 00000000..a840dc09 --- /dev/null +++ b/test/examples/booleans/intersects/true/Polygon/LineString/Polygon-Containing-Linestring.geojson @@ -0,0 +1,32 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [-1, 2], + [3, 2], + [3, 3], + [-1, 3], + [-1, 2] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [1, 2.5], + [2, 2.5] + ] + } + } + ] +} diff --git a/test/examples/booleans/intersects/true/Polygon/LineString/Polygon-LineString.geojson b/test/examples/booleans/intersects/true/Polygon/LineString/Polygon-LineString.geojson new file mode 100644 index 00000000..83323524 --- /dev/null +++ b/test/examples/booleans/intersects/true/Polygon/LineString/Polygon-LineString.geojson @@ -0,0 +1,34 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [-1, 2], + [3, 2], + [3, 3], + [-1, 3], + [-1, 2] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [0, 2], + [12, 2], + [12, 3], + [12, 4] + ] + } + } + ] +} diff --git a/test/examples/booleans/intersects/true/Polygon/MultiPolygon/Polygon-MultiPolygon.geojson b/test/examples/booleans/intersects/true/Polygon/MultiPolygon/Polygon-MultiPolygon.geojson new file mode 100644 index 00000000..59b2a579 --- /dev/null +++ b/test/examples/booleans/intersects/true/Polygon/MultiPolygon/Polygon-MultiPolygon.geojson @@ -0,0 +1,52 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": { + "fill": "#0000ff" + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [119.20166015624999, -22.776181505086495], + [125.09033203124999, -22.776181505086495], + [125.09033203124999, -18.417078658661257], + [119.20166015624999, -18.417078658661257], + [119.20166015624999, -22.776181505086495] + ] + ] + } + }, + { + "type": "Feature", + "properties": { + "fill": "#ff0000" + }, + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + [ + [ + [122.6953125, -19.186677697957833], + [128.759765625, -19.186677697957833], + [128.759765625, -15.28418511407642], + [122.6953125, -15.28418511407642], + [122.6953125, -19.186677697957833] + ] + ], + [ + [ + [123.74999999999999, -25.918526162075153], + [130.25390625, -25.918526162075153], + [130.25390625, -20.715015145512087], + [123.74999999999999, -20.715015145512087], + [123.74999999999999, -25.918526162075153] + ] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/intersects/true/Polygon/Point/Polygon-Point.geojson b/test/examples/booleans/intersects/true/Polygon/Point/Polygon-Point.geojson new file mode 100644 index 00000000..c2131b4a --- /dev/null +++ b/test/examples/booleans/intersects/true/Polygon/Point/Polygon-Point.geojson @@ -0,0 +1,29 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [-1, 2], + [3, 2], + [3, 3], + [-1, 3], + [-1, 2] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [1, 2.5] + } + } + ] +} diff --git a/test/examples/booleans/intersects/true/Polygon/Polygon/Large-Inside-Small.geojson b/test/examples/booleans/intersects/true/Polygon/Polygon/Large-Inside-Small.geojson new file mode 100644 index 00000000..9a52b0dd --- /dev/null +++ b/test/examples/booleans/intersects/true/Polygon/Polygon/Large-Inside-Small.geojson @@ -0,0 +1,39 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [19.6875, 34.016241889667015], + [14.765625, 26.745610382199022], + [19.6875, 23.563987128451217], + [23.203125, 26.43122806450644], + [22.148437499999996, 30.44867367928756], + [19.6875, 34.016241889667015] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [18.984375, 40.44694705960048], + [7.03125, 25.48295117535531], + [19.335937499999996, 18.979025953255267], + [31.640625, 24.206889622398023], + [24.960937499999996, 34.88593094075317], + [18.984375, 40.44694705960048] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/intersects/true/Polygon/Polygon/Polygon-Polygon.geojson b/test/examples/booleans/intersects/true/Polygon/Polygon/Polygon-Polygon.geojson new file mode 100644 index 00000000..70b69b88 --- /dev/null +++ b/test/examples/booleans/intersects/true/Polygon/Polygon/Polygon-Polygon.geojson @@ -0,0 +1,37 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [-1, 2], + [-13, -12], + [-13, -13], + [-11, -13], + [-1, 2] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [-1, 2], + [3, 2], + [3, 3], + [-1, 3], + [-1, 2] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/intersects/true/Polygon/Polygon/Small-Inside-Large.geojson b/test/examples/booleans/intersects/true/Polygon/Polygon/Small-Inside-Large.geojson new file mode 100644 index 00000000..15e635f5 --- /dev/null +++ b/test/examples/booleans/intersects/true/Polygon/Polygon/Small-Inside-Large.geojson @@ -0,0 +1,39 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [18.984375, 40.44694705960048], + [7.03125, 25.48295117535531], + [19.335937499999996, 18.979025953255267], + [31.640625, 24.206889622398023], + [24.960937499999996, 34.88593094075317], + [18.984375, 40.44694705960048] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [19.6875, 34.016241889667015], + [14.765625, 26.745610382199022], + [19.6875, 23.563987128451217], + [23.203125, 26.43122806450644], + [22.148437499999996, 30.44867367928756], + [19.6875, 34.016241889667015] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/intersects/true/Polygon/Polygon/issue-1216.geojson b/test/examples/booleans/intersects/true/Polygon/Polygon/issue-1216.geojson new file mode 100644 index 00000000..41157c99 --- /dev/null +++ b/test/examples/booleans/intersects/true/Polygon/Polygon/issue-1216.geojson @@ -0,0 +1,49 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [6.638240782825051, 46.513552354874435], + [6.638240782825051, 46.52452567471025], + [6.632039186485088, 46.52452567471025], + [6.632039186485088, 46.513552354874435], + [6.638240782825051, 46.513552354874435] + ] + ] + }, + "bbox": [ + 6.632039186485088, + 46.513552354874435, + 6.638240782825051, + 46.52452567471025 + ] + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [6.645459572232596, 46.51709747623775], + [6.645459572232596, 46.52102619404951], + [6.626132904233913, 46.52102619404951], + [6.626132904233913, 46.51709747623775], + [6.645459572232596, 46.51709747623775] + ] + ] + }, + "bbox": [ + 6.626132904233913, + 46.51709747623775, + 6.645459572232596, + 46.52102619404951 + ] + } + ] +} From c45a922619ed078e5ad74672fa1a596551d53f75 Mon Sep 17 00:00:00 2001 From: armantorkzaban Date: Tue, 30 Aug 2022 09:56:19 +0200 Subject: [PATCH 54/82] progress on overlap --- lib/src/booleans/boolean_overlap.dart | 292 +++++++++----------------- test/booleans/overlap_test.dart | 139 +++++++++++- 2 files changed, 235 insertions(+), 196 deletions(-) diff --git a/lib/src/booleans/boolean_overlap.dart b/lib/src/booleans/boolean_overlap.dart index e9195943..4d919d5e 100644 --- a/lib/src/booleans/boolean_overlap.dart +++ b/lib/src/booleans/boolean_overlap.dart @@ -1,48 +1,42 @@ +import 'package:turf/helpers.dart'; +import 'package:turf/line_segment.dart'; +import 'package:turf/src/line_intersect.dart'; +import 'package:turf/src/line_overlap.dart'; import 'package:turf_equality/turf_equality.dart'; -import '../../helpers.dart'; -import '../../line_segment.dart'; -import '../invariant.dart'; -import '../line_intersect.dart'; -import '../line_overlap.dart'; - -/* - * Compares two geometries of the same dimension and returns true if their intersection set results in a geometry - * different from both but of the same dimension. It applies to Polygon/Polygon, LineString/LineString, - * Multipoint/Multipoint, MultiLineString/MultiLineString and MultiPolygon/MultiPolygon. - * - * In other words, it returns true if the two geometries overlap, provided that neither completely contains the other. - * - * @name booleanOverlap - * @param {Geometry|Feature} feature1 input - * @param {Geometry|Feature} feature2 input - * @returns {boolean} true/false - * @example - * var poly1 = turf.polygon([[[0,0],[0,5],[5,5],[5,0],[0,0]]]); - * var poly2 = turf.polygon([[[1,1],[1,6],[6,6],[6,1],[1,1]]]); - * var poly3 = turf.polygon([[[10,10],[10,15],[15,15],[15,10],[10,10]]]); - * - * turf.booleanOverlap(poly1, poly2) - * //=true - * turf.booleanOverlap(poly2, poly3) - * //=false - */ -booleanOverlap(GeometryObject feature1, GeometryObject feature2) { - var geom1 = getGeom(feature1); - var geom2 = getGeom(feature2); - var type1 = geom1.type; - var type2 = geom2.type; - - if ((type1 == MultiPoint && type2 != MultiPoint) || - ((type1 == LineString || type1 == MultiLineString) && - type2 != LineString && - type2 != MultiLineString) || - ((type1 == Polygon || type1 == MultiPolygon) && - type2 != Polygon && - type2 != MultiPolygon)) { +/// Compares two geometries of the same dimension and returns true if their intersection set results in a geometry +/// different from both but of the same dimension. It applies to Polygon/Polygon, LineString/LineString, +/// Multipoint/Multipoint, MultiLineString/MultiLineString and MultiPolygon/MultiPolygon. +/// +/// In other words, it returns true if the two geometries overlap, provided that neither completely contains the other. +/// +/// @name booleanOverlap +/// @param {Geometry|Feature} feature1 input +/// @param {Geometry|Feature} feature2 input +/// @returns {boolean} true/false +/// @example +/// var poly1 = turf.polygon([[[0,0],[0,5],[5,5],[5,0],[0,0]]]); +/// var poly2 = turf.polygon([[[1,1],[1,6],[6,6],[6,1],[1,1]]]); +/// var poly3 = turf.polygon([[[10,10],[10,15],[15,15],[15,10],[10,10]]]); +/// +/// turf.booleanOverlap(poly1, poly2) +/// //=true +/// turf.booleanOverlap(poly2, poly3) +/// //=false +bool booleanOverlap(GeoJSONObject feature1, GeoJSONObject feature2) { + var geom1 = feature1 is Feature ? feature1.geometry : feature1; + var geom2 = feature2 is Feature ? feature2.geometry : feature2; + + if ((feature1 is MultiPoint && feature2 is! MultiPoint) || + ((feature1 is LineString || feature1 is MultiLineString) && + feature2 is! LineString && + feature2 is! MultiLineString) || + ((feature1 is Polygon || feature1 is MultiPolygon) && + feature2 is! Polygon && + feature2 is! MultiPolygon)) { throw Exception("features must be of the same type"); } - if (type1 == Point) throw Exception("Point geometry not supported"); + if (feature1 is Point) throw Exception("Point geometry not supported"); // features must be not equal var equality = Equality(precision: 6); @@ -50,164 +44,72 @@ booleanOverlap(GeometryObject feature1, GeometryObject feature2) { var overlap = 0; - switch (type1) { - case MultiPoint: - for (var i = 0; i < (geom1 as MultiPoint).coordinates.length; i++) { - for (var j = 0; j < (geom2 as MultiPoint).coordinates.length; j++) { - var coord1 = geom1.coordinates[i]; - var coord2 = geom2.coordinates[j]; - if (coord1[0] == coord2[0] && coord1[1] == coord2[1]) { - return true; - } + if (feature1 is MultiPoint) { + for (var i = 0; i < (geom1 as MultiPoint).coordinates.length; i++) { + for (var j = 0; j < (geom2 as MultiPoint).coordinates.length; j++) { + var coord1 = geom1.coordinates[i]; + var coord2 = geom2.coordinates[j]; + if (coord1[0] == coord2[0] && coord1[1] == coord2[1]) { + return true; } } - return false; - - case LineString: - case MultiLineString: - segmentEach( - feature1, - ( - segment1, - featureIndex, - multiFeatureIndex, - geometryIndex, - segmentIndex, - ) { - segmentEach( - feature2, - ( - segment2, - featureIndex, - multiFeatureIndex, - geometryIndex, - segmentIndex, - ) { - if (lineOverlap(line1: segment1, line2: segment2) - .features - .length) { - overlap++; - } - }, - ); - }, - ); - break; - - case Polygon: - case MultiPolygon: - segmentEach(feature1, ( - segment1, - featureIndex, - multiFeatureIndex, - geometryIndex, - segmentIndex, + } + return false; + } else if (feature1 is MultiLineString) { + segmentEach( + feature1, + ( + Feature currentSegment, + int featureIndex, + int? multiFeatureIndex, + int? geometryIndex, + int segmentIndex, ) { - segmentEach(feature2, ( - segment2, - featureIndex, - multiFeatureIndex, - geometryIndex, - segmentIndex, - ) { - if (lineIntersect(segment1, segment2).features.isNotEmpty) overlap++; - }); - }); - break; - } - - return overlap > 0; -} - -/** - * import { Feature, Geometry, MultiPoint } from "geojson"; -import { segmentEach } from "@turf/meta"; -import { getGeom } from "@turf/invariant"; -import lineOverlap from "@turf/line-overlap"; -import lineIntersect from "@turf/line-intersect"; -import GeojsonEquality from "geojson-equality"; - -/** - * Compares two geometries of the same dimension and returns true if their intersection set results in a geometry - * different from both but of the same dimension. It applies to Polygon/Polygon, LineString/LineString, - * Multipoint/Multipoint, MultiLineString/MultiLineString and MultiPolygon/MultiPolygon. - * - * In other words, it returns true if the two geometries overlap, provided that neither completely contains the other. - * - * @name booleanOverlap - * @param {Geometry|Feature} feature1 input - * @param {Geometry|Feature} feature2 input - * @returns {boolean} true/false - * @example - * var poly1 = turf.polygon([[[0,0],[0,5],[5,5],[5,0],[0,0]]]); - * var poly2 = turf.polygon([[[1,1],[1,6],[6,6],[6,1],[1,1]]]); - * var poly3 = turf.polygon([[[10,10],[10,15],[15,15],[15,10],[10,10]]]); - * - * turf.booleanOverlap(poly1, poly2) - * //=true - * turf.booleanOverlap(poly2, poly3) - * //=false - */ -export default function booleanOverlap( - feature1: Feature | Geometry, - feature2: Feature | Geometry -): boolean { - const geom1 = getGeom(feature1); - const geom2 = getGeom(feature2); - const type1 = geom1.type; - const type2 = geom2.type; - - if ( - (type1 == "MultiPoint" && type2 !== "MultiPoint") || - ((type1 === "LineString" || type1 === "MultiLineString") && - type2 !== "LineString" && - type2 !== "MultiLineString") || - ((type1 === "Polygon" || type1 === "MultiPolygon") && - type2 !== "Polygon" && - type2 !== "MultiPolygon") - ) { - throw new Error("features must be of the same type"); - } - if (type1 === "Point") throw new Error("Point geometry not supported"); - - // features must be not equal - const equality = new GeojsonEquality({ precision: 6 }); - if (equality.compare(feature1 as any, feature2 as any)) return false; - - let overlap = 0; - - switch (type1) { - case "MultiPoint": - for (var i = 0; i < (geom1 as MultiPoint).coordinates.length; i++) { - for (var j = 0; j < (geom2 as MultiPoint).coordinates.length; j++) { - var coord1 = geom1.coordinates[i]; - var coord2 = geom2.coordinates[j]; - if (coord1[0] === coord2[0] && coord1[1] === coord2[1]) { - return true; - } - } - } - return false; - - case "LineString": - case "MultiLineString": - segmentEach(feature1, (segment1) => { - segmentEach(feature2, (segment2) => { - if (lineOverlap(segment1!, segment2!).features.length) overlap++; - }); - }); - break; - - case "Polygon": - case "MultiPolygon": - segmentEach(feature1, (segment1) => { - segmentEach(feature2, (segment2) => { - if (lineIntersect(segment1!, segment2!).features.length) overlap++; - }); - }); - break; + segmentEach( + feature2, + ( + Feature currentSegment1, + int featureIndex, + int? multiFeatureIndex, + int? geometryIndex, + int segmentIndex, + ) { + if (lineOverlap(line1: currentSegment, line2: currentSegment1) + .features + .length) overlap++; + }, + ); + }, + ); + } else if (feature1 is Polygon || feature1 is MultiPolygon) { + segmentEach( + feature1, + ( + Feature currentSegment, + int featureIndex, + int? multiFeatureIndex, + int? geometryIndex, + int segmentIndex, + ) { + segmentEach( + feature2, + ( + Feature currentSegment1, + int featureIndex, + int? multiFeatureIndex, + int? geometryIndex, + int segmentIndex, + ) { + if (lineIntersect(currentSegment, currentSegment1) + .features + .isNotEmpty) { + overlap++; + } + }, + ); + }, + ); } return overlap > 0; } - */ \ No newline at end of file diff --git a/test/booleans/overlap_test.dart b/test/booleans/overlap_test.dart index 45518ca5..ca9e2851 100644 --- a/test/booleans/overlap_test.dart +++ b/test/booleans/overlap_test.dart @@ -1,2 +1,139 @@ +const glob = require("glob"); +const path = require("path"); +const test = require("tape"); +const load = require("load-json-file"); +const shapely = require("boolean-shapely"); +const { + point, + lineString, + polygon, + multiLineString, + multiPolygon, +} = require("@turf/helpers"); +const overlap = require("./index").default; -/ \ No newline at end of file +test("turf-boolean-overlap", (t) => { + // True Fixtures + glob + .sync(path.join(__dirname, "test", "true", "**", "*.geojson")) + .forEach((filepath) => { + const name = path.parse(filepath).name; + const geojson = load.sync(filepath); + const feature1 = geojson.features[0]; + const feature2 = geojson.features[1]; + const result = overlap(feature1, feature2); + + if (process.env.SHAPELY) + shapely + .contains(feature1, feature2) + .then((result) => t.true(result, "[true] shapely - " + name)); + t.true(result, "[true] " + name); + }); + // False Fixtures + glob + .sync(path.join(__dirname, "test", "false", "**", "*.geojson")) + .forEach((filepath) => { + const name = path.parse(filepath).name; + const geojson = load.sync(filepath); + const feature1 = geojson.features[0]; + const feature2 = geojson.features[1]; + const result = overlap(feature1, feature2); + + if (process.env.SHAPELY) + shapely + .contains(feature1, feature2) + .then((result) => t.false(result, "[false] shapely - " + name)); + t.false(result, "[false] " + name); + }); + t.end(); +}); + +const pt = point([9, 50]); +const line1 = lineString([ + [7, 50], + [8, 50], + [9, 50], +]); +const line2 = lineString([ + [8, 50], + [9, 50], + [10, 50], +]); +const poly1 = polygon([ + [ + [8.5, 50], + [9.5, 50], + [9.5, 49], + [8.5, 49], + [8.5, 50], + ], +]); +const poly2 = polygon([ + [ + [8, 50], + [9, 50], + [9, 49], + [8, 49], + [8, 50], + ], +]); +const poly3 = polygon([ + [ + [10, 50], + [10.5, 50], + [10.5, 49], + [10, 49], + [10, 50], + ], +]); +const multiline1 = multiLineString([ + [ + [7, 50], + [8, 50], + [9, 50], + ], +]); +const multipoly1 = multiPolygon([ + [ + [ + [8.5, 50], + [9.5, 50], + [9.5, 49], + [8.5, 49], + [8.5, 50], + ], + ], +]); + +test("turf-boolean-overlap -- geometries", (t) => { + t.true(overlap(line1.geometry, line2.geometry), "[true] LineString geometry"); + t.true(overlap(poly1.geometry, poly2.geometry), "[true] Polygon geometry"); + t.false(overlap(poly1.geometry, poly3.geometry), "[false] Polygon geometry"); + t.end(); +}); + +test("turf-boolean-overlap -- throws", (t) => { + // t.throws(() => overlap(null, line1), /feature1 is required/, 'missing feature1'); + // t.throws(() => overlap(line1, null), /feature2 is required/, 'missing feature2'); + t.throws( + () => overlap(poly1, line1), + /features must be of the same type/, + "different types" + ); + t.throws( + () => overlap(pt, pt), + /Point geometry not supported/, + "geometry not supported" + ); + + t.doesNotThrow( + () => overlap(line1, multiline1), + "supports line and multiline comparison" + ); + t.doesNotThrow( + () => overlap(poly1, multipoly1), + "supports polygon and multipolygon comparison" + ); + + t.end(); +}); From 29dd77ba00bf02320e599f8330732ea1a88f2bac Mon Sep 17 00:00:00 2001 From: armantorkzaban Date: Wed, 31 Aug 2022 01:53:48 +0200 Subject: [PATCH 55/82] bool: overlap,parallel,valid,touches & lineOverlap --- lib/src/booleans/boolean_overlap.dart | 10 +- lib/src/booleans/boolean_parallel.dart | 141 +++--- lib/src/booleans/boolean_valid.dart | 22 +- lib/src/line_overlap.dart | 402 ++++++------------ pubspec.yaml | 1 + test/booleans/overlap_test.dart | 273 ++++++------ test/booleans/touches_test.dart | 60 ++- test/booleans/within_test.dart | 60 ++- test/components/line_overlap.dart | 90 ++++ .../overlap/false/equal-linear-rings.geojson | 31 ++ .../overlap/false/equal-lines.geojson | 31 ++ .../overlap/false/equal-multipoints.geojson | 33 ++ .../overlap/false/equal-polygons.geojson | 35 ++ .../overlap/false/linear-rings.geojson | 33 ++ .../booleans/overlap/false/lines.geojson | 32 ++ .../overlap/false/multipoints.geojson | 36 ++ .../false/polygon-with-hole-polygon.geojson | 45 ++ .../booleans/overlap/false/polygons.geojson | 37 ++ .../overlap/true/linear-rings.geojson | 33 ++ .../booleans/overlap/true/lines.geojson | 32 ++ .../booleans/overlap/true/multipoints.geojson | 36 ++ .../true/polygon-with-hole-polygon.geojson | 44 ++ .../booleans/overlap/true/polygons.geojson | 37 ++ .../overlap/true/simple-lines.geojson | 30 ++ .../overlap/true/single-multipoints.geojson | 36 ++ .../booleans/parallel/false/line1.geojson | 31 ++ .../booleans/parallel/false/line2.geojson | 31 ++ .../booleans/parallel/true/city-line.geojson | 29 ++ .../booleans/parallel/true/fiji.geojson | 31 ++ .../booleans/parallel/true/line1.geojson | 31 ++ .../parallel/true/line3-reverse.geojson | 31 ++ .../booleans/parallel/true/line3.geojson | 31 ++ .../booleans/parallel/true/resolute.geojson | 29 ++ .../booleans/parallel/true/segment1.geojson | 27 ++ .../booleans/parallel/true/segment2.geojson | 27 ++ .../booleans/parallel/true/segment3.geojson | 27 ++ .../LineString/LinesExactSame.geojson | 31 ++ .../LineString/LivesOverlap.geojson | 30 ++ .../LineStringOverlapsMultiLinestring.geojson | 37 ++ .../LineStringSameAsMultiLinestring.geojson | 39 ++ .../LineStringDoesNotTouchMP.geojson | 29 ++ ...StringTouchesMultiPointButInternal.geojson | 29 ++ .../LineDoesNotTouchMultiPoly.geojson | 43 ++ .../Polygon/LineCrossesPolygon.geojson | 32 ++ .../Polygon/LineDoesNotTouch.geojson | 32 ++ .../Polygon/LineWIthinPolygon.geojson | 33 ++ .../MultiLineStringOverlapsLine.geojson | 37 ++ .../MultiLineStringSameAsLine.geojson | 39 ++ .../MultiLineStringsOverlap.geojson | 39 ++ .../MultiLineStringsSame.geojson | 41 ++ .../MpTouchesInternalMultiline.geojson | 37 ++ .../MultiPointNotTouchMultiline.geojson | 37 ++ .../MultiLineInsideMultipoly.geojson | 53 +++ .../PointNotTouchMultiLinestring.geojson | 34 ++ .../Point/PointTouchesMidLineString.geojson | 34 ++ .../Polygon/MultiLineInsidePoly.geojson | 42 ++ .../Polygon/MultiLineNotTouchPoly.geojson | 42 ++ .../MultiPointTouchesInsideLine.geojson | 29 ++ .../MultipointDoesNotTouchLine.geojson | 29 ++ .../MpDoesNotTouchMultiLine.geojson | 37 ++ .../MpTouchesInternalMultiLine.geojson | 37 ++ .../MultiPointDoesNotTouchMultipolygon | 24 ++ .../multipoint-inside-multipolygon.geojson | 43 ++ .../Polygon/MultiPointInsidePolygon.geojson | 33 ++ .../Polygon/MultiPointNoTouchPolygon.geojson | 32 ++ .../MultiPolyNotTouchLineString.geojson | 43 ++ .../MultiPolyOverlapsMultiLine.geojson | 53 +++ .../MultiPolyNotTouchMultiPoint.geojson | 43 ++ .../MultiPolygon/MultiPolysDoNotTouch.geojson | 50 +++ .../MultiPolygon/MultiPolysOverlap.geojson | 50 +++ .../Point/MultiPolyNotTouchPoint.geojson | 40 ++ .../LineString/PointIsNotTouchLine.geojson | 26 ++ .../LineString/PointOnMidLinestring.geojson | 26 ++ .../MpNotTouchMidLineString.geojson | 34 ++ .../MultiLineString/MpOnMidLineString.geojson | 34 ++ .../PointNotTouchMultipolygon.geojson | 40 ++ .../Polygon/PointDoesNotTouchPolygon.geojson | 29 ++ .../Point/Polygon/PointInsidePolygon.geojson | 29 ++ .../LineString/PolyDoesNotTouchLine.geojson | 32 ++ .../PolyNotTouchMultiLine.geojson | 42 ++ .../PolyOverlapMultiLine.geojson | 42 ++ .../PolygonNoTouchMultiPoint.geojson | 32 ++ .../PolygonOverlapsMultiPoint.geojson | 33 ++ .../PolyNotTouchMultipoly.geojson | 48 +++ .../Point/PolygonDoesNotTouchPoint.geojson | 29 ++ .../Point/PolygonOverlapsPoint.geojson | 29 ++ .../Polygon/Polygon/PolygonsDontTouch.geojson | 37 ++ .../Polygon/Polygon/PolygonsOverlap.geojson | 37 ++ .../LineString/LineTouchesEndpoint.geojson | 28 ++ .../LineStringTouchesEnd.geojson | 37 ++ .../LineStringTouchesStart.geojson | 37 ++ .../MultiPoint/MultipointTouchesLine.geojson | 30 ++ .../MultiPolygon/LineTouchesMultiPoly.geojson | 43 ++ .../LineTouchesSecondMultiPoly.geojson | 43 ++ .../Polygon/LineTouchesPolygon.geojson | 33 ++ .../LineString/MultiLineTouchesLine.geojson | 37 ++ .../MultiLineTouchesMultiLine.geojson | 43 ++ .../MultiLineTouchesMultiPoint.geojson | 37 ++ .../Point/MultiLineTouchesPoint.geojson | 34 ++ .../Polygon/MultiLineTouchesPolygon.geojson | 42 ++ .../LineString/MultipointTouchesLine.geojson | 30 ++ .../MpTouchesEndMultiLine.geojson | 37 ++ .../MpTouchesSecondMultiLine.geojson | 37 ++ .../multipoint-touches-multipolygon.geojson | 43 ++ .../Polygon/MultiPointIsWithinPolygon.geojson | 32 ++ .../MultiLineTouchesMultiPoly.geojson | 53 +++ .../MultiPolyTouchesMultiPoint.geojson | 34 ++ .../MultiPolyTouchesMultiPoly.geojson | 50 +++ .../MultiPolygon/Point/MpTouchesPoint.geojson | 31 ++ .../Polygon/MultiPolyTouchesPoly.geojson | 48 +++ .../Point/LineString/PointOnEndLine.geojson | 26 ++ .../Point/LineString/PointOnStartLine.geojson | 26 ++ .../Point/MultiLineString/MpOnEndLine.geojson | 34 ++ .../MultiLineString/MpOnStartLine.geojson | 34 ++ .../PointTouchesMultipolygon.geojson | 40 ++ .../PointTouchesMultipolygonHole.geojson | 46 ++ .../Point/Polygon/PointOnEdgePolygon.geojson | 29 ++ .../true/Point/Polygon/PointOnHole.geojson | 35 ++ .../Polygon/PointOnVerticePolygon.geojson | 29 ++ .../LineString/PolygonTouchesLines.geojson | 33 ++ .../PolygonTouchesMultiline.geojson | 42 ++ .../PolygonTouchesMultiPoint.geojson | 32 ++ .../MultiPolygon/PolyTouchMultiPolys.geojson | 48 +++ .../Polygon/Point/PolygonTouchesPoint.geojson | 29 ++ .../Point/PolygonTouchesPointVertice.geojson | 29 ++ .../Polygon/PolygonTouchesEdges.geojson | 37 ++ .../Polygon/PolygonsTouchVertices.geojson | 37 ++ .../LineString/LineIsNotWithinLine.geojson | 30 ++ .../Polygon/LineIsNotWIthinPolygon.geojson | 33 ++ .../LineIsNotWIthinPolygonBoundary.geojson | 33 ++ ...linestring-not-within-multipolygon.geojson | 49 +++ .../MultiPointsIsNotWIthinLine.geojson | 30 ++ ...ltiPointsOnLineEndsIsNotWIthinLine.geojson | 29 ++ .../MultiPointIsNotWithinMultiPoint.geojson | 28 ++ ...multipoint-not-within-multipolygon.geojson | 43 ++ ...intAllOnBoundaryIsNotWithinPolygon.geojson | 32 ++ .../MultiPointIsNotWithinPolygon.geojson | 33 ++ .../LineString/PointIsNotWithinLine.geojson | 26 ++ .../PointIsNotWithinLineBecauseOnEnd.geojson | 26 ++ .../PointOnEndIsWithinLinestring.geojson | 26 ++ .../PointIsNotWithinMultiPoint.geojson | 24 ++ .../point-not-within-multipolygon.geojson | 40 ++ .../Polygon/PointIsNotWithinPolygon.geojson | 29 ++ .../Polygon/PointOnPolygonBoundary.geojson | 29 ++ .../polygon-not-within-multipolygon.geojson | 48 +++ .../Polygon/Polygon/Polygon-Polygon.geojson | 37 ++ .../LineString/LineIsWithinLine.geojson | 30 ++ .../LineString/LinesExactSame.geojson | 31 ++ .../Polygon/LineIsContainedByPolygon.geojson | 33 ++ ...nedByPolygonWithNoInternalVertices.geojson | 32 ++ ...ultilinestring-within-multipolygon.geojson | 49 +++ .../MultipointsIsWithinLine.geojson | 29 ++ .../MultiPointsWithinMultiPoints.geojson | 29 ++ .../multipoint-within-multipolygon.geojson | 43 ++ .../Polygon/MultiPointIsWithinPolygon.geojson | 32 ++ .../MultiPointSingleIsWithinPolygon.geojson | 29 ++ ...p-multipolygon-within-multipolygon.geojson | 59 +++ .../LineString/PointIsWithinLine.geojson | 26 ++ .../PointIsWithinMultiPoint.geojson | 24 ++ .../point-within-multipolygon.geojson | 40 ++ .../Polygon/PointIsWithinPolygon.geojson | 29 ++ .../polygon-within-multipolygon.geojson | 48 +++ .../Polygon/PolygonIsWIthinPolygon.geojson | 36 ++ .../Polygon/PolygonsExactSameShape.geojson | 41 ++ .../in/boolean-line-overlap.geojson | 32 ++ .../in/issue-#901-simplified.geojson | 35 ++ .../line_overlap/in/issue-#901.geojson | 77 ++++ .../examples/line_overlap/in/polygons.geojson | 65 +++ test/examples/line_overlap/in/simple1.geojson | 40 ++ test/examples/line_overlap/in/simple2.geojson | 39 ++ test/examples/line_overlap/in/simple3.geojson | 38 ++ .../out/boolean-line-overlap.geojson | 32 ++ .../out/issue-#901-simplified.geojson | 52 +++ .../line_overlap/out/issue-#901.geojson | 170 ++++++++ .../line_overlap/out/polygons.geojson | 99 +++++ .../examples/line_overlap/out/simple1.geojson | 56 +++ .../examples/line_overlap/out/simple2.geojson | 55 +++ .../examples/line_overlap/out/simple3.geojson | 54 +++ 178 files changed, 6881 insertions(+), 490 deletions(-) create mode 100644 test/components/line_overlap.dart create mode 100644 test/examples/booleans/overlap/false/equal-linear-rings.geojson create mode 100644 test/examples/booleans/overlap/false/equal-lines.geojson create mode 100644 test/examples/booleans/overlap/false/equal-multipoints.geojson create mode 100644 test/examples/booleans/overlap/false/equal-polygons.geojson create mode 100644 test/examples/booleans/overlap/false/linear-rings.geojson create mode 100644 test/examples/booleans/overlap/false/lines.geojson create mode 100644 test/examples/booleans/overlap/false/multipoints.geojson create mode 100644 test/examples/booleans/overlap/false/polygon-with-hole-polygon.geojson create mode 100644 test/examples/booleans/overlap/false/polygons.geojson create mode 100644 test/examples/booleans/overlap/true/linear-rings.geojson create mode 100644 test/examples/booleans/overlap/true/lines.geojson create mode 100644 test/examples/booleans/overlap/true/multipoints.geojson create mode 100644 test/examples/booleans/overlap/true/polygon-with-hole-polygon.geojson create mode 100644 test/examples/booleans/overlap/true/polygons.geojson create mode 100644 test/examples/booleans/overlap/true/simple-lines.geojson create mode 100644 test/examples/booleans/overlap/true/single-multipoints.geojson create mode 100644 test/examples/booleans/parallel/false/line1.geojson create mode 100644 test/examples/booleans/parallel/false/line2.geojson create mode 100644 test/examples/booleans/parallel/true/city-line.geojson create mode 100644 test/examples/booleans/parallel/true/fiji.geojson create mode 100644 test/examples/booleans/parallel/true/line1.geojson create mode 100644 test/examples/booleans/parallel/true/line3-reverse.geojson create mode 100644 test/examples/booleans/parallel/true/line3.geojson create mode 100644 test/examples/booleans/parallel/true/resolute.geojson create mode 100644 test/examples/booleans/parallel/true/segment1.geojson create mode 100644 test/examples/booleans/parallel/true/segment2.geojson create mode 100644 test/examples/booleans/parallel/true/segment3.geojson create mode 100644 test/examples/booleans/touches/false/LineString/LineString/LinesExactSame.geojson create mode 100644 test/examples/booleans/touches/false/LineString/LineString/LivesOverlap.geojson create mode 100644 test/examples/booleans/touches/false/LineString/MultiLineString/LineStringOverlapsMultiLinestring.geojson create mode 100644 test/examples/booleans/touches/false/LineString/MultiLineString/LineStringSameAsMultiLinestring.geojson create mode 100644 test/examples/booleans/touches/false/LineString/MultiPoint/LineStringDoesNotTouchMP.geojson create mode 100644 test/examples/booleans/touches/false/LineString/MultiPoint/LineStringTouchesMultiPointButInternal.geojson create mode 100644 test/examples/booleans/touches/false/LineString/MultiPolygon/LineDoesNotTouchMultiPoly.geojson create mode 100644 test/examples/booleans/touches/false/LineString/Polygon/LineCrossesPolygon.geojson create mode 100644 test/examples/booleans/touches/false/LineString/Polygon/LineDoesNotTouch.geojson create mode 100644 test/examples/booleans/touches/false/LineString/Polygon/LineWIthinPolygon.geojson create mode 100644 test/examples/booleans/touches/false/MultiLineString/LineString/MultiLineStringOverlapsLine.geojson create mode 100644 test/examples/booleans/touches/false/MultiLineString/LineString/MultiLineStringSameAsLine.geojson create mode 100644 test/examples/booleans/touches/false/MultiLineString/MultiLineString/MultiLineStringsOverlap.geojson create mode 100644 test/examples/booleans/touches/false/MultiLineString/MultiLineString/MultiLineStringsSame.geojson create mode 100644 test/examples/booleans/touches/false/MultiLineString/MultiPoint/MpTouchesInternalMultiline.geojson create mode 100644 test/examples/booleans/touches/false/MultiLineString/MultiPoint/MultiPointNotTouchMultiline.geojson create mode 100644 test/examples/booleans/touches/false/MultiLineString/MultiPolygon/MultiLineInsideMultipoly.geojson create mode 100644 test/examples/booleans/touches/false/MultiLineString/Point/PointNotTouchMultiLinestring.geojson create mode 100644 test/examples/booleans/touches/false/MultiLineString/Point/PointTouchesMidLineString.geojson create mode 100644 test/examples/booleans/touches/false/MultiLineString/Polygon/MultiLineInsidePoly.geojson create mode 100644 test/examples/booleans/touches/false/MultiLineString/Polygon/MultiLineNotTouchPoly.geojson create mode 100644 test/examples/booleans/touches/false/MultiPoint/LineString/MultiPointTouchesInsideLine.geojson create mode 100644 test/examples/booleans/touches/false/MultiPoint/LineString/MultipointDoesNotTouchLine.geojson create mode 100644 test/examples/booleans/touches/false/MultiPoint/MultiLineString/MpDoesNotTouchMultiLine.geojson create mode 100644 test/examples/booleans/touches/false/MultiPoint/MultiLineString/MpTouchesInternalMultiLine.geojson create mode 100644 test/examples/booleans/touches/false/MultiPoint/MultiPolygon/MultiPointDoesNotTouchMultipolygon create mode 100644 test/examples/booleans/touches/false/MultiPoint/MultiPolygon/multipoint-inside-multipolygon.geojson create mode 100644 test/examples/booleans/touches/false/MultiPoint/Polygon/MultiPointInsidePolygon.geojson create mode 100644 test/examples/booleans/touches/false/MultiPoint/Polygon/MultiPointNoTouchPolygon.geojson create mode 100644 test/examples/booleans/touches/false/MultiPolygon/LineString/MultiPolyNotTouchLineString.geojson create mode 100644 test/examples/booleans/touches/false/MultiPolygon/MultiLineString/MultiPolyOverlapsMultiLine.geojson create mode 100644 test/examples/booleans/touches/false/MultiPolygon/MultiPoint/MultiPolyNotTouchMultiPoint.geojson create mode 100644 test/examples/booleans/touches/false/MultiPolygon/MultiPolygon/MultiPolysDoNotTouch.geojson create mode 100644 test/examples/booleans/touches/false/MultiPolygon/MultiPolygon/MultiPolysOverlap.geojson create mode 100644 test/examples/booleans/touches/false/MultiPolygon/Point/MultiPolyNotTouchPoint.geojson create mode 100644 test/examples/booleans/touches/false/Point/LineString/PointIsNotTouchLine.geojson create mode 100644 test/examples/booleans/touches/false/Point/LineString/PointOnMidLinestring.geojson create mode 100644 test/examples/booleans/touches/false/Point/MultiLineString/MpNotTouchMidLineString.geojson create mode 100644 test/examples/booleans/touches/false/Point/MultiLineString/MpOnMidLineString.geojson create mode 100644 test/examples/booleans/touches/false/Point/MultiPolygon/PointNotTouchMultipolygon.geojson create mode 100644 test/examples/booleans/touches/false/Point/Polygon/PointDoesNotTouchPolygon.geojson create mode 100644 test/examples/booleans/touches/false/Point/Polygon/PointInsidePolygon.geojson create mode 100644 test/examples/booleans/touches/false/Polygon/LineString/PolyDoesNotTouchLine.geojson create mode 100644 test/examples/booleans/touches/false/Polygon/MultiLineString/PolyNotTouchMultiLine.geojson create mode 100644 test/examples/booleans/touches/false/Polygon/MultiLineString/PolyOverlapMultiLine.geojson create mode 100644 test/examples/booleans/touches/false/Polygon/MultiPoint/PolygonNoTouchMultiPoint.geojson create mode 100644 test/examples/booleans/touches/false/Polygon/MultiPoint/PolygonOverlapsMultiPoint.geojson create mode 100644 test/examples/booleans/touches/false/Polygon/MultiPolygon/PolyNotTouchMultipoly.geojson create mode 100644 test/examples/booleans/touches/false/Polygon/Point/PolygonDoesNotTouchPoint.geojson create mode 100644 test/examples/booleans/touches/false/Polygon/Point/PolygonOverlapsPoint.geojson create mode 100644 test/examples/booleans/touches/false/Polygon/Polygon/PolygonsDontTouch.geojson create mode 100644 test/examples/booleans/touches/false/Polygon/Polygon/PolygonsOverlap.geojson create mode 100644 test/examples/booleans/touches/true/LineString/LineString/LineTouchesEndpoint.geojson create mode 100644 test/examples/booleans/touches/true/LineString/MultiLineString/LineStringTouchesEnd.geojson create mode 100644 test/examples/booleans/touches/true/LineString/MultiLineString/LineStringTouchesStart.geojson create mode 100644 test/examples/booleans/touches/true/LineString/MultiPoint/MultipointTouchesLine.geojson create mode 100644 test/examples/booleans/touches/true/LineString/MultiPolygon/LineTouchesMultiPoly.geojson create mode 100644 test/examples/booleans/touches/true/LineString/MultiPolygon/LineTouchesSecondMultiPoly.geojson create mode 100644 test/examples/booleans/touches/true/LineString/Polygon/LineTouchesPolygon.geojson create mode 100644 test/examples/booleans/touches/true/MultiLineString/LineString/MultiLineTouchesLine.geojson create mode 100644 test/examples/booleans/touches/true/MultiLineString/MultiLineString/MultiLineTouchesMultiLine.geojson create mode 100644 test/examples/booleans/touches/true/MultiLineString/MultiPoint/MultiLineTouchesMultiPoint.geojson create mode 100644 test/examples/booleans/touches/true/MultiLineString/Point/MultiLineTouchesPoint.geojson create mode 100644 test/examples/booleans/touches/true/MultiLineString/Polygon/MultiLineTouchesPolygon.geojson create mode 100644 test/examples/booleans/touches/true/MultiPoint/LineString/MultipointTouchesLine.geojson create mode 100644 test/examples/booleans/touches/true/MultiPoint/MultiLineString/MpTouchesEndMultiLine.geojson create mode 100644 test/examples/booleans/touches/true/MultiPoint/MultiLineString/MpTouchesSecondMultiLine.geojson create mode 100644 test/examples/booleans/touches/true/MultiPoint/MultiPolygon/multipoint-touches-multipolygon.geojson create mode 100644 test/examples/booleans/touches/true/MultiPoint/Polygon/MultiPointIsWithinPolygon.geojson create mode 100644 test/examples/booleans/touches/true/MultiPolygon/MultiLineString/MultiLineTouchesMultiPoly.geojson create mode 100644 test/examples/booleans/touches/true/MultiPolygon/MultiPoint/MultiPolyTouchesMultiPoint.geojson create mode 100644 test/examples/booleans/touches/true/MultiPolygon/MultiPolygon/MultiPolyTouchesMultiPoly.geojson create mode 100644 test/examples/booleans/touches/true/MultiPolygon/Point/MpTouchesPoint.geojson create mode 100644 test/examples/booleans/touches/true/MultiPolygon/Polygon/MultiPolyTouchesPoly.geojson create mode 100644 test/examples/booleans/touches/true/Point/LineString/PointOnEndLine.geojson create mode 100644 test/examples/booleans/touches/true/Point/LineString/PointOnStartLine.geojson create mode 100644 test/examples/booleans/touches/true/Point/MultiLineString/MpOnEndLine.geojson create mode 100644 test/examples/booleans/touches/true/Point/MultiLineString/MpOnStartLine.geojson create mode 100644 test/examples/booleans/touches/true/Point/MultiPolygon/PointTouchesMultipolygon.geojson create mode 100644 test/examples/booleans/touches/true/Point/MultiPolygon/PointTouchesMultipolygonHole.geojson create mode 100644 test/examples/booleans/touches/true/Point/Polygon/PointOnEdgePolygon.geojson create mode 100644 test/examples/booleans/touches/true/Point/Polygon/PointOnHole.geojson create mode 100644 test/examples/booleans/touches/true/Point/Polygon/PointOnVerticePolygon.geojson create mode 100644 test/examples/booleans/touches/true/Polygon/LineString/PolygonTouchesLines.geojson create mode 100644 test/examples/booleans/touches/true/Polygon/MultiLineString/PolygonTouchesMultiline.geojson create mode 100644 test/examples/booleans/touches/true/Polygon/MultiPoint/PolygonTouchesMultiPoint.geojson create mode 100644 test/examples/booleans/touches/true/Polygon/MultiPolygon/PolyTouchMultiPolys.geojson create mode 100644 test/examples/booleans/touches/true/Polygon/Point/PolygonTouchesPoint.geojson create mode 100644 test/examples/booleans/touches/true/Polygon/Point/PolygonTouchesPointVertice.geojson create mode 100644 test/examples/booleans/touches/true/Polygon/Polygon/PolygonTouchesEdges.geojson create mode 100644 test/examples/booleans/touches/true/Polygon/Polygon/PolygonsTouchVertices.geojson create mode 100644 test/examples/booleans/within/false/LineString/LineString/LineIsNotWithinLine.geojson create mode 100644 test/examples/booleans/within/false/LineString/Polygon/LineIsNotWIthinPolygon.geojson create mode 100644 test/examples/booleans/within/false/LineString/Polygon/LineIsNotWIthinPolygonBoundary.geojson create mode 100644 test/examples/booleans/within/false/MultiLineString/MultiPolygon/skip-multilinestring-not-within-multipolygon.geojson create mode 100644 test/examples/booleans/within/false/MultiPoint/LineString/MultiPointsIsNotWIthinLine.geojson create mode 100644 test/examples/booleans/within/false/MultiPoint/LineString/MultiPointsOnLineEndsIsNotWIthinLine.geojson create mode 100644 test/examples/booleans/within/false/MultiPoint/MultiPoint/MultiPointIsNotWithinMultiPoint.geojson create mode 100644 test/examples/booleans/within/false/MultiPoint/MultiPolygon/multipoint-not-within-multipolygon.geojson create mode 100644 test/examples/booleans/within/false/MultiPoint/Polygon/MultiPointAllOnBoundaryIsNotWithinPolygon.geojson create mode 100644 test/examples/booleans/within/false/MultiPoint/Polygon/MultiPointIsNotWithinPolygon.geojson create mode 100644 test/examples/booleans/within/false/Point/LineString/PointIsNotWithinLine.geojson create mode 100644 test/examples/booleans/within/false/Point/LineString/PointIsNotWithinLineBecauseOnEnd.geojson create mode 100644 test/examples/booleans/within/false/Point/LineString/PointOnEndIsWithinLinestring.geojson create mode 100644 test/examples/booleans/within/false/Point/MultiPoint/PointIsNotWithinMultiPoint.geojson create mode 100644 test/examples/booleans/within/false/Point/MultiPolygon/point-not-within-multipolygon.geojson create mode 100644 test/examples/booleans/within/false/Point/Polygon/PointIsNotWithinPolygon.geojson create mode 100644 test/examples/booleans/within/false/Point/Polygon/PointOnPolygonBoundary.geojson create mode 100644 test/examples/booleans/within/false/Polygon/MultiPolygon/polygon-not-within-multipolygon.geojson create mode 100644 test/examples/booleans/within/false/Polygon/Polygon/Polygon-Polygon.geojson create mode 100644 test/examples/booleans/within/true/LineString/LineString/LineIsWithinLine.geojson create mode 100644 test/examples/booleans/within/true/LineString/LineString/LinesExactSame.geojson create mode 100644 test/examples/booleans/within/true/LineString/Polygon/LineIsContainedByPolygon.geojson create mode 100644 test/examples/booleans/within/true/LineString/Polygon/LineIsContainedByPolygonWithNoInternalVertices.geojson create mode 100644 test/examples/booleans/within/true/MultiLineString/MultiPolygon/skip-multilinestring-within-multipolygon.geojson create mode 100644 test/examples/booleans/within/true/MultiPoint/LineString/MultipointsIsWithinLine.geojson create mode 100644 test/examples/booleans/within/true/MultiPoint/MultiPoint/MultiPointsWithinMultiPoints.geojson create mode 100644 test/examples/booleans/within/true/MultiPoint/MultiPolygon/multipoint-within-multipolygon.geojson create mode 100644 test/examples/booleans/within/true/MultiPoint/Polygon/MultiPointIsWithinPolygon.geojson create mode 100644 test/examples/booleans/within/true/MultiPoint/Polygon/MultiPointSingleIsWithinPolygon.geojson create mode 100644 test/examples/booleans/within/true/MultiPolygon/MultiPolygon/skip-multipolygon-within-multipolygon.geojson create mode 100644 test/examples/booleans/within/true/Point/LineString/PointIsWithinLine.geojson create mode 100644 test/examples/booleans/within/true/Point/MultiPoint/PointIsWithinMultiPoint.geojson create mode 100644 test/examples/booleans/within/true/Point/MultiPolygon/point-within-multipolygon.geojson create mode 100644 test/examples/booleans/within/true/Point/Polygon/PointIsWithinPolygon.geojson create mode 100644 test/examples/booleans/within/true/Polygon/MultiPolygon/polygon-within-multipolygon.geojson create mode 100644 test/examples/booleans/within/true/Polygon/Polygon/PolygonIsWIthinPolygon.geojson create mode 100644 test/examples/booleans/within/true/Polygon/Polygon/PolygonsExactSameShape.geojson create mode 100644 test/examples/line_overlap/in/boolean-line-overlap.geojson create mode 100644 test/examples/line_overlap/in/issue-#901-simplified.geojson create mode 100644 test/examples/line_overlap/in/issue-#901.geojson create mode 100644 test/examples/line_overlap/in/polygons.geojson create mode 100644 test/examples/line_overlap/in/simple1.geojson create mode 100644 test/examples/line_overlap/in/simple2.geojson create mode 100644 test/examples/line_overlap/in/simple3.geojson create mode 100644 test/examples/line_overlap/out/boolean-line-overlap.geojson create mode 100644 test/examples/line_overlap/out/issue-#901-simplified.geojson create mode 100644 test/examples/line_overlap/out/issue-#901.geojson create mode 100644 test/examples/line_overlap/out/polygons.geojson create mode 100644 test/examples/line_overlap/out/simple1.geojson create mode 100644 test/examples/line_overlap/out/simple2.geojson create mode 100644 test/examples/line_overlap/out/simple3.geojson diff --git a/lib/src/booleans/boolean_overlap.dart b/lib/src/booleans/boolean_overlap.dart index 4d919d5e..b47ad1f1 100644 --- a/lib/src/booleans/boolean_overlap.dart +++ b/lib/src/booleans/boolean_overlap.dart @@ -40,7 +40,9 @@ bool booleanOverlap(GeoJSONObject feature1, GeoJSONObject feature2) { // features must be not equal var equality = Equality(precision: 6); - if (equality.compare(feature1, feature2)) return false; + if (equality.compare(feature1, feature2)) { + return false; + } var overlap = 0; @@ -74,9 +76,11 @@ bool booleanOverlap(GeoJSONObject feature1, GeoJSONObject feature2) { int? geometryIndex, int segmentIndex, ) { - if (lineOverlap(line1: currentSegment, line2: currentSegment1) + if (lineOverlap(currentSegment, currentSegment1) .features - .length) overlap++; + .isNotEmpty) { + overlap++; + } }, ); }, diff --git a/lib/src/booleans/boolean_parallel.dart b/lib/src/booleans/boolean_parallel.dart index 8153ebbd..26411b5b 100644 --- a/lib/src/booleans/boolean_parallel.dart +++ b/lib/src/booleans/boolean_parallel.dart @@ -4,12 +4,13 @@ import '../../helpers.dart'; import '../../line_segment.dart'; import '../clean_coords.dart'; -/// Returns True if each segment of `line1` is parallel to the correspondent segment of `line2` +/// Returns [true] if each segment of `line1` is parallel to the correspondent segment of `line2` /// example: /// ```dart /// var line1 = LineString(coordinates:[Position.of([0, 0]), Position.of([0, 1])]); /// var line2 = LineString(coordinates:[Position.of([1, 0]), Position.of([1, 1])]); /// booleanParallel(line1, line2); +/// ``` /// //=true bool booleanParallel(GeoJSONObject line1, GeoJSONObject line2) { var type1 = _getType(line1, "line1"); @@ -33,8 +34,6 @@ bool booleanParallel(GeoJSONObject line1, GeoJSONObject line2) { } /// Compares slopes and returns result -/// @param {Geometry|Feature} segment1 Geometry or Feature -/// @param {Geometry|Feature} segment2 Geometry or Feature bool _isParallel(List segment1, List segment2) { var slope1 = bearingToAzimuth(rhumbBearing( Point(coordinates: segment1[0]), Point(coordinates: segment1[1]))); @@ -55,77 +54,77 @@ GeoJSONObjectType _getType(GeoJSONObject geojson, String name) { } -{ Feature, Geometry, LineString, Position } from "geojson"; -import cleanCoords from "@turf/clean-coords"; -import lineSegment from "@turf/line-segment"; -import rhumbBearing from "@turf/rhumb-bearing"; -import { bearingToAzimuth } from "@turf/helpers"; +// { Feature, Geometry, LineString, Position } from "geojson"; +// import cleanCoords from "@turf/clean-coords"; +// import lineSegment from "@turf/line-segment"; +// import rhumbBearing from "@turf/rhumb-bearing"; +// import { bearingToAzimuth } from "@turf/helpers"; -/** - * Boolean-Parallel returns True if each segment of `line1` is parallel to the correspondent segment of `line2` - * - * @name booleanParallel - * @param {Geometry|Feature} line1 GeoJSON Feature or Geometry - * @param {Geometry|Feature} line2 GeoJSON Feature or Geometry - * @returns {boolean} true/false if the lines are parallel - * @example - * var line1 = turf.lineString([[0, 0], [0, 1]]); - * var line2 = turf.lineString([[1, 0], [1, 1]]); - * - * turf.booleanParallel(line1, line2); - * //=true - */ - booleanParallel( - line1: Feature | LineString, - line2: Feature | LineString -): boolean { - // validation - if (!line1) throw new Error("line1 is required"); - if (!line2) throw new Error("line2 is required"); - var type1 = getType(line1, "line1"); - if (type1 !== "LineString") throw new Error("line1 must be a LineString"); - var type2 = getType(line2, "line2"); - if (type2 !== "LineString") throw new Error("line2 must be a LineString"); +// /** +// * Boolean-Parallel returns True if each segment of `line1` is parallel to the correspondent segment of `line2` +// * +// * @name booleanParallel +// * @param {Geometry|Feature} line1 GeoJSON Feature or Geometry +// * @param {Geometry|Feature} line2 GeoJSON Feature or Geometry +// * @returns {boolean} true/false if the lines are parallel +// * @example +// * var line1 = turf.lineString([[0, 0], [0, 1]]); +// * var line2 = turf.lineString([[1, 0], [1, 1]]); +// * +// * turf.booleanParallel(line1, line2); +// * //=true +// */ +// booleanParallel( +// line1: Feature | LineString, +// line2: Feature | LineString +// ): boolean { +// // validation +// if (!line1) throw new Error("line1 is required"); +// if (!line2) throw new Error("line2 is required"); +// var type1 = getType(line1, "line1"); +// if (type1 !== "LineString") throw new Error("line1 must be a LineString"); +// var type2 = getType(line2, "line2"); +// if (type2 !== "LineString") throw new Error("line2 must be a LineString"); - var segments1 = lineSegment(cleanCoords(line1)).features; - var segments2 = lineSegment(cleanCoords(line2)).features; +// var segments1 = lineSegment(cleanCoords(line1)).features; +// var segments2 = lineSegment(cleanCoords(line2)).features; - for (var i = 0; i < segments1.length; i++) { - var segment1 = segments1[i].geometry.coordinates; - if (!segments2[i]) break; - var segment2 = segments2[i].geometry.coordinates; - if (!isParallel(segment1, segment2)) return false; - } - return true; -} +// for (var i = 0; i < segments1.length; i++) { +// var segment1 = segments1[i].geometry.coordinates; +// if (!segments2[i]) break; +// var segment2 = segments2[i].geometry.coordinates; +// if (!isParallel(segment1, segment2)) return false; +// } +// return true; +// } -/** - * Compares slopes and return result - * - * @private - * @param {Geometry|Feature} segment1 Geometry or Feature - * @param {Geometry|Feature} segment2 Geometry or Feature - * @returns {boolean} if slopes are equal - */ -function isParallel(segment1: Position[], segment2: Position[]) { - var slope1 = bearingToAzimuth(rhumbBearing(segment1[0], segment1[1])); - var slope2 = bearingToAzimuth(rhumbBearing(segment2[0], segment2[1])); - return slope1 === slope2; -} +// /** +// * Compares slopes and return result +// * +// * @private +// * @param {Geometry|Feature} segment1 Geometry or Feature +// * @param {Geometry|Feature} segment2 Geometry or Feature +// * @returns {boolean} if slopes are equal +// */ +// function isParallel(segment1: Position[], segment2: Position[]) { +// var slope1 = bearingToAzimuth(rhumbBearing(segment1[0], segment1[1])); +// var slope2 = bearingToAzimuth(rhumbBearing(segment2[0], segment2[1])); +// return slope1 === slope2; +// } -/** - * Returns Feature's type - * - * @private - * @param {Geometry|Feature} geojson Geometry or Feature - * @param {string} name of the variable - * @returns {string} Feature's type - */ -function getType(geojson: Geometry | Feature, name: string) { - if ((geojson as Feature).geometry && (geojson as Feature).geometry.type) - return (geojson as Feature).geometry.type; - if (geojson.type) return geojson.type; // if GeoJSON geometry - throw new Error("Invalid GeoJSON object for " + name); -} +// /** +// * Returns Feature's type +// * +// * @private +// * @param {Geometry|Feature} geojson Geometry or Feature +// * @param {string} name of the variable +// * @returns {string} Feature's type +// */ +// function getType(geojson: Geometry | Feature, name: string) { +// if ((geojson as Feature).geometry && (geojson as Feature).geometry.type) +// return (geojson as Feature).geometry.type; +// if (geojson.type) return geojson.type; // if GeoJSON geometry +// throw new Error("Invalid GeoJSON object for " + name); +// } -export default booleanParallel; */ \ No newline at end of file +// export default booleanParallel; */ \ No newline at end of file diff --git a/lib/src/booleans/boolean_valid.dart b/lib/src/booleans/boolean_valid.dart index 20828cb2..d0f1bb28 100644 --- a/lib/src/booleans/boolean_valid.dart +++ b/lib/src/booleans/boolean_valid.dart @@ -4,17 +4,17 @@ import '../line_intersect.dart'; import 'boolean_crosses.dart'; import 'boolean_disjoint.dart'; -booleanValid checks if the geometry is a valid according to the OGC Simple Feature Specification. - * - * @name booleanValid - * @param {Geometry|Feature} feature GeoJSON Feature or Geometry - * @returns {boolean} true/false - * @example - * var line = turf.lineString([[1, 1], [1, 2], [1, 3], [1, 4]]); - * - * turf.booleanValid(line); // => true - * turf.booleanValid({foo: "bar"}); // => false - */ +// booleanValid checks if the geometry is a valid according to the OGC Simple Feature Specification. +// * +// * @name booleanValid +// * @param {Geometry|Feature} feature GeoJSON Feature or Geometry +// * @returns {boolean} true/false +// * @example +// * var line = turf.lineString([[1, 1], [1, 2], [1, 3], [1, 4]]); +// * +// * turf.booleanValid(line); // => true +// * turf.booleanValid({foo: "bar"}); // => false +// */ booleanValid(GeoJSONObject feature) { // // Automatic False diff --git a/lib/src/line_overlap.dart b/lib/src/line_overlap.dart index 6f957177..86392537 100644 --- a/lib/src/line_overlap.dart +++ b/lib/src/line_overlap.dart @@ -1,317 +1,175 @@ - -/// Takes any LineString or Polygon and returns the overlapping lines between both features. -/// @name lineOverlap -/// @param {Geometry|Feature} line1 any LineString or Polygon -/// @param {Geometry|Feature} line2 any LineString or Polygon -/// @param {Object} [options={}] Optional parameters -/// @param {number} [options.tolerance=0] Tolerance distance to match overlapping line segments (in kilometers) -/// @returns {FeatureCollection} lines(s) that are overlapping between both features -/// @example -/// var line1 = turf.lineString([[115, -35], [125, -30], [135, -30], [145, -35]]); -/// var line2 = turf.lineString([[115, -25], [125, -30], [135, -30], [145, -25]]); -/// var overlapping = turf.lineOverlap(line1, line2); +import 'package:rbush/rbush.dart'; +import 'package:turf/bbox.dart'; +import 'package:turf/helpers.dart'; +import 'package:turf/line_segment.dart'; +import 'package:turf/nearest_point_on_line.dart'; +import 'package:turf/src/booleans/boolean_point_on_line.dart'; +import 'package:turf/src/invariant.dart'; +import 'package:turf/src/meta/feature.dart'; +import 'package:turf_equality/turf_equality.dart'; + +/// Takes any [LineString] or [Polygon] and returns the overlapping [LineString]s between both [Feature]s. +/// [line1] is a Feature or any [LineString] or [Polygon] +/// [line2] is a Feature or any [LineString] or [Polygon] +/// [options.tolerance=0] Tolerance distance to match overlapping line segments (in kilometers) +/// returns a [FeatureCollection] lines(s) that are overlapping between both [Feature]s +/// example +/// ```dart +/// var line1 = LineString(coordiantes:[Position.of([115, -35]), Position.of([125, -30]), Position.of([135, -30]), Position.of([145, -35])]); +/// var line2 = LineString(coordiantes:[Position.of([115, -25]), Position.of([125, -30]), Position.of([135, -30]), Position.of([145, -25])]); +/// var overlapping = lineOverlap(line1, line2); /// //addToMap /// var addToMap = [line1, line2, overlapping] - lineOverlap< - G1 extends LineString | MultiLineString | Polygon | MultiPolygon, - G2 extends LineString | MultiLineString | Polygon | MultiPolygon ->( - line1: Feature | G1, - line2: Feature | G2, - options: { tolerance?: number } = {} -): FeatureCollection { +///``` +FeatureCollection lineOverlap( + GeoJSONObject line1, GeoJSONObject line2, + {num tolerance = 0}) { + RBushBox _toRBBox(Feature feature) { + var bb = bbox(feature); + return RBushBox( + minX: bb.lng1.toDouble(), + minY: bb.lat1.toDouble(), + maxX: bb.lng2.toDouble(), + maxY: bb.lat2.toDouble()); + } // Optional parameters - - options = options || {}; - if (!isObject(options)) throw new Error("options is invalid"); - var tolerance = options.tolerance || 0; - - // Containers - var features: Feature[] = []; + var features = >[]; // Create Spatial Index - var tree = rbush(); + var tree = RBushBase>( + getMinY: (Feature feature) => bbox(feature).lat1.toDouble(), + getMinX: (Feature feature) => bbox(feature).lng1.toDouble(), + toBBox: (feature) => _toRBBox(feature)); - // To-Do -- HACK way to support typescript - const line: any = lineSegment(line1); - tree.load(line); - var overlapSegment: Feature | undefined; - let additionalSegments: Feature[] = []; + var line = lineSegment(line1); + tree.load(line.features); + Feature? overlapSegment; + var additionalSegments = >[]; // Line Intersection // Iterate over line segments - segmentEach(line2, function (segment) { + segmentEach(line2, (Feature currentSegment, int featureIndex, + int? multiFeatureIndex, int? geometryIndex, int segmentIndex) { var doesOverlaps = false; - if (!segment) { - return; - } - // Iterate over each segments which falls within the same bounds - featureEach(tree.search(segment), function (match) { - if (doesOverlaps == false) { - var coordsSegment = getCoords(segment).sort(); - var coordsMatch: any = getCoords(match).sort(); - - // Segment overlaps feature - if (equal(coordsSegment, coordsMatch)) { + featureEach( + FeatureCollection( + features: tree.search(_toRBBox(currentSegment))), (match, index) { + if (!doesOverlaps) { + List coordsSegment = () { + List list = getCoords(currentSegment) as List; + list.sort(); + return list; + }(); + List coordsMatch = () { + List list = getCoords(match) as List; + list.sort(); + return list; + }(); + + Equality eq = Equality(); + // Segment overlaps feature - with dummy LineStrings just to use eq. + if (eq.compare(LineString(coordinates: coordsSegment), + LineString(coordinates: coordsMatch))) { doesOverlaps = true; // Overlaps already exists - only append last coordinate of segment - if (overlapSegment) { - overlapSegment = - concatSegment(overlapSegment, segment) || overlapSegment; - } else overlapSegment = segment; + if (overlapSegment != null) { + overlapSegment = concatSegment(overlapSegment!, currentSegment) ?? + overlapSegment; + } else { + overlapSegment = currentSegment; + } // Match segments which don't share nodes (Issue #901) - } else if ( - tolerance == 0 - ? booleanPointOnLine(coordsSegment[0], match) && - booleanPointOnLine(coordsSegment[1], match) - : nearestPointOnLine(match, coordsSegment[0]).properties.dist! <= - tolerance && - nearestPointOnLine(match, coordsSegment[1]).properties.dist! <= - tolerance - ) { + } else if (tolerance == 0 + ? booleanPointOnLine(Point(coordinates: coordsSegment[0]), + match.geometry as LineString) && + booleanPointOnLine(Point(coordinates: coordsSegment[1]), + match.geometry as LineString) + : nearestPointOnLine(match.geometry as LineString, + Point(coordinates: coordsSegment[0])) + .properties!['dist'] <= + tolerance && + nearestPointOnLine(match.geometry as LineString, + Point(coordinates: coordsSegment[1])) + .properties!['dist'] <= + tolerance) { doesOverlaps = true; - if (overlapSegment) { - overlapSegment = - concatSegment(overlapSegment, segment) || overlapSegment; - } else overlapSegment = segment; - } else if ( - tolerance == 0 - ? booleanPointOnLine(coordsMatch[0], segment) && - booleanPointOnLine(coordsMatch[1], segment) - : nearestPointOnLine(segment, coordsMatch[0]).properties.dist! <= - tolerance && - nearestPointOnLine(segment, coordsMatch[1]).properties.dist! <= - tolerance - ) { + if (overlapSegment != null) { + overlapSegment = concatSegment(overlapSegment!, currentSegment) ?? + overlapSegment; + } else { + overlapSegment = currentSegment; + } + } else if (tolerance == 0 + ? booleanPointOnLine(Point(coordinates: coordsMatch[0]), + currentSegment.geometry as LineString) && + booleanPointOnLine(Point(coordinates: coordsMatch[1]), + currentSegment.geometry as LineString) + : nearestPointOnLine(currentSegment.geometry as LineString, + Point(coordinates: coordsMatch[0])) + .properties!['dist'] <= + tolerance && + nearestPointOnLine(currentSegment.geometry as LineString, + Point(coordinates: coordsMatch[1])) + .properties!['dist'] <= + tolerance) { // Do not define (doesOverlap = true) since more matches can occur within the same segment // doesOverlaps = true; - if (overlapSegment) { - const combinedSegment = concatSegment(overlapSegment, match); - if (combinedSegment) { + if (overlapSegment != null) { + var combinedSegment = + concatSegment(overlapSegment!, match as Feature); + if (combinedSegment != null) { overlapSegment = combinedSegment; } else { - additionalSegments.push(match); + additionalSegments.add(match); } - } else overlapSegment = match; + } else { + overlapSegment = match as Feature; + } } } }); // Segment doesn't overlap - add overlaps to results & reset - if (doesOverlaps === false && overlapSegment) { - features.push(overlapSegment); - if (additionalSegments.length) { - features = features.concat(additionalSegments); + if (doesOverlaps == false && overlapSegment != null) { + features.add(overlapSegment!); + if (additionalSegments.isNotEmpty) { + features = [...features, ...additionalSegments]; additionalSegments = []; } - overlapSegment = undefined; + overlapSegment = null; } }); // Add last segment if exists - if (overlapSegment) features.push(overlapSegment); + if (overlapSegment != null) features.add(overlapSegment!); - return featureCollection(features); + return FeatureCollection(features: features); } -/// Concat Segment -/// /// @private -/// @param {Feature} line LineString -/// @param {Feature} segment 2-vertex LineString -/// @returns {Feature} concat linestring -concatSegment( - line: Feature, - segment: Feature -) { +Feature? concatSegment( + Feature line, Feature segment) { var coords = getCoords(segment); var lineCoords = getCoords(line); var start = lineCoords[0]; var end = lineCoords[lineCoords.length - 1]; - var geom = line.geometry.coordinates; - - if (equal(coords[0], start)) geom.unshift(coords[1]); - else if (equal(coords[0], end)) geom.push(coords[1]); - else if (equal(coords[1], start)) geom.unshift(coords[0]); - else if (equal(coords[1], end)) geom.push(coords[0]); - else return; // If the overlap leaves the segment unchanged, return undefined so that this can be identified. + List geom = (line.geometry as LineString).coordinates; + + if (coords[0] == start) { + geom.insert(0, coords[1]); + } else if (coords[0] == end) { + geom.add(coords[1]); + } else if (coords[1] == start) { + geom.insert(0, coords[0]); + } else if (coords[1] == end) { + geom.add(coords[0]); + } else { + return null; + } // If the overlap leaves the segment unchanged, return undefined so that this can be identified. // Otherwise return the mutated line. return line; } - -export default lineOverlap; - -/** - * import rbush from "@turf/geojson-rbush"; -import lineSegment from "@turf/line-segment"; -import nearestPointOnLine from "@turf/nearest-point-on-line"; -import booleanPointOnLine from "@turf/boolean-point-on-line"; -import { getCoords } from "@turf/invariant"; -import { featureEach, segmentEach } from "@turf/meta"; -import { - FeatureCollection, - Feature, - LineString, - MultiLineString, - Polygon, - MultiPolygon, - GeoJsonProperties, -} from "geojson"; -import { featureCollection, isObject } from "@turf/helpers"; -import equal from "deep-equal"; - -/** - * Takes any LineString or Polygon and returns the overlapping lines between both features. - * - * @name lineOverlap - * @param {Geometry|Feature} line1 any LineString or Polygon - * @param {Geometry|Feature} line2 any LineString or Polygon - * @param {Object} [options={}] Optional parameters - * @param {number} [options.tolerance=0] Tolerance distance to match overlapping line segments (in kilometers) - * @returns {FeatureCollection} lines(s) that are overlapping between both features - * @example - * var line1 = turf.lineString([[115, -35], [125, -30], [135, -30], [145, -35]]); - * var line2 = turf.lineString([[115, -25], [125, -30], [135, -30], [145, -25]]); - * - * var overlapping = turf.lineOverlap(line1, line2); - * - * //addToMap - * var addToMap = [line1, line2, overlapping] - */ -function lineOverlap< - G1 extends LineString | MultiLineString | Polygon | MultiPolygon, - G2 extends LineString | MultiLineString | Polygon | MultiPolygon ->( - line1: Feature | G1, - line2: Feature | G2, - options: { tolerance?: number } = {} -): FeatureCollection { - // Optional parameters - options = options || {}; - if (!isObject(options)) throw new Error("options is invalid"); - var tolerance = options.tolerance || 0; - - // Containers - var features: Feature[] = []; - - // Create Spatial Index - var tree = rbush(); - - // To-Do -- HACK way to support typescript - const line: any = lineSegment(line1); - tree.load(line); - var overlapSegment: Feature | undefined; - let additionalSegments: Feature[] = []; - - // Line Intersection - - // Iterate over line segments - segmentEach(line2, function (segment) { - var doesOverlaps = false; - - if (!segment) { - return; - } - - // Iterate over each segments which falls within the same bounds - featureEach(tree.search(segment), function (match) { - if (doesOverlaps === false) { - var coordsSegment = getCoords(segment).sort(); - var coordsMatch: any = getCoords(match).sort(); - - // Segment overlaps feature - if (equal(coordsSegment, coordsMatch)) { - doesOverlaps = true; - // Overlaps already exists - only append last coordinate of segment - if (overlapSegment) { - overlapSegment = - concatSegment(overlapSegment, segment) || overlapSegment; - } else overlapSegment = segment; - // Match segments which don't share nodes (Issue #901) - } else if ( - tolerance === 0 - ? booleanPointOnLine(coordsSegment[0], match) && - booleanPointOnLine(coordsSegment[1], match) - : nearestPointOnLine(match, coordsSegment[0]).properties.dist! <= - tolerance && - nearestPointOnLine(match, coordsSegment[1]).properties.dist! <= - tolerance - ) { - doesOverlaps = true; - if (overlapSegment) { - overlapSegment = - concatSegment(overlapSegment, segment) || overlapSegment; - } else overlapSegment = segment; - } else if ( - tolerance === 0 - ? booleanPointOnLine(coordsMatch[0], segment) && - booleanPointOnLine(coordsMatch[1], segment) - : nearestPointOnLine(segment, coordsMatch[0]).properties.dist! <= - tolerance && - nearestPointOnLine(segment, coordsMatch[1]).properties.dist! <= - tolerance - ) { - // Do not define (doesOverlap = true) since more matches can occur within the same segment - // doesOverlaps = true; - if (overlapSegment) { - const combinedSegment = concatSegment(overlapSegment, match); - if (combinedSegment) { - overlapSegment = combinedSegment; - } else { - additionalSegments.push(match); - } - } else overlapSegment = match; - } - } - }); - - // Segment doesn't overlap - add overlaps to results & reset - if (doesOverlaps === false && overlapSegment) { - features.push(overlapSegment); - if (additionalSegments.length) { - features = features.concat(additionalSegments); - additionalSegments = []; - } - overlapSegment = undefined; - } - }); - // Add last segment if exists - if (overlapSegment) features.push(overlapSegment); - - return featureCollection(features); -} - -/** - * Concat Segment - * - * @private - * @param {Feature} line LineString - * @param {Feature} segment 2-vertex LineString - * @returns {Feature} concat linestring - */ -function concatSegment( - line: Feature, - segment: Feature -) { - var coords = getCoords(segment); - var lineCoords = getCoords(line); - var start = lineCoords[0]; - var end = lineCoords[lineCoords.length - 1]; - var geom = line.geometry.coordinates; - - if (equal(coords[0], start)) geom.unshift(coords[1]); - else if (equal(coords[0], end)) geom.push(coords[1]); - else if (equal(coords[1], start)) geom.unshift(coords[0]); - else if (equal(coords[1], end)) geom.push(coords[0]); - else return; // If the overlap leaves the segment unchanged, return undefined so that this can be identified. - - // Otherwise return the mutated line. - return line; -} - -export default lineOverlap; - */ \ No newline at end of file diff --git a/pubspec.yaml b/pubspec.yaml index 3d3f0557..b7d89ca9 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -13,6 +13,7 @@ dependencies: sweepline_intersections: git: https://github.com/dartclub/sweepline_intersections.git turf_pip: ^0.0.1+1 + rbush: ^1.1.0 dev_dependencies: dartclub_lint: ^0.4.2 diff --git a/test/booleans/overlap_test.dart b/test/booleans/overlap_test.dart index ca9e2851..aa5f298c 100644 --- a/test/booleans/overlap_test.dart +++ b/test/booleans/overlap_test.dart @@ -1,139 +1,150 @@ -const glob = require("glob"); -const path = require("path"); -const test = require("tape"); -const load = require("load-json-file"); -const shapely = require("boolean-shapely"); -const { - point, - lineString, - polygon, - multiLineString, - multiPolygon, -} = require("@turf/helpers"); -const overlap = require("./index").default; +import 'dart:convert'; +import 'dart:io'; -test("turf-boolean-overlap", (t) => { - // True Fixtures - glob - .sync(path.join(__dirname, "test", "true", "**", "*.geojson")) - .forEach((filepath) => { - const name = path.parse(filepath).name; - const geojson = load.sync(filepath); - const feature1 = geojson.features[0]; - const feature2 = geojson.features[1]; - const result = overlap(feature1, feature2); +import 'package:test/test.dart'; +import 'package:turf/helpers.dart'; +import 'package:turf/src/booleans/boolean_overlap.dart'; - if (process.env.SHAPELY) - shapely - .contains(feature1, feature2) - .then((result) => t.true(result, "[true] shapely - " + name)); - t.true(result, "[true] " + name); - }); - // False Fixtures - glob - .sync(path.join(__dirname, "test", "false", "**", "*.geojson")) - .forEach((filepath) => { - const name = path.parse(filepath).name; - const geojson = load.sync(filepath); - const feature1 = geojson.features[0]; - const feature2 = geojson.features[1]; - const result = overlap(feature1, feature2); +main() { + group( + 'boolean-overlap', + () { + test("turf-boolean-overlap-trues", () { + // True Fixtures + Directory dir = Directory('./test/examples/booleans/overlap/true'); + for (var file in dir.listSync(recursive: true)) { + if (file is File && file.path.endsWith('.geojson')) { + var inSource = file.readAsStringSync(); + var inGeom = GeoJSONObject.fromJson(jsonDecode(inSource)); + var feature1 = (inGeom as FeatureCollection).features[0]; + var feature2 = inGeom.features[1]; + var result = booleanOverlap(feature1, feature2); + expect(result, true); + } + } + }); + test( + "turf-boolean-overlap - falses", + () { + // True Fixtures + Directory dir1 = Directory('./test/examples/booleans/overlap/false'); + for (var file in dir1.listSync(recursive: true)) { + if (file is File && file.path.endsWith('.geojson')) { + var inSource = file.readAsStringSync(); + var inGeom = GeoJSONObject.fromJson(jsonDecode(inSource)); + var feature1 = (inGeom as FeatureCollection).features[0]; + var feature2 = inGeom.features[1]; + var result = booleanOverlap(feature1, feature2); + expect(result, false); + } + } + }, + ); - if (process.env.SHAPELY) - shapely - .contains(feature1, feature2) - .then((result) => t.false(result, "[false] shapely - " + name)); - t.false(result, "[false] " + name); - }); - t.end(); -}); + var pt = Point(coordinates: Position.of([9, 50])); + var line1 = LineString( + coordinates: [ + Position.of([7, 50]), + Position.of([8, 50]), + Position.of([9, 50]), + ], + ); + var line2 = LineString( + coordinates: [ + Position.of([8, 50]), + Position.of([9, 50]), + Position.of([10, 50]), + ], + ); + var poly1 = Polygon( + coordinates: [ + [ + Position.of([8.5, 50]), + Position.of([9.5, 50]), + Position.of([9.5, 49]), + Position.of([8.5, 49]), + Position.of([8.5, 50]), + ], + ], + ); + var poly2 = Polygon( + coordinates: [ + [ + Position.of([8, 50]), + Position.of([9, 50]), + Position.of([9, 49]), + Position.of([8, 49]), + Position.of([8, 50]), + ], + ], + ); + var poly3 = Polygon( + coordinates: [ + [ + Position.of([10, 50]), + Position.of([10.5, 50]), + Position.of([10.5, 49]), + Position.of([10, 49]), + Position.of([10, 50]), + ], + ], + ); + var multiline1 = MultiLineString( + coordinates: [ + [ + Position.of([8, 50]), + Position.of([9, 50]), + Position.of([7, 50]), + ], + ], + ); + var multipoly1 = MultiPolygon( + coordinates: [ + [ + [ + Position.of([8.5, 50]), + Position.of([9.5, 50]), + Position.of([9.5, 49]), + Position.of([8.5, 49]), + Position.of([8.5, 50]), + ], + ], + ], + ); -const pt = point([9, 50]); -const line1 = lineString([ - [7, 50], - [8, 50], - [9, 50], -]); -const line2 = lineString([ - [8, 50], - [9, 50], - [10, 50], -]); -const poly1 = polygon([ - [ - [8.5, 50], - [9.5, 50], - [9.5, 49], - [8.5, 49], - [8.5, 50], - ], -]); -const poly2 = polygon([ - [ - [8, 50], - [9, 50], - [9, 49], - [8, 49], - [8, 50], - ], -]); -const poly3 = polygon([ - [ - [10, 50], - [10.5, 50], - [10.5, 49], - [10, 49], - [10, 50], - ], -]); -const multiline1 = multiLineString([ - [ - [7, 50], - [8, 50], - [9, 50], - ], -]); -const multipoly1 = multiPolygon([ - [ - [ - [8.5, 50], - [9.5, 50], - [9.5, 49], - [8.5, 49], - [8.5, 50], - ], - ], -]); + test( + "turf-boolean-overlap -- geometries", + () { + expect(booleanOverlap(line1, line2), true); + expect(booleanOverlap(poly1, poly2), true); + var z = booleanOverlap(poly1, poly3); + expect(z, isFalse); + }, + ); -test("turf-boolean-overlap -- geometries", (t) => { - t.true(overlap(line1.geometry, line2.geometry), "[true] LineString geometry"); - t.true(overlap(poly1.geometry, poly2.geometry), "[true] Polygon geometry"); - t.false(overlap(poly1.geometry, poly3.geometry), "[false] Polygon geometry"); - t.end(); -}); + test( + "turf-boolean-overlap -- throws", + () { + // t.throws(() => overlap(null, line1), /feature1 is required/, 'missing feature1'); + // t.throws(() => overlap(line1, null), /feature2 is required/, 'missing feature2'); -test("turf-boolean-overlap -- throws", (t) => { - // t.throws(() => overlap(null, line1), /feature1 is required/, 'missing feature1'); - // t.throws(() => overlap(line1, null), /feature2 is required/, 'missing feature2'); - t.throws( - () => overlap(poly1, line1), - /features must be of the same type/, - "different types" - ); - t.throws( - () => overlap(pt, pt), - /Point geometry not supported/, - "geometry not supported" - ); +//'different types', + expect( + () => booleanOverlap( + poly1, + line1, + ), + throwsA(isA())); +// "geometry not supported" - t.doesNotThrow( - () => overlap(line1, multiline1), - "supports line and multiline comparison" + expect(() => booleanOverlap(pt, pt), throwsA(isA())); + // "supports line and multiline comparison" + var x = booleanOverlap(line1, multiline1); + expect(() => booleanOverlap(line1, multiline1), x); + var y = booleanOverlap(poly1, multipoly1); + expect(() => booleanOverlap(poly1, multipoly1), y); + }, + ); + }, ); - t.doesNotThrow( - () => overlap(poly1, multipoly1), - "supports polygon and multipolygon comparison" - ); - - t.end(); -}); +} diff --git a/test/booleans/touches_test.dart b/test/booleans/touches_test.dart index 45518ca5..04abfdda 100644 --- a/test/booleans/touches_test.dart +++ b/test/booleans/touches_test.dart @@ -1,2 +1,60 @@ +/** + * const glob = require("glob"); +const path = require("path"); +const test = require("tape"); +const load = require("load-json-file"); +const shapely = require("boolean-shapely"); +const booleanJSTS = require("boolean-jsts"); +const touches = require("./index").default; -/ \ No newline at end of file +test("turf-boolean-touches", (t) => { + // True Fixtures + glob + .sync(path.join(__dirname, "test", "true", "**", "*.geojson")) + .forEach((filepath) => { + const name = path.parse(filepath).name; + if (name.includes("skip")) return t.skip(name); + + const geojson = load.sync(filepath); + const feature1 = geojson.features[0]; + const feature2 = geojson.features[1]; + const result = touches(feature1, feature2); + if (process.env.JSTS) + t.true( + booleanJSTS("touches", feature1, feature2), + "[true] JSTS - " + name + ); + + if (process.env.SHAPELY) + shapely + .touches(feature1, feature2) + .then((result) => t.true(result, "[true] shapely - " + name)); + t.true(result, "[true] " + name); + }); + // False Fixtures + glob + .sync(path.join(__dirname, "test", "false", "**", "*.geojson")) + .forEach((filepath) => { + const name = path.parse(filepath).name; + if (name.includes("skip")) return t.skip(name); + + const geojson = load.sync(filepath); + const feature1 = geojson.features[0]; + const feature2 = geojson.features[1]; + const result = touches(feature1, feature2); + if (process.env.JSTS) + t.false( + booleanJSTS("touches", feature1, feature2), + "[false] JSTS - " + name + ); + + if (process.env.SHAPELY) + shapely + .touches(feature1, feature2) + .then((result) => t.false(result, "[false] shapely - " + name)); + t.false(result, "[false] " + name); + }); + t.end(); +}); + + */ \ No newline at end of file diff --git a/test/booleans/within_test.dart b/test/booleans/within_test.dart index 45518ca5..42eb0fc9 100644 --- a/test/booleans/within_test.dart +++ b/test/booleans/within_test.dart @@ -1,2 +1,60 @@ +/** + * const glob = require("glob"); +const path = require("path"); +const test = require("tape"); +const load = require("load-json-file"); +const shapely = require("boolean-shapely"); +const booleanJSTS = require("boolean-jsts"); +const within = require("./index").default; -/ \ No newline at end of file +test("turf-boolean-within", (t) => { + // True Fixtures + glob + .sync(path.join(__dirname, "test", "true", "**", "*.geojson")) + .forEach((filepath) => { + const name = path.parse(filepath).name; + if (name.includes("skip")) return t.skip(name); + + const geojson = load.sync(filepath); + const feature1 = geojson.features[0]; + const feature2 = geojson.features[1]; + const result = within(feature1, feature2); + if (process.env.JSTS) + t.true( + booleanJSTS("within", feature1, feature2), + "[true] JSTS - " + name + ); + + if (process.env.SHAPELY) + shapely + .within(feature1, feature2) + .then((result) => t.true(result, "[true] shapely - " + name)); + t.true(result, "[true] " + name); + }); + // False Fixtures + glob + .sync(path.join(__dirname, "test", "false", "**", "*.geojson")) + .forEach((filepath) => { + const name = path.parse(filepath).name; + if (name.includes("skip")) return t.skip(name); + + const geojson = load.sync(filepath); + const feature1 = geojson.features[0]; + const feature2 = geojson.features[1]; + const result = within(feature1, feature2); + if (process.env.JSTS) + t.false( + booleanJSTS("within", feature1, feature2), + "[false] JSTS - " + name + ); + + if (process.env.SHAPELY) + shapely + .within(feature1, feature2) + .then((result) => t.false(result, "[false] shapely - " + name)); + t.false(result, "[false] " + name); + }); + t.end(); +}); + + */ \ No newline at end of file diff --git a/test/components/line_overlap.dart b/test/components/line_overlap.dart new file mode 100644 index 00000000..ad3dc7cf --- /dev/null +++ b/test/components/line_overlap.dart @@ -0,0 +1,90 @@ +const directories = { + in: path.join(__dirname, "test", "in") + path.sep, + out: path.join(__dirname, "test", "out") + path.sep, +}; + +let fixtures = fs.readdirSync(directories.in).map((filename) => { + return { + filename, + name: path.parse(filename).name, + geojson: load.sync(directories.in + filename), + }; +}); +// fixtures = fixtures.filter(({name}) => name.includes('#901')); + +test("turf-line-overlap", (t) => { + for (const { filename, name, geojson } of fixtures) { + const [source, target] = geojson.features; + const shared = colorize( + lineOverlap(source, target, geojson.properties), + "#0F0" + ); + const results = featureCollection(shared.features.concat([source, target])); + + if (process.env.REGEN) write.sync(directories.out + filename, results); + t.deepEquals(results, load.sync(directories.out + filename), name); + } + t.end(); +}); + +test("turf-line-overlap - Geometry Object", (t) => { + const line1 = lineString([ + [115, -35], + [125, -30], + [135, -30], + [145, -35], + ]); + const line2 = lineString([ + [135, -30], + [145, -35], + ]); + + t.true( + lineOverlap(line1.geometry, line2.geometry).features.length > 0, + "support geometry object" + ); + t.end(); +}); + +test("turf-line-overlap - multiple segments on same line", (t) => { + const line1 = lineString([ + [0, 1], + [1, 1], + [1, 0], + [2, 0], + [2, 1], + [3, 1], + [3, 0], + [4, 0], + [4, 1], + [4, 0], + ]); + const line2 = lineString([ + [0, 0], + [6, 0], + ]); + + t.true( + lineOverlap(line1.geometry, line2.geometry).features.length === 2, + "multiple segments on same line" + ); + t.true( + lineOverlap(line2.geometry, line1.geometry).features.length === 2, + "multiple segments on same line - swapped order" + ); + t.end(); +}); + +function colorize(features, color = "#F00", width = 25) { + const results = []; + featureEach(features, (feature) => { + feature.properties = { + stroke: color, + fill: color, + "stroke-width": width, + }; + results.push(feature); + }); + if (features.type === "Feature") return results[0]; + return featureCollection(results); +} \ No newline at end of file diff --git a/test/examples/booleans/overlap/false/equal-linear-rings.geojson b/test/examples/booleans/overlap/false/equal-linear-rings.geojson new file mode 100644 index 00000000..67dfae71 --- /dev/null +++ b/test/examples/booleans/overlap/false/equal-linear-rings.geojson @@ -0,0 +1,31 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [-53.674866943359375, 28.30135788537988], + [-53.337249755859375, 28.47412369059679], + [-53.524017333984375, 28.17492820114568], + [-53.674866943359375, 28.30135788537988] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [-53.674866943359375, 28.30135788537988], + [-53.337249755859375, 28.47412369059679], + [-53.524017333984375, 28.17492820114568], + [-53.674866943359375, 28.30135788537988] + ] + } + } + ] +} diff --git a/test/examples/booleans/overlap/false/equal-lines.geojson b/test/examples/booleans/overlap/false/equal-lines.geojson new file mode 100644 index 00000000..4c6e1810 --- /dev/null +++ b/test/examples/booleans/overlap/false/equal-lines.geojson @@ -0,0 +1,31 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [0, 0], + [0, 5], + [5, 5], + [5, 0] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [5, 0], + [5, 5], + [0, 5], + [0, 0] + ] + } + } + ] +} diff --git a/test/examples/booleans/overlap/false/equal-multipoints.geojson b/test/examples/booleans/overlap/false/equal-multipoints.geojson new file mode 100644 index 00000000..22aa40ad --- /dev/null +++ b/test/examples/booleans/overlap/false/equal-multipoints.geojson @@ -0,0 +1,33 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPoint", + "coordinates": [ + [-35.5638671875, 27.254629577800063], + [-35.6462646484375, 26.86328062676624], + [-35.4924560546875, 26.504988828743404], + [-35.1001953125, 26.12091815959972], + [-34.8969482421875, 26.455820238459893] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPoint", + "coordinates": [ + [-35.5638671875, 27.254629577800063], + [-35.6462646484375, 26.86328062676624], + [-35.4924560546875, 26.504988828743404], + [-35.1001953125, 26.12091815959972], + [-34.8969482421875, 26.455820238459893] + ] + } + } + ] +} diff --git a/test/examples/booleans/overlap/false/equal-polygons.geojson b/test/examples/booleans/overlap/false/equal-polygons.geojson new file mode 100644 index 00000000..9c89e6c9 --- /dev/null +++ b/test/examples/booleans/overlap/false/equal-polygons.geojson @@ -0,0 +1,35 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [-53.57208251953125, 28.287451910503744], + [-53.33038330078125, 28.29228897739706], + [-53.34136962890625, 28.430052892335723], + [-53.57208251953125, 28.287451910503744] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [-53.57208251953125, 28.287451910503744], + [-53.34136962890625, 28.430052892335723], + [-53.33038330078125, 28.29228897739706], + [-53.57208251953125, 28.287451910503744] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/overlap/false/linear-rings.geojson b/test/examples/booleans/overlap/false/linear-rings.geojson new file mode 100644 index 00000000..edbb4bb9 --- /dev/null +++ b/test/examples/booleans/overlap/false/linear-rings.geojson @@ -0,0 +1,33 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [-53.317337036132805, 28.445147699510212], + [-53.61053466796875, 28.263868062633772], + [-53.3770751953125, 28.214869548073377], + [-53.38531494140625, 28.272939391283685], + [-53.22052001953125, 28.272939391283685], + [-53.317337036132805, 28.445147699510212] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [-53.674866943359375, 28.30135788537988], + [-53.337249755859375, 28.47412369059679], + [-53.524017333984375, 28.17492820114568], + [-53.674866943359375, 28.30135788537988] + ] + } + } + ] +} diff --git a/test/examples/booleans/overlap/false/lines.geojson b/test/examples/booleans/overlap/false/lines.geojson new file mode 100644 index 00000000..c3414c3c --- /dev/null +++ b/test/examples/booleans/overlap/false/lines.geojson @@ -0,0 +1,32 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [-22.564544677734375, 46.25917013377904], + [-22.559051513671875, 46.32369743336783], + [-22.446441650390625, 46.352141192009334], + [-22.361297607421875, 46.32891323009468], + [-22.361297607421875, 46.30472670751783] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [-22.570724487304688, 46.36398839132818], + [-22.444381713867188, 46.357354276167015], + [-22.391510009765625, 46.3291502999477], + [-22.29263305664062, 46.382464893261165] + ] + } + } + ] +} diff --git a/test/examples/booleans/overlap/false/multipoints.geojson b/test/examples/booleans/overlap/false/multipoints.geojson new file mode 100644 index 00000000..c9c919be --- /dev/null +++ b/test/examples/booleans/overlap/false/multipoints.geojson @@ -0,0 +1,36 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPoint", + "coordinates": [ + [-36.05712890625, 26.480407161007275], + [-35.7220458984375, 27.137368359795584], + [-35.13427734375, 26.83387451505858], + [-35.4638671875, 27.254629577800063], + [-35.5462646484375, 26.86328062676624], + [-35.3924560546875, 26.504988828743404] + ] + } + }, + { + "type": "Feature", + "properties": { + "marker-color": "#000" + }, + "geometry": { + "type": "MultiPoint", + "coordinates": [ + [-35.5638671875, 27.254629577800063], + [-35.6462646484375, 26.86328062676624], + [-35.4924560546875, 26.504988828743404], + [-35.1001953125, 26.12091815959972], + [-34.8969482421875, 26.455820238459893] + ] + } + } + ] +} diff --git a/test/examples/booleans/overlap/false/polygon-with-hole-polygon.geojson b/test/examples/booleans/overlap/false/polygon-with-hole-polygon.geojson new file mode 100644 index 00000000..81e21b7f --- /dev/null +++ b/test/examples/booleans/overlap/false/polygon-with-hole-polygon.geojson @@ -0,0 +1,45 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [-37.81494140625, 30.050076521698735], + [-36.573486328125, 28.159189634046708], + [-34.20043945312499, 29.23847708592805], + [-34.44213867187499, 31.090574094954192], + [-36.507568359375, 32.045332838858506], + [-37.81494140625, 30.050076521698735] + ], + [ + [-36.661376953125, 29.516110386062277], + [-36.661376953125, 30.685163937659564], + [-35.233154296875, 30.685163937659564], + [-35.233154296875, 29.516110386062277], + [-36.661376953125, 29.516110386062277] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [-34.903564453125, 31.99875937194732], + [-33.387451171875, 31.700129553985924], + [-33.310546875, 33.165145408240285], + [-35.39794921875, 32.89803818160521], + [-34.903564453125, 31.99875937194732] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/overlap/false/polygons.geojson b/test/examples/booleans/overlap/false/polygons.geojson new file mode 100644 index 00000000..15dda991 --- /dev/null +++ b/test/examples/booleans/overlap/false/polygons.geojson @@ -0,0 +1,37 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [-53.51715087890625, 28.488005204159457], + [-53.47148895263672, 28.366933295392897], + [-53.3770751953125, 28.490419194161678], + [-53.24798583984375, 28.43246820620096], + [-53.33038330078125, 28.560400880492832], + [-53.51715087890625, 28.488005204159457] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [-53.57208251953125, 28.287451910503744], + [-53.33038330078125, 28.29228897739706], + [-53.34136962890625, 28.430052892335723], + [-53.57208251953125, 28.287451910503744] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/overlap/true/linear-rings.geojson b/test/examples/booleans/overlap/true/linear-rings.geojson new file mode 100644 index 00000000..41593df0 --- /dev/null +++ b/test/examples/booleans/overlap/true/linear-rings.geojson @@ -0,0 +1,33 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [-53.317337036132805, 28.445147699510212], + [-53.61053466796875, 28.263868062633772], + [-53.3770751953125, 28.214869548073377], + [-53.38531494140625, 28.272939391283685], + [-53.22052001953125, 28.272939391283685], + [-53.317337036132805, 28.445147699510212] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [-53.61053466796875, 28.263868062633772], + [-53.317337036132805, 28.445147699510212], + [-53.524017333984375, 28.17492820114568], + [-53.61053466796875, 28.263868062633772] + ] + } + } + ] +} diff --git a/test/examples/booleans/overlap/true/lines.geojson b/test/examples/booleans/overlap/true/lines.geojson new file mode 100644 index 00000000..30df9540 --- /dev/null +++ b/test/examples/booleans/overlap/true/lines.geojson @@ -0,0 +1,32 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [-22.564544677734375, 46.25917013377904], + [-22.559051513671875, 46.32369743336783], + [-22.446441650390625, 46.352141192009334], + [-22.361297607421875, 46.32891323009468], + [-22.361297607421875, 46.30472670751783] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [-22.570724487304688, 46.36398839132818], + [-22.446441650390625, 46.352141192009334], + [-22.361297607421875, 46.32891323009468], + [-22.29263305664062, 46.382464893261165] + ] + } + } + ] +} diff --git a/test/examples/booleans/overlap/true/multipoints.geojson b/test/examples/booleans/overlap/true/multipoints.geojson new file mode 100644 index 00000000..0155fa84 --- /dev/null +++ b/test/examples/booleans/overlap/true/multipoints.geojson @@ -0,0 +1,36 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPoint", + "coordinates": [ + [-36.05712890625, 26.480407161007275], + [-35.7220458984375, 27.137368359795584], + [-35.13427734375, 26.83387451505858], + [-35.4638671875, 27.254629577800063], + [-35.5462646484375, 26.86328062676624], + [-35.3924560546875, 26.504988828743404] + ] + } + }, + { + "type": "Feature", + "properties": { + "marker-color": "#000" + }, + "geometry": { + "type": "MultiPoint", + "coordinates": [ + [-35.4638671875, 27.254629577800063], + [-35.5462646484375, 26.86328062676624], + [-35.3924560546875, 26.504988828743404], + [-35.2001953125, 26.12091815959972], + [-34.9969482421875, 26.455820238459893] + ] + } + } + ] +} diff --git a/test/examples/booleans/overlap/true/polygon-with-hole-polygon.geojson b/test/examples/booleans/overlap/true/polygon-with-hole-polygon.geojson new file mode 100644 index 00000000..557f7310 --- /dev/null +++ b/test/examples/booleans/overlap/true/polygon-with-hole-polygon.geojson @@ -0,0 +1,44 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [-37.81494140625, 30.050076521698735], + [-36.573486328125, 28.159189634046708], + [-34.20043945312499, 29.23847708592805], + [-34.44213867187499, 31.090574094954192], + [-36.507568359375, 32.045332838858506], + [-37.81494140625, 30.050076521698735] + ], + [ + [-36.661376953125, 29.516110386062277], + [-36.661376953125, 30.685163937659564], + [-35.233154296875, 30.685163937659564], + [-35.233154296875, 29.516110386062277], + [-36.661376953125, 29.516110386062277] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [-35.980224609375, 30.315987718557867], + [-34.8486328125, 30.694611546632277], + [-35.782470703125, 31.16580958786196], + [-35.980224609375, 30.315987718557867] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/overlap/true/polygons.geojson b/test/examples/booleans/overlap/true/polygons.geojson new file mode 100644 index 00000000..e28e427b --- /dev/null +++ b/test/examples/booleans/overlap/true/polygons.geojson @@ -0,0 +1,37 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [-53.51715087890625, 28.488005204159457], + [-53.33038330078125, 28.560400880492832], + [-53.24798583984375, 28.43246820620096], + [-53.3770751953125, 28.490419194161678], + [-53.4100341796875, 28.34789944257093], + [-53.51715087890625, 28.488005204159457] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [-53.57208251953125, 28.287451910503744], + [-53.34136962890625, 28.430052892335723], + [-53.33038330078125, 28.29228897739706], + [-53.57208251953125, 28.287451910503744] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/overlap/true/simple-lines.geojson b/test/examples/booleans/overlap/true/simple-lines.geojson new file mode 100644 index 00000000..591d9494 --- /dev/null +++ b/test/examples/booleans/overlap/true/simple-lines.geojson @@ -0,0 +1,30 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [0, 0], + [0, 5], + [5, 5], + [5, 0] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [0, 5], + [5, 5], + [5, 10] + ] + } + } + ] +} diff --git a/test/examples/booleans/overlap/true/single-multipoints.geojson b/test/examples/booleans/overlap/true/single-multipoints.geojson new file mode 100644 index 00000000..c187d80f --- /dev/null +++ b/test/examples/booleans/overlap/true/single-multipoints.geojson @@ -0,0 +1,36 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPoint", + "coordinates": [ + [-36.05712890625, 26.480407161007275], + [-35.7220458984375, 27.137368359795584], + [-35.13427734375, 26.83387451505858], + [-35.4638671875, 27.254629577800063], + [-35.5462646484375, 26.86328062676624], + [-35.3924560546875, 26.504988828743404] + ] + } + }, + { + "type": "Feature", + "properties": { + "marker-color": "#000" + }, + "geometry": { + "type": "MultiPoint", + "coordinates": [ + [-35.4638671875, 27.254629577800063], + [-35.6462646484375, 26.86328062676624], + [-35.4924560546875, 26.504988828743404], + [-35.1001953125, 26.12091815959972], + [-34.8969482421875, 26.455820238459893] + ] + } + } + ] +} diff --git a/test/examples/booleans/parallel/false/line1.geojson b/test/examples/booleans/parallel/false/line1.geojson new file mode 100644 index 00000000..c1ba4219 --- /dev/null +++ b/test/examples/booleans/parallel/false/line1.geojson @@ -0,0 +1,31 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [-111.544189453125, 24.186847428521244], + [-110.687255859375, 24.966140159912975], + [-110.4510498046875, 24.467150664739002], + [-109.9951171875, 25.180087808990645] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [-111.4617919921875, 24.05148034322011], + [-110.8795166015625, 24.681961205014595], + [-110.841064453125, 24.14174098050432], + [-109.97863769531249, 24.617057340809524] + ] + } + } + ] +} diff --git a/test/examples/booleans/parallel/false/line2.geojson b/test/examples/booleans/parallel/false/line2.geojson new file mode 100644 index 00000000..29de05c1 --- /dev/null +++ b/test/examples/booleans/parallel/false/line2.geojson @@ -0,0 +1,31 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [-34.98046875, 29.38217507514529], + [30.937499999999996, 59.085738569819505], + [-10.01953125, 60.84491057364912], + [25.6640625, 67.60922060496382], + [-4.5703125, 34.59704151614417] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [-27.24609375, 51.508742458803326], + [24.43359375, 48.22467264956519], + [49.92187499999999, 65.2198939361321] + ] + } + } + ] +} diff --git a/test/examples/booleans/parallel/true/city-line.geojson b/test/examples/booleans/parallel/true/city-line.geojson new file mode 100644 index 00000000..92c2b642 --- /dev/null +++ b/test/examples/booleans/parallel/true/city-line.geojson @@ -0,0 +1,29 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [9.170356, 45.477985], + [9.164434, 45.482551], + [9.166644, 45.484003] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [9.169356, 45.477985], + [9.163434, 45.482551], + [9.165644, 45.484003] + ] + } + } + ] +} diff --git a/test/examples/booleans/parallel/true/fiji.geojson b/test/examples/booleans/parallel/true/fiji.geojson new file mode 100644 index 00000000..0ac4ed6b --- /dev/null +++ b/test/examples/booleans/parallel/true/fiji.geojson @@ -0,0 +1,31 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [-180.2911376953125, -17.07253857905758], + [-179.73358154296875, -17.203769821917533], + [-179.55780029296872, -17.463332719132794], + [-179.296875, -17.460712710429785] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [-180.7911376953125, -17.07253857905758], + [-180.23358154296875, -17.203769821917533], + [-180.05780029296872, -17.463332719132794], + [-179.796875, -17.460712710429785] + ] + } + } + ] +} diff --git a/test/examples/booleans/parallel/true/line1.geojson b/test/examples/booleans/parallel/true/line1.geojson new file mode 100644 index 00000000..66795584 --- /dev/null +++ b/test/examples/booleans/parallel/true/line1.geojson @@ -0,0 +1,31 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [-68.3349609375, 18.203262019544418], + [-67.7142333984375, 18.94266018631978], + [-66.412353515625, 18.588982352118453], + [-66.181640625, 19.19186565046399] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [-68.8349609375, 18.203262019544418], + [-68.2142333984375, 18.94266018631978], + [-66.912353515625, 18.588982352118453], + [-66.681640625, 19.19186565046399] + ] + } + } + ] +} diff --git a/test/examples/booleans/parallel/true/line3-reverse.geojson b/test/examples/booleans/parallel/true/line3-reverse.geojson new file mode 100644 index 00000000..aad47272 --- /dev/null +++ b/test/examples/booleans/parallel/true/line3-reverse.geojson @@ -0,0 +1,31 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [-74.4798388671875, 15.235164824060707], + [-74.01978637695312, 15.566159129772904], + [-73.95798828125, 15.425881893976563] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [-74.4598388671875, 15.235164824060707], + [-73.99978637695312, 15.566159129772904], + [-73.93798828125, 15.425881893976563], + [-73.795166015625, 15.681220930466825], + [-73.71002197265624, 15.551606490799015] + ] + } + } + ] +} diff --git a/test/examples/booleans/parallel/true/line3.geojson b/test/examples/booleans/parallel/true/line3.geojson new file mode 100644 index 00000000..5f85af9c --- /dev/null +++ b/test/examples/booleans/parallel/true/line3.geojson @@ -0,0 +1,31 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [-74.4598388671875, 15.235164824060707], + [-73.99978637695312, 15.566159129772904], + [-73.93798828125, 15.425881893976563], + [-73.795166015625, 15.681220930466825], + [-73.71002197265624, 15.551606490799015] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [-74.4798388671875, 15.235164824060707], + [-74.01978637695312, 15.566159129772904], + [-73.95798828125, 15.425881893976563] + ] + } + } + ] +} diff --git a/test/examples/booleans/parallel/true/resolute.geojson b/test/examples/booleans/parallel/true/resolute.geojson new file mode 100644 index 00000000..6b271052 --- /dev/null +++ b/test/examples/booleans/parallel/true/resolute.geojson @@ -0,0 +1,29 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [-89.82421875, 70.22974449563027], + [-83.056640625, 75.75894014501688], + [-64.3359375, 72.36910450725075] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [-88.52421875, 70.22974449563027], + [-81.756640625, 75.75894014501688], + [-63.0359375, 72.36910450725075] + ] + } + } + ] +} diff --git a/test/examples/booleans/parallel/true/segment1.geojson b/test/examples/booleans/parallel/true/segment1.geojson new file mode 100644 index 00000000..332d9b70 --- /dev/null +++ b/test/examples/booleans/parallel/true/segment1.geojson @@ -0,0 +1,27 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [-2, -5], + [-2, 2] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [0, -4.5], + [-0, 1] + ] + } + } + ] +} diff --git a/test/examples/booleans/parallel/true/segment2.geojson b/test/examples/booleans/parallel/true/segment2.geojson new file mode 100644 index 00000000..4450db2d --- /dev/null +++ b/test/examples/booleans/parallel/true/segment2.geojson @@ -0,0 +1,27 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [-96.591796875, 34.161818161230386], + [-94.4384765625, 35.496456056584165] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [-94.591796875, 34.161818161230386], + [-92.4384765625, 35.496456056584165] + ] + } + } + ] +} diff --git a/test/examples/booleans/parallel/true/segment3.geojson b/test/examples/booleans/parallel/true/segment3.geojson new file mode 100644 index 00000000..cef1bdcc --- /dev/null +++ b/test/examples/booleans/parallel/true/segment3.geojson @@ -0,0 +1,27 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [-86, 11.4], + [-80, 11.4] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [-88, 11], + [-81, 11] + ] + } + } + ] +} diff --git a/test/examples/booleans/touches/false/LineString/LineString/LinesExactSame.geojson b/test/examples/booleans/touches/false/LineString/LineString/LinesExactSame.geojson new file mode 100644 index 00000000..034737ba --- /dev/null +++ b/test/examples/booleans/touches/false/LineString/LineString/LinesExactSame.geojson @@ -0,0 +1,31 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [1, 1], + [1, 2], + [1, 3], + [1, 4] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [1, 1], + [1, 2], + [1, 3], + [1, 4] + ] + } + } + ] +} diff --git a/test/examples/booleans/touches/false/LineString/LineString/LivesOverlap.geojson b/test/examples/booleans/touches/false/LineString/LineString/LivesOverlap.geojson new file mode 100644 index 00000000..28c41a8c --- /dev/null +++ b/test/examples/booleans/touches/false/LineString/LineString/LivesOverlap.geojson @@ -0,0 +1,30 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [1, 2], + [1, 3], + [1, 15.5] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [1, 1], + [1, 2], + [1, 3], + [1, 4] + ] + } + } + ] +} diff --git a/test/examples/booleans/touches/false/LineString/MultiLineString/LineStringOverlapsMultiLinestring.geojson b/test/examples/booleans/touches/false/LineString/MultiLineString/LineStringOverlapsMultiLinestring.geojson new file mode 100644 index 00000000..84ce32e2 --- /dev/null +++ b/test/examples/booleans/touches/false/LineString/MultiLineString/LineStringOverlapsMultiLinestring.geojson @@ -0,0 +1,37 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [2, 2], + [2, 3] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiLineString", + "coordinates": [ + [ + [1, 1], + [1, 2], + [1, 3], + [1, 4] + ], + [ + [2, 1], + [2, 2], + [2, 3], + [2, 4] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/touches/false/LineString/MultiLineString/LineStringSameAsMultiLinestring.geojson b/test/examples/booleans/touches/false/LineString/MultiLineString/LineStringSameAsMultiLinestring.geojson new file mode 100644 index 00000000..ff778d80 --- /dev/null +++ b/test/examples/booleans/touches/false/LineString/MultiLineString/LineStringSameAsMultiLinestring.geojson @@ -0,0 +1,39 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [1, 1], + [1, 2], + [1, 3], + [1, 4] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiLineString", + "coordinates": [ + [ + [1, 1], + [1, 2], + [1, 3], + [1, 4] + ], + [ + [2, 1], + [2, 2], + [2, 3], + [2, 4] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/touches/false/LineString/MultiPoint/LineStringDoesNotTouchMP.geojson b/test/examples/booleans/touches/false/LineString/MultiPoint/LineStringDoesNotTouchMP.geojson new file mode 100644 index 00000000..37944a21 --- /dev/null +++ b/test/examples/booleans/touches/false/LineString/MultiPoint/LineStringDoesNotTouchMP.geojson @@ -0,0 +1,29 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [1, 1], + [1, 2], + [1, 3], + [1, 4] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPoint", + "coordinates": [ + [3, 1], + [3, 3] + ] + } + } + ] +} diff --git a/test/examples/booleans/touches/false/LineString/MultiPoint/LineStringTouchesMultiPointButInternal.geojson b/test/examples/booleans/touches/false/LineString/MultiPoint/LineStringTouchesMultiPointButInternal.geojson new file mode 100644 index 00000000..40b6b18e --- /dev/null +++ b/test/examples/booleans/touches/false/LineString/MultiPoint/LineStringTouchesMultiPointButInternal.geojson @@ -0,0 +1,29 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [1, 1], + [1, 2], + [1, 3], + [1, 4] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPoint", + "coordinates": [ + [1, 1], + [1, 3] + ] + } + } + ] +} diff --git a/test/examples/booleans/touches/false/LineString/MultiPolygon/LineDoesNotTouchMultiPoly.geojson b/test/examples/booleans/touches/false/LineString/MultiPolygon/LineDoesNotTouchMultiPoly.geojson new file mode 100644 index 00000000..da9b4343 --- /dev/null +++ b/test/examples/booleans/touches/false/LineString/MultiPolygon/LineDoesNotTouchMultiPoly.geojson @@ -0,0 +1,43 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [-1, 1], + [-1, 0.5] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + [ + [ + [1, 1], + [1, 10], + [10, 10], + [10, 1], + [1, 1] + ] + ], + [ + [ + [-1, -1], + [-1, -10], + [-10, -10], + [-10, -1], + [-1, -1] + ] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/touches/false/LineString/Polygon/LineCrossesPolygon.geojson b/test/examples/booleans/touches/false/LineString/Polygon/LineCrossesPolygon.geojson new file mode 100644 index 00000000..309de922 --- /dev/null +++ b/test/examples/booleans/touches/false/LineString/Polygon/LineCrossesPolygon.geojson @@ -0,0 +1,32 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [2, 0], + [11, 11] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [1, 1], + [1, 10], + [10, 10], + [10, 1], + [1, 1] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/touches/false/LineString/Polygon/LineDoesNotTouch.geojson b/test/examples/booleans/touches/false/LineString/Polygon/LineDoesNotTouch.geojson new file mode 100644 index 00000000..61f427a4 --- /dev/null +++ b/test/examples/booleans/touches/false/LineString/Polygon/LineDoesNotTouch.geojson @@ -0,0 +1,32 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [-1, -2], + [-1, -3] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [1, 1], + [1, 10], + [10, 10], + [10, 1], + [1, 1] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/touches/false/LineString/Polygon/LineWIthinPolygon.geojson b/test/examples/booleans/touches/false/LineString/Polygon/LineWIthinPolygon.geojson new file mode 100644 index 00000000..a3016cea --- /dev/null +++ b/test/examples/booleans/touches/false/LineString/Polygon/LineWIthinPolygon.geojson @@ -0,0 +1,33 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [1, 2], + [1, 3], + [3, 3] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [1, 1], + [1, 10], + [10, 10], + [10, 1], + [1, 1] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/touches/false/MultiLineString/LineString/MultiLineStringOverlapsLine.geojson b/test/examples/booleans/touches/false/MultiLineString/LineString/MultiLineStringOverlapsLine.geojson new file mode 100644 index 00000000..4762791f --- /dev/null +++ b/test/examples/booleans/touches/false/MultiLineString/LineString/MultiLineStringOverlapsLine.geojson @@ -0,0 +1,37 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiLineString", + "coordinates": [ + [ + [1, 1], + [1, 2], + [1, 3], + [1, 4] + ], + [ + [2, 1], + [2, 2], + [2, 3], + [2, 4] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [2, 2], + [2, 3] + ] + } + } + ] +} diff --git a/test/examples/booleans/touches/false/MultiLineString/LineString/MultiLineStringSameAsLine.geojson b/test/examples/booleans/touches/false/MultiLineString/LineString/MultiLineStringSameAsLine.geojson new file mode 100644 index 00000000..33a233eb --- /dev/null +++ b/test/examples/booleans/touches/false/MultiLineString/LineString/MultiLineStringSameAsLine.geojson @@ -0,0 +1,39 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiLineString", + "coordinates": [ + [ + [1, 1], + [1, 2], + [1, 3], + [1, 4] + ], + [ + [2, 1], + [2, 2], + [2, 3], + [2, 4] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [1, 1], + [1, 2], + [1, 3], + [1, 4] + ] + } + } + ] +} diff --git a/test/examples/booleans/touches/false/MultiLineString/MultiLineString/MultiLineStringsOverlap.geojson b/test/examples/booleans/touches/false/MultiLineString/MultiLineString/MultiLineStringsOverlap.geojson new file mode 100644 index 00000000..467852d0 --- /dev/null +++ b/test/examples/booleans/touches/false/MultiLineString/MultiLineString/MultiLineStringsOverlap.geojson @@ -0,0 +1,39 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiLineString", + "coordinates": [ + [ + [2, 2], + [2, 3] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiLineString", + "coordinates": [ + [ + [1, 1], + [1, 2], + [1, 3], + [1, 4] + ], + [ + [2, 1], + [2, 2], + [2, 3], + [2, 4] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/touches/false/MultiLineString/MultiLineString/MultiLineStringsSame.geojson b/test/examples/booleans/touches/false/MultiLineString/MultiLineString/MultiLineStringsSame.geojson new file mode 100644 index 00000000..eafdeba7 --- /dev/null +++ b/test/examples/booleans/touches/false/MultiLineString/MultiLineString/MultiLineStringsSame.geojson @@ -0,0 +1,41 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiLineString", + "coordinates": [ + [ + [1, 1], + [1, 2], + [1, 3], + [1, 4] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiLineString", + "coordinates": [ + [ + [1, 1], + [1, 2], + [1, 3], + [1, 4] + ], + [ + [2, 1], + [2, 2], + [2, 3], + [2, 4] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/touches/false/MultiLineString/MultiPoint/MpTouchesInternalMultiline.geojson b/test/examples/booleans/touches/false/MultiLineString/MultiPoint/MpTouchesInternalMultiline.geojson new file mode 100644 index 00000000..ee8fd090 --- /dev/null +++ b/test/examples/booleans/touches/false/MultiLineString/MultiPoint/MpTouchesInternalMultiline.geojson @@ -0,0 +1,37 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiLineString", + "coordinates": [ + [ + [1, 1], + [1, 2], + [1, 3], + [1, 4] + ], + [ + [2, 1], + [2, 2], + [2, 3], + [2, 4] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPoint", + "coordinates": [ + [1, 2], + [10, 4] + ] + } + } + ] +} diff --git a/test/examples/booleans/touches/false/MultiLineString/MultiPoint/MultiPointNotTouchMultiline.geojson b/test/examples/booleans/touches/false/MultiLineString/MultiPoint/MultiPointNotTouchMultiline.geojson new file mode 100644 index 00000000..d87e3d98 --- /dev/null +++ b/test/examples/booleans/touches/false/MultiLineString/MultiPoint/MultiPointNotTouchMultiline.geojson @@ -0,0 +1,37 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiLineString", + "coordinates": [ + [ + [1, 1], + [1, 2], + [1, 3], + [1, 4] + ], + [ + [2, 1], + [2, 2], + [2, 3], + [2, 4] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPoint", + "coordinates": [ + [12, 4], + [10, 4] + ] + } + } + ] +} diff --git a/test/examples/booleans/touches/false/MultiLineString/MultiPolygon/MultiLineInsideMultipoly.geojson b/test/examples/booleans/touches/false/MultiLineString/MultiPolygon/MultiLineInsideMultipoly.geojson new file mode 100644 index 00000000..4055d523 --- /dev/null +++ b/test/examples/booleans/touches/false/MultiLineString/MultiPolygon/MultiLineInsideMultipoly.geojson @@ -0,0 +1,53 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiLineString", + "coordinates": [ + [ + [1, 1], + [1, 2], + [1, 3], + [1, 4] + ], + [ + [2, 1], + [2, 2], + [2, 3], + [2, 4] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + [ + [ + [1, 1], + [1, 10], + [10, 10], + [10, 1], + [1, 1] + ] + ], + [ + [ + [-1, -1], + [-1, -10], + [-10, -10], + [-10, -1], + [-1, -1] + ] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/touches/false/MultiLineString/Point/PointNotTouchMultiLinestring.geojson b/test/examples/booleans/touches/false/MultiLineString/Point/PointNotTouchMultiLinestring.geojson new file mode 100644 index 00000000..04206d7d --- /dev/null +++ b/test/examples/booleans/touches/false/MultiLineString/Point/PointNotTouchMultiLinestring.geojson @@ -0,0 +1,34 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiLineString", + "coordinates": [ + [ + [1, 1], + [1, 2], + [1, 3], + [1, 4] + ], + [ + [2, 1], + [2, 2], + [2, 3], + [2, 4] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [1, 3] + } + } + ] +} diff --git a/test/examples/booleans/touches/false/MultiLineString/Point/PointTouchesMidLineString.geojson b/test/examples/booleans/touches/false/MultiLineString/Point/PointTouchesMidLineString.geojson new file mode 100644 index 00000000..66298cf0 --- /dev/null +++ b/test/examples/booleans/touches/false/MultiLineString/Point/PointTouchesMidLineString.geojson @@ -0,0 +1,34 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiLineString", + "coordinates": [ + [ + [1, 1], + [1, 2], + [1, 3], + [1, 4] + ], + [ + [2, 1], + [2, 2], + [2, 3], + [2, 4] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [10, 4] + } + } + ] +} diff --git a/test/examples/booleans/touches/false/MultiLineString/Polygon/MultiLineInsidePoly.geojson b/test/examples/booleans/touches/false/MultiLineString/Polygon/MultiLineInsidePoly.geojson new file mode 100644 index 00000000..a1ccee6d --- /dev/null +++ b/test/examples/booleans/touches/false/MultiLineString/Polygon/MultiLineInsidePoly.geojson @@ -0,0 +1,42 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiLineString", + "coordinates": [ + [ + [1, 1], + [1, 2], + [1, 3], + [1, 4] + ], + [ + [2, 1], + [2, 2], + [2, 3], + [2, 4] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [1, 1], + [1, 10], + [10, 10], + [10, 1], + [1, 1] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/touches/false/MultiLineString/Polygon/MultiLineNotTouchPoly.geojson b/test/examples/booleans/touches/false/MultiLineString/Polygon/MultiLineNotTouchPoly.geojson new file mode 100644 index 00000000..a9cefb6a --- /dev/null +++ b/test/examples/booleans/touches/false/MultiLineString/Polygon/MultiLineNotTouchPoly.geojson @@ -0,0 +1,42 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiLineString", + "coordinates": [ + [ + [1, 1], + [1, 2], + [1, 3], + [1, 4] + ], + [ + [2, 1], + [2, 2], + [2, 3], + [2, 4] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [10, 10], + [10, 100], + [100, 100], + [100, 10], + [10, 10] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/touches/false/MultiPoint/LineString/MultiPointTouchesInsideLine.geojson b/test/examples/booleans/touches/false/MultiPoint/LineString/MultiPointTouchesInsideLine.geojson new file mode 100644 index 00000000..d9d3b811 --- /dev/null +++ b/test/examples/booleans/touches/false/MultiPoint/LineString/MultiPointTouchesInsideLine.geojson @@ -0,0 +1,29 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPoint", + "coordinates": [ + [1, 1], + [1, 3] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [1, 1], + [1, 2], + [1, 3], + [1, 4] + ] + } + } + ] +} diff --git a/test/examples/booleans/touches/false/MultiPoint/LineString/MultipointDoesNotTouchLine.geojson b/test/examples/booleans/touches/false/MultiPoint/LineString/MultipointDoesNotTouchLine.geojson new file mode 100644 index 00000000..18791af1 --- /dev/null +++ b/test/examples/booleans/touches/false/MultiPoint/LineString/MultipointDoesNotTouchLine.geojson @@ -0,0 +1,29 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPoint", + "coordinates": [ + [3, 1], + [3, 3] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [1, 1], + [1, 2], + [1, 3], + [1, 4] + ] + } + } + ] +} diff --git a/test/examples/booleans/touches/false/MultiPoint/MultiLineString/MpDoesNotTouchMultiLine.geojson b/test/examples/booleans/touches/false/MultiPoint/MultiLineString/MpDoesNotTouchMultiLine.geojson new file mode 100644 index 00000000..fdd34da3 --- /dev/null +++ b/test/examples/booleans/touches/false/MultiPoint/MultiLineString/MpDoesNotTouchMultiLine.geojson @@ -0,0 +1,37 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPoint", + "coordinates": [ + [12, 4], + [10, 4] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiLineString", + "coordinates": [ + [ + [1, 1], + [1, 2], + [1, 3], + [1, 4] + ], + [ + [2, 1], + [2, 2], + [2, 3], + [2, 4] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/touches/false/MultiPoint/MultiLineString/MpTouchesInternalMultiLine.geojson b/test/examples/booleans/touches/false/MultiPoint/MultiLineString/MpTouchesInternalMultiLine.geojson new file mode 100644 index 00000000..0fc73013 --- /dev/null +++ b/test/examples/booleans/touches/false/MultiPoint/MultiLineString/MpTouchesInternalMultiLine.geojson @@ -0,0 +1,37 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPoint", + "coordinates": [ + [1, 2], + [10, 4] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiLineString", + "coordinates": [ + [ + [1, 1], + [1, 2], + [1, 3], + [1, 4] + ], + [ + [2, 1], + [2, 2], + [2, 3], + [2, 4] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/touches/false/MultiPoint/MultiPolygon/MultiPointDoesNotTouchMultipolygon b/test/examples/booleans/touches/false/MultiPoint/MultiPolygon/MultiPointDoesNotTouchMultipolygon new file mode 100644 index 00000000..5b136d62 --- /dev/null +++ b/test/examples/booleans/touches/false/MultiPoint/MultiPolygon/MultiPointDoesNotTouchMultipolygon @@ -0,0 +1,24 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPoint", + "coordinates": [[10, 14], [-14, -14]] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + [[[1, 1], [1, 10], [10, 10], [10, 1], [1, 1]]], + [[[-1, -1], [-1, -10], [-10, -10], [-10, -1], [-1, -1]]] + ] + } + } + ] +} diff --git a/test/examples/booleans/touches/false/MultiPoint/MultiPolygon/multipoint-inside-multipolygon.geojson b/test/examples/booleans/touches/false/MultiPoint/MultiPolygon/multipoint-inside-multipolygon.geojson new file mode 100644 index 00000000..7cd0e752 --- /dev/null +++ b/test/examples/booleans/touches/false/MultiPoint/MultiPolygon/multipoint-inside-multipolygon.geojson @@ -0,0 +1,43 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPoint", + "coordinates": [ + [4, 4], + [-14, -14] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + [ + [ + [1, 1], + [1, 10], + [10, 10], + [10, 1], + [1, 1] + ] + ], + [ + [ + [-1, -1], + [-1, -10], + [-10, -10], + [-10, -1], + [-1, -1] + ] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/touches/false/MultiPoint/Polygon/MultiPointInsidePolygon.geojson b/test/examples/booleans/touches/false/MultiPoint/Polygon/MultiPointInsidePolygon.geojson new file mode 100644 index 00000000..372d60e6 --- /dev/null +++ b/test/examples/booleans/touches/false/MultiPoint/Polygon/MultiPointInsidePolygon.geojson @@ -0,0 +1,33 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPoint", + "coordinates": [ + [2, 2], + [12, 12], + [15, 15] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [1, 1], + [1, 10], + [10, 10], + [10, 1], + [1, 1] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/touches/false/MultiPoint/Polygon/MultiPointNoTouchPolygon.geojson b/test/examples/booleans/touches/false/MultiPoint/Polygon/MultiPointNoTouchPolygon.geojson new file mode 100644 index 00000000..f4f285fe --- /dev/null +++ b/test/examples/booleans/touches/false/MultiPoint/Polygon/MultiPointNoTouchPolygon.geojson @@ -0,0 +1,32 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPoint", + "coordinates": [ + [0, 0], + [0, 10] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [1, 1], + [1, 10], + [10, 10], + [10, 1], + [1, 1] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/touches/false/MultiPolygon/LineString/MultiPolyNotTouchLineString.geojson b/test/examples/booleans/touches/false/MultiPolygon/LineString/MultiPolyNotTouchLineString.geojson new file mode 100644 index 00000000..e1f631c7 --- /dev/null +++ b/test/examples/booleans/touches/false/MultiPolygon/LineString/MultiPolyNotTouchLineString.geojson @@ -0,0 +1,43 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + [ + [ + [1, 1], + [1, 10], + [10, 10], + [10, 1], + [1, 1] + ] + ], + [ + [ + [-1, -1], + [-1, -10], + [-10, -10], + [-10, -1], + [-1, -1] + ] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [-1, 1], + [-1, 0.5] + ] + } + } + ] +} diff --git a/test/examples/booleans/touches/false/MultiPolygon/MultiLineString/MultiPolyOverlapsMultiLine.geojson b/test/examples/booleans/touches/false/MultiPolygon/MultiLineString/MultiPolyOverlapsMultiLine.geojson new file mode 100644 index 00000000..9ff6575e --- /dev/null +++ b/test/examples/booleans/touches/false/MultiPolygon/MultiLineString/MultiPolyOverlapsMultiLine.geojson @@ -0,0 +1,53 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + [ + [ + [1, 1], + [1, 10], + [10, 10], + [10, 1], + [1, 1] + ] + ], + [ + [ + [-1, -1], + [-1, -10], + [-10, -10], + [-10, -1], + [-1, -1] + ] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiLineString", + "coordinates": [ + [ + [1, 1], + [1, 2], + [1, 3], + [1, 4] + ], + [ + [2, 1], + [2, 2], + [2, 3], + [2, 4] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/touches/false/MultiPolygon/MultiPoint/MultiPolyNotTouchMultiPoint.geojson b/test/examples/booleans/touches/false/MultiPolygon/MultiPoint/MultiPolyNotTouchMultiPoint.geojson new file mode 100644 index 00000000..98da507a --- /dev/null +++ b/test/examples/booleans/touches/false/MultiPolygon/MultiPoint/MultiPolyNotTouchMultiPoint.geojson @@ -0,0 +1,43 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + [ + [ + [1, 1], + [1, 10], + [10, 10], + [10, 1], + [1, 1] + ] + ], + [ + [ + [-1, -1], + [-1, -10], + [-10, -10], + [-10, -1], + [-1, -1] + ] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPoint", + "coordinates": [ + [10, 14], + [-14, -14] + ] + } + } + ] +} diff --git a/test/examples/booleans/touches/false/MultiPolygon/MultiPolygon/MultiPolysDoNotTouch.geojson b/test/examples/booleans/touches/false/MultiPolygon/MultiPolygon/MultiPolysDoNotTouch.geojson new file mode 100644 index 00000000..e5beeadc --- /dev/null +++ b/test/examples/booleans/touches/false/MultiPolygon/MultiPolygon/MultiPolysDoNotTouch.geojson @@ -0,0 +1,50 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + [ + [ + [10, 10], + [10, 11], + [11, 11], + [11, 10], + [10, 10] + ] + ], + [ + [ + [30, 30], + [30, 40], + [40, 40], + [40, 30], + [30, 30] + ] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + [ + [ + [1, 1], + [1, 10], + [9, 9], + [10, 1], + [1, 1] + ] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/touches/false/MultiPolygon/MultiPolygon/MultiPolysOverlap.geojson b/test/examples/booleans/touches/false/MultiPolygon/MultiPolygon/MultiPolysOverlap.geojson new file mode 100644 index 00000000..6356e151 --- /dev/null +++ b/test/examples/booleans/touches/false/MultiPolygon/MultiPolygon/MultiPolysOverlap.geojson @@ -0,0 +1,50 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + [ + [ + [10, 10], + [10, 11], + [11, 11], + [11, 10], + [10, 10] + ] + ], + [ + [ + [30, 30], + [30, 40], + [40, 40], + [40, 30], + [30, 30] + ] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + [ + [ + [1, 1], + [1, 10], + [10.5, 10.5], + [10, 1], + [1, 1] + ] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/touches/false/MultiPolygon/Point/MultiPolyNotTouchPoint.geojson b/test/examples/booleans/touches/false/MultiPolygon/Point/MultiPolyNotTouchPoint.geojson new file mode 100644 index 00000000..c75f0b05 --- /dev/null +++ b/test/examples/booleans/touches/false/MultiPolygon/Point/MultiPolyNotTouchPoint.geojson @@ -0,0 +1,40 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + [ + [ + [1, 1], + [1, 10], + [10, 10], + [10, 1], + [1, 1] + ] + ], + [ + [ + [-1, -1], + [-1, -10], + [-10, -10], + [-10, -1], + [-1, -1] + ] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [14, 14] + } + } + ] +} diff --git a/test/examples/booleans/touches/false/Point/LineString/PointIsNotTouchLine.geojson b/test/examples/booleans/touches/false/Point/LineString/PointIsNotTouchLine.geojson new file mode 100644 index 00000000..e7595525 --- /dev/null +++ b/test/examples/booleans/touches/false/Point/LineString/PointIsNotTouchLine.geojson @@ -0,0 +1,26 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [2, 2] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [1, 1], + [1, 2], + [1, 3], + [1, 4] + ] + } + } + ] +} diff --git a/test/examples/booleans/touches/false/Point/LineString/PointOnMidLinestring.geojson b/test/examples/booleans/touches/false/Point/LineString/PointOnMidLinestring.geojson new file mode 100644 index 00000000..8cb3cc42 --- /dev/null +++ b/test/examples/booleans/touches/false/Point/LineString/PointOnMidLinestring.geojson @@ -0,0 +1,26 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [1, 2] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [1, 1], + [1, 2], + [1, 3], + [1, 4] + ] + } + } + ] +} diff --git a/test/examples/booleans/touches/false/Point/MultiLineString/MpNotTouchMidLineString.geojson b/test/examples/booleans/touches/false/Point/MultiLineString/MpNotTouchMidLineString.geojson new file mode 100644 index 00000000..9fbb963a --- /dev/null +++ b/test/examples/booleans/touches/false/Point/MultiLineString/MpNotTouchMidLineString.geojson @@ -0,0 +1,34 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [10, 4] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiLineString", + "coordinates": [ + [ + [1, 1], + [1, 2], + [1, 3], + [1, 4] + ], + [ + [2, 1], + [2, 2], + [2, 3], + [2, 4] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/touches/false/Point/MultiLineString/MpOnMidLineString.geojson b/test/examples/booleans/touches/false/Point/MultiLineString/MpOnMidLineString.geojson new file mode 100644 index 00000000..95061da0 --- /dev/null +++ b/test/examples/booleans/touches/false/Point/MultiLineString/MpOnMidLineString.geojson @@ -0,0 +1,34 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [1, 3] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiLineString", + "coordinates": [ + [ + [1, 1], + [1, 2], + [1, 3], + [1, 4] + ], + [ + [2, 1], + [2, 2], + [2, 3], + [2, 4] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/touches/false/Point/MultiPolygon/PointNotTouchMultipolygon.geojson b/test/examples/booleans/touches/false/Point/MultiPolygon/PointNotTouchMultipolygon.geojson new file mode 100644 index 00000000..30c016b8 --- /dev/null +++ b/test/examples/booleans/touches/false/Point/MultiPolygon/PointNotTouchMultipolygon.geojson @@ -0,0 +1,40 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [14, 14] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + [ + [ + [1, 1], + [1, 10], + [10, 10], + [10, 1], + [1, 1] + ] + ], + [ + [ + [-1, -1], + [-1, -10], + [-10, -10], + [-10, -1], + [-1, -1] + ] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/touches/false/Point/Polygon/PointDoesNotTouchPolygon.geojson b/test/examples/booleans/touches/false/Point/Polygon/PointDoesNotTouchPolygon.geojson new file mode 100644 index 00000000..3bc20282 --- /dev/null +++ b/test/examples/booleans/touches/false/Point/Polygon/PointDoesNotTouchPolygon.geojson @@ -0,0 +1,29 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [14, 14] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [1, 1], + [1, 10], + [10, 10], + [10, 1], + [1, 1] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/touches/false/Point/Polygon/PointInsidePolygon.geojson b/test/examples/booleans/touches/false/Point/Polygon/PointInsidePolygon.geojson new file mode 100644 index 00000000..0c44d959 --- /dev/null +++ b/test/examples/booleans/touches/false/Point/Polygon/PointInsidePolygon.geojson @@ -0,0 +1,29 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [2, 2] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [1, 1], + [1, 10], + [10, 10], + [10, 1], + [1, 1] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/touches/false/Polygon/LineString/PolyDoesNotTouchLine.geojson b/test/examples/booleans/touches/false/Polygon/LineString/PolyDoesNotTouchLine.geojson new file mode 100644 index 00000000..61f427a4 --- /dev/null +++ b/test/examples/booleans/touches/false/Polygon/LineString/PolyDoesNotTouchLine.geojson @@ -0,0 +1,32 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [-1, -2], + [-1, -3] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [1, 1], + [1, 10], + [10, 10], + [10, 1], + [1, 1] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/touches/false/Polygon/MultiLineString/PolyNotTouchMultiLine.geojson b/test/examples/booleans/touches/false/Polygon/MultiLineString/PolyNotTouchMultiLine.geojson new file mode 100644 index 00000000..0b8f2663 --- /dev/null +++ b/test/examples/booleans/touches/false/Polygon/MultiLineString/PolyNotTouchMultiLine.geojson @@ -0,0 +1,42 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [10, 10], + [10, 100], + [100, 100], + [100, 10], + [10, 10] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiLineString", + "coordinates": [ + [ + [1, 1], + [1, 2], + [1, 3], + [1, 4] + ], + [ + [2, 1], + [2, 2], + [2, 3], + [2, 4] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/touches/false/Polygon/MultiLineString/PolyOverlapMultiLine.geojson b/test/examples/booleans/touches/false/Polygon/MultiLineString/PolyOverlapMultiLine.geojson new file mode 100644 index 00000000..ff74557d --- /dev/null +++ b/test/examples/booleans/touches/false/Polygon/MultiLineString/PolyOverlapMultiLine.geojson @@ -0,0 +1,42 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [1, 1], + [1, 10], + [10, 10], + [10, 1], + [1, 1] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiLineString", + "coordinates": [ + [ + [1, 1], + [1, 2], + [1, 3], + [1, 4] + ], + [ + [2, 1], + [2, 2], + [2, 3], + [2, 4] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/touches/false/Polygon/MultiPoint/PolygonNoTouchMultiPoint.geojson b/test/examples/booleans/touches/false/Polygon/MultiPoint/PolygonNoTouchMultiPoint.geojson new file mode 100644 index 00000000..e379ce6d --- /dev/null +++ b/test/examples/booleans/touches/false/Polygon/MultiPoint/PolygonNoTouchMultiPoint.geojson @@ -0,0 +1,32 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [1, 1], + [1, 10], + [10, 10], + [10, 1], + [1, 1] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPoint", + "coordinates": [ + [0, 0], + [0, 10] + ] + } + } + ] +} diff --git a/test/examples/booleans/touches/false/Polygon/MultiPoint/PolygonOverlapsMultiPoint.geojson b/test/examples/booleans/touches/false/Polygon/MultiPoint/PolygonOverlapsMultiPoint.geojson new file mode 100644 index 00000000..5b7479c1 --- /dev/null +++ b/test/examples/booleans/touches/false/Polygon/MultiPoint/PolygonOverlapsMultiPoint.geojson @@ -0,0 +1,33 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [1, 1], + [1, 10], + [10, 10], + [10, 1], + [1, 1] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPoint", + "coordinates": [ + [2, 2], + [12, 12], + [15, 15] + ] + } + } + ] +} diff --git a/test/examples/booleans/touches/false/Polygon/MultiPolygon/PolyNotTouchMultipoly.geojson b/test/examples/booleans/touches/false/Polygon/MultiPolygon/PolyNotTouchMultipoly.geojson new file mode 100644 index 00000000..4ed0783e --- /dev/null +++ b/test/examples/booleans/touches/false/Polygon/MultiPolygon/PolyNotTouchMultipoly.geojson @@ -0,0 +1,48 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [1, 1], + [1, 10], + [9, 9], + [10, 1], + [1, 1] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + [ + [ + [10, 10], + [10, 11], + [11, 11], + [11, 10], + [10, 10] + ] + ], + [ + [ + [30, 30], + [30, 40], + [40, 40], + [40, 30], + [30, 30] + ] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/touches/false/Polygon/Point/PolygonDoesNotTouchPoint.geojson b/test/examples/booleans/touches/false/Polygon/Point/PolygonDoesNotTouchPoint.geojson new file mode 100644 index 00000000..09bb41c7 --- /dev/null +++ b/test/examples/booleans/touches/false/Polygon/Point/PolygonDoesNotTouchPoint.geojson @@ -0,0 +1,29 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [1, 1], + [1, 10], + [10, 10], + [10, 1], + [1, 1] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [14, 14] + } + } + ] +} diff --git a/test/examples/booleans/touches/false/Polygon/Point/PolygonOverlapsPoint.geojson b/test/examples/booleans/touches/false/Polygon/Point/PolygonOverlapsPoint.geojson new file mode 100644 index 00000000..b945b8e0 --- /dev/null +++ b/test/examples/booleans/touches/false/Polygon/Point/PolygonOverlapsPoint.geojson @@ -0,0 +1,29 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [1, 1], + [1, 10], + [10, 10], + [10, 1], + [1, 1] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [2, 2] + } + } + ] +} diff --git a/test/examples/booleans/touches/false/Polygon/Polygon/PolygonsDontTouch.geojson b/test/examples/booleans/touches/false/Polygon/Polygon/PolygonsDontTouch.geojson new file mode 100644 index 00000000..87fbbcaa --- /dev/null +++ b/test/examples/booleans/touches/false/Polygon/Polygon/PolygonsDontTouch.geojson @@ -0,0 +1,37 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [10, 10], + [10, 11], + [11, 11], + [11, 10], + [10, 10] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [1, 1], + [1, 10], + [9, 9], + [10, 1], + [1, 1] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/touches/false/Polygon/Polygon/PolygonsOverlap.geojson b/test/examples/booleans/touches/false/Polygon/Polygon/PolygonsOverlap.geojson new file mode 100644 index 00000000..8dc49f37 --- /dev/null +++ b/test/examples/booleans/touches/false/Polygon/Polygon/PolygonsOverlap.geojson @@ -0,0 +1,37 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [10, 10], + [10, 11], + [11, 11], + [11, 10], + [10, 10] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [1, 1], + [1, 10], + [11, 11], + [10, 1], + [1, 1] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/touches/true/LineString/LineString/LineTouchesEndpoint.geojson b/test/examples/booleans/touches/true/LineString/LineString/LineTouchesEndpoint.geojson new file mode 100644 index 00000000..45927008 --- /dev/null +++ b/test/examples/booleans/touches/true/LineString/LineString/LineTouchesEndpoint.geojson @@ -0,0 +1,28 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [1, 2], + [1, 3] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [1, 3], + [1, 4], + [1, 5] + ] + } + } + ] +} diff --git a/test/examples/booleans/touches/true/LineString/MultiLineString/LineStringTouchesEnd.geojson b/test/examples/booleans/touches/true/LineString/MultiLineString/LineStringTouchesEnd.geojson new file mode 100644 index 00000000..78fcf8fa --- /dev/null +++ b/test/examples/booleans/touches/true/LineString/MultiLineString/LineStringTouchesEnd.geojson @@ -0,0 +1,37 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [2, 5], + [2, 4] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiLineString", + "coordinates": [ + [ + [1, 1], + [1, 2], + [1, 3], + [1, 4] + ], + [ + [2, 1], + [2, 2], + [2, 3], + [2, 4] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/touches/true/LineString/MultiLineString/LineStringTouchesStart.geojson b/test/examples/booleans/touches/true/LineString/MultiLineString/LineStringTouchesStart.geojson new file mode 100644 index 00000000..8ef6dd51 --- /dev/null +++ b/test/examples/booleans/touches/true/LineString/MultiLineString/LineStringTouchesStart.geojson @@ -0,0 +1,37 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [0, 1], + [1, 1] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiLineString", + "coordinates": [ + [ + [1, 1], + [1, 2], + [1, 3], + [1, 4] + ], + [ + [2, 1], + [2, 2], + [2, 3], + [2, 4] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/touches/true/LineString/MultiPoint/MultipointTouchesLine.geojson b/test/examples/booleans/touches/true/LineString/MultiPoint/MultipointTouchesLine.geojson new file mode 100644 index 00000000..496c3bf6 --- /dev/null +++ b/test/examples/booleans/touches/true/LineString/MultiPoint/MultipointTouchesLine.geojson @@ -0,0 +1,30 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [1, 1], + [1, 2], + [1, 3], + [1, 4] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPoint", + "coordinates": [ + [1, 1], + [12, 12], + [15, 15] + ] + } + } + ] +} diff --git a/test/examples/booleans/touches/true/LineString/MultiPolygon/LineTouchesMultiPoly.geojson b/test/examples/booleans/touches/true/LineString/MultiPolygon/LineTouchesMultiPoly.geojson new file mode 100644 index 00000000..046fcafe --- /dev/null +++ b/test/examples/booleans/touches/true/LineString/MultiPolygon/LineTouchesMultiPoly.geojson @@ -0,0 +1,43 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [0, 1], + [1, 1] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + [ + [ + [1, 1], + [1, 10], + [10, 10], + [10, 1], + [1, 1] + ] + ], + [ + [ + [-1, -1], + [-1, -10], + [-10, -10], + [-10, -1], + [-1, -1] + ] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/touches/true/LineString/MultiPolygon/LineTouchesSecondMultiPoly.geojson b/test/examples/booleans/touches/true/LineString/MultiPolygon/LineTouchesSecondMultiPoly.geojson new file mode 100644 index 00000000..77d19417 --- /dev/null +++ b/test/examples/booleans/touches/true/LineString/MultiPolygon/LineTouchesSecondMultiPoly.geojson @@ -0,0 +1,43 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [-1, 1], + [-1, -1] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + [ + [ + [1, 1], + [1, 10], + [10, 10], + [10, 1], + [1, 1] + ] + ], + [ + [ + [-1, -1], + [-1, -10], + [-10, -10], + [-10, -1], + [-1, -1] + ] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/touches/true/LineString/Polygon/LineTouchesPolygon.geojson b/test/examples/booleans/touches/true/LineString/Polygon/LineTouchesPolygon.geojson new file mode 100644 index 00000000..8d3a846f --- /dev/null +++ b/test/examples/booleans/touches/true/LineString/Polygon/LineTouchesPolygon.geojson @@ -0,0 +1,33 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [0, 0], + [1, 1], + [1, 5] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [1, 1], + [1, 10], + [10, 10], + [10, 1], + [1, 1] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/touches/true/MultiLineString/LineString/MultiLineTouchesLine.geojson b/test/examples/booleans/touches/true/MultiLineString/LineString/MultiLineTouchesLine.geojson new file mode 100644 index 00000000..1f9b3972 --- /dev/null +++ b/test/examples/booleans/touches/true/MultiLineString/LineString/MultiLineTouchesLine.geojson @@ -0,0 +1,37 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiLineString", + "coordinates": [ + [ + [1, 1], + [1, 2], + [1, 3], + [1, 4] + ], + [ + [2, 1], + [2, 2], + [2, 3], + [2, 4] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [2, 0], + [2, 1] + ] + } + } + ] +} diff --git a/test/examples/booleans/touches/true/MultiLineString/MultiLineString/MultiLineTouchesMultiLine.geojson b/test/examples/booleans/touches/true/MultiLineString/MultiLineString/MultiLineTouchesMultiLine.geojson new file mode 100644 index 00000000..a7c9aef8 --- /dev/null +++ b/test/examples/booleans/touches/true/MultiLineString/MultiLineString/MultiLineTouchesMultiLine.geojson @@ -0,0 +1,43 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiLineString", + "coordinates": [ + [ + [1, 1], + [1, 2], + [1, 3], + [1, 4] + ], + [ + [2, 1], + [2, 2], + [2, 3], + [2, 4] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiLineString", + "coordinates": [ + [ + [12, 10], + [12, 11] + ], + [ + [2, 0], + [2, 1] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/touches/true/MultiLineString/MultiPoint/MultiLineTouchesMultiPoint.geojson b/test/examples/booleans/touches/true/MultiLineString/MultiPoint/MultiLineTouchesMultiPoint.geojson new file mode 100644 index 00000000..8ad24fa8 --- /dev/null +++ b/test/examples/booleans/touches/true/MultiLineString/MultiPoint/MultiLineTouchesMultiPoint.geojson @@ -0,0 +1,37 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiLineString", + "coordinates": [ + [ + [1, 1], + [1, 2], + [1, 3], + [1, 4] + ], + [ + [2, 1], + [2, 2], + [2, 3], + [2, 4] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPoint", + "coordinates": [ + [1, 1], + [10, 4] + ] + } + } + ] +} diff --git a/test/examples/booleans/touches/true/MultiLineString/Point/MultiLineTouchesPoint.geojson b/test/examples/booleans/touches/true/MultiLineString/Point/MultiLineTouchesPoint.geojson new file mode 100644 index 00000000..2be13eb2 --- /dev/null +++ b/test/examples/booleans/touches/true/MultiLineString/Point/MultiLineTouchesPoint.geojson @@ -0,0 +1,34 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiLineString", + "coordinates": [ + [ + [1, 1], + [1, 2], + [1, 3], + [1, 4] + ], + [ + [2, 1], + [2, 2], + [2, 3], + [2, 4] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [2, 4] + } + } + ] +} diff --git a/test/examples/booleans/touches/true/MultiLineString/Polygon/MultiLineTouchesPolygon.geojson b/test/examples/booleans/touches/true/MultiLineString/Polygon/MultiLineTouchesPolygon.geojson new file mode 100644 index 00000000..58348118 --- /dev/null +++ b/test/examples/booleans/touches/true/MultiLineString/Polygon/MultiLineTouchesPolygon.geojson @@ -0,0 +1,42 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiLineString", + "coordinates": [ + [ + [1, 1], + [1, 2], + [1, 3], + [1, 4] + ], + [ + [2, -1], + [2, 2], + [2, 3], + [2, 4] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [1, -1], + [1, -10], + [10, -10], + [10, -1], + [1, -1] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/touches/true/MultiPoint/LineString/MultipointTouchesLine.geojson b/test/examples/booleans/touches/true/MultiPoint/LineString/MultipointTouchesLine.geojson new file mode 100644 index 00000000..83c5eccf --- /dev/null +++ b/test/examples/booleans/touches/true/MultiPoint/LineString/MultipointTouchesLine.geojson @@ -0,0 +1,30 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPoint", + "coordinates": [ + [1, 1], + [12, 12], + [15, 15] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [1, 1], + [1, 2], + [1, 3], + [1, 4] + ] + } + } + ] +} diff --git a/test/examples/booleans/touches/true/MultiPoint/MultiLineString/MpTouchesEndMultiLine.geojson b/test/examples/booleans/touches/true/MultiPoint/MultiLineString/MpTouchesEndMultiLine.geojson new file mode 100644 index 00000000..faca8c6f --- /dev/null +++ b/test/examples/booleans/touches/true/MultiPoint/MultiLineString/MpTouchesEndMultiLine.geojson @@ -0,0 +1,37 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPoint", + "coordinates": [ + [1, 4], + [10, 4] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiLineString", + "coordinates": [ + [ + [1, 1], + [1, 2], + [1, 3], + [1, 4] + ], + [ + [2, 1], + [2, 2], + [2, 3], + [2, 4] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/touches/true/MultiPoint/MultiLineString/MpTouchesSecondMultiLine.geojson b/test/examples/booleans/touches/true/MultiPoint/MultiLineString/MpTouchesSecondMultiLine.geojson new file mode 100644 index 00000000..6e07deb3 --- /dev/null +++ b/test/examples/booleans/touches/true/MultiPoint/MultiLineString/MpTouchesSecondMultiLine.geojson @@ -0,0 +1,37 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPoint", + "coordinates": [ + [2, 4], + [10, 4] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiLineString", + "coordinates": [ + [ + [1, 1], + [1, 2], + [1, 3], + [1, 4] + ], + [ + [2, 1], + [2, 2], + [2, 3], + [2, 4] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/touches/true/MultiPoint/MultiPolygon/multipoint-touches-multipolygon.geojson b/test/examples/booleans/touches/true/MultiPoint/MultiPolygon/multipoint-touches-multipolygon.geojson new file mode 100644 index 00000000..5192bd0f --- /dev/null +++ b/test/examples/booleans/touches/true/MultiPoint/MultiPolygon/multipoint-touches-multipolygon.geojson @@ -0,0 +1,43 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPoint", + "coordinates": [ + [1, 1], + [-1, -1] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + [ + [ + [1, 1], + [1, 10], + [10, 10], + [10, 1], + [1, 1] + ] + ], + [ + [ + [-1, -1], + [-1, -10], + [-10, -10], + [-10, -1], + [-1, -1] + ] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/touches/true/MultiPoint/Polygon/MultiPointIsWithinPolygon.geojson b/test/examples/booleans/touches/true/MultiPoint/Polygon/MultiPointIsWithinPolygon.geojson new file mode 100644 index 00000000..b45ca953 --- /dev/null +++ b/test/examples/booleans/touches/true/MultiPoint/Polygon/MultiPointIsWithinPolygon.geojson @@ -0,0 +1,32 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPoint", + "coordinates": [ + [1, 1], + [14, 14] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [1, 1], + [1, 10], + [10, 10], + [10, 1], + [1, 1] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/touches/true/MultiPolygon/MultiLineString/MultiLineTouchesMultiPoly.geojson b/test/examples/booleans/touches/true/MultiPolygon/MultiLineString/MultiLineTouchesMultiPoly.geojson new file mode 100644 index 00000000..b6864333 --- /dev/null +++ b/test/examples/booleans/touches/true/MultiPolygon/MultiLineString/MultiLineTouchesMultiPoly.geojson @@ -0,0 +1,53 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + [ + [ + [20, -2], + [20, -20], + [40, -20], + [40, -2], + [20, -2] + ] + ], + [ + [ + [1, -1], + [1, -10], + [10, -10], + [10, -1], + [1, -1] + ] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiLineString", + "coordinates": [ + [ + [1, 1], + [1, 2], + [1, 3], + [1, 4] + ], + [ + [2, -1], + [2, 2], + [2, 3], + [2, 4] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/touches/true/MultiPolygon/MultiPoint/MultiPolyTouchesMultiPoint.geojson b/test/examples/booleans/touches/true/MultiPolygon/MultiPoint/MultiPolyTouchesMultiPoint.geojson new file mode 100644 index 00000000..d89beb30 --- /dev/null +++ b/test/examples/booleans/touches/true/MultiPolygon/MultiPoint/MultiPolyTouchesMultiPoint.geojson @@ -0,0 +1,34 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + [ + [ + [1, 1], + [1, 10], + [10, 10], + [10, 1], + [1, 1] + ] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPoint", + "coordinates": [ + [1, 1], + [14, 14] + ] + } + } + ] +} diff --git a/test/examples/booleans/touches/true/MultiPolygon/MultiPolygon/MultiPolyTouchesMultiPoly.geojson b/test/examples/booleans/touches/true/MultiPolygon/MultiPolygon/MultiPolyTouchesMultiPoly.geojson new file mode 100644 index 00000000..c6b54130 --- /dev/null +++ b/test/examples/booleans/touches/true/MultiPolygon/MultiPolygon/MultiPolyTouchesMultiPoly.geojson @@ -0,0 +1,50 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + [ + [ + [10, 10], + [10, 11], + [11, 11], + [11, 10], + [10, 10] + ] + ], + [ + [ + [30, 30], + [30, 40], + [40, 40], + [40, 30], + [30, 30] + ] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + [ + [ + [1, 1], + [1, 10], + [10, 11], + [10, 1], + [1, 1] + ] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/touches/true/MultiPolygon/Point/MpTouchesPoint.geojson b/test/examples/booleans/touches/true/MultiPolygon/Point/MpTouchesPoint.geojson new file mode 100644 index 00000000..90c6f586 --- /dev/null +++ b/test/examples/booleans/touches/true/MultiPolygon/Point/MpTouchesPoint.geojson @@ -0,0 +1,31 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + [ + [ + [1, 1], + [1, 10], + [10, 10], + [10, 1], + [1, 1] + ] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [1, 5] + } + } + ] +} diff --git a/test/examples/booleans/touches/true/MultiPolygon/Polygon/MultiPolyTouchesPoly.geojson b/test/examples/booleans/touches/true/MultiPolygon/Polygon/MultiPolyTouchesPoly.geojson new file mode 100644 index 00000000..3a18ef22 --- /dev/null +++ b/test/examples/booleans/touches/true/MultiPolygon/Polygon/MultiPolyTouchesPoly.geojson @@ -0,0 +1,48 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + [ + [ + [10, 10], + [10, 11], + [11, 11], + [11, 10], + [10, 10] + ] + ], + [ + [ + [30, 30], + [30, 40], + [40, 40], + [40, 30], + [30, 30] + ] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [1, 1], + [1, 10], + [10, 11], + [10, 1], + [1, 1] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/touches/true/Point/LineString/PointOnEndLine.geojson b/test/examples/booleans/touches/true/Point/LineString/PointOnEndLine.geojson new file mode 100644 index 00000000..b30df470 --- /dev/null +++ b/test/examples/booleans/touches/true/Point/LineString/PointOnEndLine.geojson @@ -0,0 +1,26 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [1, 4] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [1, 1], + [1, 2], + [1, 3], + [1, 4] + ] + } + } + ] +} diff --git a/test/examples/booleans/touches/true/Point/LineString/PointOnStartLine.geojson b/test/examples/booleans/touches/true/Point/LineString/PointOnStartLine.geojson new file mode 100644 index 00000000..b84728a8 --- /dev/null +++ b/test/examples/booleans/touches/true/Point/LineString/PointOnStartLine.geojson @@ -0,0 +1,26 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [1, 1] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [1, 1], + [1, 2], + [1, 3], + [1, 4] + ] + } + } + ] +} diff --git a/test/examples/booleans/touches/true/Point/MultiLineString/MpOnEndLine.geojson b/test/examples/booleans/touches/true/Point/MultiLineString/MpOnEndLine.geojson new file mode 100644 index 00000000..58dbf02b --- /dev/null +++ b/test/examples/booleans/touches/true/Point/MultiLineString/MpOnEndLine.geojson @@ -0,0 +1,34 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [1, 4] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiLineString", + "coordinates": [ + [ + [1, 1], + [1, 2], + [1, 3], + [1, 4] + ], + [ + [2, 1], + [2, 2], + [2, 3], + [2, 4] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/touches/true/Point/MultiLineString/MpOnStartLine.geojson b/test/examples/booleans/touches/true/Point/MultiLineString/MpOnStartLine.geojson new file mode 100644 index 00000000..34c52729 --- /dev/null +++ b/test/examples/booleans/touches/true/Point/MultiLineString/MpOnStartLine.geojson @@ -0,0 +1,34 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [2, 1] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiLineString", + "coordinates": [ + [ + [1, 1], + [1, 2], + [1, 3], + [1, 4] + ], + [ + [2, 1], + [2, 2], + [2, 3], + [2, 4] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/touches/true/Point/MultiPolygon/PointTouchesMultipolygon.geojson b/test/examples/booleans/touches/true/Point/MultiPolygon/PointTouchesMultipolygon.geojson new file mode 100644 index 00000000..40153b61 --- /dev/null +++ b/test/examples/booleans/touches/true/Point/MultiPolygon/PointTouchesMultipolygon.geojson @@ -0,0 +1,40 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [1, 2] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + [ + [ + [1, 1], + [1, 10], + [10, 10], + [10, 1], + [1, 1] + ] + ], + [ + [ + [-1, -1], + [-1, -10], + [-10, -10], + [-10, -1], + [-1, -1] + ] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/touches/true/Point/MultiPolygon/PointTouchesMultipolygonHole.geojson b/test/examples/booleans/touches/true/Point/MultiPolygon/PointTouchesMultipolygonHole.geojson new file mode 100644 index 00000000..f60d3a63 --- /dev/null +++ b/test/examples/booleans/touches/true/Point/MultiPolygon/PointTouchesMultipolygonHole.geojson @@ -0,0 +1,46 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [2, 2] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + [ + [ + [1, 1], + [1, 10], + [10, 10], + [10, 1], + [1, 1] + ], + [ + [2, 2], + [2, 4], + [4, 4], + [2, 2] + ] + ], + [ + [ + [-1, -1], + [-1, -10], + [-10, -10], + [-10, -1], + [-1, -1] + ] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/touches/true/Point/Polygon/PointOnEdgePolygon.geojson b/test/examples/booleans/touches/true/Point/Polygon/PointOnEdgePolygon.geojson new file mode 100644 index 00000000..aacac561 --- /dev/null +++ b/test/examples/booleans/touches/true/Point/Polygon/PointOnEdgePolygon.geojson @@ -0,0 +1,29 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [1, 5] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [1, 1], + [1, 10], + [10, 10], + [10, 1], + [1, 1] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/touches/true/Point/Polygon/PointOnHole.geojson b/test/examples/booleans/touches/true/Point/Polygon/PointOnHole.geojson new file mode 100644 index 00000000..4c6d4107 --- /dev/null +++ b/test/examples/booleans/touches/true/Point/Polygon/PointOnHole.geojson @@ -0,0 +1,35 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [2, 2] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [1, 1], + [1, 10], + [10, 10], + [10, 1], + [1, 1] + ], + [ + [2, 2], + [2, 4], + [4, 4], + [2, 2] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/touches/true/Point/Polygon/PointOnVerticePolygon.geojson b/test/examples/booleans/touches/true/Point/Polygon/PointOnVerticePolygon.geojson new file mode 100644 index 00000000..d24f78bd --- /dev/null +++ b/test/examples/booleans/touches/true/Point/Polygon/PointOnVerticePolygon.geojson @@ -0,0 +1,29 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [1, 1] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [1, 1], + [1, 10], + [10, 10], + [10, 1], + [1, 1] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/touches/true/Polygon/LineString/PolygonTouchesLines.geojson b/test/examples/booleans/touches/true/Polygon/LineString/PolygonTouchesLines.geojson new file mode 100644 index 00000000..6d176969 --- /dev/null +++ b/test/examples/booleans/touches/true/Polygon/LineString/PolygonTouchesLines.geojson @@ -0,0 +1,33 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [1, 1], + [1, 10], + [10, 10], + [10, 1], + [1, 1] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [0, 0], + [1, 1], + [1, 5] + ] + } + } + ] +} diff --git a/test/examples/booleans/touches/true/Polygon/MultiLineString/PolygonTouchesMultiline.geojson b/test/examples/booleans/touches/true/Polygon/MultiLineString/PolygonTouchesMultiline.geojson new file mode 100644 index 00000000..a63d41f4 --- /dev/null +++ b/test/examples/booleans/touches/true/Polygon/MultiLineString/PolygonTouchesMultiline.geojson @@ -0,0 +1,42 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [1, -1], + [1, -10], + [10, -10], + [10, -1], + [1, -1] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiLineString", + "coordinates": [ + [ + [1, 1], + [1, 2], + [1, 3], + [1, 4] + ], + [ + [2, -1], + [2, 2], + [2, 3], + [2, 4] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/touches/true/Polygon/MultiPoint/PolygonTouchesMultiPoint.geojson b/test/examples/booleans/touches/true/Polygon/MultiPoint/PolygonTouchesMultiPoint.geojson new file mode 100644 index 00000000..1a7e7091 --- /dev/null +++ b/test/examples/booleans/touches/true/Polygon/MultiPoint/PolygonTouchesMultiPoint.geojson @@ -0,0 +1,32 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [1, 1], + [1, 10], + [10, 10], + [10, 1], + [1, 1] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPoint", + "coordinates": [ + [1, 1], + [14, 14] + ] + } + } + ] +} diff --git a/test/examples/booleans/touches/true/Polygon/MultiPolygon/PolyTouchMultiPolys.geojson b/test/examples/booleans/touches/true/Polygon/MultiPolygon/PolyTouchMultiPolys.geojson new file mode 100644 index 00000000..2ea4111b --- /dev/null +++ b/test/examples/booleans/touches/true/Polygon/MultiPolygon/PolyTouchMultiPolys.geojson @@ -0,0 +1,48 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [1, 1], + [1, 10], + [10, 11], + [10, 1], + [1, 1] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + [ + [ + [10, 10], + [10, 11], + [11, 11], + [11, 10], + [10, 10] + ] + ], + [ + [ + [30, 30], + [30, 40], + [40, 40], + [40, 30], + [30, 30] + ] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/touches/true/Polygon/Point/PolygonTouchesPoint.geojson b/test/examples/booleans/touches/true/Polygon/Point/PolygonTouchesPoint.geojson new file mode 100644 index 00000000..8cba1bf9 --- /dev/null +++ b/test/examples/booleans/touches/true/Polygon/Point/PolygonTouchesPoint.geojson @@ -0,0 +1,29 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [1, 1], + [1, 10], + [10, 10], + [10, 1], + [1, 1] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [1, 5] + } + } + ] +} diff --git a/test/examples/booleans/touches/true/Polygon/Point/PolygonTouchesPointVertice.geojson b/test/examples/booleans/touches/true/Polygon/Point/PolygonTouchesPointVertice.geojson new file mode 100644 index 00000000..685a46d3 --- /dev/null +++ b/test/examples/booleans/touches/true/Polygon/Point/PolygonTouchesPointVertice.geojson @@ -0,0 +1,29 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [1, 1], + [1, 10], + [10, 10], + [10, 1], + [1, 1] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [1, 1] + } + } + ] +} diff --git a/test/examples/booleans/touches/true/Polygon/Polygon/PolygonTouchesEdges.geojson b/test/examples/booleans/touches/true/Polygon/Polygon/PolygonTouchesEdges.geojson new file mode 100644 index 00000000..ac9b8b79 --- /dev/null +++ b/test/examples/booleans/touches/true/Polygon/Polygon/PolygonTouchesEdges.geojson @@ -0,0 +1,37 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [10, 10], + [10, 11], + [11, 11], + [11, 10], + [10, 10] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [1, 1], + [1, 10], + [10, 11], + [10, 1], + [1, 1] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/touches/true/Polygon/Polygon/PolygonsTouchVertices.geojson b/test/examples/booleans/touches/true/Polygon/Polygon/PolygonsTouchVertices.geojson new file mode 100644 index 00000000..e66806a7 --- /dev/null +++ b/test/examples/booleans/touches/true/Polygon/Polygon/PolygonsTouchVertices.geojson @@ -0,0 +1,37 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [10, 10], + [10, 11], + [11, 11], + [11, 10], + [10, 10] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [1, 1], + [1, 10], + [10, 10], + [10, 1], + [1, 1] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/within/false/LineString/LineString/LineIsNotWithinLine.geojson b/test/examples/booleans/within/false/LineString/LineString/LineIsNotWithinLine.geojson new file mode 100644 index 00000000..28c41a8c --- /dev/null +++ b/test/examples/booleans/within/false/LineString/LineString/LineIsNotWithinLine.geojson @@ -0,0 +1,30 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [1, 2], + [1, 3], + [1, 15.5] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [1, 1], + [1, 2], + [1, 3], + [1, 4] + ] + } + } + ] +} diff --git a/test/examples/booleans/within/false/LineString/Polygon/LineIsNotWIthinPolygon.geojson b/test/examples/booleans/within/false/LineString/Polygon/LineIsNotWIthinPolygon.geojson new file mode 100644 index 00000000..c70523db --- /dev/null +++ b/test/examples/booleans/within/false/LineString/Polygon/LineIsNotWIthinPolygon.geojson @@ -0,0 +1,33 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [1, 2], + [1, 3], + [1, 15.5] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [1, 1], + [1, 10], + [10, 10], + [10, 1], + [1, 1] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/within/false/LineString/Polygon/LineIsNotWIthinPolygonBoundary.geojson b/test/examples/booleans/within/false/LineString/Polygon/LineIsNotWIthinPolygonBoundary.geojson new file mode 100644 index 00000000..d0125aa9 --- /dev/null +++ b/test/examples/booleans/within/false/LineString/Polygon/LineIsNotWIthinPolygonBoundary.geojson @@ -0,0 +1,33 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [1, 2], + [1, 3], + [1, 3.5] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [1, 1], + [1, 10], + [10, 10], + [10, 1], + [1, 1] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/within/false/MultiLineString/MultiPolygon/skip-multilinestring-not-within-multipolygon.geojson b/test/examples/booleans/within/false/MultiLineString/MultiPolygon/skip-multilinestring-not-within-multipolygon.geojson new file mode 100644 index 00000000..f2aca1a0 --- /dev/null +++ b/test/examples/booleans/within/false/MultiLineString/MultiPolygon/skip-multilinestring-not-within-multipolygon.geojson @@ -0,0 +1,49 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiLineString", + "coordinates": [ + [ + [4, 4], + [1, 1] + ], + [ + [-14, -14], + [-11, -11] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + [ + [ + [1, 1], + [1, 10], + [10, 10], + [10, 1], + [1, 1] + ] + ], + [ + [ + [-1, -1], + [-1, -10], + [-10, -10], + [-10, -1], + [-1, -1] + ] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/within/false/MultiPoint/LineString/MultiPointsIsNotWIthinLine.geojson b/test/examples/booleans/within/false/MultiPoint/LineString/MultiPointsIsNotWIthinLine.geojson new file mode 100644 index 00000000..83c5eccf --- /dev/null +++ b/test/examples/booleans/within/false/MultiPoint/LineString/MultiPointsIsNotWIthinLine.geojson @@ -0,0 +1,30 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPoint", + "coordinates": [ + [1, 1], + [12, 12], + [15, 15] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [1, 1], + [1, 2], + [1, 3], + [1, 4] + ] + } + } + ] +} diff --git a/test/examples/booleans/within/false/MultiPoint/LineString/MultiPointsOnLineEndsIsNotWIthinLine.geojson b/test/examples/booleans/within/false/MultiPoint/LineString/MultiPointsOnLineEndsIsNotWIthinLine.geojson new file mode 100644 index 00000000..a99fcbc1 --- /dev/null +++ b/test/examples/booleans/within/false/MultiPoint/LineString/MultiPointsOnLineEndsIsNotWIthinLine.geojson @@ -0,0 +1,29 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPoint", + "coordinates": [ + [1, 1], + [1, 4] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [1, 1], + [1, 2], + [1, 3], + [1, 4] + ] + } + } + ] +} diff --git a/test/examples/booleans/within/false/MultiPoint/MultiPoint/MultiPointIsNotWithinMultiPoint.geojson b/test/examples/booleans/within/false/MultiPoint/MultiPoint/MultiPointIsNotWithinMultiPoint.geojson new file mode 100644 index 00000000..d00c24ab --- /dev/null +++ b/test/examples/booleans/within/false/MultiPoint/MultiPoint/MultiPointIsNotWithinMultiPoint.geojson @@ -0,0 +1,28 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPoint", + "coordinates": [ + [1, 1], + [1, 1.5] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPoint", + "coordinates": [ + [1, 1], + [12, 12], + [15, 15] + ] + } + } + ] +} diff --git a/test/examples/booleans/within/false/MultiPoint/MultiPolygon/multipoint-not-within-multipolygon.geojson b/test/examples/booleans/within/false/MultiPoint/MultiPolygon/multipoint-not-within-multipolygon.geojson new file mode 100644 index 00000000..7cd0e752 --- /dev/null +++ b/test/examples/booleans/within/false/MultiPoint/MultiPolygon/multipoint-not-within-multipolygon.geojson @@ -0,0 +1,43 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPoint", + "coordinates": [ + [4, 4], + [-14, -14] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + [ + [ + [1, 1], + [1, 10], + [10, 10], + [10, 1], + [1, 1] + ] + ], + [ + [ + [-1, -1], + [-1, -10], + [-10, -10], + [-10, -1], + [-1, -1] + ] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/within/false/MultiPoint/Polygon/MultiPointAllOnBoundaryIsNotWithinPolygon.geojson b/test/examples/booleans/within/false/MultiPoint/Polygon/MultiPointAllOnBoundaryIsNotWithinPolygon.geojson new file mode 100644 index 00000000..d69eb204 --- /dev/null +++ b/test/examples/booleans/within/false/MultiPoint/Polygon/MultiPointAllOnBoundaryIsNotWithinPolygon.geojson @@ -0,0 +1,32 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPoint", + "coordinates": [ + [1, 1], + [1, 10] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [1, 1], + [1, 10], + [10, 10], + [10, 1], + [1, 1] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/within/false/MultiPoint/Polygon/MultiPointIsNotWithinPolygon.geojson b/test/examples/booleans/within/false/MultiPoint/Polygon/MultiPointIsNotWithinPolygon.geojson new file mode 100644 index 00000000..81743c73 --- /dev/null +++ b/test/examples/booleans/within/false/MultiPoint/Polygon/MultiPointIsNotWithinPolygon.geojson @@ -0,0 +1,33 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPoint", + "coordinates": [ + [1, 1], + [12, 12], + [15, 15] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [1, 1], + [1, 10], + [10, 10], + [10, 1], + [1, 1] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/within/false/Point/LineString/PointIsNotWithinLine.geojson b/test/examples/booleans/within/false/Point/LineString/PointIsNotWithinLine.geojson new file mode 100644 index 00000000..e7595525 --- /dev/null +++ b/test/examples/booleans/within/false/Point/LineString/PointIsNotWithinLine.geojson @@ -0,0 +1,26 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [2, 2] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [1, 1], + [1, 2], + [1, 3], + [1, 4] + ] + } + } + ] +} diff --git a/test/examples/booleans/within/false/Point/LineString/PointIsNotWithinLineBecauseOnEnd.geojson b/test/examples/booleans/within/false/Point/LineString/PointIsNotWithinLineBecauseOnEnd.geojson new file mode 100644 index 00000000..b30df470 --- /dev/null +++ b/test/examples/booleans/within/false/Point/LineString/PointIsNotWithinLineBecauseOnEnd.geojson @@ -0,0 +1,26 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [1, 4] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [1, 1], + [1, 2], + [1, 3], + [1, 4] + ] + } + } + ] +} diff --git a/test/examples/booleans/within/false/Point/LineString/PointOnEndIsWithinLinestring.geojson b/test/examples/booleans/within/false/Point/LineString/PointOnEndIsWithinLinestring.geojson new file mode 100644 index 00000000..b84728a8 --- /dev/null +++ b/test/examples/booleans/within/false/Point/LineString/PointOnEndIsWithinLinestring.geojson @@ -0,0 +1,26 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [1, 1] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [1, 1], + [1, 2], + [1, 3], + [1, 4] + ] + } + } + ] +} diff --git a/test/examples/booleans/within/false/Point/MultiPoint/PointIsNotWithinMultiPoint.geojson b/test/examples/booleans/within/false/Point/MultiPoint/PointIsNotWithinMultiPoint.geojson new file mode 100644 index 00000000..ad262c65 --- /dev/null +++ b/test/examples/booleans/within/false/Point/MultiPoint/PointIsNotWithinMultiPoint.geojson @@ -0,0 +1,24 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [1, 4] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPoint", + "coordinates": [ + [1, 1], + [12, 12] + ] + } + } + ] +} diff --git a/test/examples/booleans/within/false/Point/MultiPolygon/point-not-within-multipolygon.geojson b/test/examples/booleans/within/false/Point/MultiPolygon/point-not-within-multipolygon.geojson new file mode 100644 index 00000000..30c016b8 --- /dev/null +++ b/test/examples/booleans/within/false/Point/MultiPolygon/point-not-within-multipolygon.geojson @@ -0,0 +1,40 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [14, 14] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + [ + [ + [1, 1], + [1, 10], + [10, 10], + [10, 1], + [1, 1] + ] + ], + [ + [ + [-1, -1], + [-1, -10], + [-10, -10], + [-10, -1], + [-1, -1] + ] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/within/false/Point/Polygon/PointIsNotWithinPolygon.geojson b/test/examples/booleans/within/false/Point/Polygon/PointIsNotWithinPolygon.geojson new file mode 100644 index 00000000..3bc20282 --- /dev/null +++ b/test/examples/booleans/within/false/Point/Polygon/PointIsNotWithinPolygon.geojson @@ -0,0 +1,29 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [14, 14] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [1, 1], + [1, 10], + [10, 10], + [10, 1], + [1, 1] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/within/false/Point/Polygon/PointOnPolygonBoundary.geojson b/test/examples/booleans/within/false/Point/Polygon/PointOnPolygonBoundary.geojson new file mode 100644 index 00000000..d24f78bd --- /dev/null +++ b/test/examples/booleans/within/false/Point/Polygon/PointOnPolygonBoundary.geojson @@ -0,0 +1,29 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [1, 1] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [1, 1], + [1, 10], + [10, 10], + [10, 1], + [1, 1] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/within/false/Polygon/MultiPolygon/polygon-not-within-multipolygon.geojson b/test/examples/booleans/within/false/Polygon/MultiPolygon/polygon-not-within-multipolygon.geojson new file mode 100644 index 00000000..fb07e048 --- /dev/null +++ b/test/examples/booleans/within/false/Polygon/MultiPolygon/polygon-not-within-multipolygon.geojson @@ -0,0 +1,48 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [-12, -12], + [-12, -19], + [-19, -19], + [-19, -12], + [-12, -12] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + [ + [ + [1, 1], + [1, 10], + [10, 10], + [10, 1], + [1, 1] + ] + ], + [ + [ + [-1, -1], + [-1, -10], + [-10, -10], + [-10, -1], + [-1, -1] + ] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/within/false/Polygon/Polygon/Polygon-Polygon.geojson b/test/examples/booleans/within/false/Polygon/Polygon/Polygon-Polygon.geojson new file mode 100644 index 00000000..5a1b4256 --- /dev/null +++ b/test/examples/booleans/within/false/Polygon/Polygon/Polygon-Polygon.geojson @@ -0,0 +1,37 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [1, 1], + [1, 20], + [1, 3], + [1, 4], + [1, 1] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [1, 1], + [1, 10], + [10, 10], + [10, 1], + [1, 1] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/within/true/LineString/LineString/LineIsWithinLine.geojson b/test/examples/booleans/within/true/LineString/LineString/LineIsWithinLine.geojson new file mode 100644 index 00000000..dcf5cb15 --- /dev/null +++ b/test/examples/booleans/within/true/LineString/LineString/LineIsWithinLine.geojson @@ -0,0 +1,30 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [1, 2], + [1, 3], + [1, 3.5] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [1, 1], + [1, 2], + [1, 3], + [1, 4] + ] + } + } + ] +} diff --git a/test/examples/booleans/within/true/LineString/LineString/LinesExactSame.geojson b/test/examples/booleans/within/true/LineString/LineString/LinesExactSame.geojson new file mode 100644 index 00000000..034737ba --- /dev/null +++ b/test/examples/booleans/within/true/LineString/LineString/LinesExactSame.geojson @@ -0,0 +1,31 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [1, 1], + [1, 2], + [1, 3], + [1, 4] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [1, 1], + [1, 2], + [1, 3], + [1, 4] + ] + } + } + ] +} diff --git a/test/examples/booleans/within/true/LineString/Polygon/LineIsContainedByPolygon.geojson b/test/examples/booleans/within/true/LineString/Polygon/LineIsContainedByPolygon.geojson new file mode 100644 index 00000000..eba012ac --- /dev/null +++ b/test/examples/booleans/within/true/LineString/Polygon/LineIsContainedByPolygon.geojson @@ -0,0 +1,33 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [1, 1], + [2, 3], + [2, 3.5] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [1, 1], + [1, 10], + [10, 10], + [10, 1], + [1, 1] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/within/true/LineString/Polygon/LineIsContainedByPolygonWithNoInternalVertices.geojson b/test/examples/booleans/within/true/LineString/Polygon/LineIsContainedByPolygonWithNoInternalVertices.geojson new file mode 100644 index 00000000..4d4f566f --- /dev/null +++ b/test/examples/booleans/within/true/LineString/Polygon/LineIsContainedByPolygonWithNoInternalVertices.geojson @@ -0,0 +1,32 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [1, 1], + [10, 10] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [1, 1], + [1, 10], + [10, 10], + [10, 1], + [1, 1] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/within/true/MultiLineString/MultiPolygon/skip-multilinestring-within-multipolygon.geojson b/test/examples/booleans/within/true/MultiLineString/MultiPolygon/skip-multilinestring-within-multipolygon.geojson new file mode 100644 index 00000000..1def29af --- /dev/null +++ b/test/examples/booleans/within/true/MultiLineString/MultiPolygon/skip-multilinestring-within-multipolygon.geojson @@ -0,0 +1,49 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiLineString", + "coordinates": [ + [ + [4, 4], + [1, 1] + ], + [ + [-4, -4], + [-1, -1] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + [ + [ + [1, 1], + [1, 10], + [10, 10], + [10, 1], + [1, 1] + ] + ], + [ + [ + [-1, -1], + [-1, -10], + [-10, -10], + [-10, -1], + [-1, -1] + ] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/within/true/MultiPoint/LineString/MultipointsIsWithinLine.geojson b/test/examples/booleans/within/true/MultiPoint/LineString/MultipointsIsWithinLine.geojson new file mode 100644 index 00000000..cdf0856c --- /dev/null +++ b/test/examples/booleans/within/true/MultiPoint/LineString/MultipointsIsWithinLine.geojson @@ -0,0 +1,29 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPoint", + "coordinates": [ + [1, 1], + [1, 1.5] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [1, 1], + [1, 2], + [1, 3], + [1, 4] + ] + } + } + ] +} diff --git a/test/examples/booleans/within/true/MultiPoint/MultiPoint/MultiPointsWithinMultiPoints.geojson b/test/examples/booleans/within/true/MultiPoint/MultiPoint/MultiPointsWithinMultiPoints.geojson new file mode 100644 index 00000000..8a0585fe --- /dev/null +++ b/test/examples/booleans/within/true/MultiPoint/MultiPoint/MultiPointsWithinMultiPoints.geojson @@ -0,0 +1,29 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPoint", + "coordinates": [ + [1, 1], + [12, 12], + [15, 15] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPoint", + "coordinates": [ + [1, 1], + [12, 12], + [15, 15] + ] + } + } + ] +} diff --git a/test/examples/booleans/within/true/MultiPoint/MultiPolygon/multipoint-within-multipolygon.geojson b/test/examples/booleans/within/true/MultiPoint/MultiPolygon/multipoint-within-multipolygon.geojson new file mode 100644 index 00000000..9d78da41 --- /dev/null +++ b/test/examples/booleans/within/true/MultiPoint/MultiPolygon/multipoint-within-multipolygon.geojson @@ -0,0 +1,43 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPoint", + "coordinates": [ + [4, 4], + [-4, -4] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + [ + [ + [1, 1], + [1, 10], + [10, 10], + [10, 1], + [1, 1] + ] + ], + [ + [ + [-1, -1], + [-1, -10], + [-10, -10], + [-10, -1], + [-1, -1] + ] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/within/true/MultiPoint/Polygon/MultiPointIsWithinPolygon.geojson b/test/examples/booleans/within/true/MultiPoint/Polygon/MultiPointIsWithinPolygon.geojson new file mode 100644 index 00000000..81f544da --- /dev/null +++ b/test/examples/booleans/within/true/MultiPoint/Polygon/MultiPointIsWithinPolygon.geojson @@ -0,0 +1,32 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPoint", + "coordinates": [ + [1, 1], + [4, 4] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [1, 1], + [1, 10], + [10, 10], + [10, 1], + [1, 1] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/within/true/MultiPoint/Polygon/MultiPointSingleIsWithinPolygon.geojson b/test/examples/booleans/within/true/MultiPoint/Polygon/MultiPointSingleIsWithinPolygon.geojson new file mode 100644 index 00000000..f4645c5f --- /dev/null +++ b/test/examples/booleans/within/true/MultiPoint/Polygon/MultiPointSingleIsWithinPolygon.geojson @@ -0,0 +1,29 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPoint", + "coordinates": [[2, 2]] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [1, 1], + [1, 10], + [10, 10], + [10, 1], + [1, 1] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/within/true/MultiPolygon/MultiPolygon/skip-multipolygon-within-multipolygon.geojson b/test/examples/booleans/within/true/MultiPolygon/MultiPolygon/skip-multipolygon-within-multipolygon.geojson new file mode 100644 index 00000000..85aa17cf --- /dev/null +++ b/test/examples/booleans/within/true/MultiPolygon/MultiPolygon/skip-multipolygon-within-multipolygon.geojson @@ -0,0 +1,59 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + [ + [ + [2, 2], + [2, 9], + [9, 9], + [9, 2], + [2, 2] + ] + ], + [ + [ + [-2, -2], + [-2, -9], + [-9, -9], + [-9, -2], + [-2, -2] + ] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + [ + [ + [1, 1], + [1, 10], + [10, 10], + [10, 1], + [1, 1] + ] + ], + [ + [ + [-1, -1], + [-1, -10], + [-10, -10], + [-10, -1], + [-1, -1] + ] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/within/true/Point/LineString/PointIsWithinLine.geojson b/test/examples/booleans/within/true/Point/LineString/PointIsWithinLine.geojson new file mode 100644 index 00000000..8cb3cc42 --- /dev/null +++ b/test/examples/booleans/within/true/Point/LineString/PointIsWithinLine.geojson @@ -0,0 +1,26 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [1, 2] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [1, 1], + [1, 2], + [1, 3], + [1, 4] + ] + } + } + ] +} diff --git a/test/examples/booleans/within/true/Point/MultiPoint/PointIsWithinMultiPoint.geojson b/test/examples/booleans/within/true/Point/MultiPoint/PointIsWithinMultiPoint.geojson new file mode 100644 index 00000000..f958a470 --- /dev/null +++ b/test/examples/booleans/within/true/Point/MultiPoint/PointIsWithinMultiPoint.geojson @@ -0,0 +1,24 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [1, 1] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPoint", + "coordinates": [ + [1, 1], + [12, 12] + ] + } + } + ] +} diff --git a/test/examples/booleans/within/true/Point/MultiPolygon/point-within-multipolygon.geojson b/test/examples/booleans/within/true/Point/MultiPolygon/point-within-multipolygon.geojson new file mode 100644 index 00000000..84d378bc --- /dev/null +++ b/test/examples/booleans/within/true/Point/MultiPolygon/point-within-multipolygon.geojson @@ -0,0 +1,40 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [-4, -4] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + [ + [ + [1, 1], + [1, 10], + [10, 10], + [10, 1], + [1, 1] + ] + ], + [ + [ + [-1, -1], + [-1, -10], + [-10, -10], + [-10, -1], + [-1, -1] + ] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/within/true/Point/Polygon/PointIsWithinPolygon.geojson b/test/examples/booleans/within/true/Point/Polygon/PointIsWithinPolygon.geojson new file mode 100644 index 00000000..8e3ea36f --- /dev/null +++ b/test/examples/booleans/within/true/Point/Polygon/PointIsWithinPolygon.geojson @@ -0,0 +1,29 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [4, 4] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [1, 1], + [1, 10], + [10, 10], + [10, 1], + [1, 1] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/within/true/Polygon/MultiPolygon/polygon-within-multipolygon.geojson b/test/examples/booleans/within/true/Polygon/MultiPolygon/polygon-within-multipolygon.geojson new file mode 100644 index 00000000..2819e2ba --- /dev/null +++ b/test/examples/booleans/within/true/Polygon/MultiPolygon/polygon-within-multipolygon.geojson @@ -0,0 +1,48 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [-2, -2], + [-2, -9], + [-9, -9], + [-9, -2], + [-2, -2] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + [ + [ + [1, 1], + [1, 10], + [10, 10], + [10, 1], + [1, 1] + ] + ], + [ + [ + [-1, -1], + [-1, -10], + [-10, -10], + [-10, -1], + [-1, -1] + ] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/within/true/Polygon/Polygon/PolygonIsWIthinPolygon.geojson b/test/examples/booleans/within/true/Polygon/Polygon/PolygonIsWIthinPolygon.geojson new file mode 100644 index 00000000..65d65259 --- /dev/null +++ b/test/examples/booleans/within/true/Polygon/Polygon/PolygonIsWIthinPolygon.geojson @@ -0,0 +1,36 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [1, 1], + [2, 2], + [3, 2], + [1, 1] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [1, 1], + [1, 10], + [10, 10], + [10, 1], + [1, 1] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/within/true/Polygon/Polygon/PolygonsExactSameShape.geojson b/test/examples/booleans/within/true/Polygon/Polygon/PolygonsExactSameShape.geojson new file mode 100644 index 00000000..8bfd83da --- /dev/null +++ b/test/examples/booleans/within/true/Polygon/Polygon/PolygonsExactSameShape.geojson @@ -0,0 +1,41 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": { + "fill": "#F00" + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [-12.65625, 36.87962060502676], + [35.419921875, 36.38591277287651], + [37.79296875, 56.897003921272606], + [-12.12890625, 57.040729838360875], + [-12.65625, 36.87962060502676] + ] + ] + } + }, + { + "type": "Feature", + "properties": { + "fill": "#F00" + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [-12.65625, 36.87962060502676], + [35.419921875, 36.38591277287651], + [37.79296875, 56.897003921272606], + [-12.12890625, 57.040729838360875], + [-12.65625, 36.87962060502676] + ] + ] + } + } + ] +} diff --git a/test/examples/line_overlap/in/boolean-line-overlap.geojson b/test/examples/line_overlap/in/boolean-line-overlap.geojson new file mode 100644 index 00000000..c3414c3c --- /dev/null +++ b/test/examples/line_overlap/in/boolean-line-overlap.geojson @@ -0,0 +1,32 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [-22.564544677734375, 46.25917013377904], + [-22.559051513671875, 46.32369743336783], + [-22.446441650390625, 46.352141192009334], + [-22.361297607421875, 46.32891323009468], + [-22.361297607421875, 46.30472670751783] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [-22.570724487304688, 46.36398839132818], + [-22.444381713867188, 46.357354276167015], + [-22.391510009765625, 46.3291502999477], + [-22.29263305664062, 46.382464893261165] + ] + } + } + ] +} diff --git a/test/examples/line_overlap/in/issue-#901-simplified.geojson b/test/examples/line_overlap/in/issue-#901-simplified.geojson new file mode 100644 index 00000000..435be36e --- /dev/null +++ b/test/examples/line_overlap/in/issue-#901-simplified.geojson @@ -0,0 +1,35 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": { + "stroke": "#F00", + "stroke-width": 10, + "stroke-opacity": 1 + }, + "geometry": { + "type": "LineString", + "coordinates": [ + [2, 2], + [4, 4] + ] + } + }, + { + "type": "Feature", + "properties": { + "stroke": "#00F", + "stroke-width": 3, + "stroke-opacity": 1 + }, + "geometry": { + "type": "LineString", + "coordinates": [ + [0, 0], + [6, 6] + ] + } + } + ] +} diff --git a/test/examples/line_overlap/in/issue-#901.geojson b/test/examples/line_overlap/in/issue-#901.geojson new file mode 100644 index 00000000..b897d69b --- /dev/null +++ b/test/examples/line_overlap/in/issue-#901.geojson @@ -0,0 +1,77 @@ +{ + "type": "FeatureCollection", + "properties": { + "tolerance": 0.05 + }, + "features": [ + { + "type": "Feature", + "properties": { + "stroke": "#F00", + "fill": "#F00", + "stroke-width": 10, + "stroke-opacity": 1, + "fill-opacity": 0.1, + "description": "output of an intersect call with a longer pipe and the other feature in this file" + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [-113.33847575084239, 53.52244416392682], + [-113.33847394, 53.52299533509864], + [-113.338470971, 53.52389165109878], + [-113.338468309, 53.52469456909876], + [-113.338467951, 53.5248023990988], + [-113.338462214, 53.52653346709882], + [-113.3384620759999, 53.52657586409872], + [-113.3384619429999, 53.52661770709869], + [-113.3384532659999, 53.52935323209886], + [-113.338452983, 53.52944258409877], + [-113.338452982, 53.52944333909876], + [-113.3384522719999, 53.52962258909884], + [-113.338449392, 53.53035074809878], + [-113.33704111881613, 53.53215959791441], + [-113.33698987543352, 53.53214475018778], + [-113.33690471442213, 53.53212132654082], + [-113.3382987129999, 53.53033083009888], + [-113.3383022259999, 53.52944312809881], + [-113.3383113299999, 53.52657569409888], + [-113.3383232079999, 53.52299515809875], + [-113.33832502043951, 53.52244398828247], + [-113.3384152645109, 53.52244409344282], + [-113.33847575084239, 53.52244416392682] + ] + ] + } + }, + { + "type": "Feature", + "properties": { + "stroke": "#00F", + "fill": "#00F", + "stroke-width": 3, + "stroke-opacity": 1, + "fill-opacity": 0.1, + "description": "shape which was intersected with a longer pipe to produce the pipe shown" + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [-113.34145274487872, 53.53230853007057], + [-113.33797676517321, 53.53243070065233], + [-113.33698987543352, 53.53214475018778], + [-113.33287043896553, 53.53101169382826], + [-113.33387712516304, 53.522438805202505], + [-113.3384152645109, 53.52244409344282], + [-113.3429534044069, 53.522449381683145], + [-113.34145274487872, 53.53230853007057], + [-113.34145274487872, 53.53230853007057], + [-113.34145274487872, 53.53230853007057] + ] + ] + } + } + ] +} diff --git a/test/examples/line_overlap/in/polygons.geojson b/test/examples/line_overlap/in/polygons.geojson new file mode 100644 index 00000000..fc443e3d --- /dev/null +++ b/test/examples/line_overlap/in/polygons.geojson @@ -0,0 +1,65 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": { + "stroke": "#F00", + "fill": "#F00", + "stroke-width": 10, + "stroke-opacity": 1, + "fill-opacity": 0.1 + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [120.14179343574, -17.48153498141], + [120.1456007834, -30.96997373479], + [130.34864729879, -30.96772909058], + [131.64065935144, -29.20137372199], + [129.5926694017, -28.04905296815], + [130.34739288016, -26.68605235913], + [125.76890918238, -26.68710193815], + [125.76762773192, -22.1408865296], + [130.52038135971, -22.13975701932], + [131.37809653737, -20.30857774535], + [129.67954157692, -18.92360398694], + [130.51910988115, -17.47899540098], + [120.14179343574, -17.48153498141] + ] + ] + } + }, + { + "type": "Feature", + "properties": { + "stroke": "#00F", + "fill": "#00F", + "stroke-width": 3, + "stroke-opacity": 1, + "fill-opacity": 0.1 + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [139.69468150776, -17.47674988707], + [130.51910988115, -17.47899540098], + [129.67954157692, -18.92360398694], + [131.37809653737, -20.30857774535], + [130.52038135971, -22.13975701932], + [135.29428724786, -22.138622473], + [135.29556869831, -26.68491802042], + [130.34739288016, -26.68605235913], + [129.5926694017, -28.04905296815], + [131.64065935144, -29.20137372199], + [130.34864729879, -30.96772909058], + [139.69848885541, -30.96567210295], + [139.69468150776, -17.47674988707] + ] + ] + } + } + ] +} diff --git a/test/examples/line_overlap/in/simple1.geojson b/test/examples/line_overlap/in/simple1.geojson new file mode 100644 index 00000000..77f9e48a --- /dev/null +++ b/test/examples/line_overlap/in/simple1.geojson @@ -0,0 +1,40 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": { + "stroke": "#F00", + "stroke-width": 10, + "stroke-opacity": 1 + }, + "geometry": { + "type": "LineString", + "coordinates": [ + [115, -35], + [125, -30], + [135, -30], + [145, -35] + ] + } + }, + { + "type": "Feature", + "properties": { + "stroke": "#00F", + "stroke-width": 3, + "stroke-opacity": 1 + }, + "geometry": { + "type": "LineString", + "coordinates": [ + [115, -25], + [125, -30], + [135, -30], + [145, -35], + [145, -25] + ] + } + } + ] +} diff --git a/test/examples/line_overlap/in/simple2.geojson b/test/examples/line_overlap/in/simple2.geojson new file mode 100644 index 00000000..a283beac --- /dev/null +++ b/test/examples/line_overlap/in/simple2.geojson @@ -0,0 +1,39 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": { + "stroke": "#F00", + "stroke-width": 10, + "stroke-opacity": 1 + }, + "geometry": { + "type": "LineString", + "coordinates": [ + [115, -35], + [125, -30], + [135, -30], + [145, -35] + ] + } + }, + { + "type": "Feature", + "properties": { + "stroke": "#00F", + "stroke-width": 3, + "stroke-opacity": 1 + }, + "geometry": { + "type": "LineString", + "coordinates": [ + [115, -25], + [125, -30], + [135, -30], + [145, -35] + ] + } + } + ] +} diff --git a/test/examples/line_overlap/in/simple3.geojson b/test/examples/line_overlap/in/simple3.geojson new file mode 100644 index 00000000..aa813d2b --- /dev/null +++ b/test/examples/line_overlap/in/simple3.geojson @@ -0,0 +1,38 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": { + "stroke": "#ff0000", + "stroke-width": 10, + "stroke-opacity": 1 + }, + "geometry": { + "type": "LineString", + "coordinates": [ + [125, -30], + [135, -30], + [145, -35] + ] + } + }, + { + "type": "Feature", + "properties": { + "stroke": "#00F", + "stroke-width": 3, + "stroke-opacity": 1 + }, + "geometry": { + "type": "LineString", + "coordinates": [ + [125, -30], + [135, -30], + [145, -35], + [145, -25] + ] + } + } + ] +} diff --git a/test/examples/line_overlap/out/boolean-line-overlap.geojson b/test/examples/line_overlap/out/boolean-line-overlap.geojson new file mode 100644 index 00000000..c3414c3c --- /dev/null +++ b/test/examples/line_overlap/out/boolean-line-overlap.geojson @@ -0,0 +1,32 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [-22.564544677734375, 46.25917013377904], + [-22.559051513671875, 46.32369743336783], + [-22.446441650390625, 46.352141192009334], + [-22.361297607421875, 46.32891323009468], + [-22.361297607421875, 46.30472670751783] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [-22.570724487304688, 46.36398839132818], + [-22.444381713867188, 46.357354276167015], + [-22.391510009765625, 46.3291502999477], + [-22.29263305664062, 46.382464893261165] + ] + } + } + ] +} diff --git a/test/examples/line_overlap/out/issue-#901-simplified.geojson b/test/examples/line_overlap/out/issue-#901-simplified.geojson new file mode 100644 index 00000000..988780fd --- /dev/null +++ b/test/examples/line_overlap/out/issue-#901-simplified.geojson @@ -0,0 +1,52 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": { + "stroke": "#0F0", + "fill": "#0F0", + "stroke-width": 25 + }, + "geometry": { + "type": "LineString", + "coordinates": [ + [2, 2], + [4, 4] + ] + }, + "bbox": [2, 2, 4, 4], + "id": 0 + }, + { + "type": "Feature", + "properties": { + "stroke": "#F00", + "stroke-width": 10, + "stroke-opacity": 1 + }, + "geometry": { + "type": "LineString", + "coordinates": [ + [2, 2], + [4, 4] + ] + } + }, + { + "type": "Feature", + "properties": { + "stroke": "#00F", + "stroke-width": 3, + "stroke-opacity": 1 + }, + "geometry": { + "type": "LineString", + "coordinates": [ + [0, 0], + [6, 6] + ] + } + } + ] +} diff --git a/test/examples/line_overlap/out/issue-#901.geojson b/test/examples/line_overlap/out/issue-#901.geojson new file mode 100644 index 00000000..09d13e5e --- /dev/null +++ b/test/examples/line_overlap/out/issue-#901.geojson @@ -0,0 +1,170 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": { + "stroke": "#0F0", + "fill": "#0F0", + "stroke-width": 25 + }, + "geometry": { + "type": "LineString", + "coordinates": [ + [-113.33698987543352, 53.53214475018778], + [-113.33690471442213, 53.53212132654082], + [-113.33698987543352, 53.53214475018778], + [-113.33704111881613, 53.53215959791441] + ] + }, + "bbox": [ + -113.33704111881613, + 53.53214475018778, + -113.33698987543352, + 53.53215959791441 + ], + "id": 13 + }, + { + "type": "Feature", + "properties": { + "stroke": "#0F0", + "fill": "#0F0", + "stroke-width": 25 + }, + "geometry": { + "type": "LineString", + "coordinates": [ + [-113.33698987543352, 53.53214475018778], + [-113.33690471442213, 53.53212132654082], + [-113.33698987543352, 53.53214475018778], + [-113.33704111881613, 53.53215959791441] + ] + }, + "bbox": [ + -113.33704111881613, + 53.53214475018778, + -113.33698987543352, + 53.53215959791441 + ], + "id": 13 + }, + { + "type": "Feature", + "properties": { + "stroke": "#0F0", + "fill": "#0F0", + "stroke-width": 25 + }, + "geometry": { + "type": "LineString", + "coordinates": [ + [-113.33832502043951, 53.52244398828247], + [-113.3384152645109, 53.52244409344282], + [-113.33847575084239, 53.52244416392682], + [-113.3384152645109, 53.52244409344282] + ] + }, + "bbox": [ + -113.3384152645109, + 53.52244398828247, + -113.33832502043951, + 53.52244409344282 + ], + "id": 20 + }, + { + "type": "Feature", + "properties": { + "stroke": "#0F0", + "fill": "#0F0", + "stroke-width": 25 + }, + "geometry": { + "type": "LineString", + "coordinates": [ + [-113.33832502043951, 53.52244398828247], + [-113.3384152645109, 53.52244409344282], + [-113.33847575084239, 53.52244416392682], + [-113.3384152645109, 53.52244409344282] + ] + }, + "bbox": [ + -113.3384152645109, + 53.52244398828247, + -113.33832502043951, + 53.52244409344282 + ], + "id": 20 + }, + { + "type": "Feature", + "properties": { + "stroke": "#F00", + "fill": "#F00", + "stroke-width": 10, + "stroke-opacity": 1, + "fill-opacity": 0.1, + "description": "output of an intersect call with a longer pipe and the other feature in this file" + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [-113.33847575084239, 53.52244416392682], + [-113.33847394, 53.52299533509864], + [-113.338470971, 53.52389165109878], + [-113.338468309, 53.52469456909876], + [-113.338467951, 53.5248023990988], + [-113.338462214, 53.52653346709882], + [-113.3384620759999, 53.52657586409872], + [-113.3384619429999, 53.52661770709869], + [-113.3384532659999, 53.52935323209886], + [-113.338452983, 53.52944258409877], + [-113.338452982, 53.52944333909876], + [-113.3384522719999, 53.52962258909884], + [-113.338449392, 53.53035074809878], + [-113.33704111881613, 53.53215959791441], + [-113.33698987543352, 53.53214475018778], + [-113.33690471442213, 53.53212132654082], + [-113.3382987129999, 53.53033083009888], + [-113.3383022259999, 53.52944312809881], + [-113.3383113299999, 53.52657569409888], + [-113.3383232079999, 53.52299515809875], + [-113.33832502043951, 53.52244398828247], + [-113.3384152645109, 53.52244409344282], + [-113.33847575084239, 53.52244416392682] + ] + ] + } + }, + { + "type": "Feature", + "properties": { + "stroke": "#00F", + "fill": "#00F", + "stroke-width": 3, + "stroke-opacity": 1, + "fill-opacity": 0.1, + "description": "shape which was intersected with a longer pipe to produce the pipe shown" + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [-113.34145274487872, 53.53230853007057], + [-113.33797676517321, 53.53243070065233], + [-113.33698987543352, 53.53214475018778], + [-113.33287043896553, 53.53101169382826], + [-113.33387712516304, 53.522438805202505], + [-113.3384152645109, 53.52244409344282], + [-113.3429534044069, 53.522449381683145], + [-113.34145274487872, 53.53230853007057], + [-113.34145274487872, 53.53230853007057], + [-113.34145274487872, 53.53230853007057] + ] + ] + } + } + ] +} diff --git a/test/examples/line_overlap/out/polygons.geojson b/test/examples/line_overlap/out/polygons.geojson new file mode 100644 index 00000000..d2ab42eb --- /dev/null +++ b/test/examples/line_overlap/out/polygons.geojson @@ -0,0 +1,99 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": { + "stroke": "#0F0", + "fill": "#0F0", + "stroke-width": 25 + }, + "geometry": { + "type": "LineString", + "coordinates": [ + [130.52038135971, -22.13975701932], + [131.37809653737, -20.30857774535], + [129.67954157692, -18.92360398694], + [130.51910988115, -17.47899540098] + ] + } + }, + { + "type": "Feature", + "properties": { + "stroke": "#0F0", + "fill": "#0F0", + "stroke-width": 25 + }, + "geometry": { + "type": "LineString", + "coordinates": [ + [130.34864729879, -30.96772909058], + [131.64065935144, -29.20137372199], + [129.5926694017, -28.04905296815], + [130.34739288016, -26.68605235913] + ] + } + }, + { + "type": "Feature", + "properties": { + "stroke": "#F00", + "fill": "#F00", + "stroke-width": 10, + "stroke-opacity": 1, + "fill-opacity": 0.1 + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [120.14179343574, -17.48153498141], + [120.1456007834, -30.96997373479], + [130.34864729879, -30.96772909058], + [131.64065935144, -29.20137372199], + [129.5926694017, -28.04905296815], + [130.34739288016, -26.68605235913], + [125.76890918238, -26.68710193815], + [125.76762773192, -22.1408865296], + [130.52038135971, -22.13975701932], + [131.37809653737, -20.30857774535], + [129.67954157692, -18.92360398694], + [130.51910988115, -17.47899540098], + [120.14179343574, -17.48153498141] + ] + ] + } + }, + { + "type": "Feature", + "properties": { + "stroke": "#00F", + "fill": "#00F", + "stroke-width": 3, + "stroke-opacity": 1, + "fill-opacity": 0.1 + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [139.69468150776, -17.47674988707], + [130.51910988115, -17.47899540098], + [129.67954157692, -18.92360398694], + [131.37809653737, -20.30857774535], + [130.52038135971, -22.13975701932], + [135.29428724786, -22.138622473], + [135.29556869831, -26.68491802042], + [130.34739288016, -26.68605235913], + [129.5926694017, -28.04905296815], + [131.64065935144, -29.20137372199], + [130.34864729879, -30.96772909058], + [139.69848885541, -30.96567210295], + [139.69468150776, -17.47674988707] + ] + ] + } + } + ] +} diff --git a/test/examples/line_overlap/out/simple1.geojson b/test/examples/line_overlap/out/simple1.geojson new file mode 100644 index 00000000..b7da65c7 --- /dev/null +++ b/test/examples/line_overlap/out/simple1.geojson @@ -0,0 +1,56 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": { + "stroke": "#0F0", + "fill": "#0F0", + "stroke-width": 25 + }, + "geometry": { + "type": "LineString", + "coordinates": [ + [125, -30], + [135, -30], + [145, -35] + ] + } + }, + { + "type": "Feature", + "properties": { + "stroke": "#F00", + "stroke-width": 10, + "stroke-opacity": 1 + }, + "geometry": { + "type": "LineString", + "coordinates": [ + [115, -35], + [125, -30], + [135, -30], + [145, -35] + ] + } + }, + { + "type": "Feature", + "properties": { + "stroke": "#00F", + "stroke-width": 3, + "stroke-opacity": 1 + }, + "geometry": { + "type": "LineString", + "coordinates": [ + [115, -25], + [125, -30], + [135, -30], + [145, -35], + [145, -25] + ] + } + } + ] +} diff --git a/test/examples/line_overlap/out/simple2.geojson b/test/examples/line_overlap/out/simple2.geojson new file mode 100644 index 00000000..c9d5f41b --- /dev/null +++ b/test/examples/line_overlap/out/simple2.geojson @@ -0,0 +1,55 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": { + "stroke": "#0F0", + "fill": "#0F0", + "stroke-width": 25 + }, + "geometry": { + "type": "LineString", + "coordinates": [ + [125, -30], + [135, -30], + [145, -35] + ] + } + }, + { + "type": "Feature", + "properties": { + "stroke": "#F00", + "stroke-width": 10, + "stroke-opacity": 1 + }, + "geometry": { + "type": "LineString", + "coordinates": [ + [115, -35], + [125, -30], + [135, -30], + [145, -35] + ] + } + }, + { + "type": "Feature", + "properties": { + "stroke": "#00F", + "stroke-width": 3, + "stroke-opacity": 1 + }, + "geometry": { + "type": "LineString", + "coordinates": [ + [115, -25], + [125, -30], + [135, -30], + [145, -35] + ] + } + } + ] +} diff --git a/test/examples/line_overlap/out/simple3.geojson b/test/examples/line_overlap/out/simple3.geojson new file mode 100644 index 00000000..dc0d6737 --- /dev/null +++ b/test/examples/line_overlap/out/simple3.geojson @@ -0,0 +1,54 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": { + "stroke": "#0F0", + "fill": "#0F0", + "stroke-width": 25 + }, + "geometry": { + "type": "LineString", + "coordinates": [ + [125, -30], + [135, -30], + [145, -35] + ] + } + }, + { + "type": "Feature", + "properties": { + "stroke": "#ff0000", + "stroke-width": 10, + "stroke-opacity": 1 + }, + "geometry": { + "type": "LineString", + "coordinates": [ + [125, -30], + [135, -30], + [145, -35] + ] + } + }, + { + "type": "Feature", + "properties": { + "stroke": "#00F", + "stroke-width": 3, + "stroke-opacity": 1 + }, + "geometry": { + "type": "LineString", + "coordinates": [ + [125, -30], + [135, -30], + [145, -35], + [145, -25] + ] + } + } + ] +} From 26560178ec4b1f11b6ab49ce6693cb78b78cd381 Mon Sep 17 00:00:00 2001 From: armantorkzaban Date: Wed, 31 Aug 2022 13:13:56 +0200 Subject: [PATCH 56/82] issue with test is worked on --- test/components/line_overlap.dart | 150 ++++++++++++++++++------------ 1 file changed, 90 insertions(+), 60 deletions(-) diff --git a/test/components/line_overlap.dart b/test/components/line_overlap.dart index ad3dc7cf..cd3b874a 100644 --- a/test/components/line_overlap.dart +++ b/test/components/line_overlap.dart @@ -1,42 +1,66 @@ -const directories = { - in: path.join(__dirname, "test", "in") + path.sep, - out: path.join(__dirname, "test", "out") + path.sep, -}; - -let fixtures = fs.readdirSync(directories.in).map((filename) => { - return { - filename, - name: path.parse(filename).name, - geojson: load.sync(directories.in + filename), - }; -}); -// fixtures = fixtures.filter(({name}) => name.includes('#901')); +import 'dart:convert'; +import 'dart:io'; + +import 'package:test/test.dart'; +import 'package:turf/helpers.dart'; +import 'package:turf/src/line_overlap.dart'; +import 'package:turf/src/meta/feature.dart'; +import 'package:turf_equality/turf_equality.dart'; + + +main(){ + group('line_overlap function',(){ + // fixtures = fixtures.filter(({name}) => name.includes('#901')); + + +var inDir = Directory('./test/examples/line_overlaps/in'); + for (var file in inDir.listSync(recursive: true)) { + if (file is File && file.path.endsWith('.geojson')) { + test( + file.path, + () { + var inSource = file.readAsStringSync(); + var inGeom = GeoJSONObject.fromJson(jsonDecode(inSource)); + + var outPath = './' + + file.uri.pathSegments + .sublist(0, file.uri.pathSegments.length - 2) + .join('/') + + '/out/${file.uri.pathSegments.last}'; + + var outSource = File(outPath).readAsStringSync(); + + var outGeom = GeoJSONObject.fromJson(jsonDecode(outSource)); -test("turf-line-overlap", (t) => { - for (const { filename, name, geojson } of fixtures) { - const [source, target] = geojson.features; - const shared = colorize( - lineOverlap(source, target, geojson.properties), + + FeatureCollection results = lineOverlap((inGeom as FeatureCollection).features.first, inGeom.features.last); + Equality eq = Equality(); + expect(eq.compare(results, outGeom), true); + +test("turf-line-overlap", () { + + shared = colorize( + lineOverlap(source, target, tolerance: geojson.properties), "#0F0" ); - const results = featureCollection(shared.features.concat([source, target])); + var + results = FeatureCollection(features: [...shared.features, source, target]); - if (process.env.REGEN) write.sync(directories.out + filename, results); t.deepEquals(results, load.sync(directories.out + filename), name); } - t.end(); }); -test("turf-line-overlap - Geometry Object", (t) => { - const line1 = lineString([ - [115, -35], - [125, -30], - [135, -30], - [145, -35], +test("turf-line-overlap - Geometry Object", () { + var line1 = LineString(coordinates:[ + Position.of([115, -35]), + Position.of([125, -30]), + Position.of([135, -30]), + Position.of([145, -35]), ]); - const line2 = lineString([ - [135, -30], - [145, -35], + var + line2 = LineString(coordinates:[ + Position.of([135, -30]), + Position.of([145, -35]), ]); t.true( @@ -46,45 +70,51 @@ test("turf-line-overlap - Geometry Object", (t) => { t.end(); }); -test("turf-line-overlap - multiple segments on same line", (t) => { - const line1 = lineString([ - [0, 1], - [1, 1], - [1, 0], - [2, 0], - [2, 1], - [3, 1], - [3, 0], - [4, 0], - [4, 1], - [4, 0], +test("turf-line-overlap - multiple segments on same line", () { + var + line1 = LineString(coordinates:[ + Position.of([0, 1]), + Position.of([1, 1]), + Position.of([1, 0]), + Position.of([2, 0]), + Position.of([2, 1]), + Position.of([3, 1]), + Position.of([3, 0]), + Position.of([4, 0]), + Position.of([4, 1]), + Position.of([4, 0]), ]); - const line2 = lineString([ - [0, 0], - [6, 0], + var + line2 = LineString(coordinates:[ + Position.of([0, 0]), + Position.of([6, 0]), ]); t.true( - lineOverlap(line1.geometry, line2.geometry).features.length === 2, + lineOverlap(line1.geometry, line2.geometry).features.length == 2, "multiple segments on same line" ); t.true( - lineOverlap(line2.geometry, line1.geometry).features.length === 2, + lineOverlap(line2.geometry, line1.geometry).features.length ==2, "multiple segments on same line - swapped order" ); t.end(); }); -function colorize(features, color = "#F00", width = 25) { - const results = []; - featureEach(features, (feature) => { - feature.properties = { - stroke: color, - fill: color, - "stroke-width": width, - }; - results.push(feature); - }); - if (features.type === "Feature") return results[0]; - return featureCollection(results); -} \ No newline at end of file + colorize(features, {color = "#F00", width = 25}) { + var + results = []; + featureEach(features, ( Feature currentFeature, + int featureIndex) { + currentFeature.properties = { + 'stroke': color, + 'fill': color, + "stroke-width": width}; + results.add(currentFeature); + },); + if (features is List) return results[0]; + return FeatureCollection(features: results); + } + },); +} + From 2a59e67f9070ca7fca6a7d5b4248d0c307f59e71 Mon Sep 17 00:00:00 2001 From: armantorkzaban Date: Wed, 31 Aug 2022 15:29:59 +0200 Subject: [PATCH 57/82] still at porting the overlap test --- test/components/line_overlap.dart | 266 +++++++++++++++++++++--------- 1 file changed, 189 insertions(+), 77 deletions(-) diff --git a/test/components/line_overlap.dart b/test/components/line_overlap.dart index cd3b874a..2034b800 100644 --- a/test/components/line_overlap.dart +++ b/test/components/line_overlap.dart @@ -7,60 +7,177 @@ import 'package:turf/src/line_overlap.dart'; import 'package:turf/src/meta/feature.dart'; import 'package:turf_equality/turf_equality.dart'; - -main(){ - group('line_overlap function',(){ - // fixtures = fixtures.filter(({name}) => name.includes('#901')); +main() { + FeatureCollection colorize(features, {color = "#F00", width = 25}) { + var results = []; + featureEach( + features, + (Feature currentFeature, int featureIndex) { + currentFeature.properties = { + 'stroke': color, + 'fill': color, + "stroke-width": width + }; + results.add(currentFeature); + }, + ); + return FeatureCollection(features: results); + } + group( + 'line_overlap function', + () { + // fixtures = fixtures.filter(({name}) => name.includes('#901')); -var inDir = Directory('./test/examples/line_overlaps/in'); + var inDir = Directory('./test/examples/line_overlaps/in'); for (var file in inDir.listSync(recursive: true)) { if (file is File && file.path.endsWith('.geojson')) { - test( - file.path, - () { - var inSource = file.readAsStringSync(); - var inGeom = GeoJSONObject.fromJson(jsonDecode(inSource)); - - var outPath = './' + - file.uri.pathSegments - .sublist(0, file.uri.pathSegments.length - 2) - .join('/') + - '/out/${file.uri.pathSegments.last}'; - - var outSource = File(outPath).readAsStringSync(); - - var outGeom = GeoJSONObject.fromJson(jsonDecode(outSource)); - - - FeatureCollection results = lineOverlap((inGeom as FeatureCollection).features.first, inGeom.features.last); - Equality eq = Equality(); - expect(eq.compare(results, outGeom), true); - -test("turf-line-overlap", () { - - shared = colorize( - lineOverlap(source, target, tolerance: geojson.properties), + if (file.path.contains('#901')) { + test( + file.path, + () { + var inSource = file.readAsStringSync(); + var inGeom = GeoJSONObject.fromJson(jsonDecode(inSource)) + as FeatureCollection; + + var outPath = './' + + file.uri.pathSegments + .sublist(0, file.uri.pathSegments.length - 2) + .join('/') + + '/out/${file.uri.pathSegments.last}'; + + var outSource = File(outPath).readAsStringSync(); + + var outGeom = GeoJSONObject.fromJson(jsonDecode(outSource)); + + FeatureCollection results = lineOverlap( + (inGeom as FeatureCollection).features.first, + inGeom.features.last); + Equality eq = Equality(); + expect(eq.compare(results, outGeom), true); + + FeatureCollection shared = colorize( + lineOverlap(inGeom.features[0], inGeom.features[1], + tolerance: 0.05), + color: "#0F0"); + var results1 = FeatureCollection( + features: [ + ...shared.features, + inGeom.features[0], + inGeom.features[1] + ], + ); + + expect(eq.compare(results1, outGeom), true); + }, + ); + + test( + "turf-line-overlap - Geometry Object", + () { + var line1 = LineString( + coordinates: [ + Position.of([115, -35]), + Position.of([125, -30]), + Position.of([135, -30]), + Position.of([145, -35]), + ], + ); + var line2 = LineString( + coordinates: [ + Position.of([135, -30]), + Position.of([145, -35]), + ], + ); + + expect(lineOverlap(line1, line2).features.isNotEmpty, true); + }, + ); + + test( + "turf-line-overlap - multiple segments on same line", + () { + var line1 = LineString( + coordinates: [ + Position.of([0, 1]), + Position.of([1, 1]), + Position.of([1, 0]), + Position.of([2, 0]), + Position.of([2, 1]), + Position.of([3, 1]), + Position.of([3, 0]), + Position.of([4, 0]), + Position.of([4, 1]), + Position.of([4, 0]), + ], + ); + var line2 = LineString( + coordinates: [ + Position.of([0, 0]), + Position.of([6, 0]), + ], + ); + + expect(lineOverlap(line1, line2).features.length == 2, true); + expect(lineOverlap(line2, line1).features.length == 2, true); + }, + ); + } + } + } + }, + ); +} + +/** + * const fs = require("fs"); +const test = require("tape"); +const path = require("path"); +const load = require("load-json-file"); +const write = require("write-json-file"); +const { featureEach } = require("@turf/meta"); +const { featureCollection, lineString } = require("@turf/helpers"); +const lineOverlap = require("./index").default; + +const directories = { + in: path.join(__dirname, "test", "in") + path.sep, + out: path.join(__dirname, "test", "out") + path.sep, +}; + +let fixtures = fs.readdirSync(directories.in).map((filename) => { + return { + filename, + name: path.parse(filename).name, + geojson: load.sync(directories.in + filename), + }; +}); +// fixtures = fixtures.filter(({name}) => name.includes('#901')); + +test("turf-line-overlap", (t) => { + for (const { filename, name, geojson } of fixtures) { + const [source, target] = geojson.features; + const shared = colorize( + lineOverlap(source, target, geojson.properties), "#0F0" ); - var - results = FeatureCollection(features: [...shared.features, source, target]); + const results = featureCollection(shared.features.concat([source, target])); + if (process.env.REGEN) write.sync(directories.out + filename, results); t.deepEquals(results, load.sync(directories.out + filename), name); } + t.end(); }); -test("turf-line-overlap - Geometry Object", () { - var line1 = LineString(coordinates:[ - Position.of([115, -35]), - Position.of([125, -30]), - Position.of([135, -30]), - Position.of([145, -35]), +test("turf-line-overlap - Geometry Object", (t) => { + const line1 = lineString([ + [115, -35], + [125, -30], + [135, -30], + [145, -35], ]); - var - line2 = LineString(coordinates:[ - Position.of([135, -30]), - Position.of([145, -35]), + const line2 = lineString([ + [135, -30], + [145, -35], ]); t.true( @@ -70,51 +187,46 @@ test("turf-line-overlap - Geometry Object", () { t.end(); }); -test("turf-line-overlap - multiple segments on same line", () { - var - line1 = LineString(coordinates:[ - Position.of([0, 1]), - Position.of([1, 1]), - Position.of([1, 0]), - Position.of([2, 0]), - Position.of([2, 1]), - Position.of([3, 1]), - Position.of([3, 0]), - Position.of([4, 0]), - Position.of([4, 1]), - Position.of([4, 0]), +test("turf-line-overlap - multiple segments on same line", (t) => { + const line1 = lineString([ + [0, 1], + [1, 1], + [1, 0], + [2, 0], + [2, 1], + [3, 1], + [3, 0], + [4, 0], + [4, 1], + [4, 0], ]); - var - line2 = LineString(coordinates:[ - Position.of([0, 0]), - Position.of([6, 0]), + const line2 = lineString([ + [0, 0], + [6, 0], ]); t.true( - lineOverlap(line1.geometry, line2.geometry).features.length == 2, + lineOverlap(line1.geometry, line2.geometry).features.length === 2, "multiple segments on same line" ); t.true( - lineOverlap(line2.geometry, line1.geometry).features.length ==2, + lineOverlap(line2.geometry, line1.geometry).features.length === 2, "multiple segments on same line - swapped order" ); t.end(); }); - colorize(features, {color = "#F00", width = 25}) { - var - results = []; - featureEach(features, ( Feature currentFeature, - int featureIndex) { - currentFeature.properties = { - 'stroke': color, - 'fill': color, - "stroke-width": width}; - results.add(currentFeature); - },); - if (features is List) return results[0]; - return FeatureCollection(features: results); - } - },); +function colorize(features, color = "#F00", width = 25) { + const results = []; + featureEach(features, (feature) => { + feature.properties = { + stroke: color, + fill: color, + "stroke-width": width, + }; + results.push(feature); + }); + if (features.type === "Feature") return results[0]; + return featureCollection(results); } - + */ \ No newline at end of file From f8ebffd3e4438bc90b4d09970aaf6f666bdc8ee8 Mon Sep 17 00:00:00 2001 From: armantorkzaban Date: Wed, 31 Aug 2022 16:14:55 +0200 Subject: [PATCH 58/82] done: parallel --- lib/src/booleans/boolean_overlap.dart | 2 +- lib/src/booleans/boolean_parallel.dart | 80 +--------------- test/booleans/parallel_test.dart | 49 +++++++++- test/components/line_overlap.dart | 123 ++++++++++++------------- 4 files changed, 108 insertions(+), 146 deletions(-) diff --git a/lib/src/booleans/boolean_overlap.dart b/lib/src/booleans/boolean_overlap.dart index b47ad1f1..588dc2af 100644 --- a/lib/src/booleans/boolean_overlap.dart +++ b/lib/src/booleans/boolean_overlap.dart @@ -23,7 +23,7 @@ import 'package:turf_equality/turf_equality.dart'; /// //=true /// turf.booleanOverlap(poly2, poly3) /// //=false -bool booleanOverlap(GeoJSONObject feature1, GeoJSONObject feature2) { +bool bo oleanOverlap(GeoJSONObject feature1, GeoJSONObject feature2) { var geom1 = feature1 is Feature ? feature1.geometry : feature1; var geom2 = feature2 is Feature ? feature2.geometry : feature2; diff --git a/lib/src/booleans/boolean_parallel.dart b/lib/src/booleans/boolean_parallel.dart index 26411b5b..39594492 100644 --- a/lib/src/booleans/boolean_parallel.dart +++ b/lib/src/booleans/boolean_parallel.dart @@ -25,8 +25,8 @@ bool booleanParallel(GeoJSONObject line1, GeoJSONObject line2) { FeatureCollection segments2 = lineSegment(cleanCoords(line2)); for (var i = 0; i < segments1.features.length; i++) { var segment1 = segments1.features[i].geometry!.coordinates; - var seg2i = segments2.features.elementAt(i); - if (seg2i is RangeError) break; + var seg2i = segments2.features.asMap().containsKey(i); + if (!seg2i) break; var segment2 = segments2.features[i].geometry!.coordinates; if (!_isParallel(segment1, segment2)) return false; } @@ -52,79 +52,3 @@ GeoJSONObjectType _getType(GeoJSONObject geojson, String name) { } // if GeoJSON geometry throw Exception("Invalid GeoJSON object for $name"); } - - -// { Feature, Geometry, LineString, Position } from "geojson"; -// import cleanCoords from "@turf/clean-coords"; -// import lineSegment from "@turf/line-segment"; -// import rhumbBearing from "@turf/rhumb-bearing"; -// import { bearingToAzimuth } from "@turf/helpers"; - -// /** -// * Boolean-Parallel returns True if each segment of `line1` is parallel to the correspondent segment of `line2` -// * -// * @name booleanParallel -// * @param {Geometry|Feature} line1 GeoJSON Feature or Geometry -// * @param {Geometry|Feature} line2 GeoJSON Feature or Geometry -// * @returns {boolean} true/false if the lines are parallel -// * @example -// * var line1 = turf.lineString([[0, 0], [0, 1]]); -// * var line2 = turf.lineString([[1, 0], [1, 1]]); -// * -// * turf.booleanParallel(line1, line2); -// * //=true -// */ -// booleanParallel( -// line1: Feature | LineString, -// line2: Feature | LineString -// ): boolean { -// // validation -// if (!line1) throw new Error("line1 is required"); -// if (!line2) throw new Error("line2 is required"); -// var type1 = getType(line1, "line1"); -// if (type1 !== "LineString") throw new Error("line1 must be a LineString"); -// var type2 = getType(line2, "line2"); -// if (type2 !== "LineString") throw new Error("line2 must be a LineString"); - -// var segments1 = lineSegment(cleanCoords(line1)).features; -// var segments2 = lineSegment(cleanCoords(line2)).features; - -// for (var i = 0; i < segments1.length; i++) { -// var segment1 = segments1[i].geometry.coordinates; -// if (!segments2[i]) break; -// var segment2 = segments2[i].geometry.coordinates; -// if (!isParallel(segment1, segment2)) return false; -// } -// return true; -// } - -// /** -// * Compares slopes and return result -// * -// * @private -// * @param {Geometry|Feature} segment1 Geometry or Feature -// * @param {Geometry|Feature} segment2 Geometry or Feature -// * @returns {boolean} if slopes are equal -// */ -// function isParallel(segment1: Position[], segment2: Position[]) { -// var slope1 = bearingToAzimuth(rhumbBearing(segment1[0], segment1[1])); -// var slope2 = bearingToAzimuth(rhumbBearing(segment2[0], segment2[1])); -// return slope1 === slope2; -// } - -// /** -// * Returns Feature's type -// * -// * @private -// * @param {Geometry|Feature} geojson Geometry or Feature -// * @param {string} name of the variable -// * @returns {string} Feature's type -// */ -// function getType(geojson: Geometry | Feature, name: string) { -// if ((geojson as Feature).geometry && (geojson as Feature).geometry.type) -// return (geojson as Feature).geometry.type; -// if (geojson.type) return geojson.type; // if GeoJSON geometry -// throw new Error("Invalid GeoJSON object for " + name); -// } - -// export default booleanParallel; */ \ No newline at end of file diff --git a/test/booleans/parallel_test.dart b/test/booleans/parallel_test.dart index 45518ca5..eefaf0d8 100644 --- a/test/booleans/parallel_test.dart +++ b/test/booleans/parallel_test.dart @@ -1,2 +1,49 @@ +import 'dart:convert'; +import 'dart:io'; -/ \ No newline at end of file +import 'package:test/test.dart'; +import 'package:turf/src/booleans/boolean_parallel.dart'; +import 'package:turf/turf.dart'; + +main() { + group( + 'boolean-overlap', + () { + test( + "turf-boolean-overlap-trues", + () { + // True Fixtures + Directory dir = Directory('./test/examples/booleans/parallel/true'); + for (var file in dir.listSync(recursive: true)) { + if (file is File && file.path.endsWith('.geojson')) { + var inSource = file.readAsStringSync(); + var inGeom = GeoJSONObject.fromJson(jsonDecode(inSource)); + var feature1 = (inGeom as FeatureCollection).features[0]; + var feature2 = inGeom.features[1]; + var result = booleanParallel(feature1, feature2); + expect(result, true); + } + } + }, + ); + + test( + "turf-boolean-overlap-falses", + () { + // True Fixtures + Directory dir = Directory('./test/examples/booleans/parallel/false'); + for (var file in dir.listSync(recursive: true)) { + if (file is File && file.path.endsWith('.geojson')) { + var inSource = file.readAsStringSync(); + var inGeom = GeoJSONObject.fromJson(jsonDecode(inSource)); + var feature1 = (inGeom as FeatureCollection).features[0]; + var feature2 = inGeom.features[1]; + var result = booleanParallel(feature1, feature2); + expect(result, false); + } + } + }, + ); + }, + ); +} diff --git a/test/components/line_overlap.dart b/test/components/line_overlap.dart index 2034b800..b94cb0ec 100644 --- a/test/components/line_overlap.dart +++ b/test/components/line_overlap.dart @@ -29,7 +29,7 @@ main() { () { // fixtures = fixtures.filter(({name}) => name.includes('#901')); - var inDir = Directory('./test/examples/line_overlaps/in'); + var inDir = Directory('./test/examples/line_overlap/in'); for (var file in inDir.listSync(recursive: true)) { if (file is File && file.path.endsWith('.geojson')) { if (file.path.contains('#901')) { @@ -50,81 +50,72 @@ main() { var outGeom = GeoJSONObject.fromJson(jsonDecode(outSource)); - FeatureCollection results = lineOverlap( - (inGeom as FeatureCollection).features.first, - inGeom.features.last); Equality eq = Equality(); - expect(eq.compare(results, outGeom), true); - FeatureCollection shared = colorize( lineOverlap(inGeom.features[0], inGeom.features[1], tolerance: 0.05), color: "#0F0"); - var results1 = FeatureCollection( - features: [ - ...shared.features, - inGeom.features[0], - inGeom.features[1] - ], - ); - - expect(eq.compare(results1, outGeom), true); - }, - ); - - test( - "turf-line-overlap - Geometry Object", - () { - var line1 = LineString( - coordinates: [ - Position.of([115, -35]), - Position.of([125, -30]), - Position.of([135, -30]), - Position.of([145, -35]), - ], - ); - var line2 = LineString( - coordinates: [ - Position.of([135, -30]), - Position.of([145, -35]), - ], - ); - - expect(lineOverlap(line1, line2).features.isNotEmpty, true); - }, - ); - - test( - "turf-line-overlap - multiple segments on same line", - () { - var line1 = LineString( - coordinates: [ - Position.of([0, 1]), - Position.of([1, 1]), - Position.of([1, 0]), - Position.of([2, 0]), - Position.of([2, 1]), - Position.of([3, 1]), - Position.of([3, 0]), - Position.of([4, 0]), - Position.of([4, 1]), - Position.of([4, 0]), - ], - ); - var line2 = LineString( - coordinates: [ - Position.of([0, 0]), - Position.of([6, 0]), - ], - ); - - expect(lineOverlap(line1, line2).features.length == 2, true); - expect(lineOverlap(line2, line1).features.length == 2, true); + FeatureCollection results = FeatureCollection(features: [ + ...shared.features, + inGeom.features.first, + inGeom.features.last + ]); + expect(eq.compare(results, outGeom), true); }, ); } } } + // test( + // "turf-line-overlap - Geometry Object", + // () { + // var line1 = LineString( + // coordinates: [ + // Position.of([115, -35]), + // Position.of([125, -30]), + // Position.of([135, -30]), + // Position.of([145, -35]), + // ], + // ); + // var line2 = LineString( + // coordinates: [ + // Position.of([135, -30]), + // Position.of([145, -35]), + // ], + // ); + + // expect(lineOverlap(line1, line2).features.isNotEmpty, true); + // }, + // ); + + // test( + // "turf-line-overlap - multiple segments on same line", + // () { + // var line1 = LineString( + // coordinates: [ + // Position.of([0, 1]), + // Position.of([1, 1]), + // Position.of([1, 0]), + // Position.of([2, 0]), + // Position.of([2, 1]), + // Position.of([3, 1]), + // Position.of([3, 0]), + // Position.of([4, 0]), + // Position.of([4, 1]), + // Position.of([4, 0]), + // ], + // ); + // var line2 = LineString( + // coordinates: [ + // Position.of([0, 0]), + // Position.of([6, 0]), + // ], + // ); + + // expect(lineOverlap(line1, line2).features.length == 2, true); + // expect(lineOverlap(line2, line1).features.length == 2, true); + // }, + // ); }, ); } From 349bab87ebe4c56bfb63e1cbaf063f0b23fcb7fa Mon Sep 17 00:00:00 2001 From: armantorkzaban Date: Wed, 31 Aug 2022 16:20:34 +0200 Subject: [PATCH 59/82] working on valid --- lib/src/booleans/boolean_valid.dart | 147 +++------------------------- test/booleans/valid_test.dart | 42 +++++++- 2 files changed, 52 insertions(+), 137 deletions(-) diff --git a/lib/src/booleans/boolean_valid.dart b/lib/src/booleans/boolean_valid.dart index d0f1bb28..3a156dd2 100644 --- a/lib/src/booleans/boolean_valid.dart +++ b/lib/src/booleans/boolean_valid.dart @@ -4,18 +4,16 @@ import '../line_intersect.dart'; import 'boolean_crosses.dart'; import 'boolean_disjoint.dart'; -// booleanValid checks if the geometry is a valid according to the OGC Simple Feature Specification. -// * -// * @name booleanValid -// * @param {Geometry|Feature} feature GeoJSON Feature or Geometry -// * @returns {boolean} true/false -// * @example -// * var line = turf.lineString([[1, 1], [1, 2], [1, 3], [1, 4]]); -// * -// * turf.booleanValid(line); // => true -// * turf.booleanValid({foo: "bar"}); // => false -// */ - +/// booleanValid checks if the geometry is a valid according to the OGC Simple Feature Specification. +/// Take a [Feature] or a [GeometryType] +/// returns a boolean true/false +/// example +/// ```dart +/// var line = LineString(coordinates:[Position.of([1, 1]), Position.of([1, 2]), Position.of([1, 3]), Position.of([1, 4])]); +/// +/// booleanValid(line); // => true +/// booleanValid({foo: "bar"}); // => false +/// ``` booleanValid(GeoJSONObject feature) { // // Automatic False // if (!feature.type) return false; @@ -106,133 +104,10 @@ checkPolygonAgainstOthers( var polyToCheck = Polygon(coordinates: poly); for (var i = index + 1; i < geom.length; i++) { if (!booleanDisjoint(polyToCheck, Polygon(coordinates: geom[i]))) { - if (booleanCrosses(polyToCheck, LineString(coordinates: geom[i][0]))) + if (booleanCrosses(polyToCheck, LineString(coordinates: geom[i][0]))) { return false; - } - } - return true; -} - -/** - * import { Feature, Geometry, Position } from "geojson"; -import { getGeom } from "@turf/invariant"; -import { polygon, lineString } from "@turf/helpers"; -import booleanDisjoint from "@turf/boolean-disjoint"; -import booleanCrosses from "@turf/boolean-crosses"; -import lineIntersect from "@turf/line-intersect"; -import isPointOnLine from "@turf/boolean-point-on-line"; - -/** - * booleanValid checks if the geometry is a valid according to the OGC Simple Feature Specification. - * - * @name booleanValid - * @param {Geometry|Feature} feature GeoJSON Feature or Geometry - * @returns {boolean} true/false - * @example - * var line = turf.lineString([[1, 1], [1, 2], [1, 3], [1, 4]]); - * - * turf.booleanValid(line); // => true - * turf.booleanValid({foo: "bar"}); // => false - */ -export default function booleanValid(feature: Feature | Geometry) { - // Automatic False - if (!feature.type) return false; - - // Parse GeoJSON - const geom = getGeom(feature); - const type = geom.type; - const coords = geom.coordinates; - - switch (type) { - case Point: - return coords.length > 1; - case MultiPoint: - for (var i = 0; i < coords.length; i++) { - if (coords[i].length < 2) return false; } - return true; - case LineString: - if (coords.length < 2) return false; - for (var i = 0; i < coords.length; i++) { - if (coords[i].length < 2) return false; - } - return true; - case MultiLineString: - if (coords.length < 2) return false; - for (var i = 0; i < coords.length; i++) { - if (coords[i].length < 2) return false; - } - return true; - case Polygon: - for (var i = 0; i < geom.coordinates.length; i++) { - if (coords[i].length < 4) return false; - if (!checkRingsClose(coords[i])) return false; - if (checkRingsForSpikesPunctures(coords[i])) return false; - if (i > 0) { - if ( - lineIntersect(polygon([coords[0]]), polygon([coords[i]])).features - .length > 1 - ) - return false; - } - } - return true; - case MultiPolygon: - for (var i = 0; i < geom.coordinates.length; i++) { - var poly: any = geom.coordinates[i]; - - for (var ii = 0; ii < poly.length; ii++) { - if (poly[ii].length < 4) return false; - if (!checkRingsClose(poly[ii])) return false; - if (checkRingsForSpikesPunctures(poly[ii])) return false; - if (ii === 0) { - if (!checkPolygonAgainstOthers(poly, geom.coordinates, i)) - return false; - } - if (ii > 0) { - if ( - lineIntersect(polygon([poly[0]]), polygon([poly[ii]])).features - .length > 1 - ) - return false; - } - } - } - return true; - default: - return false; - } -} - -function checkRingsClose(geom: Position[]) { - return ( - geom[0][0] === geom[geom.length - 1][0] || - geom[0][1] === geom[geom.length - 1][1] - ); -} - -function checkRingsForSpikesPunctures(geom: Position[]) { - for (var i = 0; i < geom.length - 1; i++) { - var point = geom[i]; - for (var ii = i + 1; ii < geom.length - 2; ii++) { - var seg = [geom[ii], geom[ii + 1]]; - if (isPointOnLine(point, lineString(seg))) return true; - } - } - return false; -} - -function checkPolygonAgainstOthers( - poly: Position[][], - geom: Position[][][], - index: number -) { - var polyToCheck = polygon(poly); - for (var i = index + 1; i < geom.length; i++) { - if (!booleanDisjoint(polyToCheck, polygon(geom[i]))) { - if (booleanCrosses(polyToCheck, lineString(geom[i][0]))) return false; } } return true; } - */ \ No newline at end of file diff --git a/test/booleans/valid_test.dart b/test/booleans/valid_test.dart index 45518ca5..973bed54 100644 --- a/test/booleans/valid_test.dart +++ b/test/booleans/valid_test.dart @@ -1,2 +1,42 @@ +// const glob = require("glob"); +// const path = require("path"); +// const test = require("tape"); +// const load = require("load-json-file"); +// // const shapely = require('boolean-shapely'); +// const isValid = require("./index").default; -/ \ No newline at end of file +// test("turf-boolean-valid", (t) => { +// // True Fixtures +// glob +// .sync(path.join(__dirname, "test", "true", "**", "*.geojson")) +// .forEach((filepath) => { +// const name = path.parse(filepath).name; + +// if (name === "multipolygon-touch") return t.skip("multipolygon-touch"); + +// const geojson = load.sync(filepath); +// const feature1 = geojson.features[0]; +// const result = isValid(feature1); + +// // if (process.env.SHAPELY) shapely.contains(feature1).then(result => t.true(result, '[true] shapely - ' + name)); +// t.true(result, "[true] " + name); +// }); +// // False Fixtures +// glob +// .sync(path.join(__dirname, "test", "false", "**", "*.geojson")) +// .forEach((filepath) => { +// const name = path.parse(filepath).name; +// const geojson = load.sync(filepath); +// const feature1 = geojson.features[0]; +// const result = isValid(feature1); + +// // if (process.env.SHAPELY) shapely.contains(feature1, feature2).then(result => t.false(result, '[false] shapely - ' + name)); +// t.false(result, "[false] " + name); +// }); +// t.end(); +// }); + +// test("turf-boolean-valid -- obvious fails", (t) => { +// t.false(isValid({ foo: "bar" })); +// t.end(); +// }); From e4c929ba242c6809ba153760375a2fd37f82df60 Mon Sep 17 00:00:00 2001 From: armantorkzaban Date: Thu, 1 Sep 2022 09:08:08 +0200 Subject: [PATCH 60/82] touches done --- lib/src/booleans/boolean_touches.dart | 1799 +++++++------------------ test/booleans/touches_test.dart | 103 +- 2 files changed, 548 insertions(+), 1354 deletions(-) diff --git a/lib/src/booleans/boolean_touches.dart b/lib/src/booleans/boolean_touches.dart index 41f602c3..395ee5a2 100644 --- a/lib/src/booleans/boolean_touches.dart +++ b/lib/src/booleans/boolean_touches.dart @@ -1,1387 +1,592 @@ +import 'package:turf/meta.dart'; + import '../../helpers.dart'; import '../invariant.dart'; import 'boolean_point_in_polygon.dart'; import 'boolean_point_on_line.dart'; -/** - * Boolean-touches true if none of the points common to both geometries - * intersect the interiors of both geometries. - * @name booleanTouches - * @param {Geometry|Feature} feature1 GeoJSON Feature or Geometry - * @param {Geometry|Feature} feature2 GeoJSON Feature or Geometry - * @returns {boolean} true/false - * @example - * var line = turf.lineString([[1, 1], [1, 2], [1, 3], [1, 4]]); - * var point = turf.point([1, 1]); - * - * turf.booleanTouches(point, line); - * //=true - */ +/// Boolean-touches [true] if none of the [Point]s common to both geometries +/// intersect the interiors of both geometries. +/// example +/// ```dart +/// var line = LineString(coordinates;[Positin.of([1, 1]), Positin.of([1, 2]), Positin.of([1, 3]), Positin.of([1, 4])]); +/// var point = Point(coordinates: Positon.of([1, 1])); +/// booleanTouches(point, line); +/// //=true bool booleanTouches(GeoJSONObject feature1, GeoJSONObject feature2) { - var geom1 = getGeom(feature1); - var geom2 = getGeom(feature2); - var type1 = geom1.type; - var type2 = geom2.type; + var geom1 = feature1 is Feature ? feature1.geometry : feature1; + var geom2 = feature2 is Feature ? feature2.geometry : feature2; - switch (type1) { - case Point: - switch (type2) { - case LineString: - return isPointOnLineEnd(geom1, geom2); - case MultiLineString: - var foundTouchingPoint = false; - for (var ii = 0; ii < geom2.coordinates.length; ii++) { - if (isPointOnLineEnd( - geom1, - LineString( - coordinates: geom2.coordinates[ii], - ))) { + if (geom1 is Point) { + if (geom2 is LineString) { + return isPointOnLineEnd(geom1, geom2); + } else if (geom2 is MultiLineString) { + var foundTouchingPoint = false; + for (var ii = 0; ii < geom2.coordinates.length; ii++) { + if (isPointOnLineEnd( + geom1, + LineString( + coordinates: geom2.coordinates[ii], + ), + )) { + foundTouchingPoint = true; + } + } + return foundTouchingPoint; + } else if (geom2 is Polygon) { + for (var i = 0; i < geom2.coordinates.length; i++) { + if (booleanPointOnLine( + geom1, + LineString( + coordinates: geom2.coordinates[i], + ), + )) { + return true; + } + } + return false; + } else if (geom2 is MultiPolygon) { + for (var i = 0; i < geom2.coordinates.length; i++) { + for (var ii = 0; ii < geom2.coordinates[i].length; ii++) { + if (booleanPointOnLine( + geom1, + LineString( + coordinates: geom2.coordinates[i][ii], + ), + )) { + return true; + } + } + } + return false; + } else { + throw Exception("feature2 $geom2 geometry not supported"); + } + } else if (geom1 is MultiPoint) { + if (geom2 is LineString) { + var foundTouchingPoint = false; + for (var i = 0; i < geom1.coordinates.length; i++) { + if (!foundTouchingPoint) { + if (isPointOnLineEnd( + Point(coordinates: geom1.coordinates[i]), geom2)) { + foundTouchingPoint = true; + } + } + if (booleanPointOnLine(Point(coordinates: geom1.coordinates[i]), geom2, + ignoreEndVertices: true)) return false; + } + return foundTouchingPoint; + } else if (geom2 is MultiLineString) { + var foundTouchingPoint = false; + for (var i = 0; i < geom1.coordinates.length; i++) { + for (var ii = 0; ii < geom2.coordinates.length; ii++) { + if (!foundTouchingPoint) { + if (isPointOnLineEnd(Point(coordinates: geom1.coordinates[i]), + LineString(coordinates: geom2.coordinates[ii]))) { foundTouchingPoint = true; } } - return foundTouchingPoint; - case Polygon: - for (var i = 0; i < geom2.coordinates.length; i++) { - if (booleanPointOnLine( - geom1, - LineString( - coordinates: geom2.coordinates[i], - ))) { - return true; - } + if (booleanPointOnLine(Point(coordinates: geom1.coordinates[i]), + LineString(coordinates: geom2.coordinates[ii]), + ignoreEndVertices: true)) { + return false; } + } + } + return foundTouchingPoint; + } else if (geom2 is Polygon) { + var foundTouchingPoint = false; + for (var i = 0; i < geom1.coordinates.length; i++) { + if (!foundTouchingPoint) { + if (booleanPointOnLine( + Point(coordinates: geom1.coordinates[i]), + LineString(coordinates: geom2.coordinates[0]), + )) { + foundTouchingPoint = true; + } + } + if (booleanPointInPolygon(geom1.coordinates[i], geom2, + ignoreBoundary: true)) { return false; - case MultiPolygon: - for (var i = 0; i < geom2.coordinates.length; i++) { - for (var ii = 0; ii < geom2.coordinates[i].length; ii++) { - if (booleanPointOnLine( - geom1, - LineString( - coordinates: geom2.coordinates[i][ii], - ))) { - return true; - } + } + } + return foundTouchingPoint; + } else if (geom2 is MultiPolygon) { + var foundTouchingPoint = false; + for (var i = 0; i < geom1.coordinates.length; i++) { + for (var ii = 0; ii < geom2.coordinates.length; ii++) { + if (!foundTouchingPoint) { + if (booleanPointOnLine( + Point(coordinates: geom1.coordinates[i]), + LineString( + coordinates: geom2.coordinates[ii][0], + ), + )) { + foundTouchingPoint = true; } } + if (booleanPointInPolygon( + geom1.coordinates[i], Polygon(coordinates: geom2.coordinates[ii]), + ignoreBoundary: true)) { + return false; + } + } + } + return foundTouchingPoint; + } else { + throw Exception("feature2 $geom2 geometry not supported"); + } + } else if (geom1 is LineString) { + if (geom2 is Point) { + return isPointOnLineEnd(geom2, geom1); + } else if (geom2 is MultiPoint) { + var foundTouchingPoint = false; + for (var i = 0; i < geom2.coordinates.length; i++) { + if (!foundTouchingPoint) { + if (isPointOnLineEnd( + Point(coordinates: geom2.coordinates[i]), geom1)) { + foundTouchingPoint = true; + } + } + if (booleanPointOnLine(Point(coordinates: geom2.coordinates[i]), geom1, + ignoreEndVertices: true)) { return false; - default: - throw Exception("feature2 " + type2 + " geometry not supported"); + } } - case MultiPoint: - switch (type2) { - case LineString: - var foundTouchingPoint = false; - for (var i = 0; i < geom1.coordinates.length; i++) { - if (!foundTouchingPoint) { - if (isPointOnLineEnd( - Point(coordinates: geom1.coordinates[i]), geom2)) - foundTouchingPoint = true; - } + return foundTouchingPoint; + } else if (geom2 is LineString) { + var endMatch = false; + if (isPointOnLineEnd(Point(coordinates: geom1.coordinates[0]), geom2)) { + endMatch = true; + } + if (isPointOnLineEnd( + Point( + coordinates: geom1.coordinates[geom1.coordinates.length - 1], + ), + geom2)) endMatch = true; + if (endMatch == false) return false; + for (var i = 0; i < geom1.coordinates.length; i++) { + if (booleanPointOnLine(Point(coordinates: geom1.coordinates[i]), geom2, + ignoreEndVertices: true)) { + return false; + } + } + return endMatch; + } else if (geom2 is MultiLineString) { + var endMatch = false; + for (var i = 0; i < geom2.coordinates.length; i++) { + if (isPointOnLineEnd(Point(coordinates: geom1.coordinates[0]), + LineString(coordinates: geom2.coordinates[i]))) { + endMatch = true; + } + if (isPointOnLineEnd( + Point( + coordinates: geom1.coordinates[geom1.coordinates.length - 1], + ), + LineString(coordinates: geom2.coordinates[i]))) { + endMatch = true; + } + for (var ii = 0; ii < geom1.coordinates[i].length; ii++) { + if (booleanPointOnLine(Point(coordinates: geom1.coordinates[ii]), + LineString(coordinates: geom2.coordinates[i]), + ignoreEndVertices: true)) { + return false; + } + } + } + return endMatch; + } else if (geom2 is Polygon) { + var foundTouchingPoint = false; + for (var i = 0; i < geom1.coordinates.length; i++) { + if (!foundTouchingPoint) { + if (booleanPointOnLine(Point(coordinates: geom1.coordinates[i]), + LineString(coordinates: geom2.coordinates[0]))) { + foundTouchingPoint = true; + } + } + if (booleanPointInPolygon(geom1.coordinates[i], geom2, + ignoreBoundary: true)) { + return false; + } + } + return foundTouchingPoint; + } else if (geom2 is MultiPolygon) { + var foundTouchingPoint = false; + for (var i = 0; i < geom1.coordinates.length; i++) { + for (var ii = 0; ii < geom2.coordinates.length; ii++) { + if (!foundTouchingPoint) { if (booleanPointOnLine( - Point(coordinates: geom1.coordinates[i]), geom2, - ignoreEndVertices: true)) return false; - } - return foundTouchingPoint; - case MultiLineString: - var foundTouchingPoint = false; - for (var i = 0; i < geom1.coordinates.length; i++) { - for (var ii = 0; ii < geom2.coordinates.length; ii++) { - if (!foundTouchingPoint) { - if (isPointOnLineEnd(Point(coordinates: geom1.coordinates[i]), - LineString(coordinates: geom2.coordinates[ii]))) { - foundTouchingPoint = true; - } - } - if (booleanPointOnLine(Point(coordinates: geom1.coordinates[i]), - LineString(coordinates: geom2.coordinates[ii]), - ignoreEndVertices: true)) { - return false; - } + Point(coordinates: geom1.coordinates[i]), + LineString( + coordinates: geom2.coordinates[ii][0], + ), + )) { + foundTouchingPoint = true; } } - return foundTouchingPoint; - case Polygon: - var foundTouchingPoint = false; - for (var i = 0; i < geom1.coordinates.length; i++) { - if (!foundTouchingPoint) { - if (booleanPointOnLine(Point(coordinates: geom1.coordinates[i]), - LineString(coordinates: geom2.coordinates[0]))) { - foundTouchingPoint = true; - } - } - if (booleanPointInPolygon(geom1.coordinates[i], geom2, - ignoreBoundary: true)) { - return false; + } + if (booleanPointInPolygon(geom1.coordinates[i], geom2, + ignoreBoundary: true)) { + return false; + } + } + return foundTouchingPoint; + } else { + throw Exception("feature2 $geom2 geometry not supported"); + } + } else if (geom1 is MultiLineString) { + if (geom2 is Point) { + for (var i = 0; i < geom1.coordinates.length; i++) { + if (isPointOnLineEnd( + geom2, + LineString( + coordinates: geom1.coordinates[i], + ))) { + return true; + } + } + return false; + } else if (geom2 is MultiPoint) { + var foundTouchingPoint = false; + for (var i = 0; i < geom1.coordinates.length; i++) { + for (var ii = 0; ii < geom2.coordinates.length; ii++) { + if (!foundTouchingPoint) { + if (isPointOnLineEnd(Point(coordinates: geom2.coordinates[ii]), + LineString(coordinates: geom1.coordinates[ii]))) { + foundTouchingPoint = true; } } - return foundTouchingPoint; - case MultiPolygon: - var foundTouchingPoint = false; - for (var i = 0; i < geom1.coordinates.length; i++) { - for (var ii = 0; ii < geom2.coordinates.length; ii++) { - if (!foundTouchingPoint) { - if (booleanPointOnLine( - Point(coordinates: geom1.coordinates[i]), - LineString( - coordinates: geom2.coordinates[ii][0], - ))) { - foundTouchingPoint = true; - } - } - if (booleanPointInPolygon(geom1.coordinates[i], - Polygon(coordinates: geom2.coordinates[ii]), - ignoreBoundary: true)) { - return false; - } - } + if (booleanPointOnLine(Point(coordinates: geom2.coordinates[ii]), + LineString(coordinates: geom1.coordinates[ii]), + ignoreEndVertices: true)) { + return false; } - return foundTouchingPoint; - default: - throw Exception("feature2 " + type2 + " geometry not supported"); + } } - case LineString: - switch (type2) { - case Point: - return isPointOnLineEnd(geom2, geom1); - case MultiPoint: - var foundTouchingPoint = false; - for (var i = 0; i < geom2.coordinates.length; i++) { - if (!foundTouchingPoint) { - if (isPointOnLineEnd(geom2.coordinates[i], geom1)) { - foundTouchingPoint = true; - } - } - if (booleanPointOnLine(geom2.coordinates[i], geom1, - ignoreEndVertices: true)) { - return false; - } - } - return foundTouchingPoint; - case LineString: - var endMatch = false; - if (isPointOnLineEnd( - Point(coordinates: geom1.coordinates[0]), geom2)) { + return foundTouchingPoint; + } else if (geom2 is LineString) { + var endMatch = false; + for (var i = 0; i < geom1.coordinates.length; i++) { + if (isPointOnLineEnd( + Point(coordinates: geom1.coordinates[i][0]), geom2)) { + endMatch = true; + } + if (isPointOnLineEnd( + Point( + coordinates: geom1.coordinates[i] + [geom1.coordinates[i].length - 1], + ), + geom2)) { + endMatch = true; + } + for (var ii = 0; ii < geom2.coordinates.length; ii++) { + if (booleanPointOnLine(Point(coordinates: geom2.coordinates[ii]), + LineString(coordinates: geom1.coordinates[i]), + ignoreEndVertices: true)) { + return false; + } + } + } + return endMatch; + } else if (geom2 is MultiLineString) { + var endMatch = false; + for (var i = 0; i < geom1.coordinates.length; i++) { + for (var ii = 0; ii < geom2.coordinates.length; ii++) { + if (isPointOnLineEnd(Point(coordinates: geom1.coordinates[i][0]), + LineString(coordinates: geom2.coordinates[ii]))) { endMatch = true; } if (isPointOnLineEnd( Point( - coordinates: geom1.coordinates[geom1.coordinates.length - 1], + coordinates: geom1.coordinates[i] + [geom1.coordinates[i].length - 1], ), - geom2)) endMatch = true; - if (endMatch == false) return false; - for (var i = 0; i < geom1.coordinates.length; i++) { + LineString(coordinates: geom2.coordinates[ii]))) { + endMatch = true; + } + for (var iii = 0; iii < geom1.coordinates[i].length; iii++) { if (booleanPointOnLine( - Point(coordinates: geom1.coordinates[i]), geom2, + Point(coordinates: geom1.coordinates[i][iii]), + LineString(coordinates: geom2.coordinates[ii]), ignoreEndVertices: true)) { return false; } } - return endMatch; - case MultiLineString: - var endMatch = false; - for (var i = 0; i < geom2.coordinates.length; i++) { - if (isPointOnLineEnd(Point(coordinates: geom1.coordinates[0]), - LineString(coordinates: geom2.coordinates[i]))) { - endMatch = true; - } - if (isPointOnLineEnd( - Point( - coordinates: geom1.coordinates[geom1.coordinates.length - 1], - ), - LineString(coordinates: geom2.coordinates[i]))) { - endMatch = true; - } - for (var ii = 0; ii < geom1.coordinates[i].length; ii++) { - if (booleanPointOnLine(Point(coordinates: geom1.coordinates[ii]), - LineString(coordinates: geom2.coordinates[i]), - ignoreEndVertices: true)) { - return false; - } - } - } - return endMatch; - case Polygon: - var foundTouchingPoint = false; - for (var i = 0; i < geom1.coordinates.length; i++) { - if (!foundTouchingPoint) { - if (booleanPointOnLine(Point(coordinates: geom1.coordinates[i]), - LineString(coordinates: geom2.coordinates[0]))) { - foundTouchingPoint = true; - } - } - if (booleanPointInPolygon(geom1.coordinates[i], geom2, - ignoreBoundary: true)) { - return false; - } - } - return foundTouchingPoint; - case MultiPolygon: - var foundTouchingPoint = false; - for (var i = 0; i < geom1.coordinates.length; i++) { - for (var ii = 0; ii < geom2.coordinates.length; ii++) { - if (!foundTouchingPoint) { - if (booleanPointOnLine( - Point(coordinates: geom1.coordinates[i]), - LineString( - coordinates: geom2.coordinates[ii][0], - ))) { - foundTouchingPoint = true; - } - } - } - if (booleanPointInPolygon(geom1.coordinates[i], geom2, - ignoreBoundary: true)) { - return false; - } - } - return foundTouchingPoint; - default: - throw Exception("feature2 " + type2 + " geometry not supported"); + } } - case MultiLineString: - switch (type2) { - case Point: - for (var i = 0; i < geom1.coordinates.length; i++) { - if (isPointOnLineEnd( - geom2, - LineString( - coordinates: geom1.coordinates[i], - ))) { - return true; - } - } - return false; - case MultiPoint: - var foundTouchingPoint = false; - for (var i = 0; i < geom1.coordinates.length; i++) { - for (var ii = 0; ii < geom2.coordinates.length; ii++) { - if (!foundTouchingPoint) { - if (isPointOnLineEnd(Point(coordinates: geom2.coordinates[ii]), - LineString(coordinates: geom1.coordinates[ii]))) { - foundTouchingPoint = true; - } - } - if (booleanPointOnLine(Point(coordinates: geom2.coordinates[ii]), - LineString(coordinates: geom1.coordinates[ii]), - ignoreEndVertices: true)) { - return false; - } - } - } - return foundTouchingPoint; - case LineString: - var endMatch = false; - for (var i = 0; i < geom1.coordinates.length; i++) { - if (isPointOnLineEnd( - Point(coordinates: geom1.coordinates[i][0]), geom2)) { - endMatch = true; - } - if (isPointOnLineEnd( - Point( - coordinates: geom1.coordinates[i] - [geom1.coordinates[i].length - 1], - ), - geom2)) { - endMatch = true; - } - for (var ii = 0; ii < geom2.coordinates.length; ii++) { - if (booleanPointOnLine(Point(coordinates: geom2.coordinates[ii]), - LineString(coordinates: geom1.coordinates[i]), - ignoreEndVertices: true)) { - return false; - } - } - } - return endMatch; - case MultiLineString: - var endMatch = false; - for (var i = 0; i < geom1.coordinates.length; i++) { - for (var ii = 0; ii < geom2.coordinates.length; ii++) { - if (isPointOnLineEnd(Point(coordinates: geom1.coordinates[i][0]), - LineString(coordinates: geom2.coordinates[ii]))) { - endMatch = true; - } - if (isPointOnLineEnd( - Point( - coordinates: geom1.coordinates[i] - [geom1.coordinates[i].length - 1], - ), - LineString(coordinates: geom2.coordinates[ii]))) { - endMatch = true; - } - for (var iii = 0; iii < geom1.coordinates[i].length; iii++) { - if (booleanPointOnLine( - Point(coordinates: geom1.coordinates[i][iii]), - LineString(coordinates: geom2.coordinates[ii]), - ignoreEndVertices: true)) { - return false; - } - } - } - } - return endMatch; - case Polygon: - var foundTouchingPoint = false; - for (var i = 0; i < geom1.coordinates.length; i++) { - for (var ii = 0; ii < geom1.coordinates.length; ii++) { - if (!foundTouchingPoint) { - if (booleanPointOnLine( - Point(coordinates: geom1.coordinates[i][ii]), - LineString(coordinates: geom2.coordinates[0]))) { - foundTouchingPoint = true; - } - } - if (booleanPointInPolygon(geom1.coordinates[i][ii], geom2, - ignoreBoundary: true)) { - return false; - } + return endMatch; + } else if (geom2 is Polygon) { + var foundTouchingPoint = false; + for (var i = 0; i < geom1.coordinates.length; i++) { + for (var ii = 0; ii < geom1.coordinates.length; ii++) { + if (!foundTouchingPoint) { + if (booleanPointOnLine(Point(coordinates: geom1.coordinates[i][ii]), + LineString(coordinates: geom2.coordinates[0]))) { + foundTouchingPoint = true; } } - return foundTouchingPoint; - case MultiPolygon: - var foundTouchingPoint = false; - for (var i = 0; i < geom2.coordinates[0].length; i++) { - for (var ii = 0; ii < geom1.coordinates.length; ii++) { - for (var iii = 0; iii < geom1.coordinates[ii].length; iii++) { - if (!foundTouchingPoint) { - if (booleanPointOnLine( - Point( - coordinates: geom1.coordinates[ii][iii], - ), - LineString( - coordinates: geom2.coordinates[0][i], - ))) { - foundTouchingPoint = true; - } - } - if (booleanPointInPolygon(geom1.coordinates[ii][iii], - Polygon(coordinates: [geom2.coordinates[0][i]]), - ignoreBoundary: true)) { - return false; - } - } - } + if (booleanPointInPolygon(geom1.coordinates[i][ii], geom2, + ignoreBoundary: true)) { + return false; } - return foundTouchingPoint; - default: - throw Exception("feature2 " + type2 + " geometry not supported"); + } } - case Polygon: - switch (type2) { - case Point: - for (var i = 0; i < geom1.coordinates.length; i++) { - if (booleanPointOnLine( - geom2, - LineString( - coordinates: geom1.coordinates[i], - ))) { - return true; - } - } - return false; - case MultiPoint: - var foundTouchingPoint = false; - for (var i = 0; i < geom2.coordinates.length; i++) { - if (!foundTouchingPoint) { - if (booleanPointOnLine(geom2.coordinates[i], - LineString(coordinates: geom1.coordinates[0]))) { - foundTouchingPoint = true; - } - } - if (booleanPointInPolygon(geom2.coordinates[i], geom1, - ignoreBoundary: true)) return false; - } - return foundTouchingPoint; - case LineString: - var foundTouchingPoint = false; - for (var i = 0; i < geom2.coordinates.length; i++) { - if (!foundTouchingPoint) { - if (booleanPointOnLine(geom2.coordinates[i], - LineString(coordinates: geom1.coordinates[0]))) { - foundTouchingPoint = true; - } - } - if (booleanPointInPolygon(geom2.coordinates[i], geom1, - ignoreBoundary: true)) { - return false; - } - } - return foundTouchingPoint; - case MultiLineString: - var foundTouchingPoint = false; - for (var i = 0; i < geom2.coordinates.length; i++) { - for (var ii = 0; ii < geom2.coordinates[i].length; ii++) { - if (!foundTouchingPoint) { - if (booleanPointOnLine(geom2.coordinates[i][ii], - LineString(coordinates: geom1.coordinates[0]))) { - foundTouchingPoint = true; - } - } - if (booleanPointInPolygon(geom2.coordinates[i][ii], geom1, - ignoreBoundary: true)) { - return false; - } - } - } - return foundTouchingPoint; - case Polygon: - var foundTouchingPoint = false; - for (var i = 0; i < geom1.coordinates[0].length; i++) { + return foundTouchingPoint; + } else if (geom2 is MultiPolygon) { + var foundTouchingPoint = false; + for (var i = 0; i < geom2.coordinates[0].length; i++) { + for (var ii = 0; ii < geom1.coordinates.length; ii++) { + for (var iii = 0; iii < geom1.coordinates[ii].length; iii++) { if (!foundTouchingPoint) { if (booleanPointOnLine( - Point(coordinates: geom1.coordinates[0][i]), - LineString(coordinates: geom2.coordinates[0]))) { + Point( + coordinates: geom1.coordinates[ii][iii], + ), + LineString( + coordinates: geom2.coordinates[0][i], + ))) { foundTouchingPoint = true; } } - if (booleanPointInPolygon(geom1.coordinates[0][i], geom2, + if (booleanPointInPolygon(geom1.coordinates[ii][iii], + Polygon(coordinates: [geom2.coordinates[0][i]]), ignoreBoundary: true)) { return false; } } - return foundTouchingPoint; - case MultiPolygon: - var foundTouchingPoint = false; - for (var i = 0; i < geom2.coordinates[0].length; i++) { - for (var ii = 0; ii < geom1.coordinates[0].length; ii++) { - if (!foundTouchingPoint) { - if (booleanPointOnLine( - Point(coordinates: geom1.coordinates[0][ii]), - LineString(coordinates: geom2.coordinates[0][i]))) { - foundTouchingPoint = true; - } - } - if (booleanPointInPolygon(geom1.coordinates[0][ii], - Polygon(coordinates: geom2.coordinates[0][i]), - ignoreBoundary: true)) { - return false; - } - } - } - return foundTouchingPoint; - default: - throw Exception("feature2 " + type2 + " geometry not supported"); + } } - case MultiPolygon: - switch (type2) { - case Point: - for (var i = 0; i < geom1.coordinates[0].length; i++) { - if (booleanPointOnLine( - geom2, - LineString( - coordinates: geom1.coordinates[0][i], - ))) { - return true; - } - } + return foundTouchingPoint; + } else { + throw Exception("feature2 $geom2 geometry not supported"); + } + } else if (geom1 is Polygon) { + if (geom2 is Point) { + for (var i = 0; i < geom1.coordinates.length; i++) { + if (booleanPointOnLine( + geom2, + LineString( + coordinates: geom1.coordinates[i], + ))) { + return true; + } + } + return false; + } else if (geom2 is MultiPoint) { + var foundTouchingPoint = false; + for (var i = 0; i < geom2.coordinates.length; i++) { + if (!foundTouchingPoint) { + if (booleanPointOnLine(Point(coordinates: geom2.coordinates[i]), + LineString(coordinates: geom1.coordinates[0]))) { + foundTouchingPoint = true; + } + } + if (booleanPointInPolygon(geom2.coordinates[i], geom1, + ignoreBoundary: true)) return false; + } + return foundTouchingPoint; + } else if (geom2 is LineString) { + var foundTouchingPoint = false; + for (var i = 0; i < geom2.coordinates.length; i++) { + if (!foundTouchingPoint) { + if (booleanPointOnLine(Point(coordinates: geom2.coordinates[i]), + LineString(coordinates: geom1.coordinates[0]))) { + foundTouchingPoint = true; + } + } + if (booleanPointInPolygon(geom2.coordinates[i], geom1, + ignoreBoundary: true)) { return false; - case MultiPoint: - var foundTouchingPoint = false; - for (var i = 0; i < geom1.coordinates[0].length; i++) { - for (var ii = 0; ii < geom2.coordinates.length; ii++) { - if (!foundTouchingPoint) { - if (booleanPointOnLine( - Point(coordinates: geom2.coordinates[ii]), - LineString(coordinates: geom1.coordinates[0][i]))) { - foundTouchingPoint = true; - } - } - if (booleanPointInPolygon(geom2.coordinates[ii], - Polygon(coordinates: geom1.coordinates[0][i]), - ignoreBoundary: true)) { - return false; - } - } - } - return foundTouchingPoint; - case LineString: - var foundTouchingPoint = false; - for (var i = 0; i < geom1.coordinates[0].length; i++) { - for (var ii = 0; ii < geom2.coordinates.length; ii++) { - if (!foundTouchingPoint) { - if (booleanPointOnLine( - Point(coordinates: geom2.coordinates[ii]), - LineString(coordinates: geom1.coordinates[0][i]))) { - foundTouchingPoint = true; - } - } - if (booleanPointInPolygon(geom2.coordinates[ii], - Polygon(coordinates: geom1.coordinates[0][i]), - ignoreBoundary: true)) { - return false; - } - } - } - return foundTouchingPoint; - case MultiLineString: - var foundTouchingPoint = false; - for (var i = 0; i < geom1.coordinates.length; i++) { - for (var ii = 0; ii < geom2.coordinates.length; ii++) { - for (var iii = 0; iii < geom2.coordinates[ii].length; iii++) { - if (!foundTouchingPoint) { - if (booleanPointOnLine( - Point( - coordinates: geom2.coordinates[ii][iii], - ), - LineString( - coordinates: geom1.coordinates[i][0], - ))) { - foundTouchingPoint = true; - } - } - if (booleanPointInPolygon(geom2.coordinates[ii][iii], - Polygon(coordinates: [geom1.coordinates[i][0]]), - ignoreBoundary: true)) { - return false; - } - } - } - } - - return foundTouchingPoint; - case Polygon: - var foundTouchingPoint = false; - for (var i = 0; i < geom1.coordinates[0].length; i++) { - for (var ii = 0; ii < geom1.coordinates[0][i].length; ii++) { - if (!foundTouchingPoint) { - if (booleanPointOnLine( - Point(coordinates: geom1.coordinates[0][i][ii]), - LineString(coordinates: geom2.coordinates[0]))) { - foundTouchingPoint = true; - } - } - if (booleanPointInPolygon(geom1.coordinates[0][i][ii], geom2, - ignoreBoundary: true)) { - return false; - } - } - } - return foundTouchingPoint; - case MultiPolygon: - var foundTouchingPoint = false; - for (var i = 0; i < geom1.coordinates[0].length; i++) { - for (var ii = 0; ii < geom2.coordinates[0].length; ii++) { - for (var iii = 0; iii < geom1.coordinates[0].length; iii++) { - if (!foundTouchingPoint) { - if (booleanPointOnLine( - Point( - coordinates: geom1.coordinates[0][i][iii], - ), - LineString( - coordinates: geom2.coordinates[0][ii], - ))) { - foundTouchingPoint = true; - } - } - if (booleanPointInPolygon(geom1.coordinates[0][i][iii], - Polygon(coordinates: geom2.coordinates[0][ii]), - ignoreBoundary: true)) { - return false; - } - } - } - } - return foundTouchingPoint; - default: - throw Exception("feature2 " + type2 + " geometry not supported"); + } } - default: - throw Exception("feature1 " + type1 + " geometry not supported"); - } -} - -isPointOnLineEnd(Point point, LineString line) { - if (compareCoords(line.coordinates[0], point.coordinates)) return true; - if (compareCoords( - line.coordinates[line.coordinates.length - 1], point.coordinates)) { - return true; - } - return false; -} - -/** - * compareCoords - * - * @private - * @param {Position} pair1 point [x,y] - * @param {Position} pair2 point [x,y] - * @returns {boolean} true/false if coord pairs match - */ -compareCoords(Position pair1, Position pair2) { - return pair1[0] == pair2[0] && pair1[1] == pair2[1]; -} - -/** import { Feature, Geometry, LineString(Point } from "geojson"; -import booleanPointOnLine from "@turf/boolean-point-on-line"; -import booleanPointInPolygon from "@turf/boolean-point-in-polygon"; -import { getGeom } from "@turf/invariant"; - -/** - * Boolean-touches true if none of the points common to both geometries - * intersect the interiors of both geometries. - * @name booleanTouches - * @param {Geometry|Feature} feature1 GeoJSON Feature or Geometry - * @param {Geometry|Feature} feature2 GeoJSON Feature or Geometry - * @returns {boolean} true/false - * @example - * var line = turf.lineString([[1, 1], [1, 2], [1, 3], [1, 4]]); - * var point = turf.point([1, 1]); - * - * turf.booleanTouches(point, line); - * //=true - */ -function booleanTouches( - feature1: Feature | Geometry, - feature2: Feature | Geometry -): boolean { - var geom1 = getGeom(feature1); - var geom2 = getGeom(feature2); - var type1 = geom1.type; - var type2 = geom2.type; - - switch (type1) { - case Point: - switch (type2) { - case LineString: - return isPointOnLineEnd(geom1, geom2); - case MultiLineString: - var foundTouchingPoint = false; - for (var ii = 0; ii < geom2.coordinates.length; ii++) { - if ( - isPointOnLineEnd(geom1, LineString( - coordinates: geom2.coordinates[ii], - }) - ) + return foundTouchingPoint; + } else if (geom2 is MultiLineString) { + var foundTouchingPoint = false; + for (var i = 0; i < geom2.coordinates.length; i++) { + for (var ii = 0; ii < geom2.coordinates[i].length; ii++) { + if (!foundTouchingPoint) { + if (booleanPointOnLine(Point(coordinates: geom2.coordinates[i][ii]), + LineString(coordinates: geom1.coordinates[0]))) { foundTouchingPoint = true; - } - return foundTouchingPoint; - case Polygon: - for (var i = 0; i < geom2.coordinates.length; i++) { - if ( - booleanPointOnLine(geom1, LineString( - coordinates: geom2.coordinates[i], - )) - ) - return true; - } - return false; - case MultiPolygon: - for (var i = 0; i < geom2.coordinates.length; i++) { - for (var ii = 0; ii < geom2.coordinates[i].length; ii++) { - if ( - booleanPointOnLine(geom1,LineString( - coordinates: geom2.coordinates[i][ii], - }) - ) - return true; } } + if (booleanPointInPolygon(geom2.coordinates[i][ii], geom1, + ignoreBoundary: true)) { + return false; + } + } + } + return foundTouchingPoint; + } else if (geom2 is Polygon) { + var foundTouchingPoint = false; + for (var i = 0; i < geom1.coordinates[0].length; i++) { + if (!foundTouchingPoint) { + if (booleanPointOnLine( + Point(coordinates: geom1.coordinates[0][i]), + LineString(coordinates: geom2.coordinates[0]), + )) { + foundTouchingPoint = true; + } + } + if (booleanPointInPolygon(geom1.coordinates[0][i], geom2, + ignoreBoundary: true)) { return false; - default: - throw Exception("feature2 " + type2 + " geometry not supported"); + } } - case MultiPoint: - switch (type2) { - case LineString: - var foundTouchingPoint = false; - for (var i = 0; i < geom1.coordinates.length; i++) { - if (!foundTouchingPoint) { - if ( - isPointOnLineEnd( - Point(coordinates: geom1.coordinates[i]), - geom2 - ) - ) - foundTouchingPoint = true; + return foundTouchingPoint; + } else if (geom2 is MultiPolygon) { + var foundTouchingPoint = false; + for (var i = 0; i < geom2.coordinates[0].length; i++) { + for (var ii = 0; ii < geom1.coordinates[0].length; ii++) { + if (!foundTouchingPoint) { + if (booleanPointOnLine(Point(coordinates: geom1.coordinates[0][ii]), + LineString(coordinates: geom2.coordinates[0][i]))) { + foundTouchingPoint = true; } - if ( - booleanPointOnLine( - Point(coordinates: geom1.coordinates[i]), - geom2, - ignoreEndVertices: true - ) - ) - return false; } - return foundTouchingPoint; - case MultiLineString: - var foundTouchingPoint = false; - for (var i = 0; i < geom1.coordinates.length; i++) { - for (var ii = 0; ii < geom2.coordinates.length; ii++) { - if (!foundTouchingPoint) { - if ( - isPointOnLineEnd( - Point(coordinates: geom1.coordinates[i]), - LineString( coordinates: geom2.coordinates[ii] ) - ) - ) - foundTouchingPoint = true; - } - if ( - booleanPointOnLine( - Point(coordinates: geom1.coordinates[i]), - LineString( coordinates: geom2.coordinates[ii] ), - ignoreEndVertices: true - ) - ) - return false; - } + if (booleanPointInPolygon(geom1.coordinates[0][ii], + Polygon(coordinates: [geom2.coordinates[0][i]]), + ignoreBoundary: true)) { + return false; } - return foundTouchingPoint; - case Polygon: - var foundTouchingPoint = false; - for (var i = 0; i < geom1.coordinates.length; i++) { - if (!foundTouchingPoint) { - if ( - booleanPointOnLine( - Point(coordinates: geom1.coordinates[i]), - LineString(coordinates: geom2.coordinates[0] ) - ) - ) - foundTouchingPoint = true; + } + } + return foundTouchingPoint; + } else { + throw Exception("feature2 $geom2 geometry not supported"); + } + } else if (geom1 is MultiPolygon) { + if (geom2 is Point) { + for (var i = 0; i < geom1.coordinates[0].length; i++) { + if (booleanPointOnLine( + geom2, + LineString( + coordinates: geom1.coordinates[0][i], + ), + )) { + return true; + } + } + return false; + } else if (geom2 is MultiPoint) { + var foundTouchingPoint = false; + for (var i = 0; i < geom1.coordinates[0].length; i++) { + for (var ii = 0; ii < geom2.coordinates.length; ii++) { + if (!foundTouchingPoint) { + if (booleanPointOnLine(Point(coordinates: geom2.coordinates[ii]), + LineString(coordinates: geom1.coordinates[0][i]))) { + foundTouchingPoint = true; } - if ( - booleanPointInPolygon( - Point(coordinates: geom1.coordinates[i]), - geom2, - ignoreBoundary: true - ) - ) - return false; } - return foundTouchingPoint; - case MultiPolygon: - var foundTouchingPoint = false; - for (var i = 0; i < geom1.coordinates.length; i++) { - for (var ii = 0; ii < geom2.coordinates.length; ii++) { - if (!foundTouchingPoint) { - if ( - booleanPointOnLine( - Point(coordinates: geom1.coordinates[i]), -LineString( - coordinates: geom2.coordinates[ii][0], - ) - ) - ) - foundTouchingPoint = true; - } - if ( - booleanPointInPolygon( - Point(coordinates: geom1.coordinates[i]), - Polygon( coordinates: geom2.coordinates[ii] ), - ignoreBoundary: true - ) - ) - return false; - } + if (booleanPointInPolygon(geom2.coordinates[ii], + Polygon(coordinates: [geom1.coordinates[0][i]]), + ignoreBoundary: true)) { + return false; } - return foundTouchingPoint; - default: - throw Exception("feature2 " + type2 + " geometry not supported"); + } } - case LineString: - switch (type2) { - case Point: - return isPointOnLineEnd(geom2, geom1); - case MultiPoint: - var foundTouchingPoint = false; - for (var i = 0; i < geom2.coordinates.length; i++) { - if (!foundTouchingPoint) { - if ( - isPointOnLineEnd( - Point(coordinates: geom2.coordinates[i] ), - geom1 - ) - ) - foundTouchingPoint = true; + return foundTouchingPoint; + } else if (geom2 is LineString) { + var foundTouchingPoint = false; + for (var i = 0; i < geom1.coordinates[0].length; i++) { + for (var ii = 0; ii < geom2.coordinates.length; ii++) { + if (!foundTouchingPoint) { + if (booleanPointOnLine(Point(coordinates: geom2.coordinates[ii]), + LineString(coordinates: geom1.coordinates[0][i]))) { + foundTouchingPoint = true; } - if ( - booleanPointOnLine( - Point(coordinates: geom2.coordinates[i] ), - geom1, - ignoreEndVertices: true - ) - ) - return false; } - return foundTouchingPoint; - case LineString: - var endMatch = false; - if ( - isPointOnLineEnd( - Point(coordinates: geom1.coordinates[0] ), - geom2 - ) - ) - endMatch = true; - if ( - isPointOnLineEnd( - Point( - coordinates: geom1.coordinates[geom1.coordinates.length - 1], - }, - geom2 - ) - ) - endMatch = true; - if (endMatch == false) return false; - for (var i = 0; i < geom1.coordinates.length; i++) { - if ( - booleanPointOnLine( - Point(coordinates: geom1.coordinates[i]), - geom2, - ignoreEndVertices: true - ) - ) - return false; - } - return endMatch; - case MultiLineString: - var endMatch = false; - for (var i = 0; i < geom2.coordinates.length; i++) { - if ( - isPointOnLineEnd( - Point(coordinates: geom1.coordinates[0] ), - LineString(coordinates: geom2.coordinates[i] ) - ) - ) - endMatch = true; - if ( - isPointOnLineEnd( - Point( - coordinates: geom1.coordinates[geom1.coordinates.length - 1], - ), - LineString(coordinates: geom2.coordinates[i] ) - ) - ) - endMatch = true; - for (var ii = 0; ii < geom1.coordinates[i].length; ii++) { - if ( - booleanPointOnLine( - Point(coordinates: geom1.coordinates[ii] ), - LineString(coordinates: geom2.coordinates[i] ), - ignoreEndVertices: true - ) - ) - return false; - } + if (booleanPointInPolygon(geom2.coordinates[ii], + Polygon(coordinates: [geom1.coordinates[0][i]]), + ignoreBoundary: true)) { + return false; } - return endMatch; - case Polygon: - var foundTouchingPoint = false; - for (var i = 0; i < geom1.coordinates.length; i++) { + } + } + return foundTouchingPoint; + } else if (geom2 is MultiLineString) { + var foundTouchingPoint = false; + for (var i = 0; i < geom1.coordinates.length; i++) { + for (var ii = 0; ii < geom2.coordinates.length; ii++) { + for (var iii = 0; iii < geom2.coordinates[ii].length; iii++) { if (!foundTouchingPoint) { - if ( - booleanPointOnLine( - Point(coordinates: geom1.coordinates[i]), - LineString(coordinates: geom2.coordinates[0] ) - ) - ) + if (booleanPointOnLine( + Point( + coordinates: geom2.coordinates[ii][iii], + ), + LineString( + coordinates: geom1.coordinates[i][0], + ), + )) { foundTouchingPoint = true; - } - if ( - booleanPointInPolygon( - Point(coordinates: geom1.coordinates[i]), - geom2, - ignoreBoundary: true - ) - ) - return false; - } - return foundTouchingPoint; - case MultiPolygon: - var foundTouchingPoint = false; - for (var i = 0; i < geom1.coordinates.length; i++) { - for (var ii = 0; ii < geom2.coordinates.length; ii++) { - if (!foundTouchingPoint) { - if ( - booleanPointOnLine( - Point(coordinates: geom1.coordinates[i]), -LineString( - coordinates: geom2.coordinates[ii][0], - ) - ) - ) - foundTouchingPoint = true; } } - if ( - booleanPointInPolygon( - Point(coordinates: geom1.coordinates[i]), - geom2, - ignoreBoundary: true - ) - ) + if (booleanPointInPolygon(geom2.coordinates[ii][iii], + Polygon(coordinates: [geom1.coordinates[i][0]]), + ignoreBoundary: true)) { return false; - } - return foundTouchingPoint; - default: - throw Exception("feature2 " + type2 + " geometry not supported"); - } - case MultiLineString: - switch (type2) { - case Point: - for (var i = 0; i < geom1.coordinates.length; i++) { - if ( - isPointOnLineEnd(geom2, LineString( - coordinates: geom1.coordinates[i], - )) - ) - return true; - } - return false; - case MultiPoint: - var foundTouchingPoint = false; - for (var i = 0; i < geom1.coordinates.length; i++) { - for (var ii = 0; ii < geom2.coordinates.length; ii++) { - if (!foundTouchingPoint) { - if ( - isPointOnLineEnd( - Point(coordinates: geom2.coordinates[ii] ), - LineString(coordinates: geom1.coordinates[ii] ) - ) - ) - foundTouchingPoint = true; - } - if ( - booleanPointOnLine( - Point(coordinates: geom2.coordinates[ii] ), - LineString(coordinates: geom1.coordinates[ii] ), - ignoreEndVertices: true - ) - ) - return false; - } - } - return foundTouchingPoint; - case LineString: - var endMatch = false; - for (var i = 0; i < geom1.coordinates.length; i++) { - if ( - isPointOnLineEnd( - Point(coordinates: geom1.coordinates[i][0] ), - geom2 - ) - ) - endMatch = true; - if ( - isPointOnLineEnd( - Point( - coordinates: - geom1.coordinates[i][geom1.coordinates[i].length - 1], - }, - geom2 - ) - ) - endMatch = true; - for (var ii = 0; ii < geom2.coordinates.length; ii++) { - if ( - booleanPointOnLine( - Point(coordinates: geom2.coordinates[ii] ), - LineString(coordinates: geom1.coordinates[i] ), - ignoreEndVertices: true - ) - ) - return false; } } - return endMatch; - case MultiLineString: - var endMatch = false; - for (var i = 0; i < geom1.coordinates.length; i++) { - for (var ii = 0; ii < geom2.coordinates.length; ii++) { - if ( - isPointOnLineEnd( - Point(coordinates: geom1.coordinates[i][0] ), - LineString( coordinates: geom2.coordinates[ii] ) - ) - ) - endMatch = true; - if ( - isPointOnLineEnd( - Point( - coordinates: - geom1.coordinates[i][geom1.coordinates[i].length - 1], - }, - LineString( coordinates: geom2.coordinates[ii] ) - ) - ) - endMatch = true; - for (var iii = 0; iii < geom1.coordinates[i].length; iii++) { - if ( - booleanPointOnLine( - Point(coordinates: geom1.coordinates[i][iii] }, - LineString( coordinates: geom2.coordinates[ii] ), - ignoreEndVertices: true - ) - ) - return false; - } - } - } - return endMatch; - case Polygon: - var foundTouchingPoint = false; - for (var i = 0; i < geom1.coordinates.length; i++) { - for (var ii = 0; ii < geom1.coordinates.length; ii++) { - if (!foundTouchingPoint) { - if ( - booleanPointOnLine( - Point(coordinates: geom1.coordinates[i][ii] ), - LineString(coordinates: geom2.coordinates[0] ) - ) - ) - foundTouchingPoint = true; - } - if ( - booleanPointInPolygon( - Point(coordinates: geom1.coordinates[i][ii] ), - geom2, - ignoreBoundary: true - ) - ) - return false; + } + } + + return foundTouchingPoint; + } else if (geom2 is Polygon) { + var foundTouchingPoint = false; + for (var i = 0; i < geom1.coordinates[0].length; i++) { + for (var ii = 0; ii < geom1.coordinates[0][i].length; ii++) { + if (!foundTouchingPoint) { + if (booleanPointOnLine( + Point(coordinates: geom1.coordinates[0][i][ii]), + LineString(coordinates: geom2.coordinates[0]))) { + foundTouchingPoint = true; } } - return foundTouchingPoint; - case MultiPolygon: - var foundTouchingPoint = false; - for (var i = 0; i < geom2.coordinates[0].length; i++) { - for (var ii = 0; ii < geom1.coordinates.length; ii++) { - for (var iii = 0; iii < geom1.coordinates[ii].length; iii++) { - if (!foundTouchingPoint) { - if ( - booleanPointOnLine( - Point( - coordinates: geom1.coordinates[ii][iii], - }, - LineString( - coordinates: geom2.coordinates[0][i], - } - ) - ) - foundTouchingPoint = true; - } - if ( - booleanPointInPolygon( - Point(coordinates: geom1.coordinates[ii][iii] }, - Polygon( coordinates: [geom2.coordinates[0][i]] }, - ignoreBoundary: true - ) - ) - return false; - } - } + if (booleanPointInPolygon(geom1.coordinates[0][i][ii], geom2, + ignoreBoundary: true)) { + return false; } - return foundTouchingPoint; - default: - throw Exception("feature2 " + type2 + " geometry not supported"); + } } - case Polygon: - switch (type2) { - case Point: - for (var i = 0; i < geom1.coordinates.length; i++) { - if ( - booleanPointOnLine(geom2, LineString( - coordinates: geom1.coordinates[i], - )) - ) - return true; - } - return false; - case MultiPoint: - var foundTouchingPoint = false; - for (var i = 0; i < geom2.coordinates.length; i++) { + return foundTouchingPoint; + } else if (geom2 is MultiPolygon) { + var foundTouchingPoint = false; + for (var i = 0; i < geom1.coordinates[0].length; i++) { + for (var ii = 0; ii < geom2.coordinates[0].length; ii++) { + for (var iii = 0; iii < geom1.coordinates[0].length; iii++) { if (!foundTouchingPoint) { - if ( - booleanPointOnLine( - Point(coordinates: geom2.coordinates[i] ), - LineString(coordinates: geom1.coordinates[0] ) - ) - ) - foundTouchingPoint = true; - } - if ( - booleanPointInPolygon( - Point(coordinates: geom2.coordinates[i] ), - geom1, - ignoreBoundary: true - ) - ) - return false; - } - return foundTouchingPoint; - case LineString: - var foundTouchingPoint = false; - for (var i = 0; i < geom2.coordinates.length; i++) { - if (!foundTouchingPoint) { - if ( - booleanPointOnLine( - Point(coordinates: geom2.coordinates[i] ), - LineString(coordinates: geom1.coordinates[0] ) - ) - ) + if (booleanPointOnLine( + Point( + coordinates: geom1.coordinates[0][i][iii], + ), + LineString( + coordinates: geom2.coordinates[0][ii], + ), + )) { foundTouchingPoint = true; - } - if ( - booleanPointInPolygon( - Point(coordinates: geom2.coordinates[i] ), - geom1, - ignoreBoundary: true - ) - ) - return false; - } - return foundTouchingPoint; - case MultiLineString: - var foundTouchingPoint = false; - for (var i = 0; i < geom2.coordinates.length; i++) { - for (var ii = 0; ii < geom2.coordinates[i].length; ii++) { - if (!foundTouchingPoint) { - if ( - booleanPointOnLine( - Point(coordinates: geom2.coordinates[i][ii] ), - LineString(coordinates: geom1.coordinates[0] ) - ) - ) - foundTouchingPoint = true; } - if ( - booleanPointInPolygon( - Point(coordinates: geom2.coordinates[i][ii] ), - geom1, - ignoreBoundary: true - ) - ) - return false; } - } - return foundTouchingPoint; - case Polygon: - var foundTouchingPoint = false; - for (var i = 0; i < geom1.coordinates[0].length; i++) { - if (!foundTouchingPoint) { - if ( - booleanPointOnLine( - Point(coordinates: geom1.coordinates[0][i] ), - LineString(coordinates: geom2.coordinates[0] ) - ) - ) - foundTouchingPoint = true; - } - if ( - booleanPointInPolygon( - Point(coordinates: geom1.coordinates[0][i] ), - geom2, - ignoreBoundary: true - ) - ) + if (booleanPointInPolygon(geom1.coordinates[0][i][iii], + Polygon(coordinates: [geom2.coordinates[0][ii]]), + ignoreBoundary: true)) { return false; - } - return foundTouchingPoint; - case MultiPolygon: - var foundTouchingPoint = false; - for (var i = 0; i < geom2.coordinates[0].length; i++) { - for (var ii = 0; ii < geom1.coordinates[0].length; ii++) { - if (!foundTouchingPoint) { - if ( - booleanPointOnLine( - Point(coordinates: geom1.coordinates[0][ii] ), - LineString(coordinates: geom2.coordinates[0][i] ) - ) - ) - foundTouchingPoint = true; - } - if ( - booleanPointInPolygon( - Point(coordinates: geom1.coordinates[0][ii] ), - Polygon( coordinates: geom2.coordinates[0][i] ), - ignoreBoundary: true - ) - ) - return false; } } - return foundTouchingPoint; - default: - throw Exception("feature2 " + type2 + " geometry not supported"); + } } - case MultiPolygon: - switch (type2) { - case Point: - for (var i = 0; i < geom1.coordinates[0].length; i++) { - if ( - booleanPointOnLine(geom2, LineString( - coordinates: geom1.coordinates[0][i], - )) - ) - return true; - } - return false; - case MultiPoint: - var foundTouchingPoint = false; - for (var i = 0; i < geom1.coordinates[0].length; i++) { - for (var ii = 0; ii < geom2.coordinates.length; ii++) { - if (!foundTouchingPoint) { - if ( - booleanPointOnLine( - Point(coordinates: geom2.coordinates[ii] ), - LineString(coordinates: geom1.coordinates[0][i] ) - ) - ) - foundTouchingPoint = true; - } - if ( - booleanPointInPolygon( - Point(coordinates: geom2.coordinates[ii] ), - Polygon( coordinates: geom1.coordinates[0][i] ), - ignoreBoundary: true - ) - ) - return false; - } - } - return foundTouchingPoint; - case LineString: - var foundTouchingPoint = false; - for (var i = 0; i < geom1.coordinates[0].length; i++) { - for (var ii = 0; ii < geom2.coordinates.length; ii++) { - if (!foundTouchingPoint) { - if ( - booleanPointOnLine( - Point(coordinates: geom2.coordinates[ii] ), - LineString(coordinates: geom1.coordinates[0][i] ) - ) - ) - foundTouchingPoint = true; - } - if ( - booleanPointInPolygon( - Point(coordinates: geom2.coordinates[ii] ), - Polygon( coordinates: geom1.coordinates[0][i] ), - ignoreBoundary: true - ) - ) - return false; - } - } - return foundTouchingPoint; - case MultiLineString: - var foundTouchingPoint = false; - for (var i = 0; i < geom1.coordinates.length; i++) { - for (var ii = 0; ii < geom2.coordinates.length; ii++) { - for (var iii = 0; iii < geom2.coordinates[ii].length; iii++) { - if (!foundTouchingPoint) { - if ( - booleanPointOnLine( - Point( - coordinates: geom2.coordinates[ii][iii], - }, - LineString( - coordinates: geom1.coordinates[i][0], - } - ) - ) - foundTouchingPoint = true; - } - if ( - booleanPointInPolygon( - Point(coordinates: geom2.coordinates[ii][iii] }, - Polygon( coordinates: [geom1.coordinates[i][0]] }, - ignoreBoundary: true - ) - ) - return false; - } - } - } - - return foundTouchingPoint; - case Polygon: - var foundTouchingPoint = false; - for (var i = 0; i < geom1.coordinates[0].length; i++) { - for (var ii = 0; ii < geom1.coordinates[0][i].length; ii++) { - if (!foundTouchingPoint) { - if ( - booleanPointOnLine( - Point(coordinates: geom1.coordinates[0][i][ii] }, - LineString(coordinates: geom2.coordinates[0] ) - ) - ) - foundTouchingPoint = true; - } - if ( - booleanPointInPolygon( - Point(coordinates: geom1.coordinates[0][i][ii] }, - geom2, - ignoreBoundary: true - ) - ) - return false; - } - } - return foundTouchingPoint; - case MultiPolygon: - var foundTouchingPoint = false; - for (var i = 0; i < geom1.coordinates[0].length; i++) { - for (var ii = 0; ii < geom2.coordinates[0].length; ii++) { - for (var iii = 0; iii < geom1.coordinates[0].length; iii++) { - if (!foundTouchingPoint) { - if ( - booleanPointOnLine( - Point( - coordinates: geom1.coordinates[0][i][iii], - }, - LineString( - coordinates: geom2.coordinates[0][ii], - } - ) - ) - foundTouchingPoint = true; - } - if ( - booleanPointInPolygon( - Point( - coordinates: geom1.coordinates[0][i][iii], - }, - Polygon( coordinates: geom2.coordinates[0][ii] ), - ignoreBoundary: true - ) - ) - return false; - } - } - } - return foundTouchingPoint; - default: - throw Exception("feature2 " + type2 + " geometry not supported"); - } - default: - throw Exception("feature1 " + type1 + " geometry not supported"); + return foundTouchingPoint; + } else { + throw Exception("feature2 $geom2 geometry not supported"); + } + } else { + throw Exception("feature1 $geom1 geometry not supported"); } } -function isPointOnLineEnd(point: Point( line: LineString) { - if (compareCoords(line.coordinates[0], point.coordinates)) return true; - if ( - compareCoords( - line.coordinates[line.coordinates.length - 1], - point.coordinates - ) - ) +isPointOnLineEnd(Point point, LineString line) { + if (line.coordinates[0] == point.coordinates) return true; + if (line.coordinates[line.coordinates.length - 1] == point.coordinates) { return true; + } return false; } - -/** - * compareCoords - * - * @private - * @param {Position} pair1 point [x,y] - * @param {Position} pair2 point [x,y] - * @returns {boolean} true/false if coord pairs match - */ -function compareCoords(pair1: number[], pair2: number[]) { - return pair1[0] == pair2[0] && pair1[1] == pair2[1]; -} - -export default booleanTouches; */ diff --git a/test/booleans/touches_test.dart b/test/booleans/touches_test.dart index 04abfdda..6f033027 100644 --- a/test/booleans/touches_test.dart +++ b/test/booleans/touches_test.dart @@ -1,60 +1,49 @@ -/** - * const glob = require("glob"); -const path = require("path"); -const test = require("tape"); -const load = require("load-json-file"); -const shapely = require("boolean-shapely"); -const booleanJSTS = require("boolean-jsts"); -const touches = require("./index").default; +import 'dart:convert'; +import 'dart:io'; -test("turf-boolean-touches", (t) => { - // True Fixtures - glob - .sync(path.join(__dirname, "test", "true", "**", "*.geojson")) - .forEach((filepath) => { - const name = path.parse(filepath).name; - if (name.includes("skip")) return t.skip(name); +import 'package:test/test.dart'; +import 'package:turf/src/booleans/boolean_touches.dart'; +import 'package:turf/turf.dart'; - const geojson = load.sync(filepath); - const feature1 = geojson.features[0]; - const feature2 = geojson.features[1]; - const result = touches(feature1, feature2); - if (process.env.JSTS) - t.true( - booleanJSTS("touches", feature1, feature2), - "[true] JSTS - " + name - ); +main() { + group( + 'boolean-overlap', + () { + test( + "turf-boolean-overlap-trues", + () { + // True Fixtures + Directory dir = Directory('./test/examples/booleans/touches/true'); + for (var file in dir.listSync(recursive: true)) { + if (file is File && file.path.endsWith('.geojson')) { + var inSource = file.readAsStringSync(); + var inGeom = GeoJSONObject.fromJson(jsonDecode(inSource)); + var feature1 = (inGeom as FeatureCollection).features[0]; + var feature2 = inGeom.features[1]; + var result = booleanTouches(feature1, feature2); + expect(result, true); + } + } + }, + ); - if (process.env.SHAPELY) - shapely - .touches(feature1, feature2) - .then((result) => t.true(result, "[true] shapely - " + name)); - t.true(result, "[true] " + name); - }); - // False Fixtures - glob - .sync(path.join(__dirname, "test", "false", "**", "*.geojson")) - .forEach((filepath) => { - const name = path.parse(filepath).name; - if (name.includes("skip")) return t.skip(name); - - const geojson = load.sync(filepath); - const feature1 = geojson.features[0]; - const feature2 = geojson.features[1]; - const result = touches(feature1, feature2); - if (process.env.JSTS) - t.false( - booleanJSTS("touches", feature1, feature2), - "[false] JSTS - " + name - ); - - if (process.env.SHAPELY) - shapely - .touches(feature1, feature2) - .then((result) => t.false(result, "[false] shapely - " + name)); - t.false(result, "[false] " + name); - }); - t.end(); -}); - - */ \ No newline at end of file + test( + "turf-boolean-overlap-falses", + () { + // True Fixtures + Directory dir = Directory('./test/examples/booleans/touches/false'); + for (var file in dir.listSync(recursive: true)) { + if (file is File && file.path.endsWith('.geojson')) { + var inSource = file.readAsStringSync(); + var inGeom = GeoJSONObject.fromJson(jsonDecode(inSource)); + var feature1 = (inGeom as FeatureCollection).features[0]; + var feature2 = inGeom.features[1]; + var result = booleanTouches(feature1, feature2); + expect(result, false); + } + } + }, + ); + }, + ); +} From 55bbe3c9b3ca5d6a1eb4ab355a295858a53431fe Mon Sep 17 00:00:00 2001 From: armantorkzaban Date: Thu, 1 Sep 2022 13:26:46 +0200 Subject: [PATCH 61/82] valid - got stuck --- analysis_options.yaml | 5 +- lib/src/booleans/boolean_touches.dart | 3 - lib/src/booleans/boolean_valid.dart | 149 ++++++++++-------- test/booleans/valid_test.dart | 94 ++++++----- .../valid/false/MultiPoint/multipoint.geojson | 16 ++ ...multipoly-with-2-vertices-touching.geojson | 30 ++++ .../multipolygons-overlap.geojson | 39 +++++ .../MultiPolygon/not-enough-coords.geojson | 21 +++ .../booleans/valid/false/Point/point.geojson | 13 ++ .../false/Polygon/not-enough-coords.geojson | 19 +++ ...ygon-with-hole-2-vertices-touching.geojson | 28 ++++ .../Polygon/polygon-with-puncture.geojson | 24 +++ .../false/Polygon/polygon-with-spike.geojson | 22 +++ .../valid/true/LineString/linestring.geojson | 17 ++ .../MultiLineString/multilinestring.geojson | 23 +++ .../true/MultiPoint/multipoint-with-z.geojson | 16 ++ .../valid/true/MultiPoint/multipoint.geojson | 16 ++ .../MultiPolygon/multipolygon-touch.geojson | 39 +++++ .../multipolygon-with-hole.geojson | 39 +++++ .../true/MultiPolygon/multipolygon.geojson | 32 ++++ .../valid/true/Point/point-with-z.geojson | 13 ++ .../booleans/valid/true/Point/point.geojson | 13 ++ .../Polygon/polygon-internal-hole.geojson | 28 ++++ ...lygon-with-hole-1-vertice-touching.geojson | 28 ++++ .../valid/true/Polygon/polygon.geojson | 21 +++ 25 files changed, 636 insertions(+), 112 deletions(-) create mode 100644 test/examples/booleans/valid/false/MultiPoint/multipoint.geojson create mode 100644 test/examples/booleans/valid/false/MultiPolygon/multipoly-with-2-vertices-touching.geojson create mode 100644 test/examples/booleans/valid/false/MultiPolygon/multipolygons-overlap.geojson create mode 100644 test/examples/booleans/valid/false/MultiPolygon/not-enough-coords.geojson create mode 100644 test/examples/booleans/valid/false/Point/point.geojson create mode 100644 test/examples/booleans/valid/false/Polygon/not-enough-coords.geojson create mode 100644 test/examples/booleans/valid/false/Polygon/polygon-with-hole-2-vertices-touching.geojson create mode 100644 test/examples/booleans/valid/false/Polygon/polygon-with-puncture.geojson create mode 100644 test/examples/booleans/valid/false/Polygon/polygon-with-spike.geojson create mode 100644 test/examples/booleans/valid/true/LineString/linestring.geojson create mode 100644 test/examples/booleans/valid/true/MultiLineString/multilinestring.geojson create mode 100644 test/examples/booleans/valid/true/MultiPoint/multipoint-with-z.geojson create mode 100644 test/examples/booleans/valid/true/MultiPoint/multipoint.geojson create mode 100644 test/examples/booleans/valid/true/MultiPolygon/multipolygon-touch.geojson create mode 100644 test/examples/booleans/valid/true/MultiPolygon/multipolygon-with-hole.geojson create mode 100644 test/examples/booleans/valid/true/MultiPolygon/multipolygon.geojson create mode 100644 test/examples/booleans/valid/true/Point/point-with-z.geojson create mode 100644 test/examples/booleans/valid/true/Point/point.geojson create mode 100644 test/examples/booleans/valid/true/Polygon/polygon-internal-hole.geojson create mode 100644 test/examples/booleans/valid/true/Polygon/polygon-with-hole-1-vertice-touching.geojson create mode 100644 test/examples/booleans/valid/true/Polygon/polygon.geojson diff --git a/analysis_options.yaml b/analysis_options.yaml index 0b4c885d..95724bff 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -1,5 +1,8 @@ include: package:dartclub_lint/dart.yaml +linter: + rules: + always_declare_return_types: true analyzer: errors: - prefer_generic_function_type_aliases: error \ No newline at end of file + prefer_generic_function_type_aliases: error diff --git a/lib/src/booleans/boolean_touches.dart b/lib/src/booleans/boolean_touches.dart index 395ee5a2..debbd94e 100644 --- a/lib/src/booleans/boolean_touches.dart +++ b/lib/src/booleans/boolean_touches.dart @@ -1,7 +1,4 @@ -import 'package:turf/meta.dart'; - import '../../helpers.dart'; -import '../invariant.dart'; import 'boolean_point_in_polygon.dart'; import 'boolean_point_on_line.dart'; diff --git a/lib/src/booleans/boolean_valid.dart b/lib/src/booleans/boolean_valid.dart index 3a156dd2..04bdb7f8 100644 --- a/lib/src/booleans/boolean_valid.dart +++ b/lib/src/booleans/boolean_valid.dart @@ -1,8 +1,39 @@ +import 'package:turf/src/booleans/boolean_disjoint.dart'; +import 'package:turf/src/booleans/boolean_point_on_line.dart'; +import 'package:turf/src/meta/extensions.dart'; + import '../../helpers.dart'; -import '../invariant.dart'; import '../line_intersect.dart'; import 'boolean_crosses.dart'; -import 'boolean_disjoint.dart'; + +bool checkRingsClose(List geom) { + return (geom[0].lng == geom[geom.length - 1].lng || + geom[0].lat == geom[geom.length - 1].lat); +} + +bool checkRingsForSpikesPunctures(List geom) { + for (var i = 0; i < geom.length - 1; i++) { + var point = Point(coordinates: geom[i]); + for (var ii = i + 1; ii < geom.length - 2; ii++) { + var seg = [geom[ii], geom[ii + 1]]; + if (booleanPointOnLine(point, LineString(coordinates: seg))) return true; + } + } + return false; +} + +bool checkPolygonAgainstOthers( + List> poly, List>> geom, int index) { + var polyToCheck = Polygon(coordinates: poly); + for (var i = index + 1; i < geom.length; i++) { + if (!booleanDisjoint(polyToCheck, Polygon(coordinates: geom[i]))) { + if (booleanCrosses(polyToCheck, LineString(coordinates: geom[i][0]))) { + return false; + } + } + } + return true; +} /// booleanValid checks if the geometry is a valid according to the OGC Simple Feature Specification. /// Take a [Feature] or a [GeometryType] @@ -14,48 +45,60 @@ import 'boolean_disjoint.dart'; /// booleanValid(line); // => true /// booleanValid({foo: "bar"}); // => false /// ``` -booleanValid(GeoJSONObject feature) { - // // Automatic False - // if (!feature.type) return false; - +bool booleanValid(GeoJSONObject feature) { + print(feature); // Parse GeoJSON - var geom = getGeom(feature); - var type = geom.type; - var coords = geom.coordinates; + if (feature is FeatureCollection) { + for (Feature f in feature.features) { + booleanValid(f); + } + } else if (feature is GeometryCollection) { + for (GeometryObject g in feature.geometries) { + booleanValid(g); + } + } else { + var geom = feature is Feature ? feature.geometry : feature; - switch (type) { - case Point: - return coords.length > 1; - case MultiPoint: - for (var i = 0; i < coords.length; i++) { - if (coords[i].length < 2) return false; + if (geom is Point) { + if (!(geom.coordinates.length >= 2 && geom.coordinates.length <= 3)) { + return false; } - return true; - case LineString: - if (coords.length < 2) return false; - for (var i = 0; i < coords.length; i++) { - if (coords[i].length < 2) return false; + } else if (geom is MultiPoint) { + if (geom.coordinates.length < 2) { + return false; + } + for (Position p in geom.coordinates) { + booleanValid(Point(coordinates: p)); } - return true; - case MultiLineString: - if (coords.length < 2) return false; - for (var i = 0; i < coords.length; i++) { - if (coords[i].length < 2) return false; + } else if (geom is LineString) { + if (geom.coordinates.length < 2) return false; + for (Position p in geom.coordinates) { + booleanValid(Point(coordinates: p)); + } + } else if (geom is MultiLineString) { + if (geom.coordinates.length < 2) return false; + for (var i = 0; i < geom.coordinates.length; i++) { + booleanValid(LineString(coordinates: geom.coordinates[i])); } - return true; - case Polygon: + } else if (geom is Polygon) { + geom.coordEach((Position? cCoord, _, __, ___, ____) { + booleanValid(Point(coordinates: cCoord!)); + }); for (var i = 0; i < geom.coordinates.length; i++) { - if (coords[i].length < 4) return false; - if (!checkRingsClose(coords[i])) return false; - if (checkRingsForSpikesPunctures(coords[i])) return false; + if (geom.coordinates[i].length < 4) return false; + if (!checkRingsClose(geom.coordinates[i])) return false; + if (checkRingsForSpikesPunctures(geom.coordinates[i])) return false; if (i > 0) { - if (lineIntersect(Polygon(coordinates: [coords[0]]), - Polygon(coordinates: [coords[i]])).features.length > - 1) return false; + if (lineIntersect( + Polygon(coordinates: [geom.coordinates[0]]), + Polygon(coordinates: [geom.coordinates[i]]), + ).features.length > + 1) { + return false; + } } } - return true; - case MultiPolygon: + } else if (geom is MultiPolygon) { for (var i = 0; i < geom.coordinates.length; i++) { var poly = geom.coordinates[i]; @@ -71,42 +114,12 @@ booleanValid(GeoJSONObject feature) { if (ii > 0) { if (lineIntersect(Polygon(coordinates: [poly[0]]), Polygon(coordinates: [poly[ii]])).features.length > - 1) { - return false; - } + 1) return false; } } } - return true; - default: - return false; - } -} - -checkRingsClose(List geom) { - return (geom[0][0] == geom[geom.length - 1][0] || - geom[0][1] == geom[geom.length - 1][1]); -} - -checkRingsForSpikesPunctures(List geom) { - for (var i = 0; i < geom.length - 1; i++) { - var point = Point(coordinates: geom[i]); - for (var ii = i + 1; ii < geom.length - 2; ii++) { - var seg = [geom[ii], geom[ii + 1]]; - if (isPointOnLine(LineString(coordinates: seg), point)) return true; - } - } - return false; -} - -checkPolygonAgainstOthers( - List> poly, List>> geom, int index) { - var polyToCheck = Polygon(coordinates: poly); - for (var i = index + 1; i < geom.length; i++) { - if (!booleanDisjoint(polyToCheck, Polygon(coordinates: geom[i]))) { - if (booleanCrosses(polyToCheck, LineString(coordinates: geom[i][0]))) { - return false; - } + } else { + print('is strange $geom'); } } return true; diff --git a/test/booleans/valid_test.dart b/test/booleans/valid_test.dart index 973bed54..924c5a58 100644 --- a/test/booleans/valid_test.dart +++ b/test/booleans/valid_test.dart @@ -1,42 +1,56 @@ -// const glob = require("glob"); -// const path = require("path"); -// const test = require("tape"); -// const load = require("load-json-file"); -// // const shapely = require('boolean-shapely'); -// const isValid = require("./index").default; +import 'dart:convert'; +import 'dart:io'; +import 'dart:math'; -// test("turf-boolean-valid", (t) => { -// // True Fixtures -// glob -// .sync(path.join(__dirname, "test", "true", "**", "*.geojson")) -// .forEach((filepath) => { -// const name = path.parse(filepath).name; +import 'package:analyzer/dart/ast/ast.dart'; +import 'package:test/test.dart'; +import 'package:turf/src/booleans/boolean_valid.dart'; +import 'package:turf/turf.dart'; -// if (name === "multipolygon-touch") return t.skip("multipolygon-touch"); - -// const geojson = load.sync(filepath); -// const feature1 = geojson.features[0]; -// const result = isValid(feature1); - -// // if (process.env.SHAPELY) shapely.contains(feature1).then(result => t.true(result, '[true] shapely - ' + name)); -// t.true(result, "[true] " + name); -// }); -// // False Fixtures -// glob -// .sync(path.join(__dirname, "test", "false", "**", "*.geojson")) -// .forEach((filepath) => { -// const name = path.parse(filepath).name; -// const geojson = load.sync(filepath); -// const feature1 = geojson.features[0]; -// const result = isValid(feature1); - -// // if (process.env.SHAPELY) shapely.contains(feature1, feature2).then(result => t.false(result, '[false] shapely - ' + name)); -// t.false(result, "[false] " + name); -// }); -// t.end(); -// }); - -// test("turf-boolean-valid -- obvious fails", (t) => { -// t.false(isValid({ foo: "bar" })); -// t.end(); -// }); +main() { + group( + 'boolean-valid', + () { + // Directory dir = Directory('./test/examples/booleans/valid/true'); + // for (var file in dir.listSync(recursive: true)) { + // test( + // file.path, + // () { + // // True Fixtures + // if (file is File && file.path.endsWith('.geojson')) { + // var inSource = file.readAsStringSync(); + // var inGeom = GeoJSONObject.fromJson(jsonDecode(inSource)); + // var result = booleanValid(inGeom); + // expect(result, true); + // } + // }, + // ); + // } + Directory dir1 = Directory('./test/examples/booleans/valid/false'); + for (var file in dir1.listSync(recursive: true)) { + test( + file.path, + () { + // False Fixtures + if (file is File && file.path.endsWith('.geojson')) { + var inSource = file.readAsStringSync(); + try { + var inGeom = GeoJSONObject.fromJson(jsonDecode(inSource)); + } catch (e) { + if (e is AssertionError) { + print('assertion worked in case of ${file.path}'); + } + } finally { + if (!e.toString().contains('Failed assersion')) { + var inGeom = GeoJSONObject.fromJson(jsonDecode(inSource)); + var result = booleanValid(inGeom); + expect(result, false); + } + } + } + }, + ); + } + }, + ); +} diff --git a/test/examples/booleans/valid/false/MultiPoint/multipoint.geojson b/test/examples/booleans/valid/false/MultiPoint/multipoint.geojson new file mode 100644 index 00000000..ed827478 --- /dev/null +++ b/test/examples/booleans/valid/false/MultiPoint/multipoint.geojson @@ -0,0 +1,16 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPoint", + "coordinates": [ + [2.7575683593749996], + [2.5575683593749996, 2.8113711933311403] + ] + } + } + ] +} diff --git a/test/examples/booleans/valid/false/MultiPolygon/multipoly-with-2-vertices-touching.geojson b/test/examples/booleans/valid/false/MultiPolygon/multipoly-with-2-vertices-touching.geojson new file mode 100644 index 00000000..ad3cb34d --- /dev/null +++ b/test/examples/booleans/valid/false/MultiPolygon/multipoly-with-2-vertices-touching.geojson @@ -0,0 +1,30 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + [ + [ + [-0.703125, 24.84656534821976], + [11.25, 24.84656534821976], + [11.25, 31.353636941500987], + [-0.703125, 31.353636941500987], + [-0.703125, 24.84656534821976] + ], + [ + [3.076171875, 27.254629577800063], + [6.8115234375, 27.254629577800063], + [6.8115234375, 31.353636941500987], + [-0.703125, 29.916852233070173], + [3.076171875, 27.254629577800063] + ] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/valid/false/MultiPolygon/multipolygons-overlap.geojson b/test/examples/booleans/valid/false/MultiPolygon/multipolygons-overlap.geojson new file mode 100644 index 00000000..196b1f9a --- /dev/null +++ b/test/examples/booleans/valid/false/MultiPolygon/multipolygons-overlap.geojson @@ -0,0 +1,39 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + [ + [ + [-0.703125, 24.84656534821976], + [11.25, 24.84656534821976], + [11.25, 31.353636941500987], + [-0.703125, 31.353636941500987], + [-0.703125, 24.84656534821976] + ], + [ + [3.076171875, 27.254629577800063], + [6.8115234375, 27.254629577800063], + [6.8115234375, 29.916852233070173], + [3.076171875, 29.916852233070173], + [3.076171875, 27.254629577800063] + ] + ], + [ + [ + [5.80078125, 33.100745405144245], + [8.4814453125, 30.100745405144245], + [8.4814453125, 34.397844946449865], + [5.80078125, 34.397844946449865], + [5.80078125, 33.100745405144245] + ] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/valid/false/MultiPolygon/not-enough-coords.geojson b/test/examples/booleans/valid/false/MultiPolygon/not-enough-coords.geojson new file mode 100644 index 00000000..e2e15631 --- /dev/null +++ b/test/examples/booleans/valid/false/MultiPolygon/not-enough-coords.geojson @@ -0,0 +1,21 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + [ + [ + [-0.703125, 24.84656534821976], + [11.25, 24.84656534821976], + [-0.703125, 24.84656534821976] + ] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/valid/false/Point/point.geojson b/test/examples/booleans/valid/false/Point/point.geojson new file mode 100644 index 00000000..7e46c4f8 --- /dev/null +++ b/test/examples/booleans/valid/false/Point/point.geojson @@ -0,0 +1,13 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [2.7575683593749996] + } + } + ] +} diff --git a/test/examples/booleans/valid/false/Polygon/not-enough-coords.geojson b/test/examples/booleans/valid/false/Polygon/not-enough-coords.geojson new file mode 100644 index 00000000..ba0568d2 --- /dev/null +++ b/test/examples/booleans/valid/false/Polygon/not-enough-coords.geojson @@ -0,0 +1,19 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [-0.703125, 24.84656534821976], + [11.25, 24.84656534821976], + [-0.703125, 24.84656534821976] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/valid/false/Polygon/polygon-with-hole-2-vertices-touching.geojson b/test/examples/booleans/valid/false/Polygon/polygon-with-hole-2-vertices-touching.geojson new file mode 100644 index 00000000..38eff311 --- /dev/null +++ b/test/examples/booleans/valid/false/Polygon/polygon-with-hole-2-vertices-touching.geojson @@ -0,0 +1,28 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [-0.703125, 24.84656534821976], + [11.25, 24.84656534821976], + [11.25, 31.353636941500987], + [-0.703125, 31.353636941500987], + [-0.703125, 24.84656534821976] + ], + [ + [3.076171875, 27.254629577800063], + [6.8115234375, 27.254629577800063], + [6.8115234375, 31.353636941500987], + [-0.703125, 29.916852233070173], + [3.076171875, 27.254629577800063] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/valid/false/Polygon/polygon-with-puncture.geojson b/test/examples/booleans/valid/false/Polygon/polygon-with-puncture.geojson new file mode 100644 index 00000000..9266a1fb --- /dev/null +++ b/test/examples/booleans/valid/false/Polygon/polygon-with-puncture.geojson @@ -0,0 +1,24 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [-0.703125, 24.84656534821976], + [10, 24.84656534821976], + [10, 26.84656534821976], + [10, 24.84656534821976], + [11.25, 24.84656534821976], + [11.25, 31.353636941500987], + [-0.703125, 31.353636941500987], + [-0.703125, 24.84656534821976] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/valid/false/Polygon/polygon-with-spike.geojson b/test/examples/booleans/valid/false/Polygon/polygon-with-spike.geojson new file mode 100644 index 00000000..101fac28 --- /dev/null +++ b/test/examples/booleans/valid/false/Polygon/polygon-with-spike.geojson @@ -0,0 +1,22 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [-0.703125, 24.84656534821976], + [11.25, 24.84656534821976], + [11.25, 22], + [11.25, 31.353636941500987], + [-0.703125, 31.353636941500987], + [-0.703125, 24.84656534821976] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/valid/true/LineString/linestring.geojson b/test/examples/booleans/valid/true/LineString/linestring.geojson new file mode 100644 index 00000000..75a1b7a1 --- /dev/null +++ b/test/examples/booleans/valid/true/LineString/linestring.geojson @@ -0,0 +1,17 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [1.285400390625, 4.214943141390651], + [0.472412109375, 2.9649843693339677], + [1.900634765625, 2.1857489471296665] + ] + } + } + ] +} diff --git a/test/examples/booleans/valid/true/MultiLineString/multilinestring.geojson b/test/examples/booleans/valid/true/MultiLineString/multilinestring.geojson new file mode 100644 index 00000000..4af98e8e --- /dev/null +++ b/test/examples/booleans/valid/true/MultiLineString/multilinestring.geojson @@ -0,0 +1,23 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiLineString", + "coordinates": [ + [ + [1.285400390625, 4.214943141390651], + [0.472412109375, 2.9649843693339677], + [1.900634765625, 2.1857489471296665] + ], + [ + [2.076416015625, 4.07249425916745], + [3.2080078125, 2.5370123584000273] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/valid/true/MultiPoint/multipoint-with-z.geojson b/test/examples/booleans/valid/true/MultiPoint/multipoint-with-z.geojson new file mode 100644 index 00000000..12c5a939 --- /dev/null +++ b/test/examples/booleans/valid/true/MultiPoint/multipoint-with-z.geojson @@ -0,0 +1,16 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPoint", + "coordinates": [ + [2.7575683593749996, 2.8113711933311403, 1], + [2.5575683593749996, 2.8113711933311403] + ] + } + } + ] +} diff --git a/test/examples/booleans/valid/true/MultiPoint/multipoint.geojson b/test/examples/booleans/valid/true/MultiPoint/multipoint.geojson new file mode 100644 index 00000000..785542e0 --- /dev/null +++ b/test/examples/booleans/valid/true/MultiPoint/multipoint.geojson @@ -0,0 +1,16 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPoint", + "coordinates": [ + [2.7575683593749996, 2.8113711933311403], + [2.5575683593749996, 2.8113711933311403] + ] + } + } + ] +} diff --git a/test/examples/booleans/valid/true/MultiPolygon/multipolygon-touch.geojson b/test/examples/booleans/valid/true/MultiPolygon/multipolygon-touch.geojson new file mode 100644 index 00000000..ff290c16 --- /dev/null +++ b/test/examples/booleans/valid/true/MultiPolygon/multipolygon-touch.geojson @@ -0,0 +1,39 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + [ + [ + [-0.703, 24.846], + [11.25, 24.846], + [11.25, 31.353], + [-0.703, 31.353], + [-0.703, 24.846] + ], + [ + [3.076, 27.254], + [6.811, 27.254], + [6.811, 29.916], + [3.076, 29.916], + [3.076, 27.254] + ] + ], + [ + [ + [5.8, 33.1], + [8.481, 31.353], + [8.481, 34.397], + [5.8, 34.397], + [5.8, 33.1] + ] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/valid/true/MultiPolygon/multipolygon-with-hole.geojson b/test/examples/booleans/valid/true/MultiPolygon/multipolygon-with-hole.geojson new file mode 100644 index 00000000..72f4ce17 --- /dev/null +++ b/test/examples/booleans/valid/true/MultiPolygon/multipolygon-with-hole.geojson @@ -0,0 +1,39 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + [ + [ + [-0.703125, 24.84656534821976], + [11.25, 24.84656534821976], + [11.25, 31.353636941500987], + [-0.703125, 31.353636941500987], + [-0.703125, 24.84656534821976] + ], + [ + [3.076171875, 27.254629577800063], + [6.8115234375, 27.254629577800063], + [6.8115234375, 29.916852233070173], + [3.076171875, 29.916852233070173], + [3.076171875, 27.254629577800063] + ] + ], + [ + [ + [5.80078125, 33.100745405144245], + [8.4814453125, 33.100745405144245], + [8.4814453125, 34.397844946449865], + [5.80078125, 34.397844946449865], + [5.80078125, 33.100745405144245] + ] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/valid/true/MultiPolygon/multipolygon.geojson b/test/examples/booleans/valid/true/MultiPolygon/multipolygon.geojson new file mode 100644 index 00000000..e4ce0e33 --- /dev/null +++ b/test/examples/booleans/valid/true/MultiPolygon/multipolygon.geojson @@ -0,0 +1,32 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + [ + [ + [-0.703125, 24.84656534821976], + [11.25, 24.84656534821976], + [11.25, 31.353636941500987], + [-0.703125, 31.353636941500987], + [-0.703125, 24.84656534821976] + ] + ], + [ + [ + [5.80078125, 33.100745405144245], + [8.4814453125, 33.100745405144245], + [8.4814453125, 34.397844946449865], + [5.80078125, 34.397844946449865], + [5.80078125, 33.100745405144245] + ] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/valid/true/Point/point-with-z.geojson b/test/examples/booleans/valid/true/Point/point-with-z.geojson new file mode 100644 index 00000000..3082c2e9 --- /dev/null +++ b/test/examples/booleans/valid/true/Point/point-with-z.geojson @@ -0,0 +1,13 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [2.7575683593749996, 2.8113711933311403, 1] + } + } + ] +} diff --git a/test/examples/booleans/valid/true/Point/point.geojson b/test/examples/booleans/valid/true/Point/point.geojson new file mode 100644 index 00000000..430ab19c --- /dev/null +++ b/test/examples/booleans/valid/true/Point/point.geojson @@ -0,0 +1,13 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [2.7575683593749996, 2.8113711933311403] + } + } + ] +} diff --git a/test/examples/booleans/valid/true/Polygon/polygon-internal-hole.geojson b/test/examples/booleans/valid/true/Polygon/polygon-internal-hole.geojson new file mode 100644 index 00000000..788c54a3 --- /dev/null +++ b/test/examples/booleans/valid/true/Polygon/polygon-internal-hole.geojson @@ -0,0 +1,28 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [-0.703125, 24.84656534821976], + [11.25, 24.84656534821976], + [11.25, 31.353636941500987], + [-0.703125, 31.353636941500987], + [-0.703125, 24.84656534821976] + ], + [ + [3.076171875, 27.254629577800063], + [6.8115234375, 27.254629577800063], + [6.8115234375, 29.916852233070173], + [3.076171875, 29.916852233070173], + [3.076171875, 27.254629577800063] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/valid/true/Polygon/polygon-with-hole-1-vertice-touching.geojson b/test/examples/booleans/valid/true/Polygon/polygon-with-hole-1-vertice-touching.geojson new file mode 100644 index 00000000..6bf8b239 --- /dev/null +++ b/test/examples/booleans/valid/true/Polygon/polygon-with-hole-1-vertice-touching.geojson @@ -0,0 +1,28 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [-0.703125, 24.84656534821976], + [11.25, 24.84656534821976], + [11.25, 31.353636941500987], + [-0.703125, 31.353636941500987], + [-0.703125, 24.84656534821976] + ], + [ + [3.076171875, 27.254629577800063], + [6.8115234375, 27.254629577800063], + [6.8115234375, 29.916852233070173], + [-0.703125, 29.916852233070173], + [3.076171875, 27.254629577800063] + ] + ] + } + } + ] +} diff --git a/test/examples/booleans/valid/true/Polygon/polygon.geojson b/test/examples/booleans/valid/true/Polygon/polygon.geojson new file mode 100644 index 00000000..ea06e0a0 --- /dev/null +++ b/test/examples/booleans/valid/true/Polygon/polygon.geojson @@ -0,0 +1,21 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [-0.703125, 24.84656534821976], + [11.25, 24.84656534821976], + [11.25, 31.353636941500987], + [-0.703125, 31.353636941500987], + [-0.703125, 24.84656534821976] + ] + ] + } + } + ] +} From 01e860b6284013188dc77e96251d5076230fec74 Mon Sep 17 00:00:00 2001 From: armantorkzaban Date: Thu, 1 Sep 2022 14:23:19 +0200 Subject: [PATCH 62/82] progress on within --- lib/src/booleans/boolean_disjoint.dart | 2 +- lib/src/booleans/boolean_intersect.dart | 10 +- lib/src/booleans/boolean_touches.dart | 2 +- lib/src/booleans/boolean_within.dart | 195 +++++++++++------------- test/booleans/equal_test.dart | 2 +- test/booleans/within_test.dart | 102 ++++++------- 6 files changed, 148 insertions(+), 165 deletions(-) diff --git a/lib/src/booleans/boolean_disjoint.dart b/lib/src/booleans/boolean_disjoint.dart index d610d2d9..b0257757 100644 --- a/lib/src/booleans/boolean_disjoint.dart +++ b/lib/src/booleans/boolean_disjoint.dart @@ -103,7 +103,7 @@ bool isLineInPoly(Polygon polygon, LineString lineString) { /// Is [Polygon] (geom1) in [Polygon] (geom2) /// Only takes into account outer rings /// See http://stackoverflow.com/a/4833823/1979085 -_isPolyInPoly(Polygon feature1, Polygon feature2) { +bool _isPolyInPoly(Polygon feature1, Polygon feature2) { for (var coord1 in feature1.coordinates[0]) { if (booleanPointInPolygon(coord1, feature2)) { return true; diff --git a/lib/src/booleans/boolean_intersect.dart b/lib/src/booleans/boolean_intersect.dart index 5b72b2bf..f025490d 100644 --- a/lib/src/booleans/boolean_intersect.dart +++ b/lib/src/booleans/boolean_intersect.dart @@ -12,21 +12,21 @@ import 'boolean_disjoint.dart'; /// booleanIntersects(line, point); /// ``` //=true -booleanIntersects(GeoJSONObject feature1, GeoJSONObject feature2) { - var bool = false; +bool booleanIntersects(GeoJSONObject feature1, GeoJSONObject feature2) { + var result = false; flattenEach( feature1, (flatten1, featureIndex, multiFeatureIndex) { flattenEach( feature2, (flatten2, featureIndex, multiFeatureIndex) { - if (bool) { + if (result) { return true; } - bool = !booleanDisjoint(flatten1, flatten2); + result = !booleanDisjoint(flatten1, flatten2); }, ); }, ); - return bool; + return result; } diff --git a/lib/src/booleans/boolean_touches.dart b/lib/src/booleans/boolean_touches.dart index debbd94e..48febf27 100644 --- a/lib/src/booleans/boolean_touches.dart +++ b/lib/src/booleans/boolean_touches.dart @@ -580,7 +580,7 @@ bool booleanTouches(GeoJSONObject feature1, GeoJSONObject feature2) { } } -isPointOnLineEnd(Point point, LineString line) { +bool isPointOnLineEnd(Point point, LineString line) { if (line.coordinates[0] == point.coordinates) return true; if (line.coordinates[line.coordinates.length - 1] == point.coordinates) { return true; diff --git a/lib/src/booleans/boolean_within.dart b/lib/src/booleans/boolean_within.dart index d38013a4..f18b7097 100644 --- a/lib/src/booleans/boolean_within.dart +++ b/lib/src/booleans/boolean_within.dart @@ -1,85 +1,95 @@ import 'package:turf/bbox.dart'; import '../../helpers.dart'; -import '../invariant.dart'; import 'boolean_point_in_polygon.dart'; import 'boolean_point_on_line.dart'; -/** - * Boolean-within returns true if the first geometry is completely within the second geometry. - * The interiors of both geometries must intersect and, the interior and boundary of the primary (geometry a) - * must not intersect the exterior of the secondary (geometry b). - * Boolean-within returns the exact opposite result of the `@turf/boolean-contains`. - * - * @name booleanWithin - * @param {Geometry|Feature} feature1 GeoJSON Feature or Geometry - * @param {Geometry|Feature} feature2 GeoJSON Feature or Geometry - * @returns {boolean} true/false - * @example - * var line = turf.lineString([[1, 1], [1, 2], [1, 3], [1, 4]]); - * var point = turf.point([1, 2]); - * - * turf.booleanWithin(point, line); - * //=true - */ +/// Boolean-within returns true if the first geometry is completely within the second geometry. +/// The interiors of both geometries must intersect and, the interior and boundary of the primary (geometry a) +/// must not intersect the exterior of the secondary (geometry b). +/// Boolean-within returns the exact opposite result of the `@turf/boolean-contains`. +/// @name booleanWithin +/// @param {Geometry|Feature} feature1 GeoJSON Feature or Geometry +/// @param {Geometry|Feature} feature2 GeoJSON Feature or Geometry +/// @returns {boolean} true/false +/// @example +/// var line = turf.lineString([[1, 1], [1, 2], [1, 3], [1, 4]]); +/// var point = turf.point([1, 2]); +/// turf.booleanWithin(point, line); +/// //=true bool booleanWithin(GeoJSONObject feature1, GeoJSONObject feature2) { - var geom1 = getGeom(feature1); - var geom2 = getGeom(feature2); - var type1 = geom1.type; - var type2 = geom2.type; + var geom1 = feature1 is Feature ? feature1.geometry : feature1; + var geom2 = feature2 is Feature ? feature2.geometry : feature2; - switch (type1) { - case Point: - switch (type2) { - case MultiPoint: - return isPointInMultiPoint(geom1, geom2); - case LineString: - return booleanPointOnLine(geom1, geom2, ignoreEndVertices: true); - case Polygon: - case MultiPolygon: - return booleanPointInPolygon(geom1, geom2, ignoreBoundary: true); - default: - throw Exception("feature2 " + type2 + " geometry not supported"); - } - case MultiPoint: - switch (type2) { - case MultiPoint: - return isMultiPointInMultiPoint(geom1, geom2); - case LineString: - return isMultiPointOnLine(geom1, geom2); - case Polygon: - case MultiPolygon: - return isMultiPointInPoly(geom1, geom2); - default: - throw Exception("feature2 " + type2 + " geometry not supported"); + if (geom1 is Point) { + if (geom2 is MultiPoint) { + return isPointInMultiPoint(geom1, geom2); + } + if (geom2 is LineString) { + return booleanPointOnLine(geom1, geom2, ignoreEndVertices: true); + } + if (geom2 is Polygon || geom2 is MultiPolygon) { + return booleanPointInPolygon(geom1.coordinates, geom2!, + ignoreBoundary: true); + } else { + throw Exception("feature2 $geom2 geometry not supported"); + } + } else if (geom1 is MultiPoint) { + if (geom2 is MultiPoint) { + return isMultiPointInMultiPoint(geom1, geom2); + } else if (geom2 is LineString) { + return isMultiPointOnLine(geom1, geom2); + } else if (geom2 is Polygon) { + return isMultiPointInPoly(geom1, geom2); + } else if (geom2 is MultiPolygon) { + bool result = false; + for (var p in geom2.coordinates) { + if (isMultiPointInPoly(geom1, Polygon(coordinates: p))) { + result = true; + } } - case LineString: - switch (type2) { - case LineString: - return isLineOnLine(geom1, geom2); - case Polygon: - case MultiPolygon: - return isLineInPoly(geom1, geom2); - default: - throw Exception("feature2 " + type2 + " geometry not supported"); + return result; + } else { + throw Exception("feature2 $geom2 geometry not supported"); + } + } else if (geom1 is LineString) { + if (geom2 is LineString) { + return isLineOnLine(geom1, geom2); + } else if (geom2 is Polygon) { + return isLineInPoly(geom1, geom2); + } else if (geom2 is MultiPolygon) { + bool result = false; + for (var p in geom2.coordinates) { + if (isLineInPoly(geom1, Polygon(coordinates: p))) { + result = true; + } } - case Polygon: - switch (type2) { - case Polygon: - case MultiPolygon: - return isPolyInPoly(geom1, geom2); - default: - throw Exception("feature2 " + type2 + " geometry not supported"); + return result; + } else { + throw Exception("feature2: $geom2 geometry not supported"); + } + } else if (geom1 is Polygon) { + if (geom2 is Polygon) { + return isPolyInPoly(geom1, geom2); + } else if (geom2 is MultiPolygon) { + bool result = false; + for (var p in geom2.coordinates) { + if (isPolyInPoly(geom1, Polygon(coordinates: p))) { + result = true; + } } - default: - throw Exception("feature1 " + type1 + " geometry not supported"); + return result; + } else { + throw Exception("feature2 $geom2 geometry not supported"); + } + } else { + throw Exception("feature1 $geom1 geometry not supported"); } } -isPointInMultiPoint(Point point, MultiPoint multiPoint) { - var i; +bool isPointInMultiPoint(Point point, MultiPoint multiPoint) { var output = false; - for (i = 0; i < multiPoint.coordinates.length; i++) { + for (var i = 0; i < multiPoint.coordinates.length; i++) { if (compareCoords(multiPoint.coordinates[i], point.coordinates)) { output = true; break; @@ -88,7 +98,7 @@ isPointInMultiPoint(Point point, MultiPoint multiPoint) { return output; } -isMultiPointInMultiPoint(MultiPoint multiPoint1, MultiPoint multiPoint2) { +bool isMultiPointInMultiPoint(MultiPoint multiPoint1, MultiPoint multiPoint2) { for (var i = 0; i < multiPoint1.coordinates.length; i++) { var anyMatch = false; for (var i2 = 0; i2 < multiPoint2.coordinates.length; i2++) { @@ -104,7 +114,7 @@ isMultiPointInMultiPoint(MultiPoint multiPoint1, MultiPoint multiPoint2) { return true; } -isMultiPointOnLine(MultiPoint multiPoint, LineString lineString) { +bool isMultiPointOnLine(MultiPoint multiPoint, LineString lineString) { var foundInsidePoint = false; for (var i = 0; i < multiPoint.coordinates.length; i++) { @@ -121,7 +131,7 @@ isMultiPointOnLine(MultiPoint multiPoint, LineString lineString) { return foundInsidePoint; } -isMultiPointInPoly(MultiPoint multiPoint, Polygon polygon) { +bool isMultiPointInPoly(MultiPoint multiPoint, Polygon polygon) { var output = true; var oneInside = false; var isInside = false; @@ -142,7 +152,7 @@ isMultiPointInPoly(MultiPoint multiPoint, Polygon polygon) { return output && isInside; } -isLineOnLine(LineString lineString1, LineString lineString2) { +bool isLineOnLine(LineString lineString1, LineString lineString2) { for (var i = 0; i < lineString1.coordinates.length; i++) { if (!booleanPointOnLine( Point(coordinates: lineString1.coordinates[i]), lineString2)) { @@ -152,7 +162,7 @@ isLineOnLine(LineString lineString1, LineString lineString2) { return true; } -isLineInPoly(LineString linestring, Polygon polygon) { +bool isLineInPoly(LineString linestring, Polygon polygon) { var polyBbox = bbox(polygon); var lineBbox = bbox(linestring); if (!doBBoxOverlap(polyBbox, lineBbox)) { @@ -182,16 +192,10 @@ isLineInPoly(LineString linestring, Polygon polygon) { return foundInsidePoint; } -/** - * Is Polygon2 in Polygon1 - * Only takes into account outer rings - * - * @private - * @param {Polygon} geometry1 - * @param {Polygon|MultiPolygon} geometry2 - * @returns {boolean} true/false - */ -isPolyInPoly(Polygon geometry1, GeometryObject geometry2) { +/// +/// Is Polygon2 in Polygon1 +/// Only takes into account outer rings +bool isPolyInPoly(Polygon geometry1, GeometryObject geometry2) { var poly1Bbox = bbox(geometry1); var poly2Bbox = bbox(geometry2); if (!doBBoxOverlap(poly2Bbox, poly1Bbox)) { @@ -205,7 +209,7 @@ isPolyInPoly(Polygon geometry1, GeometryObject geometry2) { return true; } -doBBoxOverlap(BBox bbox1, BBox bbox2) { +bool doBBoxOverlap(BBox bbox1, BBox bbox2) { if (bbox1[0]! > bbox2[0]!) return false; if (bbox1[2]! < bbox2[2]!) return false; if (bbox1[1]! > bbox2[1]!) return false; @@ -213,28 +217,15 @@ doBBoxOverlap(BBox bbox1, BBox bbox2) { return true; } -/** - * compareCoords - * - * @private - * @param {Position} pair1 point [x,y] - * @param {Position} pair2 point [x,y] - * @returns {boolean} true/false if coord pairs match - */ -compareCoords(Position pair1, Position pair2) { +/// compareCoords +bool compareCoords(Position pair1, Position pair2) { return pair1[0] == pair2[0] && pair1[1] == pair2[1]; } -/** - * getMidpoint - * - * @private - * @param {Position} pair1 point [x,y] - * @param {Position} pair2 point [x,y] - * @returns {Position} midpoint of pair1 and pair2 - */ -getMidpoint(Position pair1, Position pair2) { - return [(pair1[0]! + pair2[0]!) / 2, (pair1[1]! + pair2[1]!) / 2]; +/// getMidpoint +Position getMidpoint(Position pair1, Position pair2) { + return Position.of( + [(pair1.lng + pair2.lng) / 2, (pair1.lat + pair2.lat) / 2]); } /* diff --git a/test/booleans/equal_test.dart b/test/booleans/equal_test.dart index cc82c985..0a6479c3 100644 --- a/test/booleans/equal_test.dart +++ b/test/booleans/equal_test.dart @@ -5,7 +5,7 @@ import 'package:test/test.dart'; import 'package:turf/helpers.dart'; import 'package:turf/src/booleans/boolean_equal.dart'; -main() { +void main() { group( 'boolean_equal', () { diff --git a/test/booleans/within_test.dart b/test/booleans/within_test.dart index 42eb0fc9..dd0a64c2 100644 --- a/test/booleans/within_test.dart +++ b/test/booleans/within_test.dart @@ -1,60 +1,52 @@ -/** - * const glob = require("glob"); -const path = require("path"); -const test = require("tape"); -const load = require("load-json-file"); -const shapely = require("boolean-shapely"); -const booleanJSTS = require("boolean-jsts"); -const within = require("./index").default; +import 'dart:convert'; +import 'dart:io'; -test("turf-boolean-within", (t) => { - // True Fixtures - glob - .sync(path.join(__dirname, "test", "true", "**", "*.geojson")) - .forEach((filepath) => { - const name = path.parse(filepath).name; - if (name.includes("skip")) return t.skip(name); +import 'package:test/test.dart'; +import 'package:turf/src/booleans/boolean_within.dart'; +import 'package:turf/turf.dart'; - const geojson = load.sync(filepath); - const feature1 = geojson.features[0]; - const feature2 = geojson.features[1]; - const result = within(feature1, feature2); - if (process.env.JSTS) - t.true( - booleanJSTS("within", feature1, feature2), - "[true] JSTS - " + name - ); +void main() { + group( + 'boolean_within', + () { + // True Fixtures + var inDir = Directory('./test/examples/booleans/within/true'); + for (var file in inDir.listSync(recursive: true)) { + if (file is File && file.path.endsWith('.geojson')) { + test( + file.path, + () { + var inSource = file.readAsStringSync(); + var inGeom = GeoJSONObject.fromJson(jsonDecode(inSource)); - if (process.env.SHAPELY) - shapely - .within(feature1, feature2) - .then((result) => t.true(result, "[true] shapely - " + name)); - t.true(result, "[true] " + name); - }); - // False Fixtures - glob - .sync(path.join(__dirname, "test", "false", "**", "*.geojson")) - .forEach((filepath) => { - const name = path.parse(filepath).name; - if (name.includes("skip")) return t.skip(name); + var feature1 = (inGeom as FeatureCollection).features[0]; + var feature2 = inGeom.features[1]; + var result = booleanWithin(feature1, feature2); + expect(result, true); + }, + ); + } + } + // False Fixtures + var inDir1 = Directory('./test/examples/booleans/within/false'); + for (var file in inDir1.listSync(recursive: true)) { + if (file is File && file.path.endsWith('.geojson')) { + test( + file.path, + () { + // True Fixtures + var inSource = file.readAsStringSync(); + var inGeom = GeoJSONObject.fromJson(jsonDecode(inSource)); - const geojson = load.sync(filepath); - const feature1 = geojson.features[0]; - const feature2 = geojson.features[1]; - const result = within(feature1, feature2); - if (process.env.JSTS) - t.false( - booleanJSTS("within", feature1, feature2), - "[false] JSTS - " + name - ); + var feature1 = (inGeom as FeatureCollection).features[0]; + var feature2 = inGeom.features[1]; - if (process.env.SHAPELY) - shapely - .within(feature1, feature2) - .then((result) => t.false(result, "[false] shapely - " + name)); - t.false(result, "[false] " + name); - }); - t.end(); -}); - - */ \ No newline at end of file + var result = booleanWithin(feature1, feature2); + expect(result, false); + }, + ); + } + } + }, + ); +} From e6792c6a8fe17b4f0544998b1a8c7795a5931bdd Mon Sep 17 00:00:00 2001 From: armantorkzaban Date: Mon, 5 Sep 2022 09:49:19 +0200 Subject: [PATCH 63/82] moved on with valid, refactored --- analysis_options.yaml | 2 +- lib/src/booleans/boolean_overlap.dart | 119 ----- lib/src/booleans/boolean_valid.dart | 24 +- lib/src/booleans/boolean_within.dart | 486 ------------------ lib/src/line_intersect.dart | 4 +- lib/src/line_to_polygon.dart | 30 +- lib/src/polygon_to_line.dart | 6 +- test/booleans/intersect_test.dart | 1 - test/booleans/overlap_test.dart | 150 ------ test/booleans/valid_test.dart | 122 +++-- test/booleans/within_test.dart | 52 -- .../MultiPoint/multipoint.geojson | 0 .../{false => assertion}/Point/point.geojson | 0 13 files changed, 127 insertions(+), 869 deletions(-) delete mode 100644 lib/src/booleans/boolean_overlap.dart delete mode 100644 lib/src/booleans/boolean_within.dart delete mode 100644 test/booleans/overlap_test.dart delete mode 100644 test/booleans/within_test.dart rename test/examples/booleans/valid/{false => assertion}/MultiPoint/multipoint.geojson (100%) rename test/examples/booleans/valid/{false => assertion}/Point/point.geojson (100%) diff --git a/analysis_options.yaml b/analysis_options.yaml index 95724bff..75bcd156 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -2,7 +2,7 @@ include: package:dartclub_lint/dart.yaml linter: rules: - always_declare_return_types: true + # always_declare_return_types: true analyzer: errors: prefer_generic_function_type_aliases: error diff --git a/lib/src/booleans/boolean_overlap.dart b/lib/src/booleans/boolean_overlap.dart deleted file mode 100644 index 588dc2af..00000000 --- a/lib/src/booleans/boolean_overlap.dart +++ /dev/null @@ -1,119 +0,0 @@ -import 'package:turf/helpers.dart'; -import 'package:turf/line_segment.dart'; -import 'package:turf/src/line_intersect.dart'; -import 'package:turf/src/line_overlap.dart'; -import 'package:turf_equality/turf_equality.dart'; - -/// Compares two geometries of the same dimension and returns true if their intersection set results in a geometry -/// different from both but of the same dimension. It applies to Polygon/Polygon, LineString/LineString, -/// Multipoint/Multipoint, MultiLineString/MultiLineString and MultiPolygon/MultiPolygon. -/// -/// In other words, it returns true if the two geometries overlap, provided that neither completely contains the other. -/// -/// @name booleanOverlap -/// @param {Geometry|Feature} feature1 input -/// @param {Geometry|Feature} feature2 input -/// @returns {boolean} true/false -/// @example -/// var poly1 = turf.polygon([[[0,0],[0,5],[5,5],[5,0],[0,0]]]); -/// var poly2 = turf.polygon([[[1,1],[1,6],[6,6],[6,1],[1,1]]]); -/// var poly3 = turf.polygon([[[10,10],[10,15],[15,15],[15,10],[10,10]]]); -/// -/// turf.booleanOverlap(poly1, poly2) -/// //=true -/// turf.booleanOverlap(poly2, poly3) -/// //=false -bool bo oleanOverlap(GeoJSONObject feature1, GeoJSONObject feature2) { - var geom1 = feature1 is Feature ? feature1.geometry : feature1; - var geom2 = feature2 is Feature ? feature2.geometry : feature2; - - if ((feature1 is MultiPoint && feature2 is! MultiPoint) || - ((feature1 is LineString || feature1 is MultiLineString) && - feature2 is! LineString && - feature2 is! MultiLineString) || - ((feature1 is Polygon || feature1 is MultiPolygon) && - feature2 is! Polygon && - feature2 is! MultiPolygon)) { - throw Exception("features must be of the same type"); - } - if (feature1 is Point) throw Exception("Point geometry not supported"); - - // features must be not equal - var equality = Equality(precision: 6); - if (equality.compare(feature1, feature2)) { - return false; - } - - var overlap = 0; - - if (feature1 is MultiPoint) { - for (var i = 0; i < (geom1 as MultiPoint).coordinates.length; i++) { - for (var j = 0; j < (geom2 as MultiPoint).coordinates.length; j++) { - var coord1 = geom1.coordinates[i]; - var coord2 = geom2.coordinates[j]; - if (coord1[0] == coord2[0] && coord1[1] == coord2[1]) { - return true; - } - } - } - return false; - } else if (feature1 is MultiLineString) { - segmentEach( - feature1, - ( - Feature currentSegment, - int featureIndex, - int? multiFeatureIndex, - int? geometryIndex, - int segmentIndex, - ) { - segmentEach( - feature2, - ( - Feature currentSegment1, - int featureIndex, - int? multiFeatureIndex, - int? geometryIndex, - int segmentIndex, - ) { - if (lineOverlap(currentSegment, currentSegment1) - .features - .isNotEmpty) { - overlap++; - } - }, - ); - }, - ); - } else if (feature1 is Polygon || feature1 is MultiPolygon) { - segmentEach( - feature1, - ( - Feature currentSegment, - int featureIndex, - int? multiFeatureIndex, - int? geometryIndex, - int segmentIndex, - ) { - segmentEach( - feature2, - ( - Feature currentSegment1, - int featureIndex, - int? multiFeatureIndex, - int? geometryIndex, - int segmentIndex, - ) { - if (lineIntersect(currentSegment, currentSegment1) - .features - .isNotEmpty) { - overlap++; - } - }, - ); - }, - ); - } - - return overlap > 0; -} diff --git a/lib/src/booleans/boolean_valid.dart b/lib/src/booleans/boolean_valid.dart index 04bdb7f8..05a6edb8 100644 --- a/lib/src/booleans/boolean_valid.dart +++ b/lib/src/booleans/boolean_valid.dart @@ -41,20 +41,22 @@ bool checkPolygonAgainstOthers( /// example /// ```dart /// var line = LineString(coordinates:[Position.of([1, 1]), Position.of([1, 2]), Position.of([1, 3]), Position.of([1, 4])]); -/// /// booleanValid(line); // => true /// booleanValid({foo: "bar"}); // => false /// ``` bool booleanValid(GeoJSONObject feature) { - print(feature); // Parse GeoJSON if (feature is FeatureCollection) { for (Feature f in feature.features) { - booleanValid(f); + if (!booleanValid(f)) { + return false; + } } } else if (feature is GeometryCollection) { for (GeometryObject g in feature.geometries) { - booleanValid(g); + if (!booleanValid(g)) { + return false; + } } } else { var geom = feature is Feature ? feature.geometry : feature; @@ -68,22 +70,26 @@ bool booleanValid(GeoJSONObject feature) { return false; } for (Position p in geom.coordinates) { - booleanValid(Point(coordinates: p)); + if (!booleanValid(Point(coordinates: p))) return false; } } else if (geom is LineString) { if (geom.coordinates.length < 2) return false; for (Position p in geom.coordinates) { - booleanValid(Point(coordinates: p)); + if (!booleanValid(Point(coordinates: p))) return false; } } else if (geom is MultiLineString) { if (geom.coordinates.length < 2) return false; for (var i = 0; i < geom.coordinates.length; i++) { - booleanValid(LineString(coordinates: geom.coordinates[i])); + if (!booleanValid(LineString(coordinates: geom.coordinates[i]))) { + return false; + } } } else if (geom is Polygon) { + var valid = true; geom.coordEach((Position? cCoord, _, __, ___, ____) { - booleanValid(Point(coordinates: cCoord!)); + valid = booleanValid(Point(coordinates: cCoord!)); }); + if (!valid) return false; for (var i = 0; i < geom.coordinates.length; i++) { if (geom.coordinates[i].length < 4) return false; if (!checkRingsClose(geom.coordinates[i])) return false; @@ -119,7 +125,7 @@ bool booleanValid(GeoJSONObject feature) { } } } else { - print('is strange $geom'); + throw Exception('the type ${geom?.type} is not supported'); } } return true; diff --git a/lib/src/booleans/boolean_within.dart b/lib/src/booleans/boolean_within.dart deleted file mode 100644 index f18b7097..00000000 --- a/lib/src/booleans/boolean_within.dart +++ /dev/null @@ -1,486 +0,0 @@ -import 'package:turf/bbox.dart'; - -import '../../helpers.dart'; -import 'boolean_point_in_polygon.dart'; -import 'boolean_point_on_line.dart'; - -/// Boolean-within returns true if the first geometry is completely within the second geometry. -/// The interiors of both geometries must intersect and, the interior and boundary of the primary (geometry a) -/// must not intersect the exterior of the secondary (geometry b). -/// Boolean-within returns the exact opposite result of the `@turf/boolean-contains`. -/// @name booleanWithin -/// @param {Geometry|Feature} feature1 GeoJSON Feature or Geometry -/// @param {Geometry|Feature} feature2 GeoJSON Feature or Geometry -/// @returns {boolean} true/false -/// @example -/// var line = turf.lineString([[1, 1], [1, 2], [1, 3], [1, 4]]); -/// var point = turf.point([1, 2]); -/// turf.booleanWithin(point, line); -/// //=true -bool booleanWithin(GeoJSONObject feature1, GeoJSONObject feature2) { - var geom1 = feature1 is Feature ? feature1.geometry : feature1; - var geom2 = feature2 is Feature ? feature2.geometry : feature2; - - if (geom1 is Point) { - if (geom2 is MultiPoint) { - return isPointInMultiPoint(geom1, geom2); - } - if (geom2 is LineString) { - return booleanPointOnLine(geom1, geom2, ignoreEndVertices: true); - } - if (geom2 is Polygon || geom2 is MultiPolygon) { - return booleanPointInPolygon(geom1.coordinates, geom2!, - ignoreBoundary: true); - } else { - throw Exception("feature2 $geom2 geometry not supported"); - } - } else if (geom1 is MultiPoint) { - if (geom2 is MultiPoint) { - return isMultiPointInMultiPoint(geom1, geom2); - } else if (geom2 is LineString) { - return isMultiPointOnLine(geom1, geom2); - } else if (geom2 is Polygon) { - return isMultiPointInPoly(geom1, geom2); - } else if (geom2 is MultiPolygon) { - bool result = false; - for (var p in geom2.coordinates) { - if (isMultiPointInPoly(geom1, Polygon(coordinates: p))) { - result = true; - } - } - return result; - } else { - throw Exception("feature2 $geom2 geometry not supported"); - } - } else if (geom1 is LineString) { - if (geom2 is LineString) { - return isLineOnLine(geom1, geom2); - } else if (geom2 is Polygon) { - return isLineInPoly(geom1, geom2); - } else if (geom2 is MultiPolygon) { - bool result = false; - for (var p in geom2.coordinates) { - if (isLineInPoly(geom1, Polygon(coordinates: p))) { - result = true; - } - } - return result; - } else { - throw Exception("feature2: $geom2 geometry not supported"); - } - } else if (geom1 is Polygon) { - if (geom2 is Polygon) { - return isPolyInPoly(geom1, geom2); - } else if (geom2 is MultiPolygon) { - bool result = false; - for (var p in geom2.coordinates) { - if (isPolyInPoly(geom1, Polygon(coordinates: p))) { - result = true; - } - } - return result; - } else { - throw Exception("feature2 $geom2 geometry not supported"); - } - } else { - throw Exception("feature1 $geom1 geometry not supported"); - } -} - -bool isPointInMultiPoint(Point point, MultiPoint multiPoint) { - var output = false; - for (var i = 0; i < multiPoint.coordinates.length; i++) { - if (compareCoords(multiPoint.coordinates[i], point.coordinates)) { - output = true; - break; - } - } - return output; -} - -bool isMultiPointInMultiPoint(MultiPoint multiPoint1, MultiPoint multiPoint2) { - for (var i = 0; i < multiPoint1.coordinates.length; i++) { - var anyMatch = false; - for (var i2 = 0; i2 < multiPoint2.coordinates.length; i2++) { - if (compareCoords( - multiPoint1.coordinates[i], multiPoint2.coordinates[i2])) { - anyMatch = true; - } - } - if (!anyMatch) { - return false; - } - } - return true; -} - -bool isMultiPointOnLine(MultiPoint multiPoint, LineString lineString) { - var foundInsidePoint = false; - - for (var i = 0; i < multiPoint.coordinates.length; i++) { - if (!booleanPointOnLine( - Point(coordinates: multiPoint.coordinates[i]), lineString)) { - return false; - } - if (!foundInsidePoint) { - foundInsidePoint = booleanPointOnLine( - Point(coordinates: multiPoint.coordinates[i]), lineString, - ignoreEndVertices: true); - } - } - return foundInsidePoint; -} - -bool isMultiPointInPoly(MultiPoint multiPoint, Polygon polygon) { - var output = true; - var oneInside = false; - var isInside = false; - for (var i = 0; i < multiPoint.coordinates.length; i++) { - isInside = booleanPointInPolygon(multiPoint.coordinates[i], polygon); - if (!isInside) { - output = false; - break; - } - if (!oneInside) { - isInside = booleanPointInPolygon( - multiPoint.coordinates[i], - polygon, - ignoreBoundary: true, - ); - } - } - return output && isInside; -} - -bool isLineOnLine(LineString lineString1, LineString lineString2) { - for (var i = 0; i < lineString1.coordinates.length; i++) { - if (!booleanPointOnLine( - Point(coordinates: lineString1.coordinates[i]), lineString2)) { - return false; - } - } - return true; -} - -bool isLineInPoly(LineString linestring, Polygon polygon) { - var polyBbox = bbox(polygon); - var lineBbox = bbox(linestring); - if (!doBBoxOverlap(polyBbox, lineBbox)) { - return false; - } - var foundInsidePoint = false; - - for (var i = 0; i < linestring.coordinates.length - 1; i++) { - if (!booleanPointInPolygon(linestring.coordinates[i], polygon)) { - return false; - } - if (!foundInsidePoint) { - foundInsidePoint = booleanPointInPolygon( - linestring.coordinates[i], polygon, - ignoreBoundary: true); - } - if (!foundInsidePoint) { - var midpoint = - getMidpoint(linestring.coordinates[i], linestring.coordinates[i + 1]); - foundInsidePoint = booleanPointInPolygon( - midpoint, - polygon, - ignoreBoundary: true, - ); - } - } - return foundInsidePoint; -} - -/// -/// Is Polygon2 in Polygon1 -/// Only takes into account outer rings -bool isPolyInPoly(Polygon geometry1, GeometryObject geometry2) { - var poly1Bbox = bbox(geometry1); - var poly2Bbox = bbox(geometry2); - if (!doBBoxOverlap(poly2Bbox, poly1Bbox)) { - return false; - } - for (var i = 0; i < geometry1.coordinates[0].length; i++) { - if (!booleanPointInPolygon(geometry1.coordinates[0][i], geometry2)) { - return false; - } - } - return true; -} - -bool doBBoxOverlap(BBox bbox1, BBox bbox2) { - if (bbox1[0]! > bbox2[0]!) return false; - if (bbox1[2]! < bbox2[2]!) return false; - if (bbox1[1]! > bbox2[1]!) return false; - if (bbox1[3]! < bbox2[3]!) return false; - return true; -} - -/// compareCoords -bool compareCoords(Position pair1, Position pair2) { - return pair1[0] == pair2[0] && pair1[1] == pair2[1]; -} - -/// getMidpoint -Position getMidpoint(Position pair1, Position pair2) { - return Position.of( - [(pair1.lng + pair2.lng) / 2, (pair1.lat + pair2.lat) / 2]); -} - -/* -import { - BBox, - Feature, - Geometry, - LineString, - MultiPoint, - MultiPolygon, - Point, - Polygon, -} from "geojson"; -import calcBbox from "@turf/bbox"; -import booleanPointOnLine from "@turf/boolean-point-on-line"; -import booleanPointInPolygon from "@turf/boolean-point-in-polygon"; -import { getGeom } from "@turf/invariant"; - -/** - * Boolean-within returns true if the first geometry is completely within the second geometry. - * The interiors of both geometries must intersect and, the interior and boundary of the primary (geometry a) - * must not intersect the exterior of the secondary (geometry b). - * Boolean-within returns the exact opposite result of the `@turf/boolean-contains`. - * - * @name booleanWithin - * @param {Geometry|Feature} feature1 GeoJSON Feature or Geometry - * @param {Geometry|Feature} feature2 GeoJSON Feature or Geometry - * @returns {boolean} true/false - * @example - * var line = turf.lineString([[1, 1], [1, 2], [1, 3], [1, 4]]); - * var point = turf.point([1, 2]); - * - * turf.booleanWithin(point, line); - * //=true - */ -function booleanWithin( - feature1: Feature | Geometry, - feature2: Feature | Geometry -): boolean { - var geom1 = getGeom(feature1); - var geom2 = getGeom(feature2); - var type1 = geom1.type; - var type2 = geom2.type; - - switch (type1) { - case "Point": - switch (type2) { - case "MultiPoint": - return isPointInMultiPoint(geom1, geom2); - case "LineString": - return booleanPointOnLine(geom1, geom2, { ignoreEndVertices: true }); - case "Polygon": - case "MultiPolygon": - return booleanPointInPolygon(geom1, geom2, { ignoreBoundary: true }); - default: - throw Exception("feature2 " + type2 + " geometry not supported"); - } - case "MultiPoint": - switch (type2) { - case "MultiPoint": - return isMultiPointInMultiPoint(geom1, geom2); - case "LineString": - return isMultiPointOnLine(geom1, geom2); - case "Polygon": - case "MultiPolygon": - return isMultiPointInPoly(geom1, geom2); - default: - throw Exception("feature2 " + type2 + " geometry not supported"); - } - case "LineString": - switch (type2) { - case "LineString": - return isLineOnLine(geom1, geom2); - case "Polygon": - case "MultiPolygon": - return isLineInPoly(geom1, geom2); - default: - throw Exception("feature2 " + type2 + " geometry not supported"); - } - case "Polygon": - switch (type2) { - case "Polygon": - case "MultiPolygon": - return isPolyInPoly(geom1, geom2); - default: - throw Exception("feature2 " + type2 + " geometry not supported"); - } - default: - throw Exception("feature1 " + type1 + " geometry not supported"); - } -} - -function isPointInMultiPoint(point: Point, multiPoint: MultiPoint) { - var i; - var output = false; - for (i = 0; i < multiPoint.coordinates.length; i++) { - if (compareCoords(multiPoint.coordinates[i], point.coordinates)) { - output = true; - break; - } - } - return output; -} - -function isMultiPointInMultiPoint( - multiPoint1: MultiPoint, - multiPoint2: MultiPoint -) { - for (var i = 0; i < multiPoint1.coordinates.length; i++) { - var anyMatch = false; - for (var i2 = 0; i2 < multiPoint2.coordinates.length; i2++) { - if ( - compareCoords(multiPoint1.coordinates[i], multiPoint2.coordinates[i2]) - ) { - anyMatch = true; - } - } - if (!anyMatch) { - return false; - } - } - return true; -} - -function isMultiPointOnLine(multiPoint: MultiPoint, lineString: LineString) { - var foundInsidePoint = false; - - for (var i = 0; i < multiPoint.coordinates.length; i++) { - if (!booleanPointOnLine(multiPoint.coordinates[i], lineString)) { - return false; - } - if (!foundInsidePoint) { - foundInsidePoint = booleanPointOnLine( - multiPoint.coordinates[i], - lineString, - { ignoreEndVertices: true } - ); - } - } - return foundInsidePoint; -} - -function isMultiPointInPoly(multiPoint: MultiPoint, polygon: Polygon) { - var output = true; - var oneInside = false; - var isInside = false; - for (var i = 0; i < multiPoint.coordinates.length; i++) { - isInside = booleanPointInPolygon(multiPoint.coordinates[i], polygon); - if (!isInside) { - output = false; - break; - } - if (!oneInside) { - isInside = booleanPointInPolygon(multiPoint.coordinates[i], polygon, { - ignoreBoundary: true, - }); - } - } - return output && isInside; -} - -function isLineOnLine(LineString lineString1, LineString lineString2) { - for (var i = 0; i < lineString1.coordinates.length; i++) { - if (!booleanPointOnLine(lineString1.coordinates[i], lineString2)) { - return false; - } - } - return true; -} - -function isLineInPoly(linestring: LineString, polygon: Polygon) { - var polyBbox = calcBbox(polygon); - var lineBbox = calcBbox(linestring); - if (!doBBoxOverlap(polyBbox, lineBbox)) { - return false; - } - var foundInsidePoint = false; - - for (var i = 0; i < linestring.coordinates.length - 1; i++) { - if (!booleanPointInPolygon(linestring.coordinates[i], polygon)) { - return false; - } - if (!foundInsidePoint) { - foundInsidePoint = booleanPointInPolygon( - linestring.coordinates[i], - polygon, - { ignoreBoundary: true } - ); - } - if (!foundInsidePoint) { - var midpoint = getMidpoint( - linestring.coordinates[i], - linestring.coordinates[i + 1] - ); - foundInsidePoint = booleanPointInPolygon(midpoint, polygon, { - ignoreBoundary: true, - }); - } - } - return foundInsidePoint; -} - -/** - * Is Polygon2 in Polygon1 - * Only takes into account outer rings - * - * @private - * @param {Polygon} geometry1 - * @param {Polygon|MultiPolygon} geometry2 - * @returns {boolean} true/false - */ -function isPolyInPoly(geometry1: Polygon, geometry2: Polygon | MultiPolygon) { - var poly1Bbox = calcBbox(geometry1); - var poly2Bbox = calcBbox(geometry2); - if (!doBBoxOverlap(poly2Bbox, poly1Bbox)) { - return false; - } - for (var i = 0; i < geometry1.coordinates[0].length; i++) { - if (!booleanPointInPolygon(geometry1.coordinates[0][i], geometry2)) { - return false; - } - } - return true; -} - -function doBBoxOverlap(bbox1: BBox, bbox2: BBox) { - if (bbox1[0] > bbox2[0]) return false; - if (bbox1[2] < bbox2[2]) return false; - if (bbox1[1] > bbox2[1]) return false; - if (bbox1[3] < bbox2[3]) return false; - return true; -} - -/** - * compareCoords - * - * @private - * @param {Position} pair1 point [x,y] - * @param {Position} pair2 point [x,y] - * @returns {boolean} true/false if coord pairs match - */ -function compareCoords(Position pair1, Position pair2) { - return pair1[0] == pair2[0] && pair1[1] == pair2[1]; -} - -/** - * getMidpoint - * - * @private - * @param {Position} pair1 point [x,y] - * @param {Position} pair2 point [x,y] - * @returns {Position} midpoint of pair1 and pair2 - */ -function getMidpoint(Position pair1, Position pair2) { - return [(pair1[0] + pair2[0]) / 2, (pair1[1] + pair2[1]) / 2]; -} - -export default booleanWithin;*/ diff --git a/lib/src/line_intersect.dart b/lib/src/line_intersect.dart index 29f047d1..f2719a7d 100644 --- a/lib/src/line_intersect.dart +++ b/lib/src/line_intersect.dart @@ -50,12 +50,12 @@ FeatureCollection lineIntersect(GeoJSONObject line1, GeoJSONObject line2, var results = []; if (removeDuplicates) { Set unique = {}; - intersections.forEach((intersection) { + for (var intersection in intersections) { if (!unique.contains(intersection)) { unique.add(intersection); results.add(intersection); } - }); + } } else { results = intersections; } diff --git a/lib/src/line_to_polygon.dart b/lib/src/line_to_polygon.dart index c26028f5..bf537dad 100644 --- a/lib/src/line_to_polygon.dart +++ b/lib/src/line_to_polygon.dart @@ -143,26 +143,24 @@ Feature lineStringToPolygon( List> multiCoords = []; num largestArea = 0; - line.coordinates.forEach( - (coord) { - if (autoComplete) { - coord = _autoCompleteCoords(coord); - } + for (var coord in line.coordinates) { + if (autoComplete) { + coord = _autoCompleteCoords(coord); + } - // Largest LineString to be placed in the first position of the coordinates array - if (orderCoords) { - var area = _calculateArea(bbox(LineString(coordinates: coord))); - if (area > largestArea) { - multiCoords.insert(0, coord); - largestArea = area; - } else { - multiCoords.add(coord); - } + // Largest LineString to be placed in the first position of the coordinates array + if (orderCoords) { + var area = _calculateArea(bbox(LineString(coordinates: coord))); + if (area > largestArea) { + multiCoords.insert(0, coord); + largestArea = area; } else { multiCoords.add(coord); } - }, - ); + } else { + multiCoords.add(coord); + } + } return Feature( geometry: Polygon(coordinates: multiCoords), properties: properties); } else { diff --git a/lib/src/polygon_to_line.dart b/lib/src/polygon_to_line.dart index aee62570..ef5a3bbb 100644 --- a/lib/src/polygon_to_line.dart +++ b/lib/src/polygon_to_line.dart @@ -48,7 +48,11 @@ FeatureCollection _multiPolygonToLine(MultiPolygon geom, properties = properties ?? {}; var lines = []; - coords.forEach((coord) => {lines.add(_coordsToLine(coord, properties))}); + for (var coord in coords) { + { + lines.add(_coordsToLine(coord, properties)); + } + } return FeatureCollection(features: lines); } diff --git a/test/booleans/intersect_test.dart b/test/booleans/intersect_test.dart index 5d0b4c37..f5da0f8e 100644 --- a/test/booleans/intersect_test.dart +++ b/test/booleans/intersect_test.dart @@ -4,7 +4,6 @@ import 'dart:io'; import 'package:test/test.dart'; import 'package:turf/helpers.dart'; import 'package:turf/src/booleans/boolean_intersect.dart'; -import 'package:turf/src/intersection.dart'; main() { var featureCollection = FeatureCollection(features: [ diff --git a/test/booleans/overlap_test.dart b/test/booleans/overlap_test.dart deleted file mode 100644 index aa5f298c..00000000 --- a/test/booleans/overlap_test.dart +++ /dev/null @@ -1,150 +0,0 @@ -import 'dart:convert'; -import 'dart:io'; - -import 'package:test/test.dart'; -import 'package:turf/helpers.dart'; -import 'package:turf/src/booleans/boolean_overlap.dart'; - -main() { - group( - 'boolean-overlap', - () { - test("turf-boolean-overlap-trues", () { - // True Fixtures - Directory dir = Directory('./test/examples/booleans/overlap/true'); - for (var file in dir.listSync(recursive: true)) { - if (file is File && file.path.endsWith('.geojson')) { - var inSource = file.readAsStringSync(); - var inGeom = GeoJSONObject.fromJson(jsonDecode(inSource)); - var feature1 = (inGeom as FeatureCollection).features[0]; - var feature2 = inGeom.features[1]; - var result = booleanOverlap(feature1, feature2); - expect(result, true); - } - } - }); - test( - "turf-boolean-overlap - falses", - () { - // True Fixtures - Directory dir1 = Directory('./test/examples/booleans/overlap/false'); - for (var file in dir1.listSync(recursive: true)) { - if (file is File && file.path.endsWith('.geojson')) { - var inSource = file.readAsStringSync(); - var inGeom = GeoJSONObject.fromJson(jsonDecode(inSource)); - var feature1 = (inGeom as FeatureCollection).features[0]; - var feature2 = inGeom.features[1]; - var result = booleanOverlap(feature1, feature2); - expect(result, false); - } - } - }, - ); - - var pt = Point(coordinates: Position.of([9, 50])); - var line1 = LineString( - coordinates: [ - Position.of([7, 50]), - Position.of([8, 50]), - Position.of([9, 50]), - ], - ); - var line2 = LineString( - coordinates: [ - Position.of([8, 50]), - Position.of([9, 50]), - Position.of([10, 50]), - ], - ); - var poly1 = Polygon( - coordinates: [ - [ - Position.of([8.5, 50]), - Position.of([9.5, 50]), - Position.of([9.5, 49]), - Position.of([8.5, 49]), - Position.of([8.5, 50]), - ], - ], - ); - var poly2 = Polygon( - coordinates: [ - [ - Position.of([8, 50]), - Position.of([9, 50]), - Position.of([9, 49]), - Position.of([8, 49]), - Position.of([8, 50]), - ], - ], - ); - var poly3 = Polygon( - coordinates: [ - [ - Position.of([10, 50]), - Position.of([10.5, 50]), - Position.of([10.5, 49]), - Position.of([10, 49]), - Position.of([10, 50]), - ], - ], - ); - var multiline1 = MultiLineString( - coordinates: [ - [ - Position.of([8, 50]), - Position.of([9, 50]), - Position.of([7, 50]), - ], - ], - ); - var multipoly1 = MultiPolygon( - coordinates: [ - [ - [ - Position.of([8.5, 50]), - Position.of([9.5, 50]), - Position.of([9.5, 49]), - Position.of([8.5, 49]), - Position.of([8.5, 50]), - ], - ], - ], - ); - - test( - "turf-boolean-overlap -- geometries", - () { - expect(booleanOverlap(line1, line2), true); - expect(booleanOverlap(poly1, poly2), true); - var z = booleanOverlap(poly1, poly3); - expect(z, isFalse); - }, - ); - - test( - "turf-boolean-overlap -- throws", - () { - // t.throws(() => overlap(null, line1), /feature1 is required/, 'missing feature1'); - // t.throws(() => overlap(line1, null), /feature2 is required/, 'missing feature2'); - -//'different types', - expect( - () => booleanOverlap( - poly1, - line1, - ), - throwsA(isA())); -// "geometry not supported" - - expect(() => booleanOverlap(pt, pt), throwsA(isA())); - // "supports line and multiline comparison" - var x = booleanOverlap(line1, multiline1); - expect(() => booleanOverlap(line1, multiline1), x); - var y = booleanOverlap(poly1, multipoly1); - expect(() => booleanOverlap(poly1, multipoly1), y); - }, - ); - }, - ); -} diff --git a/test/booleans/valid_test.dart b/test/booleans/valid_test.dart index 924c5a58..bf9387f8 100644 --- a/test/booleans/valid_test.dart +++ b/test/booleans/valid_test.dart @@ -1,8 +1,6 @@ import 'dart:convert'; import 'dart:io'; -import 'dart:math'; -import 'package:analyzer/dart/ast/ast.dart'; import 'package:test/test.dart'; import 'package:turf/src/booleans/boolean_valid.dart'; import 'package:turf/turf.dart'; @@ -11,42 +9,56 @@ main() { group( 'boolean-valid', () { - // Directory dir = Directory('./test/examples/booleans/valid/true'); - // for (var file in dir.listSync(recursive: true)) { - // test( - // file.path, - // () { - // // True Fixtures - // if (file is File && file.path.endsWith('.geojson')) { - // var inSource = file.readAsStringSync(); - // var inGeom = GeoJSONObject.fromJson(jsonDecode(inSource)); - // var result = booleanValid(inGeom); - // expect(result, true); - // } - // }, - // ); - // } - Directory dir1 = Directory('./test/examples/booleans/valid/false'); - for (var file in dir1.listSync(recursive: true)) { + /// Assertion error is caught in the fromJSON factory contructor of [GeometryType]s + Directory dir = Directory('./test/examples/booleans/valid/assertion'); + for (var file in dir.listSync(recursive: true)) { + test( + file.path, + () { + // Assertion Error Fixtures + if (file is File && file.path.endsWith('.geojson')) { + var inSource = file.readAsStringSync(); + expect( + () => booleanValid( + GeoJSONObject.fromJson( + jsonDecode(inSource), + ), + ), + throwsA(isA()), + ); + } + }, + ); + } + Directory dirFale = Directory('./test/examples/booleans/valid/false'); + for (var file in dirFale.listSync(recursive: true)) { test( file.path, () { + print(file.path); // False Fixtures if (file is File && file.path.endsWith('.geojson')) { var inSource = file.readAsStringSync(); - try { - var inGeom = GeoJSONObject.fromJson(jsonDecode(inSource)); - } catch (e) { - if (e is AssertionError) { - print('assertion worked in case of ${file.path}'); - } - } finally { - if (!e.toString().contains('Failed assersion')) { - var inGeom = GeoJSONObject.fromJson(jsonDecode(inSource)); - var result = booleanValid(inGeom); - expect(result, false); - } - } + expect( + booleanValid( + GeoJSONObject.fromJson( + jsonDecode(inSource), + ), + ), + isFalse); + } + }, + ); + } + Directory dir1 = Directory('./test/examples/booleans/valid/true'); + for (var file in dir1.listSync(recursive: true)) { + test( + file.path, + () { + if (file is File && file.path.endsWith('.geojson')) { + var inSource = file.readAsStringSync(); + var inGeom = GeoJSONObject.fromJson(jsonDecode(inSource)); + expect(booleanValid(inGeom), isTrue); } }, ); @@ -54,3 +66,49 @@ main() { }, ); } + + +/** + * const glob = require("glob"); +const path = require("path"); +const test = require("tape"); +const load = require("load-json-file"); +// const shapely = require('boolean-shapely'); +const isValid = require("./index").default; + +test("turf-boolean-valid", (t) => { + // True Fixtures + glob + .sync(path.join(__dirname, "test", "true", "**", "*.geojson")) + .forEach((filepath) => { + const name = path.parse(filepath).name; + + if (name === "multipolygon-touch") return t.skip("multipolygon-touch"); + + const geojson = load.sync(filepath); + const feature1 = geojson.features[0]; + const result = isValid(feature1); + + // if (process.env.SHAPELY) shapely.contains(feature1).then(result => t.true(result, '[true] shapely - ' + name)); + t.true(result, "[true] " + name); + }); + // False Fixtures + glob + .sync(path.join(__dirname, "test", "false", "**", "*.geojson")) + .forEach((filepath) => { + const name = path.parse(filepath).name; + const geojson = load.sync(filepath); + const feature1 = geojson.features[0]; + const result = isValid(feature1); + + // if (process.env.SHAPELY) shapely.contains(feature1, feature2).then(result => t.false(result, '[false] shapely - ' + name)); + t.false(result, "[false] " + name); + }); + t.end(); +}); + +test("turf-boolean-valid -- obvious fails", (t) => { + t.false(isValid({ foo: "bar" })); + t.end(); +}); + */ \ No newline at end of file diff --git a/test/booleans/within_test.dart b/test/booleans/within_test.dart deleted file mode 100644 index dd0a64c2..00000000 --- a/test/booleans/within_test.dart +++ /dev/null @@ -1,52 +0,0 @@ -import 'dart:convert'; -import 'dart:io'; - -import 'package:test/test.dart'; -import 'package:turf/src/booleans/boolean_within.dart'; -import 'package:turf/turf.dart'; - -void main() { - group( - 'boolean_within', - () { - // True Fixtures - var inDir = Directory('./test/examples/booleans/within/true'); - for (var file in inDir.listSync(recursive: true)) { - if (file is File && file.path.endsWith('.geojson')) { - test( - file.path, - () { - var inSource = file.readAsStringSync(); - var inGeom = GeoJSONObject.fromJson(jsonDecode(inSource)); - - var feature1 = (inGeom as FeatureCollection).features[0]; - var feature2 = inGeom.features[1]; - var result = booleanWithin(feature1, feature2); - expect(result, true); - }, - ); - } - } - // False Fixtures - var inDir1 = Directory('./test/examples/booleans/within/false'); - for (var file in inDir1.listSync(recursive: true)) { - if (file is File && file.path.endsWith('.geojson')) { - test( - file.path, - () { - // True Fixtures - var inSource = file.readAsStringSync(); - var inGeom = GeoJSONObject.fromJson(jsonDecode(inSource)); - - var feature1 = (inGeom as FeatureCollection).features[0]; - var feature2 = inGeom.features[1]; - - var result = booleanWithin(feature1, feature2); - expect(result, false); - }, - ); - } - } - }, - ); -} diff --git a/test/examples/booleans/valid/false/MultiPoint/multipoint.geojson b/test/examples/booleans/valid/assertion/MultiPoint/multipoint.geojson similarity index 100% rename from test/examples/booleans/valid/false/MultiPoint/multipoint.geojson rename to test/examples/booleans/valid/assertion/MultiPoint/multipoint.geojson diff --git a/test/examples/booleans/valid/false/Point/point.geojson b/test/examples/booleans/valid/assertion/Point/point.geojson similarity index 100% rename from test/examples/booleans/valid/false/Point/point.geojson rename to test/examples/booleans/valid/assertion/Point/point.geojson From 88677c2b7a874b9db45d223c8fda5526fabfecaf Mon Sep 17 00:00:00 2001 From: armantorkzaban Date: Mon, 5 Sep 2022 10:43:26 +0200 Subject: [PATCH 64/82] valid test --- test/components/geojson_test.dart | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/components/geojson_test.dart b/test/components/geojson_test.dart index 957c730e..c84e8755 100644 --- a/test/components/geojson_test.dart +++ b/test/components/geojson_test.dart @@ -463,7 +463,9 @@ main() { group('Example file', () { var dir = Directory('./test/examples'); for (var file in dir.listSync(recursive: true)) { - if (file is File && file.path.endsWith('.geojson')) { + if (file is File && + file.path.endsWith('.geojson') && + !file.path.contains('assertion')) { test(file.path, () { var source = (file).readAsStringSync(); var json = jsonDecode(source); From e88c9e99b21165f1f5d2b6bd72add67f8d9beb75 Mon Sep 17 00:00:00 2001 From: armantorkzaban Date: Mon, 5 Sep 2022 12:13:33 +0200 Subject: [PATCH 65/82] lineIntersection testet - contains sweepline --- lib/src/booleans/boolean_valid.dart | 31 ++- lib/src/line_intersect.dart | 91 ------- test/booleans/valid_test.dart | 46 ---- test/components/line_intersect_test.dart | 165 ++++++++++++ .../in/2-vertex-segment.geojson | 33 +++ .../in/double-intersect.geojson | 44 +++ .../in/multi-linestring.geojson | 74 ++++++ .../in/polygons-with-holes.geojson | 107 ++++++++ .../in/same-coordinates.geojson | 39 +++ .../out/2-vertex-segment.geojson | 41 +++ .../out/double-intersect.geojson | 60 +++++ .../out/multi-linestring.geojson | 154 +++++++++++ .../out/polygons-with-holes.geojson | 251 ++++++++++++++++++ .../out/same-coordinates.geojson | 55 ++++ 14 files changed, 1045 insertions(+), 146 deletions(-) create mode 100644 test/components/line_intersect_test.dart create mode 100644 test/examples/line_intersect/in/2-vertex-segment.geojson create mode 100644 test/examples/line_intersect/in/double-intersect.geojson create mode 100644 test/examples/line_intersect/in/multi-linestring.geojson create mode 100644 test/examples/line_intersect/in/polygons-with-holes.geojson create mode 100644 test/examples/line_intersect/in/same-coordinates.geojson create mode 100644 test/examples/line_intersect/out/2-vertex-segment.geojson create mode 100644 test/examples/line_intersect/out/double-intersect.geojson create mode 100644 test/examples/line_intersect/out/multi-linestring.geojson create mode 100644 test/examples/line_intersect/out/polygons-with-holes.geojson create mode 100644 test/examples/line_intersect/out/same-coordinates.geojson diff --git a/lib/src/booleans/boolean_valid.dart b/lib/src/booleans/boolean_valid.dart index 05a6edb8..3c8e1adf 100644 --- a/lib/src/booleans/boolean_valid.dart +++ b/lib/src/booleans/boolean_valid.dart @@ -23,11 +23,10 @@ bool checkRingsForSpikesPunctures(List geom) { } bool checkPolygonAgainstOthers( - List> poly, List>> geom, int index) { - var polyToCheck = Polygon(coordinates: poly); + Polygon poly, List>> geom, int index) { for (var i = index + 1; i < geom.length; i++) { - if (!booleanDisjoint(polyToCheck, Polygon(coordinates: geom[i]))) { - if (booleanCrosses(polyToCheck, LineString(coordinates: geom[i][0]))) { + if (!booleanDisjoint(poly, Polygon(coordinates: geom[i]))) { + if (booleanCrosses(poly, LineString(coordinates: geom[i][0]))) { return false; } } @@ -109,18 +108,32 @@ bool booleanValid(GeoJSONObject feature) { var poly = geom.coordinates[i]; for (var ii = 0; ii < poly.length; ii++) { - if (poly[ii].length < 4) return false; - if (!checkRingsClose(poly[ii])) return false; - if (checkRingsForSpikesPunctures(poly[ii])) return false; + if (poly[ii].length < 4) { + print('length is short'); + return false; + } + if (!checkRingsClose(poly[ii])) { + print('ring closure issues'); + return false; + } + if (checkRingsForSpikesPunctures(poly[ii])) { + print('spikes'); + return false; + } if (ii == 0) { - if (!checkPolygonAgainstOthers(poly, geom.coordinates, i)) { + if (!checkPolygonAgainstOthers( + Polygon(coordinates: poly), geom.coordinates, i)) { + print('comparison fails'); return false; } } if (ii > 0) { if (lineIntersect(Polygon(coordinates: [poly[0]]), Polygon(coordinates: [poly[ii]])).features.length > - 1) return false; + 1) { + print('intersects'); + return false; + } } } } diff --git a/lib/src/line_intersect.dart b/lib/src/line_intersect.dart index f2719a7d..9ff475d0 100644 --- a/lib/src/line_intersect.dart +++ b/lib/src/line_intersect.dart @@ -64,94 +64,3 @@ FeatureCollection lineIntersect(GeoJSONObject line1, GeoJSONObject line2, .map((r) => Feature(geometry: Point(coordinates: r))) .toList()); } -/** - * import { feature, featureCollection, point } from "@turf/helpers"; -import { - Feature, - FeatureCollection, - LineString, - MultiLineString, - MultiPolygon, - Point, - Polygon, -} from "geojson"; -import findIntersections, { Intersection } from "sweepline-intersections"; - -/** - * Takes any LineString or Polygon GeoJSON and returns the intersecting point(s). - * - * @name lineIntersect - * @param {GeoJSON} line1 any LineString or Polygon - * @param {GeoJSON} line2 any LineString or Polygon - * @param {Object} [options={}] Optional parameters - * @param {boolean} [options.removeDuplicates=true] remove duplicate intersections - * @param {boolean} [options.ignoreSelfIntersections=false] ignores self-intersections on input features - * @returns {FeatureCollection} point(s) that intersect both - * @example - * var line1 = turf.lineString([[126, -11], [129, -21]]); - * var line2 = turf.lineString([[123, -18], [131, -14]]); - * var intersects = turf.lineIntersect(line1, line2); - * - * //addToMap - * var addToMap = [line1, line2, intersects] - */ -function lineIntersect< - G1 extends LineString | MultiLineString | Polygon | MultiPolygon, - G2 extends LineString | MultiLineString | Polygon | MultiPolygon ->( - line1: FeatureCollection | Feature | G1, - line2: FeatureCollection | Feature | G2, - options: { - removeDuplicates?: boolean; - ignoreSelfIntersections?: boolean; - } = {} -): FeatureCollection { - const { removeDuplicates = true, ignoreSelfIntersections = false } = options; - let features: Feature[] = []; - if (line1.type === "FeatureCollection") - features = features.concat(line1.features); - else if (line1.type === "Feature") features.push(line1); - else if ( - line1.type === "LineString" || - line1.type === "Polygon" || - line1.type === "MultiLineString" || - line1.type === "MultiPolygon" - ) { - features.push(feature(line1)); - } - - if (line2.type === "FeatureCollection") - features = features.concat(line2.features); - else if (line2.type === "Feature") features.push(line2); - else if ( - line2.type === "LineString" || - line2.type === "Polygon" || - line2.type === "MultiLineString" || - line2.type === "MultiPolygon" - ) { - features.push(feature(line2)); - } - - const intersections = findIntersections( - featureCollection(features), - ignoreSelfIntersections - ); - - let results: Intersection[] = []; - if (removeDuplicates) { - const unique: Record = {}; - intersections.forEach((intersection) => { - const key = intersection.join(","); - if (!unique[key]) { - unique[key] = true; - results.push(intersection); - } - }); - } else { - results = intersections; - } - return featureCollection(results.map((r) => point(r))); -} - -export default lineIntersect; - */ \ No newline at end of file diff --git a/test/booleans/valid_test.dart b/test/booleans/valid_test.dart index bf9387f8..1011c37d 100644 --- a/test/booleans/valid_test.dart +++ b/test/booleans/valid_test.dart @@ -66,49 +66,3 @@ main() { }, ); } - - -/** - * const glob = require("glob"); -const path = require("path"); -const test = require("tape"); -const load = require("load-json-file"); -// const shapely = require('boolean-shapely'); -const isValid = require("./index").default; - -test("turf-boolean-valid", (t) => { - // True Fixtures - glob - .sync(path.join(__dirname, "test", "true", "**", "*.geojson")) - .forEach((filepath) => { - const name = path.parse(filepath).name; - - if (name === "multipolygon-touch") return t.skip("multipolygon-touch"); - - const geojson = load.sync(filepath); - const feature1 = geojson.features[0]; - const result = isValid(feature1); - - // if (process.env.SHAPELY) shapely.contains(feature1).then(result => t.true(result, '[true] shapely - ' + name)); - t.true(result, "[true] " + name); - }); - // False Fixtures - glob - .sync(path.join(__dirname, "test", "false", "**", "*.geojson")) - .forEach((filepath) => { - const name = path.parse(filepath).name; - const geojson = load.sync(filepath); - const feature1 = geojson.features[0]; - const result = isValid(feature1); - - // if (process.env.SHAPELY) shapely.contains(feature1, feature2).then(result => t.false(result, '[false] shapely - ' + name)); - t.false(result, "[false] " + name); - }); - t.end(); -}); - -test("turf-boolean-valid -- obvious fails", (t) => { - t.false(isValid({ foo: "bar" })); - t.end(); -}); - */ \ No newline at end of file diff --git a/test/components/line_intersect_test.dart b/test/components/line_intersect_test.dart new file mode 100644 index 00000000..cda355de --- /dev/null +++ b/test/components/line_intersect_test.dart @@ -0,0 +1,165 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:test/test.dart'; +import 'package:turf/helpers.dart'; +import 'package:turf/src/line_intersect.dart'; +import 'package:turf/src/truncate.dart'; +import 'package:turf_equality/turf_equality.dart'; + +main() { + group( + 'line_intersect', + () { + Directory dir = Directory('./test/examples/line_intersect/in'); + for (var file in dir.listSync(recursive: true)) { + if (file is File && file.path.endsWith('.geojson')) { + var inSource = file.readAsStringSync(); + var inGeom = + GeoJSONObject.fromJson(jsonDecode(inSource)) as FeatureCollection; + + var outPath = './' + + file.uri.pathSegments + .sublist(0, file.uri.pathSegments.length - 2) + .join('/') + + '/out/${file.uri.pathSegments.last}'; + + var outSource = File(outPath).readAsStringSync(); + var outGeom = GeoJSONObject.fromJson(jsonDecode(outSource)) + as FeatureCollection; + + test( + "turf-line-intersect", + () { + var results = truncate( + lineIntersect(inGeom.features.first, inGeom.features.last)); + var coll = FeatureCollection() + ..features = [...(results as FeatureCollection).features]; + + coll.features.add(inGeom.features.first); + coll.features.add(inGeom.features.last); + + Equality eq = Equality(); + expect(eq.compare(outGeom, coll), isTrue); + }, + ); + } + } + + test( + "turf-line-intersect - prevent input mutation", + () { + var line1 = LineString(coordinates: [ + Position.of([7, 50]), + Position.of([8, 50]), + Position.of([9, 50]), + ]); + var line2 = LineString(coordinates: [ + Position.of([8, 49]), + Position.of([8, 50]), + Position.of([8, 51]), + ]); + var before1 = line1.toJson(); + var before2 = line2.toJson(); + + lineIntersect(line1, line2); + Equality eq = Equality(); + expect(eq.compare(line1, LineString.fromJson(before1)), true); + expect(eq.compare(line2, LineString.fromJson(before2)), isTrue); + }, + ); + + test( + "turf-line-intersect - Geometry Objects", + () { + var line1 = LineString( + coordinates: [ + Position.of([7, 50]), + Position.of([9, 50]), + ], + ); + var line2 = LineString( + coordinates: [ + Position.of([8, 49]), + Position.of([8, 51]), + ], + ); + // "support Geometry Objects" + expect(lineIntersect(line1, line2).features, isNotEmpty); +// "support Feature Collection" + + expect( + lineIntersect( + FeatureCollection( + features: [Feature(geometry: line1)]), + FeatureCollection( + features: [Feature(geometry: line2)])).features, + isNotEmpty); + // expect( + // lineIntersect(GeometryCollection(geometries: [line1]), + // GeometryCollection(geometries: [line2])).features, + // isNotEmpty); + }, + ); + + test( + "turf-line-intersect - same point #688", + () { + var line1 = LineString( + coordinates: [ + Position.of([7, 50]), + Position.of([8, 50]), + Position.of([9, 50]), + ], + ); + var line2 = LineString( + coordinates: [ + Position.of([8, 49]), + Position.of([8, 50]), + Position.of([8, 51]), + ], + ); + + var results = lineIntersect(line1, line2); + expect(results.features.length == 1, true); + + var results2 = lineIntersect( + line1, + line2, + removeDuplicates: false, + ); + expect(results2.features.length == 3, true); + }, + ); + + test( + "turf-line-intersect - polygon support #586", + () { + var poly1 = Polygon( + coordinates: [ + [ + Position.of([7, 50]), + Position.of([8, 50]), + Position.of([9, 50]), + Position.of([7, 50]), + ], + ], + ); + var poly2 = Polygon( + coordinates: [ + [ + Position.of([8, 49]), + Position.of([8, 50]), + Position.of([8, 51]), + Position.of([8, 49]), + ], + ], + ); + + var results = lineIntersect(poly1, poly2); + expect(results.features.length == 1, true); + }, + ); + }, + ); +} diff --git a/test/examples/line_intersect/in/2-vertex-segment.geojson b/test/examples/line_intersect/in/2-vertex-segment.geojson new file mode 100644 index 00000000..f4ed4718 --- /dev/null +++ b/test/examples/line_intersect/in/2-vertex-segment.geojson @@ -0,0 +1,33 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": { + "stroke": "#F00", + "stroke-width": 6 + }, + "geometry": { + "type": "LineString", + "coordinates": [ + [124.584961, -12.768946], + [126.738281, -17.224758] + ] + } + }, + { + "type": "Feature", + "properties": { + "stroke": "#00F", + "stroke-width": 6 + }, + "geometry": { + "type": "LineString", + "coordinates": [ + [123.354492, -15.961329], + [127.22168, -14.008696] + ] + } + } + ] +} diff --git a/test/examples/line_intersect/in/double-intersect.geojson b/test/examples/line_intersect/in/double-intersect.geojson new file mode 100644 index 00000000..f699b49e --- /dev/null +++ b/test/examples/line_intersect/in/double-intersect.geojson @@ -0,0 +1,44 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": { + "stroke": "#F00", + "stroke-width": 6 + }, + "geometry": { + "type": "LineString", + "coordinates": [ + [142.03125, -11.695273], + [138.691406, -16.804541], + [136.40625, -14.604847], + [135.966797, -12.039321], + [131.308594, -11.436955], + [128.232422, -15.36895], + [125.947266, -13.581921], + [121.816406, -18.729502], + [117.421875, -20.632784], + [113.378906, -23.402765], + [114.169922, -26.667096] + ] + } + }, + { + "type": "Feature", + "properties": { + "stroke": "#00F", + "stroke-width": 6 + }, + "geometry": { + "type": "LineString", + "coordinates": [ + [117.861328, -15.029686], + [122.124023, -24.886436], + [132.583008, -22.309426], + [132.890625, -7.754537] + ] + } + } + ] +} diff --git a/test/examples/line_intersect/in/multi-linestring.geojson b/test/examples/line_intersect/in/multi-linestring.geojson new file mode 100644 index 00000000..4474df85 --- /dev/null +++ b/test/examples/line_intersect/in/multi-linestring.geojson @@ -0,0 +1,74 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": { + "stroke": "#F00", + "stroke-width": 6 + }, + "geometry": { + "type": "MultiLineString", + "coordinates": [ + [ + [142.03125, -11.695273], + [138.691406, -16.804541], + [136.40625, -14.604847], + [135.966797, -12.039321], + [131.308594, -11.436955], + [128.232422, -15.36895], + [125.947266, -13.581921], + [121.816406, -18.729502], + [117.421875, -20.632784], + [113.378906, -23.402765], + [114.169922, -26.667096] + ], + [ + [117.290039, -27.994401], + [118.87207, -25.165173], + [121.508789, -24.407138], + [122.783203, -19.228177], + [125.683594, -18.771115], + [130.78125, -21.534847], + [133.417969, -17.602139], + [137.768555, -19.55979], + [139.658203, -18.39623] + ] + ] + } + }, + { + "type": "Feature", + "properties": { + "stroke": "#00F", + "stroke-width": 6 + }, + "geometry": { + "type": "MultiLineString", + "coordinates": [ + [ + [117.861328, -15.029686], + [122.124023, -24.886436], + [132.583008, -22.309426], + [132.890625, -7.754537] + ], + [ + [115.751953, -17.014768], + [118.652344, -26.037042], + [118.344727, -28.343065], + [125.068359, -28.652031], + [125.771484, -26.627818], + [131.572266, -26.509905], + [136.40625, -24.886436], + [136.186523, -22.105999], + [134.956055, -20.591652], + [135.439453, -16.214675], + [136.713867, -15.114553], + [134.912109, -11.738302], + [135, -10.141932] + ] + ] + } + } + ] +} diff --git a/test/examples/line_intersect/in/polygons-with-holes.geojson b/test/examples/line_intersect/in/polygons-with-holes.geojson new file mode 100644 index 00000000..8b6163c8 --- /dev/null +++ b/test/examples/line_intersect/in/polygons-with-holes.geojson @@ -0,0 +1,107 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": { + "stroke": "#F00", + "stroke-width": 6 + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [127.397461, -14.221789], + [119.399414, -18.729502], + [114.741211, -21.289374], + [113.554688, -24.487149], + [114.213867, -28.304381], + [116.235352, -30.977609], + [115.532227, -33.468108], + [116.191406, -34.633208], + [120.629883, -33.541395], + [124.541016, -33.247876], + [128.62793, -32.10119], + [129.726563, -31.765537], + [129.726563, -28.806174], + [128.276367, -28.497661], + [125.727539, -28.459033], + [122.695313, -30.372875], + [120.410156, -30.562261], + [118.476562, -28.998532], + [118.608398, -27.527758], + [123.925781, -27.019984], + [126.5625, -26.549223], + [130.166016, -25.76032], + [130.166016, -23.644524], + [127.617187, -22.917923], + [123.837891, -24.567108], + [119.267578, -24.567108], + [118.564453, -23.281719], + [119.838867, -21.330315], + [123.706055, -21.493964], + [127.089844, -21.0845], + [128.232422, -19.103648], + [127.749023, -17.895114], + [130.297852, -17.182779], + [129.858398, -15.538376], + [129.023438, -14.179186], + [127.397461, -14.221789] + ], + [ + [122.958984, -19.890723], + [125.068359, -19.890723], + [125.068359, -18.187607], + [122.958984, -18.187607], + [122.958984, -19.890723] + ] + ] + } + }, + { + "type": "Feature", + "properties": { + "stroke": "#00F", + "stroke-width": 6 + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [120.849609, -14.85985], + [117.070313, -15.496032], + [117.026367, -17.769612], + [119.663086, -20.468189], + [121.157227, -23.039298], + [120.058594, -24.647017], + [118.344727, -26.076521], + [120.410156, -28.343065], + [120.146484, -30.939924], + [118.256836, -33.027088], + [123.925781, -34.885931], + [126.123047, -33.687782], + [125.947266, -31.840233], + [124.057617, -28.536275], + [122.080078, -26.273714], + [123.442383, -23.885838], + [125.200195, -22.796439], + [124.277344, -19.47695], + [120.849609, -14.85985] + ], + [ + [121.157227, -27.371767], + [121.157227, -29.42046], + [121.025391, -31.952162], + [120.893555, -33.027088], + [123.662109, -33.870416], + [124.584961, -33.431441], + [124.541016, -31.128199], + [122.827148, -29.382175], + [122.124023, -27.916767], + [121.157227, -27.371767] + ] + ] + } + } + ] +} diff --git a/test/examples/line_intersect/in/same-coordinates.geojson b/test/examples/line_intersect/in/same-coordinates.geojson new file mode 100644 index 00000000..efb0b995 --- /dev/null +++ b/test/examples/line_intersect/in/same-coordinates.geojson @@ -0,0 +1,39 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": { + "stroke": "#F00", + "stroke-width": 6 + }, + "geometry": { + "type": "LineString", + "coordinates": [ + [120, -20], + [122.5, -16], + [125, -15], + [127.5, -16], + [130, -20] + ] + } + }, + { + "type": "Feature", + "properties": { + "stroke": "#00F", + "stroke-width": 6 + }, + "geometry": { + "type": "LineString", + "coordinates": [ + [120, -20], + [122.5, -24], + [125, -25], + [127.5, -24], + [130, -20] + ] + } + } + ] +} diff --git a/test/examples/line_intersect/out/2-vertex-segment.geojson b/test/examples/line_intersect/out/2-vertex-segment.geojson new file mode 100644 index 00000000..33f7eedf --- /dev/null +++ b/test/examples/line_intersect/out/2-vertex-segment.geojson @@ -0,0 +1,41 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [125.583754, -14.835723] + } + }, + { + "type": "Feature", + "properties": { + "stroke": "#F00", + "stroke-width": 6 + }, + "geometry": { + "type": "LineString", + "coordinates": [ + [124.584961, -12.768946], + [126.738281, -17.224758] + ] + } + }, + { + "type": "Feature", + "properties": { + "stroke": "#00F", + "stroke-width": 6 + }, + "geometry": { + "type": "LineString", + "coordinates": [ + [123.354492, -15.961329], + [127.22168, -14.008696] + ] + } + } + ] +} diff --git a/test/examples/line_intersect/out/double-intersect.geojson b/test/examples/line_intersect/out/double-intersect.geojson new file mode 100644 index 00000000..52acde8e --- /dev/null +++ b/test/examples/line_intersect/out/double-intersect.geojson @@ -0,0 +1,60 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [119.832884, -19.58857] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [132.808697, -11.630938] + } + }, + { + "type": "Feature", + "properties": { + "stroke": "#F00", + "stroke-width": 6 + }, + "geometry": { + "type": "LineString", + "coordinates": [ + [142.03125, -11.695273], + [138.691406, -16.804541], + [136.40625, -14.604847], + [135.966797, -12.039321], + [131.308594, -11.436955], + [128.232422, -15.36895], + [125.947266, -13.581921], + [121.816406, -18.729502], + [117.421875, -20.632784], + [113.378906, -23.402765], + [114.169922, -26.667096] + ] + } + }, + { + "type": "Feature", + "properties": { + "stroke": "#00F", + "stroke-width": 6 + }, + "geometry": { + "type": "LineString", + "coordinates": [ + [117.861328, -15.029686], + [122.124023, -24.886436], + [132.583008, -22.309426], + [132.890625, -7.754537] + ] + } + } + ] +} diff --git a/test/examples/line_intersect/out/multi-linestring.geojson b/test/examples/line_intersect/out/multi-linestring.geojson new file mode 100644 index 00000000..5a52196c --- /dev/null +++ b/test/examples/line_intersect/out/multi-linestring.geojson @@ -0,0 +1,154 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [117.006519, -20.917359] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [118.554586, -25.732946] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [119.832884, -19.58857] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [121.656735, -23.805914] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [132.658557, -18.734814] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [132.808697, -11.630938] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [135.006479, -11.91514] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [135.197772, -18.403004] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [136.389417, -14.506578] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [136.479474, -14.675333] + } + }, + { + "type": "Feature", + "properties": { + "stroke": "#F00", + "stroke-width": 6 + }, + "geometry": { + "type": "MultiLineString", + "coordinates": [ + [ + [142.03125, -11.695273], + [138.691406, -16.804541], + [136.40625, -14.604847], + [135.966797, -12.039321], + [131.308594, -11.436955], + [128.232422, -15.36895], + [125.947266, -13.581921], + [121.816406, -18.729502], + [117.421875, -20.632784], + [113.378906, -23.402765], + [114.169922, -26.667096] + ], + [ + [117.290039, -27.994401], + [118.87207, -25.165173], + [121.508789, -24.407138], + [122.783203, -19.228177], + [125.683594, -18.771115], + [130.78125, -21.534847], + [133.417969, -17.602139], + [137.768555, -19.55979], + [139.658203, -18.39623] + ] + ] + } + }, + { + "type": "Feature", + "properties": { + "stroke": "#00F", + "stroke-width": 6 + }, + "geometry": { + "type": "MultiLineString", + "coordinates": [ + [ + [117.861328, -15.029686], + [122.124023, -24.886436], + [132.583008, -22.309426], + [132.890625, -7.754537] + ], + [ + [115.751953, -17.014768], + [118.652344, -26.037042], + [118.344727, -28.343065], + [125.068359, -28.652031], + [125.771484, -26.627818], + [131.572266, -26.509905], + [136.40625, -24.886436], + [136.186523, -22.105999], + [134.956055, -20.591652], + [135.439453, -16.214675], + [136.713867, -15.114553], + [134.912109, -11.738302], + [135, -10.141932] + ] + ] + } + } + ] +} diff --git a/test/examples/line_intersect/out/polygons-with-holes.geojson b/test/examples/line_intersect/out/polygons-with-holes.geojson new file mode 100644 index 00000000..a39d1b36 --- /dev/null +++ b/test/examples/line_intersect/out/polygons-with-holes.geojson @@ -0,0 +1,251 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [118.465639, -19.242649] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [120.170188, -33.654475] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [119.582432, -27.434744] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [120.17229, -21.344425] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [120.1132, -24.567108] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [120.201928, -30.393864] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [122.447193, -17.011768] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [122.196098, -33.423855] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [121.100749, -30.505027] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [122.824274, -27.12517] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [123.053712, -24.567108] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [123.377165, -29.942512] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [123.320136, -18.187607] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [124.468085, -29.253959] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [124.392377, -19.890723] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [124.80125, -21.361437] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [124.581243, -33.236589] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [126.041148, -32.826977] + } + }, + { + "type": "Feature", + "properties": { + "stroke": "#F00", + "stroke-width": 6 + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [127.397461, -14.221789], + [119.399414, -18.729502], + [114.741211, -21.289374], + [113.554688, -24.487149], + [114.213867, -28.304381], + [116.235352, -30.977609], + [115.532227, -33.468108], + [116.191406, -34.633208], + [120.629883, -33.541395], + [124.541016, -33.247876], + [128.62793, -32.10119], + [129.726563, -31.765537], + [129.726563, -28.806174], + [128.276367, -28.497661], + [125.727539, -28.459033], + [122.695313, -30.372875], + [120.410156, -30.562261], + [118.476562, -28.998532], + [118.608398, -27.527758], + [123.925781, -27.019984], + [126.5625, -26.549223], + [130.166016, -25.76032], + [130.166016, -23.644524], + [127.617187, -22.917923], + [123.837891, -24.567108], + [119.267578, -24.567108], + [118.564453, -23.281719], + [119.838867, -21.330315], + [123.706055, -21.493964], + [127.089844, -21.0845], + [128.232422, -19.103648], + [127.749023, -17.895114], + [130.297852, -17.182779], + [129.858398, -15.538376], + [129.023438, -14.179186], + [127.397461, -14.221789] + ], + [ + [122.958984, -19.890723], + [125.068359, -19.890723], + [125.068359, -18.187607], + [122.958984, -18.187607], + [122.958984, -19.890723] + ] + ] + } + }, + { + "type": "Feature", + "properties": { + "stroke": "#00F", + "stroke-width": 6 + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [120.849609, -14.85985], + [117.070313, -15.496032], + [117.026367, -17.769612], + [119.663086, -20.468189], + [121.157227, -23.039298], + [120.058594, -24.647017], + [118.344727, -26.076521], + [120.410156, -28.343065], + [120.146484, -30.939924], + [118.256836, -33.027088], + [123.925781, -34.885931], + [126.123047, -33.687782], + [125.947266, -31.840233], + [124.057617, -28.536275], + [122.080078, -26.273714], + [123.442383, -23.885838], + [125.200195, -22.796439], + [124.277344, -19.47695], + [120.849609, -14.85985] + ], + [ + [121.157227, -27.371767], + [121.157227, -29.42046], + [121.025391, -31.952162], + [120.893555, -33.027088], + [123.662109, -33.870416], + [124.584961, -33.431441], + [124.541016, -31.128199], + [122.827148, -29.382175], + [122.124023, -27.916767], + [121.157227, -27.371767] + ] + ] + } + } + ] +} diff --git a/test/examples/line_intersect/out/same-coordinates.geojson b/test/examples/line_intersect/out/same-coordinates.geojson new file mode 100644 index 00000000..1b69013f --- /dev/null +++ b/test/examples/line_intersect/out/same-coordinates.geojson @@ -0,0 +1,55 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [120, -20] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [130, -20] + } + }, + { + "type": "Feature", + "properties": { + "stroke": "#F00", + "stroke-width": 6 + }, + "geometry": { + "type": "LineString", + "coordinates": [ + [120, -20], + [122.5, -16], + [125, -15], + [127.5, -16], + [130, -20] + ] + } + }, + { + "type": "Feature", + "properties": { + "stroke": "#00F", + "stroke-width": 6 + }, + "geometry": { + "type": "LineString", + "coordinates": [ + [120, -20], + [122.5, -24], + [125, -25], + [127.5, -24], + [130, -20] + ] + } + } + ] +} From 63ce12de7a95aa96da320858db5bf80e413794fb Mon Sep 17 00:00:00 2001 From: Lukas Himsel Date: Mon, 5 Sep 2022 15:46:49 +0200 Subject: [PATCH 66/82] package publishabe, rm git deps, fix equality dep --- lib/src/booleans/boolean_equal.dart | 7 ++++--- pubspec.yaml | 6 ++---- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/lib/src/booleans/boolean_equal.dart b/lib/src/booleans/boolean_equal.dart index 812d6200..30a68712 100644 --- a/lib/src/booleans/boolean_equal.dart +++ b/lib/src/booleans/boolean_equal.dart @@ -31,8 +31,9 @@ bool booleanEqual( } var equality = Equality( - precision: precision, - shiftedPolygons: shiftedPolygon, - reversedGeometries: direction); + precision: precision, + shiftedPolygon: shiftedPolygon, + direction: direction, + ); return equality.compare(cleanCoords(feature1), cleanCoords(feature2)); } diff --git a/pubspec.yaml b/pubspec.yaml index b7d89ca9..c02d252d 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -5,13 +5,11 @@ environment: sdk: ">=2.12.0 <3.0.0" homepage: https://github.com/dartclub/turf_dart repository: https://github.com/dartclub/turf_dart -publish_to: none dependencies: json_annotation: ^4.4.0 - turf_equality: ^0.0.1 - sweepline_intersections: - git: https://github.com/dartclub/sweepline_intersections.git + turf_equality: ^0.0.2 + sweepline_intersections: ^0.0.1 turf_pip: ^0.0.1+1 rbush: ^1.1.0 From ad47ac43862f424066a8d47617b2c241bb8e7796 Mon Sep 17 00:00:00 2001 From: Lukas Himsel Date: Mon, 5 Sep 2022 15:47:35 +0200 Subject: [PATCH 67/82] update params in equality --- lib/src/booleans/boolean_equal.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/src/booleans/boolean_equal.dart b/lib/src/booleans/boolean_equal.dart index 30a68712..7bc0802c 100644 --- a/lib/src/booleans/boolean_equal.dart +++ b/lib/src/booleans/boolean_equal.dart @@ -32,8 +32,8 @@ bool booleanEqual( var equality = Equality( precision: precision, - shiftedPolygon: shiftedPolygon, - direction: direction, + shiftedPolygons: shiftedPolygon, + reversedGeometries: direction, ); return equality.compare(cleanCoords(feature1), cleanCoords(feature2)); } From 775f0eee9470364185ac8d224372699d08786d41 Mon Sep 17 00:00:00 2001 From: armantorkzaban Date: Wed, 7 Sep 2022 14:50:02 +0200 Subject: [PATCH 68/82] mod. on valid to cover the std. - MutiPs' 'finite' --- lib/src/booleans/boolean_crosses.dart | 5 ++--- lib/src/booleans/boolean_valid.dart | 31 +++++++++++++++------------ lib/src/line_intersect.dart | 10 ++++----- test/booleans/crosses_test.dart | 2 +- test/booleans/valid_test.dart | 1 - 5 files changed, 25 insertions(+), 24 deletions(-) diff --git a/lib/src/booleans/boolean_crosses.dart b/lib/src/booleans/boolean_crosses.dart index 313ba67a..131864ad 100644 --- a/lib/src/booleans/boolean_crosses.dart +++ b/lib/src/booleans/boolean_crosses.dart @@ -116,9 +116,8 @@ bool doLineStringsCross(LineString lineString1, LineString lineString2) { bool doLineStringAndPolygonCross(LineString lineString, Polygon polygon) { Feature line = polygonToLine(polygon) as Feature; var doLinesIntersect = lineIntersect(lineString, line); - if (doLinesIntersect.features.isNotEmpty) { - return true; - } + if (doLinesIntersect.features.isNotEmpty) return true; + return false; } diff --git a/lib/src/booleans/boolean_valid.dart b/lib/src/booleans/boolean_valid.dart index 3c8e1adf..5847a8ef 100644 --- a/lib/src/booleans/boolean_valid.dart +++ b/lib/src/booleans/boolean_valid.dart @@ -1,3 +1,4 @@ +import 'package:turf/polygon_to_line.dart'; import 'package:turf/src/booleans/boolean_disjoint.dart'; import 'package:turf/src/booleans/boolean_point_on_line.dart'; import 'package:turf/src/meta/extensions.dart'; @@ -22,11 +23,17 @@ bool checkRingsForSpikesPunctures(List geom) { return false; } -bool checkPolygonAgainstOthers( - Polygon poly, List>> geom, int index) { - for (var i = index + 1; i < geom.length; i++) { - if (!booleanDisjoint(poly, Polygon(coordinates: geom[i]))) { - if (booleanCrosses(poly, LineString(coordinates: geom[i][0]))) { +bool checkPolygonAgainstOthers(Polygon poly, MultiPolygon geom, int index) { + for (var i = index + 1; i < geom.coordinates.length; i++) { + if (!booleanDisjoint(poly, Polygon(coordinates: geom.coordinates[i]))) { + LineString lineS = LineString(coordinates: geom.coordinates[i][0]); + if (booleanCrosses(poly, lineS)) { + Feature line = polygonToLine(poly) as Feature; + var doLinesIntersect = lineIntersect(lineS, line); + + /// http://portal.opengeospatial.org/files/?artifact_id=829 p.22 - 2 : + /// 1 intersection Point is 'finite', therefore passes the test + if (doLinesIntersect.features.length == 1) return true; return false; } } @@ -34,12 +41,13 @@ bool checkPolygonAgainstOthers( return true; } -/// booleanValid checks if the geometry is a valid according to the OGC Simple Feature Specification. +/// booleanValid checks if the geometry is a valid according to the OGC Simple +/// Feature Specification. /// Take a [Feature] or a [GeometryType] -/// returns a boolean true/false /// example /// ```dart -/// var line = LineString(coordinates:[Position.of([1, 1]), Position.of([1, 2]), Position.of([1, 3]), Position.of([1, 4])]); +/// var line = LineString(coordinates:[Position.of([1, 1]), Position.of([1, 2]), +/// Position.of([1, 3]), Position.of([1, 4])]); /// booleanValid(line); // => true /// booleanValid({foo: "bar"}); // => false /// ``` @@ -109,21 +117,17 @@ bool booleanValid(GeoJSONObject feature) { for (var ii = 0; ii < poly.length; ii++) { if (poly[ii].length < 4) { - print('length is short'); return false; } if (!checkRingsClose(poly[ii])) { - print('ring closure issues'); return false; } if (checkRingsForSpikesPunctures(poly[ii])) { - print('spikes'); return false; } if (ii == 0) { if (!checkPolygonAgainstOthers( - Polygon(coordinates: poly), geom.coordinates, i)) { - print('comparison fails'); + Polygon(coordinates: poly), geom, i)) { return false; } } @@ -131,7 +135,6 @@ bool booleanValid(GeoJSONObject feature) { if (lineIntersect(Polygon(coordinates: [poly[0]]), Polygon(coordinates: [poly[ii]])).features.length > 1) { - print('intersects'); return false; } } diff --git a/lib/src/line_intersect.dart b/lib/src/line_intersect.dart index 9ff475d0..e45a0094 100644 --- a/lib/src/line_intersect.dart +++ b/lib/src/line_intersect.dart @@ -5,7 +5,7 @@ import '../helpers.dart'; /// Takes any [LineString] or [Polygon] and returns the intersecting [Point](s). /// [removeDuplicates=true] removes duplicate intersections, /// [ignoreSelfIntersections=false] ignores self-intersections on input features -/// Returns [FeatureCollection] point(s) that intersect both +/// Returns a [FeatureCollection] containing point(s) that intersect both /// example: /// ```dart /// var line1 = LineString(coordinates:[ @@ -23,25 +23,25 @@ FeatureCollection lineIntersect(GeoJSONObject line1, GeoJSONObject line2, {bool removeDuplicates = true, bool ignoreSelfIntersections = false}) { var features = []; if (line1 is FeatureCollection) { - features = features..addAll(line1.features); + features.addAll(line1.features); } else if (line1 is Feature) { features.add(line1); } else if (line1 is LineString || line1 is Polygon || line1 is MultiLineString || line1 is MultiPolygon) { - features.add(Feature(geometry: line1 as GeometryObject)); + features.add(Feature(geometry: line1 as GeometryType)); } if (line2 is FeatureCollection) { - features = features..addAll(line2.features); + features.addAll(line2.features); } else if (line2 is Feature) { features.add(line2); } else if (line2 is LineString || line2 is Polygon || line2 is MultiLineString || line2 is MultiPolygon) { - features.add(Feature(geometry: line2 as GeometryObject)); + features.add(Feature(geometry: line2 as GeometryType)); } var intersections = sweeplineIntersections( diff --git a/test/booleans/crosses_test.dart b/test/booleans/crosses_test.dart index 25d8d9b5..7b79a27a 100644 --- a/test/booleans/crosses_test.dart +++ b/test/booleans/crosses_test.dart @@ -38,7 +38,7 @@ main() { var feature1 = (inGeom as FeatureCollection).features[0]; var feature2 = inGeom.features[1]; expect(booleanCrosses(feature1.geometry!, feature2.geometry!), - false); + isFalse); }, ); } diff --git a/test/booleans/valid_test.dart b/test/booleans/valid_test.dart index 1011c37d..916c0809 100644 --- a/test/booleans/valid_test.dart +++ b/test/booleans/valid_test.dart @@ -35,7 +35,6 @@ main() { test( file.path, () { - print(file.path); // False Fixtures if (file is File && file.path.endsWith('.geojson')) { var inSource = file.readAsStringSync(); From 7b61f7f05641cbabebb279ddc19abd9a97d950ab Mon Sep 17 00:00:00 2001 From: armantorkzaban Date: Sat, 10 Sep 2022 16:22:45 +0200 Subject: [PATCH 69/82] RFCs resolved - readied for merge --- lib/src/booleans/boolean_clockwise.dart | 39 ++++++++++++------- lib/src/booleans/boolean_concave.dart | 5 ++- lib/src/booleans/boolean_contains.dart | 2 +- lib/src/booleans/boolean_equal.dart | 2 +- .../booleans/boolean_point_in_polygon.dart | 36 +++++++---------- lib/src/invariant.dart | 4 +- lib/src/line_intersect.dart | 31 ++++++++------- lib/src/line_overlap.dart | 36 ++++++++++++----- pubspec.yaml | 2 +- test/booleans/clockwise_test.dart | 34 +++++++--------- test/booleans/concave_test.dart | 4 +- test/components/line_intersect_test.dart | 3 +- 12 files changed, 106 insertions(+), 92 deletions(-) diff --git a/lib/src/booleans/boolean_clockwise.dart b/lib/src/booleans/boolean_clockwise.dart index cb9aeb52..9333c241 100644 --- a/lib/src/booleans/boolean_clockwise.dart +++ b/lib/src/booleans/boolean_clockwise.dart @@ -2,25 +2,36 @@ import 'package:turf/src/invariant.dart'; import '../../helpers.dart'; -/// Takes a ring and return true or false whether or not the ring is clockwise or counter-clockwise. -/// Takes a [Feature]or [LineString] or a [List] to be evaluated +/// Takes a ring and return [true] or [false] whether or not the ring is clockwise +/// or counter-clockwise. +/// Takes a [Feature] or[LineString] or a [List] to be +/// evaluated. /// example: /// ```dart -/// var clockwiseRing = LineString(coordinates: [Position.of([0,0]),Position.of([1,1]),Position.of([1,0]),Position.of([0,0])]); -/// var counterClockwiseRing = LineString(coordinates: [Position.of([0,0]),Position.of([1,0]),Position.of([1,1]),Position.of([0,0])]); +/// var clockwiseRing = LineString( +/// coordinates: [ +/// Position.of([0, 0]), +/// Position.of([1, 1]), +/// Position.of([1, 0]), +/// Position.of([0, 0]) +/// ], +/// ); +/// var counterClockwiseRing = LineString( +/// coordinates: [ +/// Position.of([0, 0]), +/// Position.of([1, 0]), +/// Position.of([1, 1]), +/// Position.of([0, 0]) +/// ], +/// ); /// -/// booleanClockwise(clockwiseRing) +/// booleanClockwise(clockwiseRing); /// //=true -/// booleanClockwise(counterClockwiseRing) +/// booleanClockwise(counterClockwiseRing); /// //=false /// ``` -bool booleanClockwise(dynamic line) { - if (line is List) { - if (line is! List) { - throw UnsupportedError(" type $line is not supperted"); - } - } - var ring = getCoords(line); +bool booleanClockwise(LineString line) { + var ring = getCoords(line) as List; num sum = 0; int i = 1; Position prev; @@ -29,7 +40,7 @@ bool booleanClockwise(dynamic line) { while (i < ring.length) { prev = cur ?? ring[0]; cur = ring[i]; - sum += (cur![0]! - prev[0]!) * (cur[1]! + prev[1]!); + sum += (cur[0]! - prev[0]!) * (cur[1]! + prev[1]!); i++; } return sum > 0; diff --git a/lib/src/booleans/boolean_concave.dart b/lib/src/booleans/boolean_concave.dart index b8ed1143..1e13e193 100644 --- a/lib/src/booleans/boolean_concave.dart +++ b/lib/src/booleans/boolean_concave.dart @@ -1,6 +1,7 @@ import 'package:turf/helpers.dart'; -/// Takes a [Polygon] and returns true or false as to whether it is concave or not. +/// Takes a [Polygon] and returns [true] or [false] as to whether it is concave +/// or not. /// example: /// ```dart /// var convexPolygon = Polygon(coordinates: [ @@ -12,7 +13,7 @@ import 'package:turf/helpers.dart'; /// Position.of([0, 0]) /// ] /// ]); -/// booleanConcave(convexPolygon) +/// booleanConcave(convexPolygon); /// //=false /// ``` bool booleanConcave(Polygon polygon) { diff --git a/lib/src/booleans/boolean_contains.dart b/lib/src/booleans/boolean_contains.dart index 3d764fcf..74daa083 100644 --- a/lib/src/booleans/boolean_contains.dart +++ b/lib/src/booleans/boolean_contains.dart @@ -3,7 +3,7 @@ import 'package:turf/turf.dart'; import 'boolean_point_in_polygon.dart'; import 'boolean_point_on_line.dart'; -/// Boolean-contains returns True if the second geometry is completely contained +/// [booleanContains] returns [true] if the second geometry is completely contained /// by the first geometry. /// The interiors of both geometries must intersect and, the interior and /// boundary of the secondary must not intersect the exterior of the primary. diff --git a/lib/src/booleans/boolean_equal.dart b/lib/src/booleans/boolean_equal.dart index 7bc0802c..8600dcb1 100644 --- a/lib/src/booleans/boolean_equal.dart +++ b/lib/src/booleans/boolean_equal.dart @@ -10,7 +10,7 @@ import '../clean_coords.dart'; /// of each other but they have similar [Position]s, they will be considered the /// same. If [shiftedPolygon] is [true], two [Polygon]s with shifted [Position]s /// are considered the same. -/// Returns [true] if the objects are equal, false otherwise +/// Returns [true] if the objects are equal, [false] otherwise /// example: /// var pt1 = Point(coordinates: Position.of([0, 0])); /// var pt2 = Point(coordinates: Position.of([0, 0])); diff --git a/lib/src/booleans/boolean_point_in_polygon.dart b/lib/src/booleans/boolean_point_in_polygon.dart index 64f516f1..9e20680b 100644 --- a/lib/src/booleans/boolean_point_in_polygon.dart +++ b/lib/src/booleans/boolean_point_in_polygon.dart @@ -5,11 +5,12 @@ import 'package:turf_pip/turf_pip.dart'; import '../../helpers.dart'; +import '../invariant.dart'; /// Takes a [Point], and a [Polygon] or [MultiPolygon]and determines if the -/// [Point] resides within the [Polygon]. The [polygon] can be convex or concave. +/// [Point] resides within the [Polygon]. The [Polygon] can be convex or concave. /// The function accounts for holes. By taking a [Feature] or a -/// [Feature]. [ignoreBoundary=false] should be set to [true] if +/// [Feature]<[MultiPolygon]>. [ignoreBoundary=false] should be set to [true] if /// [Polygon]'s boundary should be ignored when determining if the [Point] is /// inside the [Polygon], otherwise, false. /// example: @@ -27,28 +28,18 @@ import '../../helpers.dart'; /// ``` bool booleanPointInPolygon(Position point, GeoJSONObject polygon, {bool ignoreBoundary = false}) { - GeometryType? geom; List>>? polys; BBox? bbox = polygon.bbox; - Exception exception = Exception('${polygon.type} is not supported'); + Exception _exception = Exception('${polygon.type} is not supported'); - if (polygon is Feature) { - if (polygon.geometry is Polygon || polygon.geometry is MultiPolygon) { - return booleanPointInPolygon(point, polygon.geometry!); - } else { - throw exception; - } - } else if (polygon is GeometryType) { - if (polygon is Polygon && polygon.coordinates.isNotEmpty) { - geom = polygon; - polys = [geom.coordinates]; - } else if (polygon is MultiPolygon && polygon.coordinates.isNotEmpty) { - geom = polygon; - polys = geom.coordinates; - } + var theGeom = getGeom(polygon); + if (theGeom is Polygon) { + polys = [theGeom.coordinates]; + } else if (theGeom is MultiPolygon) { + polys = theGeom.coordinates; } else { - throw exception; + throw _exception; } // Quick elimination if point is not inside bbox @@ -56,18 +47,17 @@ bool booleanPointInPolygon(Position point, GeoJSONObject polygon, return false; } - var result = false; - for (var i = 0; i < polys!.length; ++i) { + for (var i = 0; i < polys.length; ++i) { var polyResult = pointInPolygon( Point(coordinates: point), Polygon(coordinates: polys[i])); if (polyResult == PointInPolygonResult.isOnEdge) { return ignoreBoundary ? false : true; } else if (polyResult == PointInPolygonResult.isInside) { - result = true; + return true; } } - return result; + return false; } bool _inBBox(Position pt, BBox bbox) { diff --git a/lib/src/invariant.dart b/lib/src/invariant.dart index b3309747..bdfa5d5a 100644 --- a/lib/src/invariant.dart +++ b/lib/src/invariant.dart @@ -27,7 +27,6 @@ Position getCoord(dynamic coord) { } /// Unwraps coordinates from a [Feature], [GeometryObject] or a [List] -/// /// Gets a [List], [GeometryObject] or a [Feature] or a [List] and /// returns [List]. /// For example: @@ -77,8 +76,7 @@ _getCoordsForGeometry(GeometryObject geom) { return (geom as GeometryType).coordinates; } -// TODO -/// Get Geometry or Geometries from [Feature] or [GeometryType] +/// Get Geometry or Geometries from [Feature] or [GeometryCollection] /// Returns [List] in case geojson is a [GeometryCollection] and a /// [GeometryType] if geojson is a simple [GeometryType]. /// example: diff --git a/lib/src/line_intersect.dart b/lib/src/line_intersect.dart index e45a0094..d1be8ec3 100644 --- a/lib/src/line_intersect.dart +++ b/lib/src/line_intersect.dart @@ -19,8 +19,13 @@ import '../helpers.dart'; /// var intersects = lineIntersect(line1, line2); /// //addToMap /// var addToMap = [line1, line2, intersects] -FeatureCollection lineIntersect(GeoJSONObject line1, GeoJSONObject line2, - {bool removeDuplicates = true, bool ignoreSelfIntersections = false}) { +/// ``` +FeatureCollection lineIntersect( + GeoJSONObject line1, + GeoJSONObject line2, { + bool removeDuplicates = true, + bool ignoreSelfIntersections = false, +}) { var features = []; if (line1 is FeatureCollection) { features.addAll(line1.features); @@ -46,21 +51,19 @@ FeatureCollection lineIntersect(GeoJSONObject line1, GeoJSONObject line2, var intersections = sweeplineIntersections( FeatureCollection(features: features), ignoreSelfIntersections); - - var results = []; + Set unique = {}; if (removeDuplicates) { - Set unique = {}; for (var intersection in intersections) { - if (!unique.contains(intersection)) { - unique.add(intersection); - results.add(intersection); - } + unique.add(intersection); } - } else { - results = intersections; } return FeatureCollection( - features: results - .map((r) => Feature(geometry: Point(coordinates: r))) - .toList()); + features: (removeDuplicates ? unique.toList() : intersections) + .map( + (r) => Feature( + geometry: Point(coordinates: r), + ), + ) + .toList(), + ); } diff --git a/lib/src/line_overlap.dart b/lib/src/line_overlap.dart index 86392537..5f004d2f 100644 --- a/lib/src/line_overlap.dart +++ b/lib/src/line_overlap.dart @@ -8,15 +8,31 @@ import 'package:turf/src/invariant.dart'; import 'package:turf/src/meta/feature.dart'; import 'package:turf_equality/turf_equality.dart'; -/// Takes any [LineString] or [Polygon] and returns the overlapping [LineString]s between both [Feature]s. -/// [line1] is a Feature or any [LineString] or [Polygon] -/// [line2] is a Feature or any [LineString] or [Polygon] -/// [options.tolerance=0] Tolerance distance to match overlapping line segments (in kilometers) -/// returns a [FeatureCollection] lines(s) that are overlapping between both [Feature]s +/// Takes any [LineString] or [Polygon] and returns the overlapping [LineString]s +/// between both [Feature]s. [line1] is a [Feature]<[LineString]|[MultiLineString] +/// |[Polygon]|[MultiPolygon]> or any [LineString] or [Polygon], [line2] is a +/// [Feature]<[LineString]|[MultiLineString]|[Polygon]|[MultiPolygon]> or any +/// [LineString] or [Polygon]. [tolerance=0] Tolerance distance to match +/// overlapping line segments (in kilometers) returns a [FeatureCollection]<[LineString]> +/// lines(s) that are overlapping between both [Feature]s. /// example /// ```dart -/// var line1 = LineString(coordiantes:[Position.of([115, -35]), Position.of([125, -30]), Position.of([135, -30]), Position.of([145, -35])]); -/// var line2 = LineString(coordiantes:[Position.of([115, -25]), Position.of([125, -30]), Position.of([135, -30]), Position.of([145, -25])]); +/// var line1 = LineString( +/// coordinates: [ +/// Position.of([115, -35]), +/// Position.of([125, -30]), +/// Position.of([135, -30]), +/// Position.of([145, -35]) +/// ], +/// ); +/// var line2 = LineString( +/// coordinates: [ +/// Position.of([115, -25]), +/// Position.of([125, -30]), +/// Position.of([135, -30]), +/// Position.of([145, -25]) +/// ], +/// ); /// var overlapping = lineOverlap(line1, line2); /// //addToMap /// var addToMap = [line1, line2, overlapping] @@ -117,7 +133,8 @@ FeatureCollection lineOverlap( Point(coordinates: coordsMatch[1])) .properties!['dist'] <= tolerance) { - // Do not define (doesOverlap = true) since more matches can occur within the same segment + // Do not define doesOverlap = true since more matches can occur + // within the same segment // doesOverlaps = true; if (overlapSegment != null) { var combinedSegment = @@ -168,7 +185,8 @@ Feature? concatSegment( geom.add(coords[0]); } else { return null; - } // If the overlap leaves the segment unchanged, return undefined so that this can be identified. + } // If the overlap leaves the segment unchanged, return null so that this can be + // identified. // Otherwise return the mutated line. return line; diff --git a/pubspec.yaml b/pubspec.yaml index c02d252d..1497e2e9 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -9,9 +9,9 @@ repository: https://github.com/dartclub/turf_dart dependencies: json_annotation: ^4.4.0 turf_equality: ^0.0.2 - sweepline_intersections: ^0.0.1 turf_pip: ^0.0.1+1 rbush: ^1.1.0 + sweepline_intersections: ^0.0.3+1 dev_dependencies: dartclub_lint: ^0.4.2 diff --git a/test/booleans/clockwise_test.dart b/test/booleans/clockwise_test.dart index 1ed121e1..21011ba2 100644 --- a/test/booleans/clockwise_test.dart +++ b/test/booleans/clockwise_test.dart @@ -9,25 +9,19 @@ main() { group( 'clockwise', () { - test('', () { - var list = [ - Position.of([10, 10]), - Position.of([11, 10]), - Position.of([12, 10]), - Position.of([13, 10]), - ]; - expect(booleanClockwise(list), true); - }); + test( + 'simple LineString', + () { + var list = [ + Position.of([10, 10]), + Position.of([11, 10]), + Position.of([12, 10]), + Position.of([13, 10]), + ]; + expect(booleanClockwise(LineString(coordinates: list)), true); + }, + ); - test('', () { - var list = [ - [10, 10], - [11, 10], - [12, 10], - [13, 10], - ]; - expect(() => booleanClockwise(list), throwsA(isA())); - }); var inDir = Directory('./test/examples/booleans/clockwise/true'); for (var file in inDir.listSync(recursive: true)) { if (file is File && file.path.endsWith('.geojson')) { @@ -38,7 +32,7 @@ main() { var inGeom = GeoJSONObject.fromJson(json); var feature0 = (inGeom as FeatureCollection).features[0]; - expect(booleanClockwise(feature0), true); + expect(booleanClockwise(feature0.geometry as LineString), true); }); } } @@ -54,7 +48,7 @@ main() { dynamic json = jsonDecode(inSource); var inGeom = GeoJSONObject.fromJson(json); var feature0 = (inGeom as FeatureCollection).features[0]; - expect(booleanClockwise(feature0), false); + expect(booleanClockwise(feature0.geometry as LineString), false); }, ); } diff --git a/test/booleans/concave_test.dart b/test/booleans/concave_test.dart index 0d736661..debc3869 100644 --- a/test/booleans/concave_test.dart +++ b/test/booleans/concave_test.dart @@ -18,7 +18,7 @@ main() { () { // True Fixtures var inSource = file.readAsStringSync(); - dynamic json = jsonDecode(inSource); + var json = jsonDecode(inSource); var inGeom = GeoJSONObject.fromJson(json); var feature = (inGeom as FeatureCollection).features[0]; expect(booleanConcave(feature.geometry as Polygon), true); @@ -35,7 +35,7 @@ main() { () { // False Fixtures var inSource = file.readAsStringSync(); - dynamic json = jsonDecode(inSource); + var json = jsonDecode(inSource); var inGeom = GeoJSONObject.fromJson(json); var feature = (inGeom as FeatureCollection).features[0]; expect(booleanConcave(feature.geometry as Polygon), false); diff --git a/test/components/line_intersect_test.dart b/test/components/line_intersect_test.dart index cda355de..06b8725e 100644 --- a/test/components/line_intersect_test.dart +++ b/test/components/line_intersect_test.dart @@ -86,8 +86,7 @@ main() { ); // "support Geometry Objects" expect(lineIntersect(line1, line2).features, isNotEmpty); -// "support Feature Collection" - + // "support Feature Collection" expect( lineIntersect( FeatureCollection( From 3baae8bdb9d8114c0aae694e1e4fb7471d6ab0db Mon Sep 17 00:00:00 2001 From: armantorkzaban Date: Sat, 10 Sep 2022 16:47:55 +0200 Subject: [PATCH 70/82] return type of getGeom --- lib/src/invariant.dart | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/src/invariant.dart b/lib/src/invariant.dart index bdfa5d5a..1fac8995 100644 --- a/lib/src/invariant.dart +++ b/lib/src/invariant.dart @@ -87,11 +87,9 @@ _getCoordsForGeometry(GeometryObject geom) { /// )); /// var geom = getGeom(feature) /// //= Point(coordinates: Position.of([110, 40])) -getGeom(GeoJSONObject geojson) { +GeoJSONObject getGeom(GeoJSONObject geojson) { if (geojson is Feature) { - return (geojson).geometry; - } else if (geojson is GeometryCollection) { - return geojson.geometries; + return geojson.geometry!; } return geojson; } From c783bece761cc290c931b7a27f7fb4168e2fce59 Mon Sep 17 00:00:00 2001 From: armantorkzaban Date: Sat, 10 Sep 2022 22:09:47 +0200 Subject: [PATCH 71/82] linter effect! --- README.md | 2 +- benchmark/explode_benchmark.dart | 2 +- example/main.dart | 2 +- lib/src/booleans/boolean_contains.dart | 9 +++++++-- lib/src/geojson.dart | 4 ++-- lib/src/invariant.dart | 2 +- pubspec.yaml | 2 +- test/booleans/clockwise_test.dart | 2 +- test/booleans/concave_test.dart | 2 +- test/booleans/contains_test.dart | 2 +- test/booleans/crosses_test.dart | 2 +- test/booleans/disjoint_test.dart | 2 +- test/booleans/intersect_test.dart | 2 +- test/booleans/parallel_test.dart | 2 +- test/booleans/point_in_polygon_test.dart | 4 ++-- test/booleans/point_on_line_test.dart | 2 +- test/booleans/touches_test.dart | 2 +- test/booleans/valid_test.dart | 2 +- test/components/bbox_polygon_test.dart | 2 +- test/components/bbox_test.dart | 2 +- test/components/bearing_test.dart | 2 +- test/components/center_test.dart | 2 +- test/components/clean_coords_test.dart | 2 +- test/components/cluster_test.dart | 2 +- test/components/destination_test.dart | 2 +- test/components/explode_test.dart | 2 +- test/components/geojson_test.dart | 10 +++++----- test/components/helpers_test.dart | 2 +- test/components/intersection_test.dart | 2 +- test/components/invariant_test.dart | 2 +- test/components/line_intersect_test.dart | 2 +- test/components/line_overlap.dart | 2 +- test/components/line_segment_test.dart | 2 +- test/components/meta_test.dart | 2 +- test/components/midpoint_test.dart | 6 +++--- test/components/nearest_point_on_line_test.dart | 2 +- test/components/polygon_to_line_test.dart | 2 +- test/components/polyline.dart | 2 +- test/components/rhumb_bearing_test.dart | 2 +- test/components/truncate_test.dart | 2 +- 40 files changed, 54 insertions(+), 49 deletions(-) diff --git a/README.md b/README.md index 18c4b08b..e6c5f202 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ Feature poly = Feature( ]), ); -main() { +void main() { var total = segmentReduce( poly, (previousValue, currentSegment, initialValue, featureIndex, diff --git a/benchmark/explode_benchmark.dart b/benchmark/explode_benchmark.dart index 782e0ff6..52f18084 100644 --- a/benchmark/explode_benchmark.dart +++ b/benchmark/explode_benchmark.dart @@ -12,7 +12,7 @@ var poly = Polygon(coordinates: [ ], ]); -main() { +void main() { group('explode', () { benchmark('simple', () { explode(poly); diff --git a/example/main.dart b/example/main.dart index 498079ef..0ee0b2be 100644 --- a/example/main.dart +++ b/example/main.dart @@ -18,7 +18,7 @@ Feature poly = Feature( ]), ); -main() { +void main() { var total = segmentReduce( poly, (previousValue, currentSegment, initialValue, featureIndex, diff --git a/lib/src/booleans/boolean_contains.dart b/lib/src/booleans/boolean_contains.dart index 74daa083..90045e66 100644 --- a/lib/src/booleans/boolean_contains.dart +++ b/lib/src/booleans/boolean_contains.dart @@ -10,8 +10,13 @@ import 'boolean_point_on_line.dart'; /// Boolean-contains returns the exact opposite result of the `turf/boolean-within`. /// example: /// ```dart -/// var line = LineString(coordinates: [Position.of([1, 1]), Position.of([1, 2]), Position.of([1, 3]), Position.of([1, 4])]); -/// var point = Point(cooridantes:Position.of([1, 2])); +/// var line = LineString(coordinates: [ +/// Position.of([1, 1]), +/// Position.of([1, 2]), +/// Position.of([1, 3]), +/// Position.of([1, 4]) +/// ]); +/// var point = Point(coordinates: Position.of([1, 2])); /// booleanContains(line, point); /// //=true /// ``` diff --git a/lib/src/geojson.dart b/lib/src/geojson.dart index 75f2e3b6..eacf22d5 100644 --- a/lib/src/geojson.dart +++ b/lib/src/geojson.dart @@ -61,7 +61,7 @@ abstract class GeoJSONObject { } } - toJson(); + Map toJson(); GeoJSONObject clone(); } @@ -182,7 +182,7 @@ abstract class CoordinateType implements Iterable { bool get isSigned; - _untilSigned(val, limit) { + num _untilSigned(num val, limit) { if (val > limit) { return _untilSigned(val - 360, limit); } else { diff --git a/lib/src/invariant.dart b/lib/src/invariant.dart index 1fac8995..20bd36f5 100644 --- a/lib/src/invariant.dart +++ b/lib/src/invariant.dart @@ -68,7 +68,7 @@ List getCoords(dynamic coords) { "Parameter must be a List, Geometry, Feature. coords Feature, Geometry Object or a List"); } -_getCoordsForGeometry(GeometryObject geom) { +List _getCoordsForGeometry(GeometryObject geom) { if (geom is Point || geom is GeometryCollection) { throw Exception("Type must contain a list of Positions e.g Polygon"); } diff --git a/pubspec.yaml b/pubspec.yaml index 1497e2e9..c1f54c7a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -14,7 +14,7 @@ dependencies: sweepline_intersections: ^0.0.3+1 dev_dependencies: - dartclub_lint: ^0.4.2 + dartclub_lint: ^1.0.0 test: ^1.19.3 json_serializable: ^6.1.1 build_runner: ^2.1.5 diff --git a/test/booleans/clockwise_test.dart b/test/booleans/clockwise_test.dart index 21011ba2..599ecc4f 100644 --- a/test/booleans/clockwise_test.dart +++ b/test/booleans/clockwise_test.dart @@ -5,7 +5,7 @@ import 'package:test/test.dart'; import 'package:turf/helpers.dart'; import 'package:turf/src/booleans/boolean_clockwise.dart'; -main() { +void main() { group( 'clockwise', () { diff --git a/test/booleans/concave_test.dart b/test/booleans/concave_test.dart index debc3869..33f2df28 100644 --- a/test/booleans/concave_test.dart +++ b/test/booleans/concave_test.dart @@ -5,7 +5,7 @@ import 'package:test/test.dart'; import 'package:turf/helpers.dart'; import 'package:turf/src/booleans/boolean_concave.dart'; -main() { +void main() { group( 'concave', () { diff --git a/test/booleans/contains_test.dart b/test/booleans/contains_test.dart index de9057af..7e89cfce 100644 --- a/test/booleans/contains_test.dart +++ b/test/booleans/contains_test.dart @@ -5,7 +5,7 @@ import 'package:test/test.dart'; import 'package:turf/helpers.dart'; import 'package:turf/src/booleans/boolean_contains.dart'; -main() { +void main() { group( 'contains', () { diff --git a/test/booleans/crosses_test.dart b/test/booleans/crosses_test.dart index 7b79a27a..f2faaf4d 100644 --- a/test/booleans/crosses_test.dart +++ b/test/booleans/crosses_test.dart @@ -5,7 +5,7 @@ import 'package:test/test.dart'; import 'package:turf/helpers.dart'; import 'package:turf/src/booleans/boolean_crosses.dart'; -main() { +void main() { group( 'boolean_crosses', () { diff --git a/test/booleans/disjoint_test.dart b/test/booleans/disjoint_test.dart index 74aa07ef..6a547138 100644 --- a/test/booleans/disjoint_test.dart +++ b/test/booleans/disjoint_test.dart @@ -5,7 +5,7 @@ import 'package:test/test.dart'; import 'package:turf/helpers.dart'; import 'package:turf/src/booleans/boolean_disjoint.dart'; -main() { +void main() { group('boolean_disjoint', () { // True Fixtures var inDir = Directory('./test/examples/booleans/disjoint/test/true'); diff --git a/test/booleans/intersect_test.dart b/test/booleans/intersect_test.dart index f5da0f8e..3769445e 100644 --- a/test/booleans/intersect_test.dart +++ b/test/booleans/intersect_test.dart @@ -5,7 +5,7 @@ import 'package:test/test.dart'; import 'package:turf/helpers.dart'; import 'package:turf/src/booleans/boolean_intersect.dart'; -main() { +void main() { var featureCollection = FeatureCollection(features: [ Feature( properties: {"fill": "#ff0000"}, diff --git a/test/booleans/parallel_test.dart b/test/booleans/parallel_test.dart index eefaf0d8..3e693208 100644 --- a/test/booleans/parallel_test.dart +++ b/test/booleans/parallel_test.dart @@ -5,7 +5,7 @@ import 'package:test/test.dart'; import 'package:turf/src/booleans/boolean_parallel.dart'; import 'package:turf/turf.dart'; -main() { +void main() { group( 'boolean-overlap', () { diff --git a/test/booleans/point_in_polygon_test.dart b/test/booleans/point_in_polygon_test.dart index ffdfc056..9cc9a12e 100644 --- a/test/booleans/point_in_polygon_test.dart +++ b/test/booleans/point_in_polygon_test.dart @@ -5,7 +5,7 @@ import 'package:test/test.dart'; import 'package:turf/helpers.dart'; import 'package:turf/src/booleans/boolean_point_in_polygon.dart'; -main() { +void main() { group( 'pip', () { @@ -186,7 +186,7 @@ main() { ], ); - runTest(bool ignoreBoundary) { + void runTest(bool ignoreBoundary) { var isBoundaryIncluded = ignoreBoundary == false; var tests = [ [ diff --git a/test/booleans/point_on_line_test.dart b/test/booleans/point_on_line_test.dart index c6177f66..84d0e3bc 100644 --- a/test/booleans/point_on_line_test.dart +++ b/test/booleans/point_on_line_test.dart @@ -5,7 +5,7 @@ import 'package:test/test.dart'; import 'package:turf/helpers.dart'; import 'package:turf/src/booleans/boolean_point_on_line.dart'; -main() { +void main() { group( 'pointOnLine', () { diff --git a/test/booleans/touches_test.dart b/test/booleans/touches_test.dart index 6f033027..f3983435 100644 --- a/test/booleans/touches_test.dart +++ b/test/booleans/touches_test.dart @@ -5,7 +5,7 @@ import 'package:test/test.dart'; import 'package:turf/src/booleans/boolean_touches.dart'; import 'package:turf/turf.dart'; -main() { +void main() { group( 'boolean-overlap', () { diff --git a/test/booleans/valid_test.dart b/test/booleans/valid_test.dart index 916c0809..6720eafb 100644 --- a/test/booleans/valid_test.dart +++ b/test/booleans/valid_test.dart @@ -5,7 +5,7 @@ import 'package:test/test.dart'; import 'package:turf/src/booleans/boolean_valid.dart'; import 'package:turf/turf.dart'; -main() { +void main() { group( 'boolean-valid', () { diff --git a/test/components/bbox_polygon_test.dart b/test/components/bbox_polygon_test.dart index 199341d6..d5824750 100644 --- a/test/components/bbox_polygon_test.dart +++ b/test/components/bbox_polygon_test.dart @@ -2,7 +2,7 @@ import 'package:test/test.dart'; import 'package:turf/helpers.dart'; import 'package:turf/src/bbox_polygon.dart'; -main() { +void main() { test( "bbox-polygon", () { diff --git a/test/components/bbox_test.dart b/test/components/bbox_test.dart index 75740b74..e9efefcf 100644 --- a/test/components/bbox_test.dart +++ b/test/components/bbox_test.dart @@ -2,7 +2,7 @@ import 'package:test/test.dart'; import 'package:turf/bbox.dart'; import 'package:turf/helpers.dart'; -main() { +void main() { final pt = Feature( geometry: Point(coordinates: Position.named(lat: 102.0, lng: 0.5))); final line = Feature( diff --git a/test/components/bearing_test.dart b/test/components/bearing_test.dart index 8a550ba5..42949459 100644 --- a/test/components/bearing_test.dart +++ b/test/components/bearing_test.dart @@ -2,7 +2,7 @@ import 'package:test/test.dart'; import 'package:turf/bearing.dart'; import 'package:turf/helpers.dart'; -main() { +void main() { test( 'bearing', () { diff --git a/test/components/center_test.dart b/test/components/center_test.dart index 2ad5fac5..b6cc1bbf 100644 --- a/test/components/center_test.dart +++ b/test/components/center_test.dart @@ -6,7 +6,7 @@ import 'package:turf/meta.dart'; import 'package:turf/src/bbox_polygon.dart'; import 'package:turf/turf.dart'; -main() { +void main() { group( 'center in == out', () { diff --git a/test/components/clean_coords_test.dart b/test/components/clean_coords_test.dart index f631059b..591dcb92 100644 --- a/test/components/clean_coords_test.dart +++ b/test/components/clean_coords_test.dart @@ -6,7 +6,7 @@ import 'package:turf/src/clean_coords.dart'; import 'package:turf/src/truncate.dart'; import 'package:turf_equality/turf_equality.dart'; -main() { +void main() { group( 'cleanCoords', () { diff --git a/test/components/cluster_test.dart b/test/components/cluster_test.dart index 967e8fd5..8b6d0738 100644 --- a/test/components/cluster_test.dart +++ b/test/components/cluster_test.dart @@ -23,7 +23,7 @@ final geojson = FeatureCollection(features: [ Feature(geometry: Point(coordinates: Position.of([4, 3])), properties: null), ]); -main() { +void main() { test("clusters -- getCluster", () { expect(getCluster(geojson, '0').features.length, 1); expect(() => getCluster(geojson, 1), throwsA(isA())); diff --git a/test/components/destination_test.dart b/test/components/destination_test.dart index 257aef65..341570e2 100644 --- a/test/components/destination_test.dart +++ b/test/components/destination_test.dart @@ -4,7 +4,7 @@ import 'package:turf/destination.dart'; import 'package:turf/distance.dart'; import 'package:turf/helpers.dart'; -main() { +void main() { num defaultBearing = 180; num defaultDistance = 100; diff --git a/test/components/explode_test.dart b/test/components/explode_test.dart index a068ad4b..e83e7f06 100644 --- a/test/components/explode_test.dart +++ b/test/components/explode_test.dart @@ -5,7 +5,7 @@ import 'package:test/test.dart'; import 'package:turf/src/explode.dart'; import 'package:turf/turf.dart'; -main() { +void main() { group( 'explode in == out', () { diff --git a/test/components/geojson_test.dart b/test/components/geojson_test.dart index c84e8755..a7439d3c 100644 --- a/test/components/geojson_test.dart +++ b/test/components/geojson_test.dart @@ -6,10 +6,10 @@ import 'package:test/test.dart'; import 'package:turf/distance.dart'; import 'package:turf/helpers.dart'; -main() { +void main() { group('Coordinate Types:', () { test('Position', () { - _expectArgs(Position pos) { + void _expectArgs(Position pos) { expect(pos.lng, 1); expect(pos.lat, 2); expect(pos.alt, 3); @@ -55,7 +55,7 @@ main() { }); test('BBox', () { - _expectArgs(BBox bbox) { + void _expectArgs(BBox bbox) { expect(bbox.lng1, 1); expect(bbox.lat1, 2); expect(bbox.alt1, 3); @@ -110,7 +110,7 @@ main() { }); group('Longitude normalization:', () { var rand = Random(); - _rand() => rand.nextDouble() * (360 * 2) - 360; + double _rand() => rand.nextDouble() * (360 * 2) - 360; test('Position.toSigned', () { for (var i = 0; i < 10; i++) { var coord = Position.named(lat: _rand(), lng: _rand(), alt: 0); @@ -396,7 +396,7 @@ main() { expect(geom.bbox, isNotNull); expect(geom.coordinates, isNotEmpty); - _expandRecursively(List inner) { + Iterable _expandRecursively(List inner) { if (inner is List) { return inner; } else { diff --git a/test/components/helpers_test.dart b/test/components/helpers_test.dart index aa76ac32..3ad0cb6d 100644 --- a/test/components/helpers_test.dart +++ b/test/components/helpers_test.dart @@ -2,7 +2,7 @@ import 'dart:math'; import 'package:test/test.dart'; import 'package:turf/helpers.dart'; -main() { +void main() { test('radiansToLength', () { expect(radiansToLength(1, Unit.radians), equals(1)); expect(radiansToLength(1, Unit.kilometers), equals(earthRadius / 1000)); diff --git a/test/components/intersection_test.dart b/test/components/intersection_test.dart index 13bc630f..8ca01927 100644 --- a/test/components/intersection_test.dart +++ b/test/components/intersection_test.dart @@ -22,7 +22,7 @@ final l4 = LineString(coordinates: [ Position(0, 2), ]); -main() { +void main() { test('test intersects()', () { expect(intersects(l1, l2)?.coordinates, Position(1, 1)); expect(intersects(l1, l3)?.coordinates, Position(2, 2)); diff --git a/test/components/invariant_test.dart b/test/components/invariant_test.dart index 3e19cc6c..3fd3539e 100644 --- a/test/components/invariant_test.dart +++ b/test/components/invariant_test.dart @@ -2,7 +2,7 @@ import 'package:test/test.dart'; import 'package:turf/helpers.dart'; import 'package:turf/src/invariant.dart'; -main() { +void main() { LineString line1 = LineString(coordinates: [Position(1, 2), Position(3, 4)]); var feature1 = Feature(geometry: Point(coordinates: Position(1, 2, 3))); diff --git a/test/components/line_intersect_test.dart b/test/components/line_intersect_test.dart index 06b8725e..eafa6746 100644 --- a/test/components/line_intersect_test.dart +++ b/test/components/line_intersect_test.dart @@ -7,7 +7,7 @@ import 'package:turf/src/line_intersect.dart'; import 'package:turf/src/truncate.dart'; import 'package:turf_equality/turf_equality.dart'; -main() { +void main() { group( 'line_intersect', () { diff --git a/test/components/line_overlap.dart b/test/components/line_overlap.dart index b94cb0ec..67d5333d 100644 --- a/test/components/line_overlap.dart +++ b/test/components/line_overlap.dart @@ -7,7 +7,7 @@ import 'package:turf/src/line_overlap.dart'; import 'package:turf/src/meta/feature.dart'; import 'package:turf_equality/turf_equality.dart'; -main() { +void main() { FeatureCollection colorize(features, {color = "#F00", width = 25}) { var results = []; featureEach( diff --git a/test/components/line_segment_test.dart b/test/components/line_segment_test.dart index 3de552e3..8f88c90d 100644 --- a/test/components/line_segment_test.dart +++ b/test/components/line_segment_test.dart @@ -2,7 +2,7 @@ import 'package:turf/src/line_segment.dart'; import 'package:test/test.dart'; import 'package:turf/helpers.dart'; -main() { +void main() { Feature multiLine = Feature( geometry: MultiLineString( coordinates: [ diff --git a/test/components/meta_test.dart b/test/components/meta_test.dart index 102bdbab..b178cb18 100644 --- a/test/components/meta_test.dart +++ b/test/components/meta_test.dart @@ -193,7 +193,7 @@ FeatureCollection getAsMixedFeatCollection( ); } -main() { +void main() { test('coordEach -- Point', () { featureAndCollection(pt.geometry!).forEach((input) { coordEach(input, (currentCoord, coordIndex, featureIndex, diff --git a/test/components/midpoint_test.dart b/test/components/midpoint_test.dart index 6f512498..118403d1 100644 --- a/test/components/midpoint_test.dart +++ b/test/components/midpoint_test.dart @@ -4,8 +4,8 @@ import 'package:turf/helpers.dart'; import 'package:turf/midpoint.dart'; void checkLatLngInRange(Point result) { - _lngRange(num lng) => lng >= -180 && lng <= 180; - _latRange(num lat) => lat >= -90 && lat <= 90; + bool _lngRange(num lng) => lng >= -180 && lng <= 180; + bool _latRange(num lat) => lat >= -90 && lat <= 90; expect(_lngRange(result.coordinates.lng), true, reason: 'Longitude of ${result.coordinates.lng} out of range'); @@ -13,7 +13,7 @@ void checkLatLngInRange(Point result) { reason: 'Latitude of ${result.coordinates.lat} out of range'); } -main() { +void main() { test('simple midpoint', () { Position result = midpointRaw( Position.named( diff --git a/test/components/nearest_point_on_line_test.dart b/test/components/nearest_point_on_line_test.dart index 84079e2f..059c688b 100644 --- a/test/components/nearest_point_on_line_test.dart +++ b/test/components/nearest_point_on_line_test.dart @@ -3,7 +3,7 @@ import 'package:turf/distance.dart'; import 'package:turf/helpers.dart'; import 'package:turf/nearest_point_on_line.dart'; -main() { +void main() { test('nearest_point_on_line -- start point', () { final start = Point(coordinates: Position.of([-122.457175, 37.720033])); final end = Point(coordinates: Position.of([-122.457175, 37.718242])); diff --git a/test/components/polygon_to_line_test.dart b/test/components/polygon_to_line_test.dart index 80846538..6e6f976d 100644 --- a/test/components/polygon_to_line_test.dart +++ b/test/components/polygon_to_line_test.dart @@ -6,7 +6,7 @@ import 'package:test/scaffolding.dart'; import 'package:turf/polygon_to_line.dart'; import 'package:turf/turf.dart'; -main() { +void main() { group( 'polygonToLine', () { diff --git a/test/components/polyline.dart b/test/components/polyline.dart index 6f9b030e..1083e688 100644 --- a/test/components/polyline.dart +++ b/test/components/polyline.dart @@ -2,7 +2,7 @@ import 'package:test/test.dart'; import 'package:turf/helpers.dart'; import 'package:turf/polyline.dart'; -main() { +void main() { group('Polyline:', () { var example = [ Position.named(lat: 38.5, lng: -120.2), diff --git a/test/components/rhumb_bearing_test.dart b/test/components/rhumb_bearing_test.dart index 61893e10..4c995743 100644 --- a/test/components/rhumb_bearing_test.dart +++ b/test/components/rhumb_bearing_test.dart @@ -5,7 +5,7 @@ import 'package:test/test.dart'; import 'package:turf/helpers.dart'; import 'package:turf/src/rhumb_bearing.dart'; -main() { +void main() { group( '', () { diff --git a/test/components/truncate_test.dart b/test/components/truncate_test.dart index 10d2958d..aff618d0 100644 --- a/test/components/truncate_test.dart +++ b/test/components/truncate_test.dart @@ -6,7 +6,7 @@ import 'package:turf/helpers.dart'; import 'package:turf/truncate.dart'; import 'package:turf_equality/turf_equality.dart'; -main() { +void main() { group( 'truncate', () { From 7a8d0ba88b5932110521c91b4b85980be75e435d Mon Sep 17 00:00:00 2001 From: armantorkzaban Date: Sun, 11 Sep 2022 00:05:06 +0200 Subject: [PATCH 72/82] reolved requests --- lib/src/booleans/boolean_contains.dart | 79 ++++++++----------- .../booleans/boolean_point_in_polygon.dart | 11 +-- lib/src/booleans/boolean_point_on_line.dart | 26 +++--- lib/src/booleans/boolean_touches.dart | 1 + lib/src/booleans/boolean_valid.dart | 16 ++-- lib/src/line_overlap.dart | 7 +- 6 files changed, 68 insertions(+), 72 deletions(-) diff --git a/lib/src/booleans/boolean_contains.dart b/lib/src/booleans/boolean_contains.dart index 90045e66..214cc1da 100644 --- a/lib/src/booleans/boolean_contains.dart +++ b/lib/src/booleans/boolean_contains.dart @@ -1,3 +1,4 @@ +import 'package:turf/src/invariant.dart'; import 'package:turf/turf.dart'; import 'boolean_point_in_polygon.dart'; @@ -21,84 +22,78 @@ import 'boolean_point_on_line.dart'; /// //=true /// ``` bool booleanContains(GeoJSONObject feature1, GeoJSONObject feature2) { - var geom1 = feature1 is Feature ? feature1.geometry : feature1; - var geom2 = feature2 is Feature ? feature2.geometry : feature2; + var geom1 = getGeom(feature1); + var geom2 = getGeom(feature2); var coords1 = (geom1 as GeometryType).coordinates; var coords2 = (geom2 as GeometryType).coordinates; - Exception exception() => + Exception _exception() => Exception("{feature2 $geom2 geometry not supported}"); if (geom1 is Point) { if (geom2 is Point) { - return compareCoords(coords1, coords2); + return coords1 == coords2; } else { - throw exception(); + throw _exception(); } } else if (geom1 is MultiPoint) { if (geom2 is Point) { - return isPointInMultiPoint(geom1, geom2); + return _isPointInMultiPoint(geom1, geom2); } else if (geom2 is MultiPoint) { - return isMultiPointInMultiPoint(geom1, geom2); + return _isMultiPointInMultiPoint(geom1, geom2); } else { - throw exception(); + throw _exception(); } } else if (geom1 is LineString) { if (geom2 is Point) { return booleanPointOnLine(geom2, geom1, ignoreEndVertices: true); } else if (geom2 is LineString) { - return isLineOnLine(geom1, geom2); + return _isLineOnLine(geom1, geom2); } else if (geom2 is MultiPoint) { - return isMultiPointOnLine(geom1, geom2); + return _isMultiPointOnLine(geom1, geom2); } else { - throw exception(); + throw _exception(); } } else if (geom1 is Polygon) { if (geom2 is Point) { return booleanPointInPolygon((geom2).coordinates, geom1, ignoreBoundary: true); } else if (geom2 is LineString) { - return isLineInPoly(geom1, geom2); + return _isLineInPoly(geom1, geom2); } else if (geom2 is Polygon) { return isPolyInPoly(geom1, geom2); } else if (geom2 is MultiPoint) { - return isMultiPointInPoly(geom1, geom2); + return _isMultiPointInPoly(geom1, geom2); } else { - throw exception(); + throw _exception(); } } else { - throw exception(); + throw _exception(); } } -bool isPointInMultiPoint(MultiPoint multiPoint, Point pt) { - int i; - var output = false; - for (i = 0; i < multiPoint.coordinates.length; i++) { - if (compareCoords(multiPoint.coordinates[i], pt.coordinates)) { - output = true; - break; +bool _isPointInMultiPoint(MultiPoint multiPoint, Point pt) { + for (int i = 0; i < multiPoint.coordinates.length; i++) { + if ((multiPoint.coordinates[i] == pt.coordinates)) { + return true; } } - return output; + return false; } -bool isMultiPointInMultiPoint(MultiPoint multiPoint1, MultiPoint multiPoint2) { - for (var coord2 in multiPoint2.coordinates) { - var matchFound = false; - for (var coord1 in multiPoint1.coordinates) { - if (compareCoords(coord2, coord1)) { - matchFound = true; - break; +bool _isMultiPointInMultiPoint(MultiPoint multiPoint1, MultiPoint multiPoint2) { + for (Position coord2 in multiPoint2.coordinates) { + bool match = false; + for (Position coord1 in multiPoint1.coordinates) { + if (coord2 == coord1) { + match = true; } } - if (!matchFound) { - return false; - } + if (!match) return false; } return true; } -bool isMultiPointOnLine(LineString lineString, MultiPoint multiPoint) { +bool _isMultiPointOnLine(LineString lineString, MultiPoint multiPoint) { var haveFoundInteriorPoint = false; for (var coord in multiPoint.coordinates) { if (booleanPointOnLine(Point(coordinates: coord), lineString, @@ -112,7 +107,7 @@ bool isMultiPointOnLine(LineString lineString, MultiPoint multiPoint) { return haveFoundInteriorPoint; } -bool isMultiPointInPoly(Polygon polygon, MultiPoint multiPoint) { +bool _isMultiPointInPoly(Polygon polygon, MultiPoint multiPoint) { for (var coord in multiPoint.coordinates) { if (!booleanPointInPolygon(coord, polygon, ignoreBoundary: true)) { return false; @@ -121,18 +116,18 @@ bool isMultiPointInPoly(Polygon polygon, MultiPoint multiPoint) { return true; } -bool isLineOnLine(LineString lineString1, LineString lineString2) { +bool _isLineOnLine(LineString lineString1, LineString lineString2) { var haveFoundInteriorPoint = false; - for (var coords in lineString2.coordinates) { + for (Position coord in lineString2.coordinates) { if (booleanPointOnLine( - Point(coordinates: coords), + Point(coordinates: coord), lineString1, ignoreEndVertices: true, )) { haveFoundInteriorPoint = true; } if (!booleanPointOnLine( - Point(coordinates: coords), + Point(coordinates: coord), lineString1, ignoreEndVertices: false, )) { @@ -142,7 +137,7 @@ bool isLineOnLine(LineString lineString1, LineString lineString2) { return haveFoundInteriorPoint; } -bool isLineInPoly(Polygon polygon, LineString linestring) { +bool _isLineInPoly(Polygon polygon, LineString linestring) { var output = false; var i = 0; @@ -201,10 +196,6 @@ bool doBBoxOverlap(BBox bbox1, BBox bbox2) { return true; } -bool compareCoords(Position pair1, Position pair2) { - return pair1[0] == pair2[0] && pair1[1] == pair2[1]; -} - Position getMidpoint(Position pair1, Position pair2) { return Position.of( [(pair1[0]! + pair2[0]!) / 2, (pair1[1]! + pair2[1]!) / 2]); diff --git a/lib/src/booleans/boolean_point_in_polygon.dart b/lib/src/booleans/boolean_point_in_polygon.dart index 9e20680b..1f297e06 100644 --- a/lib/src/booleans/boolean_point_in_polygon.dart +++ b/lib/src/booleans/boolean_point_in_polygon.dart @@ -26,20 +26,21 @@ import '../invariant.dart'; /// turf.booleanPointInPolygon(pt, poly); /// //= true /// ``` -bool booleanPointInPolygon(Position point, GeoJSONObject polygon, - {bool ignoreBoundary = false}) { +bool booleanPointInPolygon( + Position point, + GeoJSONObject polygon, { + bool ignoreBoundary = false, +}) { List>>? polys; BBox? bbox = polygon.bbox; - Exception _exception = Exception('${polygon.type} is not supported'); - var theGeom = getGeom(polygon); if (theGeom is Polygon) { polys = [theGeom.coordinates]; } else if (theGeom is MultiPolygon) { polys = theGeom.coordinates; } else { - throw _exception; + throw Exception('${polygon.type} is not supported'); } // Quick elimination if point is not inside bbox diff --git a/lib/src/booleans/boolean_point_on_line.dart b/lib/src/booleans/boolean_point_on_line.dart index 76ab207b..ffc0dd5b 100644 --- a/lib/src/booleans/boolean_point_on_line.dart +++ b/lib/src/booleans/boolean_point_on_line.dart @@ -1,10 +1,10 @@ import 'package:turf/helpers.dart'; -/// Returns true if a point is on a line. Accepts an optional parameter to ignore the -/// start and end vertices of the [Linestring]. +/// Returns [true] if a point is on a line. Accepts an optional parameter to ignore the +/// start and end vertices of the [LineString]. /// The [ignoreEndVertices=false] controls whether to ignore the start and end vertices. /// [epsilon] is the Fractional number to compare with the cross product result. -/// It's useful for dealing with floating points such as lng/lat points +/// It's useful for dealing with floating points in lng/lat /// example: /// ```dart /// var pt = Point(coordinates:Position.of([0, 0])); @@ -16,19 +16,21 @@ import 'package:turf/helpers.dart'; /// var isPointOnLine = booleanPointOnLine(pt, line); /// //=true /// ``` +enum BoundaryType { none, start, end, both } + bool booleanPointOnLine(Point pt, LineString line, {bool ignoreEndVertices = false, num? epsilon}) { for (var i = 0; i < line.coordinates.length - 1; i++) { - dynamic ignoreBoundary = false; + BoundaryType ignoreBoundary = BoundaryType.none; if (ignoreEndVertices) { if (i == 0) { - ignoreBoundary = "start"; + ignoreBoundary = BoundaryType.start; } if (i == line.coordinates.length - 2) { - ignoreBoundary = "end"; + ignoreBoundary = BoundaryType.end; } if (i == 0 && i + 1 == line.coordinates.length - 1) { - ignoreBoundary = "both"; + ignoreBoundary = BoundaryType.both; } } if (_isPointOnLineSegment(line.coordinates[i], line.coordinates[i + 1], @@ -46,7 +48,7 @@ bool booleanPointOnLine(Point pt, LineString line, /// [epsilon] is the Fractional number to compare with the cross product result. /// Useful for dealing with floating points such as lng/lat points. bool _isPointOnLineSegment(Position lineSegmentStart, Position lineSegmentEnd, - Position pt, dynamic excludeBoundary, num? epsilon) { + Position pt, BoundaryType excludeBoundary, num? epsilon) { var x = pt[0]!; var y = pt[1]!; var x1 = lineSegmentStart[0]; @@ -65,22 +67,22 @@ bool _isPointOnLineSegment(Position lineSegmentStart, Position lineSegmentEnd, } else if (cross != 0) { return false; } - if (excludeBoundary is bool && !excludeBoundary) { + if (excludeBoundary == BoundaryType.none) { if ((dxl).abs() >= (dyl).abs()) { return dxl > 0 ? x1 <= x && x <= x2 : x2 <= x && x <= x1; } return dyl > 0 ? y1 <= y && y <= y2 : y2 <= y && y <= y1; - } else if (excludeBoundary == "start") { + } else if (excludeBoundary == BoundaryType.start) { if ((dxl).abs() >= (dyl).abs()) { return dxl > 0 ? x1 < x && x <= x2 : x2 <= x && x < x1; } return dyl > 0 ? y1 < y && y <= y2 : y2 <= y && y < y1; - } else if (excludeBoundary == "end") { + } else if (excludeBoundary == BoundaryType.end) { if ((dxl).abs() >= (dyl).abs()) { return dxl > 0 ? x1 <= x && x < x2 : x2 < x && x <= x1; } return dyl > 0 ? y1 <= y && y < y2 : y2 < y && y <= y1; - } else if (excludeBoundary == "both") { + } else if (excludeBoundary == BoundaryType.both) { if ((dxl).abs() >= (dyl).abs()) { return dxl > 0 ? x1 < x && x < x2 : x2 < x && x < x1; } diff --git a/lib/src/booleans/boolean_touches.dart b/lib/src/booleans/boolean_touches.dart index 48febf27..451cc3a5 100644 --- a/lib/src/booleans/boolean_touches.dart +++ b/lib/src/booleans/boolean_touches.dart @@ -10,6 +10,7 @@ import 'boolean_point_on_line.dart'; /// var point = Point(coordinates: Positon.of([1, 1])); /// booleanTouches(point, line); /// //=true +/// ``` bool booleanTouches(GeoJSONObject feature1, GeoJSONObject feature2) { var geom1 = feature1 is Feature ? feature1.geometry : feature1; var geom2 = feature2 is Feature ? feature2.geometry : feature2; diff --git a/lib/src/booleans/boolean_valid.dart b/lib/src/booleans/boolean_valid.dart index 5847a8ef..2566fff9 100644 --- a/lib/src/booleans/boolean_valid.dart +++ b/lib/src/booleans/boolean_valid.dart @@ -7,12 +7,12 @@ import '../../helpers.dart'; import '../line_intersect.dart'; import 'boolean_crosses.dart'; -bool checkRingsClose(List geom) { +bool _checkRingsClose(List geom) { return (geom[0].lng == geom[geom.length - 1].lng || geom[0].lat == geom[geom.length - 1].lat); } -bool checkRingsForSpikesPunctures(List geom) { +bool _checkRingsForSpikesPunctures(List geom) { for (var i = 0; i < geom.length - 1; i++) { var point = Point(coordinates: geom[i]); for (var ii = i + 1; ii < geom.length - 2; ii++) { @@ -23,7 +23,7 @@ bool checkRingsForSpikesPunctures(List geom) { return false; } -bool checkPolygonAgainstOthers(Polygon poly, MultiPolygon geom, int index) { +bool _checkPolygonAgainstOthers(Polygon poly, MultiPolygon geom, int index) { for (var i = index + 1; i < geom.coordinates.length; i++) { if (!booleanDisjoint(poly, Polygon(coordinates: geom.coordinates[i]))) { LineString lineS = LineString(coordinates: geom.coordinates[i][0]); @@ -99,8 +99,8 @@ bool booleanValid(GeoJSONObject feature) { if (!valid) return false; for (var i = 0; i < geom.coordinates.length; i++) { if (geom.coordinates[i].length < 4) return false; - if (!checkRingsClose(geom.coordinates[i])) return false; - if (checkRingsForSpikesPunctures(geom.coordinates[i])) return false; + if (!_checkRingsClose(geom.coordinates[i])) return false; + if (_checkRingsForSpikesPunctures(geom.coordinates[i])) return false; if (i > 0) { if (lineIntersect( Polygon(coordinates: [geom.coordinates[0]]), @@ -119,14 +119,14 @@ bool booleanValid(GeoJSONObject feature) { if (poly[ii].length < 4) { return false; } - if (!checkRingsClose(poly[ii])) { + if (!_checkRingsClose(poly[ii])) { return false; } - if (checkRingsForSpikesPunctures(poly[ii])) { + if (_checkRingsForSpikesPunctures(poly[ii])) { return false; } if (ii == 0) { - if (!checkPolygonAgainstOthers( + if (!_checkPolygonAgainstOthers( Polygon(coordinates: poly), geom, i)) { return false; } diff --git a/lib/src/line_overlap.dart b/lib/src/line_overlap.dart index 5f004d2f..efa68d52 100644 --- a/lib/src/line_overlap.dart +++ b/lib/src/line_overlap.dart @@ -169,11 +169,12 @@ FeatureCollection lineOverlap( Feature? concatSegment( Feature line, Feature segment) { + var newLine = line.clone(); var coords = getCoords(segment); - var lineCoords = getCoords(line); + var lineCoords = getCoords(newLine); var start = lineCoords[0]; var end = lineCoords[lineCoords.length - 1]; - List geom = (line.geometry as LineString).coordinates; + List geom = (newLine.geometry as LineString).coordinates; if (coords[0] == start) { geom.insert(0, coords[1]); @@ -189,5 +190,5 @@ Feature? concatSegment( // identified. // Otherwise return the mutated line. - return line; + return newLine; } From 1589d98425a9f2dd3a42798b3dad660e47817cac Mon Sep 17 00:00:00 2001 From: armantorkzaban Date: Sun, 11 Sep 2022 00:42:57 +0200 Subject: [PATCH 73/82] more requests resolved --- lib/src/booleans/boolean_contains.dart | 20 +++++---------- lib/src/booleans/boolean_crosses.dart | 26 +++++++++++--------- lib/src/booleans/boolean_disjoint.dart | 34 +++----------------------- 3 files changed, 24 insertions(+), 56 deletions(-) diff --git a/lib/src/booleans/boolean_contains.dart b/lib/src/booleans/boolean_contains.dart index 214cc1da..e7c1eadf 100644 --- a/lib/src/booleans/boolean_contains.dart +++ b/lib/src/booleans/boolean_contains.dart @@ -154,8 +154,7 @@ bool _isLineInPoly(Polygon polygon, LineString linestring) { polygon, ignoreBoundary: true, )) { - output = true; - break; + return true; } } return output; @@ -181,18 +180,11 @@ bool isPolyInPoly(GeoJSONObject geom1, GeoJSONObject geom2) { } bool doBBoxOverlap(BBox bbox1, BBox bbox2) { - if (bbox1[0]! > bbox2[0]!) { - return false; - } - if (bbox1[2]! < bbox2[2]!) { - return false; - } - if (bbox1[1]! > bbox2[1]!) { - return false; - } - if (bbox1[3]! < bbox2[3]!) { - return false; - } + if (bbox1[0]! > bbox2[0]! || + bbox1[2]! < bbox2[2]! || + bbox1[1]! > bbox2[1]! || + bbox1[3]! < bbox2[3]!) return false; + return true; } diff --git a/lib/src/booleans/boolean_crosses.dart b/lib/src/booleans/boolean_crosses.dart index 131864ad..7bf03e7b 100644 --- a/lib/src/booleans/boolean_crosses.dart +++ b/lib/src/booleans/boolean_crosses.dart @@ -1,12 +1,14 @@ +import 'package:turf/src/invariant.dart'; + import '../../helpers.dart'; import '../line_intersect.dart'; import '../polygon_to_line.dart'; import 'boolean_point_in_polygon.dart'; -/// Boolean-Crosses returns True if the intersection results in a geometry whose +/// [booleanCrosses] returns [true] if the intersection results in a geometry whose /// dimension is one less than the maximum dimension of the two source geometries /// and the intersection set is interior to both source geometries. -/// Boolean-Crosses returns [true] for only [MultiPoint]/[Polygon], [MultiPoint]/[LineString], +/// [booleanCsses] returns [true] for only [MultiPoint]/[Polygon], [MultiPoint]/[LineString], /// [LineString]/[LineString], [LineString]/[Polygon], and [LineString]/[MultiPolygon] comparisons. /// Other comparisons are not supported as they are outside the OpenGIS Simple /// [Feature]s spec and may give unexpected results. @@ -26,17 +28,17 @@ import 'boolean_point_in_polygon.dart'; /// //=true /// ``` bool booleanCrosses(GeoJSONObject feature1, GeoJSONObject feature2) { - var geom1 = feature1 is Feature ? feature1.geometry : feature1; - var geom2 = feature2 is Feature ? feature2.geometry : feature2; + var geom1 = getGeom(feature1); + var geom2 = getGeom(feature2); - Exception exception() => Exception("$geom2 is not supperted"); + var exception = Exception("$geom2 is not supperted"); if (geom1 is MultiPoint) { if (geom2 is LineString) { return doMultiPointAndLineStringCross(geom1, geom2); } else if (geom2 is Polygon) { return doesMultiPointCrossPoly(geom1, geom2); } else { - throw exception(); + throw exception; } } else if (geom1 is LineString) { if (geom2 is MultiPoint) { @@ -47,7 +49,7 @@ bool booleanCrosses(GeoJSONObject feature1, GeoJSONObject feature2) { } else if (geom2 is Polygon) { return doLineStringAndPolygonCross(geom1, geom2); } else { - throw exception(); + throw exception; } } else if (geom1 is Polygon) { if (geom2 is MultiPoint) { @@ -57,10 +59,10 @@ bool booleanCrosses(GeoJSONObject feature1, GeoJSONObject feature2) { // An inverse operation return doLineStringAndPolygonCross(geom2, geom1); } else { - throw exception(); + throw exception; } } else { - throw exception(); + throw exception; } } @@ -76,7 +78,7 @@ bool doMultiPointAndLineStringCross( if (i2 == 0 || i2 == lineString.coordinates.length - 2) { incEndVertices = false; } - if (_isPointOnLineSegment( + if (isPointOnLineSegment( lineString.coordinates[i2], lineString.coordinates[i2 + 1], multiPoint.coordinates[i], @@ -100,7 +102,7 @@ bool doLineStringsCross(LineString lineString1, LineString lineString2) { if (i2 == 0 || i2 == lineString2.coordinates.length - 2) { incEndVertices = false; } - if (_isPointOnLineSegment( + if (isPointOnLineSegment( lineString1.coordinates[i], lineString1.coordinates[i + 1], lineString2.coordinates[i2], @@ -142,7 +144,7 @@ bool doesMultiPointCrossPoly(MultiPoint multiPoint, Polygon polygon) { /// lineSegmentEnd [Position] of end of line /// pt [Position] of point to check /// [incEnd] controls whether the [Point] is allowed to fall on the line ends -bool _isPointOnLineSegment( +bool isPointOnLineSegment( Position lineSegmentStart, Position lineSegmentEnd, Position pt, diff --git a/lib/src/booleans/boolean_disjoint.dart b/lib/src/booleans/boolean_disjoint.dart index b0257757..dab2fe68 100644 --- a/lib/src/booleans/boolean_disjoint.dart +++ b/lib/src/booleans/boolean_disjoint.dart @@ -1,3 +1,5 @@ +import 'package:turf/src/booleans/boolean_crosses.dart'; + import '../../helpers.dart'; import '../../meta.dart'; import '../line_intersect.dart'; @@ -42,7 +44,7 @@ bool booleanDisjoint(GeoJSONObject feature1, GeoJSONObject feature2) { bool _disjoint(GeometryType geom1, GeometryType geom2) { if (geom1 is Point) { if (geom2 is Point) { - return !_compareCoords(geom1.coordinates, geom2.coordinates); + return geom1.coordinates != geom2.coordinates; } else if (geom2 is LineString) { return !isPointOnLine(geom2, geom1); } else if (geom2 is Polygon) { @@ -72,7 +74,7 @@ bool _disjoint(GeometryType geom1, GeometryType geom2) { bool isPointOnLine(LineString lineString, Point pt) { for (var i = 0; i < lineString.coordinates.length - 1; i++) { if (isPointOnLineSegment(lineString.coordinates[i], - lineString.coordinates[i + 1], pt.coordinates)) { + lineString.coordinates[i + 1], pt.coordinates, true)) { return true; } } @@ -121,31 +123,3 @@ bool _isPolyInPoly(Polygon feature1, Polygon feature2) { } return false; } - -bool isPointOnLineSegment( - Position lineSegmentStart, Position lineSegmentEnd, Position pt) { - var dxc = pt[0]! - lineSegmentStart[0]!; - var dyc = pt[1]! - lineSegmentStart[1]!; - var dxl = lineSegmentEnd[0]! - lineSegmentStart[0]!; - var dyl = lineSegmentEnd[1]! - lineSegmentStart[1]!; - var cross = dxc * dyl - dyc * dxl; - if (cross != 0) { - return false; - } - if ((dxl).abs() >= (dyl).abs()) { - if (dxl > 0) { - return lineSegmentStart[0]! <= pt[0]! && pt[0]! <= lineSegmentEnd[0]!; - } else { - return lineSegmentEnd[0]! <= pt[0]! && pt[0]! <= lineSegmentStart[0]!; - } - } else if (dyl > 0) { - return lineSegmentStart[1]! <= pt[1]! && pt[1]! <= lineSegmentEnd[1]!; - } else { - return lineSegmentEnd[1]! <= pt[1]! && pt[1]! <= lineSegmentStart[1]!; - } -} - -/// Returns true/false if coord pairs match -bool _compareCoords(Position pair1, Position pair2) { - return pair1[0] == pair2[0] && pair1[1] == pair2[1]; -} From 73c26fe44babcfeca1f46e95810a2e24c282bde7 Mon Sep 17 00:00:00 2001 From: armantorkzaban Date: Sun, 11 Sep 2022 01:25:49 +0200 Subject: [PATCH 74/82] more requests resolved --- lib/src/booleans/boolean_equal.dart | 6 ++-- lib/src/booleans/boolean_intersect.dart | 6 ++-- lib/src/booleans/boolean_parallel.dart | 42 ++++++++++--------------- lib/src/polygon_to_line.dart | 4 +-- test/booleans/parallel_test.dart | 6 ++-- 5 files changed, 29 insertions(+), 35 deletions(-) diff --git a/lib/src/booleans/boolean_equal.dart b/lib/src/booleans/boolean_equal.dart index 8600dcb1..6fadc741 100644 --- a/lib/src/booleans/boolean_equal.dart +++ b/lib/src/booleans/boolean_equal.dart @@ -12,6 +12,7 @@ import '../clean_coords.dart'; /// are considered the same. /// Returns [true] if the objects are equal, [false] otherwise /// example: +/// ```dart /// var pt1 = Point(coordinates: Position.of([0, 0])); /// var pt2 = Point(coordinates: Position.of([0, 0])); /// var pt3 = Point(coordinates: Position.of([1, 1])); @@ -19,6 +20,7 @@ import '../clean_coords.dart'; /// //= true /// booleanEqual(pt2, pt3); /// //= false +/// ``` bool booleanEqual( GeoJSONObject feature1, GeoJSONObject feature2, { @@ -26,8 +28,8 @@ bool booleanEqual( bool direction = false, bool shiftedPolygon = false, }) { - if (!(precision >= 0)) { - throw Exception("precision must be a positive number"); + if (precision < 0 || precision > 17) { + throw Exception("precision must be a positive number and smaller than 15"); } var equality = Equality( diff --git a/lib/src/booleans/boolean_intersect.dart b/lib/src/booleans/boolean_intersect.dart index f025490d..2c978701 100644 --- a/lib/src/booleans/boolean_intersect.dart +++ b/lib/src/booleans/boolean_intersect.dart @@ -2,16 +2,16 @@ import '../../helpers.dart'; import '../../meta.dart'; import 'boolean_disjoint.dart'; -/// returns [true] when two geometries intersect. -/// Takes a feature1 & feature2 parameters of type [GeoJSONObject] which can be +/// Returns [true] when two geometries intersect. +/// Takes [feature1] & [feature2] parameters of type [GeoJSONObject] which can be /// a [Feature] or [GeometryType]. /// example /// ```dart /// var point = Point(coordinates:Position.of([2, 2])); /// var line = LineString(coordinates:[Position.of([1, 1]), Position.of([1, 2]), Position.of([1, 3]), Position.of([1, 4]])); /// booleanIntersects(line, point); +/// //=true /// ``` -//=true bool booleanIntersects(GeoJSONObject feature1, GeoJSONObject feature2) { var result = false; flattenEach( diff --git a/lib/src/booleans/boolean_parallel.dart b/lib/src/booleans/boolean_parallel.dart index 39594492..8f446f57 100644 --- a/lib/src/booleans/boolean_parallel.dart +++ b/lib/src/booleans/boolean_parallel.dart @@ -4,26 +4,29 @@ import '../../helpers.dart'; import '../../line_segment.dart'; import '../clean_coords.dart'; -/// Returns [true] if each segment of `line1` is parallel to the correspondent segment of `line2` +/// Returns [true] if each segment of [line1] is parallel to the correspondent +/// segment of [line2] /// example: /// ```dart -/// var line1 = LineString(coordinates:[Position.of([0, 0]), Position.of([0, 1])]); -/// var line2 = LineString(coordinates:[Position.of([1, 0]), Position.of([1, 1])]); +/// var line1 = LineString( +/// coordinates: [ +/// Position.of([0, 0]), +/// Position.of([0, 1]) +/// ], +/// ); +/// var line2 = LineString( +/// coordinates: [ +/// Position.of([1, 0]), +/// Position.of([1, 1]) +/// ], +/// ); /// booleanParallel(line1, line2); -/// ``` /// //=true -bool booleanParallel(GeoJSONObject line1, GeoJSONObject line2) { - var type1 = _getType(line1, "line1"); - if (type1 != GeoJSONObjectType.lineString) { - throw Exception("line1 must be a LineString"); - } - var type2 = _getType(line2, "line2"); - if (type2 != GeoJSONObjectType.lineString) { - throw Exception("line2 must be a LineString"); - } +/// ``` +bool booleanParallel(LineString line1, LineString line2) { FeatureCollection segments1 = lineSegment(cleanCoords(line1)); FeatureCollection segments2 = lineSegment(cleanCoords(line2)); - for (var i = 0; i < segments1.features.length; i++) { + for (int i = 0; i < segments1.features.length; i++) { var segment1 = segments1.features[i].geometry!.coordinates; var seg2i = segments2.features.asMap().containsKey(i); if (!seg2i) break; @@ -41,14 +44,3 @@ bool _isParallel(List segment1, List segment2) { Point(coordinates: segment2[0]), Point(coordinates: segment2[1]))); return slope1 == slope2; } - -/// Returns Feature's type -GeoJSONObjectType _getType(GeoJSONObject geojson, String name) { - if ((geojson as Feature).geometry != null) { - return geojson.geometry!.type; - } - if (geojson is GeometryType) { - return geojson.type; - } // if GeoJSON geometry - throw Exception("Invalid GeoJSON object for $name"); -} diff --git a/lib/src/polygon_to_line.dart b/lib/src/polygon_to_line.dart index ef5a3bbb..a1b6d65b 100644 --- a/lib/src/polygon_to_line.dart +++ b/lib/src/polygon_to_line.dart @@ -49,9 +49,7 @@ FeatureCollection _multiPolygonToLine(MultiPolygon geom, var lines = []; for (var coord in coords) { - { - lines.add(_coordsToLine(coord, properties)); - } + lines.add(_coordsToLine(coord, properties)); } return FeatureCollection(features: lines); } diff --git a/test/booleans/parallel_test.dart b/test/booleans/parallel_test.dart index 3e693208..02c569c1 100644 --- a/test/booleans/parallel_test.dart +++ b/test/booleans/parallel_test.dart @@ -20,7 +20,8 @@ void main() { var inGeom = GeoJSONObject.fromJson(jsonDecode(inSource)); var feature1 = (inGeom as FeatureCollection).features[0]; var feature2 = inGeom.features[1]; - var result = booleanParallel(feature1, feature2); + var result = booleanParallel(feature1.geometry as LineString, + feature2.geometry as LineString); expect(result, true); } } @@ -38,7 +39,8 @@ void main() { var inGeom = GeoJSONObject.fromJson(jsonDecode(inSource)); var feature1 = (inGeom as FeatureCollection).features[0]; var feature2 = inGeom.features[1]; - var result = booleanParallel(feature1, feature2); + var result = booleanParallel(feature1.geometry as LineString, + feature2.geometry as LineString); expect(result, false); } } From fdd34d238148477469f6bb75993fecc436f05d00 Mon Sep 17 00:00:00 2001 From: armantorkzaban Date: Sun, 11 Sep 2022 16:24:52 +0200 Subject: [PATCH 75/82] test name, touching lineOverlap --- test/components/line_overlap.dart | 2 +- test/components/rhumb_bearing_test.dart | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/components/line_overlap.dart b/test/components/line_overlap.dart index 67d5333d..e3ba3056 100644 --- a/test/components/line_overlap.dart +++ b/test/components/line_overlap.dart @@ -220,4 +220,4 @@ function colorize(features, color = "#F00", width = 25) { if (features.type === "Feature") return results[0]; return featureCollection(results); } - */ \ No newline at end of file + */ diff --git a/test/components/rhumb_bearing_test.dart b/test/components/rhumb_bearing_test.dart index 4c995743..2dd01b17 100644 --- a/test/components/rhumb_bearing_test.dart +++ b/test/components/rhumb_bearing_test.dart @@ -7,7 +7,7 @@ import 'package:turf/src/rhumb_bearing.dart'; void main() { group( - '', + 'Rhumb Bearing test', () { Directory inDir = Directory('./test/examples/rhumb_bearing/in'); for (var file in inDir.listSync(recursive: true)) { From f0e83d4d06c939be76cff7bad950f94f9f76be59 Mon Sep 17 00:00:00 2001 From: Lukas Himsel Date: Sun, 11 Sep 2022 16:52:37 +0200 Subject: [PATCH 76/82] fix conversations in booleanContains --- benchmark/area_benchmark.dart | 2 +- benchmark/polygon_smooth_benchmark.dart | 2 +- lib/src/booleans/boolean_contains.dart | 39 +++++++++--------------- lib/src/polygon_smooth.dart | 4 +-- test/components/area_test.dart | 2 +- test/components/polygon_smooth_test.dart | 2 +- 6 files changed, 21 insertions(+), 30 deletions(-) diff --git a/benchmark/area_benchmark.dart b/benchmark/area_benchmark.dart index 60c0fc6c..178624a6 100644 --- a/benchmark/area_benchmark.dart +++ b/benchmark/area_benchmark.dart @@ -16,7 +16,7 @@ Feature poly = Feature( ]), ); -main() { +void main() { group('area', () { benchmark('simple', () { area(poly); diff --git a/benchmark/polygon_smooth_benchmark.dart b/benchmark/polygon_smooth_benchmark.dart index a3b5dcbb..9e4d5feb 100644 --- a/benchmark/polygon_smooth_benchmark.dart +++ b/benchmark/polygon_smooth_benchmark.dart @@ -5,7 +5,7 @@ import 'package:benchmark/benchmark.dart'; import 'package:turf/polygon_smooth.dart'; import 'package:turf/turf.dart'; -main() { +void main() { group("turf-polygon-smooth", () { var inDir = Directory('./test/examples/polygonSmooth/in'); for (var file in inDir.listSync(recursive: true)) { diff --git a/lib/src/booleans/boolean_contains.dart b/lib/src/booleans/boolean_contains.dart index e7c1eadf..eeeb7260 100644 --- a/lib/src/booleans/boolean_contains.dart +++ b/lib/src/booleans/boolean_contains.dart @@ -8,7 +8,7 @@ import 'boolean_point_on_line.dart'; /// by the first geometry. /// The interiors of both geometries must intersect and, the interior and /// boundary of the secondary must not intersect the exterior of the primary. -/// Boolean-contains returns the exact opposite result of the `turf/boolean-within`. +/// [booleanContains] returns the exact opposite result of the [booleanWithin]. /// example: /// ```dart /// var line = LineString(coordinates: [ @@ -27,13 +27,12 @@ bool booleanContains(GeoJSONObject feature1, GeoJSONObject feature2) { var coords1 = (geom1 as GeometryType).coordinates; var coords2 = (geom2 as GeometryType).coordinates; - Exception _exception() => - Exception("{feature2 $geom2 geometry not supported}"); + final exception = Exception("{feature2 $geom2 geometry not supported}"); if (geom1 is Point) { if (geom2 is Point) { return coords1 == coords2; } else { - throw _exception(); + throw exception; } } else if (geom1 is MultiPoint) { if (geom2 is Point) { @@ -41,7 +40,7 @@ bool booleanContains(GeoJSONObject feature1, GeoJSONObject feature2) { } else if (geom2 is MultiPoint) { return _isMultiPointInMultiPoint(geom1, geom2); } else { - throw _exception(); + throw exception; } } else if (geom1 is LineString) { if (geom2 is Point) { @@ -51,7 +50,7 @@ bool booleanContains(GeoJSONObject feature1, GeoJSONObject feature2) { } else if (geom2 is MultiPoint) { return _isMultiPointOnLine(geom1, geom2); } else { - throw _exception(); + throw exception; } } else if (geom1 is Polygon) { if (geom2 is Point) { @@ -60,14 +59,14 @@ bool booleanContains(GeoJSONObject feature1, GeoJSONObject feature2) { } else if (geom2 is LineString) { return _isLineInPoly(geom1, geom2); } else if (geom2 is Polygon) { - return isPolyInPoly(geom1, geom2); + return _isPolyInPoly(geom1, geom2); } else if (geom2 is MultiPoint) { return _isMultiPointInPoly(geom1, geom2); } else { - throw _exception(); + throw exception; } } else { - throw _exception(); + throw exception; } } @@ -138,17 +137,14 @@ bool _isLineOnLine(LineString lineString1, LineString lineString2) { } bool _isLineInPoly(Polygon polygon, LineString linestring) { - var output = false; - var i = 0; - var polyBbox = bbox(polygon); var lineBbox = bbox(linestring); - if (!doBBoxOverlap(polyBbox, lineBbox)) { + if (!_doBBoxesOverlap(polyBbox, lineBbox)) { return false; } - for (i; i < linestring.coordinates.length - 1; i++) { + for (var i = 0; i < linestring.coordinates.length - 1; i++) { var midPoint = - getMidpoint(linestring.coordinates[i], linestring.coordinates[i + 1]); + midpointRaw(linestring.coordinates[i], linestring.coordinates[i + 1]); if (booleanPointInPolygon( midPoint, polygon, @@ -157,15 +153,15 @@ bool _isLineInPoly(Polygon polygon, LineString linestring) { return true; } } - return output; + return false; } /// Is Polygon2 in Polygon1 /// Only takes into account outer rings -bool isPolyInPoly(GeoJSONObject geom1, GeoJSONObject geom2) { +bool _isPolyInPoly(GeoJSONObject geom1, GeoJSONObject geom2) { var poly1Bbox = bbox(geom1); var poly2Bbox = bbox(geom2); - if (!doBBoxOverlap(poly1Bbox, poly2Bbox)) { + if (!_doBBoxesOverlap(poly1Bbox, poly2Bbox)) { return false; } @@ -179,7 +175,7 @@ bool isPolyInPoly(GeoJSONObject geom1, GeoJSONObject geom2) { return true; } -bool doBBoxOverlap(BBox bbox1, BBox bbox2) { +bool _doBBoxesOverlap(BBox bbox1, BBox bbox2) { if (bbox1[0]! > bbox2[0]! || bbox1[2]! < bbox2[2]! || bbox1[1]! > bbox2[1]! || @@ -187,8 +183,3 @@ bool doBBoxOverlap(BBox bbox1, BBox bbox2) { return true; } - -Position getMidpoint(Position pair1, Position pair2) { - return Position.of( - [(pair1[0]! + pair2[0]!) / 2, (pair1[1]! + pair2[1]!) / 2]); -} diff --git a/lib/src/polygon_smooth.dart b/lib/src/polygon_smooth.dart index d55930f1..33b3f473 100644 --- a/lib/src/polygon_smooth.dart +++ b/lib/src/polygon_smooth.dart @@ -75,7 +75,7 @@ FeatureCollection polygonSmooth(GeoJSONObject inputPolys, return FeatureCollection(features: outPolys); } -_processPolygon(Polygon poly, List> tempOutput) { +void _processPolygon(Polygon poly, List> tempOutput) { var prevGeomIndex = 0; var subtractCoordIndex = 0; @@ -106,7 +106,7 @@ _processPolygon(Polygon poly, List> tempOutput) { } } -_processMultiPolygon(poly, List>> tempOutput) { +void _processMultiPolygon(poly, List>> tempOutput) { var prevGeomIndex = 0; var subtractCoordIndex = 0; var prevMultiIndex = 0; diff --git a/test/components/area_test.dart b/test/components/area_test.dart index d15a2932..d6b73c9b 100644 --- a/test/components/area_test.dart +++ b/test/components/area_test.dart @@ -1,7 +1,7 @@ import 'package:test/test.dart'; import 'package:turf/turf.dart'; -main() { +void main() { group('area', () { final position1 = Position(0, 0); final position2 = Position(0, 1); diff --git a/test/components/polygon_smooth_test.dart b/test/components/polygon_smooth_test.dart index 73379b9e..7a01170d 100644 --- a/test/components/polygon_smooth_test.dart +++ b/test/components/polygon_smooth_test.dart @@ -6,7 +6,7 @@ import 'package:turf/polygon_smooth.dart'; import 'package:turf/turf.dart'; import 'package:turf_equality/turf_equality.dart'; -main() { +void main() { group("turf-polygon-smooth", () { var inDir = Directory('./test/examples/polygonSmooth/in'); for (var file in inDir.listSync(recursive: true)) { From 59d452fe0a554a83a85d776562491d5e1e5caafa Mon Sep 17 00:00:00 2001 From: Lukas Himsel Date: Sun, 11 Sep 2022 17:02:56 +0200 Subject: [PATCH 77/82] fixes conversations in crosses and disjoint --- lib/src/booleans/boolean_crosses.dart | 22 +++++++++++----------- lib/src/booleans/boolean_disjoint.dart | 16 ++++++++-------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/lib/src/booleans/boolean_crosses.dart b/lib/src/booleans/boolean_crosses.dart index 7bf03e7b..54ccdc54 100644 --- a/lib/src/booleans/boolean_crosses.dart +++ b/lib/src/booleans/boolean_crosses.dart @@ -34,30 +34,30 @@ bool booleanCrosses(GeoJSONObject feature1, GeoJSONObject feature2) { var exception = Exception("$geom2 is not supperted"); if (geom1 is MultiPoint) { if (geom2 is LineString) { - return doMultiPointAndLineStringCross(geom1, geom2); + return _doMultiPointAndLineStringCross(geom1, geom2); } else if (geom2 is Polygon) { - return doesMultiPointCrossPoly(geom1, geom2); + return _doesMultiPointCrossPoly(geom1, geom2); } else { throw exception; } } else if (geom1 is LineString) { if (geom2 is MultiPoint) { // An inverse operation - return doMultiPointAndLineStringCross(geom2, geom1); + return _doMultiPointAndLineStringCross(geom2, geom1); } else if (geom2 is LineString) { - return doLineStringsCross(geom1, geom2); + return _doLineStringsCross(geom1, geom2); } else if (geom2 is Polygon) { - return doLineStringAndPolygonCross(geom1, geom2); + return _doLineStringAndPolygonCross(geom1, geom2); } else { throw exception; } } else if (geom1 is Polygon) { if (geom2 is MultiPoint) { // An inverse operation - return doesMultiPointCrossPoly(geom2, geom1); + return _doesMultiPointCrossPoly(geom2, geom1); } else if (geom2 is LineString) { // An inverse operation - return doLineStringAndPolygonCross(geom2, geom1); + return _doLineStringAndPolygonCross(geom2, geom1); } else { throw exception; } @@ -66,7 +66,7 @@ bool booleanCrosses(GeoJSONObject feature1, GeoJSONObject feature2) { } } -bool doMultiPointAndLineStringCross( +bool _doMultiPointAndLineStringCross( MultiPoint multiPoint, LineString lineString) { var foundIntPoint = false; var foundExtPoint = false; @@ -93,7 +93,7 @@ bool doMultiPointAndLineStringCross( return foundIntPoint && foundExtPoint; } -bool doLineStringsCross(LineString lineString1, LineString lineString2) { +bool _doLineStringsCross(LineString lineString1, LineString lineString2) { var doLinesIntersect = lineIntersect(lineString1, lineString2); if (doLinesIntersect.features.isNotEmpty) { for (var i = 0; i < lineString1.coordinates.length - 1; i++) { @@ -115,7 +115,7 @@ bool doLineStringsCross(LineString lineString1, LineString lineString2) { return false; } -bool doLineStringAndPolygonCross(LineString lineString, Polygon polygon) { +bool _doLineStringAndPolygonCross(LineString lineString, Polygon polygon) { Feature line = polygonToLine(polygon) as Feature; var doLinesIntersect = lineIntersect(lineString, line); if (doLinesIntersect.features.isNotEmpty) return true; @@ -123,7 +123,7 @@ bool doLineStringAndPolygonCross(LineString lineString, Polygon polygon) { return false; } -bool doesMultiPointCrossPoly(MultiPoint multiPoint, Polygon polygon) { +bool _doesMultiPointCrossPoly(MultiPoint multiPoint, Polygon polygon) { var foundIntPoint = false; var foundExtPoint = false; var pointLength = multiPoint.coordinates.length; diff --git a/lib/src/booleans/boolean_disjoint.dart b/lib/src/booleans/boolean_disjoint.dart index dab2fe68..ff104ca4 100644 --- a/lib/src/booleans/boolean_disjoint.dart +++ b/lib/src/booleans/boolean_disjoint.dart @@ -46,23 +46,23 @@ bool _disjoint(GeometryType geom1, GeometryType geom2) { if (geom2 is Point) { return geom1.coordinates != geom2.coordinates; } else if (geom2 is LineString) { - return !isPointOnLine(geom2, geom1); + return !_isPointOnLine(geom2, geom1); } else if (geom2 is Polygon) { return !booleanPointInPolygon((geom1).coordinates, geom2); } } else if (geom1 is LineString) { if (geom2 is Point) { - return !isPointOnLine(geom1, geom2); + return !_isPointOnLine(geom1, geom2); } else if (geom2 is LineString) { - return !isLineOnLine(geom1, geom2); + return !_isLineOnLine(geom1, geom2); } else if (geom2 is Polygon) { - return !isLineInPoly(geom2, geom1); + return !_isLineInPoly(geom2, geom1); } } else if (geom1 is Polygon) { if (geom2 is Point) { return !booleanPointInPolygon((geom2).coordinates, geom1); } else if (geom2 is LineString) { - return !isLineInPoly(geom1, geom2); + return !_isLineInPoly(geom1, geom2); } else if (geom2 is Polygon) { return !_isPolyInPoly(geom2, geom1); } @@ -71,7 +71,7 @@ bool _disjoint(GeometryType geom1, GeometryType geom2) { } // http://stackoverflow.com/a/11908158/1979085 -bool isPointOnLine(LineString lineString, Point pt) { +bool _isPointOnLine(LineString lineString, Point pt) { for (var i = 0; i < lineString.coordinates.length - 1; i++) { if (isPointOnLineSegment(lineString.coordinates[i], lineString.coordinates[i + 1], pt.coordinates, true)) { @@ -81,7 +81,7 @@ bool isPointOnLine(LineString lineString, Point pt) { return false; } -bool isLineOnLine(LineString lineString1, LineString lineString2) { +bool _isLineOnLine(LineString lineString1, LineString lineString2) { var doLinesIntersect = lineIntersect(lineString1, lineString2); if (doLinesIntersect.features.isNotEmpty) { return true; @@ -89,7 +89,7 @@ bool isLineOnLine(LineString lineString1, LineString lineString2) { return false; } -bool isLineInPoly(Polygon polygon, LineString lineString) { +bool _isLineInPoly(Polygon polygon, LineString lineString) { for (var coord in lineString.coordinates) { if (booleanPointInPolygon(coord, polygon)) { return true; From 2ac6308b67bded78936b9bac6cb4a833a7247a7a Mon Sep 17 00:00:00 2001 From: Lukas Himsel Date: Sun, 11 Sep 2022 17:16:29 +0200 Subject: [PATCH 78/82] resolves allllllllll outdated conversations, refactor --- analysis_options.yaml | 2 +- lib/src/polygon_smooth.dart | 6 +++--- test/components/center_test.dart | 1 + test/components/clean_coords_test.dart | 1 + test/components/explode_test.dart | 1 + test/components/geojson_test.dart | 1 - test/components/line_intersect_test.dart | 1 + test/components/line_overlap.dart | 1 + test/components/line_to_polygon_test.dart | 1 + test/components/polygon_smooth_test.dart | 1 + test/components/polygon_to_line_test.dart | 1 + 11 files changed, 12 insertions(+), 5 deletions(-) diff --git a/analysis_options.yaml b/analysis_options.yaml index 75bcd156..95724bff 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -2,7 +2,7 @@ include: package:dartclub_lint/dart.yaml linter: rules: - # always_declare_return_types: true + always_declare_return_types: true analyzer: errors: prefer_generic_function_type_aliases: error diff --git a/lib/src/polygon_smooth.dart b/lib/src/polygon_smooth.dart index 33b3f473..cb30c98e 100644 --- a/lib/src/polygon_smooth.dart +++ b/lib/src/polygon_smooth.dart @@ -33,9 +33,9 @@ FeatureCollection polygonSmooth(GeoJSONObject inputPolys, BBox? featureBBox, dynamic featureId, ) { - var outCoords; - var poly; - var tempOutput; + dynamic outCoords; + dynamic poly; + dynamic tempOutput; switch (geom?.type) { case GeoJSONObjectType.polygon: diff --git a/test/components/center_test.dart b/test/components/center_test.dart index b6cc1bbf..c642d22e 100644 --- a/test/components/center_test.dart +++ b/test/components/center_test.dart @@ -58,6 +58,7 @@ void main() { ); featureCollection.features.add(extent); + // ignore: prefer_interpolation_to_compose_strings var outPath = './' + file.uri.pathSegments .sublist(0, file.uri.pathSegments.length - 2) diff --git a/test/components/clean_coords_test.dart b/test/components/clean_coords_test.dart index 591dcb92..4edd3b39 100644 --- a/test/components/clean_coords_test.dart +++ b/test/components/clean_coords_test.dart @@ -19,6 +19,7 @@ void main() { var inSource = file.readAsStringSync(); var inGeom = GeoJSONObject.fromJson(jsonDecode(inSource)); Feature results = cleanCoords(inGeom); + // ignore: prefer_interpolation_to_compose_strings var outPath = './' + file.uri.pathSegments .sublist(0, file.uri.pathSegments.length - 2) diff --git a/test/components/explode_test.dart b/test/components/explode_test.dart index e83e7f06..d5c55984 100644 --- a/test/components/explode_test.dart +++ b/test/components/explode_test.dart @@ -19,6 +19,7 @@ void main() { var inGeom = GeoJSONObject.fromJson(jsonDecode(inSource)); var inExploded = explode(inGeom); + // ignore: prefer_interpolation_to_compose_strings var outPath = './' + file.uri.pathSegments .sublist(0, file.uri.pathSegments.length - 2) diff --git a/test/components/geojson_test.dart b/test/components/geojson_test.dart index a7439d3c..87a29c67 100644 --- a/test/components/geojson_test.dart +++ b/test/components/geojson_test.dart @@ -411,7 +411,6 @@ void main() { Position(100, 0), ); } - // TODO refine tests }, ); diff --git a/test/components/line_intersect_test.dart b/test/components/line_intersect_test.dart index eafa6746..cfa50260 100644 --- a/test/components/line_intersect_test.dart +++ b/test/components/line_intersect_test.dart @@ -18,6 +18,7 @@ void main() { var inGeom = GeoJSONObject.fromJson(jsonDecode(inSource)) as FeatureCollection; + // ignore: prefer_interpolation_to_compose_strings var outPath = './' + file.uri.pathSegments .sublist(0, file.uri.pathSegments.length - 2) diff --git a/test/components/line_overlap.dart b/test/components/line_overlap.dart index e3ba3056..ad25466f 100644 --- a/test/components/line_overlap.dart +++ b/test/components/line_overlap.dart @@ -40,6 +40,7 @@ void main() { var inGeom = GeoJSONObject.fromJson(jsonDecode(inSource)) as FeatureCollection; + // ignore: prefer_interpolation_to_compose_strings var outPath = './' + file.uri.pathSegments .sublist(0, file.uri.pathSegments.length - 2) diff --git a/test/components/line_to_polygon_test.dart b/test/components/line_to_polygon_test.dart index 05ee4378..75591f3f 100644 --- a/test/components/line_to_polygon_test.dart +++ b/test/components/line_to_polygon_test.dart @@ -25,6 +25,7 @@ void main() { properties: properties, ); + // ignore: prefer_interpolation_to_compose_strings var outPath = './' + file.uri.pathSegments .sublist(0, file.uri.pathSegments.length - 2) diff --git a/test/components/polygon_smooth_test.dart b/test/components/polygon_smooth_test.dart index 7a01170d..2b92dab5 100644 --- a/test/components/polygon_smooth_test.dart +++ b/test/components/polygon_smooth_test.dart @@ -15,6 +15,7 @@ void main() { var inSource = file.readAsStringSync(); var inGeom = GeoJSONObject.fromJson(jsonDecode(inSource)); var results = polygonSmooth(inGeom, iterations: 3); + // ignore: prefer_interpolation_to_compose_strings var outPath = './' + file.uri.pathSegments .sublist(0, file.uri.pathSegments.length - 2) diff --git a/test/components/polygon_to_line_test.dart b/test/components/polygon_to_line_test.dart index 6e6f976d..a4b761f1 100644 --- a/test/components/polygon_to_line_test.dart +++ b/test/components/polygon_to_line_test.dart @@ -20,6 +20,7 @@ void main() { var inGeom = GeoJSONObject.fromJson(jsonDecode(inSource)); var results = polygonToLine(inGeom); + // ignore: prefer_interpolation_to_compose_strings var outPath = './' + file.uri.pathSegments .sublist(0, file.uri.pathSegments.length - 2) From 8f06118ee89ed29b9068be6c0dfe3e9771dd2356 Mon Sep 17 00:00:00 2001 From: Lukas Himsel Date: Sun, 11 Sep 2022 17:21:01 +0200 Subject: [PATCH 79/82] use getGeom in booleanTouches --- lib/src/booleans/boolean_touches.dart | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/src/booleans/boolean_touches.dart b/lib/src/booleans/boolean_touches.dart index 451cc3a5..79109e90 100644 --- a/lib/src/booleans/boolean_touches.dart +++ b/lib/src/booleans/boolean_touches.dart @@ -1,3 +1,5 @@ +import 'package:turf/src/invariant.dart'; + import '../../helpers.dart'; import 'boolean_point_in_polygon.dart'; import 'boolean_point_on_line.dart'; @@ -12,8 +14,8 @@ import 'boolean_point_on_line.dart'; /// //=true /// ``` bool booleanTouches(GeoJSONObject feature1, GeoJSONObject feature2) { - var geom1 = feature1 is Feature ? feature1.geometry : feature1; - var geom2 = feature2 is Feature ? feature2.geometry : feature2; + var geom1 = getGeom(feature1); + var geom2 = getGeom(feature2); if (geom1 is Point) { if (geom2 is LineString) { From 0c7dc7902bd3cd08cb9ba973e5876fa3f2a6f084 Mon Sep 17 00:00:00 2001 From: Lukas Himsel Date: Sun, 11 Sep 2022 17:26:32 +0200 Subject: [PATCH 80/82] use getGeom more frequently --- lib/src/booleans/boolean_valid.dart | 5 +++-- lib/src/clean_coords.dart | 3 +-- lib/src/invariant.dart | 8 ++++++-- lib/src/polygon_to_line.dart | 4 +++- 4 files changed, 13 insertions(+), 7 deletions(-) diff --git a/lib/src/booleans/boolean_valid.dart b/lib/src/booleans/boolean_valid.dart index 2566fff9..5a06e741 100644 --- a/lib/src/booleans/boolean_valid.dart +++ b/lib/src/booleans/boolean_valid.dart @@ -1,6 +1,7 @@ import 'package:turf/polygon_to_line.dart'; import 'package:turf/src/booleans/boolean_disjoint.dart'; import 'package:turf/src/booleans/boolean_point_on_line.dart'; +import 'package:turf/src/invariant.dart'; import 'package:turf/src/meta/extensions.dart'; import '../../helpers.dart'; @@ -66,7 +67,7 @@ bool booleanValid(GeoJSONObject feature) { } } } else { - var geom = feature is Feature ? feature.geometry : feature; + var geom = getGeom(feature); if (geom is Point) { if (!(geom.coordinates.length >= 2 && geom.coordinates.length <= 3)) { @@ -141,7 +142,7 @@ bool booleanValid(GeoJSONObject feature) { } } } else { - throw Exception('the type ${geom?.type} is not supported'); + throw Exception('the type ${geom.type} is not supported'); } } return true; diff --git a/lib/src/clean_coords.dart b/lib/src/clean_coords.dart index 5ee1b37e..41989a66 100644 --- a/lib/src/clean_coords.dart +++ b/lib/src/clean_coords.dart @@ -21,8 +21,7 @@ Feature cleanCoords( if (geojson is Feature && geojson.geometry == null) { throw Exception("Geometry of the Feature is null"); } - GeometryObject geom = - geojson is Feature ? geojson.geometry! : geojson as GeometryObject; + GeometryObject geom = getGeom(geojson); geom = mutate ? geom : geom.clone() as GeometryObject; if (geojson is GeometryCollection || geojson is FeatureCollection) { diff --git a/lib/src/invariant.dart b/lib/src/invariant.dart index 20bd36f5..89fd3c74 100644 --- a/lib/src/invariant.dart +++ b/lib/src/invariant.dart @@ -87,9 +87,13 @@ List _getCoordsForGeometry(GeometryObject geom) { /// )); /// var geom = getGeom(feature) /// //= Point(coordinates: Position.of([110, 40])) -GeoJSONObject getGeom(GeoJSONObject geojson) { +GeometryObject getGeom(GeoJSONObject geojson) { if (geojson is Feature) { return geojson.geometry!; + } else if (geojson is FeatureCollection) { + throw Exception( + 'Cannot retrieve single Geometry from FeatureCollection in getGeom', + ); } - return geojson; + return geojson as GeometryObject; } diff --git a/lib/src/polygon_to_line.dart b/lib/src/polygon_to_line.dart index a1b6d65b..609fe151 100644 --- a/lib/src/polygon_to_line.dart +++ b/lib/src/polygon_to_line.dart @@ -1,3 +1,5 @@ +import 'package:turf/src/invariant.dart'; + import '../helpers.dart'; /// Converts a [Polygon] to [LineString] or [MultiLineString] or a [MultiPolygon] @@ -21,7 +23,7 @@ import '../helpers.dart'; /// ``` GeoJSONObject polygonToLine(GeoJSONObject poly, {Map? properties}) { - var geom = poly is Feature ? poly.geometry : poly; + var geom = getGeom(poly); properties = properties ?? ((poly is Feature) ? poly.properties : {}); From 955c01564a65013352369596e2049cb2d882574a Mon Sep 17 00:00:00 2001 From: Lukas Himsel Date: Sun, 11 Sep 2022 17:32:58 +0200 Subject: [PATCH 81/82] rm linter rule, which is already inherited from dartclub_lint --- analysis_options.yaml | 3 --- 1 file changed, 3 deletions(-) diff --git a/analysis_options.yaml b/analysis_options.yaml index 95724bff..f6555aff 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -1,8 +1,5 @@ include: package:dartclub_lint/dart.yaml -linter: - rules: - always_declare_return_types: true analyzer: errors: prefer_generic_function_type_aliases: error From 2306c59e514d8addaf210388cc790a7db1eccdfa Mon Sep 17 00:00:00 2001 From: Lukas Himsel Date: Sun, 11 Sep 2022 18:26:10 +0200 Subject: [PATCH 82/82] cleanup, ready for merge --- README.md | 31 ++- ...intersect.dart => boolean_intersects.dart} | 0 lib/src/line_overlap.dart | 194 --------------- ...tersect_test.dart => intersects_test.dart} | 2 +- test/components/line_overlap.dart | 224 ------------------ 5 files changed, 19 insertions(+), 432 deletions(-) rename lib/src/booleans/{boolean_intersect.dart => boolean_intersects.dart} (100%) delete mode 100644 lib/src/line_overlap.dart rename test/booleans/{intersect_test.dart => intersects_test.dart} (98%) delete mode 100644 test/components/line_overlap.dart diff --git a/README.md b/README.md index 92e8c258..bd066e46 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,7 @@ Most of the implementation is a direct translation from [turf.js](https://github - Get the [Dart tools](https://dart.dev/tools) - Install the library with `dart pub add turf` - Import the library in your code and use it. For example: + ```dart import 'package:turf/helpers.dart'; import 'package:turf/src/line_segment.dart'; @@ -145,7 +146,7 @@ Any new benchmarks must be named `*_benchmark.dart` and reside in the - [ ] kinks - [ ] lineArc - [ ] lineChunk -- [ ] lineIntersect +- [ ] [lineIntersect](https://github.com/dartclub/turf_dart/blob/main/lib/src/line_intersect.dart) - [ ] lineOverlap - [x] [lineSegment](https://github.com/dartclub/turf_dart/blob/main/lib/src/line_segment.dart) - [ ] lineSlice @@ -207,8 +208,6 @@ Any new benchmarks must be named `*_benchmark.dart` and reside in the - [x] [featureReduce](https://github.com/dartclub/turf_dart/blob/main/lib/src/meta/feature.dart) - [x] [flattenEach](https://github.com/dartclub/turf_dart/blob/main/lib/src/meta/flatten.dart) - [x] [flattenReduce](https://github.com/dartclub/turf_dart/blob/main/lib/src/meta/flatten.dart) -- [x] [getCoord](https://github.com/dartclub/turf_dart/blob/main/lib/src/meta/coord.dart) -- [x] [getCoords](https://github.com/dartclub/turf_dart/blob/main/lib/src/meta/coord.dart) - [x] [geomEach](https://github.com/dartclub/turf_dart/blob/main/lib/src/meta/geom.dart) - [x] [geomReduce](https://github.com/dartclub/turf_dart/blob/main/lib/src/meta/geom.dart) - [x] [propEach](https://github.com/dartclub/turf_dart/blob/main/lib/src/meta/prop.dart) @@ -219,19 +218,25 @@ Any new benchmarks must be named `*_benchmark.dart` and reside in the - [x] [clusterEach](https://github.com/dartclub/turf_dart/blob/main/lib/src/meta/cluster.dart) - [x] [clusterReduce](https://github.com/dartclub/turf_dart/blob/main/lib/src/meta/cluster.dart) +### Invariants + +- [x] [getCoord](https://github.com/dartclub/turf_dart/blob/main/lib/src/meta/coord.dart) +- [x] [getCoords](https://github.com/dartclub/turf_dart/blob/main/lib/src/invariant.dart) +- [x] [getGeom](https://github.com/dartclub/turf_dart/blob/main/lib/src/invariant.dart) + ### Booleans -- [ ] booleanClockwise -- [ ] booleanConcave -- [ ] booleanContains -- [ ] booleanCrosses -- [ ] booleanDisjoint -- [ ] booleanEqual -- [ ] booleanIntersects +- [x] [booleanClockwise](https://github.com/dartclub/turf_dart/blob/main/lib/src/booleans/boolean_clockwise.dart) +- [x] [booleanConcave](https://github.com/dartclub/turf_dart/blob/main/lib/src/booleans/boolean_concave.dart) +- [x] [booleanContains](https://github.com/dartclub/turf_dart/blob/main/lib/src/booleans/boolean_contains.dart) +- [x] [booleanCrosses](https://github.com/dartclub/turf_dart/blob/main/lib/src/booleans/boolean_crosses.dart) +- [x] [booleanDisjoint](https://github.com/dartclub/turf_dart/blob/main/lib/src/booleans/boolean_disjoint.dart) +- [x] [booleanEqual](https://github.com/dartclub/turf_dart/blob/main/lib/src/booleans/boolean_equal.dart) +- [x] [booleanIntersects](https://github.com/dartclub/turf_dart/blob/main/lib/src/booleans/boolean_intersect.dart) - [ ] booleanOverlap -- [ ] booleanParallel -- [ ] booleanPointInPolygon -- [ ] booleanPointOnLine +- [x] [booleanParallel](https://github.com/dartclub/turf_dart/blob/main/lib/src/booleans/boolean_parallel.dart) +- [x] [booleanPointInPolygon](https://github.com/dartclub/turf_dart/blob/main/lib/src/booleans/boolean_point_in_polygon.dart) +- [x] [booleanPointOnLine](https://github.com/dartclub/turf_dart/blob/main/lib/src/booleans/boolean_point_on_line.dart) - [ ] booleanWithin ### Unit Conversion diff --git a/lib/src/booleans/boolean_intersect.dart b/lib/src/booleans/boolean_intersects.dart similarity index 100% rename from lib/src/booleans/boolean_intersect.dart rename to lib/src/booleans/boolean_intersects.dart diff --git a/lib/src/line_overlap.dart b/lib/src/line_overlap.dart deleted file mode 100644 index efa68d52..00000000 --- a/lib/src/line_overlap.dart +++ /dev/null @@ -1,194 +0,0 @@ -import 'package:rbush/rbush.dart'; -import 'package:turf/bbox.dart'; -import 'package:turf/helpers.dart'; -import 'package:turf/line_segment.dart'; -import 'package:turf/nearest_point_on_line.dart'; -import 'package:turf/src/booleans/boolean_point_on_line.dart'; -import 'package:turf/src/invariant.dart'; -import 'package:turf/src/meta/feature.dart'; -import 'package:turf_equality/turf_equality.dart'; - -/// Takes any [LineString] or [Polygon] and returns the overlapping [LineString]s -/// between both [Feature]s. [line1] is a [Feature]<[LineString]|[MultiLineString] -/// |[Polygon]|[MultiPolygon]> or any [LineString] or [Polygon], [line2] is a -/// [Feature]<[LineString]|[MultiLineString]|[Polygon]|[MultiPolygon]> or any -/// [LineString] or [Polygon]. [tolerance=0] Tolerance distance to match -/// overlapping line segments (in kilometers) returns a [FeatureCollection]<[LineString]> -/// lines(s) that are overlapping between both [Feature]s. -/// example -/// ```dart -/// var line1 = LineString( -/// coordinates: [ -/// Position.of([115, -35]), -/// Position.of([125, -30]), -/// Position.of([135, -30]), -/// Position.of([145, -35]) -/// ], -/// ); -/// var line2 = LineString( -/// coordinates: [ -/// Position.of([115, -25]), -/// Position.of([125, -30]), -/// Position.of([135, -30]), -/// Position.of([145, -25]) -/// ], -/// ); -/// var overlapping = lineOverlap(line1, line2); -/// //addToMap -/// var addToMap = [line1, line2, overlapping] -///``` -FeatureCollection lineOverlap( - GeoJSONObject line1, GeoJSONObject line2, - {num tolerance = 0}) { - RBushBox _toRBBox(Feature feature) { - var bb = bbox(feature); - return RBushBox( - minX: bb.lng1.toDouble(), - minY: bb.lat1.toDouble(), - maxX: bb.lng2.toDouble(), - maxY: bb.lat2.toDouble()); - } - // Optional parameters - - // Containers - var features = >[]; - - // Create Spatial Index - var tree = RBushBase>( - getMinY: (Feature feature) => bbox(feature).lat1.toDouble(), - getMinX: (Feature feature) => bbox(feature).lng1.toDouble(), - toBBox: (feature) => _toRBBox(feature)); - - var line = lineSegment(line1); - tree.load(line.features); - Feature? overlapSegment; - var additionalSegments = >[]; - - // Line Intersection - - // Iterate over line segments - segmentEach(line2, (Feature currentSegment, int featureIndex, - int? multiFeatureIndex, int? geometryIndex, int segmentIndex) { - var doesOverlaps = false; - - // Iterate over each segments which falls within the same bounds - featureEach( - FeatureCollection( - features: tree.search(_toRBBox(currentSegment))), (match, index) { - if (!doesOverlaps) { - List coordsSegment = () { - List list = getCoords(currentSegment) as List; - list.sort(); - return list; - }(); - List coordsMatch = () { - List list = getCoords(match) as List; - list.sort(); - return list; - }(); - - Equality eq = Equality(); - // Segment overlaps feature - with dummy LineStrings just to use eq. - if (eq.compare(LineString(coordinates: coordsSegment), - LineString(coordinates: coordsMatch))) { - doesOverlaps = true; - // Overlaps already exists - only append last coordinate of segment - if (overlapSegment != null) { - overlapSegment = concatSegment(overlapSegment!, currentSegment) ?? - overlapSegment; - } else { - overlapSegment = currentSegment; - } - // Match segments which don't share nodes (Issue #901) - } else if (tolerance == 0 - ? booleanPointOnLine(Point(coordinates: coordsSegment[0]), - match.geometry as LineString) && - booleanPointOnLine(Point(coordinates: coordsSegment[1]), - match.geometry as LineString) - : nearestPointOnLine(match.geometry as LineString, - Point(coordinates: coordsSegment[0])) - .properties!['dist'] <= - tolerance && - nearestPointOnLine(match.geometry as LineString, - Point(coordinates: coordsSegment[1])) - .properties!['dist'] <= - tolerance) { - doesOverlaps = true; - if (overlapSegment != null) { - overlapSegment = concatSegment(overlapSegment!, currentSegment) ?? - overlapSegment; - } else { - overlapSegment = currentSegment; - } - } else if (tolerance == 0 - ? booleanPointOnLine(Point(coordinates: coordsMatch[0]), - currentSegment.geometry as LineString) && - booleanPointOnLine(Point(coordinates: coordsMatch[1]), - currentSegment.geometry as LineString) - : nearestPointOnLine(currentSegment.geometry as LineString, - Point(coordinates: coordsMatch[0])) - .properties!['dist'] <= - tolerance && - nearestPointOnLine(currentSegment.geometry as LineString, - Point(coordinates: coordsMatch[1])) - .properties!['dist'] <= - tolerance) { - // Do not define doesOverlap = true since more matches can occur - // within the same segment - // doesOverlaps = true; - if (overlapSegment != null) { - var combinedSegment = - concatSegment(overlapSegment!, match as Feature); - if (combinedSegment != null) { - overlapSegment = combinedSegment; - } else { - additionalSegments.add(match); - } - } else { - overlapSegment = match as Feature; - } - } - } - }); - - // Segment doesn't overlap - add overlaps to results & reset - if (doesOverlaps == false && overlapSegment != null) { - features.add(overlapSegment!); - if (additionalSegments.isNotEmpty) { - features = [...features, ...additionalSegments]; - additionalSegments = []; - } - overlapSegment = null; - } - }); - // Add last segment if exists - if (overlapSegment != null) features.add(overlapSegment!); - - return FeatureCollection(features: features); -} - -Feature? concatSegment( - Feature line, Feature segment) { - var newLine = line.clone(); - var coords = getCoords(segment); - var lineCoords = getCoords(newLine); - var start = lineCoords[0]; - var end = lineCoords[lineCoords.length - 1]; - List geom = (newLine.geometry as LineString).coordinates; - - if (coords[0] == start) { - geom.insert(0, coords[1]); - } else if (coords[0] == end) { - geom.add(coords[1]); - } else if (coords[1] == start) { - geom.insert(0, coords[0]); - } else if (coords[1] == end) { - geom.add(coords[0]); - } else { - return null; - } // If the overlap leaves the segment unchanged, return null so that this can be - // identified. - - // Otherwise return the mutated line. - return newLine; -} diff --git a/test/booleans/intersect_test.dart b/test/booleans/intersects_test.dart similarity index 98% rename from test/booleans/intersect_test.dart rename to test/booleans/intersects_test.dart index 3769445e..886cfe07 100644 --- a/test/booleans/intersect_test.dart +++ b/test/booleans/intersects_test.dart @@ -3,7 +3,7 @@ import 'dart:io'; import 'package:test/test.dart'; import 'package:turf/helpers.dart'; -import 'package:turf/src/booleans/boolean_intersect.dart'; +import 'package:turf/src/booleans/boolean_intersects.dart'; void main() { var featureCollection = FeatureCollection(features: [ diff --git a/test/components/line_overlap.dart b/test/components/line_overlap.dart deleted file mode 100644 index ad25466f..00000000 --- a/test/components/line_overlap.dart +++ /dev/null @@ -1,224 +0,0 @@ -import 'dart:convert'; -import 'dart:io'; - -import 'package:test/test.dart'; -import 'package:turf/helpers.dart'; -import 'package:turf/src/line_overlap.dart'; -import 'package:turf/src/meta/feature.dart'; -import 'package:turf_equality/turf_equality.dart'; - -void main() { - FeatureCollection colorize(features, {color = "#F00", width = 25}) { - var results = []; - featureEach( - features, - (Feature currentFeature, int featureIndex) { - currentFeature.properties = { - 'stroke': color, - 'fill': color, - "stroke-width": width - }; - results.add(currentFeature); - }, - ); - return FeatureCollection(features: results); - } - - group( - 'line_overlap function', - () { - // fixtures = fixtures.filter(({name}) => name.includes('#901')); - - var inDir = Directory('./test/examples/line_overlap/in'); - for (var file in inDir.listSync(recursive: true)) { - if (file is File && file.path.endsWith('.geojson')) { - if (file.path.contains('#901')) { - test( - file.path, - () { - var inSource = file.readAsStringSync(); - var inGeom = GeoJSONObject.fromJson(jsonDecode(inSource)) - as FeatureCollection; - - // ignore: prefer_interpolation_to_compose_strings - var outPath = './' + - file.uri.pathSegments - .sublist(0, file.uri.pathSegments.length - 2) - .join('/') + - '/out/${file.uri.pathSegments.last}'; - - var outSource = File(outPath).readAsStringSync(); - - var outGeom = GeoJSONObject.fromJson(jsonDecode(outSource)); - - Equality eq = Equality(); - FeatureCollection shared = colorize( - lineOverlap(inGeom.features[0], inGeom.features[1], - tolerance: 0.05), - color: "#0F0"); - FeatureCollection results = FeatureCollection(features: [ - ...shared.features, - inGeom.features.first, - inGeom.features.last - ]); - expect(eq.compare(results, outGeom), true); - }, - ); - } - } - } - // test( - // "turf-line-overlap - Geometry Object", - // () { - // var line1 = LineString( - // coordinates: [ - // Position.of([115, -35]), - // Position.of([125, -30]), - // Position.of([135, -30]), - // Position.of([145, -35]), - // ], - // ); - // var line2 = LineString( - // coordinates: [ - // Position.of([135, -30]), - // Position.of([145, -35]), - // ], - // ); - - // expect(lineOverlap(line1, line2).features.isNotEmpty, true); - // }, - // ); - - // test( - // "turf-line-overlap - multiple segments on same line", - // () { - // var line1 = LineString( - // coordinates: [ - // Position.of([0, 1]), - // Position.of([1, 1]), - // Position.of([1, 0]), - // Position.of([2, 0]), - // Position.of([2, 1]), - // Position.of([3, 1]), - // Position.of([3, 0]), - // Position.of([4, 0]), - // Position.of([4, 1]), - // Position.of([4, 0]), - // ], - // ); - // var line2 = LineString( - // coordinates: [ - // Position.of([0, 0]), - // Position.of([6, 0]), - // ], - // ); - - // expect(lineOverlap(line1, line2).features.length == 2, true); - // expect(lineOverlap(line2, line1).features.length == 2, true); - // }, - // ); - }, - ); -} - -/** - * const fs = require("fs"); -const test = require("tape"); -const path = require("path"); -const load = require("load-json-file"); -const write = require("write-json-file"); -const { featureEach } = require("@turf/meta"); -const { featureCollection, lineString } = require("@turf/helpers"); -const lineOverlap = require("./index").default; - -const directories = { - in: path.join(__dirname, "test", "in") + path.sep, - out: path.join(__dirname, "test", "out") + path.sep, -}; - -let fixtures = fs.readdirSync(directories.in).map((filename) => { - return { - filename, - name: path.parse(filename).name, - geojson: load.sync(directories.in + filename), - }; -}); -// fixtures = fixtures.filter(({name}) => name.includes('#901')); - -test("turf-line-overlap", (t) => { - for (const { filename, name, geojson } of fixtures) { - const [source, target] = geojson.features; - const shared = colorize( - lineOverlap(source, target, geojson.properties), - "#0F0" - ); - const results = featureCollection(shared.features.concat([source, target])); - - if (process.env.REGEN) write.sync(directories.out + filename, results); - t.deepEquals(results, load.sync(directories.out + filename), name); - } - t.end(); -}); - -test("turf-line-overlap - Geometry Object", (t) => { - const line1 = lineString([ - [115, -35], - [125, -30], - [135, -30], - [145, -35], - ]); - const line2 = lineString([ - [135, -30], - [145, -35], - ]); - - t.true( - lineOverlap(line1.geometry, line2.geometry).features.length > 0, - "support geometry object" - ); - t.end(); -}); - -test("turf-line-overlap - multiple segments on same line", (t) => { - const line1 = lineString([ - [0, 1], - [1, 1], - [1, 0], - [2, 0], - [2, 1], - [3, 1], - [3, 0], - [4, 0], - [4, 1], - [4, 0], - ]); - const line2 = lineString([ - [0, 0], - [6, 0], - ]); - - t.true( - lineOverlap(line1.geometry, line2.geometry).features.length === 2, - "multiple segments on same line" - ); - t.true( - lineOverlap(line2.geometry, line1.geometry).features.length === 2, - "multiple segments on same line - swapped order" - ); - t.end(); -}); - -function colorize(features, color = "#F00", width = 25) { - const results = []; - featureEach(features, (feature) => { - feature.properties = { - stroke: color, - fill: color, - "stroke-width": width, - }; - results.push(feature); - }); - if (features.type === "Feature") return results[0]; - return featureCollection(results); -} - */