mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-09 09:21:46 +00:00
Move handling legacy mathutils buffer types to separate methods
This commit is contained in:
@@ -1762,40 +1762,34 @@ class CutDecorator:
|
||||
shader.uniform_float("color", color)
|
||||
batch.draw(shader)
|
||||
|
||||
def cache_camera_matrix(self):
|
||||
def cache_camera_matrix(self) -> None:
|
||||
assert bpy.context.scene and bpy.context.scene.camera
|
||||
obj = bpy.context.scene.camera
|
||||
# Explicit `dtype` for Blender <5.0 compatibility.
|
||||
DecoratorData.camera_location_checksum = repr(
|
||||
np.array(obj.matrix_world.translation, dtype=np.float32).tobytes()
|
||||
tool.Blender.np_array_legacy(obj.matrix_world.translation).tobytes()
|
||||
)
|
||||
DecoratorData.camera_rotation_checksum = repr(np.array(obj.matrix_world.to_3x3(), dtype=np.float32).tobytes())
|
||||
DecoratorData.camera_rotation_checksum = repr(tool.Blender.np_array_legacy(obj.matrix_world.to_3x3()).tobytes())
|
||||
|
||||
def is_camera_moved(self):
|
||||
def is_camera_moved(self) -> bool:
|
||||
if not DecoratorData.camera_location_checksum:
|
||||
self.cache_camera_matrix()
|
||||
return True # Let's be conservative
|
||||
|
||||
assert bpy.context.scene and bpy.context.scene.camera
|
||||
obj = bpy.context.scene.camera
|
||||
|
||||
# Handle both old float64 and new float32 checksums for version compatibility
|
||||
loc_checksum_bytes = eval(DecoratorData.camera_location_checksum)
|
||||
if len(loc_checksum_bytes) == 24: # Old format: 3 * 8 bytes (float64)
|
||||
loc_check = np.frombuffer(loc_checksum_bytes, dtype=np.float64).astype(np.float32)
|
||||
else: # New format: 3 * 4 bytes (float32)
|
||||
loc_check = np.frombuffer(loc_checksum_bytes, dtype=np.float32)
|
||||
|
||||
loc_real = np.array(obj.matrix_world.translation, dtype=np.float32).flatten()
|
||||
loc_checksum_bytes: bytes = eval(DecoratorData.camera_location_checksum)
|
||||
loc_check = tool.Blender.np_frombuffer_legacy(loc_checksum_bytes, 3)
|
||||
loc_real = tool.Blender.np_array_legacy(obj.matrix_world.translation)
|
||||
if not np.allclose(loc_check, loc_real, atol=1e-4): # 0.1 mm
|
||||
self.cache_camera_matrix()
|
||||
return True
|
||||
|
||||
# Handle both old float64 and new float32 checksums for version compatibility
|
||||
rot_checksum_bytes = eval(DecoratorData.camera_rotation_checksum)
|
||||
if len(rot_checksum_bytes) == 72: # Old format: 9 * 8 bytes (float64)
|
||||
rot_check = np.frombuffer(rot_checksum_bytes, dtype=np.float64).astype(np.float32).reshape(3, 3)
|
||||
else: # New format: 9 * 4 bytes (float32)
|
||||
rot_check = np.frombuffer(rot_checksum_bytes, dtype=np.float32).reshape(3, 3)
|
||||
|
||||
rot_real = np.array(obj.matrix_world.to_3x3(), dtype=np.float32)
|
||||
rot_checksum_bytes: bytes = eval(DecoratorData.camera_rotation_checksum)
|
||||
rot_check = tool.Blender.np_frombuffer_legacy(rot_checksum_bytes, 9)
|
||||
rot_real = tool.Blender.np_array_legacy(obj.matrix_world.to_3x3())
|
||||
rot_dot = np.dot(rot_check, rot_real.T)
|
||||
angle_rad = np.arccos(np.clip((np.trace(rot_dot) - 1) / 2, -1, 1))
|
||||
if angle_rad > 0.0017453292519943296: # 0.1 degrees
|
||||
|
||||
@@ -49,7 +49,7 @@ import ifcopenshell.util.element
|
||||
import numpy as np
|
||||
import numpy.typing as npt
|
||||
from ifcopenshell import entity_instance
|
||||
from mathutils import Vector
|
||||
from mathutils import Matrix, Vector
|
||||
|
||||
import bonsai.bim
|
||||
import bonsai.core.tool
|
||||
@@ -2127,3 +2127,32 @@ class Blender(bonsai.core.tool.Blender):
|
||||
if cls.BLENDER_5:
|
||||
return "BLENDER_EEVEE"
|
||||
return "BLENDER_EEVEE_NEXT"
|
||||
|
||||
@classmethod
|
||||
def np_frombuffer_legacy(cls, bytedata: bytes, n: int) -> npt.NDArray[np.float32]:
|
||||
"""
|
||||
Read ``n`` float values from ``bytedata``, regardless if they are stored as ``float32`` or ``float64``.
|
||||
Needed to support .blend files saved in Blender <5.0.0.
|
||||
Also allows to work with .blend files from 5.0.0+ in older Blender versions.
|
||||
|
||||
In ``bpy.app.version >= 5.0.0`` ``mathutils`` transitioned to use ``float32`` buffer type,
|
||||
while in previous version they were using ``float64``.
|
||||
In some cases we are storing raw bytes (e.g. object transforms cheksums), so old .blend files
|
||||
might still have ``float64`` data stored.
|
||||
|
||||
See https://projects.blender.org/blender/blender/issues/149283
|
||||
"""
|
||||
if len(bytedata) == (n * 2):
|
||||
return np.frombuffer(bytedata, dtype=np.float64).astype(np.float32)
|
||||
return np.frombuffer(bytedata, dtype=np.float32)
|
||||
|
||||
@classmethod
|
||||
def np_array_legacy(cls, mathutils_type: Union[Vector, Matrix]) -> npt.NDArray[np.float32]:
|
||||
"""
|
||||
Converts ``mathutils`` types to ``np.float32`` arrays, regardless of Blender version.
|
||||
|
||||
See ``np_frombuffer_legacy`` for more details.
|
||||
"""
|
||||
if cls.BLENDER_5:
|
||||
return np.array(mathutils_type)
|
||||
return np.array(mathutils_type, dtype=np.float32)
|
||||
|
||||
@@ -1152,9 +1152,8 @@ class Geometry(bonsai.core.tool.Geometry):
|
||||
def record_object_position(cls, obj: bpy.types.Object) -> None:
|
||||
# These are recorded separately because they have different numerical tolerances
|
||||
props = tool.Blender.get_object_bim_props(obj)
|
||||
# Explicit dtype for Blender <5.0 compatibility.
|
||||
props.location_checksum = repr(np.array(obj.matrix_world.translation, dtype=np.float32).tobytes())
|
||||
props.rotation_checksum = repr(np.array(obj.matrix_world.to_3x3(), dtype=np.float32).tobytes())
|
||||
props.location_checksum = repr(tool.Blender.np_array_legacy(obj.matrix_world.translation).tobytes())
|
||||
props.rotation_checksum = repr(tool.Blender.np_array_legacy(obj.matrix_world.to_3x3()).tobytes())
|
||||
|
||||
@classmethod
|
||||
def remove_connection(cls, connection: ifcopenshell.entity_instance) -> None:
|
||||
|
||||
@@ -115,24 +115,17 @@ class Ifc(bonsai.core.tool.Ifc):
|
||||
return True # Let's be conservative
|
||||
|
||||
# Handle both old float64 and new float32 checksums for version compatibility
|
||||
loc_checksum_bytes = eval(oprops.location_checksum)
|
||||
if len(loc_checksum_bytes) == 24: # Old format: 3 * 8 bytes (float64)
|
||||
loc_check = np.frombuffer(loc_checksum_bytes, dtype=np.float64).astype(np.float32)
|
||||
else: # New format: 3 * 4 bytes (float32)
|
||||
loc_check = np.frombuffer(loc_checksum_bytes, dtype=np.float32)
|
||||
|
||||
loc_real = np.array(obj.matrix_world.translation, dtype=np.float32).flatten()
|
||||
loc_checksum_bytes: bytes = eval(oprops.location_checksum)
|
||||
loc_check = tool.Blender.np_frombuffer_legacy(loc_checksum_bytes, 3)
|
||||
loc_real = tool.Blender.np_array_legacy(obj.matrix_world.translation)
|
||||
if not np.allclose(loc_check, loc_real, atol=1e-4): # 0.1 mm
|
||||
return True
|
||||
|
||||
# Handle both old float64 and new float32 checksums for version compatibility
|
||||
rot_checksum_bytes = eval(oprops.rotation_checksum)
|
||||
if len(rot_checksum_bytes) == 72: # Old format: 9 * 8 bytes (float64)
|
||||
rot_check = np.frombuffer(rot_checksum_bytes, dtype=np.float64).astype(np.float32).reshape(3, 3)
|
||||
else: # New format: 9 * 4 bytes (float32)
|
||||
rot_check = np.frombuffer(rot_checksum_bytes, dtype=np.float32).reshape(3, 3)
|
||||
|
||||
rot_real = np.array(obj.matrix_world.to_3x3(), dtype=np.float32)
|
||||
rot_checksum_bytes: bytes = eval(oprops.rotation_checksum)
|
||||
rot_check = tool.Blender.np_frombuffer_legacy(rot_checksum_bytes, 9)
|
||||
rot_check = rot_check.reshape(3, 3)
|
||||
rot_real = tool.Blender.np_array_legacy(obj.matrix_world.to_3x3())
|
||||
rot_dot = np.dot(rot_check, rot_real.T)
|
||||
angle_rad = np.arccos(np.clip((np.trace(rot_dot) - 1) / 2, -1, 1))
|
||||
if angle_rad > 0.0017453292519943296: # 0.1 degrees
|
||||
|
||||
@@ -323,8 +323,8 @@ class TestRecordObjectPosition(NewFile):
|
||||
obj = bpy.data.objects.new("Object", None)
|
||||
props = tool.Blender.get_object_bim_props(obj)
|
||||
subject.record_object_position(obj)
|
||||
assert props.location_checksum == repr(np.array(obj.matrix_world.translation, dtype=np.float32).tobytes())
|
||||
assert props.rotation_checksum == repr(np.array(obj.matrix_world.to_3x3(), dtype=np.float32).tobytes())
|
||||
assert props.location_checksum == repr(tool.Blender.np_array_legacy(obj.matrix_world.translation).tobytes())
|
||||
assert props.rotation_checksum == repr(tool.Blender.np_array_legacy(obj.matrix_world.to_3x3()).tobytes())
|
||||
|
||||
|
||||
class TestRemoveConnection(NewFile):
|
||||
|
||||
Reference in New Issue
Block a user