C# VTK 移动旋转交互功能实现
作者:Mr.For
对vtk 场景中一个或多个选中物体进行移动旋转。
交互移动旋转坐标系
首先我们创建旋转的交互坐标系,三个移动Actor,三个旋转Actor,还需要4个定位坐标的小球Actor。
public class CoordinateActor 中添加Actor // 当前选中的Actor public vtkActor selActor; // 定位中心小球 public vtkActor cenActor; // 旋转Actor public vtkActor rotX; public vtkActor rotY; public vtkActor rotZ; // 移动Actor public vtkActor moveX; public vtkActor moveY; public vtkActor moveZ; // 末端定位小球 public vtkActor moveXEnd; public vtkActor moveYEnd; public vtkActor moveZEnd;
创建X轴移动Actor
public vtkActor LineActor(Point3d p1, Point3d p2, double[] color) { vtkLineSource lineSource = new vtkLineSource(); lineSource.SetPoint1(p1.X, p1.Y, p1.Z); lineSource.SetPoint2(p2.X, p2.Y, p2.Z); lineSource.Update(); vtkPolyDataMapper mapper = new vtkPolyDataMapper(); mapper.SetInputData(lineSource.GetOutput()); mapper.Update(); vtkActor actor = new vtkActor(); actor.SetMapper(mapper); actor.GetProperty().SetColor(color[0], color[1], color[2]); actor.GetProperty().SetLineWidth(10); return actor; }
这里的p1,p2 是根据模型的中心点和大小决定的。
假设创建了一个Box 长宽高 200, 模型中心在(0,0,0)。
以X移动Actor为例,这样vtkLineSource p1 = (0,0,0) p2(200,0,0) 。
同时创建 cenActor , moveXEnd 两个定位小球。
现在我们已经创建了一个X轴方向的移动交互Actor ------- moveX。
X轴移动交互
有了moveX 现在为其添加移动交互的事件,参与移动的鼠标事件有四种。
MouseMove(LeftDown==false):
当鼠标只是在场景中自由移动,未点击时,移动到moveX时应该触发待选状态,既是改变moveX 颜色。在MouseMove中需要随时判断是否鼠标选中Actor 且是 moveX。是就改变颜色,不是就还原颜色(需要设置为默认颜色)。
MouseDown
改变 bool LeftDown = true
MouseUp
改变 bool LeftDown = false
firstPos == null
lastPos = null
MouseMove(LeftDown==true):
此时真正开始旋转
1.计算移动距离方向
需要 两个Point2d 记录firstPos 和 lastPos 两个鼠标平面点,用于鼠标的移动距离和方向。
Point2d moveNorm = lastPos - firstPos;
还记得我们之前的定位小球吗,将cenActor 和 moveXEnd 中心点 转换为屏幕坐标。
得到 center2d ,moveXEnd2d
Point2d xLineNorm = moveXEnd2d - center2d
计算 moveNorm 投影到 xLineNorm 的 长度,既是移动的长度和方向(我们只在X 的正负方向移动)。
// 计算点积 public static double DotProduct2D(Point2d vectorA, Point2d vectorB) { return vectorA.X * vectorB.X + vectorA.Y * vectorB.Y; } // 计算向量的模(长度) public static double Magnitude2D(Point2d vector) { return Math.Sqrt(vector.X * vector.X + vector.Y * vector.Y); } // 计算向量 A 投影到向量 B 上的长度 public static double ProjectionLength(Point2d vectorA, Point2d vectorB) { double dotProduct = DotProduct2D(vectorA, vectorB); double magnitudeB = Magnitude2D(vectorB); if (magnitudeB == 0) return 0; return dotProduct / magnitudeB; }
2.实现移动
vtk 通过vtkTransform实现移动旋转
public void MoveAllAcotr(double moveValue, Orien orien) { vtkTransform transform = new vtkTransform(); if(orien == Orien.X) { transform.Translate(moveValue,0,0); } else if (orien == Orien.Y) { transform.Translate(0, moveValue, 0); } else if (orien == Orien.Z) { transform.Translate(0, 0, moveValue); } transform.Update(); // 移动 模型 TransformActor(model, transform); TransformActor(cenActor, transform); TransformActor(moveXEnd, transform); TransformActor(moveYEnd, transform); TransformActor(moveZEnd, transform); TransformActor(moveX, transform); TransformActor(moveY, transform); TransformActor(moveZ, transform); TransformActor(rotX, transform); TransformActor(rotY, transform); TransformActor(rotZ, transform); }
public void TransformActor(vtkActor actor, vtkTransform transform) { vtkTransformFilter filter = new vtkTransformFilter(); filter.SetTransform(transform); filter.SetInputData(actor.GetMapper().GetInput()); filter.Update(); actor.GetMapper().GetInput().DeepCopy(filter.GetOutput()); }
(记得每一个交互的Actor 都要进行这个操作一起移动,包括定位小球)
X 轴旋转交互
使用 vtkRegularPolygonSource 创建空间圆 rotX, norm 为 (1,0,0)
public vtkActor CircleActor(Point3d center, Point3d norm, double radius, double[] color) { vtkRegularPolygonSource polygonSource = new vtkRegularPolygonSource(); polygonSource.SetCenter(center.X, center.Y, center.Z); polygonSource.SetNormal(norm.X, norm.Y, norm.Z); polygonSource.SetRadius(radius); polygonSource.SetNumberOfSides(30); polygonSource.SetGeneratePolyline(1); polygonSource.SetGeneratePolygon(0); polygonSource.Update(); vtkPolyDataMapper mapper = new vtkPolyDataMapper(); mapper.SetInputData(polygonSource.GetOutput()); mapper.Update(); vtkActor actor = new vtkActor(); actor.SetMapper(mapper); actor.GetProperty().SetColor(color[0], color[1], color[2]); actor.GetProperty().SetLineWidth(10); return actor; }
其他操作与移动相同。
不同的是旋转时和移动相关Actor不旋转的,为了保持永远在X 方向上移动。
(如果想在任意方向上移动可以计算移动时的方向向量,此时全部Actor旋转)
旋转代码
public void RotateAllAcotr(double rotAngel, Point3d norm, Orien orien) { Point3d center = new Point3d(cenActor.GetCenter()); vtkTransform transform = new vtkTransform(); transform.Translate(-center.X, -center.Y, -center.Z); if (orien == Orien.X) { transform.RotateWXYZ(rotAngel, norm.X, norm.Y, norm.Z); } else if (orien == Orien.Y) { transform.RotateWXYZ(rotAngel, norm.X, norm.Y, norm.Z); } else if (orien == Orien.Z) { transform.RotateWXYZ(rotAngel, norm.X, norm.Y, norm.Z); } transform.Translate(center.X, center.Y, center.Z); transform.Update(); TransformActor(model, transform); TransformActor(cenActor, transform); TransformActor(rotX, transform); TransformActor(rotY, transform); TransformActor(rotZ, transform); }
public void TransformActor(vtkActor actor, vtkTransform transform) { vtkTransformFilter filter = new vtkTransformFilter(); filter.SetTransform(transform); filter.SetInputData(actor.GetMapper().GetInput()); filter.Update(); actor.GetMapper().GetInput().DeepCopy(filter.GetOutput()); }
这只是个简单的基本方法有不足的地方,其中有很过细节可以根据需要进行修改。
到此这篇关于C# VTK 移动旋转的文章就介绍到这了,更多相关C# 移动旋转内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!