Skip to content

Commit

Permalink
Refactor arc() and ellipse() to use lyon_geom::Arc
Browse files Browse the repository at this point in the history
  • Loading branch information
pylbrecht committed Feb 26, 2020
1 parent 455fb18 commit 86ad6ed
Show file tree
Hide file tree
Showing 21 changed files with 59 additions and 155 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions components/canvas/Cargo.toml
Expand Up @@ -30,6 +30,7 @@ gleam = "0.6.7"
half = "1"
ipc-channel = "0.12"
log = "0.4"
lyon_geom = "0.14"
num-traits = "0.2"
raqote = {git = "https://github.com/jrmuizel/raqote", optional = true}
pixels = {path = "../pixels"}
Expand Down
139 changes: 57 additions & 82 deletions components/canvas/raqote_backend.rs
Expand Up @@ -12,8 +12,9 @@ use crate::canvas_paint_thread::AntialiasMode;
use canvas_traits::canvas::*;
use cssparser::RGBA;
use euclid::default::{Point2D, Rect, Size2D, Transform2D, Vector2D};
use euclid::Angle;
use lyon_geom::Arc;
use raqote::PathOp;
use std::f32::consts::PI;
use std::marker::PhantomData;

pub struct RaqoteBackend;
Expand Down Expand Up @@ -684,25 +685,19 @@ impl GenericPathBuilder for PathBuilder {
&mut self,
origin: Point2D<f32>,
radius: f32,
mut start_angle: f32,
mut end_angle: f32,
start_angle: f32,
end_angle: f32,
anticlockwise: bool,
) {
if (!anticlockwise && start_angle > end_angle + 2. * PI) ||
(anticlockwise && end_angle > start_angle + 2. * PI)
{
start_angle = start_angle % (2. * PI);
end_angle = end_angle % (2. * PI);
}

if (anticlockwise && end_angle > 0.) || (!anticlockwise && end_angle < 0.) {
end_angle = -end_angle;
}

self.0
.as_mut()
.unwrap()
.arc(origin.x, origin.y, radius, start_angle, end_angle);
self.ellipse(
origin,
radius,
radius,
0.,
start_angle,
end_angle,
anticlockwise,
);
}
fn bezier_curve_to(
&mut self,
Expand All @@ -727,77 +722,57 @@ impl GenericPathBuilder for PathBuilder {
origin: Point2D<f32>,
radius_x: f32,
radius_y: f32,
_rotation_angle: f32,
rotation_angle: f32,
start_angle: f32,
mut end_angle: f32,
end_angle: f32,
anticlockwise: bool,
) {
let start_point = Point2D::new(
origin.x + start_angle.cos() * radius_x,
origin.y + end_angle.sin() * radius_y,
);
self.line_to(start_point);

if !anticlockwise && (end_angle < start_angle) {
let correction = ((start_angle - end_angle) / (2.0 * PI)).ceil();
end_angle += correction * 2.0 * PI;
} else if anticlockwise && (start_angle < end_angle) {
let correction = ((end_angle - start_angle) / (2.0 * PI)).ceil();
end_angle += correction * 2.0 * PI;
}
// Sweeping more than 2 * pi is a full circle.
if !anticlockwise && (end_angle - start_angle > 2.0 * PI) {
end_angle = start_angle + 2.0 * PI;
} else if anticlockwise && (start_angle - end_angle > 2.0 * PI) {
end_angle = start_angle - 2.0 * PI;
let mut start = Angle::radians(start_angle);
let mut end = Angle::radians(end_angle);

// Wrap angles mod 2 * PI if necessary
if !anticlockwise && start > end + Angle::two_pi() ||
anticlockwise && end > start + Angle::two_pi()
{
start = start.positive();
end = end.positive();
}

// Calculate the total arc we're going to sweep.
let mut arc_sweep_left = (end_angle - start_angle).abs();
let sweep_direction = match anticlockwise {
true => -1.0,
false => 1.0,
let sweep = match anticlockwise {
true => {
if end - start == Angle::two_pi() {
-Angle::two_pi()
} else if end > start {
-(Angle::two_pi() - (end - start))
} else {
-(start - end)
}
},
false => {
if start - end == Angle::two_pi() {
Angle::two_pi()
} else if start > end {
Angle::two_pi() - (start - end)
} else {
end - start
}
},
};
let mut current_start_angle = start_angle;
while arc_sweep_left > 0.0 {
// We guarantee here the current point is the start point of the next
// curve segment.
let current_end_angle;
if arc_sweep_left > PI / 2.0 {
current_end_angle = current_start_angle + PI / 2.0 * sweep_direction;
} else {
current_end_angle = current_start_angle + arc_sweep_left * sweep_direction;
}
let current_start_point = Point2D::new(
origin.x + current_start_angle.cos() * radius_x,
origin.y + current_start_angle.sin() * radius_y,
);
let current_end_point = Point2D::new(
origin.x + current_end_angle.cos() * radius_x,
origin.y + current_end_angle.sin() * radius_y,
);
// Calculate kappa constant for partial curve. The sign of angle in the
// tangent will actually ensure this is negative for a counter clockwise
// sweep, so changing signs later isn't needed.
let kappa_factor =
(4.0 / 3.0) * ((current_end_angle - current_start_angle) / 4.0).tan();
let kappa_x = kappa_factor * radius_x;
let kappa_y = kappa_factor * radius_y;

let tangent_start =
Point2D::new(-(current_start_angle.sin()), current_start_angle.cos());
let mut cp1 = current_start_point;
cp1 += Point2D::new(tangent_start.x * kappa_x, tangent_start.y * kappa_y).to_vector();
let rev_tangent_end = Point2D::new(current_end_angle.sin(), -(current_end_angle.cos()));
let mut cp2 = current_end_point;
cp2 +=
Point2D::new(rev_tangent_end.x * kappa_x, rev_tangent_end.y * kappa_y).to_vector();

self.bezier_curve_to(&cp1, &cp2, &current_end_point);

arc_sweep_left -= PI / 2.0;
current_start_angle = current_end_angle;
}

let arc: Arc<f32> = Arc {
center: origin,
radii: Vector2D::new(radius_x, radius_y),
start_angle: start,
sweep_angle: sweep,
x_rotation: Angle::radians(rotation_angle),
};

self.line_to(arc.from());

arc.for_each_quadratic_bezier(&mut |q| {
self.quadratic_curve_to(&q.ctrl, &q.to);
});
}

fn get_current_point(&mut self) -> Option<Point2D<f32>> {
Expand Down

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

0 comments on commit 86ad6ed

Please sign in to comment.