Ortho-Foto sichtbar (PictureFrame) + Oberleiste-Polish

Swisstopo Ortho
- AddPictureFrame statt Mesh+Material — Rhinos eigener Picture-Pfad mit
  embedBitmap=True + selfIllumination=True macht die Textur in allen
  Display-Modi sichtbar (Wireframe / Shaded / Rendered / Raytraced)
- asMesh=False (Brep-Variante) — asMesh=True ist auf Mac Rhino 8 broken
  (alle Pictures landen am gleichen Punkt unabhaengig von der Plane)
- Per-Tile Sub-Ebenen unter 80_swisstopo (z.B. 80_swisstopo/2763-1254_Ortho)
  via dossier_ebenen JSON registriert → erscheinen im Dossier-Ebenen-Manager
  mit eigener Visibility
- target_layer_idx wird vor AddPictureFrame als Active-Layer gesetzt,
  Picture landet direkt auf richtigem Sub-Layer (Move-danach broeselte
  das Material)
- Regex-Fix in _parse_swisstopo_tile_bbox: Separator zwischen den beiden
  Coords MUSS Hyphen sein, sonst matcht es faelschlich auf `_YEAR_EAST_`
  Patterns wie `_2025_2763_`

Oberleiste
- DOSSIER. Logo (Krungthep + Petrol-Punkt) + Launcher-Version
  (via __LAUNCHER_VERSION__ Vite-Define aus launcher/package.json)
- Overrides + Kombi vertikal gestapelt, gleiche Label-Spalte + Dropdown-
  Breite → Dropdowns auf gleicher X-Linie
- View-Icons neu zugeordnet:
    Top=view_quilt (Raster), Front=north (Pfeil), Persp=view_in_ar (3D)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-05-20 00:44:19 +02:00
