From d9cbf2cb0716c46df531b8849018992e0ea378d7 Mon Sep 17 00:00:00 2001 From: Karim Date: Fri, 21 Aug 2026 20:37:15 +0200 Subject: [PATCH] =?UTF-8?q?2D:=20Tab-Feld-Controller=20f=C3=BCr=20Kreis/Bo?= =?UTF-8?q?gen-Griffe=20repariert=20(Radius/Winkel=20tippbar)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Nutzer-Report: Editieren bestehender Linien/Kreise fühlt sich noch eingeschränkt an, man sollte einen Wert eingeben können. Root Cause bei Kreis/Bogen: cycleGripEditField() ermittelt den Anker für die Tab-Feld-Eingabe (Länge/Winkel) über eine Polylinien-Heuristik ("Nachbar- Griff im Array") — für den Kreis-Radius-Griff (nur 1 Griff, kein Nachbar) gab das GAR KEINEN Anker, Tab tat nichts. Beim Bogen (3 Griffe) fand die Heuristik zwar irgendeinen Nachbar-Griff als Anker, aber semantisch falsch — moveGrip() misst dort tatsächlich Winkel/Radius relativ zum ZENTRUM, nicht relativ zum jeweils anderen Griff. Fix: cycleGripEditField() erkennt jetzt Kreis/Bogen (selectedDrawing.geom) und nimmt deren `center` als Anker — "Länge" tippen setzt damit exakt den Radius, konsistent mit moveGrip()s eigener Distanz-vom-Zentrum-Logik. tsc -b / vitest run (919/919) / npm run build grün. Keine Unit-Tests ergänzt (useGripEditing ist ein React-Hook ohne renderHook-Infrastruktur im Projekt — bestehende Testgrenze, s. andere Hooks). Nutzer prüft in der laufenden App. --- src/state/useGripEditing.ts | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/state/useGripEditing.ts b/src/state/useGripEditing.ts index c19373b..08a5c45 100644 --- a/src/state/useGripEditing.ts +++ b/src/state/useGripEditing.ts @@ -363,12 +363,23 @@ export function useGripEditing(opts: { // Stabiler Ref auf cycleGripEditField (der globale Tab-Handler hat leere Deps). const cycleGripEditFieldRef = useRef<() => void>(() => {}); - // Tab im Vertex-Drag: Feld-Controller öffnen/zyklen (length ↔ angle). + // Tab im Vertex-Drag: Feld-Controller öffnen/zyklen (length ↔ angle). Der + // Anker ist normalerweise die BENACHBARTE Ecke (Polylinien-Semantik: Länge/ + // Winkel relativ zum Nachbarpunkt) — bei Kreis/Bogen ist das falsch (deren + // Griffe liegen auf dem Ring, "Länge" muss der RADIUS sein, also relativ + // zum ZENTRUM). Ohne diese Sonderfälle blieb der Kreis-Radius-Griff sogar + // ganz ohne Anker (nur 1 Griff, kein Nachbar) → Tab tat nichts. const cycleGripEditField = () => { const info = gripDragInfoRef.current; if (!info) return; - const refIndex = info.index > 0 ? info.index - 1 : grips.length > 1 ? 1 : -1; - const anchor = refIndex >= 0 ? grips[refIndex] : null; + const g = selectedDrawing?.geom; + const anchor = + g && (g.shape === "circle" || g.shape === "arc") + ? g.center + : (() => { + const refIndex = info.index > 0 ? info.index - 1 : grips.length > 1 ? 1 : -1; + return refIndex >= 0 ? grips[refIndex] : null; + })(); if (!anchor) return; // ohne Anker keine polare Eingabe möglich setGripEdit((prev) => prev