From 7b78ebc0f39c29608864e68e5d5b71e8069a8ccd Mon Sep 17 00:00:00 2001 From: Andrej730 Date: Wed, 12 Feb 2025 12:51:02 +0500 Subject: [PATCH] Fix possible float precision issues similar to f6087613f0 --- .../bonsai/bim/module/geometry/operator.py | 24 ++++++++++++------- src/bonsai/bonsai/tool/blender.py | 10 ++++++++ src/bonsai/bonsai/tool/geometry.py | 10 ++++---- 3 files changed, 32 insertions(+), 12 deletions(-) diff --git a/src/bonsai/bonsai/bim/module/geometry/operator.py b/src/bonsai/bonsai/bim/module/geometry/operator.py index d8a2f8a006..e231f878dc 100644 --- a/src/bonsai/bonsai/bim/module/geometry/operator.py +++ b/src/bonsai/bonsai/bim/module/geometry/operator.py @@ -98,20 +98,25 @@ class OverrideMeshSeparate(bpy.types.Operator, tool.Ifc.Operator): unit_scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get()) rep_obj = props.representation_obj assert rep_obj + assert isinstance(obj.data, bpy.types.Mesh) + verts = tool.Blender.get_verts_coordinates(obj.data.vertices) + verts = verts.astype("d") if (coordinate_offset := tool.Geometry.get_cartesian_point_offset(rep_obj)) is not None: - verts = [((np.array(v.co) + coordinate_offset) / unit_scale).tolist() for v in obj.data.vertices] - else: - verts = [v.co / unit_scale for v in obj.data.vertices] + verts += coordinate_offset + verts /= unit_scale faces = [p.vertices[:] for p in obj.data.polygons] representation = tool.Geometry.get_active_representation(rep_obj) assert representation representation = ifcopenshell.util.representation.resolve_representation(representation) - if representation.RepresentationType in ("Brep", "AdvancedBrep"): + representation_type = representation.RepresentationType + if representation_type in ("Brep", "AdvancedBrep"): item = builder.faceted_brep(verts, faces) - elif representation.RepresentationType in ("Tessellation"): + elif representation_type in ("Tessellation"): item = builder.mesh(verts, faces) + else: + assert False, f"Unexpected representation type: '{representation_type}'." representation.Items = list(representation.Items) + [item] obj.name = obj.data.name = f"Item/{item.is_a()}/{item.id()}" @@ -2928,10 +2933,13 @@ class AddMeshlikeItem(bpy.types.Operator, tool.Ifc.Operator): builder = ifcopenshell.util.shape_builder.ShapeBuilder(tool.Ifc.get()) unit_scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get()) rep_obj = tool.Geometry.get_geometry_props().representation_obj + assert rep_obj + assert isinstance(obj.data, bpy.types.Mesh) + verts = tool.Blender.get_verts_coordinates(obj.data.vertices) + verts = verts.astype("d") if (coordinate_offset := tool.Geometry.get_cartesian_point_offset(rep_obj)) is not None: - verts = [((np.array(v.co) + coordinate_offset) / unit_scale).tolist() for v in obj.data.vertices] - else: - verts = [v.co / unit_scale for v in obj.data.vertices] + verts += coordinate_offset + verts /= unit_scale faces = [p.vertices[:] for p in obj.data.polygons] representation = tool.Geometry.get_active_representation(props.representation_obj) diff --git a/src/bonsai/bonsai/tool/blender.py b/src/bonsai/bonsai/tool/blender.py index fa8ace8818..f7e997158a 100644 --- a/src/bonsai/bonsai/tool/blender.py +++ b/src/bonsai/bonsai/tool/blender.py @@ -23,6 +23,8 @@ import json import os import platform import subprocess +import numpy as np +import numpy.typing as npt from ifcopenshell import entity_instance import ifcopenshell.api import ifcopenshell.util.element @@ -1143,6 +1145,14 @@ class Blender(bonsai.core.tool.Blender): else: raise NotImplementedError(f"Attribute data type `{data_type}` not implemented yet") + @classmethod + def get_verts_coordinates(cls, verts: bpy.types.MeshVertices) -> npt.NDArray[np.float32]: + # It's faster to get them as f and then convert to d + # with .astype("d"), if precision is needed. + coords = np.empty(len(verts) * 3, dtype="f") + coords = coords.reshape(-1, 3) + return coords + @classmethod def get_last_commit_hash(cls) -> Union[str, None]: """Get 8 symbols of last commit hash if it's present or return None otherwise.""" diff --git a/src/bonsai/bonsai/tool/geometry.py b/src/bonsai/bonsai/tool/geometry.py index 4521fa103a..5e904886e8 100644 --- a/src/bonsai/bonsai/tool/geometry.py +++ b/src/bonsai/bonsai/tool/geometry.py @@ -1818,10 +1818,12 @@ class Geometry(bonsai.core.tool.Geometry): props = tool.Geometry.get_geometry_props() rep_obj = props.representation_obj assert rep_obj - if (coordinate_offset := cls.get_cartesian_point_offset(rep_obj)) is not None: - verts = [((np.array(v.co) + coordinate_offset) / unit_scale).tolist() for v in obj.data.vertices] - else: - verts = [v.co / unit_scale for v in obj.data.vertices] + assert isinstance(obj.data, bpy.types.Mesh) + verts = tool.Blender.get_verts_coordinates(obj.data.vertices) + verts = verts.astype("d") + if (coordinate_offset := tool.Geometry.get_cartesian_point_offset(rep_obj)) is not None: + verts += coordinate_offset + verts /= unit_scale faces = [p.vertices[:] for p in obj.data.polygons] if item.is_a("IfcAdvancedBrep"):