1use super::backend::{
15 denom, int_from_uint, mul_int_uint, mul_uint, numer, rat_is_zero, rat_new, Int, Rational,
16 Signed,
17};
18
19use super::rational::{R2, R3};
20use super::Sign;
21
22#[inline]
34fn homog2(p: &R2) -> (Int, Int, Int) {
35 let (xn, xd) = (numer(&p.x), denom(&p.x));
36 let (yn, yd) = (numer(&p.y), denom(&p.y));
37 (
38 mul_int_uint(xn, yd),
39 mul_int_uint(yn, xd),
40 int_from_uint(mul_uint(xd, yd)),
41 )
42}
43
44#[inline]
46fn homog3(p: &R3) -> (Int, Int, Int, Int) {
47 let (xn, xd) = (numer(&p.x), denom(&p.x));
48 let (yn, yd) = (numer(&p.y), denom(&p.y));
49 let (zn, zd) = (numer(&p.z), denom(&p.z));
50 let yz = mul_uint(yd, zd);
51 (
52 mul_int_uint(xn, &yz),
53 mul_int_uint(yn, &mul_uint(xd, zd)),
54 mul_int_uint(zn, &mul_uint(xd, yd)),
55 int_from_uint(mul_uint(xd, &yz)),
56 )
57}
58
59#[derive(Clone, Debug)]
63pub struct Homog2(pub Int, pub Int, pub Int);
64
65pub fn homog2_of(p: &R2) -> Homog2 {
66 let (x, y, w) = homog2(p);
67 Homog2(x, y, w)
68}
69
70pub fn orient2d_h(a: &Homog2, b: &Homog2, c: &Homog2) -> Sign {
73 let ux = &b.0 * &a.2 - &a.0 * &b.2;
74 let uy = &b.1 * &a.2 - &a.1 * &b.2;
75 let vx = &c.0 * &a.2 - &a.0 * &c.2;
76 let vy = &c.1 * &a.2 - &a.1 * &c.2;
77 sign_of_int(&(ux * vy - uy * vx))
78}
79
80pub fn incircle_h(a: &Homog2, b: &Homog2, c: &Homog2, d: &Homog2) -> Sign {
83 let row = |p: &Homog2| -> (Int, Int, Int) {
84 let nx = &p.0 * &d.2 - &d.0 * &p.2;
85 let ny = &p.1 * &d.2 - &d.1 * &p.2;
86 let s = &p.2 * &d.2;
87 let lift = &nx * &nx + &ny * &ny;
88 (nx * &s, ny * &s, lift)
89 };
90 let (ux, uy, ul) = row(a);
91 let (vx, vy, vl) = row(b);
92 let (wx, wy, wl) = row(c);
93 let det = ul * (&vx * &wy - &vy * &wx)
94 + vl * (&wx * &uy - &wy * &ux)
95 + wl * (&ux * &vy - &uy * &vx);
96 sign_of_int(&det)
97}
98
99pub fn point_in_tri_2d_h(p: &Homog2, a: &Homog2, b: &Homog2, c: &Homog2) -> TriLoc {
101 let orient = orient2d_h(a, b, c);
102 if orient == Sign::Zero {
103 return TriLoc::Outside;
104 }
105 let normalize = |s: Sign| if orient == Sign::Pos { s } else { s.flip() };
106 let s0 = normalize(orient2d_h(a, b, p));
107 let s1 = normalize(orient2d_h(b, c, p));
108 let s2 = normalize(orient2d_h(c, a, p));
109 if s0 == Sign::Neg || s1 == Sign::Neg || s2 == Sign::Neg {
110 return TriLoc::Outside;
111 }
112 match (s0 == Sign::Zero, s1 == Sign::Zero, s2 == Sign::Zero) {
113 (false, false, false) => TriLoc::Inside,
114 (true, false, false) => TriLoc::OnEdge(0),
115 (false, true, false) => TriLoc::OnEdge(1),
116 (false, false, true) => TriLoc::OnEdge(2),
117 (true, false, true) => TriLoc::OnVertex(0),
118 (true, true, false) => TriLoc::OnVertex(1),
119 (false, true, true) => TriLoc::OnVertex(2),
120 (true, true, true) => TriLoc::Outside,
121 }
122}
123
124#[inline]
125fn sign_of_int(v: &Int) -> Sign {
126 if v.is_positive() {
127 Sign::Pos
128 } else if v.is_negative() {
129 Sign::Neg
130 } else {
131 Sign::Zero
132 }
133}
134
135pub fn orient2d_r(a: &R2, b: &R2, c: &R2) -> Sign {
137 let (ax, ay, aw) = homog2(a);
138 let (bx, by, bw) = homog2(b);
139 let (cx, cy, cw) = homog2(c);
140 let ux = &bx * &aw - &ax * &bw;
142 let uy = &by * &aw - &ay * &bw;
143 let vx = &cx * &aw - &ax * &cw;
144 let vy = &cy * &aw - &ay * &cw;
145 sign_of_int(&(ux * vy - uy * vx))
146}
147
148pub fn orient3d_r(a: &R3, b: &R3, c: &R3, d: &R3) -> Sign {
151 let (ax, ay, az, aw) = homog3(a);
152 let (bx, by, bz, bw) = homog3(b);
153 let (cx, cy, cz, cw) = homog3(c);
154 let (dx, dy, dz, dw) = homog3(d);
155 let ux = &bx * &aw - &ax * &bw;
158 let uy = &by * &aw - &ay * &bw;
159 let uz = &bz * &aw - &az * &bw;
160 let vx = &cx * &aw - &ax * &cw;
161 let vy = &cy * &aw - &ay * &cw;
162 let vz = &cz * &aw - &az * &cw;
163 let wx = &dx * &aw - &ax * &dw;
164 let wy = &dy * &aw - &ay * &dw;
165 let wz = &dz * &aw - &az * &dw;
166 let det = (&uy * &vz - &uz * &vy) * wx
167 + (&uz * &vx - &ux * &vz) * wy
168 + (&ux * &vy - &uy * &vx) * wz;
169 sign_of_int(&det)
170}
171
172pub fn incircle_r(a: &R2, b: &R2, c: &R2, d: &R2) -> Sign {
176 let (dx, dy, dw) = homog2(d);
177 let row = |p: &R2| -> (Int, Int, Int) {
182 let (px, py, pw) = homog2(p);
183 let nx = &px * &dw - &dx * &pw;
184 let ny = &py * &dw - &dy * &pw;
185 let s = pw * &dw;
186 let lift = &nx * &nx + &ny * &ny;
187 (nx * &s, ny * &s, lift)
188 };
189 let (ux, uy, ul) = row(a);
190 let (vx, vy, vl) = row(b);
191 let (wx, wy, wl) = row(c);
192 let det = ul * (&vx * &wy - &vy * &wx)
193 + vl * (&wx * &uy - &wy * &ux)
194 + wl * (&ux * &vy - &uy * &vx);
195 sign_of_int(&det)
196}
197
198pub fn point_on_segment_r(p: &R3, a: &R3, b: &R3) -> bool {
202 let (px, py, pz, pw) = homog3(p);
203 let (ax, ay, az, aw) = homog3(a);
204 let (bx, by, bz, bw) = homog3(b);
205 let apx = &px * &aw - &ax * &pw;
207 let apy = &py * &aw - &ay * &pw;
208 let apz = &pz * &aw - &az * &pw;
209 let dx = &bx * &aw - &ax * &bw;
210 let dy = &by * &aw - &ay * &bw;
211 let dz = &bz * &aw - &az * &bw;
212 if !(&apy * &dz - &apz * &dy).is_zero()
214 || !(&apz * &dx - &apx * &dz).is_zero()
215 || !(&apx * &dy - &apy * &dx).is_zero()
216 {
217 return false;
218 }
219 let s1 = &apx * &dx + &apy * &dy + &apz * &dz;
223 if s1.is_negative() {
224 return false;
225 }
226 let s2 = &dx * &dx + &dy * &dy + &dz * &dz;
227 s1 * (&aw * &bw) <= s2 * (pw * aw)
228}
229
230pub fn dot_diff_raw(a: &R3, o: &R3, u: &R3) -> (Int, Int) {
236 let (ax, ay, az, aw) = homog3(a);
237 let (ox, oy, oz, ow) = homog3(o);
238 let (ux, uy, uz, uw) = homog3(u);
239 let num = (&ax * &ow - &ox * &aw) * ux
241 + (&ay * &ow - &oy * &aw) * uy
242 + (&az * &ow - &oz * &aw) * uz;
243 (num, aw * ow * uw)
244}
245
246pub fn tri_normal_int(a: &R3, b: &R3, c: &R3) -> [Int; 3] {
250 let (ax, ay, az, aw) = homog3(a);
251 let (bx, by, bz, bw) = homog3(b);
252 let (cx, cy, cz, cw) = homog3(c);
253 let ux = &bx * &aw - &ax * &bw;
254 let uy = &by * &aw - &ay * &bw;
255 let uz = &bz * &aw - &az * &bw;
256 let vx = &cx * &aw - &ax * &cw;
257 let vy = &cy * &aw - &ay * &cw;
258 let vz = &cz * &aw - &az * &cw;
259 [
260 &uy * &vz - &uz * &vy,
261 &uz * &vx - &ux * &vz,
262 &ux * &vy - &uy * &vx,
263 ]
264}
265
266pub fn dot_point_raw(d: &[Int; 3], p: &R3) -> (Int, Int) {
271 let (px, py, pz, pw) = homog3(p);
272 (&d[0] * &px + &d[1] * &py + &d[2] * &pz, pw)
273}
274
275pub fn tri_normal_r(a: &R3, b: &R3, c: &R3) -> R3 {
278 b.sub(a).cross(&c.sub(a))
279}
280
281#[derive(Clone, Copy, Debug, PartialEq, Eq)]
283pub enum TriLoc {
284 Inside,
285 OnEdge(u8),
287 OnVertex(u8),
289 Outside,
290}
291
292pub fn point_in_tri_2d(p: &R2, a: &R2, b: &R2, c: &R2) -> TriLoc {
296 let orient = orient2d_r(a, b, c);
297 if orient == Sign::Zero {
298 return TriLoc::Outside;
299 }
300 let normalize = |s: Sign| if orient == Sign::Pos { s } else { s.flip() };
302 let s0 = normalize(orient2d_r(a, b, p)); let s1 = normalize(orient2d_r(b, c, p)); let s2 = normalize(orient2d_r(c, a, p)); if s0 == Sign::Neg || s1 == Sign::Neg || s2 == Sign::Neg {
306 return TriLoc::Outside;
307 }
308 match (s0 == Sign::Zero, s1 == Sign::Zero, s2 == Sign::Zero) {
309 (false, false, false) => TriLoc::Inside,
310 (true, false, false) => TriLoc::OnEdge(0),
311 (false, true, false) => TriLoc::OnEdge(1),
312 (false, false, true) => TriLoc::OnEdge(2),
313 (true, false, true) => TriLoc::OnVertex(0), (true, true, false) => TriLoc::OnVertex(1), (false, true, true) => TriLoc::OnVertex(2), (true, true, true) => TriLoc::Outside, }
318}
319
320pub fn line_plane_intersect(p: &R3, q: &R3, a: &R3, b: &R3, c: &R3) -> Option<R3> {
329 let (px, py, pz, pw) = homog3(p);
335 let (qx, qy, qz, qw) = homog3(q);
336 let (ax, ay, az, aw) = homog3(a);
337 let (bx, by, bz, bw) = homog3(b);
338 let (cx, cy, cz, cw) = homog3(c);
339
340 let ux = &bx * &aw - &ax * &bw;
342 let uy = &by * &aw - &ay * &bw;
343 let uz = &bz * &aw - &az * &bw;
344 let vx = &cx * &aw - &ax * &cw;
345 let vy = &cy * &aw - &ay * &cw;
346 let vz = &cz * &aw - &az * &cw;
347 let nx = &uy * &vz - &uz * &vy;
348 let ny = &uz * &vx - &ux * &vz;
349 let nz = &ux * &vy - &uy * &vx;
350
351 let dx = &qx * &pw - &px * &qw;
353 let dy = &qy * &pw - &py * &qw;
354 let dz = &qz * &pw - &pz * &qw;
355 let n_dot_d = &nx * &dx + &ny * &dy + &nz * &dz;
356 if n_dot_d.is_zero() {
357 return None;
358 }
359 let ex = &ax * &pw - &px * &aw;
360 let ey = &ay * &pw - &py * &aw;
361 let ez = &az * &pw - &pz * &aw;
362 let n_dot_e = &nx * &ex + &ny * &ey + &nz * &ez;
363
364 let t_n = &n_dot_e * &qw;
366 let t_d = &aw * &n_dot_d;
367 let den = &pw * &qw * &t_d;
368 let coord = |pi: &Int, di: &Int| -> Rational {
369 rat_new(pi * &qw * &t_d + di * &t_n, den.clone())
370 };
371 Some(R3::new(coord(&px, &dx), coord(&py, &dy), coord(&pz, &dz)))
372}
373
374pub fn line_line_intersect_2d(a: &R2, b: &R2, c: &R2, d: &R2) -> Option<R2> {
378 let (ax, ay, aw) = homog2(a);
384 let (bx, by, bw) = homog2(b);
385 let (cx, cy, cw) = homog2(c);
386 let (dx, dy, dw) = homog2(d);
387
388 let abx = &bx * &aw - &ax * &bw;
389 let aby = &by * &aw - &ay * &bw;
390 let cdx = &dx * &cw - &cx * &dw;
391 let cdy = &dy * &cw - &cy * &dw;
392 let dn = &abx * &cdy - &aby * &cdx;
393 if dn.is_zero() {
394 return None;
395 }
396 let cax = &cx * &aw - &ax * &cw;
397 let cay = &cy * &aw - &ay * &cw;
398 let n = &cax * &cdy - &cay * &cdx;
399
400 let den = &aw * &cw * &dn;
402 let dn_cw = &dn * &cw;
403 let x = rat_new(&ax * &dn_cw + &n * &abx, den.clone());
404 let y = rat_new(&ay * &dn_cw + &n * &aby, den);
405 Some(R2::new(x, y))
406}
407
408pub fn lift_to_plane(p: &R2, axis: usize, a: &R3, n: &R3) -> R3 {
414 let (nx, ny, nz, nw) = homog3(n);
415 let (ax, ay, az, aw) = homog3(a);
416 let (px, py, pw) = homog2(p);
417 let s = &nx * &ax + &ny * &ay + &nz * &az;
420 let rebuild = |ni: &Int, nj: &Int, nk: &Int| -> Rational {
421 rat_new(
422 &s * &pw - &aw * (ni * &px + nj * &py),
423 &aw * &pw * nk,
424 )
425 };
426 let _ = nw; match axis {
428 0 => {
429 let x = rebuild(&ny, &nz, &nx);
430 R3::new(x, p.x.clone(), p.y.clone())
431 }
432 1 => {
433 let y = rebuild(&nz, &nx, &ny);
434 R3::new(p.y.clone(), y, p.x.clone())
435 }
436 2 => {
437 let z = rebuild(&nx, &ny, &nz);
438 R3::new(p.x.clone(), p.y.clone(), z)
439 }
440 _ => unreachable!("axis must be 0, 1, or 2"),
441 }
442}
443
444pub fn segment_param(p: &R3, q: &R3, x: &R3) -> Rational {
448 let d = q.sub(p);
449 let (num, den) = if !rat_is_zero(&d.x) {
450 (&x.x - &p.x, d.x)
451 } else if !rat_is_zero(&d.y) {
452 (&x.y - &p.y, d.y)
453 } else {
454 (&x.z - &p.z, d.z)
455 };
456 debug_assert!(!rat_is_zero(&den), "segment_param requires p != q");
457 num / den
458}