mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-10-06 06:08:12 +08:00
Bezier-rs: Use nonzero winding order for Poisson-disk insideness test (#1590)
* Proper winding order for poisson dist * More robust cubic solving * Fix test expecting roots in a different order * Manual sort impl * Code review nits --------- Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
co-authored by
Keavon Chambers
parent
349ec5da72
commit
5f72a6a8a1
@@ -134,15 +134,20 @@ impl Bezier {
|
||||
match self.handles {
|
||||
BezierHandles::Linear => [[None; 3]; 2],
|
||||
BezierHandles::Quadratic { handle } => {
|
||||
let a = handle - self.start;
|
||||
let b = self.end - handle;
|
||||
let b_minus_a = b - a;
|
||||
[utils::solve_linear(b_minus_a.x, a.x), utils::solve_linear(b_minus_a.y, a.y)]
|
||||
let d0 = handle - self.start;
|
||||
let d1 = self.end - handle;
|
||||
let dd = d1 - d0;
|
||||
let a = (dd.x != 0.).then(|| -d0.x / dd.x);
|
||||
let b = (dd.y != 0.).then(|| -d0.y / dd.y);
|
||||
[[a, None, None], [b, None, None]]
|
||||
}
|
||||
BezierHandles::Cubic { handle_start, handle_end } => {
|
||||
let a = 3. * (-self.start + 3. * handle_start - 3. * handle_end + self.end);
|
||||
let b = 6. * (self.start - 2. * handle_start + handle_end);
|
||||
let c = 3. * (handle_start - self.start);
|
||||
let d0 = handle_start - self.start;
|
||||
let d1 = handle_end - handle_start;
|
||||
let d2 = self.end - handle_end;
|
||||
let a = d0 - 2. * d1 + d2;
|
||||
let b = 2. * (d1 - d0);
|
||||
let c = d0;
|
||||
let discriminant = b * b - 4. * a * c;
|
||||
let two_times_a = 2. * a;
|
||||
[
|
||||
@@ -592,9 +597,27 @@ impl Bezier {
|
||||
///
|
||||
/// Cast a ray to the left and count intersections.
|
||||
pub fn winding(&self, target_point: DVec2) -> i32 {
|
||||
let extrema = self.get_extrema_t_list();
|
||||
extrema
|
||||
let [x_extrema_t, y_extrema_t] = self.unrestricted_local_extrema();
|
||||
let mut x_extrema_t = x_extrema_t.map(|t| t.filter(|&t| t > 0. && t < 1.));
|
||||
let mut y_extrema_t = y_extrema_t.map(|t| t.filter(|&t| t > 0. && t < 1.));
|
||||
|
||||
let mut results = [None; 8];
|
||||
results[7] = Some(1.);
|
||||
for i in (0..7).rev() {
|
||||
let Some(min) = x_extrema_t.iter_mut().chain(y_extrema_t.iter_mut()).max_by(|a, b| a.partial_cmp(b).unwrap()) else {
|
||||
results[i] = Some(0.);
|
||||
break;
|
||||
};
|
||||
if let Some(value) = min.take() {
|
||||
results[i] = Some(value);
|
||||
} else {
|
||||
results[i] = Some(0.);
|
||||
break;
|
||||
}
|
||||
}
|
||||
results
|
||||
.windows(2)
|
||||
.flat_map(|t| t[0].and_then(|first| t[1].map(|second| [first, second])))
|
||||
.map(|t| self.trim(TValue::Parametric(t[0]), TValue::Parametric(t[1])).pre_split_winding_number(target_point))
|
||||
.sum()
|
||||
}
|
||||
@@ -737,7 +760,7 @@ mod tests {
|
||||
let p = DVec2::new(127., 121.);
|
||||
validate(bz, p);
|
||||
|
||||
let bz = Bezier::from_cubic_coordinates(55.0, 30.0, 85.0, 140.0, 175.0, 30.0, 185.0, 160.0);
|
||||
let bz = Bezier::from_cubic_coordinates(55., 30., 85., 140., 175., 30., 185., 160.);
|
||||
let p = DVec2::new(17., 172.);
|
||||
validate(bz, p);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user