Treppen 2D-Plansymbol + Pure-Transform fuer hidden Layer

Frontend:
- 2D-Plansymbol pro Treppe (Tritte/Lauflinie/Aussenlinie/Bruchsymbol)
  mit per-Treppe-Toggles in Properties-Panel
- 'Obere Stufen gestrichelt'-Toggle splittet Tritte/Aussenlinie an
  Schnittebene; Lauflinie hat zwei Pfeile bei Bruch
- Wand-Polyline-Grips fuer alle Vertices (nicht nur Enden)
- PopupMenu unterstuetzt Divider + Checkbox-Items

Backend:
- Eigener Layer 41_Treppen_2D fuer Plansymbol, Layer-Default schwarz
- Aussenlinie-Polygone folgen der Bruch-Diagonale (kein Versatz mehr)
- Linetype-Fallback laedt Dashed bei Bedarf nach
- Tritten-immer-an (Toggle entfernt), Z auf Geschoss-OKFF
- TREPPEN/RAEUME Layer-Migration auf Capital-Case (Treppen/Raeume)
- Selection-Partnership: treppe_2d_symbol pairs in axis + volume

Pure-Transform fuer Treppen-Move:
- treppe_2d_symbol + treppe_volume in VOLUME_TYPES → cascade-Support
- Phase 1.5 Volume-only-Detection: wenn Source unbewegt aber Volumes
  uniform translated → synthetisiere canonical aus Avg-Delta der
  bewegten Volumes (unbewegte rausgefiltert sonst Verzerrung)
- Hidden-inclusive ObjectEnumerator in Snapshot + Apply-Loop damit
  hidden treppe_axis auf 40_Treppen mit-transformiert wird
- Properties-Fallback im _send_state findet hidden Sources via
  expliziter Iteration → Panel zeigt Treppe auch bei 3D-Layer aus
- Dimensionen-Panel skipt on_select/idle waehrend UT_ACTIVE oder
  Partnership-Cascade → keine Flicker beim Drag mehr
