-
Notifications
You must be signed in to change notification settings - Fork 1
/
FastCollinearPoints.ts
87 lines (65 loc) · 1.67 KB
/
FastCollinearPoints.ts
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
import LineSegment from './LineSegment';
import Point from './Point';
/**
* The number of points that must be collinear in order to form a segment.
*/
const MINIMUM_SEGMENT_SIZE = 4;
export default class FastCollinearPoints {
_points: Array<Point>;
constructor(points: Array<Point>) {
this._points = points;
}
numberOfSegments(): number {
return this.segments().length;
}
segments(): Array<LineSegment> {
if (this._points.length < MINIMUM_SEGMENT_SIZE) {
return [];
}
const segments: Array<LineSegment> = [];
for (let i = 0; i < this._points.length; i++) {
const p = this._points[i];
const slopes: Array<{point: Point; slope: number}> = [];
for (let j = 1; j < this._points.length; j++) {
if (i === j) {
continue;
}
const q = this._points[j];
slopes.push({
point: q,
slope: p.slope(q),
});
}
slopes.sort((a, b) => {
return a.slope - b.slope || a.point.compareTo(b.point);
});
let start = 0;
let previous = slopes[start];
for (let j = 1; j < slopes.length; j++) {
const current = slopes[j];
const minimum = slopes[start].point;
if (current.slope !== previous.slope) {
const maximum = previous.point;
if (
j - start >= MINIMUM_SEGMENT_SIZE - 1 &&
p.compareTo(minimum) < 0
) {
segments.push(new LineSegment(p, maximum));
}
start = j;
} else if (j === slopes.length - 1) {
const maximum = current.point;
if (
j - start >= MINIMUM_SEGMENT_SIZE - 1 &&
p.compareTo(minimum) < 0
) {
segments.push(new LineSegment(p, maximum));
}
start = j;
}
previous = current;
}
}
return segments;
}
}