blob: 71533cb63237d9f786a901e0e657b6af3dc6860e [file] [log] [blame]
Simon Hunt1c219892014-10-22 16:32:39 -07001/*
2 Geometry library - based on work by Mike Bostock.
3 */
4
5(function() {
6
7 if (typeof geo == 'undefined') {
8 geo = {};
9 }
10
11 var tolerance = 1e-10;
12
13 function eq(a, b) {
14 return (Math.abs(a - b) < tolerance);
15 }
16
17 function gt(a, b) {
18 return (a - b > -tolerance);
19 }
20
21 function lt(a, b) {
22 return gt(b, a);
23 }
24
25 geo.eq = eq;
26 geo.gt = gt;
27 geo.lt = lt;
28
29 geo.LineSegment = function(x1, y1, x2, y2) {
30 this.x1 = x1;
31 this.y1 = y1;
32 this.x2 = x2;
33 this.y2 = y2;
34
35 // Ax + By = C
36 this.a = y2 - y1;
37 this.b = x1 - x2;
38 this.c = x1 * this.a + y1 * this.b;
39
40 if (eq(this.a, 0) && eq(this.b, 0)) {
41 throw new Error(
42 'Cannot construct a LineSegment with two equal endpoints.');
43 }
44 };
45
46 geo.LineSegment.prototype.intersect = function(that) {
47 var d = (this.x1 - this.x2) * (that.y1 - that.y2) -
48 (this.y1 - this.y2) * (that.x1 - that.x2);
49
50 if (eq(d, 0)) {
51 // The two lines are parallel or very close.
52 return {
53 x : NaN,
54 y : NaN
55 };
56 }
57
58 var t1 = this.x1 * this.y2 - this.y1 * this.x2,
59 t2 = that.x1 * that.y2 - that.y1 * that.x2,
60 x = (t1 * (that.x1 - that.x2) - t2 * (this.x1 - this.x2)) / d,
61 y = (t1 * (that.y1 - that.y2) - t2 * (this.y1 - this.y2)) / d,
62 in1 = (gt(x, Math.min(this.x1, this.x2)) && lt(x, Math.max(this.x1, this.x2)) &&
63 gt(y, Math.min(this.y1, this.y2)) && lt(y, Math.max(this.y1, this.y2))),
64 in2 = (gt(x, Math.min(that.x1, that.x2)) && lt(x, Math.max(that.x1, that.x2)) &&
65 gt(y, Math.min(that.y1, that.y2)) && lt(y, Math.max(that.y1, that.y2)));
66
67 return {
68 x : x,
69 y : y,
70 in1 : in1,
71 in2 : in2
72 };
73 };
74
75 geo.LineSegment.prototype.x = function(y) {
76 // x = (C - By) / a;
77 if (this.a) {
78 return (this.c - this.b * y) / this.a;
79 } else {
80 // a == 0 -> horizontal line
81 return NaN;
82 }
83 };
84
85 geo.LineSegment.prototype.y = function(x) {
86 // y = (C - Ax) / b;
87 if (this.b) {
88 return (this.c - this.a * x) / this.b;
89 } else {
90 // b == 0 -> vertical line
91 return NaN;
92 }
93 };
94
95 geo.LineSegment.prototype.length = function() {
96 return Math.sqrt(
97 (this.y2 - this.y1) * (this.y2 - this.y1) +
98 (this.x2 - this.x1) * (this.x2 - this.x1));
99 };
100
101 geo.LineSegment.prototype.offset = function(x, y) {
102 return new geo.LineSegment(
103 this.x1 + x, this.y1 + y,
104 this.x2 + x, this.y2 + y);
105 };
106
107})();