Schnitt/Ansicht-Feature + Terrain-Volumen + Geschoss-Add-Dialog
Schnitt-Feature V1+V2: - Neues rhino/schnitte.py mit Pick-Workflow, Activation (Clipping-Planes + Parallel-View), 2D-Plan-Symbol auf 18_Schnittlinien-Sublayer - Doppelklick auf Symbol aktiviert den Schnitt - Schnitt-Settings (cutAtLine/Tiefe/Höhen/Blickrichtung) im GeschossSettingsDialog - View-Snapshot + Restore beim Wechsel Schnitt → Geschoss - Symbol-Cleanup bei Delete via normalem Ebenen-Menü Terrain als Volumen: - swisstopo.volumize_terrain_object: Skirt + Bottom-Cap auf Mesh/Brep damit Clipping-Planes gefuellte Querschnitte erzeugen - UI im SwisstopoApp mit Nachbearbeitung-Section + Tiefen-Eingabe Geschoss-Add mit Dialog: - + im GeschossManager oeffnet 3-Optionen-Picker (Geschoss/Schnitt/Zeichnung) - Geschoss-Dialog mit Anker-Dropdown, Position über/unter, Auto-Name, Höhen-Prefill aus Anker Fix: _send_state fallback — Element gilt als selektiert wenn Source ODER Volume in der Selection ist (robust gegen Layer-Visibility wenn Referenz- linien-Layer im aktuellen Mode versteckt ist) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
+58
-1
@@ -657,6 +657,16 @@ def _layer_path_referenz(doc, geschoss_name):
|
||||
return "{}::{}".format(geschoss_name, sub)
|
||||
|
||||
|
||||
def _layer_path_schnittlinie(doc, geschoss_name):
|
||||
"""Sublayer 'Schnittlinien' (Code 18) — fuer die 2D-Plan-Symbole von
|
||||
Schnitten/Ansichten. Eigene Ebene damit der User sie unabhaengig vom
|
||||
Restplan ein-/ausblenden kann. Konvention SIA: dunkle Linie + Pfeile."""
|
||||
sub = _find_ebene_sublayer_name(doc, ["schnittlinie", "schnittlinien"],
|
||||
"18", "Schnittlinien",
|
||||
default_color="#404040", default_lw=0.35)
|
||||
return "{}::{}".format(geschoss_name, sub)
|
||||
|
||||
|
||||
def _ensure_oeff_ebenen_in_doc(doc):
|
||||
"""Registriert die Oeffnungen-Ebene + alle Piece-Children im
|
||||
`dossier_ebenen`-JSON-Tree (als Children der WAENDE-Ebene). Damit
|
||||
@@ -5551,6 +5561,23 @@ class ElementeBridge(panel_base.BaseBridge):
|
||||
self.send("STATE", {"elements": [], "geschosse": [], "selection": None})
|
||||
return
|
||||
geschosse = _load_geschosse(doc)
|
||||
# Vorpass: alle Element-IDs sammeln deren Source ODER irgendein
|
||||
# Volume gerade selektiert ist. Macht die Selection-Detection
|
||||
# robust gegen Layer-Visibility-Edge-Cases: wenn die Source-Curve
|
||||
# auf einem hidden Layer liegt (z.B. Referenzlinien ausgeblendet
|
||||
# oder im "Nur aktive"-Visibility-Mode), wuerde der Partner-Sync
|
||||
# in _on_select_objects das Source-Objekt nicht selektieren
|
||||
# koennen — der User klickt aber das sichtbare Volume an, also
|
||||
# ist die Element-Auswahl trotzdem eindeutig.
|
||||
sel_eids = set()
|
||||
try:
|
||||
for o in doc.Objects.GetSelectedObjects(False, False):
|
||||
m = _read_meta(o)
|
||||
if not m: continue
|
||||
t = m.get("type")
|
||||
if t in SOURCE_TYPES or t in VOLUME_TYPES:
|
||||
sel_eids.add(m["id"])
|
||||
except Exception: pass
|
||||
# Alle Source-Objekte (Achsen + Outlines) durchgehen
|
||||
elements = []
|
||||
seen_ids = set()
|
||||
@@ -5562,7 +5589,7 @@ class ElementeBridge(panel_base.BaseBridge):
|
||||
seen_ids.add(meta["id"])
|
||||
g = _geschoss_by_id(doc, meta["geschoss"])
|
||||
geschoss_name = g.get("name", "?") if g else "?"
|
||||
selected = obj.IsSelected(False) > 0
|
||||
selected = (meta["id"] in sel_eids) or (obj.IsSelected(False) > 0)
|
||||
base = {
|
||||
"id": meta["id"],
|
||||
"objectId": str(obj.Id),
|
||||
@@ -7968,6 +7995,13 @@ class ElementeBridge(panel_base.BaseBridge):
|
||||
except Exception as ex:
|
||||
self._push_log("Grid-Merge fehlgeschlagen: {}".format(ex))
|
||||
|
||||
# Terrain-Volumize-Option: aus Opts lesen. depth in
|
||||
# METERN aus UI → in Doc-Units konvertieren.
|
||||
as_volume = bool(opts.get("terrainAsVolume"))
|
||||
try: vol_depth_m = float(opts.get("terrainVolumeDepth") or 10.0)
|
||||
except Exception: vol_depth_m = 10.0
|
||||
vol_depth_doc = max(0.01, vol_depth_m) * m_to_unit
|
||||
|
||||
# 3D-Mesh bauen wenn Terrain gewuenscht — unabhaengig vom
|
||||
# Ortho. Wenn Ortho auch an ist: Drape-Mesh liegt ueber
|
||||
# dem Plain-Mesh (User togglet im Layer-Panel was er
|
||||
@@ -7982,6 +8016,11 @@ class ElementeBridge(panel_base.BaseBridge):
|
||||
mesh.Vertices.Count, mesh.Faces.Count))
|
||||
gid = d.Objects.AddMesh(mesh)
|
||||
obj = d.Objects.Find(gid)
|
||||
if obj and as_volume:
|
||||
vol_obj = swisstopo.volumize_terrain_object(
|
||||
d, obj, vol_depth_doc,
|
||||
progress=self._push_log)
|
||||
if vol_obj is not None: obj = vol_obj
|
||||
if obj: mesh_objects.append((obj, merged_grid["bbox"]))
|
||||
except Exception as ex:
|
||||
self._push_log("Mesh-Bau fehlgeschlagen: {}".format(ex))
|
||||
@@ -8059,6 +8098,11 @@ class ElementeBridge(panel_base.BaseBridge):
|
||||
m_to_unit=m_to_unit,
|
||||
progress=self._push_log)
|
||||
if tin_obj:
|
||||
if as_volume:
|
||||
vol_obj = swisstopo.volumize_terrain_object(
|
||||
d, tin_obj, vol_depth_doc,
|
||||
progress=self._push_log)
|
||||
if vol_obj is not None: tin_obj = vol_obj
|
||||
# Tag + auf 80_swisstopo Parent
|
||||
at = tin_obj.Attributes.Duplicate()
|
||||
at.SetUserString("dossier_swisstopo_kind", "contour_tin")
|
||||
@@ -8100,6 +8144,11 @@ class ElementeBridge(panel_base.BaseBridge):
|
||||
patch_obj = swisstopo.generate_patch_from_contours(
|
||||
d, raw_contours, progress=self._push_log)
|
||||
if patch_obj:
|
||||
if as_volume:
|
||||
vol_obj = swisstopo.volumize_terrain_object(
|
||||
d, patch_obj, vol_depth_doc,
|
||||
progress=self._push_log)
|
||||
if vol_obj is not None: patch_obj = vol_obj
|
||||
at = patch_obj.Attributes.Duplicate()
|
||||
at.SetUserString("dossier_swisstopo_kind", "contour_patch")
|
||||
d.Objects.ModifyAttributes(patch_obj, at, True)
|
||||
@@ -11496,6 +11545,14 @@ def _install_listeners(bridge):
|
||||
"cmd_end": _on_command_end,
|
||||
}
|
||||
print("[ELEMENTE] Listener aktiv (Replace + Add + Delete + Select + Idle + Cmd)")
|
||||
# Schnitt-Doppelklick-Handler global registrieren — idempotent via
|
||||
# sticky-Flag im schnitte-Modul, mehrfache Aufrufe bei Re-Loads
|
||||
# raeumen den alten Handler vorher weg.
|
||||
try:
|
||||
import schnitte
|
||||
schnitte.install_double_click_handler()
|
||||
except Exception as ex:
|
||||
print("[ELEMENTE] schnitt dblclick install:", ex)
|
||||
|
||||
|
||||
def _bridge_factory():
|
||||
|
||||
Reference in New Issue
Block a user