Split paths into monotonic segments before partitioning them in the demo

This commit is contained in:
Patrick Walton 2017-09-12 09:35:57 -07:00
parent c3e02d6faa
commit a7d75f913c
4 changed files with 64 additions and 14 deletions

View File

@ -26,8 +26,9 @@ use bincode::Infinite;
use euclid::{Point2D, Size2D, Transform2D};
use pathfinder_font_renderer::{FontContext, FontInstanceKey, FontKey, GlyphKey};
use pathfinder_partitioner::partitioner::Partitioner;
use pathfinder_path_utils::monotonic::MonotonicPathSegmentStream;
use pathfinder_path_utils::stroke;
use pathfinder_path_utils::{PathBuffer, PathSegment, Transform2DPathStream};
use pathfinder_path_utils::{PathBuffer, PathBufferStream, PathSegment, Transform2DPathStream};
use rocket::http::{ContentType, Status};
use rocket::request::Request;
use rocket::response::{NamedFile, Redirect, Responder, Response};
@ -410,7 +411,9 @@ fn partition_font(request: Json<PartitionFontRequest>)
// This might fail; if so, just leave it blank.
if let Ok(glyph_outline) = font_context.glyph_outline(&font_instance_key, &glyph_key) {
path_buffer.add_stream(Transform2DPathStream::new(glyph_outline, &glyph.transform))
let stream = Transform2DPathStream::new(glyph_outline, &glyph.transform);
let stream = MonotonicPathSegmentStream::new(stream);
path_buffer.add_stream(stream)
}
let last_subpath_index = path_buffer.subpaths.len();
@ -497,9 +500,15 @@ fn partition_svg_paths(request: Json<PartitionSvgPathsRequest>)
}
match path.kind {
PartitionSvgPathKind::Fill => path_buffer.add_stream(stream.into_iter()),
PartitionSvgPathKind::Fill => {
path_buffer.add_stream(MonotonicPathSegmentStream::new(stream.into_iter()))
}
PartitionSvgPathKind::Stroke(stroke_width) => {
stroke::stroke(&mut path_buffer, stream.into_iter(), stroke_width)
let mut temp_path_buffer = PathBuffer::new();
stroke::stroke(&mut temp_path_buffer, stream.into_iter(), stroke_width);
let stream = PathBufferStream::new(&temp_path_buffer);
let stream = MonotonicPathSegmentStream::new(stream);
path_buffer.add_stream(stream)
}
}

View File

@ -10,6 +10,7 @@
use euclid::Point2D;
use euclid::approxeq::ApproxEq;
use pathfinder_path_utils::curve::Curve;
use std::cmp::Ordering;
pub(crate) trait ApproxOrdered {
@ -85,11 +86,6 @@ pub fn quadratic_bezier_quadratic_bezier_crossing_point(_a_p0: &Point2D<f32>,
None
}
pub fn sample_quadratic_bezier(t: f32, p0: &Point2D<f32>, p1: &Point2D<f32>, p2: &Point2D<f32>)
-> Point2D<f32> {
p0.lerp(*p1, t).lerp(p1.lerp(*p2, t), t)
}
pub fn solve_line_t_for_x(x: f32, a: &Point2D<f32>, b: &Point2D<f32>) -> f32 {
if b.x == a.x {
0.0
@ -121,7 +117,7 @@ pub fn solve_quadratic_bezier_y_for_x(x: f32,
p1: &Point2D<f32>,
p2: &Point2D<f32>)
-> f32 {
sample_quadratic_bezier(solve_quadratic_bezier_t_for_x(x, p0, p1, p2), p0, p1, p2).y
Curve::new(p0, p1, p2).sample(solve_quadratic_bezier_t_for_x(x, p0, p1, p2)).y
}
fn quadratic_bezier_axis_inflection_point(p0: f32, p1: f32, p2: f32) -> Option<f32> {

View File

@ -13,6 +13,7 @@ use euclid::Point2D;
use geometry::{self, SubdividedQuadraticBezier};
use log::LogLevel;
use pathfinder_path_utils::PathBuffer;
use pathfinder_path_utils::curve::Curve;
use std::collections::BinaryHeap;
use std::cmp::Ordering;
use std::f32;
@ -712,10 +713,7 @@ impl<'a> Partitioner<'a> {
}
control_point_vertex_index => {
let control_point = &self.b_vertex_positions[control_point_vertex_index as usize];
geometry::sample_quadratic_bezier(t,
left_vertex_position,
control_point,
right_endpoint_position)
Curve::new(left_vertex_position, control_point, right_endpoint_position).sample(t)
}
}
}

View File

@ -98,6 +98,53 @@ impl PathBuffer {
}
}
pub struct PathBufferStream<'a> {
path_buffer: &'a PathBuffer,
endpoint_index: u32,
subpath_index: u32,
}
impl<'a> PathBufferStream<'a> {
pub fn new<'b>(path_buffer: &'b PathBuffer) -> PathBufferStream<'b> {
PathBufferStream {
path_buffer: path_buffer,
endpoint_index: 0,
subpath_index: 0,
}
}
}
impl<'a> Iterator for PathBufferStream<'a> {
type Item = PathSegment;
fn next(&mut self) -> Option<PathSegment> {
if self.subpath_index as usize == self.path_buffer.subpaths.len() {
return None
}
let subpath = &self.path_buffer.subpaths[self.subpath_index as usize];
if self.endpoint_index == subpath.last_endpoint_index {
self.subpath_index += 1;
return Some(PathSegment::ClosePath)
}
let endpoint = &self.path_buffer.endpoints[self.endpoint_index as usize];
self.endpoint_index += 1;
if self.endpoint_index == subpath.first_endpoint_index {
return Some(PathSegment::MoveTo(endpoint.position))
}
if endpoint.control_point_index == u32::MAX {
return Some(PathSegment::LineTo(endpoint.position))
}
let control_point = &self.path_buffer
.control_points[endpoint.control_point_index as usize];
Some(PathSegment::CurveTo(*control_point, endpoint.position))
}
}
#[repr(C)]
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub struct Endpoint {