Add arc building methods and switch the Moiré demo to use them.

Also, stop taking points by reference in many methods, for consistency.
This commit is contained in:
Patrick Walton 2019-05-13 12:17:49 -07:00
parent 55be787ffd
commit f24d93819b
14 changed files with 157 additions and 97 deletions

1
Cargo.lock generated
View File

@ -180,6 +180,7 @@ dependencies = [
"pathfinder_gl 0.1.0", "pathfinder_gl 0.1.0",
"pathfinder_gpu 0.1.0", "pathfinder_gpu 0.1.0",
"pathfinder_renderer 0.1.0", "pathfinder_renderer 0.1.0",
"pretty_env_logger 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"sdl2 0.32.1 (registry+https://github.com/rust-lang/crates.io-index)", "sdl2 0.32.1 (registry+https://github.com/rust-lang/crates.io-index)",
"sdl2-sys 0.32.5 (registry+https://github.com/rust-lang/crates.io-index)", "sdl2-sys 0.32.5 (registry+https://github.com/rust-lang/crates.io-index)",
] ]

View File

@ -97,7 +97,7 @@ impl CanvasRenderingContext2D {
drop(self.scene.push_text(string, drop(self.scene.push_text(string,
&TextStyle { size: self.current_state.font_size }, &TextStyle { size: self.current_state.font_size },
&self.current_state.font_collection, &self.current_state.font_collection,
&Transform2DF32::from_translation(&position), &Transform2DF32::from_translation(position),
TextRenderMode::Fill, TextRenderMode::Fill,
HintingOptions::None, HintingOptions::None,
paint_id)); paint_id));
@ -109,7 +109,7 @@ impl CanvasRenderingContext2D {
drop(self.scene.push_text(string, drop(self.scene.push_text(string,
&TextStyle { size: self.current_state.font_size }, &TextStyle { size: self.current_state.font_size },
&self.current_state.font_collection, &self.current_state.font_collection,
&Transform2DF32::from_translation(&position), &Transform2DF32::from_translation(position),
TextRenderMode::Stroke(self.current_state.line_width), TextRenderMode::Stroke(self.current_state.line_width),
HintingOptions::None, HintingOptions::None,
paint_id)); paint_id));
@ -196,7 +196,7 @@ pub struct Path2D {
current_contour: Contour, current_contour: Contour,
} }
// TODO(pcwalton): `arc`, `ellipse` // TODO(pcwalton): `ellipse`
impl Path2D { impl Path2D {
#[inline] #[inline]
pub fn new() -> Path2D { pub fn new() -> Path2D {
@ -230,6 +230,11 @@ impl Path2D {
self.current_contour.push_cubic(ctrl0, ctrl1, to); self.current_contour.push_cubic(ctrl0, ctrl1, to);
} }
#[inline]
pub fn arc(&mut self, center: Point2DF32, radius: f32, start_angle: f32, end_angle: f32) {
self.current_contour.push_arc(center, radius, start_angle, end_angle);
}
pub fn rect(&mut self, rect: RectF32) { pub fn rect(&mut self, rect: RectF32) {
self.flush_current_contour(); self.flush_current_contour();
self.current_contour.push_endpoint(rect.origin()); self.current_contour.push_endpoint(rect.origin());

View File

@ -6,6 +6,7 @@ edition = "2018"
[dependencies] [dependencies]
gl = "0.6" gl = "0.6"
pretty_env_logger = "0.3"
sdl2 = "0.32" sdl2 = "0.32"
sdl2-sys = "0.32" sdl2-sys = "0.32"

View File

@ -21,6 +21,7 @@ use pathfinder_renderer::options::RenderOptions;
use sdl2::event::Event; use sdl2::event::Event;
use sdl2::keyboard::Keycode; use sdl2::keyboard::Keycode;
use sdl2::video::GLProfile; use sdl2::video::GLProfile;
use std::f32::consts::PI;
use std::f32; use std::f32;
const VELOCITY: f32 = 0.02; const VELOCITY: f32 = 0.02;
@ -36,6 +37,8 @@ const CIRCLE_THICKNESS: f32 = 16.0;
const COLOR_CYCLE_SPEED: f32 = 0.0025; const COLOR_CYCLE_SPEED: f32 = 0.0025;
fn main() { fn main() {
pretty_env_logger::init();
// Set up SDL2. // Set up SDL2.
let sdl_context = sdl2::init().unwrap(); let sdl_context = sdl2::init().unwrap();
let video = sdl_context.video().unwrap(); let video = sdl_context.video().unwrap();
@ -150,27 +153,14 @@ impl MoireRenderer {
} }
fn draw_circles(&self, canvas: &mut CanvasRenderingContext2D, center: Point2DF32) { fn draw_circles(&self, canvas: &mut CanvasRenderingContext2D, center: Point2DF32) {
let center = center.scale(self.device_pixel_ratio);
for index in 0..CIRCLE_COUNT { for index in 0..CIRCLE_COUNT {
let radius = (index + 1) as f32 * CIRCLE_SPACING * self.device_pixel_ratio;
let mut path = Path2D::new(); let mut path = Path2D::new();
self.add_circle_subpath(&mut path, path.arc(center, radius, 0.0, PI * 2.0);
center.scale(self.device_pixel_ratio),
index as f32 * CIRCLE_SPACING * self.device_pixel_ratio);
canvas.stroke_path(path); canvas.stroke_path(path);
} }
} }
fn add_circle_subpath(&self, path: &mut Path2D, center: Point2DF32, radius: f32) {
path.move_to(center + Point2DF32::new(0.0, -radius));
path.quadratic_curve_to(center + Point2DF32::new(radius, -radius),
center + Point2DF32::new(radius, 0.0));
path.quadratic_curve_to(center + Point2DF32::new(radius, radius),
center + Point2DF32::new(0.0, radius));
path.quadratic_curve_to(center + Point2DF32::new(-radius, radius),
center + Point2DF32::new(-radius, 0.0));
path.quadratic_curve_to(center + Point2DF32::new(-radius, -radius),
center + Point2DF32::new(0.0, -radius));
path.close_path();
}
} }
struct ColorGradient([ColorF; 5]); struct ColorGradient([ColorF; 5]);

View File

@ -20,7 +20,7 @@ pub struct LineSegmentF32(pub F32x4);
impl LineSegmentF32 { impl LineSegmentF32 {
#[inline] #[inline]
pub fn new(from: &Point2DF32, to: &Point2DF32) -> LineSegmentF32 { pub fn new(from: Point2DF32, to: Point2DF32) -> LineSegmentF32 {
LineSegmentF32(from.0.concat_xy_xy(to.0)) LineSegmentF32(from.0.concat_xy_xy(to.0))
} }

View File

@ -10,6 +10,7 @@
//! 2D affine transforms. //! 2D affine transforms.
use crate::basic::line_segment::LineSegmentF32;
use crate::basic::point::Point2DF32; use crate::basic::point::Point2DF32;
use crate::basic::rect::RectF32; use crate::basic::rect::RectF32;
use crate::basic::transform3d::Transform3DF32; use crate::basic::transform3d::Transform3DF32;
@ -24,13 +25,13 @@ pub struct Matrix2x2F32(pub F32x4);
impl Default for Matrix2x2F32 { impl Default for Matrix2x2F32 {
#[inline] #[inline]
fn default() -> Matrix2x2F32 { fn default() -> Matrix2x2F32 {
Self::from_scale(&Point2DF32::splat(1.0)) Self::from_scale(Point2DF32::splat(1.0))
} }
} }
impl Matrix2x2F32 { impl Matrix2x2F32 {
#[inline] #[inline]
pub fn from_scale(scale: &Point2DF32) -> Matrix2x2F32 { pub fn from_scale(scale: Point2DF32) -> Matrix2x2F32 {
Matrix2x2F32(F32x4::new(scale.x(), 0.0, 0.0, scale.y())) Matrix2x2F32(F32x4::new(scale.x(), 0.0, 0.0, scale.y()))
} }
@ -66,7 +67,7 @@ impl Matrix2x2F32 {
} }
#[inline] #[inline]
pub fn transform_point(&self, point: &Point2DF32) -> Point2DF32 { pub fn transform_point(&self, point: Point2DF32) -> Point2DF32 {
let halves = self.0 * point.0.xxyy(); let halves = self.0 * point.0.xxyy();
Point2DF32(halves + halves.zwzw()) Point2DF32(halves + halves.zwzw())
} }
@ -118,13 +119,13 @@ pub struct Transform2DF32 {
impl Default for Transform2DF32 { impl Default for Transform2DF32 {
#[inline] #[inline]
fn default() -> Transform2DF32 { fn default() -> Transform2DF32 {
Self::from_scale(&Point2DF32::splat(1.0)) Self::from_scale(Point2DF32::splat(1.0))
} }
} }
impl Transform2DF32 { impl Transform2DF32 {
#[inline] #[inline]
pub fn from_scale(scale: &Point2DF32) -> Transform2DF32 { pub fn from_scale(scale: Point2DF32) -> Transform2DF32 {
Transform2DF32 { Transform2DF32 {
matrix: Matrix2x2F32::from_scale(scale), matrix: Matrix2x2F32::from_scale(scale),
vector: Point2DF32::default(), vector: Point2DF32::default(),
@ -140,11 +141,8 @@ impl Transform2DF32 {
} }
#[inline] #[inline]
pub fn from_translation(vector: &Point2DF32) -> Transform2DF32 { pub fn from_translation(vector: Point2DF32) -> Transform2DF32 {
Transform2DF32 { Transform2DF32 { matrix: Matrix2x2F32::default(), vector }
matrix: Matrix2x2F32::default(),
vector: *vector,
}
} }
#[inline] #[inline]
@ -154,10 +152,8 @@ impl Transform2DF32 {
translation: Point2DF32, translation: Point2DF32,
) -> Transform2DF32 { ) -> Transform2DF32 {
let rotation = Transform2DF32::from_rotation(theta); let rotation = Transform2DF32::from_rotation(theta);
let translation = Transform2DF32::from_translation(&translation); let translation = Transform2DF32::from_translation(translation);
Transform2DF32::from_scale(&scale) Transform2DF32::from_scale(scale).post_mul(&rotation).post_mul(&translation)
.post_mul(&rotation)
.post_mul(&translation)
} }
#[inline] #[inline]
@ -169,16 +165,22 @@ impl Transform2DF32 {
} }
#[inline] #[inline]
pub fn transform_point(&self, point: &Point2DF32) -> Point2DF32 { pub fn transform_point(&self, point: Point2DF32) -> Point2DF32 {
self.matrix.transform_point(point) + self.vector self.matrix.transform_point(point) + self.vector
} }
#[inline]
pub fn transform_line_segment(&self, line_segment: &LineSegmentF32) -> LineSegmentF32 {
LineSegmentF32::new(self.transform_point(line_segment.from()),
self.transform_point(line_segment.to()))
}
#[inline] #[inline]
pub fn transform_rect(&self, rect: &RectF32) -> RectF32 { pub fn transform_rect(&self, rect: &RectF32) -> RectF32 {
let upper_left = self.transform_point(&rect.origin()); let upper_left = self.transform_point(rect.origin());
let upper_right = self.transform_point(&rect.upper_right()); let upper_right = self.transform_point(rect.upper_right());
let lower_left = self.transform_point(&rect.lower_left()); let lower_left = self.transform_point(rect.lower_left());
let lower_right = self.transform_point(&rect.lower_right()); let lower_right = self.transform_point(rect.lower_right());
let min_point = upper_left.min(upper_right).min(lower_left).min(lower_right); let min_point = upper_left.min(upper_right).min(lower_left).min(lower_right);
let max_point = upper_left.max(upper_right).max(lower_left).max(lower_right); let max_point = upper_left.max(upper_right).max(lower_left).max(lower_right);
RectF32::from_points(min_point, max_point) RectF32::from_points(min_point, max_point)
@ -187,7 +189,7 @@ impl Transform2DF32 {
#[inline] #[inline]
pub fn post_mul(&self, other: &Transform2DF32) -> Transform2DF32 { pub fn post_mul(&self, other: &Transform2DF32) -> Transform2DF32 {
let matrix = self.matrix.post_mul(&other.matrix); let matrix = self.matrix.post_mul(&other.matrix);
let vector = other.transform_point(&self.vector); let vector = other.transform_point(self.vector);
Transform2DF32 { matrix, vector } Transform2DF32 { matrix, vector }
} }
@ -243,7 +245,7 @@ impl Transform2DF32 {
#[inline] #[inline]
pub fn post_translate(&self, vector: Point2DF32) -> Transform2DF32 { pub fn post_translate(&self, vector: Point2DF32) -> Transform2DF32 {
self.post_mul(&Transform2DF32::from_translation(&vector)) self.post_mul(&Transform2DF32::from_translation(vector))
} }
#[inline] #[inline]
@ -253,7 +255,7 @@ impl Transform2DF32 {
#[inline] #[inline]
pub fn post_scale(&self, scale: Point2DF32) -> Transform2DF32 { pub fn post_scale(&self, scale: Point2DF32) -> Transform2DF32 {
self.post_mul(&Transform2DF32::from_scale(&scale)) self.post_mul(&Transform2DF32::from_scale(scale))
} }
/// Returns the translation part of this matrix. /// Returns the translation part of this matrix.
@ -303,18 +305,18 @@ where
if !segment.is_none() { if !segment.is_none() {
segment segment
.baseline .baseline
.set_from(&self.transform.transform_point(&segment.baseline.from())); .set_from(&self.transform.transform_point(segment.baseline.from()));
segment segment
.baseline .baseline
.set_to(&self.transform.transform_point(&segment.baseline.to())); .set_to(&self.transform.transform_point(segment.baseline.to()));
if !segment.is_line() { if !segment.is_line() {
segment segment
.ctrl .ctrl
.set_from(&self.transform.transform_point(&segment.ctrl.from())); .set_from(&self.transform.transform_point(segment.ctrl.from()));
if !segment.is_quadratic() { if !segment.is_quadratic() {
segment segment
.ctrl .ctrl
.set_to(&self.transform.transform_point(&segment.ctrl.to())); .set_to(&self.transform.transform_point(segment.ctrl.to()));
} }
} }
} }

View File

@ -325,7 +325,7 @@ impl ContourPolygonClipper {
Some(prev) => *prev, Some(prev) => *prev,
}; };
for &next in &clip_polygon { for &next in &clip_polygon {
self.clip_against(Edge(LineSegmentF32::new(&prev, &next))); self.clip_against(Edge(LineSegmentF32::new(prev, next)));
prev = next; prev = next;
} }

View File

@ -19,6 +19,7 @@ use crate::clip::{self, ContourPolygonClipper, ContourRectClipper};
use crate::dilation::ContourDilator; use crate::dilation::ContourDilator;
use crate::orientation::Orientation; use crate::orientation::Orientation;
use crate::segment::{Segment, SegmentFlags, SegmentKind}; use crate::segment::{Segment, SegmentFlags, SegmentKind};
use std::f32::consts::FRAC_PI_2;
use std::fmt::{self, Debug, Formatter}; use std::fmt::{self, Debug, Formatter};
use std::mem; use std::mem;
@ -292,7 +293,10 @@ impl Contour {
// TODO(pcwalton): SIMD. // TODO(pcwalton): SIMD.
#[inline] #[inline]
pub(crate) fn push_point(&mut self, point: Point2DF32, flags: PointFlags, update_bounds: bool) { pub(crate) fn push_point(&mut self,
point: Point2DF32,
flags: PointFlags,
update_bounds: bool) {
debug_assert!(!point.x().is_nan() && !point.y().is_nan()); debug_assert!(!point.x().is_nan() && !point.y().is_nan());
if update_bounds { if update_bounds {
@ -354,6 +358,37 @@ impl Contour {
self.push_point(segment.baseline.to(), PointFlags::empty(), update_bounds); self.push_point(segment.baseline.to(), PointFlags::empty(), update_bounds);
} }
pub fn push_arc(&mut self, center: Point2DF32, radius: f32, start_angle: f32, end_angle: f32) {
let scale = Transform2DF32::from_scale(Point2DF32::splat(radius));
let translation = Transform2DF32::from_translation(center);
let (mut angle, mut first_segment) = (start_angle, true);
while angle < end_angle {
let sweep_angle = f32::min(FRAC_PI_2, end_angle - angle);
let mut segment = Segment::arc(sweep_angle);
let rotation = Transform2DF32::from_rotation(angle);
segment = segment.transform(&scale.post_mul(&rotation).post_mul(&translation));
/*
println!("angle={} start_angle={} end_angle={} sweep_angle={} segment={:?}",
angle,
start_angle,
end_angle,
sweep_angle,
segment);
*/
if first_segment {
self.push_full_segment(&segment, true);
first_segment = false;
} else {
self.push_segment(segment, true);
}
angle += sweep_angle;
}
}
#[inline] #[inline]
pub fn segment_after(&self, point_index: u32) -> Segment { pub fn segment_after(&self, point_index: u32) -> Segment {
debug_assert!(self.point_is_endpoint(point_index)); debug_assert!(self.point_is_endpoint(point_index));
@ -388,8 +423,8 @@ impl Contour {
pub fn hull_segment_after(&self, prev_point_index: u32) -> LineSegmentF32 { pub fn hull_segment_after(&self, prev_point_index: u32) -> LineSegmentF32 {
let next_point_index = self.next_point_index_of(prev_point_index); let next_point_index = self.next_point_index_of(prev_point_index);
LineSegmentF32::new( LineSegmentF32::new(
&self.points[prev_point_index as usize], self.points[prev_point_index as usize],
&self.points[next_point_index as usize], self.points[next_point_index as usize],
) )
} }
@ -455,7 +490,7 @@ impl Contour {
pub fn transform(&mut self, transform: &Transform2DF32) { pub fn transform(&mut self, transform: &Transform2DF32) {
for (point_index, point) in self.points.iter_mut().enumerate() { for (point_index, point) in self.points.iter_mut().enumerate() {
*point = transform.transform_point(point); *point = transform.transform_point(*point);
union_rect(&mut self.bounds, *point, point_index == 0); union_rect(&mut self.bounds, *point, point_index == 0);
} }
} }
@ -522,8 +557,8 @@ impl Contour {
point_index point_index
}; };
let baseline = LineSegmentF32::new( let baseline = LineSegmentF32::new(
&contour.points[last_endpoint_index as usize], contour.points[last_endpoint_index as usize],
&contour.points[position_index as usize], contour.points[position_index as usize],
); );
let point_count = point_index - last_endpoint_index + 1; let point_count = point_index - last_endpoint_index + 1;
if point_count == 3 { if point_count == 3 {
@ -531,13 +566,13 @@ impl Contour {
let ctrl_position = &contour.points[ctrl_point_index]; let ctrl_position = &contour.points[ctrl_point_index];
handle_cubic( handle_cubic(
self, self,
Segment::quadratic(&baseline, &ctrl_position).to_cubic(), Segment::quadratic(&baseline, *ctrl_position).to_cubic(),
); );
} else if point_count == 4 { } else if point_count == 4 {
let first_ctrl_point_index = last_endpoint_index as usize + 1; let first_ctrl_point_index = last_endpoint_index as usize + 1;
let ctrl_position_0 = &contour.points[first_ctrl_point_index + 0]; let ctrl_position_0 = &contour.points[first_ctrl_point_index + 0];
let ctrl_position_1 = &contour.points[first_ctrl_point_index + 1]; let ctrl_position_1 = &contour.points[first_ctrl_point_index + 1];
let ctrl = LineSegmentF32::new(&ctrl_position_0, &ctrl_position_1); let ctrl = LineSegmentF32::new(*ctrl_position_0, *ctrl_position_1);
handle_cubic(self, Segment::cubic(&baseline, &ctrl)); handle_cubic(self, Segment::cubic(&baseline, &ctrl));
} }
@ -723,24 +758,21 @@ impl<'a> Iterator for ContourIter<'a> {
if self.index == contour.len() { if self.index == contour.len() {
let point1 = contour.position_of(0); let point1 = contour.position_of(0);
self.index += 1; self.index += 1;
return Some(Segment::line(&LineSegmentF32::new(&point0, &point1))); return Some(Segment::line(&LineSegmentF32::new(point0, point1)));
} }
let point1_index = self.index; let point1_index = self.index;
self.index += 1; self.index += 1;
let point1 = contour.position_of(point1_index); let point1 = contour.position_of(point1_index);
if contour.point_is_endpoint(point1_index) { if contour.point_is_endpoint(point1_index) {
return Some(Segment::line(&LineSegmentF32::new(&point0, &point1))); return Some(Segment::line(&LineSegmentF32::new(point0, point1)));
} }
let point2_index = self.index; let point2_index = self.index;
let point2 = contour.position_of(point2_index); let point2 = contour.position_of(point2_index);
self.index += 1; self.index += 1;
if contour.point_is_endpoint(point2_index) { if contour.point_is_endpoint(point2_index) {
return Some(Segment::quadratic( return Some(Segment::quadratic(&LineSegmentF32::new(point0, point2), point1));
&LineSegmentF32::new(&point0, &point2),
&point1,
));
} }
let point3_index = self.index; let point3_index = self.index;
@ -748,8 +780,8 @@ impl<'a> Iterator for ContourIter<'a> {
self.index += 1; self.index += 1;
debug_assert!(contour.point_is_endpoint(point3_index)); debug_assert!(contour.point_is_endpoint(point3_index));
return Some(Segment::cubic( return Some(Segment::cubic(
&LineSegmentF32::new(&point0, &point3), &LineSegmentF32::new(point0, point3),
&LineSegmentF32::new(&point1, &point2), &LineSegmentF32::new(point1, point2),
)); ));
} }
} }

View File

@ -12,8 +12,10 @@
use crate::basic::line_segment::LineSegmentF32; use crate::basic::line_segment::LineSegmentF32;
use crate::basic::point::Point2DF32; use crate::basic::point::Point2DF32;
use crate::basic::transform2d::Transform2DF32;
use crate::util::{self, EPSILON}; use crate::util::{self, EPSILON};
use pathfinder_simd::default::F32x4; use pathfinder_simd::default::F32x4;
use std::f32::consts::SQRT_2;
const MAX_NEWTON_ITERATIONS: u32 = 32; const MAX_NEWTON_ITERATIONS: u32 = 32;
@ -47,10 +49,10 @@ impl Segment {
} }
#[inline] #[inline]
pub fn quadratic(baseline: &LineSegmentF32, ctrl: &Point2DF32) -> Segment { pub fn quadratic(baseline: &LineSegmentF32, ctrl: Point2DF32) -> Segment {
Segment { Segment {
baseline: *baseline, baseline: *baseline,
ctrl: LineSegmentF32::new(ctrl, &Point2DF32::default()), ctrl: LineSegmentF32::new(ctrl, Point2DF32::default()),
kind: SegmentKind::Quadratic, kind: SegmentKind::Quadratic,
flags: SegmentFlags::empty(), flags: SegmentFlags::empty(),
} }
@ -66,6 +68,24 @@ impl Segment {
} }
} }
/// Approximates an unit-length arc with a cubic Bézier curve.
///
/// The maximum supported `sweep_angle` is π/2 (i.e. 90°).
pub fn arc(sweep_angle: f32) -> Segment {
// Aleksas Riškus, "Approximation of a Cubic Bézier Curve by Circular Arcs and Vice Versa"
// 2006.
//
// https://pdfs.semanticscholar.org/1639/0db1a470bd13fe428e0896671a9a5745070a.pdf
let phi = 0.5 * sweep_angle;
let p0 = Point2DF32::new(f32::cos(phi), f32::sin(phi));
let p3 = p0.scale_xy(Point2DF32::new(1.0, -1.0));
let p1 = p0 - p3.yx().scale(K);
let p2 = p3 + p0.yx().scale(K);
return Segment::cubic(&LineSegmentF32::new(p3, p0), &LineSegmentF32::new(p2, p1));
const K: f32 = 4.0 / 3.0 * (SQRT_2 - 1.0);
}
#[inline] #[inline]
pub fn as_line_segment(&self) -> LineSegmentF32 { pub fn as_line_segment(&self) -> LineSegmentF32 {
debug_assert!(self.is_line()); debug_assert!(self.is_line());
@ -109,7 +129,7 @@ impl Segment {
let mut new_segment = *self; let mut new_segment = *self;
let p1_2 = self.ctrl.from() + self.ctrl.from(); let p1_2 = self.ctrl.from() + self.ctrl.from();
new_segment.ctrl = new_segment.ctrl =
LineSegmentF32::new(&(self.baseline.from() + p1_2), &(p1_2 + self.baseline.to())) LineSegmentF32::new(self.baseline.from() + p1_2, p1_2 + self.baseline.to())
.scale(1.0 / 3.0); .scale(1.0 / 3.0);
new_segment.kind = SegmentKind::Cubic; new_segment.kind = SegmentKind::Cubic;
new_segment new_segment
@ -176,6 +196,16 @@ impl Segment {
self.to_cubic().as_cubic_segment().sample(t) self.to_cubic().as_cubic_segment().sample(t)
} }
} }
#[inline]
pub fn transform(self, transform: &Transform2DF32) -> Segment {
Segment {
baseline: transform.transform_line_segment(&self.baseline),
ctrl: transform.transform_line_segment(&self.ctrl),
kind: self.kind,
flags: self.flags,
}
}
} }
#[derive(Clone, Copy, Debug, PartialEq)] #[derive(Clone, Copy, Debug, PartialEq)]
@ -215,16 +245,16 @@ impl<'s> CubicSegment<'s> {
let (baseline0, ctrl0, baseline1, ctrl1); let (baseline0, ctrl0, baseline1, ctrl1);
if t <= 0.0 { if t <= 0.0 {
let from = &self.0.baseline.from(); let from = &self.0.baseline.from();
baseline0 = LineSegmentF32::new(from, from); baseline0 = LineSegmentF32::new(*from, *from);
ctrl0 = LineSegmentF32::new(from, from); ctrl0 = LineSegmentF32::new(*from, *from);
baseline1 = self.0.baseline; baseline1 = self.0.baseline;
ctrl1 = self.0.ctrl; ctrl1 = self.0.ctrl;
} else if t >= 1.0 { } else if t >= 1.0 {
let to = &self.0.baseline.to(); let to = &self.0.baseline.to();
baseline0 = self.0.baseline; baseline0 = self.0.baseline;
ctrl0 = self.0.ctrl; ctrl0 = self.0.ctrl;
baseline1 = LineSegmentF32::new(to, to); baseline1 = LineSegmentF32::new(*to, *to);
ctrl1 = LineSegmentF32::new(to, to); ctrl1 = LineSegmentF32::new(*to, *to);
} else { } else {
let tttt = F32x4::splat(t); let tttt = F32x4::splat(t);

View File

@ -118,51 +118,51 @@ impl Offset for Segment {
} }
if self.is_quadratic() { if self.is_quadratic() {
let mut segment_0 = LineSegmentF32::new(&self.baseline.from(), &self.ctrl.from()); let mut segment_0 = LineSegmentF32::new(self.baseline.from(), self.ctrl.from());
let mut segment_1 = LineSegmentF32::new(&self.ctrl.from(), &self.baseline.to()); let mut segment_1 = LineSegmentF32::new(self.ctrl.from(), self.baseline.to());
segment_0 = segment_0.offset(distance); segment_0 = segment_0.offset(distance);
segment_1 = segment_1.offset(distance); segment_1 = segment_1.offset(distance);
let ctrl = match segment_0.intersection_t(&segment_1) { let ctrl = match segment_0.intersection_t(&segment_1) {
Some(t) => segment_0.sample(t), Some(t) => segment_0.sample(t),
None => segment_0.to().lerp(segment_1.from(), 0.5), None => segment_0.to().lerp(segment_1.from(), 0.5),
}; };
let baseline = LineSegmentF32::new(&segment_0.from(), &segment_1.to()); let baseline = LineSegmentF32::new(segment_0.from(), segment_1.to());
return Segment::quadratic(&baseline, &ctrl); return Segment::quadratic(&baseline, ctrl);
} }
debug_assert!(self.is_cubic()); debug_assert!(self.is_cubic());
if self.baseline.from() == self.ctrl.from() { if self.baseline.from() == self.ctrl.from() {
let mut segment_0 = LineSegmentF32::new(&self.baseline.from(), &self.ctrl.to()); let mut segment_0 = LineSegmentF32::new(self.baseline.from(), self.ctrl.to());
let mut segment_1 = LineSegmentF32::new(&self.ctrl.to(), &self.baseline.to()); let mut segment_1 = LineSegmentF32::new(self.ctrl.to(), self.baseline.to());
segment_0 = segment_0.offset(distance); segment_0 = segment_0.offset(distance);
segment_1 = segment_1.offset(distance); segment_1 = segment_1.offset(distance);
let ctrl = match segment_0.intersection_t(&segment_1) { let ctrl = match segment_0.intersection_t(&segment_1) {
Some(t) => segment_0.sample(t), Some(t) => segment_0.sample(t),
None => segment_0.to().lerp(segment_1.from(), 0.5), None => segment_0.to().lerp(segment_1.from(), 0.5),
}; };
let baseline = LineSegmentF32::new(&segment_0.from(), &segment_1.to()); let baseline = LineSegmentF32::new(segment_0.from(), segment_1.to());
let ctrl = LineSegmentF32::new(&segment_0.from(), &ctrl); let ctrl = LineSegmentF32::new(segment_0.from(), ctrl);
return Segment::cubic(&baseline, &ctrl); return Segment::cubic(&baseline, &ctrl);
} }
if self.ctrl.to() == self.baseline.to() { if self.ctrl.to() == self.baseline.to() {
let mut segment_0 = LineSegmentF32::new(&self.baseline.from(), &self.ctrl.from()); let mut segment_0 = LineSegmentF32::new(self.baseline.from(), self.ctrl.from());
let mut segment_1 = LineSegmentF32::new(&self.ctrl.from(), &self.baseline.to()); let mut segment_1 = LineSegmentF32::new(self.ctrl.from(), self.baseline.to());
segment_0 = segment_0.offset(distance); segment_0 = segment_0.offset(distance);
segment_1 = segment_1.offset(distance); segment_1 = segment_1.offset(distance);
let ctrl = match segment_0.intersection_t(&segment_1) { let ctrl = match segment_0.intersection_t(&segment_1) {
Some(t) => segment_0.sample(t), Some(t) => segment_0.sample(t),
None => segment_0.to().lerp(segment_1.from(), 0.5), None => segment_0.to().lerp(segment_1.from(), 0.5),
}; };
let baseline = LineSegmentF32::new(&segment_0.from(), &segment_1.to()); let baseline = LineSegmentF32::new(segment_0.from(), segment_1.to());
let ctrl = LineSegmentF32::new(&ctrl, &segment_1.to()); let ctrl = LineSegmentF32::new(ctrl, segment_1.to());
return Segment::cubic(&baseline, &ctrl); return Segment::cubic(&baseline, &ctrl);
} }
let mut segment_0 = LineSegmentF32::new(&self.baseline.from(), &self.ctrl.from()); let mut segment_0 = LineSegmentF32::new(self.baseline.from(), self.ctrl.from());
let mut segment_1 = LineSegmentF32::new(&self.ctrl.from(), &self.ctrl.to()); let mut segment_1 = LineSegmentF32::new(self.ctrl.from(), self.ctrl.to());
let mut segment_2 = LineSegmentF32::new(&self.ctrl.to(), &self.baseline.to()); let mut segment_2 = LineSegmentF32::new(self.ctrl.to(), self.baseline.to());
segment_0 = segment_0.offset(distance); segment_0 = segment_0.offset(distance);
segment_1 = segment_1.offset(distance); segment_1 = segment_1.offset(distance);
segment_2 = segment_2.offset(distance); segment_2 = segment_2.offset(distance);
@ -176,8 +176,8 @@ impl Offset for Segment {
segment_1.to().lerp(segment_2.from(), 0.5), segment_1.to().lerp(segment_2.from(), 0.5),
), ),
}; };
let baseline = LineSegmentF32::new(&segment_0.from(), &segment_2.to()); let baseline = LineSegmentF32::new(segment_0.from(), segment_2.to());
let ctrl = LineSegmentF32::new(&ctrl_0, &ctrl_1); let ctrl = LineSegmentF32::new(ctrl_0, ctrl_1);
Segment::cubic(&baseline, &ctrl) Segment::cubic(&baseline, &ctrl)
} }

View File

@ -236,9 +236,9 @@ impl BuiltObject {
let right = Point2DF32::new(right, tile_origin_y); let right = Point2DF32::new(right, tile_origin_y);
let segment = if winding < 0 { let segment = if winding < 0 {
LineSegmentF32::new(&left, &right) LineSegmentF32::new(left, right)
} else { } else {
LineSegmentF32::new(&right, &left) LineSegmentF32::new(right, left)
}; };
debug!( debug!(
@ -300,14 +300,14 @@ impl BuiltObject {
let point = Point2DF32::new(x, segment.solve_y_for_x(x)); let point = Point2DF32::new(x, segment.solve_y_for_x(x));
if !winding { if !winding {
fill_to = point; fill_to = point;
segment = LineSegmentF32::new(&point, &segment.to()); segment = LineSegmentF32::new(point, segment.to());
} else { } else {
fill_from = point; fill_from = point;
segment = LineSegmentF32::new(&segment.from(), &point); segment = LineSegmentF32::new(segment.from(), point);
} }
} }
let fill_segment = LineSegmentF32::new(&fill_from, &fill_to); let fill_segment = LineSegmentF32::new(fill_from, fill_to);
let fill_tile_coords = Point2DI32::new(subsegment_tile_x, tile_y); let fill_tile_coords = Point2DI32::new(subsegment_tile_x, tile_y);
self.add_fill(builder, &fill_segment, fill_tile_coords); self.add_fill(builder, &fill_segment, fill_tile_coords);
} }

View File

@ -129,7 +129,7 @@ impl Scene {
}; };
if options.subpixel_aa_enabled { if options.subpixel_aa_enabled {
transform = transform transform = transform
.post_mul(&Transform2DF32::from_scale(&Point2DF32::new(3.0, 1.0))) .post_mul(&Transform2DF32::from_scale(Point2DF32::new(3.0, 1.0)))
} }
outline.transform(&transform); outline.transform(&transform);
} }

View File

@ -434,8 +434,7 @@ impl ActiveEdge {
// If necessary, draw initial line. // If necessary, draw initial line.
if self.crossing.y() < segment.baseline.min_y() { if self.crossing.y() < segment.baseline.min_y() {
let first_line_segment = let first_line_segment =
LineSegmentF32::new(&self.crossing, &segment.baseline.upper_point()) LineSegmentF32::new(self.crossing, segment.baseline.upper_point()).orient(winding);
.orient(winding);
if self if self
.process_line_segment(&first_line_segment, builder, built_object, tile_y) .process_line_segment(&first_line_segment, builder, built_object, tile_y)
.is_some() .is_some()

View File

@ -93,7 +93,7 @@ impl SceneExt for Scene {
let scale = style.size / (font.metrics().units_per_em as f32); let scale = style.size / (font.metrics().units_per_em as f32);
let scale = Point2DF32::new(scale, -scale); let scale = Point2DF32::new(scale, -scale);
let transform = let transform =
Transform2DF32::from_scale(&scale).post_mul(transform).post_translate(offset); Transform2DF32::from_scale(scale).post_mul(transform).post_translate(offset);
self.push_glyph(font, self.push_glyph(font,
glyph.glyph_id, glyph.glyph_id,
&transform, &transform,
@ -147,7 +147,7 @@ impl OutlinePathBuilder {
} }
fn convert_point(&self, point: Point2D<f32>) -> Point2DF32 { fn convert_point(&self, point: Point2D<f32>) -> Point2DF32 {
self.transform.transform_point(&Point2DF32::new(point.x, point.y)) self.transform.transform_point(Point2DF32::new(point.x, point.y))
} }
} }