-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathMath.pde
134 lines (118 loc) · 4.06 KB
/
Math.pde
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
128
129
130
131
132
133
134
// Math Utilities
// ======================
// Geometry Class
// --------------
//
// Provides elementary geometrical operations
public static final class Geometry
{
// Computes the _per product_ (aka. _cross product_) of two vectors
public static float per(PVector u, PVector v) {
return u.x * v.y - v.x * u.y;
}
// Produces a vector spanned between two points
public static PVector span(PVector a, PVector b) {
return PVector.sub(b, a);
}
// Tests which side of line a given point lies at.
//
// * Returns positive value if `p` is on the left side of line through
// `a` and `b`.
//
// * Returns negative value if `p` is on the right side of line through
// `a` and `b`.
//
// * Returns 0 if `a`, `b` and `p` are colinear.
public static float side(PVector a, PVector b, PVector p) {
return per(span(a, b), span(a, p));
}
// Computes the squared distance between two points
public static float distSq(PVector a, PVector b) {
float dx = a.x - b.x;
float dy = a.y - b.y;
return dx * dx + dy * dy;
}
// Tests whether segments `ab` and `cd` intersect
public static boolean intersect(PVector a, PVector b, PVector c, PVector d) {
// The segments intersect only if the endpoints of one are on opposite sides
// of the other (both ways)
PVector ab = span(a, b), ac = span(a, c), ad = span(a, d);
float sab = per(ab, ac) * per(ab, ad);
if (sab > 0)
return false;
PVector cd = span(c, d), cb = span(c, b);
float scd = per(cd, ac) * per(cd, cb);
// Note that `ac` is used instead of `ca` in the above line, thus reversing
// the following condition
if (scd < 0)
return false;
// When the points are colinear, we have to check if the segments overlap
if (sab == 0 && scd == 0) {
float abSq = ab.magSq();
return ac.magSq() <= abSq || ad.magSq() < abSq;
}
return true;
}
// Returns a projection of point onto a line
public static PVector project(PVector p, Line l) {
float t = -(l.a * p.x + l.b * p.y + l.c) / (l.a * l.a + l.b * l.b);
return new PVector(p.x + t * l.a, p.y + t * l.b);
}
// Returns the intersection point of two lines. The result may contain ifinities
// if the lines are parallel, or NaNs if they are identical.
public static PVector intersection(Line l1, Line l2) {
float a11 = l1.a, a12 = l1.b, b1 = -l1.c;
float a21 = l2.a, a22 = l2.b, b2 = -l2.c;
// We now solve a linear equation `Ax = b`, where `A = [a11 a12; a21 a22]`,
// `x = [x1; x2]` `b = [b1; b2]`. We use Gaussian elimination method with
// full pivot selection.
// We rearrange the equation so that the pivot is `a11`
boolean swapResult = false;
if (max(abs(a11), abs(a12)) < max(abs(a21), abs(a22))) {
float tmp;
tmp = a11; a11 = a21; a21 = tmp;
tmp = a12; a12 = a22; a22 = tmp;
tmp = b1; b1 = b2; b2 = tmp;
}
if (abs(a11) < abs(a12)) {
float tmp;
tmp = a11; a11 = a12; a12 = tmp;
tmp = a21; a21 = a22; a22 = tmp;
swapResult = true;
}
a22 -= a12 * a21 / a11;
b2 -= b1 * a21 / a11;
float x2 = b2 / a22;
float x1 = (b1 - a12 * x2) / a11;
return swapResult ? new PVector(x2, x1) : new PVector(x1, x2);
}
}
// Gets the smallest of five values
public static float min(float x1, float x2, float x3, float x4, float x5) {
return min(min(x1, x2, x3), min(x4, x5));
}
// Gets the biggest of five values
public static float max(float x1, float x2, float x3, float x4, float x5) {
return max(max(x1, x2, x3), max(x4, x5));
}
// Truncates value to given range
public static float clamp (float x, float a, float b) {
if (x < a)
return a;
else if (b < x)
return b;
else return x;
}
// Truncates value to given range
public static final int clamp (int x, int a, int b) {
if (x < a)
return a;
else if (b < x)
return b;
else return x;
}
// Determines whether a `PVector` contains infinities or NaNs
public static final boolean isSingular(PVector v) {
return Float.isInfinite(v.x) || Float.isNaN(v.x)
|| Float.isInfinite(v.y) || Float.isNaN(v.y);
}