Dächer anwählbar + editierbar + löschbar
Platzierte Dächer sind jetzt vollwertige Auswahl-Elemente (analog Decke): - 2D-Auswahl per Klick: unsichtbares Traufe-Pick-Polygon (roofId) + pickRoof (Punkt-in-Polygon, niedrigste Priorität) in PlanView. - Auswahl-Kanal selectedRoofIds (selectionSlice), updateRoof (projectSlice), RoofInfo + roofSelection + deriveSelection-Dispatch (selectionInfo). - Attribut-Panel „Dach": Form (Sattel/Walm/Pult/Mansarde/Zelt/Flach), Firstrichtung X/Y, Neigung(en), Überstand, Dachdicke — live editierbar über host.onSetRoofPatch; dazu abgeleitete Firsthöhe + Grundfläche (read-only). - Löschen (Delete) + Abwählen bei Geschosswechsel/Marquee/anderer Auswahl. +2 Tests (Roof-Selection). tsc + vitest 642 + vite build grün.
This commit is contained in:
+27
-1
@@ -192,6 +192,11 @@ export interface PlanSelection {
|
||||
* traf und KEIN Element höherer Priorität (Öffnung/Wand); sonst `null`.
|
||||
*/
|
||||
columnId: string | null;
|
||||
/**
|
||||
* ID des getroffenen Dachs (Traufe-Fläche), wenn der Klick es traf und KEIN
|
||||
* Element höherer Priorität (alle anderen gehen vor); sonst `null`.
|
||||
*/
|
||||
roofId: string | null;
|
||||
/**
|
||||
* War beim Klick Shift gedrückt? Dann ERWEITERT der Aufrufer (App) die
|
||||
* Auswahl um das getroffene Element (bzw. schaltet es ab/zu), statt sie zu
|
||||
@@ -985,6 +990,20 @@ export const PlanView = forwardRef<PlanViewHandle, PlanViewProps>(
|
||||
return null;
|
||||
};
|
||||
|
||||
// Getroffenes Dach: das unsichtbare Traufe-Pick-Polygon per Punkt-in-Polygon
|
||||
// (die sichtbaren Dachlinien allein wären schwer exakt zu treffen).
|
||||
const pickRoof = (clientX: number, clientY: number): string | null => {
|
||||
const v = clientToView(clientX, clientY, view);
|
||||
const m = viewToModel(v.x, v.y);
|
||||
for (let i = plan.primitives.length - 1; i >= 0; i--) {
|
||||
const p = plan.primitives[i];
|
||||
if (p.kind === "polygon" && p.roofId && pointInPolygon(m, p.pts)) {
|
||||
return p.roofId;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
// Getroffener extrudierter Körper (truck-Integration): der Footprint-Umriss
|
||||
// ist ein reiner Haarlinien-Umriss (fill:"none"), aber per Punkt-in-Polygon
|
||||
// trotzdem als FLÄCHE anklickbar (analog Raum, nicht nur auf der Linie).
|
||||
@@ -1536,11 +1555,17 @@ export const PlanView = forwardRef<PlanViewHandle, PlanViewProps>(
|
||||
openingId || wallId || columnId || drawingId || extrudedSolidId || ceilingId
|
||||
? null
|
||||
: pickStair(e.clientX, e.clientY);
|
||||
// Raum als letzte Priorität: die Raum-Fläche liegt UNTER allem anderen.
|
||||
// Raum als vorletzte Priorität: die Raum-Fläche liegt UNTER allem anderen.
|
||||
const roomId =
|
||||
openingId || wallId || columnId || drawingId || extrudedSolidId || ceilingId || stairId
|
||||
? null
|
||||
: pickRoom(e.clientX, e.clientY);
|
||||
// Dach als LETZTE Priorität: die Traufe-Fläche deckt den ganzen Grundriss
|
||||
// ab, daher erst wählen, wenn wirklich nichts anderes getroffen wurde.
|
||||
const roofId =
|
||||
openingId || wallId || columnId || drawingId || extrudedSolidId || ceilingId || stairId || roomId
|
||||
? null
|
||||
: pickRoof(e.clientX, e.clientY);
|
||||
onSelect({
|
||||
model: viewToModel(v.x, v.y),
|
||||
hitIndex,
|
||||
@@ -1552,6 +1577,7 @@ export const PlanView = forwardRef<PlanViewHandle, PlanViewProps>(
|
||||
roomId,
|
||||
extrudedSolidId,
|
||||
columnId,
|
||||
roofId,
|
||||
shift: e.shiftKey,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -258,6 +258,8 @@ export type Primitive =
|
||||
* (Poché) einer Stütze ist (für die Links-Klick-Auswahl der Fläche).
|
||||
*/
|
||||
columnId?: string;
|
||||
/** ID des Dachs (Roof), falls dieses (unsichtbare) Polygon der Traufe-Umriss ist (Auswahl). */
|
||||
roofId?: string;
|
||||
}
|
||||
| {
|
||||
kind: "line";
|
||||
@@ -2466,6 +2468,23 @@ function addRoof(
|
||||
const stroke = roof.color ?? category?.color ?? POCHE_STROKE;
|
||||
const geo = roofGeometry(roof, 0);
|
||||
|
||||
// Unsichtbares Pick-Polygon über der Traufe-Fläche — macht das Dach über die
|
||||
// ganze Fläche per Links-Klick selektierbar (die Dachlinien allein wären
|
||||
// schwer exakt zu treffen). fill/stroke "none" ⇒ zeichnet nichts; PlanView
|
||||
// testet nur die `pts` (Punkt-in-Polygon), analog Öffnung/Decke.
|
||||
if (geo.eaves.length >= 3) {
|
||||
out.push({
|
||||
kind: "polygon",
|
||||
pts: geo.eaves,
|
||||
fill: "none",
|
||||
stroke: "none",
|
||||
strokeWidthMm: 0,
|
||||
hatch: NO_HATCH,
|
||||
greyed,
|
||||
roofId: roof.id,
|
||||
});
|
||||
}
|
||||
|
||||
const n = geo.eaves.length;
|
||||
for (let i = 0; i < n; i++) {
|
||||
out.push({
|
||||
|
||||
Reference in New Issue
Block a user