"""Base Scene package and canonical tetrahedron asset construction.""" from __future__ import annotations import hashlib import math import struct from simplecadapi.scene import canonical_json_bytes, with_scene_revision from .binary_cases import glb from .common import content_hash, sha256_hex IDENTITY = { "origin": [0, 0, 0], "x_axis": [1, 0, 0], "y_axis": [0, 1, 0], "z_axis": [0, 0, 1], } ASSET_TO_SCENE = [1000, 0, 0, 0, 0, 0, -1000, 0, 0, 1000, 0, 0, 0, 0, 0, 1] def _normalize(vector): length = math.sqrt(sum(component * component for component in vector)) return tuple(component / length for component in vector) def _cross(left, right): return ( left[1] * right[2] - left[2] * right[1], left[2] * right[0] - left[0] * right[2], left[0] * right[1] - left[1] * right[0], ) def _frame(origin, x_axis): x_axis = _normalize(x_axis) seed = (0.0, 0.0, 1.0) if abs(x_axis[2]) < 0.9 else (0.0, 1.0, 0.0) projection = sum(left * right for left, right in zip(seed, x_axis)) y_axis = _normalize( tuple(seed[index] - projection * x_axis[index] for index in range(3)) ) z_axis = _normalize(_cross(x_axis, y_axis)) return { "origin": list(origin), "x_axis": list(x_axis), "y_axis": list(y_axis), "z_axis": list(z_axis), } def _canonical_triangle_asset(): points = { "a": (0.0, 0.0, 0.0), "b": (1.0, 0.0, 0.0), "c": (0.0, 1.0, 0.0), "d": (0.0, 0.0, 1.0), } oriented_faces = { "abc": ("a", "c", "b"), "abd": ("a", "b", "d"), "acd": ("a", "d", "c"), "bcd": ("b", "c", "d"), } blocks = [] for name, corners in oriented_faces.items(): a, b, c = (points[corner] for corner in corners) normal = _normalize( _cross( tuple(b[i] - a[i] for i in range(3)), tuple(c[i] - a[i] for i in range(3)), ) ) local_positions = sorted( (points[corner] for corner in corners), key=lambda point: struct.pack("