Library: Format-Konvertierung beim Import (.dwg/.obj/.fbx/.dae/.stl/...)
User kann jetzt im Symbole-Tab Dateien in vielen Formaten waehlen — Rhino konvertiert automatisch nach .3dm via _-Import + File3dm.Write. library.py — convert_to_3dm_via_import(): - Snapshot der existierenden Object-IDs im aktiven Doc - User-Selection sichern - _-Import scripted ausfuehren → neue Objekte in Doc - Diff -> neue Objekte sammeln - BoundingBox.Min als Origin → in File3dm packen - f3.Write nach library/assets/<name>.3dm - Neue Objekte aus Doc wieder loeschen + User-Selection restoren - sticky 'dossier_library_import_busy' + 'dossier_swisstopo_busy' damit unsere Listener nichts cascaden waehrend Doc kurzzeitig die Importe haelt rhinopanel.py — _add_library_file(): - .3dm: copy_to_assets (wie bisher) - .dwg/.dxf/.obj/.fbx/.dae/.stl/.3ds/.skp/.iges/.step/.ply: konvertieren - Sonst LIBRARY_ERROR Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -210,6 +210,137 @@ def add_item(item):
|
||||
return ok, load_manifest()
|
||||
|
||||
|
||||
def convert_to_3dm_via_import(src_path, target_name):
|
||||
"""Konvertiert eine beliebige CAD-Datei (.dwg/.obj/.fbx/.dae/.stl/...)
|
||||
nach .3dm. Strategie: Rhinos _-Import in den aktiven Doc, dann die
|
||||
NEU hinzugekommenen Objekte als File3dm in library/assets/<name>.3dm
|
||||
speichern + aus dem Doc wieder loeschen. Returns relativer Pfad oder
|
||||
None.
|
||||
|
||||
WARNUNG: User-Doc wird kurz veraendert (Objects in/out) — wir
|
||||
delete'n alles wieder am Ende. Setzt einen sticky-Flag damit unsere
|
||||
eigenen Listener nichts cascaden."""
|
||||
if not src_path or not os.path.isfile(src_path): return None
|
||||
if Rhino is None: return None
|
||||
import scriptcontext as sc
|
||||
doc = Rhino.RhinoDoc.ActiveDoc
|
||||
if doc is None: return None
|
||||
ensure_library()
|
||||
assets_dir = os.path.join(library_root(), "assets")
|
||||
if not os.path.isdir(assets_dir):
|
||||
try: os.makedirs(assets_dir)
|
||||
except Exception: pass
|
||||
safe = "".join(c if (c.isalnum() or c in "-_") else "_" for c in target_name)
|
||||
if not safe.endswith(".3dm"): safe += ".3dm"
|
||||
target = os.path.join(assets_dir, safe)
|
||||
if os.path.isfile(target):
|
||||
stem, ext = os.path.splitext(safe)
|
||||
n = 2
|
||||
while os.path.isfile(os.path.join(assets_dir, "{}_{}{}".format(stem, n, ext))):
|
||||
n += 1
|
||||
target = os.path.join(assets_dir, "{}_{}{}".format(stem, n, ext))
|
||||
# Listener stilllegen: unsere Add-/Delete-Cascade soll bei diesem
|
||||
# temporaeren Import nicht greifen (Objekte haben keine DOSSIER-
|
||||
# UserStrings, kommen aber trotzdem durch unsere Schnellfilter).
|
||||
sc.sticky["dossier_library_import_busy"] = True
|
||||
sc.sticky["dossier_swisstopo_busy"] = True # blockt schon viele Listener
|
||||
# Snapshot der existierenden Object-IDs
|
||||
before_ids = set()
|
||||
try:
|
||||
for o in doc.Objects:
|
||||
try:
|
||||
if not o.IsDeleted: before_ids.add(str(o.Id))
|
||||
except Exception: pass
|
||||
except Exception: pass
|
||||
# User-Selection sichern damit wir sie am Ende restoren
|
||||
sel_before_ids = []
|
||||
try:
|
||||
for o in doc.Objects.GetSelectedObjects(False, False):
|
||||
sel_before_ids.append(o.Id)
|
||||
except Exception: pass
|
||||
new_objs = []
|
||||
try:
|
||||
try: doc.Objects.UnselectAll()
|
||||
except Exception: pass
|
||||
# _-Import dash-prefix = scripted, kein UI-Dialog. Pfad in Quotes
|
||||
# damit Spaces nicht splitten. _Enter beendet die Optionen.
|
||||
cmd = '_-Import "' + src_path + '" _Enter _Enter'
|
||||
try:
|
||||
Rhino.RhinoApp.RunScript(cmd, False)
|
||||
except Exception as ex:
|
||||
print("[LIBRARY] convert_to_3dm RunScript:", ex)
|
||||
# Sammle die NEU hinzugekommenen Objekte
|
||||
try:
|
||||
for o in doc.Objects:
|
||||
try:
|
||||
if o.IsDeleted: continue
|
||||
if str(o.Id) not in before_ids:
|
||||
new_objs.append(o)
|
||||
except Exception: pass
|
||||
except Exception: pass
|
||||
if not new_objs:
|
||||
print("[LIBRARY] convert_to_3dm: Import lieferte keine Objekte")
|
||||
return None
|
||||
# In File3dm packen
|
||||
try:
|
||||
from Rhino.FileIO import File3dm
|
||||
import Rhino.Geometry as rg
|
||||
bbox = rg.BoundingBox.Empty
|
||||
geoms_attrs = []
|
||||
for o in new_objs:
|
||||
g = o.Geometry
|
||||
if g is None: continue
|
||||
try:
|
||||
bb = g.GetBoundingBox(True)
|
||||
if bb.IsValid: bbox.Union(bb)
|
||||
except Exception: pass
|
||||
geoms_attrs.append((g, o.Attributes))
|
||||
if bbox.IsValid:
|
||||
offset = rg.Transform.Translation(
|
||||
-bbox.Min.X, -bbox.Min.Y, -bbox.Min.Z)
|
||||
else:
|
||||
offset = rg.Transform.Identity
|
||||
f3 = File3dm()
|
||||
for g, a in geoms_attrs:
|
||||
try:
|
||||
g2 = g.Duplicate()
|
||||
try: g2.Transform(offset)
|
||||
except Exception: pass
|
||||
try: f3.Objects.Add(g2, a)
|
||||
except Exception:
|
||||
if isinstance(g2, rg.Brep): f3.Objects.AddBrep(g2)
|
||||
elif isinstance(g2, rg.Curve): f3.Objects.AddCurve(g2)
|
||||
elif isinstance(g2, rg.Mesh): f3.Objects.AddMesh(g2)
|
||||
except Exception as ex:
|
||||
print("[LIBRARY] convert add geom:", ex)
|
||||
try: f3.Write(target, 8)
|
||||
except Exception as ex:
|
||||
print("[LIBRARY] convert_to_3dm Write:", ex)
|
||||
return None
|
||||
except Exception as ex:
|
||||
print("[LIBRARY] convert_to_3dm File3dm:", ex)
|
||||
return None
|
||||
finally:
|
||||
# Cleanup: importierte Objekte wieder loeschen
|
||||
for o in new_objs:
|
||||
try: doc.Objects.Delete(o.Id, True)
|
||||
except Exception: pass
|
||||
# Restore Selection
|
||||
try:
|
||||
for gid in sel_before_ids:
|
||||
try: doc.Objects.Select(gid, True)
|
||||
except Exception: pass
|
||||
except Exception: pass
|
||||
rel = os.path.relpath(target, library_root())
|
||||
print("[LIBRARY] convert_to_3dm OK: {} → {}".format(src_path, rel))
|
||||
return rel
|
||||
finally:
|
||||
sc.sticky["dossier_library_import_busy"] = False
|
||||
sc.sticky["dossier_swisstopo_busy"] = False
|
||||
try: doc.Views.Redraw()
|
||||
except Exception: pass
|
||||
|
||||
|
||||
def save_selection_to_asset(doc, target_name):
|
||||
"""Speichert die aktuelle Selection aus dem Doc als eigene .3dm-Datei
|
||||
in library/assets/<target_name>.3dm. Returns relativer Pfad oder None.
|
||||
|
||||
+19
-14
@@ -1224,20 +1224,28 @@ class EbenenBridge(panel_base.BaseBridge):
|
||||
path = dlg.FileName or ""
|
||||
if not path: return
|
||||
ext = (path.split(".")[-1] if "." in path else "").lower()
|
||||
if ext != "3dm":
|
||||
# TODO: konvertieren via temporaerer RhinoDoc-Import
|
||||
# Phase 1: nur .3dm direkt unterstuetzt
|
||||
print("[PROJECT-SETTINGS] Format '.{}' wird in dieser "
|
||||
"Version noch nicht konvertiert — bitte in Rhino "
|
||||
"oeffnen + als .3dm speichern".format(ext))
|
||||
import os
|
||||
base = os.path.basename(path)
|
||||
stem = os.path.splitext(base)[0]
|
||||
rel = None
|
||||
if ext == "3dm":
|
||||
# Direkt kopieren
|
||||
rel = library.copy_to_assets(path)
|
||||
elif ext in ("dwg", "dxf", "obj", "fbx", "dae",
|
||||
"stl", "3ds", "skp", "iges", "igs",
|
||||
"step", "stp", "ply"):
|
||||
# Konvertieren via Rhino-Import
|
||||
rel = library.convert_to_3dm_via_import(
|
||||
path, stem + "_" + variant)
|
||||
else:
|
||||
self.send("LIBRARY_ERROR", {
|
||||
"msg": "Format .{} noch nicht unterstuetzt. "
|
||||
"Konvertiere in Rhino zu .3dm.".format(ext),
|
||||
"msg": "Format .{} wird nicht unterstuetzt.".format(ext),
|
||||
})
|
||||
return
|
||||
rel = library.copy_to_assets(path)
|
||||
if not rel:
|
||||
print("[PROJECT-SETTINGS] copy_to_assets failed")
|
||||
print("[PROJECT-SETTINGS] add file failed")
|
||||
self.send("LIBRARY_ERROR", {
|
||||
"msg": "Konnte Datei nicht importieren — siehe Log."})
|
||||
return
|
||||
if target_id:
|
||||
# Bestehendes Item updaten
|
||||
@@ -1250,10 +1258,7 @@ class EbenenBridge(panel_base.BaseBridge):
|
||||
break
|
||||
library.save_manifest(m)
|
||||
else:
|
||||
# Neues Item
|
||||
import os
|
||||
base = os.path.basename(path)
|
||||
stem = os.path.splitext(base)[0]
|
||||
# Neues Item — stem aus dem Pfad oben bereits berechnet
|
||||
import uuid as _uuid
|
||||
new_id = "obj-" + _uuid.uuid4().hex[:10]
|
||||
item = {
|
||||
|
||||
Reference in New Issue
Block a user