This commit is contained in:
2026-05-28 00:41:05 +02:00
parent d9589e99f5
commit bcf7d557b1
5 changed files with 1172 additions and 107 deletions
+57 -5
View File
@@ -6,7 +6,7 @@ import { BarToggle, BarButton, BarCombo } from './components/BarControls'
import {
onMessage, notifyReady,
createWall, createDecke, createDach,
createFenster, createTuer, createAussparung, createTreppe,
createFenster, createTuer, createAussparung, createTreppe, setTreppe2DShow,
createStuetze, createTraeger, createRaum, createStempel,
openSwisstopo, openSwisstopoDialog, openOsmDialog,
updateElement, deleteElement, openElementeUebersicht, openElementeProperties,
@@ -136,9 +136,15 @@ function PopupMenu({ items, onClose }) {
zIndex: 100,
minWidth: 140,
}}>
{items.map((it, i) => (
{items.map((it, i) => it._divider ? (
<div key={i} style={{
height: 1, margin: '4px 2px',
background: 'var(--border)', opacity: 0.6,
}} />
) : (
<button key={i}
onClick={(e) => { e.stopPropagation(); it.onClick(); onClose() }}
onClick={(e) => { e.stopPropagation(); it.onClick();
if (!it.keepOpen) onClose() }}
disabled={it.disabled}
title={it.hint || ''}
style={{
@@ -157,7 +163,10 @@ function PopupMenu({ items, onClose }) {
onMouseLeave={(e) => {
e.currentTarget.style.background = 'transparent'
}}>
{it.icon && <Icon name={it.icon} size={12}
{it.checked !== undefined ? (
<Icon name={it.checked ? 'check_box' : 'check_box_outline_blank'}
size={12} style={{ color: 'var(--accent)' }} />
) : it.icon && <Icon name={it.icon} size={12}
style={{ color: 'var(--accent)' }} />}
<span style={{ flex: 1 }}>{it.label}</span>
{it.badge && (
@@ -331,7 +340,7 @@ function ElementListRow({ el, meta }) {
}
function NeuesElementSection({ noGeschoss, activeName, elementsCount }) {
function NeuesElementSection({ noGeschoss, activeName, elementsCount, treppe2DShow }) {
const [treppeMenuOpen, setTreppeMenuOpen] = useState(false)
const [stuetzeMenuOpen, setStuetzeMenuOpen] = useState(false)
const [traegerMenuOpen, setTraegerMenuOpen] = useState(false)
@@ -348,6 +357,7 @@ function NeuesElementSection({ noGeschoss, activeName, elementsCount }) {
const openStuetzeMenu = (e) => { e.preventDefault(); setStuetzeMenuOpen(true) }
const openTraegerMenu = (e) => { e.preventDefault(); setTraegerMenuOpen(true) }
const treppe2DOn = treppe2DShow !== false
const treppeItems = [
{ icon: 'stairs', label: 'Gerade Treppe',
hint: 'Lauflinie mit 2 Punkten',
@@ -358,6 +368,10 @@ function NeuesElementSection({ noGeschoss, activeName, elementsCount }) {
{ icon: 'rotate_right', label: 'Wendeltreppe',
hint: '3 Punkte: Mittelpunkt, Start-Lauflinie, End-Lauflinie',
onClick: () => createTreppe({ treppeArt: 'wendel' }) },
{ _divider: true },
{ checked: treppe2DOn, label: '2D-Plansymbol',
hint: 'Trittlinien + Auf-Pfeil auf Schnittebene zeichnen',
onClick: () => setTreppe2DShow(!treppe2DOn) },
]
const profilItems = (factory) => [
@@ -604,6 +618,7 @@ export default function ElementeApp() {
noGeschoss={noGeschoss}
activeName={activeName}
elementsCount={elements.length}
treppe2DShow={state.treppe2DShow}
/>
</div>
</div>
@@ -2197,6 +2212,43 @@ function TreppeProperties({ treppe, geschosse, onUpdate, onDelete }) {
</div>
)}
{/* 2D-Plansymbol Bestandteile */}
<div style={{ height: 1, background: 'var(--border-light)', margin: '2px 0' }} />
<div style={{ display: 'flex', flexDirection: 'column', gap: 3 }}>
<span style={{ fontSize: 9, color: 'var(--text-muted)',
letterSpacing: '0.06em', textTransform: 'uppercase' }}>
2D-Plansymbol
</span>
{[
['showLauflinie', 'Lauflinie'],
['showAussen', 'Außenlinie'],
['showBruch', 'Bruchsymbol'],
].map(([key, label]) => {
const on = treppe[key] !== false
return (
<label key={key} style={{
display: 'flex', alignItems: 'center', gap: 6,
fontSize: 11, cursor: 'pointer',
}}>
<input type="checkbox" checked={on}
onChange={(e) => onUpdate({ [key]: e.target.checked })}
style={{ accentColor: 'var(--accent)' }} />
<span>{label}</span>
</label>
)
})}
<label style={{
display: 'flex', alignItems: 'center', gap: 6,
fontSize: 10, cursor: 'pointer',
marginLeft: 18, color: 'var(--text-secondary)',
}} title="Tritte und Außenlinie oberhalb der Schnittebene gestrichelt anzeigen">
<input type="checkbox" checked={treppe.obereDashed !== false}
onChange={(e) => onUpdate({ obereDashed: e.target.checked })}
style={{ accentColor: 'var(--accent)' }} />
<span>Obere Stufen gestrichelt</span>
</label>
</div>
{/* Schrittmass-Tabelle: H (editierbar), S, A, 2S+A mit on/off + range */}
<div style={{
display: 'flex', flexDirection: 'column', gap: 3,
+1
View File
@@ -389,6 +389,7 @@ export function createFenster(p) { send('CREATE_FENSTER', p || {}) }
export function createTuer(p) { send('CREATE_TUER', p || {}) }
export function createAussparung(p) { send('CREATE_AUSSPARUNG', p || {}) }
export function createTreppe(p) { send('CREATE_TREPPE', p || {}) }
export function setTreppe2DShow(on) { send('SET_TREPPE_2D_SHOW', { on: !!on }) }
export function createStuetze(p) { send('CREATE_STUETZE', p || {}) }
export function createTraeger(p) { send('CREATE_TRAEGER', p || {}) }
export function createRaum(p) { send('CREATE_RAUM', p || {}) }