feat: per-position camera settings, material alias dialog, product delete, media browser links
- Per-render-position focal_length_mm/sensor_width_mm (DB → pipeline → Blender)
- FOV-based camera distance with min clamp fix for wide-angle lenses
- Unmapped materials blocking dialog on "Dispatch Renders" with batch alias creation
- Material check endpoint (GET /orders/{id}/check-materials)
- Batch alias endpoint (POST /materials/batch-aliases)
- Quick-map "No alias" badges on Materials page
- Full product hard-delete with storage cleanup (MinIO + disk files + orphaned CadFile)
- Delete button on ProductDetail page with confirmation
- Clickable product names in Media Browser (links to product page)
- Single-line render dispatch/retry (POST /orders/{id}/lines/{id}/dispatch-render)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -497,56 +497,6 @@ def _collect_part_key_map(shape_tool, free_labels) -> dict:
|
||||
return part_key_map
|
||||
|
||||
|
||||
def _apply_glb_mm_to_m_scale(glb_path: Path) -> None:
|
||||
"""Wrap all GLB scene root nodes under a new root node with scale 0.001.
|
||||
|
||||
RWGltf_CafWriter exports geometry in mm (original STEP units).
|
||||
BRepBuilderAPI_Transform destroys Poly_Triangulation, so we cannot scale
|
||||
the B-Rep before export. Instead we add a root transform node to the GLB
|
||||
that scales mm → m. glTF spec uses metres; Three.js and Blender honour
|
||||
node scale transforms.
|
||||
|
||||
The GLB binary is re-serialized in-place.
|
||||
"""
|
||||
import struct as _struct
|
||||
|
||||
data = glb_path.read_bytes()
|
||||
json_len = _struct.unpack_from("<I", data, 12)[0]
|
||||
json_type = _struct.unpack_from("<I", data, 16)[0]
|
||||
if json_type != 0x4E4F534A: # "JSON"
|
||||
return
|
||||
|
||||
j = json.loads(data[20: 20 + json_len])
|
||||
|
||||
if "scenes" not in j or not j["scenes"]:
|
||||
return
|
||||
|
||||
scene = j["scenes"][0]
|
||||
old_roots = scene.get("nodes", [])
|
||||
if not old_roots:
|
||||
return
|
||||
|
||||
# Create a new root node with mm→m scale
|
||||
nodes = j.setdefault("nodes", [])
|
||||
new_root_idx = len(nodes)
|
||||
nodes.append({
|
||||
"name": "__mm_to_m_root__",
|
||||
"scale": [0.001, 0.001, 0.001],
|
||||
"children": old_roots,
|
||||
})
|
||||
scene["nodes"] = [new_root_idx]
|
||||
|
||||
new_json = json.dumps(j, separators=(",", ":"))
|
||||
pad = (4 - len(new_json) % 4) % 4
|
||||
new_json_bytes = new_json.encode() + b" " * pad
|
||||
|
||||
rest = data[20 + json_len:] # BIN chunk and anything after
|
||||
new_chunk = _struct.pack("<II", len(new_json_bytes), 0x4E4F534A) + new_json_bytes
|
||||
new_total = 12 + len(new_chunk) + len(rest)
|
||||
new_header = _struct.pack("<III", 0x46546C67, 2, new_total)
|
||||
glb_path.write_bytes(new_header + new_chunk + rest)
|
||||
|
||||
|
||||
def _inject_glb_extras(glb_path: Path, extras: dict, part_key_map: dict | None = None) -> None:
|
||||
"""Patch a GLB binary to add/update scenes[0].extras JSON field.
|
||||
|
||||
@@ -817,8 +767,10 @@ def main() -> None:
|
||||
except Exception as _exc:
|
||||
print(f"WARNING: GLB extras injection failed (non-fatal): {_exc}", file=sys.stderr)
|
||||
|
||||
# NOTE: RWGltf_CafWriter already converts mm → m and Z-up → Y-up internally.
|
||||
# No additional scaling or coordinate transform is needed.
|
||||
# NOTE: RWGltf_CafWriter reads unit metadata from the XDE document (set by
|
||||
# STEPCAFControl_Reader from the STEP file's SI_UNIT declarations) and converts
|
||||
# mm → m automatically. It also handles Z-up → Y-up coordinate transform.
|
||||
# No additional scaling or BRepBuilderAPI_Transform is needed.
|
||||
|
||||
|
||||
try:
|
||||
|
||||
Reference in New Issue
Block a user