Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 10 additions & 12 deletions crates/geom/src/arc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use num_traits::NumCast;
use crate::scalar::{cast, Float, Scalar};
use crate::segment::Segment;
use crate::{point, vector, Angle, Box2D, Point, Rotation, Transform, Vector};
use crate::{CubicBezierSegment, Line, LineSegment, QuadraticBezierSegment};
use crate::{CubicBezierSegment, LineSegment, QuadraticBezierSegment};

/// An elliptic arc curve segment.
#[derive(Copy, Clone, Debug, PartialEq)]
Expand Down Expand Up @@ -661,6 +661,10 @@ pub struct ArcFlags {
pub sweep: bool,
}

// See "Drawing an elliptical arc using polylines, quadratic or cubic Bézier curves"
// by L. Maisonobe
// https://web.archive.org/web/20210414175418/http://www.spaceroots.org/documents/ellipse/elliptical-arc.pdf

fn arc_to_quadratic_beziers_with_t<S, F>(arc: &Arc<S>, callback: &mut F)
where
S: Scalar,
Expand All @@ -675,6 +679,8 @@ where
let mut t0 = S::ZERO;
let dt = S::ONE / n_steps;

let alpha = Float::tan(step.radians * S::HALF);

let n = cast::<S, i32>(n_steps).unwrap();
for i in 0..n {
let a1 = arc.start_angle + step * cast(i).unwrap();
Expand All @@ -684,15 +690,8 @@ where
let v2 = sample_ellipse(arc.radii, arc.x_rotation, a2).to_vector();
let from = arc.center + v1;
let to = arc.center + v2;
let l1 = Line {
point: from,
vector: arc.tangent_at_angle(a1),
};
let l2 = Line {
point: to,
vector: arc.tangent_at_angle(a2),
};
let ctrl = l2.intersection(&l1).unwrap_or(from);

let ctrl = from + arc.tangent_at_angle(a1) * alpha;

let t1 = if i + 1 == n { S::ONE } else { t0 + dt };

Expand Down Expand Up @@ -721,9 +720,8 @@ where
let from = arc.center + v1;
let to = arc.center + v2;

// From http://www.spaceroots.org/documents/ellipse/elliptical-arc.pdf
// Note that the parameterization used by Arc (see sample_ellipse for
// example) is the same as the eta-parameterization used at the link.
// example) is the same as the eta-parameterization used at paper.
let delta_a = a2 - a1;
let tan_da = Float::tan(delta_a.get() * S::HALF);
let alpha_sqrt = S::sqrt(S::FOUR + S::THREE * tan_da * tan_da);
Expand Down
3 changes: 1 addition & 2 deletions crates/path/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1303,8 +1303,7 @@ impl<Builder: PathBuilder> WithSvg<Builder> {
self.builder.line_to(arc_start, &self.attribute_buffer);
}

arc.cast::<f64>().for_each_quadratic_bezier(&mut |curve| {
let curve = curve.cast::<f32>();
arc.for_each_quadratic_bezier(&mut |curve| {
self.builder
.quadratic_bezier_to(curve.ctrl, curve.to, &self.attribute_buffer);
self.current_position = curve.to;
Expand Down
Loading