Skip to content

Commit

Permalink
progress #132
Browse files Browse the repository at this point in the history
  • Loading branch information
armantorkzaban committed Sep 12, 2022
1 parent cdef417 commit 09806ee
Show file tree
Hide file tree
Showing 3 changed files with 186 additions and 129 deletions.
76 changes: 52 additions & 24 deletions lib/src/booleans/boolean_overlap.dart
Original file line number Diff line number Diff line change
@@ -1,31 +1,61 @@
import 'package:turf/helpers.dart';
import 'package:turf/line_segment.dart';
import 'package:turf/src/invariant.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<LineString|MultiLineString|Polygon|MultiPolygon>} feature1 input
/// @param {Geometry|Feature<LineString|MultiLineString|Polygon|MultiPolygon>} 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)
/// 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.
/// Takes [feature1] and [feature2] which could be [Feature]<[LineString]|
/// [MultiLineString]|[Polygon]|[MultiPolygon]>
/// example
/// ```dart
/// var poly1 = Polygon(
/// coordinates: [
/// [
/// Position.of([0, 0]),
/// Position.of([0, 5]),
/// Position.of([5, 5]),
/// Position.of([5, 0]),
/// Position.of([0, 0])
/// ]
/// ],
/// );
/// var poly2 = Polygon(
/// coordinates: [
/// [
/// Position.of([1, 1]),
/// Position.of([1, 6]),
/// Position.of([6, 6]),
/// Position.of([6, 1]),
/// Position.of([1, 1])
/// ]
/// ],
/// );
/// var poly3 = Polygon(
/// coordinates: [
/// [
/// Position.of([10, 10]),
/// Position.of([10, 15]),
/// Position.of([15, 15]),
/// Position.of([15, 10]),
/// Position.of([10, 10])
/// ]
/// ],
/// );
/// booleanOverlap(poly1, poly2);
/// //=true
/// turf.booleanOverlap(poly2, poly3)
/// 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;
var geom1 = getGeom(feature1);
var geom2 = getGeom(feature2);

if ((feature1 is MultiPoint && feature2 is! MultiPoint) ||
((feature1 is LineString || feature1 is MultiLineString) &&
Expand All @@ -46,12 +76,10 @@ bool booleanOverlap(GeoJSONObject feature1, GeoJSONObject feature2) {

var overlap = 0;

if (feature1 is MultiPoint) {
for (var i = 0; i < (geom1 as MultiPoint).coordinates.length; i++) {
if (geom1 is MultiPoint) {
for (var i = 0; i < geom1.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]) {
if (geom1.coordinates[i] == geom2.coordinates[j]) {
return true;
}
}
Expand Down
208 changes: 113 additions & 95 deletions lib/src/line_overlap.dart
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ FeatureCollection<LineString> lineOverlap(
maxX: bb.lng2.toDouble(),
maxY: bb.lat2.toDouble());
}
// Optional parameters

// Containers
var features = <Feature<LineString>>[];
Expand All @@ -59,108 +58,127 @@ FeatureCollection<LineString> lineOverlap(
getMinX: (Feature<LineString> feature) => bbox(feature).lng1.toDouble(),
toBBox: (feature) => _toRBBox(feature));

var line = lineSegment(line1);
FeatureCollection<LineString> line = lineSegment(line1);
tree.load(line.features);
Feature<LineString>? overlapSegment;
var additionalSegments = <Feature<LineString>>[];

// Line Intersection

// Iterate over line segments
segmentEach(line2, (Feature<LineString> currentSegment, int featureIndex,
int? multiFeatureIndex, int? geometryIndex, int segmentIndex) {
var doesOverlaps = false;
segmentEach(
line2,
(Feature<LineString> currentSegment, int featureIndex,
int? multiFeatureIndex, int? geometryIndex, int segmentIndex) {
var doesOverlap = false;

// Iterate over each segments which falls within the same bounds
featureEach(
// Iterate over each segments which falls within the same bounds
featureEach(
FeatureCollection<LineString>(
features: tree.search(_toRBBox(currentSegment))), (match, index) {
if (!doesOverlaps) {
List<Position> coordsSegment = () {
List<Position> list = getCoords(currentSegment) as List<Position>;
list.sort();
return list;
}();
List<Position> coordsMatch = () {
List<Position> list = getCoords(match) as List<Position>;
list.sort();
return list;
}();
features: tree.search(_toRBBox(currentSegment))),
(match, index) {
if (!doesOverlap) {
List<Position> coordsSegment = () {
List<Position> list = getCoords(currentSegment) as List<Position>;
list.sort(((a, b) {
return a.lng < b.lng
? -1
: a.lng > b.lng
? 1
: 0;
}));
return list;
}();
List<Position> coordsMatch = () {
List<Position> list = getCoords(match) as List<Position>;
list.sort(((a, b) {
return a.lng < b.lng
? -1
: a.lng > b.lng
? 1
: 0;
}));
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<LineString>);
if (combinedSegment != null) {
overlapSegment = combinedSegment;
} else {
additionalSegments.add(match);
Equality eq = Equality();
// Segment overlaps feature - with dummy LineStrings just to use eq.
if (eq.compare(LineString(coordinates: coordsSegment),
LineString(coordinates: coordsMatch))) {
doesOverlap = 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) {
doesOverlap = 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) {
Feature<LineString>? combinedSegment = concatSegment(
overlapSegment!, match as Feature<LineString>);
if (combinedSegment != null) {
overlapSegment = combinedSegment;
} else {
additionalSegments.add(match);
}
} else {
overlapSegment = match as Feature<LineString>;
}
}
} else {
overlapSegment = match as Feature<LineString>;
}
}
}
});
},
);

// Segment doesn't overlap - add overlaps to results & reset
if (doesOverlaps == false && overlapSegment != null) {
features.add(overlapSegment!);
if (additionalSegments.isNotEmpty) {
features = [...features, ...additionalSegments];
additionalSegments = [];
// Segment doesn't overlap - add overlaps to results & reset
if (doesOverlap == false && overlapSegment != null) {
features.add(overlapSegment!);
if (additionalSegments.isNotEmpty) {
features = [...features, ...additionalSegments];
additionalSegments = [];
}
overlapSegment = null;
}
overlapSegment = null;
}
});
},
);
// Add last segment if exists
if (overlapSegment != null) features.add(overlapSegment!);

Expand All @@ -173,21 +191,21 @@ Feature<LineString>? concatSegment(
var lineCoords = getCoords(line);
var start = lineCoords[0];
var end = lineCoords[lineCoords.length - 1];
List<Position> geom = (line.geometry as LineString).coordinates;
List<Position> positions = (line.geometry as LineString).clone().coordinates;

if (coords[0] == start) {
geom.insert(0, coords[1]);
positions.insert(0, coords[1]);
} else if (coords[0] == end) {
geom.add(coords[1]);
positions.add(coords[1]);
} else if (coords[1] == start) {
geom.insert(0, coords[0]);
positions.insert(0, coords[0]);
} else if (coords[1] == end) {
geom.add(coords[0]);
positions.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 line;
return Feature(geometry: LineString(coordinates: positions));
}
Loading

0 comments on commit 09806ee

Please sign in to comment.