mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-10 01:41:57 +00:00
shape_builder.create_axis2_placement_3d utility method and docs
This commit is contained in:
@@ -17,6 +17,7 @@
|
||||
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import numpy as np
|
||||
import ifcopenshell
|
||||
|
||||
|
||||
def a2p(o, z, x):
|
||||
@@ -44,7 +45,7 @@ def a2p(o, z, x):
|
||||
return r.T
|
||||
|
||||
|
||||
def get_axis2placement(placement):
|
||||
def get_axis2placement(placement: ifcopenshell.entity_instance) -> np.array:
|
||||
"""Parses an IfcAxis2Placement (2D or 3D) to a 4x4 transformation matrix
|
||||
|
||||
Note that this function only parses a single placement axis. If you want to
|
||||
@@ -202,6 +203,7 @@ def rotation(angle, axis, is_degrees=True):
|
||||
theta = np.radians(angle) if is_degrees else angle
|
||||
cos, sin = np.cos(theta), np.sin(theta)
|
||||
|
||||
# fmt: off
|
||||
if axis == "X":
|
||||
return np.array([
|
||||
[1, 0, 0, 0],
|
||||
@@ -223,3 +225,4 @@ def rotation(angle, axis, is_degrees=True):
|
||||
[0, 0, 1, 0],
|
||||
[0, 0, 0, 1]
|
||||
])
|
||||
# fmt: on
|
||||
|
||||
@@ -21,7 +21,7 @@ import collections
|
||||
import ifcopenshell
|
||||
import ifcopenshell.api
|
||||
from math import cos, sin, pi, tan, radians, degrees, atan, sqrt, ceil
|
||||
from typing import List
|
||||
from typing import List, Tuple, Type, Union
|
||||
from itertools import chain
|
||||
from mathutils import Vector, Matrix
|
||||
|
||||
@@ -29,6 +29,9 @@ V = lambda *x: Vector([float(i) for i in x])
|
||||
sign = lambda x: x and (1, -1)[x < 0]
|
||||
PRECISION = 1.0e-5
|
||||
|
||||
VectorTuple = Type[Tuple[float, float, float]]
|
||||
"tuple of 3 `float` values"
|
||||
|
||||
|
||||
def is_x(value, x, si_conversion=None):
|
||||
if si_conversion:
|
||||
@@ -217,15 +220,24 @@ class ShapeBuilder:
|
||||
|
||||
def plane(
|
||||
self, location: Vector = Vector((0.0, 0.0, 0.0)).freeze(), normal: Vector = Vector((0.0, 0.0, 1.0)).freeze()
|
||||
):
|
||||
location = self.file.createIfcCartesianPoint(location)
|
||||
direction = self.file.createIfcDirection(normal)
|
||||
) -> ifcopenshell.entity_instance:
|
||||
"""
|
||||
Create IfcPlane.
|
||||
|
||||
:param location: plane position, defaults to `(0.0, 0.0, 0.0)`
|
||||
:type location: Vector, optional
|
||||
:param normal: plane normal direction, defaults to `(0.0, 0.0, 1.0)`
|
||||
:type normal: Vector, optional
|
||||
:return: IfcPlane
|
||||
:rtype: ifcopenshell.entity_instance
|
||||
"""
|
||||
|
||||
if normal.to_tuple(2) == Vector((0.0, 0.0, 1.0)):
|
||||
arbitrary_vector = Vector((0.0, 1.0, 0.0))
|
||||
else:
|
||||
arbitrary_vector = Vector((0.0, 0.0, 1.0))
|
||||
x_axis = self.file.createIfcDirection(normal.cross(arbitrary_vector).normalized())
|
||||
axis_placement = self.file.createIfcAxis2Placement3D(location, direction, x_axis)
|
||||
x_axis = normal.cross(arbitrary_vector).normalized()
|
||||
axis_placement = self.create_axis2_placement_3d(location, normal, x_axis)
|
||||
return self.file.createIfcPlane(axis_placement)
|
||||
|
||||
# TODO: explain points order for the curve_between_two_points
|
||||
@@ -465,8 +477,15 @@ class ShapeBuilder:
|
||||
point_2d = relative_point + mirror_point
|
||||
return point_2d
|
||||
|
||||
def get_axis2_placement_3d_matrix(self, axis2_placement_3d):
|
||||
# > IfcAxis2Placement3D
|
||||
def get_axis2_placement_3d_matrix(self, axis2_placement_3d: ifcopenshell.entity_instance) -> Matrix:
|
||||
"""
|
||||
Generate a Matrix from IfcAxis2Placement3D.
|
||||
|
||||
:param axis2_placement_3d: IfcAxis2Placement3D
|
||||
:type axis2_placement_3d: ifcopenshell.entity_instance
|
||||
:return: generated matrix
|
||||
:rtype: Matrix
|
||||
"""
|
||||
p = axis2_placement_3d
|
||||
|
||||
M = Matrix.Identity(3)
|
||||
@@ -484,6 +503,48 @@ class ShapeBuilder:
|
||||
|
||||
return rotation_matrix
|
||||
|
||||
def create_axis2_placement_3d(
|
||||
self,
|
||||
position: VectorTuple = (0.0, 0.0, 0.0),
|
||||
z_axis: VectorTuple = (0.0, 0.0, 1.0),
|
||||
x_axis: VectorTuple = (1.0, 0.0, 0.0),
|
||||
) -> ifcopenshell.entity_instance:
|
||||
"""
|
||||
Create IfcAxis2Placement3D.
|
||||
|
||||
:param position: placement position (Axis), defaults to `(0.0, 0.0, 0.0)`
|
||||
:type position: VectorTuple, optional
|
||||
:param z_axis: local Z axis direction, defaults to `(0.0, 0.0, 1.0)`
|
||||
:type z_axis: VectorTuple, optional
|
||||
:param x_axis: local X axis direction (RefDirection), defaults to `(1.0, 0.0, 0.0)`
|
||||
:type x_axis: VectorTuple, optional
|
||||
:return: IfcAxis2Placement3D
|
||||
:rtype: ifcopenshell.entity_instance
|
||||
"""
|
||||
return self.file.createIfcAxis2Placement3D(
|
||||
self.file.createIfcCartesianPoint(position),
|
||||
Axis=self.file.createIfcDirection(z_axis),
|
||||
RefDirection=self.file.createIfcDirection(x_axis),
|
||||
)
|
||||
|
||||
def create_axis2_placement_3d_from_matrix(
|
||||
self,
|
||||
matrix: Union[np.ndarray, None] = None,
|
||||
) -> ifcopenshell.entity_instance:
|
||||
"""
|
||||
Create IfcAxis2Placement3D from numpy matrix.
|
||||
|
||||
:param matrix: 4x4 transformation matrix, defaults to `np.eye(4)`
|
||||
:type matrix: np.array[np.array[float]], optional
|
||||
:return: IfcAxis2Placement3D
|
||||
:rtype: ifcopenshell.entity_instance
|
||||
"""
|
||||
if matrix is None:
|
||||
matrix = np.eye(4, dtype=float)
|
||||
return self.create_axis2_placement_3d(
|
||||
position=matrix[:, 3][:3].tolist(), z_axis=matrix[:, 2][:3].tolist(), x_axis=matrix[:, 0][:3].tolist()
|
||||
)
|
||||
|
||||
def mirror(
|
||||
self,
|
||||
curve_or_item,
|
||||
@@ -599,22 +660,18 @@ class ShapeBuilder:
|
||||
|
||||
return processed_objects if (multiple_objects or multiple_transformations) else processed_objects[0]
|
||||
|
||||
def sphere(self, radius: float = 1.0, center: Vector = Vector((0, 0, 0)).freeze()) -> ifcopenshell.entity_instance:
|
||||
def sphere(self, radius: float = 1.0, center: VectorTuple = (0.0, 0.0, 0.0)) -> ifcopenshell.entity_instance:
|
||||
"""
|
||||
:param radius: radius of the sphere, defaults to 1.0
|
||||
:type radius: float, optional
|
||||
:param center: sphere position, defaults to zero-vector
|
||||
:type center: Vector, optional
|
||||
:param center: sphere position, defaults to `(0.0, 0.0, 0.0)`
|
||||
:type center: VectorTuple, optional
|
||||
|
||||
:return: IfcSphere
|
||||
:rtype: ifcopenshell.entity_instance
|
||||
"""
|
||||
|
||||
ifc_position = self.file.createIfcAxis2Placement3D(
|
||||
self.file.createIfcCartesianPoint(center), # position
|
||||
self.file.createIfcDirection((0.0, 0.0, 1.0)), # Z-axis / Axis
|
||||
self.file.createIfcDirection((1.0, 0.0, 0.0)), # X-axis / RefDirection
|
||||
)
|
||||
ifc_position = self.create_axis2_placement_3d(position=center)
|
||||
return self.file.createIfcSphere(Radius=radius, Position=ifc_position)
|
||||
|
||||
def extrude(
|
||||
@@ -655,11 +712,7 @@ class ShapeBuilder:
|
||||
if position_y_axis:
|
||||
position_z_axis = position_x_axis.cross(position_y_axis)
|
||||
|
||||
ifc_position = self.file.createIfcAxis2Placement3D(
|
||||
self.file.createIfcCartesianPoint(position), # position
|
||||
self.file.createIfcDirection(position_z_axis), # Z-axis / Axis
|
||||
self.file.createIfcDirection(position_x_axis), # X-axis / RefDirection
|
||||
)
|
||||
ifc_position = self.create_axis2_placement_3d(position, position_z_axis, position_x_axis)
|
||||
ifc_direction = self.file.createIfcDirection(extrusion_vector)
|
||||
extruded_area = self.file.createIfcExtrudedAreaSolid(
|
||||
SweptArea=profile_or_curve, Position=ifc_position, ExtrudedDirection=ifc_direction, Depth=magnitude
|
||||
|
||||
Reference in New Issue
Block a user