mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-10 17:58:20 +00:00
#2089. Fix and simplify OffsetObjectPlacement recipe for multiple absolute placements.
This commit is contained in:
@@ -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()),
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user