Skip to content

Rebuild ConcaveConvexSlice & BiConvexSlice as single coherent paths (fix artifacts, add pie & full-circle support)#152

Open
postfixNotation wants to merge 3 commits into
KoalaPlot:mainfrom
postfixNotation:bugfix/piechartshapes
Open

Rebuild ConcaveConvexSlice & BiConvexSlice as single coherent paths (fix artifacts, add pie & full-circle support)#152
postfixNotation wants to merge 3 commits into
KoalaPlot:mainfrom
postfixNotation:bugfix/piechartshapes

Conversation

@postfixNotation

Copy link
Copy Markdown
Contributor

Summary

Refactors the convex-capped slice shapes used for donut and pie charts — ConcaveConvexSlice and BiConvexSlice — so that each slice is built as a single, continuous Path instead of several independent subpaths. This removes rendering artifacts that appeared for a number of data configurations (most visibly on BiConvexSlice), simplifies the implementations, and extends the shapes to cover solid pie charts and full-circle slices.

Background / root cause

The previous implementations assembled each slice from multiple addArc / addRect / addPath subpaths. When a Path is filled, every subpath is implicitly closed with a straight chord — and with separate subpaths those chords could cut across the slice interior. Certain sweep angles therefore produced wedge- or blob-shaped fill artifacts, and stroking the outline (e.g. via a border) drew spurious internal edges. The effect was most pronounced on BiConvexSlice.

Changes

ConcaveConvexSlice

  • Rebuilt as one continuous, self-closing contour — outer arc → convex end cap → inner arc (reversed) → concave start cap → close() — chained with arcTo(forceMoveTo = false) so the entire outline is a single subpath.
  • Significantly simpler implementation based on a correct geometric model.
  • Free of the previous fill artifacts.

BiConvexSlice

  • Same single-contour approach, with two convex caps.
  • Full circle (360°): a 360° sweep is degenerate for arcTo/addArc (start and end unit vectors coincide, so no arc is drawn). It is now handled explicitly and rendered as a ring (donut) or disc (pie) via the even-odd fill rule. A small tolerance (360f - 0.01f) also catches sweeps that land just below 360° through float accumulation.
  • Pie mode (innerRadius == 0): the convex caps round the ends of a ring and are undefined without a ring thickness, so a holeless slice now falls back to a plain sector (wedge). This makes the shape usable for solid pie charts as well as donut charts.
  • Thin slices: below the angle at which the two caps meet, the slice transitions smoothly into a shrinking circle, preventing self-overlap.
  • Simplified implementation; artifact-free.

Result

  • A single coherent path per slice — no internal subpath seams.
  • Correct rendering for both fill and stroke (border).
  • Verified artifact-free across the configurations shown below.

Screenshots

Biconvex slices

Drawing mode Current Fixed Latest (pie mode)
Filled TwoSlicesPreview TwoSlicesPreview_No_Pie_Mode TwoSlicesPreview_Pie_Mode
Stroked TwoSlicesStrokedPreview TwoSlicesStrokedPreview_No_Pie_Mode TwoSlicesStrokedPreview_Pie_Mode
Drawing mode Current Fixed Latest (pie mode)
Filled FibonacciSlicesHalvedPreview FibonacciSlicesHalvedPreview_No_Pie_Mode FibonacciSlicesHalvedPreview_Pie_Mode
Stroked FibonacciSlicesHalvedStrokedPreview FibonacciSlicesHalvedStrokedPreview_No_Pie_Mode FibonacciSlicesHalvedStrokedPreview_Pie_Mode

Concave convex slices

Drawing mode Current Fixed/Latest (angular offset removed)
Filled FibonacciSlicesHalvedPreview FibonacciSlicesHalvedPreview
Stroked FibonacciSlicesHalvedStrokedPreview FibonacciSlicesHalvedStrokedPreview

Testing

Validated with Compose @Previews covering: two slices (donut and pie), Fibonacci-distributed slices and the "halved" variant (many adjacent slices), a full circle (360°), a single 350° slice, and a 10° + 350° combination (a thin slice next to a near-full slice) — each filled and stroked.

- significantly simplifying implementation
- correct mental model of aforementioned shape
- free of any artifacts
- shape consists of single coherent path without multiple subpaths as in previous implementation
- Fix rendering artifacts that appeared for certain data configurations, caused by the shape being assembled from multiple subpaths (each implicitly closed on fill)
- Build the slice as one continuous, self-closing path from a correct geometric model
- Render holeRadius = 0 (pie instead of donut) as a plain sector (wedge) instead of the distorted ring slice the cap geometry produced
- Handle the full-circle (360°) sweep explicitly
- Significantly simplify the implementation
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant