/
index.js
127 lines (117 loc) · 3.91 KB
/
index.js
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
124
125
126
127
var rbush = require('geojson-rbush');
var clone = require('clone');
var meta = require('@turf/meta');
var helpers = require('@turf/helpers');
var getCoords = require('@turf/invariant').getCoords;
var lineSegment = require('@turf/line-segment');
var lineIntersect = require('@turf/line-intersect');
var featureCollection = helpers.featureCollection;
var lineString = helpers.lineString;
var coordEach = meta.coordEach;
var featureEach = meta.featureEach;
var featureReduce = meta.featureReduce;
/**
* Slices {@link Polygon} using a {@link Linestring}.
*
* @name polygonSlice
* @param {Feature<Polygon>} polygon Polygon to slice
* @param {Feature<LineString>} linestring LineString used to slice Polygon
* @returns {FeatureCollection<Polygon>} Sliced Polygons
* @example
* var polygon = {
* "geometry": {
* "type": "Polygon",
* "coordinates": [[
* [0, 0],
* [0, 10],
* [10, 10],
* [10, 0],
* [0, 0]
* ]]
* }
* };
* var linestring = {
* "type": "Feature",
* "properties": {},
* "geometry": {
* "type": "LineString",
* "coordinates": [
* [5, 15],
* [5, -15]
* ]
* }
* }
* var sliced = turf.polygonSlice(polygon, linestring);
* //=sliced
*/
module.exports = function polygonSlice(polygon, linestring) {
linestring = clone(linestring);
polygon = clone(polygon);
var splitLines = lineSplit(linestring, polygon);
var splitPolygons = lineSplit(polygon, linestring);
return featureCollection(splitLines.features.concat(splitPolygons.features));
};
/**
* Split a LineString at the intersections of another LineString.
*
* @private
* @param {Feature<LineString>} source Line Feature to split
* @param {Feature<LineString>} target Line Feature used to find intersections
* @returns {FeatureCollection<LineString>} Split lines
*/
function lineSplit(source, target) {
var results = [];
// Spatial Index
var tree = rbush();
tree.load(lineSegment(target));
// Lines of 2-vertex
var segments = lineSegment(source);
var initialValue = segments.features[0];
var last = featureReduce(segments, function (previous, current, index) {
var matched = false;
var lastCoord = getCoords(clone(current))[1];
featureEach(tree.search(current), function (polySegment) {
if (!matched) {
// Segments match
var intersect = lineIntersect(current, polySegment).features[0];
if (intersect) {
// Create Segment
var newSegment = clone(previous);
if (index === 0) {
newSegment = lineString([getCoords(current)[0], getCoords(intersect)]);
} else {
newSegment.geometry.coordinates.push(getCoords(intersect));
}
// Push new split lines to results
if (validSegment(newSegment)) {
results.push(newSegment);
}
// Restart previous value to intersection point
previous.geometry.coordinates = [intersect.geometry.coordinates];
matched = true;
}
}
});
// Append last coordinate of current segment
previous.geometry.coordinates.push(lastCoord);
return previous;
}, initialValue);
// Add the end segment to the lineEnd of the line
if (validSegment(last)) {
results.push(last);
}
return featureCollection(results);
}
/**
* Validate Segment - Must contain more than 1 unique point
*
* @param {Feature<LineString>} segment Line Segment
* @returns {boolean} true if segment is valid
*/
function validSegment(segment) {
var uniques = {};
coordEach(segment, function (coord) {
uniques[coord.join(',')] = true;
});
return Object.keys(uniques).length > 1;
}