#2089. Fix and simplify OffsetObjectPlacement recipe for multiple absolute placements.

This commit is contained in:
Dion Moult
2022-03-22 17:27:38 +11:00
parent 533111a1fb
commit 43d0c098a0
@@ -17,6 +17,9 @@
# along with IfcPatch. If not, see <http://www.gnu.org/licenses/>.
import math
import numpy as np
import ifcopenshell
import ifcopenshell.util.placement
class Patcher:
def __init__(self, src, file, logger, args=None):
@@ -36,49 +39,17 @@ class Patcher:
absolute_placements.append(absolute_placement)
absolute_placements = set(absolute_placements)
angle = float(self.args[3])
transformation = self.z_rotation_matrix(math.radians(angle)) if angle else np.eye(4)
transformation[0][3] += float(self.args[0])
transformation[1][3] += float(self.args[1])
transformation[2][3] += float(self.args[2])
for placement in absolute_placements:
offset_location = (
placement.RelativePlacement.Location.Coordinates[0] + float(self.args[0]),
placement.RelativePlacement.Location.Coordinates[1] + float(self.args[1]),
placement.RelativePlacement.Location.Coordinates[2] + float(self.args[2])
placement.RelativePlacement = self.get_relative_placement(
transformation @ ifcopenshell.util.placement.get_local_placement(placement)
)
relative_placement = self.file.createIfcAxis2Placement3D(
self.file.createIfcCartesianPoint(offset_location))
if placement.RelativePlacement.Axis:
relative_placement.Axis = placement.RelativePlacement.Axis
if placement.RelativePlacement.RefDirection:
relative_placement.RefDirection = placement.RelativePlacement.RefDirection
angle = float(self.args[3])
if not angle:
placement.RelativePlacement = relative_placement
continue
rotation_matrix = self.z_rotation_matrix(math.radians(angle))
if len(self.args) == 5:
# Move then rotate, if you want
relative_placement.Location.Coordinates = self.multiply_by_matrix(offset_location, rotation_matrix)
else:
# Rotate then move, like Solibri
pass
if placement.RelativePlacement.Axis:
z_axis = placement.RelativePlacement.Axis.DirectionRatios
relative_placement.Axis = self.file.createIfcDirection(
self.multiply_by_matrix(z_axis, rotation_matrix))
if placement.RelativePlacement.RefDirection:
x_axis = placement.RelativePlacement.RefDirection.DirectionRatios
else:
x_axis = (1., 0., 0.)
relative_placement.RefDirection = self.file.createIfcDirection(
self.multiply_by_matrix(x_axis, rotation_matrix))
placement.RelativePlacement = relative_placement
def get_absolute_placement(self, object_placement):
if object_placement.PlacementRelTo:
return self.get_absolute_placement(object_placement.PlacementRelTo)
@@ -86,14 +57,26 @@ class Patcher:
def z_rotation_matrix(self, angle):
return [
[math.cos(angle), -math.sin(angle), 0.],
[math.sin(angle), math.cos(angle), 0.],
[0., 0., 1.]
[math.cos(angle), -math.sin(angle), 0., 0.],
[math.sin(angle), math.cos(angle), 0., 0.],
[0., 0., 1., 0.],
[0., 0., 0., 1.],
]
def multiply_by_matrix(self, v, m):
return [
v[0]*m[0][0] + v[1]*m[0][1] + v[2]*m[0][2],
v[0]*m[1][0] + v[1]*m[1][1] + v[2]*m[1][2],
v[0]*m[2][0] + v[1]*m[2][1] + v[2]*m[2][2]
]
def get_relative_placement(self, m):
x = np.array((m[0][0], m[1][0], m[2][0]))
z = np.array((m[0][2], m[1][2], m[2][2]))
o = np.array((m[0][3], m[1][3], m[2][3]))
object_matrix = ifcopenshell.util.placement.a2p(o, z, x)
return self.create_ifc_axis_2_placement_3d(
object_matrix[:, 3][0:3],
object_matrix[:, 2][0:3],
object_matrix[:, 0][0:3],
)
def create_ifc_axis_2_placement_3d(self, point, up, forward):
return self.file.createIfcAxis2Placement3D(
self.file.createIfcCartesianPoint(point.tolist()),
self.file.createIfcDirection(up.tolist()),
self.file.createIfcDirection(forward.tolist()),
)