summaryrefslogtreecommitdiff
path: root/src/geom/path.rs
diff options
context:
space:
mode:
authorMartin Haug <mhaug@live.de>2022-05-03 11:40:27 +0200
committerMartin Haug <mhaug@live.de>2022-05-03 12:59:41 +0200
commit6a8a0ec6ec8bb8cf346ee0dd2c45ddcfbee7fbe6 (patch)
tree0d8716d2fa0c01a2319bb84be0283253bc6490fe /src/geom/path.rs
parent33213abe7dfcb8d8065faadd2f5b72ec4b718af1 (diff)
Code Review: Heap is Stack. Unsafe is Good.
Spaghetti Code is Style.
Diffstat (limited to 'src/geom/path.rs')
-rw-r--r--src/geom/path.rs45
1 files changed, 45 insertions, 0 deletions
diff --git a/src/geom/path.rs b/src/geom/path.rs
index 836be1b4..721cc20b 100644
--- a/src/geom/path.rs
+++ b/src/geom/path.rs
@@ -71,3 +71,48 @@ impl Path {
self.0.push(PathElement::ClosePath);
}
}
+
+/// Get the control points for a bezier curve that describes a circular arc
+/// of this angle with the given radius.
+pub fn bezier_arc(
+ angle: Angle,
+ radius: Length,
+ rotate: bool,
+ mirror_x: bool,
+ mirror_y: bool,
+) -> [Point; 4] {
+ let end = Point::new(angle.cos() * radius - radius, angle.sin() * radius);
+ let center = Point::new(-radius, Length::zero());
+
+ let mut ts = if mirror_y {
+ Transform::mirror_y()
+ } else {
+ Transform::identity()
+ };
+
+ if mirror_x {
+ ts = ts.pre_concat(Transform::mirror_x());
+ }
+
+ if rotate {
+ ts = ts.pre_concat(Transform::rotate(Angle::deg(90.0)));
+ }
+
+ let a = center * -1.0;
+ let b = end - center;
+
+ let q1 = a.x.to_raw() * a.x.to_raw() + a.y.to_raw() * a.y.to_raw();
+ let q2 = q1 + a.x.to_raw() * b.x.to_raw() + a.y.to_raw() * b.y.to_raw();
+ let k2 = (4.0 / 3.0) * ((2.0 * q1 * q2).sqrt() - q2)
+ / (a.x.to_raw() * b.y.to_raw() - a.y.to_raw() * b.x.to_raw());
+
+ let control_1 = Point::new(center.x + a.x - k2 * a.y, center.y + a.y + k2 * a.x);
+ let control_2 = Point::new(center.x + b.x + k2 * b.y, center.y + b.y - k2 * b.x);
+
+ [
+ Point::zero(),
+ control_1.transform(ts),
+ control_2.transform(ts),
+ end.transform(ts),
+ ]
+}