Fix invalid IfcGrid cartesian points (774a770)

They were saved as 4d coordinates, not 2d.
This commit is contained in:
Andrej730
2025-04-30 19:34:41 +05:00
parent 814c16d3ee
commit c7a29d5604
3 changed files with 23 additions and 9 deletions
+2 -2
View File
@@ -48,7 +48,7 @@ from bonsai.bim import import_ifc
from bonsai.bim.module.model.data import AuthoringData, RailingData, RoofData, WindowData, DoorData from bonsai.bim.module.model.data import AuthoringData, RailingData, RoofData, WindowData, DoorData
from bonsai.bim.module.model.opening import FilledOpeningGenerator from bonsai.bim.module.model.opening import FilledOpeningGenerator
from ifcopenshell.util.shape_builder import ShapeBuilder from ifcopenshell.util.shape_builder import ShapeBuilder, np_to_3d
from typing import Optional, Union, TypeVar, Any, Iterable, Literal, TYPE_CHECKING, Sequence, TypedDict from typing import Optional, Union, TypeVar, Any, Iterable, Literal, TYPE_CHECKING, Sequence, TypedDict
T = TypeVar("T") T = TypeVar("T")
@@ -2126,7 +2126,7 @@ class Model(bonsai.core.tool.Model):
assert isinstance(obj.data, bpy.types.Mesh) assert isinstance(obj.data, bpy.types.Mesh)
points = [m @ np.array(v.co.to_4d()) for v in obj.data.vertices[0:2]] points = [m @ np.array(v.co.to_4d()) for v in obj.data.vertices[0:2]]
ifcopenshell.api.grid.create_axis_curve( ifcopenshell.api.grid.create_axis_curve(
tool.Ifc.get(), p1=points[0], p2=points[1], is_si=True, grid_axis=grid_axis tool.Ifc.get(), p1=np_to_3d(points[0]), p2=np_to_3d(points[1]), is_si=True, grid_axis=grid_axis
) )
@classmethod @classmethod
@@ -22,7 +22,7 @@ import ifcopenshell.util.element
import ifcopenshell.util.unit import ifcopenshell.util.unit
import ifcopenshell.util.placement import ifcopenshell.util.placement
import numpy as np import numpy as np
from ifcopenshell.util.shape_builder import VectorType, V, ifc_safe_vector_type from ifcopenshell.util.shape_builder import VectorType, V, ifc_safe_vector_type, np_apply_matrix
def create_axis_curve( def create_axis_curve(
@@ -38,6 +38,10 @@ def create_axis_curve(
An IFC grid will have a minimum of two axes (typically perpendicular). Each An IFC grid will have a minimum of two axes (typically perpendicular). Each
axis will then have a line which represents the extents of the axis. axis will then have a line which represents the extents of the axis.
Points are provided as 3D coordinates in world space.
During axis creation, the coordinates will be localized relative to IfcGrid
and saved as 2D.
:param p1: The first point of the grid axis :param p1: The first point of the grid axis
:param p2: The second point of the grid axis :param p2: The second point of the grid axis
:param grid_axis: The IfcGridAxis element to add geometry to. :param grid_axis: The IfcGridAxis element to add geometry to.
@@ -61,19 +65,19 @@ def create_axis_curve(
model, p1=np.array((0., 0., 0.)), p2=np.array((0., 10., 0.)), grid_axis=axis_1) model, p1=np.array((0., 0., 0.)), p2=np.array((0., 10., 0.)), grid_axis=axis_1)
""" """
existing_curve = grid_axis.AxisCurve existing_curve = grid_axis.AxisCurve
p1, p2 = V(p1), V(p2) points = V([p1, p2])
if is_si: if is_si:
unit_scale = ifcopenshell.util.unit.calculate_unit_scale(file) unit_scale = ifcopenshell.util.unit.calculate_unit_scale(file)
p1 /= unit_scale points /= unit_scale
p2 /= unit_scale
grid = [i for i in file.get_inverse(grid_axis) if i.is_a("IfcGrid")][0] grid = next(i for i in file.get_inverse(grid_axis) if i.is_a("IfcGrid"))
grid_matrix_i = np.linalg.inv(ifcopenshell.util.placement.get_local_placement(grid.ObjectPlacement)) grid_matrix_i = np.linalg.inv(ifcopenshell.util.placement.get_local_placement(grid.ObjectPlacement))
p1, p2 = ifc_safe_vector_type(np_apply_matrix(points, grid_matrix_i))
grid_axis.AxisCurve = file.create_entity( grid_axis.AxisCurve = file.create_entity(
"IfcPolyline", "IfcPolyline",
( (
file.create_entity("IfcCartesianPoint", ifc_safe_vector_type(grid_matrix_i @ p1)), file.create_entity("IfcCartesianPoint", p1[:2]),
file.create_entity("IfcCartesianPoint", ifc_safe_vector_type(grid_matrix_i @ p2)), file.create_entity("IfcCartesianPoint", p2[:2]),
), ),
) )
@@ -129,6 +129,16 @@ def np_to_4x4(matrix_3x3: np.ndarray) -> np.ndarray:
return matrix_4x4 return matrix_4x4
def np_apply_matrix(vectors: SequenceOfVectors, matrix: npt.NDArray) -> npt.NDArray:
"""
:param vectors: Nx3 array of vectors.
:param matrix: 4x4 transformation matrix.
"""
m3x3 = matrix[:3, :3]
translation = matrix[:3, 3]
return vectors @ m3x3.T + translation
def np_angle(a: VectorType, b: VectorType) -> float: def np_angle(a: VectorType, b: VectorType) -> float:
"""Get angle between vectors in radians. """Get angle between vectors in radians.
Designed to work similar to `Vector.angle`. Designed to work similar to `Vector.angle`.