Skip to content

Commit

Permalink
fix #199 - handle small arcs with rounded corners
Browse files Browse the repository at this point in the history
  • Loading branch information
mbostock committed Dec 20, 2022
1 parent 8fe68eb commit 439713e
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 10 deletions.
26 changes: 16 additions & 10 deletions src/arc.js
Original file line number Diff line number Diff line change
Expand Up @@ -152,16 +152,22 @@ export default function() {
y00 = r0 * sin(a00),
oc;

// Restrict the corner radius according to the sector angle.
if (da < pi && (oc = intersect(x01, y01, x00, y00, x11, y11, x10, y10))) {
var ax = x01 - oc[0],
ay = y01 - oc[1],
bx = x11 - oc[0],
by = y11 - oc[1],
kc = 1 / sin(acos((ax * bx + ay * by) / (sqrt(ax * ax + ay * ay) * sqrt(bx * bx + by * by))) / 2),
lc = sqrt(oc[0] * oc[0] + oc[1] * oc[1]);
rc0 = min(rc, (r0 - lc) / (kc - 1));
rc1 = min(rc, (r1 - lc) / (kc + 1));
// Restrict the corner radius according to the sector angle. If this
// intersection fails, it’s probably because the arc is too small, so
// disable the corner radius entirely.
if (da < pi) {
if (oc = intersect(x01, y01, x00, y00, x11, y11, x10, y10)) {
var ax = x01 - oc[0],
ay = y01 - oc[1],
bx = x11 - oc[0],
by = y11 - oc[1],
kc = 1 / sin(acos((ax * bx + ay * by) / (sqrt(ax * ax + ay * ay) * sqrt(bx * bx + by * by))) / 2),
lc = sqrt(oc[0] * oc[0] + oc[1] * oc[1]);
rc0 = min(rc, (r0 - lc) / (kc - 1));
rc1 = min(rc, (r1 - lc) / (kc + 1));
} else {
rc0 = rc1 = 0;
}
}
}

Expand Down
5 changes: 5 additions & 0 deletions test/arc-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -360,3 +360,8 @@ it("arc().innerRadius(r₀).outerRadius(r₁).startAngle(θ₀).endAngle(θ₁).
const a = arc().innerRadius(10).outerRadius(100).startAngle(0).endAngle(Math.PI / 2).padAngle(0.2).cornerRadius(10);
assertPathEqual(a(), "M9.669396,-88.145811A10,10,0,0,1,21.849183,-97.583878A100,100,0,0,1,97.583878,-21.849183A10,10,0,0,1,88.145811,-9.669396L7.071068,-7.071068Z");
});

it("arc() handles a very small arc with rounded corners", () => {
const a = arc().innerRadius(15).outerRadius(24).padAngle(0).startAngle(1.2 - 1e-8).endAngle(1.2).cornerRadius(4);
assertPathEqual(a(), "M22.369,-8.697L13.981,-5.435Z");
});

0 comments on commit 439713e

Please sign in to comment.