fix: Torte – große Segmente als zwei Teilbögen (A13-T3)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -2,7 +2,8 @@
|
||||
|
||||
Beträge und Anteile bleiben Decimal; nur die Geometrie (Winkel, SVG-
|
||||
Koordinaten im Einheitskreis) rechnet mit float. Start 12 Uhr, im
|
||||
Uhrzeigersinn (SVG-y zeigt nach unten).
|
||||
Uhrzeigersinn (SVG-y zeigt nach unten). Große Segmente (> 50 %) werden als
|
||||
zwei Teilbögen durch Mittelpunkt gezogen, um Rundungsfehler zu vermeiden.
|
||||
"""
|
||||
import math
|
||||
from dataclasses import dataclass
|
||||
@@ -35,8 +36,13 @@ def _point(fraction: float) -> tuple[float, float]:
|
||||
def _arc(start: float, end: float) -> str:
|
||||
x0, y0 = _point(start)
|
||||
x1, y1 = _point(end)
|
||||
large = 1 if end - start > 0.5 else 0
|
||||
return f"M 0 0 L {x0:.4f} {y0:.4f} A 1 1 0 {large} 1 {x1:.4f} {y1:.4f} Z"
|
||||
if end - start > 0.5:
|
||||
# Großes Segment: zwei Teilbögen durch Mittelpunkt, um Rundungsfehler zu vermeiden
|
||||
mid = (start + end) / 2
|
||||
xm, ym = _point(mid)
|
||||
return f"M 0 0 L {x0:.4f} {y0:.4f} A 1 1 0 0 1 {xm:.4f} {ym:.4f} A 1 1 0 0 1 {x1:.4f} {y1:.4f} Z"
|
||||
else:
|
||||
return f"M 0 0 L {x0:.4f} {y0:.4f} A 1 1 0 0 1 {x1:.4f} {y1:.4f} Z"
|
||||
|
||||
|
||||
def pie_slices(values: list[tuple[str, Decimal]], rest: Decimal | None = None,
|
||||
|
||||
@@ -23,10 +23,26 @@ def test_segmente_lueckenlos_und_anteile():
|
||||
assert sl[0].path.startswith("M 0 0 L 0.0000 -1.0000 A 1 1 0 0 1 ")
|
||||
|
||||
|
||||
def test_large_arc_flag():
|
||||
def test_grosses_segment_als_zwei_teilboegen():
|
||||
a, b = pie_slices([("A", D("70")), ("B", D("30"))])
|
||||
assert " A 1 1 0 1 1 " in a.path
|
||||
assert " A 1 1 0 0 1 " in b.path
|
||||
assert a.path.count(" A 1 1 0 0 1 ") == 2
|
||||
assert b.path.count(" A 1 1 0 0 1 ") == 1
|
||||
assert " 0 1 1 " not in a.path
|
||||
|
||||
|
||||
def test_fast_volles_segment_bleibt_sichtbar():
|
||||
gross, klein = pie_slices([("Gross", D("4999.99"))], rest=D("0.01"),
|
||||
rest_label="Frei verfügbar")
|
||||
# Zwei Teilbögen: der Zwischenpunkt liegt gegenüber (unten), der Bogen
|
||||
# kann also nie zu einem Punkt zusammenfallen.
|
||||
assert gross.path.count(" A 1 1 0 0 1 ") == 2
|
||||
assert " A 1 1 0 0 1 0.0000 1.0000 " in gross.path or " A 1 1 0 0 1 -0.0000 1.0000 " in gross.path
|
||||
assert klein.path is not None
|
||||
|
||||
|
||||
def test_letztes_segment_schliesst_bei_zwoelf_uhr():
|
||||
sl = pie_slices([("A", D("50")), ("B", D("30")), ("C", D("20"))])
|
||||
assert sl[-1].path.endswith(" 0.0000 -1.0000 Z") or sl[-1].path.endswith(" -0.0000 -1.0000 Z")
|
||||
|
||||
|
||||
def test_einzelsegment_ist_vollkreis():
|
||||
|
||||
Reference in New Issue
Block a user