Kantenverschieben faengt an aktiven Geometrie-Snaps
Beim Verschieben einer Kante ueber den Dreiecks-Griff wird der Cursor jetzt durch die Snap-Engine (snapFor) gefuehrt: bei einem Geometrie-Snap (Endpunkt/Mittelpunkt/Schnittpunkt) wird der gefangene Punkt statt des rohen Cursors auf die Kanten-Normale projiziert — die Kante rastet an reale Geometrie statt nur ans Raster. Ohne Geometrie-Snap bleibt die bisherige Raster-Rundung. Der freie Delta-Fall bleibt unveraendert.
This commit is contained in:
+24
-9
@@ -1294,10 +1294,17 @@ export default function App() {
|
|||||||
// Cursor-Delta — beide Endpunkte wandern gleich, die geteilten Ecken ziehen
|
// Cursor-Delta — beide Endpunkte wandern gleich, die geteilten Ecken ziehen
|
||||||
// die Nachbar-Segmente nach. Shift = Ortho (H/V) auf das Gesamt-Delta.
|
// die Nachbar-Segmente nach. Shift = Ortho (H/V) auf das Gesamt-Delta.
|
||||||
// • sonst (rect/geschlossene Polylinie/Wand): NUR die Komponente senkrecht
|
// • sonst (rect/geschlossene Polylinie/Wand): NUR die Komponente senkrecht
|
||||||
// zur Kante (Seite verschiebt sich parallel nach außen/innen), aufs Raster
|
// zur Kante (Seite verschiebt sich parallel nach außen/innen). Fängt an
|
||||||
// gerundet — wie bisher.
|
// eingeschalteten Geometrie-Snaps (Endpunkt/Mittelpunkt/Schnittpunkt/…);
|
||||||
onEdgeMove: (edge: EdgeGrip, raw: Vec2, _pxPerMeter: number, mods: ToolMods) => {
|
// ohne Geometrie-Snap wird der Offset wie bisher aufs Raster gerundet.
|
||||||
|
onEdgeMove: (edge: EdgeGrip, raw: Vec2, pxPerMeter: number, mods: ToolMods) => {
|
||||||
if (edge.free) {
|
if (edge.free) {
|
||||||
|
// Freier Fall arbeitet mit einem inkrementellen Cursor-DELTA (nicht
|
||||||
|
// einem absoluten Punkt) — eine Geometrie-Snap-Projektion auf die
|
||||||
|
// Normale ergibt hier keinen Sinn, da es keine feste Kanten-Normale
|
||||||
|
// gibt, an die sich ein gefangener Punkt anlehnen könnte. Bleibt beim
|
||||||
|
// bisherigen Raster-Delta-Verhalten.
|
||||||
|
//
|
||||||
// Inkrementelles 2D-Delta gegen den letzten rohen Cursor. Erster Event
|
// Inkrementelles 2D-Delta gegen den letzten rohen Cursor. Erster Event
|
||||||
// verankert nur (kein Sprung, da der Griff am Kanten-Mittelpunkt sitzt).
|
// verankert nur (kein Sprung, da der Griff am Kanten-Mittelpunkt sitzt).
|
||||||
const last = edgeFreeLastRef.current;
|
const last = edgeFreeLastRef.current;
|
||||||
@@ -1325,13 +1332,21 @@ export default function App() {
|
|||||||
setDraft({ preview: [], vertices: [], snap: null });
|
setDraft({ preview: [], vertices: [], snap: null });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Senkrechte Projektion von (raw − Grab-Mittelpunkt) auf die Außennormale.
|
// Cursor zuerst durch die Snap-Engine schicken (Ctrl unterdrückt Snap
|
||||||
const rel = sub(raw, edge.mid);
|
// wie überall sonst, siehe computeSnap). Ein GEOMETRIE-Snap (Endpunkt/
|
||||||
|
// Mittelpunkt/Schnittpunkt/…, nicht Raster/Ortho) liefert den gefangenen
|
||||||
|
// Punkt, der dann auf die Außennormale projiziert wird — so rastet die
|
||||||
|
// Kante an reale Geometrie statt nur ans Raster.
|
||||||
|
const snapResult = snapFor(raw, pxPerMeter, mods);
|
||||||
|
const isGeometrySnap = !!snapResult && snapResult.kind !== "grid" && snapResult.kind !== "ortho";
|
||||||
|
const cursor = isGeometrySnap ? snapResult!.point : raw;
|
||||||
|
// Senkrechte Projektion von (Cursor − Grab-Mittelpunkt) auf die Außennormale.
|
||||||
|
const rel = sub(cursor, edge.mid);
|
||||||
let offset = rel.x * edge.normal.x + rel.y * edge.normal.y;
|
let offset = rel.x * edge.normal.x + rel.y * edge.normal.y;
|
||||||
// Raster-Schritt (Snap) anwenden, sofern Snap+Raster aktiv und nicht per
|
// Raster-Schritt (Snap) nur, wenn kein Geometrie-Snap gefangen wurde —
|
||||||
// Ctrl unterdrückt sind.
|
// sonst gewinnt der gefangene Punkt.
|
||||||
const step = snap.gridSize;
|
const step = snap.gridSize;
|
||||||
if (!mods.ctrl && snap.enabled && snap.grid && step > 0) {
|
if (!isGeometrySnap && !mods.ctrl && snap.enabled && snap.grid && step > 0) {
|
||||||
offset = Math.round(offset / step) * step;
|
offset = Math.round(offset / step) * step;
|
||||||
}
|
}
|
||||||
// INKREMENTELL + Grab-Anker: moveEdge verschiebt additiv, daher nur die
|
// INKREMENTELL + Grab-Anker: moveEdge verschiebt additiv, daher nur die
|
||||||
@@ -1343,7 +1358,7 @@ export default function App() {
|
|||||||
const inc = offset - prev;
|
const inc = offset - prev;
|
||||||
if (inc === 0) return;
|
if (inc === 0) return;
|
||||||
applyEdge(edge.aIndex, edge.bIndex, scale(edge.normal, inc));
|
applyEdge(edge.aIndex, edge.bIndex, scale(edge.normal, inc));
|
||||||
setDraft({ preview: [], vertices: [], snap: null });
|
setDraft({ preview: [], vertices: [], snap: isGeometrySnap ? snapResult : null });
|
||||||
},
|
},
|
||||||
onGripEnd: () => {
|
onGripEnd: () => {
|
||||||
setDraft(null);
|
setDraft(null);
|
||||||
|
|||||||
Reference in New Issue
Block a user