Python - VTK 限制对象旋转问题(四元数)
Python - VTK limit rotation of object issue (Quaternion)
我正在尝试通过交互限制框小部件的旋转,以使用户能够围绕上轴旋转框。
因此我尝试了向"InteractionEvent"添加观察者的方法,并使用回调函数来反转绕x轴和z轴的旋转。
实施后我遇到了两个问题:
-) 对象变换的变化 - 在 window 中没有明显效果(也许我只是在处理 3D 对象的副本?)
-) 我所做的计算改变了四元数 - 但不是假设的那样。
有人提到只是否定 x 和 z 的符号并保持相同的程度。
我希望看到修改后的旋转结果 x 和 z 值变为零......我假设我一般误解了四元数,或者我在 vtk 函数调用中犯了一个错误
Old Orientation [11.79730158 0.87192947 0.29194216 0.39307604]
Will rotate object with the following quaternion: [11.79730158 -0.87192947 -0. -0.39307604]
New Orientation [ 3.47624906 -0.17562846 0.98392544 0.03233235]
Different Access: Orientation [ 3.47624906 -0.17562846 0.98392544 0.03233235]
结果由以下代码产生:
import numpy as np
import vtk
import math
from math import atan2, sqrt, pi
from vtk.util import numpy_support
##########################################################################
def transform(T, points):
assert(points.shape[0] >= 3)
assert(T.shape == (4, 4))
points_hom = np.vstack((points[0:3], np.ones((1, points.shape[1]))))
points_hom = np.matmul(T, points_hom)
points_hom = points_hom[0:3, :] / points_hom[3, :]
points = np.vstack((points_hom, points[3:, :]))
return points
def LeftButtonPressEvent(obj, event):
t = vtk.vtkTransform()
obj.GetTransform(t)
q = np.zeros(4)
t.GetOrientationWXYZ(q)
print(f"Old Orientation {q}")
q[2] = 0
q[1:] = -q[1:]
#angle = 2.0 * atan2(np.linalg.norm(q[1:]), q[0]/180.0*pi)*180.0/pi
print(f"Will rotate object with the following quaternion: {q}")
t.RotateWXYZ(q[0], q[1:])
obj.GetProp3D().SetUserTransform( t )
t.GetOrientationWXYZ(q)
print(f"New Orientation {q}")
obj_transform = obj.GetProp3D().GetUserTransform()
obj_transform.GetOrientationWXYZ(q)
print(f"Different Access: Orientation {q}\n\n\n")
##########################################################################
def init_vtk_pointcloud(pts, point_size=2.0, points_per_row=True):
if not points_per_row:
pts = pts.T
assert (pts.shape[1] == 3 or
pts.shape[1] == 4 or
pts.shape[1] == 6)
if pts.shape[1] == 3:
color = np.ones((pts.shape[0], 3), np.uint8) * 255
elif pts.shape[1] == 4:
color = (pts[:, 3] * np.ones((3, 1)) * 255).astype(np.uint8).T
elif pts.shape[1] == 6 or pts.shape[1] == 7:
color = pts[:, 3:6]
else:
assert False, "Dimension of points is not 3 (without color), " \
"4 (with intensity) or 6/7 (with color and optionally intensity)"
vtk_point_cloud = VtkPointCloud(point_size=point_size)
vtk_point_cloud.set_points(pts[:, :3], color)
return vtk_point_cloud
##########################################################################
def init_rendering(axes_scaling, background_color, camera, point_size, other_actors,
points_per_row, pts, window_name, window_size):
vtk_point_cloud = init_vtk_pointcloud(pts, point_size, points_per_row)
# Renderer
renderer = vtk.vtkRenderer()
renderer.SetActiveCamera(camera)
renderer.SetBackground(*background_color)
# Render Window
render_window = vtk.vtkRenderWindow()
render_window.AddRenderer(renderer)
render_window.SetWindowName(window_name)
render_window.SetSize(*window_size)
# Add actor
renderer.AddActor(vtk_point_cloud.vtkActor)
return render_window, vtk_point_cloud
##########################################################################
def show_pointcloud(pts, window_name='Debug', points_per_row=True, background_color=[.0, .3, .4], camera=None,
axes_scaling=1.0, point_size=1.0, other_actors=[], window_size=(1280, 720), finalize=True):
renderWindow, vtk_point_cloud = init_rendering(axes_scaling, background_color, camera, point_size,
other_actors, points_per_row, pts, window_name, window_size)
# Interactor
renderWindowInteractor = vtk.vtkRenderWindowInteractor()
renderWindowInteractor.SetInteractorStyle(
PointSizeInteractorStyle(renderWindowInteractor, vtk_point_cloud))
renderWindowInteractor.SetRenderWindow(renderWindow)
boxActor = vtk.vtkActor()
boxWidget = vtk.vtkBoxWidget()
boxWidget.SetInteractor(renderWindowInteractor)#renderer interactor
boxWidget.SetProp3D(boxActor)#actor here
boxWidget.SetPlaceFactor(1.0)
boxWidget.PlaceWidget()
#ToDo: first interaction does not work except user scrolls beforehand... why?
boxWidget.On()
boxWidget.AddObserver("InteractionEvent", LeftButtonPressEvent)
renderWindow.Render()
renderWindowInteractor.Start()
if finalize:
renderWindow.Finalize()
##########################################################################
def create_cylinder(radius=1.0, height=1.0, pos=[0.0, 0.0, 0.0], approx_samples=1000):
perimeter = 2 * math.pi * radius
base_area = radius**2 * math.pi
area = perimeter * height + 2*base_area
# points per areal unit
pts_per_au = approx_samples / area
no_base_square_samples = int(pts_per_au*4*radius**2)
base = np.random.rand(no_base_square_samples, 2) * 2 * radius - radius
radii = np.linalg.norm(base, axis=1)
mask = radii < radius
base = base[mask, :]
max_dim = max(perimeter, height)
surface_samples = int(pts_per_au * (max_dim**2))
surface = np.random.rand(surface_samples, 2) * max_dim
mask = (surface[:, 0] < perimeter) & (surface[:, 1] < height)
surface = surface[mask, :]
surface = np.vstack((radius*np.sin(surface[:, 0]/radius), radius*np.cos(surface[:, 0]/radius),
surface[:, 1] - height/2.0)).T
top = np.hstack((base, np.ones((base.shape[0], 1)) * height/2.0))
bottom = top * (1.0, 1.0, -1.0)
pts = np.vstack((top, bottom, surface)) + pos
return pts
##########################################################################
class VtkPointCloud:
def add_point(self, point):
if self.vtkPoints.GetNumberOfPoints() < self.maxNumPoints:
pointId = self.vtkPoints.InsertNextPoint(point[:])
self.vtkDepth.InsertNextValue(point[2])
self.vtkCells.InsertNextCell(1)
self.vtkCells.InsertCellPoint(pointId)
else:
r = np.random.randint(0, self.maxNumPoints)
self.vtkPoints.SetPoint(r, point[:])
self.vtkCells.Modified()
self.vtkPoints.Modified()
self.vtkDepth.Modified()
##########################################################################
def __init__(self, zMin=-10.0, zMax=10.0, maxNumPoints=1e6, point_size=2):
self.maxNumPoints = maxNumPoints
self.vtkPolyData = vtk.vtkPolyData()
self.clear_points()
mapper = vtk.vtkPolyDataMapper()
mapper.SetInputData(self.vtkPolyData)
mapper.SetColorModeToDefault()
mapper.SetScalarRange(zMin, zMax)
mapper.SetScalarVisibility(1)
self.vtkActor = vtk.vtkActor()
self.vtkActor.SetMapper(mapper)
self.vtkActor.GetProperty().SetPointSize(point_size)
##########################################################################
def set_points(self, points, color=None):
if color is None:
if points.shape[1] == 3:
color = np.ones((points.shape[0], 3), np.uint8) * 255
elif points.shape[1] == 4:
color = value2hsvcolormap(points[:, 3])
# color = (points[:, 3] * np.ones((3, 1)) * 255).astype(np.uint8).T
elif points.shape[1] == 6 or points.shape[1] == 7:
color = points[:, 3:6]
color = np.ascontiguousarray(color)
points = np.ascontiguousarray(points[:, :3])
vtk_cell_idc = np.zeros((points.shape[0] * 2,), dtype=np.int64)
vtk_cell_idc[0::2] = 1
vtk_cell_idc[1::2] = np.arange(points.shape[0])
vtk_point_data = numpy_support.numpy_to_vtk(num_array=points, deep=True, array_type=vtk.VTK_FLOAT)
self.vtkPoints.SetData(vtk_point_data)
if color is not None:
vtk_color_data = numpy_support.numpy_to_vtk(num_array=color, deep=True, array_type=vtk.VTK_UNSIGNED_CHAR)
vtk_color_data.SetName('Color')
self.vtkPolyData.GetPointData().SetScalars(vtk_color_data)
self.vtkPolyData.GetPointData().SetActiveScalars('Color')
vtk_cell_data = numpy_support.numpy_to_vtk(num_array=vtk_cell_idc, deep=True, array_type=vtk.VTK_ID_TYPE)
self.vtkCells.SetCells(points.shape[0], vtk_cell_data)
self.vtkPoints.Modified()
self.vtkCells.Modified()
self.vtkPolyData.Modified()
##########################################################################
def clear_points(self):
self.vtkPoints = vtk.vtkPoints()
self.vtkCells = vtk.vtkCellArray()
self.vtkPolyData.SetPoints(self.vtkPoints)
self.vtkPolyData.SetVerts(self.vtkCells)
##########################################################################
class PointSizeInteractorStyle(vtk.vtkInteractorStyleTrackballCamera):
def __init__(self, parent, point_cloud=None, max_pt_size=20):
self.AddObserver("MouseWheelForwardEvent", self.mouse_wheel_forward_event)
self.AddObserver("MouseWheelBackwardEvent", self.mouse_wheel_backward_event)
self.AddObserver("LeftButtonPressEvent", self.LeftButtonPressEvent)
self._parent = parent
self._point_cloud = point_cloud
self._max_pt_size = max_pt_size
##########################################################################
def mouse_wheel_forward_event(self, obj, event):
if self._parent.GetAltKey():
new_point_size = self._point_cloud_actor.GetProperty().GetPointSize() + 1
new_point_size = self._max_pt_size if new_point_size > self._max_pt_size else new_point_size
self._point_cloud.vtkActor.GetProperty().SetPointSize(new_point_size)
self._parent.GetRenderWindow().Render()
else:
self.OnMouseWheelForward()
return
def LeftButtonPressEvent(self, obj, event):
print("Global interactor")
self.OnLeftButtonDown()
##########################################################################
def mouse_wheel_backward_event(self, obj, event):
if self._parent.GetAltKey():
new_point_size = self._point_cloud_actor.GetProperty().GetPointSize() - 1
new_point_size = 1 if new_point_size < 1 else new_point_size
self._point_cloud.vtkActor.GetProperty().SetPointSize(new_point_size)
self._parent.GetRenderWindow().Render()
else:
self.OnMouseWheelBackward()
return
##########################################################################
class PointCloudInteractorStyle(PointSizeInteractorStyle):
def __init__(self, parent, image_actor, point_cloud, caption_renderer, pc_gen=None, max_pt_size=20):
# self.AddObserver("KeyPressEvent", self.key_press_event)
self._parent = parent
self._image_actor = image_actor
self._pc_gen = pc_gen
self._caption_renderer = caption_renderer
self._caption_renderer.RemoveAllViewProps()
point_cloud.set_points(pts)
super().__init__(parent, point_cloud)
#########################################################################
def main():
point_cloud_cube = create_cylinder()
# point_cloud_cube = point_cloud_cube + np.random.rand(*point_cloud_cube.shape) * 0.02
R, _ = np.linalg.qr(np.random.rand(3, 3))
#point_cloud_cube = transformation.rotate(R, point_cloud_cube.T).T
point_cloud = np.vstack((point_cloud_cube))
color = np.ones((point_cloud.shape[0], 3), dtype=point_cloud.dtype) * 255
camera = vtk.vtkCamera()
camera.SetViewUp(0, -1, 0)
camera.SetPosition(2, -1, -4)
camera.SetFocalPoint(0, 0, 0)
point_cloud = np.hstack((point_cloud[:, :3], color))
show_pointcloud(point_cloud, 'Test', camera=camera, axes_scaling=0.5)
if __name__ == '__main__':
main()
我能够解决它 - 因此我不得不使用 oldTransform.PostMultiply() 推迟某些矩阵操作,正如您在这里看到的...
class ModBoxWidget(vtk.vtkBoxWidget):
def __init__(self, fixed_Y_pos=None):
self.AddObserver("InteractionEvent", self.horizontal_move_event)
#super().__init__(self)
self.fixed_Y_pos = fixed_Y_pos
def horizontal_move_event(self, obj, event):
oldTransform = vtk.vtkTransform()
obj.GetTransform(oldTransform)
q = np.zeros(4)
oldTransform.GetOrientationWXYZ(q)
oldTransform.PostMultiply()
newTransform = vtk.vtkTransform()
pos = np.zeros(3)
polyData = vtk.vtkPolyData()
obj.GetPolyData(polyData)
num_points = polyData.GetNumberOfPoints()
coords = np.zeros((num_points, 3))
for i in range(num_points):
polyData.GetPoint(i, coords[i])
pos[0] = coords[14][0]
pos[1] = coords[14][1]
pos[2] = coords[14][2]
newTransform.PostMultiply()
newTransform.Identity()
newTransform.Translate(-pos[0], -pos[1], -pos[2])
print(f"{-q[0]*q[1]:3.2f} {-q[0]*q[1]:3.2f} {-q[0]*q[2]:3.2f}")
newTransform.RotateX(-q[0]*q[1])
newTransform.RotateY(-q[0]*q[2])
newTransform.Translate(pos[0], pos[1], self.fixed_Y_pos or obj.GetProp3D().GetScale()[1]/2.0)
oldTransform.Concatenate(newTransform)
obj.SetTransform(oldTransform)
obj.SetHandleSize(0.001)
我正在尝试通过交互限制框小部件的旋转,以使用户能够围绕上轴旋转框。
因此我尝试了向"InteractionEvent"添加观察者的方法,并使用回调函数来反转绕x轴和z轴的旋转。
实施后我遇到了两个问题:
-) 对象变换的变化 - 在 window 中没有明显效果(也许我只是在处理 3D 对象的副本?)
-) 我所做的计算改变了四元数 - 但不是假设的那样。 有人提到只是否定 x 和 z 的符号并保持相同的程度。 我希望看到修改后的旋转结果 x 和 z 值变为零......我假设我一般误解了四元数,或者我在 vtk 函数调用中犯了一个错误
Old Orientation [11.79730158 0.87192947 0.29194216 0.39307604]
Will rotate object with the following quaternion: [11.79730158 -0.87192947 -0. -0.39307604]
New Orientation [ 3.47624906 -0.17562846 0.98392544 0.03233235]
Different Access: Orientation [ 3.47624906 -0.17562846 0.98392544 0.03233235]
结果由以下代码产生:
import numpy as np
import vtk
import math
from math import atan2, sqrt, pi
from vtk.util import numpy_support
##########################################################################
def transform(T, points):
assert(points.shape[0] >= 3)
assert(T.shape == (4, 4))
points_hom = np.vstack((points[0:3], np.ones((1, points.shape[1]))))
points_hom = np.matmul(T, points_hom)
points_hom = points_hom[0:3, :] / points_hom[3, :]
points = np.vstack((points_hom, points[3:, :]))
return points
def LeftButtonPressEvent(obj, event):
t = vtk.vtkTransform()
obj.GetTransform(t)
q = np.zeros(4)
t.GetOrientationWXYZ(q)
print(f"Old Orientation {q}")
q[2] = 0
q[1:] = -q[1:]
#angle = 2.0 * atan2(np.linalg.norm(q[1:]), q[0]/180.0*pi)*180.0/pi
print(f"Will rotate object with the following quaternion: {q}")
t.RotateWXYZ(q[0], q[1:])
obj.GetProp3D().SetUserTransform( t )
t.GetOrientationWXYZ(q)
print(f"New Orientation {q}")
obj_transform = obj.GetProp3D().GetUserTransform()
obj_transform.GetOrientationWXYZ(q)
print(f"Different Access: Orientation {q}\n\n\n")
##########################################################################
def init_vtk_pointcloud(pts, point_size=2.0, points_per_row=True):
if not points_per_row:
pts = pts.T
assert (pts.shape[1] == 3 or
pts.shape[1] == 4 or
pts.shape[1] == 6)
if pts.shape[1] == 3:
color = np.ones((pts.shape[0], 3), np.uint8) * 255
elif pts.shape[1] == 4:
color = (pts[:, 3] * np.ones((3, 1)) * 255).astype(np.uint8).T
elif pts.shape[1] == 6 or pts.shape[1] == 7:
color = pts[:, 3:6]
else:
assert False, "Dimension of points is not 3 (without color), " \
"4 (with intensity) or 6/7 (with color and optionally intensity)"
vtk_point_cloud = VtkPointCloud(point_size=point_size)
vtk_point_cloud.set_points(pts[:, :3], color)
return vtk_point_cloud
##########################################################################
def init_rendering(axes_scaling, background_color, camera, point_size, other_actors,
points_per_row, pts, window_name, window_size):
vtk_point_cloud = init_vtk_pointcloud(pts, point_size, points_per_row)
# Renderer
renderer = vtk.vtkRenderer()
renderer.SetActiveCamera(camera)
renderer.SetBackground(*background_color)
# Render Window
render_window = vtk.vtkRenderWindow()
render_window.AddRenderer(renderer)
render_window.SetWindowName(window_name)
render_window.SetSize(*window_size)
# Add actor
renderer.AddActor(vtk_point_cloud.vtkActor)
return render_window, vtk_point_cloud
##########################################################################
def show_pointcloud(pts, window_name='Debug', points_per_row=True, background_color=[.0, .3, .4], camera=None,
axes_scaling=1.0, point_size=1.0, other_actors=[], window_size=(1280, 720), finalize=True):
renderWindow, vtk_point_cloud = init_rendering(axes_scaling, background_color, camera, point_size,
other_actors, points_per_row, pts, window_name, window_size)
# Interactor
renderWindowInteractor = vtk.vtkRenderWindowInteractor()
renderWindowInteractor.SetInteractorStyle(
PointSizeInteractorStyle(renderWindowInteractor, vtk_point_cloud))
renderWindowInteractor.SetRenderWindow(renderWindow)
boxActor = vtk.vtkActor()
boxWidget = vtk.vtkBoxWidget()
boxWidget.SetInteractor(renderWindowInteractor)#renderer interactor
boxWidget.SetProp3D(boxActor)#actor here
boxWidget.SetPlaceFactor(1.0)
boxWidget.PlaceWidget()
#ToDo: first interaction does not work except user scrolls beforehand... why?
boxWidget.On()
boxWidget.AddObserver("InteractionEvent", LeftButtonPressEvent)
renderWindow.Render()
renderWindowInteractor.Start()
if finalize:
renderWindow.Finalize()
##########################################################################
def create_cylinder(radius=1.0, height=1.0, pos=[0.0, 0.0, 0.0], approx_samples=1000):
perimeter = 2 * math.pi * radius
base_area = radius**2 * math.pi
area = perimeter * height + 2*base_area
# points per areal unit
pts_per_au = approx_samples / area
no_base_square_samples = int(pts_per_au*4*radius**2)
base = np.random.rand(no_base_square_samples, 2) * 2 * radius - radius
radii = np.linalg.norm(base, axis=1)
mask = radii < radius
base = base[mask, :]
max_dim = max(perimeter, height)
surface_samples = int(pts_per_au * (max_dim**2))
surface = np.random.rand(surface_samples, 2) * max_dim
mask = (surface[:, 0] < perimeter) & (surface[:, 1] < height)
surface = surface[mask, :]
surface = np.vstack((radius*np.sin(surface[:, 0]/radius), radius*np.cos(surface[:, 0]/radius),
surface[:, 1] - height/2.0)).T
top = np.hstack((base, np.ones((base.shape[0], 1)) * height/2.0))
bottom = top * (1.0, 1.0, -1.0)
pts = np.vstack((top, bottom, surface)) + pos
return pts
##########################################################################
class VtkPointCloud:
def add_point(self, point):
if self.vtkPoints.GetNumberOfPoints() < self.maxNumPoints:
pointId = self.vtkPoints.InsertNextPoint(point[:])
self.vtkDepth.InsertNextValue(point[2])
self.vtkCells.InsertNextCell(1)
self.vtkCells.InsertCellPoint(pointId)
else:
r = np.random.randint(0, self.maxNumPoints)
self.vtkPoints.SetPoint(r, point[:])
self.vtkCells.Modified()
self.vtkPoints.Modified()
self.vtkDepth.Modified()
##########################################################################
def __init__(self, zMin=-10.0, zMax=10.0, maxNumPoints=1e6, point_size=2):
self.maxNumPoints = maxNumPoints
self.vtkPolyData = vtk.vtkPolyData()
self.clear_points()
mapper = vtk.vtkPolyDataMapper()
mapper.SetInputData(self.vtkPolyData)
mapper.SetColorModeToDefault()
mapper.SetScalarRange(zMin, zMax)
mapper.SetScalarVisibility(1)
self.vtkActor = vtk.vtkActor()
self.vtkActor.SetMapper(mapper)
self.vtkActor.GetProperty().SetPointSize(point_size)
##########################################################################
def set_points(self, points, color=None):
if color is None:
if points.shape[1] == 3:
color = np.ones((points.shape[0], 3), np.uint8) * 255
elif points.shape[1] == 4:
color = value2hsvcolormap(points[:, 3])
# color = (points[:, 3] * np.ones((3, 1)) * 255).astype(np.uint8).T
elif points.shape[1] == 6 or points.shape[1] == 7:
color = points[:, 3:6]
color = np.ascontiguousarray(color)
points = np.ascontiguousarray(points[:, :3])
vtk_cell_idc = np.zeros((points.shape[0] * 2,), dtype=np.int64)
vtk_cell_idc[0::2] = 1
vtk_cell_idc[1::2] = np.arange(points.shape[0])
vtk_point_data = numpy_support.numpy_to_vtk(num_array=points, deep=True, array_type=vtk.VTK_FLOAT)
self.vtkPoints.SetData(vtk_point_data)
if color is not None:
vtk_color_data = numpy_support.numpy_to_vtk(num_array=color, deep=True, array_type=vtk.VTK_UNSIGNED_CHAR)
vtk_color_data.SetName('Color')
self.vtkPolyData.GetPointData().SetScalars(vtk_color_data)
self.vtkPolyData.GetPointData().SetActiveScalars('Color')
vtk_cell_data = numpy_support.numpy_to_vtk(num_array=vtk_cell_idc, deep=True, array_type=vtk.VTK_ID_TYPE)
self.vtkCells.SetCells(points.shape[0], vtk_cell_data)
self.vtkPoints.Modified()
self.vtkCells.Modified()
self.vtkPolyData.Modified()
##########################################################################
def clear_points(self):
self.vtkPoints = vtk.vtkPoints()
self.vtkCells = vtk.vtkCellArray()
self.vtkPolyData.SetPoints(self.vtkPoints)
self.vtkPolyData.SetVerts(self.vtkCells)
##########################################################################
class PointSizeInteractorStyle(vtk.vtkInteractorStyleTrackballCamera):
def __init__(self, parent, point_cloud=None, max_pt_size=20):
self.AddObserver("MouseWheelForwardEvent", self.mouse_wheel_forward_event)
self.AddObserver("MouseWheelBackwardEvent", self.mouse_wheel_backward_event)
self.AddObserver("LeftButtonPressEvent", self.LeftButtonPressEvent)
self._parent = parent
self._point_cloud = point_cloud
self._max_pt_size = max_pt_size
##########################################################################
def mouse_wheel_forward_event(self, obj, event):
if self._parent.GetAltKey():
new_point_size = self._point_cloud_actor.GetProperty().GetPointSize() + 1
new_point_size = self._max_pt_size if new_point_size > self._max_pt_size else new_point_size
self._point_cloud.vtkActor.GetProperty().SetPointSize(new_point_size)
self._parent.GetRenderWindow().Render()
else:
self.OnMouseWheelForward()
return
def LeftButtonPressEvent(self, obj, event):
print("Global interactor")
self.OnLeftButtonDown()
##########################################################################
def mouse_wheel_backward_event(self, obj, event):
if self._parent.GetAltKey():
new_point_size = self._point_cloud_actor.GetProperty().GetPointSize() - 1
new_point_size = 1 if new_point_size < 1 else new_point_size
self._point_cloud.vtkActor.GetProperty().SetPointSize(new_point_size)
self._parent.GetRenderWindow().Render()
else:
self.OnMouseWheelBackward()
return
##########################################################################
class PointCloudInteractorStyle(PointSizeInteractorStyle):
def __init__(self, parent, image_actor, point_cloud, caption_renderer, pc_gen=None, max_pt_size=20):
# self.AddObserver("KeyPressEvent", self.key_press_event)
self._parent = parent
self._image_actor = image_actor
self._pc_gen = pc_gen
self._caption_renderer = caption_renderer
self._caption_renderer.RemoveAllViewProps()
point_cloud.set_points(pts)
super().__init__(parent, point_cloud)
#########################################################################
def main():
point_cloud_cube = create_cylinder()
# point_cloud_cube = point_cloud_cube + np.random.rand(*point_cloud_cube.shape) * 0.02
R, _ = np.linalg.qr(np.random.rand(3, 3))
#point_cloud_cube = transformation.rotate(R, point_cloud_cube.T).T
point_cloud = np.vstack((point_cloud_cube))
color = np.ones((point_cloud.shape[0], 3), dtype=point_cloud.dtype) * 255
camera = vtk.vtkCamera()
camera.SetViewUp(0, -1, 0)
camera.SetPosition(2, -1, -4)
camera.SetFocalPoint(0, 0, 0)
point_cloud = np.hstack((point_cloud[:, :3], color))
show_pointcloud(point_cloud, 'Test', camera=camera, axes_scaling=0.5)
if __name__ == '__main__':
main()
我能够解决它 - 因此我不得不使用 oldTransform.PostMultiply() 推迟某些矩阵操作,正如您在这里看到的...
class ModBoxWidget(vtk.vtkBoxWidget):
def __init__(self, fixed_Y_pos=None):
self.AddObserver("InteractionEvent", self.horizontal_move_event)
#super().__init__(self)
self.fixed_Y_pos = fixed_Y_pos
def horizontal_move_event(self, obj, event):
oldTransform = vtk.vtkTransform()
obj.GetTransform(oldTransform)
q = np.zeros(4)
oldTransform.GetOrientationWXYZ(q)
oldTransform.PostMultiply()
newTransform = vtk.vtkTransform()
pos = np.zeros(3)
polyData = vtk.vtkPolyData()
obj.GetPolyData(polyData)
num_points = polyData.GetNumberOfPoints()
coords = np.zeros((num_points, 3))
for i in range(num_points):
polyData.GetPoint(i, coords[i])
pos[0] = coords[14][0]
pos[1] = coords[14][1]
pos[2] = coords[14][2]
newTransform.PostMultiply()
newTransform.Identity()
newTransform.Translate(-pos[0], -pos[1], -pos[2])
print(f"{-q[0]*q[1]:3.2f} {-q[0]*q[1]:3.2f} {-q[0]*q[2]:3.2f}")
newTransform.RotateX(-q[0]*q[1])
newTransform.RotateY(-q[0]*q[2])
newTransform.Translate(pos[0], pos[1], self.fixed_Y_pos or obj.GetProp3D().GetScale()[1]/2.0)
oldTransform.Concatenate(newTransform)
obj.SetTransform(oldTransform)
obj.SetHandleSize(0.001)