-
Notifications
You must be signed in to change notification settings - Fork 31
/
Copy pathclean_coords.dart
123 lines (115 loc) · 4.15 KB
/
clean_coords.dart
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
import '../helpers.dart';
import 'booleans/boolean_point_on_line.dart';
import 'invariant.dart';
/// Removes redundant coordinates from any [GeometryType].
/// Takes a [Feature] or [GeometryType]
/// [mutate] allows GeoJSON input to be mutated
/// Returns the cleaned input [Feature]
/// 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;
/// //= [Position.of([0, 0]), Position.of([0, 10])]
/// cleanCoords(multiPoint).geometry.coordinates;
/// //= [Position.of([0, 0]), Position.of([2, 2])]
/// ```
Feature cleanCoords(
GeoJSONObject geojson, {
bool mutate = false,
}) {
if (geojson is Feature && geojson.geometry == null) {
throw Exception("Geometry of the Feature is null");
}
GeometryObject geom = getGeom(geojson);
geom = mutate ? geom : geom.clone() as GeometryObject;
if (geojson is GeometryCollection || geojson is FeatureCollection) {
throw Exception("${geojson.type} is not supported");
} else if (geom is LineString) {
var newCoords = _cleanLine(geom.coordinates, geojson);
geom.coordinates = newCoords;
} else if (geom is MultiLineString || geom is Polygon) {
var newCoords = <List<Position>>[];
for (var coord in (getCoords(geom) as List<List<Position>>)) {
newCoords.add(_cleanLine(coord, geom));
}
(geom as GeometryType).coordinates = newCoords;
} else if (geom is MultiPolygon) {
var newCoords = <List<List<Position>>>[];
for (var polyList in (getCoords(geom) as List<List<List<Position>>>)) {
var listPoly = <List<Position>>[];
for (var poly in polyList) {
listPoly.add(_cleanLine(poly, geom));
}
newCoords.add(listPoly);
}
geom.coordinates = newCoords;
} else if (geom is MultiPoint) {
var newCoords = <Position>[];
Set set = <String>{};
var list = getCoords(geom) as List<Position>;
for (var element in list) {
if (!set.contains([element.alt, element.lat, element.lng].join('-'))) {
newCoords.add(element);
}
set.add([element.alt, element.lat, element.lng].join('-'));
}
geom.coordinates = newCoords;
}
if (geojson is GeometryType) {
return Feature(geometry: geom);
} else if (geojson is Feature) {
if (mutate) {
return geojson;
} else {
return Feature(
geometry: geom,
properties: Map.of(geojson.properties ?? {}),
bbox: geojson.bbox?.clone(),
id: geojson.id,
);
}
} else {
throw Exception('${geojson.type} is not a supported type');
}
}
List<Position> _cleanLine(List<Position> coords, GeoJSONObject geojson) {
// handle "clean" segment
if (coords.length == 2 && coords[0] != coords[1]) {
return coords;
}
var newPoints = <Position>[];
int secondToLast = coords.length - 1;
int newPointsLength = newPoints.length;
newPoints.add(coords[0]);
for (int i = 1; i < secondToLast; i++) {
var prevAddedPoint = newPoints[newPoints.length - 1];
if (coords[i] == prevAddedPoint) {
continue;
} else {
newPoints.add(coords[i]);
newPointsLength = newPoints.length;
if (newPointsLength > 2) {
if (isPointOnLineSegmentCleanCoordsVariant(
newPoints[newPointsLength - 3],
newPoints[newPointsLength - 1],
newPoints[newPointsLength - 2])) {
newPoints.removeAt(newPoints.length - 2);
}
}
}
}
newPoints.add(coords[coords.length - 1]);
newPointsLength = newPoints.length;
// (Multi)Polygons must have at least 4 points, but a closed LineString with only 3 points is acceptable
if ((geojson is Polygon || geojson is MultiPolygon) &&
coords[0] == coords[coords.length - 1] &&
newPointsLength < 4) {
throw Exception("invalid polygon");
}
if (isPointOnLineSegmentCleanCoordsVariant(newPoints[newPointsLength - 3],
newPoints[newPointsLength - 1], newPoints[newPointsLength - 2])) {
newPoints.removeAt(newPoints.length - 2);
}
return newPoints;
}