Schnittführungs-Symbol im Grundriss + Schnittlinien-Auswahl
generatePlan zeichnet fuer jede Schnitt-/Ansichtsebene mit linePoints das klassische Symbol: Strichpunkt-Linie, Endmarken + Richtungspfeile (directionSign), Kurz-Label an beiden Enden und ein unsichtbares Pick-Band (Polygon mit sectionLineId). PlanView pickt die Linie (hoechste Prioritaet) und hebt die Auswahl hervor. Neuer Selektionskanal selectedSectionLineId (Einzel-DrawingLevel- Id) in selectionSlice; onPlanSelect + alle Reset-Stellen in App gepflegt. Primitive.sectionLineId, PlanSelection.sectionLineId, Tests.
This commit is contained in:
+41
-1
@@ -581,6 +581,9 @@ export default function App() {
|
|||||||
const selectedRoofIds = useStore((s) => s.selectedRoofIds);
|
const selectedRoofIds = useStore((s) => s.selectedRoofIds);
|
||||||
const setSelectedRoofIds = useStore((s) => s.setSelectedRoofIds);
|
const setSelectedRoofIds = useStore((s) => s.setSelectedRoofIds);
|
||||||
const selectedRoofId = selectedRoofIds.length === 1 ? selectedRoofIds[0] : null;
|
const selectedRoofId = selectedRoofIds.length === 1 ? selectedRoofIds[0] : null;
|
||||||
|
// Schnitt-/Ansichtslinien-Auswahl (Einzel-DrawingLevel-Id oder null).
|
||||||
|
const selectedSectionLineId = useStore((s) => s.selectedSectionLineId);
|
||||||
|
const setSelectedSectionLineId = useStore((s) => s.setSelectedSectionLineId);
|
||||||
const updateRoof = useStore((s) => s.updateRoof);
|
const updateRoof = useStore((s) => s.updateRoof);
|
||||||
const moveRoofGrip = useStore((s) => s.moveRoofGrip);
|
const moveRoofGrip = useStore((s) => s.moveRoofGrip);
|
||||||
const moveRoofBy = useStore((s) => s.moveRoofBy);
|
const moveRoofBy = useStore((s) => s.moveRoofBy);
|
||||||
@@ -634,6 +637,7 @@ export default function App() {
|
|||||||
setSelectedExtrudedSolidIds([]);
|
setSelectedExtrudedSolidIds([]);
|
||||||
setSelectedColumnIds([]);
|
setSelectedColumnIds([]);
|
||||||
setSelectedRoofIds([]);
|
setSelectedRoofIds([]);
|
||||||
|
setSelectedSectionLineId(null);
|
||||||
setMenu(null);
|
setMenu(null);
|
||||||
setEditor(null);
|
setEditor(null);
|
||||||
}, [activeLevelId]);
|
}, [activeLevelId]);
|
||||||
@@ -1897,6 +1901,7 @@ export default function App() {
|
|||||||
setSelectedExtrudedSolidIds([]);
|
setSelectedExtrudedSolidIds([]);
|
||||||
setSelectedColumnIds([]);
|
setSelectedColumnIds([]);
|
||||||
setSelectedRoofIds([]);
|
setSelectedRoofIds([]);
|
||||||
|
setSelectedSectionLineId(null);
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -3474,6 +3479,7 @@ export default function App() {
|
|||||||
setSelectedExtrudedSolidIds([]);
|
setSelectedExtrudedSolidIds([]);
|
||||||
setSelectedColumnIds([]);
|
setSelectedColumnIds([]);
|
||||||
setSelectedRoofIds([]);
|
setSelectedRoofIds([]);
|
||||||
|
setSelectedSectionLineId(null);
|
||||||
switch (kind) {
|
switch (kind) {
|
||||||
case "Wand":
|
case "Wand":
|
||||||
setSelectedWallIds([id]);
|
setSelectedWallIds([id]);
|
||||||
@@ -4333,6 +4339,7 @@ export default function App() {
|
|||||||
setSelectedExtrudedSolidIds([]);
|
setSelectedExtrudedSolidIds([]);
|
||||||
setSelectedColumnIds([]);
|
setSelectedColumnIds([]);
|
||||||
setSelectedRoofIds([]);
|
setSelectedRoofIds([]);
|
||||||
|
setSelectedSectionLineId(null);
|
||||||
setStampEditorRoomId(roomId);
|
setStampEditorRoomId(roomId);
|
||||||
};
|
};
|
||||||
// Doppelklick auf ein Text-2D-Element: selektieren + Inhalts-Editor öffnen.
|
// Doppelklick auf ein Text-2D-Element: selektieren + Inhalts-Editor öffnen.
|
||||||
@@ -4348,6 +4355,7 @@ export default function App() {
|
|||||||
setSelectedExtrudedSolidIds([]);
|
setSelectedExtrudedSolidIds([]);
|
||||||
setSelectedColumnIds([]);
|
setSelectedColumnIds([]);
|
||||||
setSelectedRoofIds([]);
|
setSelectedRoofIds([]);
|
||||||
|
setSelectedSectionLineId(null);
|
||||||
setEditTextId(drawingId);
|
setEditTextId(drawingId);
|
||||||
};
|
};
|
||||||
// Bearbeiteten Text-Inhalt übernehmen (immutabel; nur bei Text-Geometrie).
|
// Bearbeiteten Text-Inhalt übernehmen (immutabel; nur bei Text-Geometrie).
|
||||||
@@ -4372,6 +4380,13 @@ export default function App() {
|
|||||||
// Rest behalten (Wände und 2D-Zeichnungen unabhängig, gemischte Auswahl
|
// Rest behalten (Wände und 2D-Zeichnungen unabhängig, gemischte Auswahl
|
||||||
// erlaubt). Leerraum-Klick mit Shift lässt die Auswahl unverändert.
|
// erlaubt). Leerraum-Klick mit Shift lässt die Auswahl unverändert.
|
||||||
if (sel.shift) {
|
if (sel.shift) {
|
||||||
|
// Schnittlinie ist Einzelauswahl — Shift+Klick togglet sie an/aus.
|
||||||
|
if (sel.sectionLineId) {
|
||||||
|
setSelectedSectionLineId(
|
||||||
|
selectedSectionLineId === sel.sectionLineId ? null : sel.sectionLineId,
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (sel.wallId) {
|
if (sel.wallId) {
|
||||||
const id = sel.wallId;
|
const id = sel.wallId;
|
||||||
setSelectedWallIds(
|
setSelectedWallIds(
|
||||||
@@ -4453,8 +4468,12 @@ export default function App() {
|
|||||||
if (keep !== "extrudedSolid") setSelectedExtrudedSolidIds([]);
|
if (keep !== "extrudedSolid") setSelectedExtrudedSolidIds([]);
|
||||||
if (keep !== "column") setSelectedColumnIds([]);
|
if (keep !== "column") setSelectedColumnIds([]);
|
||||||
if (keep !== "roof") setSelectedRoofIds([]);
|
if (keep !== "roof") setSelectedRoofIds([]);
|
||||||
|
if (keep !== "sectionLine") setSelectedSectionLineId(null);
|
||||||
};
|
};
|
||||||
if (sel.openingId) {
|
if (sel.sectionLineId) {
|
||||||
|
setSelectedSectionLineId(sel.sectionLineId);
|
||||||
|
clearOthers("sectionLine");
|
||||||
|
} else if (sel.openingId) {
|
||||||
setSelectedOpeningIds([sel.openingId]);
|
setSelectedOpeningIds([sel.openingId]);
|
||||||
clearOthers("opening");
|
clearOthers("opening");
|
||||||
} else if (sel.wallId) {
|
} else if (sel.wallId) {
|
||||||
@@ -4499,6 +4518,7 @@ export default function App() {
|
|||||||
setSelectedExtrudedSolidIds([]);
|
setSelectedExtrudedSolidIds([]);
|
||||||
setSelectedColumnIds([]);
|
setSelectedColumnIds([]);
|
||||||
setSelectedRoofIds([]);
|
setSelectedRoofIds([]);
|
||||||
|
setSelectedSectionLineId(null);
|
||||||
};
|
};
|
||||||
// Rechts-Klick im Grundriss: Wand-Kontextmenü. Trifft der Klick eine Wand, die
|
// Rechts-Klick im Grundriss: Wand-Kontextmenü. Trifft der Klick eine Wand, die
|
||||||
// NICHT bereits in der Auswahl ist, wird die Auswahl auf sie gesetzt (damit die
|
// NICHT bereits in der Auswahl ist, wird die Auswahl auf sie gesetzt (damit die
|
||||||
@@ -4525,6 +4545,7 @@ export default function App() {
|
|||||||
setSelectedExtrudedSolidIds([]);
|
setSelectedExtrudedSolidIds([]);
|
||||||
setSelectedColumnIds([]);
|
setSelectedColumnIds([]);
|
||||||
setSelectedRoofIds([]);
|
setSelectedRoofIds([]);
|
||||||
|
setSelectedSectionLineId(null);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
// Links-Klick im 3D: per Raycast getroffene Treppe wählen (Einzelauswahl).
|
// Links-Klick im 3D: per Raycast getroffene Treppe wählen (Einzelauswahl).
|
||||||
@@ -4539,6 +4560,7 @@ export default function App() {
|
|||||||
setSelectedExtrudedSolidIds([]);
|
setSelectedExtrudedSolidIds([]);
|
||||||
setSelectedColumnIds([]);
|
setSelectedColumnIds([]);
|
||||||
setSelectedRoofIds([]);
|
setSelectedRoofIds([]);
|
||||||
|
setSelectedSectionLineId(null);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
// Links-Klick im 3D: per Raycast getroffene Decke wählen (Einzelauswahl).
|
// Links-Klick im 3D: per Raycast getroffene Decke wählen (Einzelauswahl).
|
||||||
@@ -4553,6 +4575,7 @@ export default function App() {
|
|||||||
setSelectedExtrudedSolidIds([]);
|
setSelectedExtrudedSolidIds([]);
|
||||||
setSelectedColumnIds([]);
|
setSelectedColumnIds([]);
|
||||||
setSelectedRoofIds([]);
|
setSelectedRoofIds([]);
|
||||||
|
setSelectedSectionLineId(null);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
// Links-Klick im 3D: per Raycast getroffene Öffnung wählen (Einzelauswahl).
|
// Links-Klick im 3D: per Raycast getroffene Öffnung wählen (Einzelauswahl).
|
||||||
@@ -4567,6 +4590,7 @@ export default function App() {
|
|||||||
setSelectedExtrudedSolidIds([]);
|
setSelectedExtrudedSolidIds([]);
|
||||||
setSelectedColumnIds([]);
|
setSelectedColumnIds([]);
|
||||||
setSelectedRoofIds([]);
|
setSelectedRoofIds([]);
|
||||||
|
setSelectedSectionLineId(null);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
// Links-KLICK im Nordstern-3D-Viewport (WASM, TS-Raycast): getroffenes Bauteil
|
// Links-KLICK im Nordstern-3D-Viewport (WASM, TS-Raycast): getroffenes Bauteil
|
||||||
@@ -4586,6 +4610,7 @@ export default function App() {
|
|||||||
setSelectedExtrudedSolidIds([]);
|
setSelectedExtrudedSolidIds([]);
|
||||||
setSelectedColumnIds([]);
|
setSelectedColumnIds([]);
|
||||||
setSelectedRoofIds([]);
|
setSelectedRoofIds([]);
|
||||||
|
setSelectedSectionLineId(null);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Öffnung (Fenster/Tür) und Treppe sind jetzt auch im WASM-Viewport pickbar
|
// Öffnung (Fenster/Tür) und Treppe sind jetzt auch im WASM-Viewport pickbar
|
||||||
@@ -4601,6 +4626,7 @@ export default function App() {
|
|||||||
setSelectedExtrudedSolidIds([]);
|
setSelectedExtrudedSolidIds([]);
|
||||||
setSelectedColumnIds([]);
|
setSelectedColumnIds([]);
|
||||||
setSelectedRoofIds([]);
|
setSelectedRoofIds([]);
|
||||||
|
setSelectedSectionLineId(null);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (hit.kind === "stair") {
|
if (hit.kind === "stair") {
|
||||||
@@ -4613,6 +4639,7 @@ export default function App() {
|
|||||||
setSelectedExtrudedSolidIds([]);
|
setSelectedExtrudedSolidIds([]);
|
||||||
setSelectedColumnIds([]);
|
setSelectedColumnIds([]);
|
||||||
setSelectedRoofIds([]);
|
setSelectedRoofIds([]);
|
||||||
|
setSelectedSectionLineId(null);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (hit.kind === "roof") {
|
if (hit.kind === "roof") {
|
||||||
@@ -4645,6 +4672,7 @@ export default function App() {
|
|||||||
setSelectedExtrudedSolidIds([]);
|
setSelectedExtrudedSolidIds([]);
|
||||||
setSelectedColumnIds([]);
|
setSelectedColumnIds([]);
|
||||||
setSelectedRoofIds([]);
|
setSelectedRoofIds([]);
|
||||||
|
setSelectedSectionLineId(null);
|
||||||
};
|
};
|
||||||
// Rechts-Klick im 3D: Wand-Kontextmenü an der Cursorposition.
|
// Rechts-Klick im 3D: Wand-Kontextmenü an der Cursorposition.
|
||||||
const onViewportContextMenu = (info: ViewportContextInfo) => {
|
const onViewportContextMenu = (info: ViewportContextInfo) => {
|
||||||
@@ -4930,6 +4958,7 @@ export default function App() {
|
|||||||
selectedColumnIds={selectedColumnIds}
|
selectedColumnIds={selectedColumnIds}
|
||||||
selectedRoomIds={selectedRoomIds}
|
selectedRoomIds={selectedRoomIds}
|
||||||
selectedRoofIds={selectedRoofIds}
|
selectedRoofIds={selectedRoofIds}
|
||||||
|
selectedSectionLineId={selectedSectionLineId}
|
||||||
roomStamp={roomStamp}
|
roomStamp={roomStamp}
|
||||||
onStampMove={moveRoomStamp}
|
onStampMove={moveRoomStamp}
|
||||||
onStampEdit={onOpenStampEditor}
|
onStampEdit={onOpenStampEditor}
|
||||||
@@ -6063,6 +6092,7 @@ function Content({
|
|||||||
selectedColumnIds,
|
selectedColumnIds,
|
||||||
selectedRoomIds,
|
selectedRoomIds,
|
||||||
selectedRoofIds,
|
selectedRoofIds,
|
||||||
|
selectedSectionLineId,
|
||||||
roomStamp,
|
roomStamp,
|
||||||
onStampMove,
|
onStampMove,
|
||||||
onStampEdit,
|
onStampEdit,
|
||||||
@@ -6141,6 +6171,7 @@ function Content({
|
|||||||
selectedColumnIds: string[];
|
selectedColumnIds: string[];
|
||||||
selectedRoomIds: string[];
|
selectedRoomIds: string[];
|
||||||
selectedRoofIds: string[];
|
selectedRoofIds: string[];
|
||||||
|
selectedSectionLineId: string | null;
|
||||||
roomStamp: { roomId: string; anchor: Vec2 } | null;
|
roomStamp: { roomId: string; anchor: Vec2 } | null;
|
||||||
onStampMove: (roomId: string, delta: Vec2) => void;
|
onStampMove: (roomId: string, delta: Vec2) => void;
|
||||||
onStampEdit: (roomId: string) => void;
|
onStampEdit: (roomId: string) => void;
|
||||||
@@ -6258,6 +6289,7 @@ function Content({
|
|||||||
selectedColumnIds={selectedColumnIds}
|
selectedColumnIds={selectedColumnIds}
|
||||||
selectedRoomIds={selectedRoomIds}
|
selectedRoomIds={selectedRoomIds}
|
||||||
selectedRoofIds={selectedRoofIds}
|
selectedRoofIds={selectedRoofIds}
|
||||||
|
selectedSectionLineId={selectedSectionLineId}
|
||||||
roomStamp={roomStamp}
|
roomStamp={roomStamp}
|
||||||
onStampMove={onStampMove}
|
onStampMove={onStampMove}
|
||||||
onStampEdit={onStampEdit}
|
onStampEdit={onStampEdit}
|
||||||
@@ -6313,6 +6345,7 @@ function Content({
|
|||||||
selectedColumnIds={selectedColumnIds}
|
selectedColumnIds={selectedColumnIds}
|
||||||
selectedRoomIds={selectedRoomIds}
|
selectedRoomIds={selectedRoomIds}
|
||||||
selectedRoofIds={selectedRoofIds}
|
selectedRoofIds={selectedRoofIds}
|
||||||
|
selectedSectionLineId={selectedSectionLineId}
|
||||||
roomStamp={roomStamp}
|
roomStamp={roomStamp}
|
||||||
onStampMove={onStampMove}
|
onStampMove={onStampMove}
|
||||||
onStampEdit={onStampEdit}
|
onStampEdit={onStampEdit}
|
||||||
@@ -6408,6 +6441,7 @@ function Content({
|
|||||||
selectedColumnIds={selectedColumnIds}
|
selectedColumnIds={selectedColumnIds}
|
||||||
selectedRoomIds={selectedRoomIds}
|
selectedRoomIds={selectedRoomIds}
|
||||||
selectedRoofIds={selectedRoofIds}
|
selectedRoofIds={selectedRoofIds}
|
||||||
|
selectedSectionLineId={selectedSectionLineId}
|
||||||
roomStamp={roomStamp}
|
roomStamp={roomStamp}
|
||||||
onStampMove={onStampMove}
|
onStampMove={onStampMove}
|
||||||
onStampEdit={onStampEdit}
|
onStampEdit={onStampEdit}
|
||||||
@@ -6453,6 +6487,7 @@ function LevelPlanView({
|
|||||||
selectedColumnIds,
|
selectedColumnIds,
|
||||||
selectedRoomIds,
|
selectedRoomIds,
|
||||||
selectedRoofIds,
|
selectedRoofIds,
|
||||||
|
selectedSectionLineId,
|
||||||
roomStamp,
|
roomStamp,
|
||||||
onStampMove,
|
onStampMove,
|
||||||
onStampEdit,
|
onStampEdit,
|
||||||
@@ -6491,6 +6526,7 @@ function LevelPlanView({
|
|||||||
selectedColumnIds: string[];
|
selectedColumnIds: string[];
|
||||||
selectedRoomIds: string[];
|
selectedRoomIds: string[];
|
||||||
selectedRoofIds: string[];
|
selectedRoofIds: string[];
|
||||||
|
selectedSectionLineId: string | null;
|
||||||
roomStamp: { roomId: string; anchor: Vec2 } | null;
|
roomStamp: { roomId: string; anchor: Vec2 } | null;
|
||||||
onStampMove: (roomId: string, delta: Vec2) => void;
|
onStampMove: (roomId: string, delta: Vec2) => void;
|
||||||
onStampEdit: (roomId: string) => void;
|
onStampEdit: (roomId: string) => void;
|
||||||
@@ -6568,6 +6604,7 @@ function LevelPlanView({
|
|||||||
selectedColumnIds={selectedColumnIds}
|
selectedColumnIds={selectedColumnIds}
|
||||||
selectedRoomIds={selectedRoomIds}
|
selectedRoomIds={selectedRoomIds}
|
||||||
selectedRoofIds={selectedRoofIds}
|
selectedRoofIds={selectedRoofIds}
|
||||||
|
selectedSectionLineIds={selectedSectionLineId ? [selectedSectionLineId] : []}
|
||||||
roomStamp={roomStamp}
|
roomStamp={roomStamp}
|
||||||
onStampMove={onStampMove}
|
onStampMove={onStampMove}
|
||||||
onStampEdit={onStampEdit}
|
onStampEdit={onStampEdit}
|
||||||
@@ -6621,6 +6658,7 @@ function SectionPlanView({
|
|||||||
selectedColumnIds,
|
selectedColumnIds,
|
||||||
selectedRoomIds,
|
selectedRoomIds,
|
||||||
selectedRoofIds,
|
selectedRoofIds,
|
||||||
|
selectedSectionLineId,
|
||||||
roomStamp,
|
roomStamp,
|
||||||
onStampMove,
|
onStampMove,
|
||||||
onStampEdit,
|
onStampEdit,
|
||||||
@@ -6655,6 +6693,7 @@ function SectionPlanView({
|
|||||||
selectedColumnIds: string[];
|
selectedColumnIds: string[];
|
||||||
selectedRoomIds: string[];
|
selectedRoomIds: string[];
|
||||||
selectedRoofIds: string[];
|
selectedRoofIds: string[];
|
||||||
|
selectedSectionLineId: string | null;
|
||||||
roomStamp: { roomId: string; anchor: Vec2 } | null;
|
roomStamp: { roomId: string; anchor: Vec2 } | null;
|
||||||
onStampMove: (roomId: string, delta: Vec2) => void;
|
onStampMove: (roomId: string, delta: Vec2) => void;
|
||||||
onStampEdit: (roomId: string) => void;
|
onStampEdit: (roomId: string) => void;
|
||||||
@@ -6742,6 +6781,7 @@ function SectionPlanView({
|
|||||||
selectedColumnIds={selectedColumnIds}
|
selectedColumnIds={selectedColumnIds}
|
||||||
selectedRoomIds={selectedRoomIds}
|
selectedRoomIds={selectedRoomIds}
|
||||||
selectedRoofIds={selectedRoofIds}
|
selectedRoofIds={selectedRoofIds}
|
||||||
|
selectedSectionLineIds={selectedSectionLineId ? [selectedSectionLineId] : []}
|
||||||
roomStamp={roomStamp}
|
roomStamp={roomStamp}
|
||||||
onStampMove={onStampMove}
|
onStampMove={onStampMove}
|
||||||
onStampEdit={onStampEdit}
|
onStampEdit={onStampEdit}
|
||||||
|
|||||||
@@ -197,6 +197,12 @@ export interface PlanSelection {
|
|||||||
* Element höherer Priorität (alle anderen gehen vor); sonst `null`.
|
* Element höherer Priorität (alle anderen gehen vor); sonst `null`.
|
||||||
*/
|
*/
|
||||||
roofId: string | null;
|
roofId: string | null;
|
||||||
|
/**
|
||||||
|
* ID der getroffenen Schnitt-/Ansichtslinie (DrawingLevel), wenn der Klick ihr
|
||||||
|
* dünnes Pick-Band traf; sonst `null`. Höchste Priorität (das schmale Band liegt
|
||||||
|
* über allem — ein Klick genau darauf meint die Linie).
|
||||||
|
*/
|
||||||
|
sectionLineId: string | null;
|
||||||
/**
|
/**
|
||||||
* War beim Klick Shift gedrückt? Dann ERWEITERT der Aufrufer (App) die
|
* 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
|
* Auswahl um das getroffene Element (bzw. schaltet es ab/zu), statt sie zu
|
||||||
@@ -287,6 +293,11 @@ export interface PlanViewProps {
|
|||||||
selectedRoomIds?: string[];
|
selectedRoomIds?: string[];
|
||||||
/** Aktuell ausgewählte Dach-IDs (von App); die Ansicht markiert die Traufe. */
|
/** Aktuell ausgewählte Dach-IDs (von App); die Ansicht markiert die Traufe. */
|
||||||
selectedRoofIds?: string[];
|
selectedRoofIds?: string[];
|
||||||
|
/**
|
||||||
|
* Aktuell ausgewählte Schnitt-/Ansichtslinien-IDs (DrawingLevel; von App). Die
|
||||||
|
* Ansicht markiert das Pick-Band JEDER dieser Linien mit einer Akzentkontur.
|
||||||
|
*/
|
||||||
|
selectedSectionLineIds?: string[];
|
||||||
/**
|
/**
|
||||||
* Aktuell ausgewählte IDs extrudierter Körper (truck-Integration; kontrolliert
|
* Aktuell ausgewählte IDs extrudierter Körper (truck-Integration; kontrolliert
|
||||||
* von App). Die Ansicht markiert den Footprint-Umriss JEDES dieser Körper mit
|
* von App). Die Ansicht markiert den Footprint-Umriss JEDES dieser Körper mit
|
||||||
@@ -416,6 +427,7 @@ export const PlanView = forwardRef<PlanViewHandle, PlanViewProps>(
|
|||||||
selectedStairIds,
|
selectedStairIds,
|
||||||
selectedRoomIds,
|
selectedRoomIds,
|
||||||
selectedRoofIds,
|
selectedRoofIds,
|
||||||
|
selectedSectionLineIds,
|
||||||
selectedExtrudedSolidIds,
|
selectedExtrudedSolidIds,
|
||||||
selectedColumnIds,
|
selectedColumnIds,
|
||||||
roomStamp,
|
roomStamp,
|
||||||
@@ -1007,6 +1019,20 @@ export const PlanView = forwardRef<PlanViewHandle, PlanViewProps>(
|
|||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Getroffene Schnitt-/Ansichtslinie: ihr schmales, unsichtbares Pick-Band
|
||||||
|
// (Polygon mit sectionLineId) per Punkt-in-Polygon.
|
||||||
|
const pickSectionLine = (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.sectionLineId && pointInPolygon(m, p.pts)) {
|
||||||
|
return p.sectionLineId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
// Getroffener extrudierter Körper (truck-Integration): der Footprint-Umriss
|
// Getroffener extrudierter Körper (truck-Integration): der Footprint-Umriss
|
||||||
// ist ein reiner Haarlinien-Umriss (fill:"none"), aber per Punkt-in-Polygon
|
// ist ein reiner Haarlinien-Umriss (fill:"none"), aber per Punkt-in-Polygon
|
||||||
// trotzdem als FLÄCHE anklickbar (analog Raum, nicht nur auf der Linie).
|
// trotzdem als FLÄCHE anklickbar (analog Raum, nicht nur auf der Linie).
|
||||||
@@ -1518,6 +1544,28 @@ export const PlanView = forwardRef<PlanViewHandle, PlanViewProps>(
|
|||||||
const hit = hitIndex !== null ? plan.primitives[hitIndex] : undefined;
|
const hit = hitIndex !== null ? plan.primitives[hitIndex] : undefined;
|
||||||
// Öffnung (Fenster/Tür) zuerst: ihr Symbol sitzt in der ausgesparten Lücke
|
// Öffnung (Fenster/Tür) zuerst: ihr Symbol sitzt in der ausgesparten Lücke
|
||||||
// bzw. schlägt über die Wand — ein Klick nahe am Symbol wählt die Öffnung.
|
// bzw. schlägt über die Wand — ein Klick nahe am Symbol wählt die Öffnung.
|
||||||
|
// Schnitt-/Ansichtslinie zuerst: ihr schmales Band liegt über allem, ein
|
||||||
|
// Klick genau darauf meint die Linie (nicht die darunterliegende Wand) —
|
||||||
|
// dann sofort melden (kein anderes Element konkurriert).
|
||||||
|
const sectionLineId = pickSectionLine(e.clientX, e.clientY);
|
||||||
|
if (sectionLineId) {
|
||||||
|
onSelect({
|
||||||
|
model: viewToModel(v.x, v.y),
|
||||||
|
hitIndex,
|
||||||
|
wallId: null,
|
||||||
|
drawingId: null,
|
||||||
|
ceilingId: null,
|
||||||
|
openingId: null,
|
||||||
|
stairId: null,
|
||||||
|
roomId: null,
|
||||||
|
extrudedSolidId: null,
|
||||||
|
columnId: null,
|
||||||
|
roofId: null,
|
||||||
|
sectionLineId,
|
||||||
|
shift: e.shiftKey,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
const openingId = pickOpening(e.clientX, e.clientY);
|
const openingId = pickOpening(e.clientX, e.clientY);
|
||||||
const wallId =
|
const wallId =
|
||||||
openingId ? null : hit && hit.kind === "polygon" ? hit.wallId ?? null : null;
|
openingId ? null : hit && hit.kind === "polygon" ? hit.wallId ?? null : null;
|
||||||
@@ -1581,6 +1629,7 @@ export const PlanView = forwardRef<PlanViewHandle, PlanViewProps>(
|
|||||||
extrudedSolidId,
|
extrudedSolidId,
|
||||||
columnId,
|
columnId,
|
||||||
roofId,
|
roofId,
|
||||||
|
sectionLineId: null,
|
||||||
shift: e.shiftKey,
|
shift: e.shiftKey,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -1780,6 +1829,20 @@ export const PlanView = forwardRef<PlanViewHandle, PlanViewProps>(
|
|||||||
);
|
);
|
||||||
}, [plan, selectedRoofIds]);
|
}, [plan, selectedRoofIds]);
|
||||||
|
|
||||||
|
// Hervorhebung der selektierten Schnitt-/Ansichtslinie: das (unsichtbare)
|
||||||
|
// Pick-Band (Polygon mit sectionLineId) mit Akzentkontur überzeichnen.
|
||||||
|
const highlightSectionLinePolys = useMemo(() => {
|
||||||
|
const ids =
|
||||||
|
selectedSectionLineIds && selectedSectionLineIds.length
|
||||||
|
? new Set(selectedSectionLineIds)
|
||||||
|
: null;
|
||||||
|
if (!ids) return [];
|
||||||
|
return plan.primitives.filter(
|
||||||
|
(p): p is Extract<Primitive, { kind: "polygon" }> =>
|
||||||
|
p.kind === "polygon" && p.sectionLineId != null && ids.has(p.sectionLineId),
|
||||||
|
);
|
||||||
|
}, [plan, selectedSectionLineIds]);
|
||||||
|
|
||||||
// Hervorhebung der selektierten extrudierten Körper (truck-Integration): der
|
// Hervorhebung der selektierten extrudierten Körper (truck-Integration): der
|
||||||
// Footprint-Umriss (Polygon mit extrudedSolidId) mit Akzentkontur überzeichnen
|
// Footprint-Umriss (Polygon mit extrudedSolidId) mit Akzentkontur überzeichnen
|
||||||
// — analog zur Raum-Auswahl.
|
// — analog zur Raum-Auswahl.
|
||||||
@@ -2024,6 +2087,18 @@ export const PlanView = forwardRef<PlanViewHandle, PlanViewProps>(
|
|||||||
pointerEvents="none"
|
pointerEvents="none"
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
|
{/* Auswahl-Hervorhebung der gewählten Schnitt-/Ansichtslinie (Pick-Band). */}
|
||||||
|
{highlightSectionLinePolys.map((poly, i) => (
|
||||||
|
<polygon
|
||||||
|
key={`selsl-${i}`}
|
||||||
|
className="plan-selected"
|
||||||
|
points={poly.pts
|
||||||
|
.map(toScreen)
|
||||||
|
.map((s) => `${s.x},${s.y}`)
|
||||||
|
.join(" ")}
|
||||||
|
pointerEvents="none"
|
||||||
|
/>
|
||||||
|
))}
|
||||||
{/* Auswahl-Hervorhebung der gewählten extrudierten Körper (truck-Integration). */}
|
{/* Auswahl-Hervorhebung der gewählten extrudierten Körper (truck-Integration). */}
|
||||||
{highlightExtrudedSolidPolys.map((poly, i) => (
|
{highlightExtrudedSolidPolys.map((poly, i) => (
|
||||||
<polygon
|
<polygon
|
||||||
|
|||||||
@@ -0,0 +1,98 @@
|
|||||||
|
/**
|
||||||
|
* Schnittführungs-Symbol im Grundriss (generatePlan → addSectionLines): jede
|
||||||
|
* Schnitt-/Ansichtsebene MIT `linePoints` erzeugt eine Strichpunkt-Linie
|
||||||
|
* (cls "section-line"), Endmarken + ein unsichtbares Pick-Band (Polygon mit
|
||||||
|
* `sectionLineId`). Ebenen OHNE Linie erzeugen nichts.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { describe, it, expect } from "vitest";
|
||||||
|
import { generatePlan } from "./generatePlan";
|
||||||
|
import type { DrawingLevel, Project } from "../model/types";
|
||||||
|
|
||||||
|
const visible = new Set(["20", "35"]);
|
||||||
|
|
||||||
|
function baseProject(levels: DrawingLevel[]): Project {
|
||||||
|
return {
|
||||||
|
id: "t",
|
||||||
|
name: "T",
|
||||||
|
lineStyles: [],
|
||||||
|
hatches: [],
|
||||||
|
components: [],
|
||||||
|
wallTypes: [],
|
||||||
|
drawingLevels: levels,
|
||||||
|
layers: [{ code: "20", name: "Wände", color: "#333", lw: 0.18, visible: true, locked: false }],
|
||||||
|
walls: [],
|
||||||
|
doors: [],
|
||||||
|
openings: [],
|
||||||
|
ceilings: [],
|
||||||
|
stairs: [],
|
||||||
|
rooms: [],
|
||||||
|
drawings2d: [],
|
||||||
|
context: [],
|
||||||
|
} as unknown as Project;
|
||||||
|
}
|
||||||
|
|
||||||
|
const floor: DrawingLevel = {
|
||||||
|
id: "eg",
|
||||||
|
name: "EG",
|
||||||
|
kind: "floor",
|
||||||
|
visible: true,
|
||||||
|
locked: false,
|
||||||
|
floorHeight: 2.6,
|
||||||
|
cutHeight: 1.0,
|
||||||
|
baseElevation: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
describe("generatePlan — Schnittführungs-Symbol", () => {
|
||||||
|
it("zeichnet Linie + Pick-Band für eine Schnittebene mit linePoints", () => {
|
||||||
|
const p = baseProject([
|
||||||
|
floor,
|
||||||
|
{
|
||||||
|
id: "s-a",
|
||||||
|
name: "Schnitt A",
|
||||||
|
kind: "section",
|
||||||
|
visible: true,
|
||||||
|
locked: false,
|
||||||
|
linePoints: [{ x: 0, y: 2 }, { x: 6, y: 2 }],
|
||||||
|
directionSign: 1,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
const prims = generatePlan(p, "eg", visible).primitives;
|
||||||
|
// Strichpunkt-Hauptlinie vorhanden.
|
||||||
|
const lines = prims.filter((pr) => pr.kind === "line" && pr.cls === "section-line");
|
||||||
|
expect(lines.length).toBeGreaterThan(0);
|
||||||
|
// Pick-Band trägt die Level-Id.
|
||||||
|
const band = prims.find((pr) => pr.kind === "polygon" && pr.sectionLineId === "s-a");
|
||||||
|
expect(band).toBeTruthy();
|
||||||
|
// Label-Text (Kurz-Tag „A") an den Enden.
|
||||||
|
const labels = prims.filter((pr) => pr.kind === "drawingText" && pr.text === "A");
|
||||||
|
expect(labels.length).toBe(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("zeichnet NICHTS für eine Schnittebene ohne linePoints", () => {
|
||||||
|
const p = baseProject([
|
||||||
|
floor,
|
||||||
|
{ id: "s-b", name: "Schnitt B", kind: "section", visible: true, locked: false },
|
||||||
|
]);
|
||||||
|
const prims = generatePlan(p, "eg", visible).primitives;
|
||||||
|
expect(prims.some((pr) => pr.kind === "polygon" && pr.sectionLineId != null)).toBe(false);
|
||||||
|
expect(prims.some((pr) => pr.kind === "line" && pr.cls === "section-line")).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("behandelt Ansichtsebenen (elevation) gleich", () => {
|
||||||
|
const p = baseProject([
|
||||||
|
floor,
|
||||||
|
{
|
||||||
|
id: "e-a",
|
||||||
|
name: "Ansicht Süd",
|
||||||
|
kind: "elevation",
|
||||||
|
visible: true,
|
||||||
|
locked: false,
|
||||||
|
linePoints: [{ x: 0, y: 0 }, { x: 4, y: 0 }],
|
||||||
|
directionSign: -1,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
const prims = generatePlan(p, "eg", visible).primitives;
|
||||||
|
expect(prims.some((pr) => pr.kind === "polygon" && pr.sectionLineId === "e-a")).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -265,6 +265,12 @@ export type Primitive =
|
|||||||
columnId?: string;
|
columnId?: string;
|
||||||
/** ID des Dachs (Roof), falls dieses (unsichtbare) Polygon der Traufe-Umriss ist (Auswahl). */
|
/** ID des Dachs (Roof), falls dieses (unsichtbare) Polygon der Traufe-Umriss ist (Auswahl). */
|
||||||
roofId?: string;
|
roofId?: string;
|
||||||
|
/**
|
||||||
|
* ID der Schnitt-/Ansichtslinie (DrawingLevel), falls dieses (unsichtbare)
|
||||||
|
* Pick-Band das Schnittführungs-Symbol umhüllt (für die Links-Klick-Auswahl
|
||||||
|
* der Schnittlinie im Grundriss).
|
||||||
|
*/
|
||||||
|
sectionLineId?: string;
|
||||||
}
|
}
|
||||||
| {
|
| {
|
||||||
kind: "line";
|
kind: "line";
|
||||||
@@ -892,6 +898,10 @@ export function generatePlan(
|
|||||||
// die Reihenfolge unkritisch; wir hängen sie als Referenz an.
|
// die Reihenfolge unkritisch; wir hängen sie als Referenz an.
|
||||||
addContextContours(primitives, project);
|
addContextContours(primitives, project);
|
||||||
|
|
||||||
|
// Schnittführungs-Symbole (klassische Schnittlinien) aller Schnitt-/Ansichts-
|
||||||
|
// ebenen mit gesetzter Linie — projektglobale Referenzgeometrie über dem Plan.
|
||||||
|
addSectionLines(primitives, project);
|
||||||
|
|
||||||
// Schwarz-Weiss (mono): nachträglich alle Farben auf reine Tinte zwingen.
|
// Schwarz-Weiss (mono): nachträglich alle Farben auf reine Tinte zwingen.
|
||||||
// Element-/Kategorie-/Hatch-Farben werden ignoriert, Füllungen werden weiss,
|
// Element-/Kategorie-/Hatch-Farben werden ignoriert, Füllungen werden weiss,
|
||||||
// Musterlinien/Striche schwarz — so entsteht ein reiner S/W-Plan.
|
// Musterlinien/Striche schwarz — so entsteht ein reiner S/W-Plan.
|
||||||
@@ -2641,6 +2651,139 @@ function addRoof(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ── Schnittführungs-Symbol (klassische Schnittlinie im Grundriss) ───────────
|
||||||
|
/** Tinte der Schnittführungs-Linie/Marken (kräftiges Grau). */
|
||||||
|
const SECTION_LINE_INK = "#1f242c";
|
||||||
|
/** Haarlinie der Strichpunkt-Schnittlinie (mm Papier). */
|
||||||
|
const SECTION_LINE_MM = 0.18;
|
||||||
|
/** Kräftige Endmarken (Querstrich + Pfeil) (mm Papier). */
|
||||||
|
const SECTION_LINE_MARK_MM = 0.5;
|
||||||
|
/** Strichpunkt-Muster der Schnittlinie (lange Striche + Punkt, mm Papier). */
|
||||||
|
const SECTION_LINE_DASH: number[] = [6, 1.5, 0.4, 1.5];
|
||||||
|
/** Länge der Endmarken (Querstrich/Pfeil) in Modell-Metern. */
|
||||||
|
const SECTION_MARK_LEN = 0.6;
|
||||||
|
/** Halbe Breite des unsichtbaren Pick-Bands über der Linie (Modell-Meter). */
|
||||||
|
const SECTION_PICK_HALF = 0.3;
|
||||||
|
/** Schrifthöhe des Schnitt-Labels (Modell-Meter). */
|
||||||
|
const SECTION_LABEL_H = 0.5;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Kurz-Tag eines Schnitt-Labels: der letzte „Wort"-Teil des Ebenennamens (z. B.
|
||||||
|
* „Schnitt A" → „A"); enthält der Name kein Leerzeichen, der ganze Name. Klassisch
|
||||||
|
* wird der Schnitt an beiden Enden mit diesem Tag beschriftet (A–A).
|
||||||
|
*/
|
||||||
|
function sectionLabelTag(name: string): string {
|
||||||
|
const parts = name.trim().split(/\s+/);
|
||||||
|
return parts.length > 1 ? parts[parts.length - 1] : name.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Zeichnet für jede Schnitt-/Ansichtsebene MIT gesetzter `linePoints` das
|
||||||
|
* klassische Schnittführungs-Symbol in den Grundriss: eine Strichpunkt-Haarlinie
|
||||||
|
* über die volle Länge, an beiden Enden einen kräftigen Querstrich + Richtungspfeil
|
||||||
|
* auf der Blickseite (`directionSign`) und das Schnitt-Label (Kurz-Tag) daneben.
|
||||||
|
* Zusätzlich ein unsichtbares Pick-Band (Polygon mit `sectionLineId`), damit die
|
||||||
|
* Linie im Grundriss anklickbar ist (analog dem Dach-Traufe-Pick-Polygon).
|
||||||
|
*/
|
||||||
|
function addSectionLines(out: Primitive[], project: Project): void {
|
||||||
|
for (const level of project.drawingLevels) {
|
||||||
|
if (level.kind !== "section" && level.kind !== "elevation") continue;
|
||||||
|
const line = level.linePoints;
|
||||||
|
if (!line) continue;
|
||||||
|
const [p0, p1] = line;
|
||||||
|
const axis = sub(p1, p0);
|
||||||
|
const len = Math.hypot(axis.x, axis.y);
|
||||||
|
if (len < 1e-6) continue;
|
||||||
|
const u = normalize(axis);
|
||||||
|
const n = leftNormal(u); // (-uy, ux)
|
||||||
|
const sign = level.directionSign ?? 1;
|
||||||
|
const bn = { x: n.x * sign, y: n.y * sign }; // Blicknormale
|
||||||
|
|
||||||
|
// Hauptlinie (Strichpunkt-Haarlinie).
|
||||||
|
out.push({
|
||||||
|
kind: "line",
|
||||||
|
a: p0,
|
||||||
|
b: p1,
|
||||||
|
cls: "section-line",
|
||||||
|
weightMm: SECTION_LINE_MM,
|
||||||
|
dash: SECTION_LINE_DASH,
|
||||||
|
color: SECTION_LINE_INK,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Endmarken (Querstrich + Richtungspfeil + Label) an beiden Enden.
|
||||||
|
const half = SECTION_MARK_LEN / 2;
|
||||||
|
for (const end of [p0, p1]) {
|
||||||
|
// Querstrich senkrecht zur Linie, mittig am Endpunkt.
|
||||||
|
const t0 = { x: end.x - n.x * half, y: end.y - n.y * half };
|
||||||
|
const t1 = { x: end.x + n.x * half, y: end.y + n.y * half };
|
||||||
|
out.push({
|
||||||
|
kind: "line",
|
||||||
|
a: t0,
|
||||||
|
b: t1,
|
||||||
|
cls: "section-line",
|
||||||
|
weightMm: SECTION_LINE_MARK_MM,
|
||||||
|
color: SECTION_LINE_INK,
|
||||||
|
});
|
||||||
|
// Richtungspfeil: vom Querstrich-Ende auf der Blickseite entlang bn.
|
||||||
|
const base = { x: end.x + bn.x * half, y: end.y + bn.y * half };
|
||||||
|
const tip = { x: base.x + bn.x * SECTION_MARK_LEN, y: base.y + bn.y * SECTION_MARK_LEN };
|
||||||
|
const wingBack = {
|
||||||
|
x: tip.x - bn.x * SECTION_MARK_LEN * 0.4,
|
||||||
|
y: tip.y - bn.y * SECTION_MARK_LEN * 0.4,
|
||||||
|
};
|
||||||
|
const w = SECTION_MARK_LEN * 0.25;
|
||||||
|
out.push({ kind: "line", a: base, b: tip, cls: "section-line", weightMm: SECTION_LINE_MARK_MM, color: SECTION_LINE_INK });
|
||||||
|
out.push({
|
||||||
|
kind: "line",
|
||||||
|
a: tip,
|
||||||
|
b: { x: wingBack.x + u.x * w, y: wingBack.y + u.y * w },
|
||||||
|
cls: "section-line",
|
||||||
|
weightMm: SECTION_LINE_MARK_MM,
|
||||||
|
color: SECTION_LINE_INK,
|
||||||
|
});
|
||||||
|
out.push({
|
||||||
|
kind: "line",
|
||||||
|
a: tip,
|
||||||
|
b: { x: wingBack.x - u.x * w, y: wingBack.y - u.y * w },
|
||||||
|
cls: "section-line",
|
||||||
|
weightMm: SECTION_LINE_MARK_MM,
|
||||||
|
color: SECTION_LINE_INK,
|
||||||
|
});
|
||||||
|
// Label (Kurz-Tag) etwas hinter dem Pfeil, horizontal.
|
||||||
|
const labelAt = {
|
||||||
|
x: tip.x + bn.x * SECTION_MARK_LEN * 0.4 - SECTION_LABEL_H * 0.3,
|
||||||
|
y: tip.y + bn.y * SECTION_MARK_LEN * 0.4 + SECTION_LABEL_H * 0.5,
|
||||||
|
};
|
||||||
|
out.push({
|
||||||
|
kind: "drawingText",
|
||||||
|
at: labelAt,
|
||||||
|
text: sectionLabelTag(level.name),
|
||||||
|
heightM: SECTION_LABEL_H,
|
||||||
|
angle: 0,
|
||||||
|
color: SECTION_LINE_INK,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unsichtbares Pick-Band (Rechteck entlang der Linie) — klickbar per
|
||||||
|
// Punkt-in-Polygon in PlanView, trägt die DrawingLevel-Id.
|
||||||
|
const off = { x: n.x * SECTION_PICK_HALF, y: n.y * SECTION_PICK_HALF };
|
||||||
|
out.push({
|
||||||
|
kind: "polygon",
|
||||||
|
pts: [
|
||||||
|
{ x: p0.x + off.x, y: p0.y + off.y },
|
||||||
|
{ x: p1.x + off.x, y: p1.y + off.y },
|
||||||
|
{ x: p1.x - off.x, y: p1.y - off.y },
|
||||||
|
{ x: p0.x - off.x, y: p0.y - off.y },
|
||||||
|
],
|
||||||
|
fill: "none",
|
||||||
|
stroke: "none",
|
||||||
|
strokeWidthMm: 0,
|
||||||
|
hatch: NO_HATCH,
|
||||||
|
sectionLineId: level.id,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deckkraft (0..255) der Raum-Füllung → 2-stelliges Hex-Suffix. Transluzente
|
* Deckkraft (0..255) der Raum-Füllung → 2-stelliges Hex-Suffix. Transluzente
|
||||||
* Farbfüllung entfällt — Plandarstellung schwarz/grau; Farbe bleibt späteren
|
* Farbfüllung entfällt — Plandarstellung schwarz/grau; Farbe bleibt späteren
|
||||||
|
|||||||
@@ -25,6 +25,9 @@ export interface SelectionSlice {
|
|||||||
selectedColumnIds: string[];
|
selectedColumnIds: string[];
|
||||||
// Gewählte Dächer als MENGE von IDs — getrennt von den übrigen Kanälen.
|
// Gewählte Dächer als MENGE von IDs — getrennt von den übrigen Kanälen.
|
||||||
selectedRoofIds: string[];
|
selectedRoofIds: string[];
|
||||||
|
// Gewählte Schnitt-/Ansichtslinie (DrawingLevel-Id) — EINZELauswahl (eine Linie
|
||||||
|
// zur Zeit), getrennt von den übrigen Kanälen. `null` = keine Linie gewählt.
|
||||||
|
selectedSectionLineId: string | null;
|
||||||
|
|
||||||
setSelectedWallIds: (ids: string[]) => void;
|
setSelectedWallIds: (ids: string[]) => void;
|
||||||
setSelectedDrawingIds: (ids: string[]) => void;
|
setSelectedDrawingIds: (ids: string[]) => void;
|
||||||
@@ -35,6 +38,7 @@ export interface SelectionSlice {
|
|||||||
setSelectedExtrudedSolidIds: (ids: string[]) => void;
|
setSelectedExtrudedSolidIds: (ids: string[]) => void;
|
||||||
setSelectedColumnIds: (ids: string[]) => void;
|
setSelectedColumnIds: (ids: string[]) => void;
|
||||||
setSelectedRoofIds: (ids: string[]) => void;
|
setSelectedRoofIds: (ids: string[]) => void;
|
||||||
|
setSelectedSectionLineId: (id: string | null) => void;
|
||||||
/** Auswahl (Wände + Decken + Öffnungen + Treppen + Dächer + 2D-Elemente) leeren. */
|
/** Auswahl (Wände + Decken + Öffnungen + Treppen + Dächer + 2D-Elemente) leeren. */
|
||||||
clearSelection: () => void;
|
clearSelection: () => void;
|
||||||
}
|
}
|
||||||
@@ -53,6 +57,7 @@ export function createSelectionSlice(
|
|||||||
selectedExtrudedSolidIds: [],
|
selectedExtrudedSolidIds: [],
|
||||||
selectedColumnIds: [],
|
selectedColumnIds: [],
|
||||||
selectedRoofIds: [],
|
selectedRoofIds: [],
|
||||||
|
selectedSectionLineId: null,
|
||||||
setSelectedWallIds: (ids) => set({ selectedWallIds: ids }),
|
setSelectedWallIds: (ids) => set({ selectedWallIds: ids }),
|
||||||
setSelectedDrawingIds: (ids) => set({ selectedDrawingIds: ids }),
|
setSelectedDrawingIds: (ids) => set({ selectedDrawingIds: ids }),
|
||||||
setSelectedCeilingIds: (ids) => set({ selectedCeilingIds: ids }),
|
setSelectedCeilingIds: (ids) => set({ selectedCeilingIds: ids }),
|
||||||
@@ -62,6 +67,7 @@ export function createSelectionSlice(
|
|||||||
setSelectedExtrudedSolidIds: (ids) => set({ selectedExtrudedSolidIds: ids }),
|
setSelectedExtrudedSolidIds: (ids) => set({ selectedExtrudedSolidIds: ids }),
|
||||||
setSelectedColumnIds: (ids) => set({ selectedColumnIds: ids }),
|
setSelectedColumnIds: (ids) => set({ selectedColumnIds: ids }),
|
||||||
setSelectedRoofIds: (ids) => set({ selectedRoofIds: ids }),
|
setSelectedRoofIds: (ids) => set({ selectedRoofIds: ids }),
|
||||||
|
setSelectedSectionLineId: (id) => set({ selectedSectionLineId: id }),
|
||||||
clearSelection: () =>
|
clearSelection: () =>
|
||||||
set({
|
set({
|
||||||
selectedWallIds: [],
|
selectedWallIds: [],
|
||||||
@@ -73,6 +79,7 @@ export function createSelectionSlice(
|
|||||||
selectedExtrudedSolidIds: [],
|
selectedExtrudedSolidIds: [],
|
||||||
selectedColumnIds: [],
|
selectedColumnIds: [],
|
||||||
selectedRoofIds: [],
|
selectedRoofIds: [],
|
||||||
|
selectedSectionLineId: null,
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user