Symbol-Funktion in Elemente-Panel (Phase S1+S2)
Schema (library.py): - Item-Format erweitert: files2d + files3d (Backwards-compat zu 'files') - _build_variant_block + _place_instance + Layer-Routing pro Variante - import_item akzeptiert at_point + layer2d/layer3d - _ensure_block_definition mit variant-Suffix (dossier_lib_<id>_2d/_3d) Backend (elemente.py): - _layer_path_symbole(geschoss_name, variant) → <geschoss>::40_SYMBOLE:: SYMBOLE_2D bzw. SYMBOLE_3D - Default-Ebene 40 SYMBOLE via _find_ebene_sublayer_name - LIST_LIBRARY-Handler: sendet Library-Manifest als LIBRARY_LIST - CREATE_SYMBOL-Handler: interactive GetPoint im aktiven Viewport, laedt Block-Def + platziert Instanz(en) auf den richtigen Ebenen - Pair-Items (2D+3D) werden an gleichem Punkt beidseitig platziert → Top zeigt 2D-Layer, Persp zeigt 3D-Layer wenn User entsprechend Sichtbarkeit setzt Frontend: - SymbolPicker Modal-Component: Grid mit Symbol/Object-Cards, Search, Type-Filter (Alle/Symbole/Objekte), Doppelklick = Pick - Symbol-Button in ElementeApp (PillGroup "Library") oeffnet Modal + triggert listLibrary() fuer aktuelle Items - createSymbol(id) → Backend → GetPoint → Place Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -929,6 +929,20 @@ def _layer_path_raum(doc, geschoss_name):
|
||||
return "{}::{}".format(geschoss_name, sub)
|
||||
|
||||
|
||||
def _layer_path_symbole(doc, geschoss_name, variant):
|
||||
"""Symbol-Layer (Library-Items). variant = '2d' oder '3d'.
|
||||
Pfad: <geschoss>::40_SYMBOLE::SYMBOLE_2D bzw. SYMBOLE_3D.
|
||||
User kann die Top-Level-Ebene 40 frei rein-/raus-schalten — die
|
||||
Sub-Layer 2D/3D regeln View-spezifische Sichtbarkeit (Top zeigt 2D,
|
||||
Persp zeigt 3D)."""
|
||||
sub = _find_ebene_sublayer_name(doc, ["symbol"],
|
||||
"40", "SYMBOLE",
|
||||
default_color="#5fa896", default_lw=0.13)
|
||||
if variant.lower() == "3d":
|
||||
return "{}::{}::SYMBOLE_3D".format(geschoss_name, sub)
|
||||
return "{}::{}::SYMBOLE_2D".format(geschoss_name, sub)
|
||||
|
||||
|
||||
def _ensure_layer(doc, path):
|
||||
"""Stellt sicher, dass ein Layer-Pfad existiert. Liefert Layer-Index."""
|
||||
idx = doc.Layers.FindByFullPath(path, -1)
|
||||
@@ -6030,6 +6044,8 @@ class ElementeBridge(panel_base.BaseBridge):
|
||||
elif t == "CREATE_TRAEGER": self._cmd_create_traeger(p)
|
||||
elif t == "CREATE_RAUM": self._cmd_create_raum(p)
|
||||
elif t == "EXPORT_RAEUME": self._cmd_export_raeume(p)
|
||||
elif t == "LIST_LIBRARY": self._cmd_list_library(p)
|
||||
elif t == "CREATE_SYMBOL": self._cmd_create_symbol(p)
|
||||
elif t == "OPEN_SWISSTOPO": self._cmd_open_swisstopo(p)
|
||||
elif t == "IMPORT_SWISSTOPO": self._cmd_import_swisstopo(p)
|
||||
elif t == "OPEN_SWISSTOPO_DIALOG": self._cmd_open_swisstopo_dialog(p)
|
||||
@@ -8071,6 +8087,75 @@ class ElementeBridge(panel_base.BaseBridge):
|
||||
# unter dem aktiven Geschoss.
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Library-Symbol/Object — listet + platziert Library-Items im Doc
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def _cmd_list_library(self, p):
|
||||
"""Liefert Library-Manifest ans Frontend (fuer den Symbol-Picker
|
||||
im Elemente-Panel). Antwort: LIBRARY_LIST message."""
|
||||
try:
|
||||
import library
|
||||
manifest = library.load_manifest()
|
||||
self.send("LIBRARY_LIST", {
|
||||
"items": manifest.get("items", []),
|
||||
"name": manifest.get("name", "Dossier-Library"),
|
||||
})
|
||||
except Exception as ex:
|
||||
print("[ELEMENTE] list library:", ex)
|
||||
self.send("LIBRARY_LIST", {"items": [], "name": ""})
|
||||
|
||||
def _cmd_create_symbol(self, p):
|
||||
"""Platziert ein Library-Item (symbol/object) im Doc. Interactive
|
||||
GetPoint im aktiven Viewport — User klickt Position.
|
||||
Payload: { id: libraryId }. Layer-Routing auf 40_SYMBOLE::2D/3D
|
||||
unter aktivem Geschoss."""
|
||||
lib_id = (p.get("id") or "").strip()
|
||||
if not lib_id:
|
||||
print("[ELEMENTE] CREATE_SYMBOL ohne id")
|
||||
return
|
||||
doc = Rhino.RhinoDoc.ActiveDoc
|
||||
if doc is None: return
|
||||
import library
|
||||
item = library.find_item(lib_id)
|
||||
if item is None:
|
||||
print("[ELEMENTE] CREATE_SYMBOL: item not found", lib_id)
|
||||
return
|
||||
if item.get("type") not in ("symbol", "object"):
|
||||
print("[ELEMENTE] CREATE_SYMBOL: ungueltiger Typ", item.get("type"))
|
||||
return
|
||||
# Interactive point pick
|
||||
try:
|
||||
import Rhino.Input.Custom as ric
|
||||
from Rhino.Input import GetResult
|
||||
except Exception as ex:
|
||||
print("[ELEMENTE] Imports:", ex); return
|
||||
try:
|
||||
gp = ric.GetPoint()
|
||||
gp.SetCommandPrompt("Symbol platzieren — Punkt waehlen")
|
||||
res = gp.Get()
|
||||
if res != GetResult.Point: return
|
||||
pt = gp.Point()
|
||||
except Exception as ex:
|
||||
print("[ELEMENTE] GetPoint:", ex); return
|
||||
# Layer-Routing
|
||||
geschoss_id = _active_geschoss_id(doc)
|
||||
g = _geschoss_by_id(doc, geschoss_id) if geschoss_id else None
|
||||
geschoss_name = (g.get("name") if g else "EG") or "EG"
|
||||
layer2d = _ensure_layer(doc, _layer_path_symbole(doc, geschoss_name, "2d"))
|
||||
layer3d = _ensure_layer(doc, _layer_path_symbole(doc, geschoss_name, "3d"))
|
||||
# Import + place
|
||||
undo_serial = doc.BeginUndoRecord(
|
||||
"Symbol einfuegen: " + (item.get("name") or ""))
|
||||
try:
|
||||
ok, msg = library.import_item(doc, lib_id, at_point=pt,
|
||||
layer2d=layer2d, layer3d=layer3d)
|
||||
print("[ELEMENTE] CREATE_SYMBOL '{}': ok={} ({})".format(
|
||||
item.get("name"), ok, msg))
|
||||
finally:
|
||||
try: doc.EndUndoRecord(undo_serial)
|
||||
except Exception: pass
|
||||
|
||||
def _cmd_open_swisstopo(self, p):
|
||||
"""Oeffnet map.geo.admin.ch im Default-Browser mit den swisstopo-
|
||||
Layern voreingestellt. Param `mode`: 'buildings' | 'terrain' | 'both'.
|
||||
|
||||
Reference in New Issue
Block a user