Skip to content

Commit

Permalink
Add support for counterclockwise winding to arcs
Browse files Browse the repository at this point in the history
  • Loading branch information
pcwalton committed Jun 1, 2019
1 parent 99c1cca commit 678b6f1
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 15 deletions.
19 changes: 13 additions & 6 deletions canvas/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use pathfinder_geometry::basic::point::Point2DF;
use pathfinder_geometry::basic::rect::RectF;
use pathfinder_geometry::basic::transform2d::Transform2DF;
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::{OutlineStrokeToFill, StrokeStyle};
use pathfinder_renderer::paint::{Paint, PaintId};
Expand Down Expand Up @@ -246,7 +246,7 @@ impl CanvasRenderingContext2D {
}

#[derive(Clone)]
pub struct State {
struct State {
transform: Transform2DF,
font_collection: Arc<FontCollection>,
font_size: f32,
Expand Down Expand Up @@ -336,10 +336,15 @@ impl Path2D {
}

#[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));
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]
Expand All @@ -357,7 +362,9 @@ impl Path2D {

let chord = LineSegmentF::new(vu0.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) {
Expand All @@ -380,7 +387,7 @@ impl Path2D {
let mut transform = Transform2DF::from_rotation(rotation);
transform = transform.post_mul(&Transform2DF::from_scale(axes));
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 {
self.current_contour.close();
Expand Down
5 changes: 5 additions & 0 deletions geometry/src/basic/line_segment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,11 @@ impl LineSegmentF {
LineSegmentF(self.0 * F32x4::splat(factor))
}

#[inline]
pub fn scale_xy(&self, factors: Point2DF) -> LineSegmentF {
LineSegmentF(self.0 * factors.0.xyxy())
}

#[inline]
pub fn split(&self, t: f32) -> (LineSegmentF, LineSegmentF) {
debug_assert!(t >= 0.0 && t <= 1.0);
Expand Down
32 changes: 26 additions & 6 deletions geometry/src/outline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -352,17 +352,30 @@ impl Contour {
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 {
self.push_ellipse(transform);
} else {
let start = Point2DF::new(f32::cos(start_angle), f32::sin(start_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 first_segment = true;

Expand All @@ -378,9 +391,10 @@ impl Contour {
segment = Segment::arc_from_cos(sweep_vector.0.x());
}

let rotation =
Transform2DF::from_rotation_vector(sweep_vector.halve_angle().rotate_by(vector));
segment = segment.transform(&rotation.post_mul(&transform));
let half_sweep_vector = sweep_vector.halve_angle();
let rotation = Transform2DF::from_rotation_vector(half_sweep_vector.rotate_by(vector));
segment = segment.transform(&direction_transform.post_mul(&rotation)
.post_mul(&transform));

let mut push_segment_flags = PushSegmentFlags::UPDATE_BOUNDS;
if first_segment {
Expand Down Expand Up @@ -816,6 +830,12 @@ impl<'a> Iterator for ContourIter<'a> {
}
}

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum ArcDirection {
CW,
CCW,
}

#[inline]
pub(crate) fn union_rect(bounds: &mut RectF, new_point: Point2DF, first: bool) {
if first {
Expand Down
8 changes: 5 additions & 3 deletions geometry/src/stroke.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use crate::basic::line_segment::LineSegmentF;
use crate::basic::point::Point2DF;
use crate::basic::rect::RectF;
use crate::basic::transform2d::Transform2DF;
use crate::outline::{Contour, Outline, PushSegmentFlags};
use crate::outline::{ArcDirection, Contour, Outline, PushSegmentFlags};
use crate::segment::Segment;
use std::f32;

Expand Down Expand Up @@ -141,7 +141,8 @@ impl<'a> OutlineStrokeToFill<'a> {
let mut transform = Transform2DF::from_scale(scale);
let translation = p1 + offset.scale(width * 0.5);
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);
}
}
}
Expand Down Expand Up @@ -377,7 +378,8 @@ impl Contour {
transform = transform.post_mul(&Transform2DF::from_translation(join_point));
let chord_from = (prev_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);
}
}
}
Expand Down

0 comments on commit 678b6f1

Please sign in to comment.