parent afb59b6626
commit 85f09390bc
4 changed files with 405 additions and 161 deletions
+71 -34
View File
@@ -18,6 +18,7 @@ import urllib.request
import urllib.parse
import Rhino
import Rhino.Geometry as rg
import System
CACHE_DIR = os.path.expanduser("~/Library/Caches/Dossier/swisstopo")
STAC_BASE = "https://data.geo.admin.ch/api/stac/v1"
@@ -737,7 +738,7 @@ def _geotiff_to_png(tif_path, max_dim=2048):
def add_ortho_plane(doc, ortho_path, tile_bbox_lv95, shift_lv95, m_to_unit,
z_doc=0.0):
z_doc=0.0, target_layer_idx=-1):
"""Erzeugt eine planare Brep-Flaeche mit dem SWISSIMAGE-Foto als Material,
direkt sichtbar in Top/Shaded/Rendered Display-Mode.
@@ -760,41 +761,77 @@ def add_ortho_plane(doc, ortho_path, tile_bbox_lv95, shift_lv95, m_to_unit,
x_max = (e_max - sx) * m_to_unit
y_min = (n_min - sy) * m_to_unit
y_max = (n_max - sy) * m_to_unit
# Mesh-Quad mit expliziten Per-Vertex-UV-Koordinaten — bombensicher
# fuer Cycles/Raytraced. Eine Brep-Plane braucht erst Render-Mesh-
# Erzeugung + TextureMapping, was diverse Fallstricke hat.
mesh = rg.Mesh()
mesh.Vertices.Add(x_min, y_min, z_doc) # 0 → UV (0,0)
mesh.Vertices.Add(x_max, y_min, z_doc) # 1 → UV (1,0)
mesh.Vertices.Add(x_max, y_max, z_doc) # 2 → UV (1,1)
mesh.Vertices.Add(x_min, y_max, z_doc) # 3 → UV (0,1)
mesh.Faces.AddFace(0, 1, 2, 3)
mesh.TextureCoordinates.Add(0.0, 0.0)
mesh.TextureCoordinates.Add(1.0, 0.0)
mesh.TextureCoordinates.Add(1.0, 1.0)
mesh.TextureCoordinates.Add(0.0, 1.0)
mesh.Normals.ComputeNormals()
mesh.Compact()
gid = doc.Objects.AddMesh(mesh)
# Centered plane, mesh-based PictureFrame mit embedded Bitmap.
# asMesh=True ist anders gerendert als Brep-Variante; bei Brep zeigte
# Mac Rhino 8 die Textur in keinem Modus.
cx = (x_min + x_max) / 2.0
cy = (y_min + y_max) / 2.0
width = abs(x_max - x_min)
height = abs(y_max - y_min)
plane = rg.Plane(rg.Point3d(cx, cy, z_doc),
rg.Vector3d.XAxis, rg.Vector3d.YAxis)
try:
size_mb = os.path.getsize(ortho_path) / 1e6
print("[SWISSTOPO] PictureFrame src: {} ({:.1f} MB)".format(
os.path.basename(ortho_path), size_mb))
except Exception:
print("[SWISSTOPO] file nicht lesbar:", ortho_path)
return None
try:
gid = doc.Objects.AddPictureFrame(
plane, ortho_path,
False, # asMesh=False (Brep) — Mac Rhino 8 ignoriert die
# Plane bei asMesh=True, alle Pictures landen
# uebereinander
width, height,
True, # selfIllumination=True — Textur unabhaengig von
# Lighting sichtbar (sonst evtl. dunkel in modes
# ohne Lichtquellen)
True) # embedBitmap=True (Pfad-Probleme umgehen)
if gid == System.Guid.Empty:
print("[SWISSTOPO] AddPictureFrame: Empty-GUID")
return None
except Exception as ex:
print("[SWISSTOPO] AddPictureFrame exception:", ex)
return None
obj = doc.Objects.Find(gid)
if obj is None: return None
# Material: Legacy + ToPhysicallyBased + PBR_BaseColor-Texture.
# Bekannt instabil unter Mac Rhino 8 für Raytraced (Cycles greift den
# Shim nicht zuverlaessig); zumindest Shaded zeigt die Textur.
# Auf Ziel-Layer schieben (nachträglich; Material bleibt auf Object).
if target_layer_idx >= 0:
try:
at = obj.Attributes.Duplicate()
at.LayerIndex = target_layer_idx
doc.Objects.ModifyAttributes(obj, at, True)
except Exception as ex:
print("[SWISSTOPO] Layer-Move fail:", ex)
# Diagnose: hat das Material tatsaechlich eine Bitmap-Textur drin?
try:
mat = Rhino.DocObjects.Material()
mat.Name = "swisstopo_ortho"
mat.SetBitmapTexture(ortho_path)
mat.ToPhysicallyBased()
tex = Rhino.DocObjects.Texture()
tex.FileName = ortho_path
tex.Enabled = True
mat.SetTexture(tex, Rhino.DocObjects.TextureType.PBR_BaseColor)
midx = doc.Materials.Add(mat)
attrs = obj.Attributes.Duplicate()
attrs.MaterialSource = Rhino.DocObjects.ObjectMaterialSource.MaterialFromObject
attrs.MaterialIndex = midx
doc.Objects.ModifyAttributes(obj, attrs, True)
o2 = doc.Objects.Find(gid)
a = o2.Attributes
print("[SWISSTOPO] PictureFrame OK id={} layer='{}' MatSrc={} MatIdx={} hidden={}".format(
gid, doc.Layers[a.LayerIndex].FullPath,
a.MaterialSource, a.MaterialIndex, o2.IsHidden))
# Material-Inspect
mat = None
try:
if a.MaterialIndex >= 0 and a.MaterialIndex < doc.Materials.Count:
mat = doc.Materials[a.MaterialIndex]
except Exception: pass
if mat is not None:
try: bmp_fn = mat.GetBitmapTexture().FileName if mat.GetBitmapTexture() else None
except Exception: bmp_fn = None
try: tex = mat.GetTexture(Rhino.DocObjects.TextureType.Bitmap)
except Exception: tex = None
print("[SWISSTOPO] material[{}].Name='{}' bitmap='{}' tex={} textures={}".format(
a.MaterialIndex, mat.Name, bmp_fn, tex,
mat.GetTextures().Length if hasattr(mat, "GetTextures") else "?"))
# RenderMaterial-Inspect
try:
rm = a.RenderMaterial
print("[SWISSTOPO] RenderMaterial: {}".format(
rm.Name if rm else "None"))
except Exception as ex:
print("[SWISSTOPO] RenderMaterial-check fail:", ex)
except Exception as ex:
print("[SWISSTOPO] ortho-material:", ex)
print("[SWISSTOPO] diag fail:", ex)
return obj