Fix drawing of full circles

This commit is contained in:
Patrick Walton 2019-05-30 10:56:19 -07:00
parent d5ba6ab6da
commit ce127caf76
1 changed files with 33 additions and 13 deletions

View File

@ -369,25 +369,22 @@ impl Contour {
}
pub fn push_arc(&mut self, center: Point2DF, radius: f32, start_angle: f32, end_angle: f32) {
if end_angle - start_angle >= PI * 2.0 {
return self.push_circle(center, radius);
}
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 chord = LineSegmentF::new(start, end).scale(radius).translate(center);
let full_circle = end_angle - start_angle >= PI * 2.0;
self.push_arc_from_chord_full(radius, chord, full_circle);
self.push_arc_from_chord(radius, chord);
}
#[inline]
pub fn push_arc_from_chord(&mut self, radius: f32, chord: LineSegmentF) {
self.push_arc_from_chord_full(radius, chord, false);
}
fn push_arc_from_chord_full(&mut self,
radius: f32,
mut chord: LineSegmentF,
full_circle: bool) {
pub fn push_arc_from_chord(&mut self, radius: f32, mut chord: LineSegmentF) {
let chord_length = chord.vector().length();
let radius_minus_sagitta_sq = radius * radius - 0.25 * chord_length * chord_length;
let radius_minus_sagitta = f32::sqrt(f32::max(0.0, radius_minus_sagitta_sq));
let scale_factor = radius_minus_sagitta / chord_length;
let center = chord.midpoint() + chord.vector().yx().scale_xy(Point2DF::new(-scale_factor,
scale_factor));
@ -401,12 +398,12 @@ impl Contour {
let mut first_segment = true;
loop {
let mut sweep_vector = end_vector.rev_rotate_by(vector);
let last = !(full_circle && first_segment) &&
sweep_vector.0.x() >= -EPSILON && sweep_vector.0.y() >= -EPSILON;
let last = sweep_vector.0.x() >= -EPSILON && sweep_vector.0.y() >= -EPSILON;
if !last {
sweep_vector = UnitVector(Point2DF::new(0.0, 1.0));
}
// TODO(pcwalton): Cache 90 degree arc segments so we aren't calling this all the time.
let mut segment = Segment::arc_from_cos(sweep_vector.0.x());
let rotation =
Transform2DF::from_rotation_vector(sweep_vector.halve_angle().rotate_by(vector));
@ -429,6 +426,29 @@ impl Contour {
const EPSILON: f32 = 0.001;
}
fn push_circle(&mut self, center: Point2DF, radius: f32) {
let scale = Transform2DF::from_scale(Point2DF::splat(radius));
let translation = Transform2DF::from_translation(center);
let rotations = [
Transform2DF::default(),
Transform2DF::from_rotation_vector(UnitVector(Point2DF::new( 0.0, 1.0))),
Transform2DF::from_rotation_vector(UnitVector(Point2DF::new(-1.0, 0.0))),
Transform2DF::from_rotation_vector(UnitVector(Point2DF::new( 0.0, -1.0))),
];
let base_segment = Segment::arc_from_cos(0.0);
for (rotation_index, rotation) in rotations.iter().enumerate() {
let segment = base_segment.transform(&scale.post_mul(rotation).post_mul(&translation));
if rotation_index == 0 {
self.push_full_segment(&segment, true);
} else {
self.push_segment(segment, true);
}
}
}
#[inline]
pub fn segment_after(&self, point_index: u32) -> Segment {
debug_assert!(self.point_is_endpoint(point_index));