-
Notifications
You must be signed in to change notification settings - Fork 19
/
Copy pathbush.js
92 lines (78 loc) · 2.51 KB
/
bush.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
import Flatbush from 'flatbush';
import intersectSegments from './src/intersectSegments';
/**
* This implementation is inspired by discussion here
* https://twitter.com/mourner/status/1049325199617921024 and
* here https://github.com/anvaka/isect/issues/1
*
* It builds an index of all segments using static spatial index
* and then for each segment it queries overlapping rectangles.
*/
export default function bush(lines, options) {
var results = [];
var reportIntersection = (options && options.onFound) ||
defaultIntersectionReporter;
var asyncState;
var index = new Flatbush(lines.length);
lines.forEach(addToIndex);
index.finish();
return {
run: run,
step: step,
results: results,
// undocumented, don't use unless you know what you are doing:
checkIntersection: checkIntersection
}
function run() {
for (var i = 0; i < lines.length; ++i) {
if (checkIntersection(lines[i], i)) {
return; // stop early
}
}
return results;
}
function checkIntersection(currentSegment, currentId) {
// sorry about code duplication.
var minX = currentSegment.from.x; var maxX = currentSegment.to.x;
var minY = currentSegment.from.y; var maxY = currentSegment.to.y;
var t;
if (minX > maxX) { t = minX; minX = maxX; maxX = t; }
if (minY > maxY) { t = minY; minY = maxY; maxY = t; }
var ids = index.search(minX, minY, maxX, maxY);
for (var i = 0; i < ids.length; ++i) {
var segmentIndex = ids[i];
if (segmentIndex <= currentId) continue; // we have either reported it, or it is current.
var otherSegment = lines[segmentIndex];
var point = intersectSegments(otherSegment, currentSegment);
if (point) {
if (reportIntersection(point, [currentSegment, otherSegment])) {
// stop early
return true;
}
}
}
}
function step() {
if (!asyncState) {
asyncState = {i: 0};
}
var test = lines[asyncState.i];
checkIntersection(test, asyncState.i);
asyncState.i += 1;
return asyncState.i < lines.length;
}
function addToIndex(line) {
var minX = line.from.x; var maxX = line.to.x;
var minY = line.from.y; var maxY = line.to.y;
var t;
if (minX > maxX) { t = minX; minX = maxX; maxX = t; }
if (minY > maxY) { t = minY; minY = maxY; maxY = t; }
index.add(minX, minY, maxX, maxY);
}
function defaultIntersectionReporter(p, interior) {
results.push({
point: p,
segments: interior
});
}
}