diff --git a/crates/engine/src/tests.rs b/crates/engine/src/tests.rs
index ab539561..2a374503 100644
--- a/crates/engine/src/tests.rs
+++ b/crates/engine/src/tests.rs
@@ -2923,7 +2923,6 @@ fn a_pattern_of_a_reduced_fillet_rounds_each_copy_alike() {
/// half-round front R 4.6 tangent to them) grows by d = z · tan 5° with mitred corners:
/// A(d) = A₀ + P·d + (2 + π/2)·d², integrated over the 10 mm height.
#[test]
-#[ignore = "fails until #546 is fixed"]
fn tapered_extrude_of_a_profile_mixing_lines_and_an_arc() {
let mut s = Session::default();
run(&mut s, "sketch.create", json!({"plane": "XY", "name": "D"}));
diff --git a/crates/kernel/src/build.rs b/crates/kernel/src/build.rs
index 2eaa52f1..b69f6579 100644
--- a/crates/kernel/src/build.rs
+++ b/crates/kernel/src/build.rs
@@ -494,7 +494,8 @@ pub fn torus(center: Vec3, major: f64, minor: f64) -> Result
{
}
/// Offset every segment of a loop to its right by `d` (outward for a region's outer loop and
-/// holes alike). Loops of lines (mitred corners) and loops of arcs on one circle are supported.
+/// holes alike). Loops of lines (mitred corners), loops of arcs on one circle, and loops of lines
+/// and arcs that meet the arcs tangentially are supported.
fn offset_loop(lp: &Loop2, d: f64) -> Result {
if d == 0.0 {
return Ok(lp.clone());
@@ -518,6 +519,9 @@ fn offset_loop(lp: &Loop2, d: f64) -> Result {
.collect::>>()?;
return Ok(Loop2 { segs });
}
+ if lp.segs.iter().any(|s| matches!(s, Seg2::Arc { .. })) {
+ return offset_lines_and_arcs(lp, d);
+ }
let n = lp.segs.len();
let mut lines: Vec<(Vec2, Vec2)> = Vec::with_capacity(n);
for s in &lp.segs {
@@ -544,6 +548,75 @@ fn offset_loop(lp: &Loop2, d: f64) -> Result {
Ok(out)
}
+/// [`offset_loop`] for a loop of lines and arcs. Each arc keeps its centre and angles and its
+/// radius moves by `d` (so its side stays an exact cone), each line moves `d` to its right, and
+/// two lines meeting at a corner are mitred. An arc has to meet its neighbours tangentially: at
+/// a corner its side would meet the next one along a conic, not a straight ruling.
+fn offset_lines_and_arcs(lp: &Loop2, d: f64) -> Result {
+ let closes = || KernelError::Invalid("the taper closes the profile".into());
+ let right = |v: Vec2| Vec2::new(v.y, -v.x);
+ let n = lp.segs.len();
+ let moved: Vec