Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Detect coincident points when drawing arcs with rounding. #39

Open
wants to merge 4 commits into
base: main
Choose a base branch
from

Conversation

jasondavies
Copy link

When rounding is used, it's possible for arc() to generate empty arcs in the case where the start and end points are almost coincident, and become coincident after rounding is applied.

This adds a check for coincident points after rounding is applied, and splits the arc into two if coincident points are detected.

Fixes #38.

When rounding is used, it's possible for `arc()` to generate empty arcs
in the case where the start and end points are almost coincident, and
become coincident after rounding is applied.

This adds a check for coincident points after rounding is applied, and
splits the arc into two if coincident points are detected.

Fixes d3#38.
src/path.js Outdated Show resolved Hide resolved
Skip unnecessary division for performance. Use `d` rather than `digits` to compute the power of 10.

Co-authored-by: Philippe Rivière <[email protected]>
src/path.js Show resolved Hide resolved
Copy link
Member

@mbostock mbostock left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the fix! And hi Jason! 👋 Two small nits.

src/path.js Outdated Show resolved Hide resolved
src/path.js Outdated Show resolved Hide resolved
- Use pessimistic `!(d <= 15)` check in case of NaN.
- Use `digits == null` check to match previous line.
@jasondavies
Copy link
Author

jasondavies commented Oct 16, 2024

It might also be worth generating a set of visual tests to double-check ccw={true, false} and values of a0, a1 where abs(a1 - a0) is some multiple of 2π, in case there's a faulty assumption with da /= 2.

@jasondavies
Copy link
Author

I think my assumptions are correct. After these lines:

// Does the angle go the wrong way? Flip the direction.
if (da < 0) da = da % tau + tau;

// Is this a complete circle? Draw two arcs to complete the circle.
if (da > tauEpsilon) {
  this._append`A${r},${r},0,1,${cw},${x - dx},${y - dy}A${r},${r},0,1,${cw},${this._x1 = x0},${this._y1 = y0}`;
}

We can be sure that 0 ≤ da ≤ tauEpsilon, hence it's safe to use da /= 2 to determine the midpoint of the arc.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

Near-circular arcs generate empty paths when rounding is used
3 participants