-
Notifications
You must be signed in to change notification settings - Fork 71
/
quad_intersect.rs
92 lines (83 loc) · 2.77 KB
/
quad_intersect.rs
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
// Copyright 2022 the Kurbo Authors
// SPDX-License-Identifier: Apache-2.0 OR MIT
//! Test case that demonstrates quadratic/quadratic intersection using
//! new quartic solver.
use arrayvec::ArrayVec;
use kurbo::{common::solve_quartic, ParamCurve, Point, QuadBez, Shape};
use rand::{thread_rng, Rng};
fn rand_point() -> Point {
let mut rng = thread_rng();
Point::new(rng.gen_range(0.0..500.0), rng.gen_range(0.0..500.0))
}
fn rand_quad() -> QuadBez {
QuadBez::new(rand_point(), rand_point(), rand_point())
}
struct ImplicitQuad {
x2: f64,
xy: f64,
y2: f64,
x: f64,
y: f64,
c: f64,
}
impl ImplicitQuad {
fn from_quad(q: QuadBez) -> Self {
let Point { x: ax, y: ay } = q.p0;
let Point { x: bx, y: by } = q.p1;
let Point { x: cx, y: cy } = q.p2;
let (u0, u1, u2) = (by - cy, cx - bx, bx * cy - by * cx);
let (v0, v1, v2) = (cy - ay, ax - cx, cx * ay - cy * ax);
let (w0, w1, w2) = (ay - by, bx - ax, ax * by - ay * bx);
ImplicitQuad {
x2: 4. * u0 * w0 - v0 * v0,
xy: 4. * (u0 * w1 + u1 * w0) - 2. * v0 * v1,
y2: 4. * u1 * w1 - v1 * v1,
x: 4. * (u0 * w2 + u2 * w0) - 2. * v0 * v2,
y: 4. * (u1 * w2 + u2 * w1) - 2. * v1 * v2,
c: 4. * u2 * w2 - v2 * v2,
}
}
fn eval(&self, x: f64, y: f64) -> f64 {
self.x2 * x * x + self.xy * x * y + self.y2 * y * y + self.x * x + self.y * y + self.c
}
}
fn intersect_quads(q0: QuadBez, q1: QuadBez) -> ArrayVec<f64, 4> {
let iq = ImplicitQuad::from_quad(q0);
let c = q1.p0.to_vec2();
let b = (q1.p1 - q1.p0) * 2.0;
let a = c - q1.p1.to_vec2() * 2.0 + q1.p2.to_vec2();
let c0 = iq.eval(c.x, c.y);
let c1 = iq.x * b.x
+ iq.y * b.y
+ 2. * iq.x2 * (b.x * c.x)
+ 2. * iq.y2 * (b.y * c.y)
+ iq.xy * (b.x * c.y + b.y * c.x);
let c2 = iq.x * a.x
+ iq.y * a.y
+ iq.x2 * (2. * a.x * c.x + b.x * b.x)
+ iq.xy * (a.x * c.y + b.x * b.y + a.y * c.x)
+ iq.y2 * (2. * a.y * c.y + b.y * b.y);
let c3 = iq.x2 * 2. * a.x * b.x + iq.xy * (a.x * b.y + b.x * a.y) + iq.y2 * 2. * a.y * b.y;
let c4 = iq.x2 * a.x * a.x + iq.xy * a.x * a.y + iq.y2 * a.y * a.y;
let ts = solve_quartic(c0, c1, c2, c3, c4);
println!("ts: {:?}", ts);
ts
}
fn main() {
let q0 = rand_quad();
let q1 = rand_quad();
println!(
" <path d='{}' stroke='#000' fill='none' />",
q0.to_path(1e-9).to_svg()
);
println!(
" <path d='{}' stroke='#008' fill='none' />",
q1.to_path(1e-9).to_svg()
);
for t in intersect_quads(q0, q1) {
if (0.0..=1.0).contains(&t) {
let p = q1.eval(t);
println!(" <circle cx='{}' cy='{}' r='3' />", p.x, p.y);
}
}
}