From 8730df37a7cbc65e96f8c8ef19871fcc770ff0cf Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Tue, 11 Jul 2017 17:20:03 -0700 Subject: [PATCH] Quadratics work now for simple cases --- partitionfinder/src/capi.rs | 8 ++-- partitionfinder/src/geometry.rs | 34 ++++++++++++----- partitionfinder/src/legalizer.rs | 55 +++++++++++++++++++++++++-- partitionfinder/src/partitionfinder.h | 2 +- 4 files changed, 81 insertions(+), 18 deletions(-) diff --git a/partitionfinder/src/capi.rs b/partitionfinder/src/capi.rs index 194e9109..b6d0b27d 100644 --- a/partitionfinder/src/capi.rs +++ b/partitionfinder/src/capi.rs @@ -133,13 +133,13 @@ pub unsafe extern fn pf_partitioner_init<'a>(partitioner: *mut Partitioner<'a>, endpoints: *const Endpoint, endpoint_count: u32, control_points: *const Point2DF32, - control_points_count: u32, + control_point_count: u32, subpaths: *const Subpath, subpath_count: u32) { // FIXME(pcwalton): This is unsafe! `Point2D` and `Point2DF32` may have different layouts! (*partitioner).init(slice::from_raw_parts(endpoints, endpoint_count as usize), slice::from_raw_parts(control_points as *const Point2D, - control_points_count as usize), + control_point_count as usize), slice::from_raw_parts(subpaths, subpath_count as usize)) } @@ -165,7 +165,7 @@ pub unsafe extern fn pf_partitioner_b_quads<'a>(partitioner: *mut Partitioner<'a pub unsafe extern fn pf_tessellator_new(endpoints: *const Endpoint, endpoint_count: u32, control_points: *const Point2D, - control_points_count: u32, + control_point_count: u32, b_quads: *const BQuad, b_quad_count: u32, antialiasing_mode: AntialiasingMode) @@ -174,7 +174,7 @@ pub unsafe extern fn pf_tessellator_new(endpoints: *const Endpoint, let mut tessellator = Box::new(Tessellator::new(slice::from_raw_parts(endpoints, endpoint_count as usize), slice::from_raw_parts(control_points, - control_points_count as usize), + control_point_count as usize), slice::from_raw_parts(b_quads, b_quad_count as usize), antialiasing_mode)); let tessellator_ptr: *mut Tessellator<'static> = &mut *tessellator; diff --git a/partitionfinder/src/geometry.rs b/partitionfinder/src/geometry.rs index edc6488b..7825e546 100644 --- a/partitionfinder/src/geometry.rs +++ b/partitionfinder/src/geometry.rs @@ -94,15 +94,6 @@ pub fn sample_quadratic_bezier_deriv(t: f32, return ((*p1 - *p0) * (1.0 - t) + (*p2 - *p1) * t) * 2.0 } -pub fn sample_quadratic_bezier_deriv_deriv(p0: &Point2D, - p1: &Point2D, - p2: &Point2D) - -> Vector2D { - // https://en.wikipedia.org/wiki/B%C3%A9zier_curve#Quadratic_B.C3.A9zier_curves - // FIXME(pcwalton): Can this be made faster? - (*p2 - *p1 * 2.0 + p0.to_vector()) * 2.0 -} - pub fn solve_line_y_for_x(x: f32, a: &Point2D, b: &Point2D) -> f32 { a.lerp(*b, (x - a.x) / (b.x - a.x)).y } @@ -139,6 +130,31 @@ pub fn solve_quadratic_bezier_y_for_x(x: f32, sample_quadratic_bezier(solve_quadratic_bezier_t_for_x(x, p0, p1, p2), p0, p1, p2).y } +fn quadratic_bezier_axis_inflection_point(p0: f32, p1: f32, p2: f32) -> Option { + let t = (p0 - p1) / (p0 - 2.0 * p1 + p2); + if t > f32::approx_epsilon() && t < 1.0 - f32::approx_epsilon() { + Some(t) + } else { + None + } +} + +#[derive(Clone, Copy, Debug)] +pub struct QuadraticBezierInflectionPoints { + pub xt: Option, + pub yt: Option, +} + +impl QuadraticBezierInflectionPoints { + pub fn calculate(p0: &Point2D, p1: &Point2D, p2: &Point2D) + -> QuadraticBezierInflectionPoints { + QuadraticBezierInflectionPoints { + xt: quadratic_bezier_axis_inflection_point(p0.x, p1.x, p2.x), + yt: quadratic_bezier_axis_inflection_point(p0.y, p1.y, p2.y), + } + } +} + #[derive(Clone, Copy, Debug)] pub struct SubdividedQuadraticBezier { pub ap0: Point2D, diff --git a/partitionfinder/src/legalizer.rs b/partitionfinder/src/legalizer.rs index b92a53ff..c0f1bb69 100644 --- a/partitionfinder/src/legalizer.rs +++ b/partitionfinder/src/legalizer.rs @@ -1,6 +1,7 @@ // partitionfinder/legalizer.rs use euclid::Point2D; +use geometry::{QuadraticBezierInflectionPoints, SubdividedQuadraticBezier}; use std::u32; use {Endpoint, Subpath}; @@ -64,11 +65,12 @@ impl Legalizer { }) } - #[inline] - pub fn quadratic_curve_to(&mut self, control_point: &Point2D, endpoint: &Point2D) { + fn monotone_quadratic_curve_to(&mut self, + control_point: &Point2D, + endpoint: &Point2D) { self.subpaths .last_mut() - .expect("`line_to()` called with no current subpath") + .expect("`quadratic_curve_to()` called with no current subpath") .last_endpoint_index += 1; self.endpoints.push(Endpoint { position: *endpoint, @@ -78,6 +80,51 @@ impl Legalizer { self.control_points.push(*control_point) } + pub fn quadratic_curve_to(&mut self, control_point: &Point2D, endpoint: &Point2D) { + let last_endpoint_index = + self.subpaths + .last() + .expect("`quadratic_curve_to()` called with no current subpath") + .last_endpoint_index; + let point0 = self.endpoints[last_endpoint_index as usize - 1].position; + + match QuadraticBezierInflectionPoints::calculate(&point0, control_point, endpoint) { + QuadraticBezierInflectionPoints { + xt: Some(xt), + yt: Some(yt), + } => { + let subdivision = SubdividedQuadraticBezier::new(f32::min(xt, yt), + &point0, + control_point, + endpoint); + self.monotone_quadratic_curve_to(&subdivision.ap1, &subdivision.ap2bp0); + self.quadratic_curve_to(&subdivision.bp1, &subdivision.bp2) + } + QuadraticBezierInflectionPoints { + xt: Some(t), + yt: None, + } | + QuadraticBezierInflectionPoints { + xt: None, + yt: Some(t), + } => { + let subdivision = SubdividedQuadraticBezier::new(t, + &point0, + control_point, + endpoint); + self.monotone_quadratic_curve_to(&subdivision.ap1, &subdivision.ap2bp0); + self.quadratic_curve_to(&subdivision.bp1, &subdivision.bp2) + } + QuadraticBezierInflectionPoints { + xt: None, + yt: None, + } => { + self.monotone_quadratic_curve_to(control_point, endpoint) + } + } + } + + pub fn bezier_curve_to(&mut self, point1: &Point2D, point2: &Point2D, @@ -94,4 +141,4 @@ impl Legalizer { (point0.to_vector() + endpoint.to_vector()) * 0.25).to_point(); self.quadratic_curve_to(&control_point, endpoint) } -} \ No newline at end of file +} diff --git a/partitionfinder/src/partitionfinder.h b/partitionfinder/src/partitionfinder.h index 2718c7b8..097fc2d8 100644 --- a/partitionfinder/src/partitionfinder.h +++ b/partitionfinder/src/partitionfinder.h @@ -65,7 +65,7 @@ typedef struct pf_b_quad pf_b_quad_t; struct pf_endpoint { pf_point2d_f32_t position; - uint32_t control_points_index; + uint32_t control_point_index; uint32_t subpath_index; };