Skip to content

Commit 09806ee

Browse files
progress #132
1 parent cdef417 commit 09806ee

File tree

3 files changed

+186
-129
lines changed

3 files changed

+186
-129
lines changed

lib/src/booleans/boolean_overlap.dart

Lines changed: 52 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,61 @@
11
import 'package:turf/helpers.dart';
22
import 'package:turf/line_segment.dart';
3+
import 'package:turf/src/invariant.dart';
34
import 'package:turf/src/line_intersect.dart';
45
import 'package:turf/src/line_overlap.dart';
56
import 'package:turf_equality/turf_equality.dart';
67

7-
/// Compares two geometries of the same dimension and returns true if their intersection set results in a geometry
8-
/// different from both but of the same dimension. It applies to Polygon/Polygon, LineString/LineString,
9-
/// Multipoint/Multipoint, MultiLineString/MultiLineString and MultiPolygon/MultiPolygon.
10-
///
11-
/// In other words, it returns true if the two geometries overlap, provided that neither completely contains the other.
12-
///
13-
/// @name booleanOverlap
14-
/// @param {Geometry|Feature<LineString|MultiLineString|Polygon|MultiPolygon>} feature1 input
15-
/// @param {Geometry|Feature<LineString|MultiLineString|Polygon|MultiPolygon>} feature2 input
16-
/// @returns {boolean} true/false
17-
/// @example
18-
/// var poly1 = turf.polygon([[[0,0],[0,5],[5,5],[5,0],[0,0]]]);
19-
/// var poly2 = turf.polygon([[[1,1],[1,6],[6,6],[6,1],[1,1]]]);
20-
/// var poly3 = turf.polygon([[[10,10],[10,15],[15,15],[15,10],[10,10]]]);
21-
///
22-
/// turf.booleanOverlap(poly1, poly2)
8+
/// Compares two geometries of the same dimension and returns [true] if their
9+
/// intersection Set results in a geometry different from both but of the same
10+
/// dimension. It applies to [Polygon]/[Polygon], [LineString]/[LineString], [MultiPoint]/
11+
/// [MultiPoint], [MultiLineString]/[MultiLineString] and [MultiPolygon]/[MultiPolygon].
12+
/// In other words, it returns [true] if the two geometries overlap, provided that
13+
/// neither completely contains the other.
14+
/// Takes [feature1] and [feature2] which could be [Feature]<[LineString]|
15+
/// [MultiLineString]|[Polygon]|[MultiPolygon]>
16+
/// example
17+
/// ```dart
18+
/// var poly1 = Polygon(
19+
/// coordinates: [
20+
/// [
21+
/// Position.of([0, 0]),
22+
/// Position.of([0, 5]),
23+
/// Position.of([5, 5]),
24+
/// Position.of([5, 0]),
25+
/// Position.of([0, 0])
26+
/// ]
27+
/// ],
28+
/// );
29+
/// var poly2 = Polygon(
30+
/// coordinates: [
31+
/// [
32+
/// Position.of([1, 1]),
33+
/// Position.of([1, 6]),
34+
/// Position.of([6, 6]),
35+
/// Position.of([6, 1]),
36+
/// Position.of([1, 1])
37+
/// ]
38+
/// ],
39+
/// );
40+
/// var poly3 = Polygon(
41+
/// coordinates: [
42+
/// [
43+
/// Position.of([10, 10]),
44+
/// Position.of([10, 15]),
45+
/// Position.of([15, 15]),
46+
/// Position.of([15, 10]),
47+
/// Position.of([10, 10])
48+
/// ]
49+
/// ],
50+
/// );
51+
/// booleanOverlap(poly1, poly2);
2352
/// //=true
24-
/// turf.booleanOverlap(poly2, poly3)
53+
/// booleanOverlap(poly2, poly3);
2554
/// //=false
55+
/// ```
2656
bool booleanOverlap(GeoJSONObject feature1, GeoJSONObject feature2) {
27-
var geom1 = feature1 is Feature ? feature1.geometry : feature1;
28-
var geom2 = feature2 is Feature ? feature2.geometry : feature2;
57+
var geom1 = getGeom(feature1);
58+
var geom2 = getGeom(feature2);
2959

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

4777
var overlap = 0;
4878

49-
if (feature1 is MultiPoint) {
50-
for (var i = 0; i < (geom1 as MultiPoint).coordinates.length; i++) {
79+
if (geom1 is MultiPoint) {
80+
for (var i = 0; i < geom1.coordinates.length; i++) {
5181
for (var j = 0; j < (geom2 as MultiPoint).coordinates.length; j++) {
52-
var coord1 = geom1.coordinates[i];
53-
var coord2 = geom2.coordinates[j];
54-
if (coord1[0] == coord2[0] && coord1[1] == coord2[1]) {
82+
if (geom1.coordinates[i] == geom2.coordinates[j]) {
5583
return true;
5684
}
5785
}

lib/src/line_overlap.dart

Lines changed: 113 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,6 @@ FeatureCollection<LineString> lineOverlap(
4848
maxX: bb.lng2.toDouble(),
4949
maxY: bb.lat2.toDouble());
5050
}
51-
// Optional parameters
5251

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

62-
var line = lineSegment(line1);
61+
FeatureCollection<LineString> line = lineSegment(line1);
6362
tree.load(line.features);
6463
Feature<LineString>? overlapSegment;
6564
var additionalSegments = <Feature<LineString>>[];
6665

6766
// Line Intersection
6867

6968
// Iterate over line segments
70-
segmentEach(line2, (Feature<LineString> currentSegment, int featureIndex,
71-
int? multiFeatureIndex, int? geometryIndex, int segmentIndex) {
72-
var doesOverlaps = false;
69+
segmentEach(
70+
line2,
71+
(Feature<LineString> currentSegment, int featureIndex,
72+
int? multiFeatureIndex, int? geometryIndex, int segmentIndex) {
73+
var doesOverlap = false;
7374

74-
// Iterate over each segments which falls within the same bounds
75-
featureEach(
75+
// Iterate over each segments which falls within the same bounds
76+
featureEach(
7677
FeatureCollection<LineString>(
77-
features: tree.search(_toRBBox(currentSegment))), (match, index) {
78-
if (!doesOverlaps) {
79-
List<Position> coordsSegment = () {
80-
List<Position> list = getCoords(currentSegment) as List<Position>;
81-
list.sort();
82-
return list;
83-
}();
84-
List<Position> coordsMatch = () {
85-
List<Position> list = getCoords(match) as List<Position>;
86-
list.sort();
87-
return list;
88-
}();
78+
features: tree.search(_toRBBox(currentSegment))),
79+
(match, index) {
80+
if (!doesOverlap) {
81+
List<Position> coordsSegment = () {
82+
List<Position> list = getCoords(currentSegment) as List<Position>;
83+
list.sort(((a, b) {
84+
return a.lng < b.lng
85+
? -1
86+
: a.lng > b.lng
87+
? 1
88+
: 0;
89+
}));
90+
return list;
91+
}();
92+
List<Position> coordsMatch = () {
93+
List<Position> list = getCoords(match) as List<Position>;
94+
list.sort(((a, b) {
95+
return a.lng < b.lng
96+
? -1
97+
: a.lng > b.lng
98+
? 1
99+
: 0;
100+
}));
101+
return list;
102+
}();
89103

90-
Equality eq = Equality();
91-
// Segment overlaps feature - with dummy LineStrings just to use eq.
92-
if (eq.compare(LineString(coordinates: coordsSegment),
93-
LineString(coordinates: coordsMatch))) {
94-
doesOverlaps = true;
95-
// Overlaps already exists - only append last coordinate of segment
96-
if (overlapSegment != null) {
97-
overlapSegment = concatSegment(overlapSegment!, currentSegment) ??
98-
overlapSegment;
99-
} else {
100-
overlapSegment = currentSegment;
101-
}
102-
// Match segments which don't share nodes (Issue #901)
103-
} else if (tolerance == 0
104-
? booleanPointOnLine(Point(coordinates: coordsSegment[0]),
105-
match.geometry as LineString) &&
106-
booleanPointOnLine(Point(coordinates: coordsSegment[1]),
107-
match.geometry as LineString)
108-
: nearestPointOnLine(match.geometry as LineString,
109-
Point(coordinates: coordsSegment[0]))
110-
.properties!['dist'] <=
111-
tolerance &&
112-
nearestPointOnLine(match.geometry as LineString,
113-
Point(coordinates: coordsSegment[1]))
114-
.properties!['dist'] <=
115-
tolerance) {
116-
doesOverlaps = true;
117-
if (overlapSegment != null) {
118-
overlapSegment = concatSegment(overlapSegment!, currentSegment) ??
119-
overlapSegment;
120-
} else {
121-
overlapSegment = currentSegment;
122-
}
123-
} else if (tolerance == 0
124-
? booleanPointOnLine(Point(coordinates: coordsMatch[0]),
125-
currentSegment.geometry as LineString) &&
126-
booleanPointOnLine(Point(coordinates: coordsMatch[1]),
127-
currentSegment.geometry as LineString)
128-
: nearestPointOnLine(currentSegment.geometry as LineString,
129-
Point(coordinates: coordsMatch[0]))
130-
.properties!['dist'] <=
131-
tolerance &&
132-
nearestPointOnLine(currentSegment.geometry as LineString,
133-
Point(coordinates: coordsMatch[1]))
134-
.properties!['dist'] <=
135-
tolerance) {
136-
// Do not define doesOverlap = true since more matches can occur
137-
// within the same segment
138-
// doesOverlaps = true;
139-
if (overlapSegment != null) {
140-
var combinedSegment =
141-
concatSegment(overlapSegment!, match as Feature<LineString>);
142-
if (combinedSegment != null) {
143-
overlapSegment = combinedSegment;
144-
} else {
145-
additionalSegments.add(match);
104+
Equality eq = Equality();
105+
// Segment overlaps feature - with dummy LineStrings just to use eq.
106+
if (eq.compare(LineString(coordinates: coordsSegment),
107+
LineString(coordinates: coordsMatch))) {
108+
doesOverlap = true;
109+
// Overlaps already exists - only append last coordinate of segment
110+
if (overlapSegment != null) {
111+
overlapSegment =
112+
concatSegment(overlapSegment!, currentSegment) ??
113+
overlapSegment;
114+
} else {
115+
overlapSegment = currentSegment;
116+
}
117+
// Match segments which don't share nodes (Issue #901)
118+
} else if (tolerance == 0
119+
? booleanPointOnLine(Point(coordinates: coordsSegment[0]),
120+
match.geometry as LineString) &&
121+
booleanPointOnLine(Point(coordinates: coordsSegment[1]),
122+
match.geometry as LineString)
123+
: nearestPointOnLine(match.geometry as LineString,
124+
Point(coordinates: coordsSegment[0]))
125+
.properties!['dist'] <=
126+
tolerance &&
127+
nearestPointOnLine(match.geometry as LineString,
128+
Point(coordinates: coordsSegment[1]))
129+
.properties!['dist'] <=
130+
tolerance) {
131+
doesOverlap = true;
132+
if (overlapSegment != null) {
133+
overlapSegment =
134+
concatSegment(overlapSegment!, currentSegment) ??
135+
overlapSegment;
136+
} else {
137+
overlapSegment = currentSegment;
138+
}
139+
} else if (tolerance == 0
140+
? booleanPointOnLine(Point(coordinates: coordsMatch[0]),
141+
currentSegment.geometry as LineString) &&
142+
booleanPointOnLine(Point(coordinates: coordsMatch[1]),
143+
currentSegment.geometry as LineString)
144+
: nearestPointOnLine(currentSegment.geometry as LineString,
145+
Point(coordinates: coordsMatch[0]))
146+
.properties!['dist'] <=
147+
tolerance &&
148+
nearestPointOnLine(currentSegment.geometry as LineString,
149+
Point(coordinates: coordsMatch[1]))
150+
.properties!['dist'] <=
151+
tolerance) {
152+
// Do not define doesOverlap = true since more matches can occur
153+
// within the same segment
154+
// doesOverlaps = true;
155+
if (overlapSegment != null) {
156+
Feature<LineString>? combinedSegment = concatSegment(
157+
overlapSegment!, match as Feature<LineString>);
158+
if (combinedSegment != null) {
159+
overlapSegment = combinedSegment;
160+
} else {
161+
additionalSegments.add(match);
162+
}
163+
} else {
164+
overlapSegment = match as Feature<LineString>;
165+
}
146166
}
147-
} else {
148-
overlapSegment = match as Feature<LineString>;
149167
}
150-
}
151-
}
152-
});
168+
},
169+
);
153170

154-
// Segment doesn't overlap - add overlaps to results & reset
155-
if (doesOverlaps == false && overlapSegment != null) {
156-
features.add(overlapSegment!);
157-
if (additionalSegments.isNotEmpty) {
158-
features = [...features, ...additionalSegments];
159-
additionalSegments = [];
171+
// Segment doesn't overlap - add overlaps to results & reset
172+
if (doesOverlap == false && overlapSegment != null) {
173+
features.add(overlapSegment!);
174+
if (additionalSegments.isNotEmpty) {
175+
features = [...features, ...additionalSegments];
176+
additionalSegments = [];
177+
}
178+
overlapSegment = null;
160179
}
161-
overlapSegment = null;
162-
}
163-
});
180+
},
181+
);
164182
// Add last segment if exists
165183
if (overlapSegment != null) features.add(overlapSegment!);
166184

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

178196
if (coords[0] == start) {
179-
geom.insert(0, coords[1]);
197+
positions.insert(0, coords[1]);
180198
} else if (coords[0] == end) {
181-
geom.add(coords[1]);
199+
positions.add(coords[1]);
182200
} else if (coords[1] == start) {
183-
geom.insert(0, coords[0]);
201+
positions.insert(0, coords[0]);
184202
} else if (coords[1] == end) {
185-
geom.add(coords[0]);
203+
positions.add(coords[0]);
186204
} else {
187205
return null;
188206
} // If the overlap leaves the segment unchanged, return null so that this can be
189207
// identified.
190208

191209
// Otherwise return the mutated line.
192-
return line;
210+
return Feature(geometry: LineString(coordinates: positions));
193211
}

0 commit comments

Comments
 (0)