Quadratics work now for simple cases

This commit is contained in:
Patrick Walton 2017-07-11 17:20:03 -07:00
parent a7ba7d200e
commit 8730df37a7
4 changed files with 81 additions and 18 deletions

View File

@ -133,13 +133,13 @@ pub unsafe extern fn pf_partitioner_init<'a>(partitioner: *mut Partitioner<'a>,
endpoints: *const Endpoint, endpoints: *const Endpoint,
endpoint_count: u32, endpoint_count: u32,
control_points: *const Point2DF32, control_points: *const Point2DF32,
control_points_count: u32, control_point_count: u32,
subpaths: *const Subpath, subpaths: *const Subpath,
subpath_count: u32) { subpath_count: u32) {
// FIXME(pcwalton): This is unsafe! `Point2D<f32>` and `Point2DF32` may have different layouts! // FIXME(pcwalton): This is unsafe! `Point2D<f32>` and `Point2DF32` may have different layouts!
(*partitioner).init(slice::from_raw_parts(endpoints, endpoint_count as usize), (*partitioner).init(slice::from_raw_parts(endpoints, endpoint_count as usize),
slice::from_raw_parts(control_points as *const Point2D<f32>, slice::from_raw_parts(control_points as *const Point2D<f32>,
control_points_count as usize), control_point_count as usize),
slice::from_raw_parts(subpaths, subpath_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, pub unsafe extern fn pf_tessellator_new(endpoints: *const Endpoint,
endpoint_count: u32, endpoint_count: u32,
control_points: *const Point2D<f32>, control_points: *const Point2D<f32>,
control_points_count: u32, control_point_count: u32,
b_quads: *const BQuad, b_quads: *const BQuad,
b_quad_count: u32, b_quad_count: u32,
antialiasing_mode: AntialiasingMode) antialiasing_mode: AntialiasingMode)
@ -174,7 +174,7 @@ pub unsafe extern fn pf_tessellator_new(endpoints: *const Endpoint,
let mut tessellator = let mut tessellator =
Box::new(Tessellator::new(slice::from_raw_parts(endpoints, endpoint_count as usize), Box::new(Tessellator::new(slice::from_raw_parts(endpoints, endpoint_count as usize),
slice::from_raw_parts(control_points, 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), slice::from_raw_parts(b_quads, b_quad_count as usize),
antialiasing_mode)); antialiasing_mode));
let tessellator_ptr: *mut Tessellator<'static> = &mut *tessellator; let tessellator_ptr: *mut Tessellator<'static> = &mut *tessellator;

View File

@ -94,15 +94,6 @@ pub fn sample_quadratic_bezier_deriv(t: f32,
return ((*p1 - *p0) * (1.0 - t) + (*p2 - *p1) * t) * 2.0 return ((*p1 - *p0) * (1.0 - t) + (*p2 - *p1) * t) * 2.0
} }
pub fn sample_quadratic_bezier_deriv_deriv(p0: &Point2D<f32>,
p1: &Point2D<f32>,
p2: &Point2D<f32>)
-> Vector2D<f32> {
// 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<f32>, b: &Point2D<f32>) -> f32 { pub fn solve_line_y_for_x(x: f32, a: &Point2D<f32>, b: &Point2D<f32>) -> f32 {
a.lerp(*b, (x - a.x) / (b.x - a.x)).y 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 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<f32> {
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<f32>,
pub yt: Option<f32>,
}
impl QuadraticBezierInflectionPoints {
pub fn calculate(p0: &Point2D<f32>, p1: &Point2D<f32>, p2: &Point2D<f32>)
-> 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)] #[derive(Clone, Copy, Debug)]
pub struct SubdividedQuadraticBezier { pub struct SubdividedQuadraticBezier {
pub ap0: Point2D<f32>, pub ap0: Point2D<f32>,

View File

@ -1,6 +1,7 @@
// partitionfinder/legalizer.rs // partitionfinder/legalizer.rs
use euclid::Point2D; use euclid::Point2D;
use geometry::{QuadraticBezierInflectionPoints, SubdividedQuadraticBezier};
use std::u32; use std::u32;
use {Endpoint, Subpath}; use {Endpoint, Subpath};
@ -64,11 +65,12 @@ impl Legalizer {
}) })
} }
#[inline] fn monotone_quadratic_curve_to(&mut self,
pub fn quadratic_curve_to(&mut self, control_point: &Point2D<f32>, endpoint: &Point2D<f32>) { control_point: &Point2D<f32>,
endpoint: &Point2D<f32>) {
self.subpaths self.subpaths
.last_mut() .last_mut()
.expect("`line_to()` called with no current subpath") .expect("`quadratic_curve_to()` called with no current subpath")
.last_endpoint_index += 1; .last_endpoint_index += 1;
self.endpoints.push(Endpoint { self.endpoints.push(Endpoint {
position: *endpoint, position: *endpoint,
@ -78,6 +80,51 @@ impl Legalizer {
self.control_points.push(*control_point) self.control_points.push(*control_point)
} }
pub fn quadratic_curve_to(&mut self, control_point: &Point2D<f32>, endpoint: &Point2D<f32>) {
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, pub fn bezier_curve_to(&mut self,
point1: &Point2D<f32>, point1: &Point2D<f32>,
point2: &Point2D<f32>, point2: &Point2D<f32>,
@ -94,4 +141,4 @@ impl Legalizer {
(point0.to_vector() + endpoint.to_vector()) * 0.25).to_point(); (point0.to_vector() + endpoint.to_vector()) * 0.25).to_point();
self.quadratic_curve_to(&control_point, endpoint) self.quadratic_curve_to(&control_point, endpoint)
} }
} }

View File

@ -65,7 +65,7 @@ typedef struct pf_b_quad pf_b_quad_t;
struct pf_endpoint { struct pf_endpoint {
pf_point2d_f32_t position; pf_point2d_f32_t position;
uint32_t control_points_index; uint32_t control_point_index;
uint32_t subpath_index; uint32_t subpath_index;
}; };