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.
|
||||
|
||||
Reference in New Issue
Block a user