Add support for counterclockwise winding to arcs
This commit is contained in:
parent
99c1cca05c
commit
678b6f12c7
|
@ -19,7 +19,7 @@ use pathfinder_geometry::basic::point::Point2DF;
|
||||||
use pathfinder_geometry::basic::rect::RectF;
|
use pathfinder_geometry::basic::rect::RectF;
|
||||||
use pathfinder_geometry::basic::transform2d::Transform2DF;
|
use pathfinder_geometry::basic::transform2d::Transform2DF;
|
||||||
use pathfinder_geometry::color::ColorU;
|
use pathfinder_geometry::color::ColorU;
|
||||||
use pathfinder_geometry::outline::{Contour, Outline};
|
use pathfinder_geometry::outline::{ArcDirection, Contour, Outline};
|
||||||
use pathfinder_geometry::stroke::{LineCap, LineJoin as StrokeLineJoin};
|
use pathfinder_geometry::stroke::{LineCap, LineJoin as StrokeLineJoin};
|
||||||
use pathfinder_geometry::stroke::{OutlineStrokeToFill, StrokeStyle};
|
use pathfinder_geometry::stroke::{OutlineStrokeToFill, StrokeStyle};
|
||||||
use pathfinder_renderer::paint::{Paint, PaintId};
|
use pathfinder_renderer::paint::{Paint, PaintId};
|
||||||
|
@ -246,7 +246,7 @@ impl CanvasRenderingContext2D {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct State {
|
struct State {
|
||||||
transform: Transform2DF,
|
transform: Transform2DF,
|
||||||
font_collection: Arc<FontCollection>,
|
font_collection: Arc<FontCollection>,
|
||||||
font_size: f32,
|
font_size: f32,
|
||||||
|
@ -336,10 +336,15 @@ impl Path2D {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn arc(&mut self, center: Point2DF, radius: f32, start_angle: f32, end_angle: f32) {
|
pub fn arc(&mut self,
|
||||||
|
center: Point2DF,
|
||||||
|
radius: f32,
|
||||||
|
start_angle: f32,
|
||||||
|
end_angle: f32,
|
||||||
|
direction: ArcDirection) {
|
||||||
let mut transform = Transform2DF::from_scale(Point2DF::splat(radius));
|
let mut transform = Transform2DF::from_scale(Point2DF::splat(radius));
|
||||||
transform = transform.post_mul(&Transform2DF::from_translation(center));
|
transform = transform.post_mul(&Transform2DF::from_translation(center));
|
||||||
self.current_contour.push_arc(&transform, start_angle, end_angle);
|
self.current_contour.push_arc(&transform, start_angle, end_angle, direction);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -357,7 +362,9 @@ impl Path2D {
|
||||||
|
|
||||||
let chord = LineSegmentF::new(vu0.yx().scale_xy(Point2DF::new(-1.0, 1.0)),
|
let chord = LineSegmentF::new(vu0.yx().scale_xy(Point2DF::new(-1.0, 1.0)),
|
||||||
vu1.yx().scale_xy(Point2DF::new(1.0, -1.0)));
|
vu1.yx().scale_xy(Point2DF::new(1.0, -1.0)));
|
||||||
self.current_contour.push_arc_from_unit_chord(&transform, chord);
|
|
||||||
|
// FIXME(pcwalton): Is clockwise direction correct?
|
||||||
|
self.current_contour.push_arc_from_unit_chord(&transform, chord, ArcDirection::CW);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn rect(&mut self, rect: RectF) {
|
pub fn rect(&mut self, rect: RectF) {
|
||||||
|
@ -380,7 +387,7 @@ impl Path2D {
|
||||||
let mut transform = Transform2DF::from_rotation(rotation);
|
let mut transform = Transform2DF::from_rotation(rotation);
|
||||||
transform = transform.post_mul(&Transform2DF::from_scale(axes));
|
transform = transform.post_mul(&Transform2DF::from_scale(axes));
|
||||||
transform = transform.post_mul(&Transform2DF::from_translation(center));
|
transform = transform.post_mul(&Transform2DF::from_translation(center));
|
||||||
self.current_contour.push_arc(&transform, start_angle, end_angle);
|
self.current_contour.push_arc(&transform, start_angle, end_angle, ArcDirection::CW);
|
||||||
|
|
||||||
if end_angle - start_angle >= 2.0 * PI {
|
if end_angle - start_angle >= 2.0 * PI {
|
||||||
self.current_contour.close();
|
self.current_contour.close();
|
||||||
|
|
|
@ -97,6 +97,11 @@ impl LineSegmentF {
|
||||||
LineSegmentF(self.0 * F32x4::splat(factor))
|
LineSegmentF(self.0 * F32x4::splat(factor))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn scale_xy(&self, factors: Point2DF) -> LineSegmentF {
|
||||||
|
LineSegmentF(self.0 * factors.0.xyxy())
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn split(&self, t: f32) -> (LineSegmentF, LineSegmentF) {
|
pub fn split(&self, t: f32) -> (LineSegmentF, LineSegmentF) {
|
||||||
debug_assert!(t >= 0.0 && t <= 1.0);
|
debug_assert!(t >= 0.0 && t <= 1.0);
|
||||||
|
|
|
@ -352,17 +352,30 @@ 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, transform: &Transform2DF, start_angle: f32, end_angle: f32) {
|
pub fn push_arc(&mut self,
|
||||||
|
transform: &Transform2DF,
|
||||||
|
start_angle: f32,
|
||||||
|
end_angle: f32,
|
||||||
|
direction: ArcDirection) {
|
||||||
if end_angle - start_angle >= PI * 2.0 {
|
if end_angle - start_angle >= PI * 2.0 {
|
||||||
self.push_ellipse(transform);
|
self.push_ellipse(transform);
|
||||||
} else {
|
} else {
|
||||||
let start = Point2DF::new(f32::cos(start_angle), f32::sin(start_angle));
|
let start = Point2DF::new(f32::cos(start_angle), f32::sin(start_angle));
|
||||||
let end = Point2DF::new(f32::cos(end_angle), f32::sin(end_angle));
|
let end = Point2DF::new(f32::cos(end_angle), f32::sin(end_angle));
|
||||||
self.push_arc_from_unit_chord(transform, LineSegmentF::new(start, end));
|
self.push_arc_from_unit_chord(transform, LineSegmentF::new(start, end), direction);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push_arc_from_unit_chord(&mut self, transform: &Transform2DF, chord: LineSegmentF) {
|
pub fn push_arc_from_unit_chord(&mut self,
|
||||||
|
transform: &Transform2DF,
|
||||||
|
mut chord: LineSegmentF,
|
||||||
|
direction: ArcDirection) {
|
||||||
|
let mut direction_transform = Transform2DF::default();
|
||||||
|
if direction == ArcDirection::CCW {
|
||||||
|
chord = chord.scale_xy(Point2DF::new(-1.0, 1.0));
|
||||||
|
direction_transform = Transform2DF::from_scale(Point2DF::new(-1.0, 1.0));
|
||||||
|
}
|
||||||
|
|
||||||
let (mut vector, end_vector) = (UnitVector(chord.from()), UnitVector(chord.to()));
|
let (mut vector, end_vector) = (UnitVector(chord.from()), UnitVector(chord.to()));
|
||||||
let mut first_segment = true;
|
let mut first_segment = true;
|
||||||
|
|
||||||
|
@ -378,9 +391,10 @@ impl Contour {
|
||||||
segment = Segment::arc_from_cos(sweep_vector.0.x());
|
segment = Segment::arc_from_cos(sweep_vector.0.x());
|
||||||
}
|
}
|
||||||
|
|
||||||
let rotation =
|
let half_sweep_vector = sweep_vector.halve_angle();
|
||||||
Transform2DF::from_rotation_vector(sweep_vector.halve_angle().rotate_by(vector));
|
let rotation = Transform2DF::from_rotation_vector(half_sweep_vector.rotate_by(vector));
|
||||||
segment = segment.transform(&rotation.post_mul(&transform));
|
segment = segment.transform(&direction_transform.post_mul(&rotation)
|
||||||
|
.post_mul(&transform));
|
||||||
|
|
||||||
let mut push_segment_flags = PushSegmentFlags::UPDATE_BOUNDS;
|
let mut push_segment_flags = PushSegmentFlags::UPDATE_BOUNDS;
|
||||||
if first_segment {
|
if first_segment {
|
||||||
|
@ -816,6 +830,12 @@ impl<'a> Iterator for ContourIter<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
|
pub enum ArcDirection {
|
||||||
|
CW,
|
||||||
|
CCW,
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn union_rect(bounds: &mut RectF, new_point: Point2DF, first: bool) {
|
pub(crate) fn union_rect(bounds: &mut RectF, new_point: Point2DF, first: bool) {
|
||||||
if first {
|
if first {
|
||||||
|
|
|
@ -14,7 +14,7 @@ use crate::basic::line_segment::LineSegmentF;
|
||||||
use crate::basic::point::Point2DF;
|
use crate::basic::point::Point2DF;
|
||||||
use crate::basic::rect::RectF;
|
use crate::basic::rect::RectF;
|
||||||
use crate::basic::transform2d::Transform2DF;
|
use crate::basic::transform2d::Transform2DF;
|
||||||
use crate::outline::{Contour, Outline, PushSegmentFlags};
|
use crate::outline::{ArcDirection, Contour, Outline, PushSegmentFlags};
|
||||||
use crate::segment::Segment;
|
use crate::segment::Segment;
|
||||||
use std::f32;
|
use std::f32;
|
||||||
|
|
||||||
|
@ -141,7 +141,8 @@ impl<'a> OutlineStrokeToFill<'a> {
|
||||||
let mut transform = Transform2DF::from_scale(scale);
|
let mut transform = Transform2DF::from_scale(scale);
|
||||||
let translation = p1 + offset.scale(width * 0.5);
|
let translation = p1 + offset.scale(width * 0.5);
|
||||||
transform = transform.post_mul(&Transform2DF::from_translation(translation));
|
transform = transform.post_mul(&Transform2DF::from_translation(translation));
|
||||||
contour.push_arc_from_unit_chord(&transform, LineSegmentF::new(-offset, offset));
|
let chord = LineSegmentF::new(-offset, offset);
|
||||||
|
contour.push_arc_from_unit_chord(&transform, chord, ArcDirection::CW);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -377,7 +378,8 @@ impl Contour {
|
||||||
transform = transform.post_mul(&Transform2DF::from_translation(join_point));
|
transform = transform.post_mul(&Transform2DF::from_translation(join_point));
|
||||||
let chord_from = (prev_tangent.to() - join_point).normalize();
|
let chord_from = (prev_tangent.to() - join_point).normalize();
|
||||||
let chord_to = (next_tangent.to() - join_point).normalize();
|
let chord_to = (next_tangent.to() - join_point).normalize();
|
||||||
self.push_arc_from_unit_chord(&transform, LineSegmentF::new(chord_from, chord_to));
|
let chord = LineSegmentF::new(chord_from, chord_to);
|
||||||
|
self.push_arc_from_unit_chord(&transform, chord, ArcDirection::CW);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue