mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-20 23:36: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/>.
|
# along with IfcPatch. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import math
|
import math
|
||||||
|
import numpy as np
|
||||||
|
import ifcopenshell
|
||||||
|
import ifcopenshell.util.placement
|
||||||
|
|
||||||
class Patcher:
|
class Patcher:
|
||||||
def __init__(self, src, file, logger, args=None):
|
def __init__(self, src, file, logger, args=None):
|
||||||
@@ -36,49 +39,17 @@ class Patcher:
|
|||||||
absolute_placements.append(absolute_placement)
|
absolute_placements.append(absolute_placement)
|
||||||
absolute_placements = set(absolute_placements)
|
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:
|
for placement in absolute_placements:
|
||||||
offset_location = (
|
placement.RelativePlacement = self.get_relative_placement(
|
||||||
placement.RelativePlacement.Location.Coordinates[0] + float(self.args[0]),
|
transformation @ ifcopenshell.util.placement.get_local_placement(placement)
|
||||||
placement.RelativePlacement.Location.Coordinates[1] + float(self.args[1]),
|
|
||||||
placement.RelativePlacement.Location.Coordinates[2] + float(self.args[2])
|
|
||||||
)
|
)
|
||||||
|
|
||||||
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):
|
def get_absolute_placement(self, object_placement):
|
||||||
if object_placement.PlacementRelTo:
|
if object_placement.PlacementRelTo:
|
||||||
return self.get_absolute_placement(object_placement.PlacementRelTo)
|
return self.get_absolute_placement(object_placement.PlacementRelTo)
|
||||||
@@ -86,14 +57,26 @@ class Patcher:
|
|||||||
|
|
||||||
def z_rotation_matrix(self, angle):
|
def z_rotation_matrix(self, angle):
|
||||||
return [
|
return [
|
||||||
[math.cos(angle), -math.sin(angle), 0.],
|
[math.cos(angle), -math.sin(angle), 0., 0.],
|
||||||
[math.sin(angle), math.cos(angle), 0.],
|
[math.sin(angle), math.cos(angle), 0., 0.],
|
||||||
[0., 0., 1.]
|
[0., 0., 1., 0.],
|
||||||
|
[0., 0., 0., 1.],
|
||||||
]
|
]
|
||||||
|
|
||||||
def multiply_by_matrix(self, v, m):
|
def get_relative_placement(self, m):
|
||||||
return [
|
x = np.array((m[0][0], m[1][0], m[2][0]))
|
||||||
v[0]*m[0][0] + v[1]*m[0][1] + v[2]*m[0][2],
|
z = np.array((m[0][2], m[1][2], m[2][2]))
|
||||||
v[0]*m[1][0] + v[1]*m[1][1] + v[2]*m[1][2],
|
o = np.array((m[0][3], m[1][3], m[2][3]))
|
||||||
v[0]*m[2][0] + v[1]*m[2][1] + v[2]*m[2][2]
|
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