forked from thi-ng/umbrella
-
Notifications
You must be signed in to change notification settings - Fork 0
/
circumcenter.ts
110 lines (103 loc) · 2.5 KB
/
circumcenter.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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
import { EPS } from "@thi.ng/math";
import {
add3,
addmN3,
cross3,
magSq3,
mulN3,
ReadonlyVec,
sub3,
Vec,
} from "@thi.ng/vectors";
/**
* Computes and returns the center of the circumcircle of the given 2D
* triangle points. Returns `undefined` if the points are colinear or
* coincident.
*
* @param a - triangle vertex 1
* @param b - triangle vertex 2
* @param c - triangle vertex 3
* @param eps - epsilon value for colinear check
*/
export const circumCenter2 = (
a: ReadonlyVec,
b: ReadonlyVec,
c: ReadonlyVec,
eps = EPS
): Vec | undefined => {
const ax = a[0],
ay = a[1];
const bx = b[0],
by = b[1];
const cx = c[0],
cy = c[1];
const bax = bx - ax;
const bay = by - ay;
const cbx = cx - bx;
const cby = cy - by;
const deltaAB = Math.abs(bay);
const deltaBC = Math.abs(cby);
// colinear check
if (
(deltaAB < eps && deltaBC < eps) ||
(Math.abs(bax) < eps && Math.abs(cbx) < eps)
) {
return;
}
const abx2 = (ax + bx) / 2;
const aby2 = (ay + by) / 2;
const bcx2 = (bx + cx) / 2;
const bcy2 = (by + cy) / 2;
if (deltaAB < eps) {
return [abx2, (-cbx / cby) * (abx2 - bcx2) + bcy2];
}
if (deltaBC < eps) {
return [bcx2, (-bax / bay) * (bcx2 - abx2) + aby2];
}
let m1 = -bax / bay;
let m2 = -cbx / cby;
let mx1 = abx2;
let my1 = aby2;
let mx2 = bcx2;
let my2 = bcy2;
let xc = (m1 * mx1 - m2 * mx2 + my2 - my1) / (m1 - m2);
let yc = deltaAB > deltaBC ? m1 * (xc - mx1) + my1 : m2 * (xc - mx2) + my2;
return [xc, yc];
};
/**
* Computes and returns the center of the circumsphere of the given 3D
* triangle points. Returns `undefined` if the points are colinear or
* coincident.
*
* @remarks
* Based on Jonathan R Shewchuk:
* https://www.ics.uci.edu/~eppstein/junkyard/circumcenter.html
*
* @param a
* @param b
* @param c
* @param eps
*/
export const circumCenter3 = (
a: ReadonlyVec,
b: ReadonlyVec,
c: ReadonlyVec,
eps = EPS
): Vec | undefined => {
const ab = sub3([], b, a);
const ac = sub3([], c, a);
const d = cross3([], ab, ac);
const m = magSq3(d);
return m >= eps
? add3(
null,
addmN3(
null,
mulN3(null, cross3([], d, ab), magSq3(ac)),
mulN3(null, cross3([], ac, d), magSq3(ab)),
0.5 / m
),
a
)
: undefined;
};