Skip to content

Commit

Permalink
Implement booleanWithin (#167)
Browse files Browse the repository at this point in the history
* document feature booleanWithin

* implement boolean within

* implement boolean within

* add boolean within tests

* export boolean features

* remove duplicate code

* refactor tests

* rename import

* remove warnings

* add source link to readme

* add library declaration for turf_boolean

* Code review suggestions

* .

* .

* fix typos

* fix analyzer warning due to recent dart 3.3.0 release
  • Loading branch information
jsiedentop authored Feb 17, 2024
1 parent f377e46 commit dafa3cd
Show file tree
Hide file tree
Showing 10 changed files with 496 additions and 132 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ Any new benchmarks must be named `*_benchmark.dart` and reside in the
- [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
- [x] [booleanWithin](https://github.com/dartclub/turf_dart/blob/main/lib/src/booleans/boolean_within.dart)

### Unit Conversion

Expand All @@ -250,4 +250,4 @@ Any new benchmarks must be named `*_benchmark.dart` and reside in the
- [x] [radiansToLength](https://github.com/dartclub/turf_dart/blob/main/lib/src/helpers.dart)
- [x] [radiansToDegrees](https://github.com/dartclub/turf_dart/blob/main/lib/src/helpers.dart)
- [ ] toMercator
- [ ] toWgs84
- [ ] toWgs84
16 changes: 16 additions & 0 deletions lib/boolean.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
library turf_boolean;

export 'src/booleans/boolean_clockwise.dart';
export 'src/booleans/boolean_concave.dart';
export 'src/booleans/boolean_contains.dart';
export 'src/booleans/boolean_crosses.dart';
export 'src/booleans/boolean_disjoint.dart';
export 'src/booleans/boolean_equal.dart';
export 'src/booleans/boolean_intersects.dart';
// export 'src/booleans/boolean_overlap.dart';
export 'src/booleans/boolean_parallel.dart';
export 'src/booleans/boolean_point_in_polygon.dart';
export 'src/booleans/boolean_point_on_line.dart';
export 'src/booleans/boolean_touches.dart';
export 'src/booleans/boolean_valid.dart';
export 'src/booleans/boolean_within.dart';
130 changes: 22 additions & 108 deletions lib/src/booleans/boolean_contains.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import 'package:turf/turf.dart';

import 'boolean_point_in_polygon.dart';
import 'boolean_point_on_line.dart';
import 'boolean_helper.dart';

/// [booleanContains] returns [true] if the second geometry is completely contained
/// by the first geometry.
Expand All @@ -11,162 +12,75 @@ import 'boolean_point_on_line.dart';
/// [booleanContains] returns the exact opposite result of the [booleanWithin].
/// example:
/// ```dart
/// var line = LineString(coordinates: [
/// final 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]));
/// final point = Point(coordinates: Position.of([1, 2]));
/// booleanContains(line, point);
/// //=true
/// ```
bool booleanContains(GeoJSONObject feature1, GeoJSONObject feature2) {
var geom1 = getGeom(feature1);
var geom2 = getGeom(feature2);
final geom1 = getGeom(feature1);
final geom2 = getGeom(feature2);

var coords1 = (geom1 as GeometryType).coordinates;
var coords2 = (geom2 as GeometryType).coordinates;
final exception = Exception("{feature2 $geom2 geometry not supported}");
final coords1 = (geom1 as GeometryType).coordinates;
final coords2 = (geom2 as GeometryType).coordinates;
if (geom1 is Point) {
if (geom2 is Point) {
return coords1 == coords2;
} else {
throw exception;
throw FeatureNotSupported(geom1, geom2);
}
} else if (geom1 is MultiPoint) {
if (geom2 is Point) {
return _isPointInMultiPoint(geom1, geom2);
return isPointInMultiPoint(geom2, geom1);
} else if (geom2 is MultiPoint) {
return _isMultiPointInMultiPoint(geom1, geom2);
return isMultiPointInMultiPoint(geom2, geom1);
} else {
throw exception;
throw FeatureNotSupported(geom1, geom2);
}
} 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(geom2, geom1);
} else if (geom2 is MultiPoint) {
return _isMultiPointOnLine(geom1, geom2);
return isMultiPointOnLine(geom2, geom1);
} else {
throw exception;
throw FeatureNotSupported(geom1, geom2);
}
} 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 isLineInPolygon(geom2, geom1);
} else if (geom2 is Polygon) {
return _isPolyInPoly(geom1, geom2);
} else if (geom2 is MultiPoint) {
return _isMultiPointInPoly(geom1, geom2);
return isMultiPointInPolygon(geom2, geom1);
} else {
throw exception;
throw FeatureNotSupported(geom1, geom2);
}
} else {
throw exception;
throw FeatureNotSupported(geom1, geom2);
}
}

bool _isPointInMultiPoint(MultiPoint multiPoint, Point pt) {
for (int i = 0; i < multiPoint.coordinates.length; i++) {
if ((multiPoint.coordinates[i] == pt.coordinates)) {
return true;
}
}
return false;
}

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 (!match) return false;
}
return true;
}

bool _isMultiPointOnLine(LineString lineString, MultiPoint multiPoint) {
var haveFoundInteriorPoint = false;
for (var coord in multiPoint.coordinates) {
if (booleanPointOnLine(Point(coordinates: coord), lineString,
ignoreEndVertices: true)) {
haveFoundInteriorPoint = true;
}
if (!booleanPointOnLine(Point(coordinates: coord), lineString)) {
return false;
}
}
return haveFoundInteriorPoint;
}

bool _isMultiPointInPoly(Polygon polygon, MultiPoint multiPoint) {
for (var coord in multiPoint.coordinates) {
if (!booleanPointInPolygon(coord, polygon, ignoreBoundary: true)) {
return false;
}
}
return true;
}

bool _isLineOnLine(LineString lineString1, LineString lineString2) {
var haveFoundInteriorPoint = false;
for (Position coord in lineString2.coordinates) {
if (booleanPointOnLine(
Point(coordinates: coord),
lineString1,
ignoreEndVertices: true,
)) {
haveFoundInteriorPoint = true;
}
if (!booleanPointOnLine(
Point(coordinates: coord),
lineString1,
ignoreEndVertices: false,
)) {
return false;
}
}
return haveFoundInteriorPoint;
}

bool _isLineInPoly(Polygon polygon, LineString linestring) {
var polyBbox = bbox(polygon);
var lineBbox = bbox(linestring);
if (!_doBBoxesOverlap(polyBbox, lineBbox)) {
return false;
}
for (var i = 0; i < linestring.coordinates.length - 1; i++) {
var midPoint =
midpointRaw(linestring.coordinates[i], linestring.coordinates[i + 1]);
if (booleanPointInPolygon(
midPoint,
polygon,
ignoreBoundary: true,
)) {
return true;
}
}
return false;
}

/// Is Polygon2 in Polygon1
/// Only takes into account outer rings
bool _isPolyInPoly(GeoJSONObject geom1, GeoJSONObject geom2) {
var poly1Bbox = bbox(geom1);
var poly2Bbox = bbox(geom2);
final poly1Bbox = bbox(geom1);
final poly2Bbox = bbox(geom2);
if (!_doBBoxesOverlap(poly1Bbox, poly2Bbox)) {
return false;
}

for (var ring in (geom2 as GeometryType).coordinates) {
for (var coord in ring) {
for (final ring in (geom2 as GeometryType).coordinates) {
for (final coord in ring) {
if (!booleanPointInPolygon(coord, geom1)) {
return false;
}
Expand Down
Loading

0 comments on commit dafa3cd

Please sign in to comment.