- startup.py: all user-visible messages translated to English
- panel_base.py: icon/rendering log messages translated
- toolbar.py: display mode check messages translated
- Global: Panel registered/opened/listener-active across all modules
- Fix: elemente.py and other files with stale 'import rhinopanel'
were missing from PROJECTS sync — now properly copied
- Disable text selection (CSS user-select:none) + block browser
context menu (contextmenu preventDefault) in all panels
- ContextMenu: pill items, accent hover, entrance animation,
optional title header — controlled via single ContextMenu.css
- EbenenManager + GeschossManager: show layer name as menu title
- startup.py: skip splash on Cmd+N when plugin already loaded
- startup.py: hook NewDocument so display-modes apply to new docs
- Alt+Click bypass im Cluster-Volume-Select-Handler raus.
- _layer_join_attempt + dJoin-Detection in smart_join.py raus.
Phase 2 automatic handling deckt die Use-Cases ab. Falls Manual-Layer-
Merge spaeter doch noetig: commit 118bc51 hat den Code als Referenz.
Phase-2-Fixes:
- Backbone-Ext berechnet bis MATCHING-Layer (Stahl) far-face, nicht bis
Body-far-face. Beton drillt durch Stahl-Band, nicht durch Daemm/Putz.
- Case A/B detection via dot(out_dir, RhinoPerp). Rhino Curve.Offset
benutzt (tan × +z) = (b_tan.Y, -b_tan.X), nicht (-b_tan.Y, b_tan.X).
- Backbone-axis-ext separat von _my_axis_ext: nur Backbone-Column
extended, non-backbone columns stoppen am Snap.
- Through-only Mats (z.B. Daemm wo T-stem keinen hat) werden auch
durchlaufen damit hoehere-prio backbone diese carven kann.
- Post-Carve Union: gleiche-Material-Pieces mergen (Backbone-Beton-Col
+ Through-Stahl-Band → T-Shape).
- BBox-overlap strict-Filter vor BoolDiff: touching coplanar faces
ueberspringen, vermeidet Rhino BoolDiff "punch-through" Artefakte.
- _has_my_cols guard: KeyError beim consume von T-stem-Layern fuer
through-only mats verhindert.
Layer-Smart-Join (smart_join.py):
- Neue _layer_join_attempt: 2 selektierte wand_volume Breps gleicher
Material via BoolUnion mergen. Manueller Override fuer Edge-Cases
wo auto Phase 2 nicht reicht.
Cluster-Volume Select-Handler (elemente.py):
- Alt-Click bypassed Cluster-Swap → User kann einzelne Layer-Breps
direkt anwaehlen (= fuer Layer-Smart-Join).
Asymmetric L-merge fuer Schichtdurchdringung:
- Backbone (= hoechste Material-Prio in beiden Waenden) bildet T-form
- Non-backbone Layer werden gecarved mit backbone-Column + through-Bands
hoeherer Prio
- ext=0 fuer T-Stem-Axis (= column endet am snap, kein "drueber")
- 3D Brep Union via Brep.CreateBooleanUnion mit cross-junction safety
(= aktueller through-Brep statt von Meta neu zu bauen)
- Cleanup: MergeCoplanarFaces
Plus:
- Innenwand Beton 20cm Style (Putz + Beton + Putz, ref-mid)
- curve_vertex_dots.py: gruene Vertex-Punkte fuer Polylinen/Curves
- Cluster-Volume Select Handler: Shift-Modifier fuer Multi-Select
- startup.py: Top-View maximieren on Doc-Open
Known limitation: Putz-Schicht kann in bestimmten Konfigurationen visuell
suedlich des Daemm-Band-Top weiter sichtbar sein (= edge case fuer
asymmetric layers). Naechster Schritt: manuelle 2D-Polygon-Konstruktion
statt 3D Boolean.
UX-Verbesserung: User-Frage "muss ich nur das Element anwaehlen das ich
snappen moechte?" — jetzt ja.
Wenn nur 1 wand_axis in der Selection ist, sucht T-Join automatisch die
naechste andere Wand-Achse im Doc (innerhalb 1m) und snappt die selektierte
Wand auf jene. Die andere bleibt unangetastet — wie bei klassischem T-Stem
gegen Through-Wand.
2-Wand-Modus bleibt: dann werden GENAU die beiden selektierten betrachtet
(z.B. wenn 3+ Waende in der Nähe sind und User exakt eine andere meinen will).
Selection-Hint vereinfacht: nur noch warnen wenn 0 Wand-Achsen aber wand-
Objekte vorhanden (z.B. nur Volumen selektiert, wo Axis nicht mitkam).
User-Test: Bei T-Konfig waren Wand-Achsen 55cm auseinander (vermutlich
auf Outline statt Axis gesnappt). Mit 20cm tol fiel T-Join durch → L-Join
machte Tangent-Schnittpunkt (= L-Form falsch fuer T-Intent).
Fix: T-Join Snap-Radius von 20cm auf 1m. Generous genug fuer typische
Drift-Faelle (Outline-Snap statt Axis-Snap, ungefaehre Platzierung etc.),
aber tight genug damit absichtliche Lücken (>1m) nicht versehentlich
zugesnapped werden.
Plus: Hint wenn < 2 Wand-Achsen selektiert → User weiss explizit dass
GENAU 2 Wand selektiert sein muss.
User-Test: L-Join layered funktioniert (3/3 layers built). Aber T-Join laeuft
fuer layered immer in den L-Join-Fallback. Um zu sehen warum, jetzt fuer
jeden der 4 Endpunkt-Checks im T-Join:
- distance zur anderen Curve
- distance zur deren Endpunkten
- Reason warum verworfen (zu weit / nahe Endpunkt / schon snapped)
So koennen wir live im Log sehen ob T-Stem geometrisch zu weit weg ist
oder ob er an einem Endpunkt der Through-Wand landet (= L-Sache).
ROOT CAUSE: Wenn doc.Objects.Replace einer wand_axis ausgefuehrt wird (z.B.
nach L-Join von smart_join), prueft der Replace-Listener ob das neue Object
schon Meta hat. Wenn nicht, re-attached er via _attach_meta — aber die
wand-spezifischen Felder (wand_layered, wand_layers, wand_style_id,
wand_joint_rolle) wurden NICHT mit-uebergeben.
Effekt: layered Wand verlor wand_layered=True nach L-Join → naechster Regen
sieht is_layered=False → baut single SOLID Brep statt per-Layer-Breps →
"die gemerged walls sind dann leider solid walls".
Fix: Im Re-Attach-Aufruf die 4 wand-Felder mit weiterreichen aus meta.
Folge-Effekt: auch wand_style_id und wand_joint_rolle waren weg, was
Material-Lookup + Joint-Rolle-Override gebrochen hat. Beide jetzt fix.
Bug: in _walls_and_curves_from_sel + safety check + diagnostic wurde
"dossier_type" als UserString-Key gelesen, aber der echte Key (definiert
in elemente.py via _KEY_TYPE) ist "dossier_element_type".
Effekt: kein einziges Objekt wurde als wand_axis/wand_volume erkannt.
ALLES landete im "elif t == '':" Branch (= generic curves).
Solid L-Join funktionierte per ZUFALL: bei Solid-Wand (axis + outline +
volume) sind nur 1 Curve open (axis); outline ist closed rectangle. Bei
2 Solid-Waenden waren also 2 offene Curves in generic → L-Join fand die
2 vermeintlich generic Curves (= eigentlich Achsen).
Bei Layered scheiterte es: 2 Achsen + 2 Centerlines = 4 offene Curves im
generic. L-Join Bedingung "len(generic) == 2" nicht erfuellt → silent
return → Fallthrough zu _Join.
Fix: alle 4 Vorkommen auf "dossier_element_type" gefixt. Jetzt erkennt
smart_join Waende richtig, dedupliziert per wall_id, und T-Join/L-Join/
Safety-Check funktionieren wie geplant.
T-Junction-Detection (_detect_t_junction): pos_tol von 1mm auf 1cm erhoeht.
User-Feedback: bei manuellem Snap kann's leicht ein paar mm danebengehen,
1mm war zu eng. 1cm ist immer noch tight genug fuer Architektur-Workflow.
smart_join (dJoin): Safety-Check vor _Join-Fallback. Wenn IRGENDEINE
wand_axis in der Selection ist (auch zusaetzlich zu anderen Curves), wird
NICHT auf Standard-_Join gefallen — sonst kleistert _Join mehrere Wand-
Achsen zu einer Polyline zusammen, der Listener detektiert das als
"Source-Duplikat" und vergibt neue Wall-IDs → alle Meta-Verknuepfungen
brechen.
Stattdessen: Print-Meldung dass T-Join/L-Join nicht gegriffen hat. User
muss GENAU 2 Waende selektieren die verbunden werden sollen.
Bisher: bei T-Junction stoppen ALLE Layers des T-Stems uniform am Near-Face
der Through-Wand (uniformer T-Miter pro Wand).
Neu: per-Schicht Logik im _make_wand_layer_breps:
- T-Stem-Schicht mit Material das in Through-Wand auch vorkommt → Layer-Axis
extends um through_dicke/2 → Layer durchstoesst Through-Wand bis zur
Far-Face → visuell verbunden, kein sichtbarer Joint
- Schicht ohne Material-Match in Through-Wand → standard T-Miter, stoppt
am Near-Face
Beispiel "Aussenwand 30cm" (Beton/Daemmung/Putz) T auf gleicher Aussenwand:
alle 3 Schichten matchen → durchgehend gemerged.
Beispiel "Aussenwand 30cm" T auf "Beton solid 15cm":
- T-Stem Beton matched (Through-Solid hat Beton via Style) → durchstoesst
- T-Stem Daemmung/Putz: kein Match → stoppen am Through-Beton-Aussenkante
Implementation:
- _make_wand_layer_breps: per_layer_ext_start/end + per_layer_miter_start/end
- _t_junction_layer_overrides(doc, my_meta, through_meta, ...): baut die
per-Layer Overrides via Material-Set-Lookup. Solid through wird via
_wand_solid_material auf Style-Material aufgeloest.
- Regen-Pfad: t_junction_start/end speichern (oid+tan+dicke+ep+out_dir),
vor _make_wand_layer_breps die Overrides bauen.
Bisher konnte dJoin nur L-Verbindungen herstellen (zwei Endpunkte zum
Schnittpunkt der verlaengerten Tangenten ziehen). Neu auch T-Verbindungen:
_t_join_attempt: pro Endpunkt-Kombination wird der naechste Punkt auf der
ANDEREN Curve gesucht. Wenn distance < 20cm UND nicht nahe deren Endpunkt
(= waere L-Sache) → snap diesen Endpunkt exakt auf die Curve. Die andere
Curve bleibt unveraendert (= Through-Wand stays).
_run: T-Join wird ZUERST probiert (spezifischer), L-Join als Fallback.
UX: User selektiert 2 Waende die fast aber nicht ganz verbinden →
Cmd+J (dJoin) → System erkennt T- oder L-Konfig und snappt entsprechend.
Predictable + intentional, kein auto-snap-Magic mehr.
User-Feedback: bei vielen Waenden im Layout wurde unklar wann sich Wand-
Endpunkte automatisch verbinden und wann nicht. Auto-Snap auf Move/Mirror
machte das Verhalten unvorhersehbar.
Jetzt zurueck zum Standard-BIM-Workflow:
- Wand-Endpunkte verbinden sich NUR wenn User explizit Rhino's End/Mid-
Snap nutzt (oder das L-Join in dJoin)
- T-Junction-Detection bleibt 1mm-tight → praezise Geometrie erforderlich
- Joint-Rolle (auto/durchgehend/anstossend) regelt weiterhin wer am
geprueften T-Stoss durchgeht
Helper _snap_endpoint_to_other_wand_axis bleibt — fuer evtl. spaetere
explizite Connect-Befehle.
Neues UserString-Feld 'dossier_wand_joint_rolle' per wand_axis:
- 'auto' (default): bisherige Logik. Bei beidseitig auto entscheidet die
Style-Prio (hoehere = durchgehend)
- 'durchgehend': diese Wand ueberschreibt → ich gehe durch, T-Miter wird
NICHT auf mich angewendet
- 'anstossend': diese Wand stoppt immer am Joint, auch wenn ich Prio-haerter waere
T-Junction-Detection in regen ruft jetzt _wand_should_apply_t_miter:
- my.rolle entscheidet zuerst
- bei my=auto: through.rolle entscheidet
- bei beide=auto: Prio-Vergleich (hoehere Prio = durchgehend)
- Default: T-Miter applied (= ich stoppe am Through)
Frontend: neue Dropdown 'Joint' in WallProperties zwischen Stil und Aufbau:
- Auto (Prio entscheidet)
- Durchgehend
- Anstossend
Backend-Pipeline: _attach_meta + _read_meta um wand_joint_rolle erweitert,
state-JSON sendet 'jointRolle', _update_wall_body handhabt jointRolle-Patch.
Cluster-Dispatch: is_layered_meta Check zurueck — layered + non-linear (T,
Verzweigung) ist geometrisch sinnlos via per-Layer-Union (Schichten orthogonal
zwischen perpendikulaeren Waenden). Faellt zu Solo+Miter durch.
dWall-Prompt:
- Neue Option 'Aufbau' (Solid|Mehrschichtig)
- Stil-Liste gefiltert auf den gewaehlten Aufbau-Typ
- Beim Toggle: erster Style des neuen Typs uebernommen + dicke/referenz
- Default-Aufbau aus dem zuletzt verwendeten Style
Bug: nach _Delete einer Wand blieben die Hilfslinien (Centerline, Outline)
als Orphan-Curves stehen. _find_all_volumes filtert nur VOLUME_TYPES, in
denen Centerline/Outline nicht sind.
Fix: bei wand_axis-Delete-Event zusaetzlich alle wand_centerline/wand_outline
Curves mit derselben wall_id ID-Liste ergaenzen → nach 500ms cascade-delete
raeumt sie mit weg.
Layered Cluster + per-Layer BooleanUnion via _build_cluster_layered_breps
+ erweiterter _regen_cluster_anchor sind im selben commit drin (siehe
diff vor diesem Bugfix).
Bisher: bei jedem Project-Settings-Save wurden ALLE wand_axis im Doc regenert
(auch wenn nichts wand-relevantes geaendert wurde, z.B. nur ein Default-Wert
oder ein Library-Eintrag).
Jetzt: Diff der wand_styles + materials vor/nach Save. Sammle nur die Waende
die einen geaenderten Style nutzen ODER ein geaendertes Material (direkt via
Style oder als Schicht in layered Wand). Regen nur diese.
Plus: Joint-Cache-Batch-Flag waehrend des Regens setzen (war im sync-Pfad
sonst pro Regen invalidiert worden → unnoetiger Overhead).
Log zeigt jetzt z.B. "3 Waende regenert (1 Stile, 2 Materials geaendert)"
statt blind "N Waende regenert".
Beim install_listeners() werden dummy Curve.Offset, Extrusion.Create und
Brep.CreateBooleanUnion/Difference Aufrufe gemacht damit der lazy-loaded
native code geladen ist. Soll den First-Call-Lag bei der ersten echten
Wand-Operation reduzieren.
In der Praxis hilft das bei der Tech-Drawing-Failure nicht (das ist eine
Rhino-interne Limitation der Hidden-Line-Analyse die mit rapid brep
Delete+Add nicht klar kommt) — aber schadet auch nicht und kann andere
Cold-Start-Edge-Cases verbessern.
Bug: Beim Verbinden/Trennen zweier Waende via Move (= synchroner Replace-
Event-Pfad) lief jeder _regenerate_element-Call ohne den
_dossier_regen_batch_active Flag → jeder Regen invalidierte den Joint-Cache
neu (O(N²) Rebuilds) → Rhinos Technical-Drawing-Analyse choked →
"Switching all technical views to wireframe display".
Fix: Im post-Command Regen-Loop (line ~17285) den Flag setzen + Cache
einmal invalidieren bevor die affected_walls durchlaufen. Pattern analog
zur Idle-Batch-Logik die das schon hatte.
Outline + Centerline wieder aktiviert — waren nicht der Schuldige.
Die Outline-Curves lagen exakt auf z=0 wie die unteren Brep-Edges. Rhinos
Technical-Drawing Hidden-Line-Analyse choked nach jedem Regen mit Duplikat-
Linien → wireframe-Fallback.
- _regen_wall_lines.outline branch auskommentiert
- _migrate_strip_wand_outlines_once raeumt existierende wand_outline-Curves
beim naechsten Doc-Open weg
- Centerline (offset, dashed, locked) bleibt — kein Edge-Overlap
Wenn Outline-Visualisierung wieder gewollt: via Display-Conduit (visual-only,
keine Tech-Drawing-Interferenz).
Backend
- wand-State enthaelt jetzt styleId (aus _KEY_WAND_STYLE_ID)
- STATE-Payload sendet wandStyles (analog oeffStyles)
- _update_wall_body handhabt styleId-Patch: bei Stil-Wechsel uebernimmt die
dicke aus dem Stil (wenn nicht explizit im selben Patch ueberschrieben);
wand_style_id wird per _attach_meta auf die Achse persistiert
Frontend
- WallProperties bekommt wandStyles-Prop + zeigt Stil-Picker zwischen
Geschoss und Aufbau (nur wenn Stile vorhanden)
- Dropdown: "kein Stil" + alle definierten Stile mit (dicke, prio)
- PropertiesView + ElementeApp + ElementePropertiesApp propagieren wandStyles
Outline + Centerline
- Outline-Curves (geschlossenes Viereck) jetzt fuer ALLE Waende (auch
Cluster/Chain-Member) — in_cluster-Flag suppressed Outline nicht mehr
- Mode = Normal (statt Locked) damit ObjectColor (Petrol #5fa896) durchschlaegt
und doc.Objects.Replace bei Pure-Transform funktioniert
- Trade-off: User kann Hilfslinien greifen, aber jeder Axis-Regen schreibt sie
neu (selbst-korrigierend)
Pure-Transform Sync
- wand_centerline + wand_outline werden im Pure-Transform-Pfad explizit
mit-transformed (vorher nur SOURCE_TYPES + VOLUME_TYPES → Linien blieben
in alter Position haengen)
Selection Pairing
- wand_axis zurueck in _PAIRED_SOURCE_TYPES → Achsen-Klick selektiert
Outline + Centerline mit (alle "Referenzlinien" leuchten zusammen auf)
- _collect_partners special-case fuer wand_axis: NUR Hilfslinien als Partner,
NICHT das Volume (sonst wuerde das ganze Brep mit-aufleuchten)
- wand_volume Pairing wie bisher: Volume-Klick → Achsen + Centerlines +
Outlines aller Cluster-Members
Bisher griff der Schrittmass-Clamp nur bei treppe_art=='gerade'.
Fuer L-Treppen jetzt:
- gp2 (Eck-Klick): clampt erste Lauf-Laenge auf [1-Stufe-min, (n-1)-Stufen-max]
- gp3 (End-Klick): schaetzt N1 aus erster Lauf-Laenge, clampt zweiten Lauf
auf den S/A-konformen Bereich (mit cut_back kompensiert)
Volume-Fix _make_treppe_l_volume:
- cut_back am Eckpunkt war hardcoded half_b (= passt nur fuer Lage=mid).
Fuer Lage=links/rechts wird die FULL breite cut-back gebraucht — sonst
ueberlappen die Lauf-Volumen am Eckpunkt mit dem Podest falsch.
Fix: cut_back = half_b if mid else breite.
User-Feedback: L-Treppe bleibt 3-Punkt-Polyline (Start/Eck/End), Podest
ergibt sich aus dem Eckpunkt + Breite. Aber Referenz darf nie 'mid'
sein — sonst kollidieren die Laeufe am Eck. Constraint:
- _update_wall: bei treppe_art=='l' und tref=='mid' → 'links' erzwungen
- Frontend: REF_OPTIONS filtert 'mittig' raus wenn treppeArt=='l'
Dead-Code: _l_segments + _aussen_l_polygon + _lauflinie_l + _make_treppe_l_volume
behalten 4-Punkt-Handling als optionalen Pfad (gerade nicht erreicht weil
Creation immer 3-Punkt produziert) — schaden nicht, koennen spaeter
wieder aktiviert werden wenn Podest-als-Segment doch gewuenscht.
Schlafsession-Status: Trittmass-Lock + Lauflinie zentriert + Pfeile +
Cmd+Z + Pure-Transform fuer hidden Layer = alles in main.
_line_intersect_xy lieferte Z=0 was nicht zum Polygon-Z (=OKFF) passte,
PolylineCurve mit gemischten Z konnte fehlschlagen → 2D-Generierung
broken fuer L-Treppen. Fix: _at_z(p, fallback) Helper setzt Z explicit.
Plus try/except um die ganze Polygon-Konstruktion — Fallback auf
2-Rechteck-Variante bei Fehler.
Cmd+Z:
- _update_wall wrapped in BeginUndoRecord/EndUndoRecord — sodass
Property-Patches + Regen-Delete/Add als ein Undo-Schritt rueckgaengig
L-Treppe Aussenlinie:
- _aussen_l_polygon: sauberes 6-Punkt L-Polygon mit korrekt projizierten
Ecken (Outer + Inner via Linien-Schnitt der mid-versetzten Seiten)
- _aussen_l: nutzt Polygon wenn kein Cut, faellt sonst zurueck auf
per-Lauf Rechtecke mit Diagonal-Cut (wie bisher)
L-Treppe Lauflinie:
- ueber BEIDE Laeufe, mid-perp versetzt, Pfeil am Treppen-Ende
- Eck-Mitte als Linien-Schnitt der zwei versetzten Schaft-Linien →
sauberer Übergang auch bei Lage=links/rechts (kein Versatz an der Ecke)
- 'voll'-Pfeil-Style mit wide-Offsets relativ zur Lauflinie
Wendel-Treppe:
- _lauflinie_wendel: 'voll'-Pfeil-Style mit r_inner/r_outer-Spitzen
relativ zu r_mid (Radial-Offsets)
Trittmass-Lock auf alle Treppen-Arten:
- L: Beide Laeufe proportional skalieren (ratio = N*target_A / (L1+L2))
- Wendel: Sweep-Winkel anpassen (new_delta = sign × N*target_A/r_mid)
- Axis-Geometrie wird in-place via Replace ausgetauscht — Source moves
fliessen in regulären Regen-Pfad ein
Properties-Panel:
- Konsistentes 50px/1fr/14px Grid fuer alle Treppen-Rows
- Lage + Unten als Dropdown (lowercase Labels)
- Versatz: Dropdown (Geschoss-OKFF) oder eigenes Z mit Input + x-Button
- Ziel: gleich (Geschoss-Liste oder eigene Hoehe), Geschosse-Filter
excludes das Start-Geschoss
- Start-Dropdown filtert auf okff < Ziel-Z (kein hoeheres Geschoss als
Start waehlbar, beachtet auch eigene-Hoehe-Ziel)
- Stufen: Dropdown 2-40 (statt freie Eingabe), mit Lock nur S-konforme
Werte
- Dropdowns nutzen System-Font (statt mono)
- Ausgrenzung 'Aussenlinie'-Toggle (Aussenlinie immer an)
- Pfeil-Style-Dropdown unter Lauflinie-Checkbox: klassisch / gefuellt
(Solid-Hatch) / breit / voll (Spitzen bis Treppen-Aussenkanten)
Backend Treppe:
- Start-Z-Override via treppe_uk_over (m Offset relativ zu Geschoss-OKFF)
- 2D-Symbol bleibt auf OKFF (egal ob Versatz) — Symbol klebt am Boden
- Lauflinie-Schaft auf visuellen Treppen-Mittelpunkt versetzt
(bei Lage=links/rechts), nicht mehr auf der Referenz-Achse
- Trittmass-Lock: treppe_lock_s + target_S/A. Beim Aktivieren werden
S+A als Ziel gespeichert. Bei H-Change wird N=round(H/target_S)
recomputed + Axis-Laenge auf N*target_A angepasst (gerade Treppen)
- Bruchsymbol-Toggle aus: ganze Treppe ungesplittet zeichnen
(eff_cut_h=0 → kein Lower/Upper-Split)
- Treppen-Endpunkt-Marker (treppe_grips.py) — gruene Punkte an Start/
Ende der Lauflinie, beachtet treppe_art (Wendel: poly[1]/poly[2])
Verdoppelungs-Fix:
- _find_target_volume skipt treppe_2d_symbol explicit (sind 2D-Curves,
kein Volume). Vorher konnte Replace(curve, brep) fehlschlagen → das
echte Treppen-Brep blieb stehen + neues kam dazu → Duplikat
- _find_objects_by_wall_id mit HiddenObjects+LockedObjects-Iterator,
findet auch Objs auf hidden 3D-Layer
- Anti-Dup-Cleanup in _regenerate_element: bei mehreren treppe_volume
mit gleicher element_id → alle ausser dem ersten loeschen
State-Pipeline:
- geschosse-Liste enthaelt jetzt okff+hoehe (fuer Frontend-Constraints)
- Treppe-State neu: ukOver, arrowStyle, lockS, targetS, targetA
- Hidden-Source-Fallback in _send_state findet auch Treppen wenn der
3D-Layer aus ist (sodass Properties-Panel angezeigt wird)
Dimensionen-Panel:
- on_select + on_idle skippen waehrend Partnership-Cascade oder
User-Transform — kein Flicker mehr beim Drag
Andere:
- Wand-Polyline-Vertex-Grips (alle Vertices, nicht nur Enden)
- PopupMenu unterstuetzt _divider + checked-Items
- TREPPEN/RAEUME Layer-Migration auf Capital-Case
- selection-partnership tolerant: hidden Source wird trotzdem in die
Selection genommen (sonst kann Drag nicht durch Pure-Transform)
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
User-Bug: Layout-Skip-Optimierung war zu aggressiv — Mac Rhino haelt die
Panel-Anordnung zwischen Sessions doch nicht im internen State, also
wurden Panels falsch platziert nach Quick-Restart. Skip-Logik raus, der
~3s _-WindowLayout-Apply laeuft wieder jedes Mal. Das ist OK weil der
Splash diese Wartezeit jetzt optisch abdeckt.
Splash verbessert:
- _try_borderless_mac(): direkter NSWindow-Zugriff via Eto.ControlObject
+ ObjC-Methoden (setStyleMask_, setOpaque_, setHasShadow_,
setBackgroundColor_, setMovableByWindowBackground_) — produziert
echten borderless Mac-Look wie der Launcher-Splash
- Form-BackgroundColor auf transparent damit das gradient des WebView-
HTMLs durchscheint (rounded petrol gradient mit weichem Verlauf)
- WebView selber transparenter Hintergrund
- Closeable/Minimizable/Maximizable/Resizable alle False
- [SPLASH] visible log fuer Debug-Sichtbarkeit
Verdeckt visuell die 3+ Sekunden Wartezeit beim Cold-Start (Panel-
Registration + WindowLayout-Apply). Stilistisch identisch zum
Launcher-Splash: petrol-gruener Verlauf mit "DOSSIER."-Logo, pulsierendem
Dot, animierter Progress-Bar.
Architektur:
- _startup_splash.py: zentrale show() / hide() Helpers
- Borderless Eto.Forms.Form (420x160), Topmost, kein Taskbar-Eintrag
- WebView mit Inline-HTML (gleicher Stil wie launcher/public/splash.html)
- Sticky-Key _dossier_startup_splash haelt die Form-Referenz
- Safety-Timeout 8s falls hide() vergessen wird
- startup.py _load_all: show() ganz am Anfang (bevor Imports laufen)
- oberleiste._on_ready: hide() via 200ms-Timer NACH window-layout-apply
(bzw. nach skip) — Layout-Animation ist auf Panels in Finalposition
kurz sichtbar bevor Splash verschwindet
Effekt: User sieht sofort einen schoenen Branded-Loading-Screen statt
3s grauer Rhino-UI mit halb-geladenen Panels.
Diagnose-Log zeigte: 3046 ms (= 93% der 3.3s Cold-Start-Zeit) gehen
allein in den _-WindowLayout RunScript-Call beim ersten oberleiste-
_on_ready. Rhino dockt dabei alle Panels neu — teuer.
Optimierung: Marker-File-basiertes Skip
- Nach erfolgreichem Apply: ~/Library/Application Support/
ch.gabrielevarano.Dossier/layout_marker.json mit Timestamp + Name
- Bei _on_ready: wenn Marker < 10 min alt UND derselbe Layout-Name →
skip (Rhino "remembers" die Panel-Positionen meistens noch im
internen State, nur unzuverlaessig zwischen LANGEN Pausen)
- Sonst (kalter Tag, langer Reboot, anderer Name): apply normal
Effekt fuer typischen Dev-Workflow (haeufige Quick-Restarts):
- Erster Restart heute: 3s Apply (wie bisher) + Marker
- Naechste Restarts < 10 min spaeter: ~0ms (skip)
- Nach Pause > 10 min: erneuter Apply
Helpers _is_layout_recently_applied + _mark_layout_applied. Marker
wird auch geschrieben wenn User manuell apply (z.B. via Settings-
Dialog oder Launcher pendingApplyLayout) → konsistent.
Falls Layout doch falsch ist nach Skip: Oberleiste-Settings →
"Jetzt anwenden"-Button erzwingt Apply.
Bisher: Wall-time 3.2s vs gemessene Arbeit 0.9s → 2.3s unmeasured.
Jetzt werden auch die bisher blinden Stellen getrackt:
- 9× Modul-Import (rhinopanel, oberleiste, ausschnitte, ...) als
phase="import", label=mod_id
- oberleiste display-mode-Ensure-Loop (4× DisplayModeDescription-Calls)
als phase="display_modes"
- _apply_window_layout RunScript-Sequenz als phase="window_layout"
- text_editor doppelklick-Hook + view-modes assign + unit-check als
post_init/hook Phases
Nach Reload sollte das Summary zeigen wo die 2.3s versickern → daraus
gezielte Optimierungen.
Download-Button (file_download Icon) neben den Expand/Collapse-Buttons
in der Toolbar. Klick → SaveFileDialog (Default 'sia_bilanz.csv') →
schreibt Excel-kompatible CSV.
Backend (elemente_uebersicht._export_bilanz):
- Wide-Format: Spalten = Kategorie + ein Geschoss + Total
- Zeilen: HNF, NNF, NF, VF, FF, NGF, GF, AGF, Räume (count), Personen
- Werte via _elm.compute_sia_bilanz fuer jeden Scope (gleiche Logik
wie Bilanz-Stempel + Uebersicht — single source of truth)
- Format: Semikolon-Separator + UTF-8 BOM + Komma als Dezimaltrenner
(Excel CH/DE-kompatibel, oeffnet ohne Umweg)
- Flaechen mit 2 Nachkommastellen, Raume/Personen als int
Architekten-Workflow: bei Schulen/Buero/Versammlungsstaetten muss die
Personenzahl pro Raum erfasst werden (SIA: m²/Person als Indikator).
Backend:
- UserString dossier_raum_personen (int)
- _attach_meta + _read_meta + state-emit
- _update_wall raum-Branch akzeptiert "personen" im Patch
- compute_sia_bilanz aggregiert personen-Summe ueber Scope
- Stempel: neue Show-Flag stempel_show_personen (default false) +
Bilanz-Renderer-Zeile "N Personen"
- Stempel-Stil-Field showPersonen mit dabei
Frontend (RaumProperties):
- Personen-Input (number, min 0) zwischen Funktion + Layout-Builder
- Nur sichtbar bei normalen Raeumen (nicht GF/AGF)
- Live-Anzeige "m²/Person" Suffix wenn area + personen > 0
→ User sieht sofort ob die Belegung sinnvoll ist (SIA-Vergleich)
Frontend (StempelProperties):
- Neuer Show-Toggle "Personen" (default off)
- Live-Vorschau zeigt Personen-Summe wenn aktiv + > 0
- _OFF_BY_DEFAULT Set generalisiert Default-Handling (showCount, showPersonen)
Doppelbelegung Code 60: alte Konvention "Plangrafik" steht im Weg fuer
die neuen Raum-Layer (RAEUME 60, GF 61, AGF 62). Wenn ein Doc beides
hat, fiel die Auto-Add-Logik in _find_ebene_sublayer_name aus → Raeume
landeten auf Rhino-Layer "60_RAEUME" der aber im Dossier-Ebenen-Panel
nie auftauchte (dort stand 60 = Plangrafik).
Fix in zwei Teilen:
1) Frontend-Default-Schema (App.jsx INITIAL_EBENEN):
- 60: RAEUME (neu, fuer HNF/NNF/VF/FF)
- 61: GF (Geschossflaeche)
- 62: AGF (Aussengeschossflaeche)
- 80: Plangrafik (verschoben von 60)
2) One-shot Migration in elemente._migrate_plangrafik_60_to_80_once():
- Detect: dossier_ebenen hat code=60 + name=Plangrafik
- Action: code 60 → 80, RAEUME/GF/AGF auf 60/61/62 hinzufuegen
- Rhino-Layer rename: alle "60_Plangrafik" Layer → "80_Plangrafik"
- build_layers + broadcast_state → Ebenen-Manager UI aktualisiert
- Sticky-Flag verhindert Re-Run
Plus kleinerer UX-Fix: Skala-Dropdown-Labels gekuerzt
("fix (m)" / "massstaeblich (mm)" statt langer Beschreibungen).
Geschossflaeche (GF) und Aussengeschossflaeche (AGF) sind reine
Flaechen-Ausweisungs-Outlines — keine Raeume mit Name/Nummer/Funktion.
Backend:
- Neue Layer-Helpers _layer_path_raum_gf (61_GF) und _layer_path_raum_agf
(62_AGF) — eigene Sublayer pro Geschoss, eigene Default-Farben
- _layer_path_for_raum_sia(doc, gname, sia): routet sia=gf → GF-Layer,
sia=agf → AGF-Layer, sonst RAEUME-Layer (HNF/NNF/VF/FF/leer)
- _regenerate_element_body raum_outline-Branch nutzt das Routing →
Source-Outline migriert automatisch auf den richtigen Layer
- _update_wall raum-Branch: bei SIA-Wechsel (z.B. HNF → GF) auch
Layer-Migration
- _make_raum_stamp_text: bei sia=gf/agf default-layout
override auf [["sia", "area"]] → Stempel zeigt nur "GF 234.5 m²" /
"AGF 18.0 m²" ohne Nummer/Name/Funktion
Frontend (RaumProperties):
- Conditional isFlaeche = sia in (gf, agf)
- Versteckt bei isFlaeche: Stil-Picker, Nummer-Input, Name-Input,
Funktion-Input, StempelLayoutBuilder
- Bleibt sichtbar: Geschoss, SIA-Tag-Selector, Fuellung, Rundung,
Skala-Modus, Flaeche/Umfang-Footer
- Info-Zeile zeigt bei isFlaeche: "Flaechen-Outline (GF) auf eigenem
Layer · Stempel zeigt nur GF + Flaeche"
Neuer Element-Type "stempel" — TextEntity die automatisch eine SIA-416
Bilanz aggregiert und im Plan platziert wird. Re-rendert sich live wenn
sich Raeume im Scope aendern.
Backend (elemente.py):
- Neue SIA-Tags: GF (Geschossflaeche), AGF (Aussengeschossflaeche)
mit eigenen Labels + Pastell-Farben in _SIA_COLORS_HEX
- "stempel" als SOURCE_TYPE; eigene UserStrings:
- stempel_scope: "total" | "geschoss:<gid>"
- stempel_txt_h, stempel_font, stempel_bold, stempel_italic
- compute_sia_bilanz(doc, scope): aggregiert nach SIA-Tags, liefert
HNF/NNF/VF/FF/GF/AGF + abgeleitet NF/NGF/count + Scope-Label
- _format_bilanz_lines: kompakte Stempel-Textzeilen ("HNF 120.5 m²"),
Trennlinien + nur Kategorien > 0
- _make_stempel_text: TextEntity-Builder mit Header "Nutzflächen · {Scope}"
- _regenerate_element_body "stempel"-Branch: in-place Replace mit
aktualisiertem Text (Position bleibt aus alter Geometrie)
- _regenerate_stempel_for_geschoss: regennt alle Stempel im selben
Geschoss + alle "total"-Stempel
- Auto-Cascade: raum_outline-Regen setzt sticky-marker; nach REGEN_BUSY-
Release wird _regenerate_stempel_for_geschoss aufgerufen
- _cmd_create_stempel: GetPoint im Viewport, layer = aktives Geschoss
Raum-Sublayer, default-Scope = aktives Geschoss
- _update_wall "stempel"-Branch: scope/txtH/font/bold/italic via patch
- elemente_uebersicht: SIA-Bilanz um gf/agf/ngf erweitert; "stempel"
als KIND-Eintrag
Frontend:
- createStempel-Bridge-Export
- "Stempel"-Pill-Button in der "Raeume"-PillGroup
- StempelProperties-Component: Scope-Dropdown (Total + alle Geschosse),
Bilanz-Vorschau mit Hervorhebung der NF (Accent-Farbe)
- KIND_META + RAUM_SIA_KINDS um GF/AGF erweitert
Workflow: Pill "Stempel" klicken → Punkt im Viewport → Stempel erscheint
mit Header "Nutzflächen · EG" + Bilanz. Properties: Scope auf Total
umstellen oder anderes Geschoss waehlen. Neue Raeume taggen mit SIA-
Tag → Stempel aktualisiert sich automatisch.