C# VTK 移动旋转

news2024/12/23 15:22:31

对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());
        }

这只是个简单的基本方法有不足的地方,其中有很过细节可以根据需要进行修改。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1859810.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数据结构与算法:回溯算法约束条件:剪枝详解、示例(C#、C++)与回溯典型例题详解

文章目录 一、约束条件二、剪枝三、典型例题四、常用术语五、示例N 皇后问题 C# 示例N 皇后问题 C 示例 六、常见用用回溯算法解决的问题汇总组合问题:图论问题:棋盘游戏问题:优化问题:调度问题:其他问题: …

Study--Oracle-04-SQL练习

一、SQL语句思维导图 二、SQL练习 -- 以employee_id 为排序,列出前5个人 -- FETCH select employee_id,first_name from employees order by employee_id FETCH FIRST 5 rows only; -- 以employee_id 为排序,从第6个人开始 到第10个人 -- offset …

48、基于深度学习的离群值输入向量(matlab)

1、基于深度学习的离群值输入向量原理及流程 基于深度学习的离群值检测的输入向量原理是通过神经网络模型对数据进行学习和表示,在该表示中探测异常样本。其流程大致如下: 数据预处理:将数据进行归一化处理,确保神经网络模型能够…

【MDK5问题】:MDK5无法跳转,并且提示:no browse information available in xxxxx

1、问题: MDK5原来的函数调用可以直接跳转到原函数,但是出现不能跳转原函数的情况,且提示:no browse information available in xxxxx 的情况; 2、解决: 如下图所示:在魔术棒(pro…

Springboot启动mongoDB报错后禁用mongoDB自动配置

一、背景 最近在项目当中使用到MongoDB的驱动及相关依赖,发现在启动的时候有MongoDB启动报错信息,目前也不直接使用MongoDB,所以把自动配置这一块在启动的时候去除掉。 二、操作方式 Application启动类,修改启动SpringBootAppli…

【STM32】GPIO复用和映射

1.什么叫管脚复用 STM32F4有很多的内置外设,这些外设的外部引脚都是与GPIO复用的。也就是说,一个GPIO如果可以复用为内置外设的功能引脚,那么当这个GPIO作为内置外设使用的时候,就叫做复用。 STM32F4系列微控制器IO引脚通过一个…

GPT-5:人工智能的新篇章,未来已来

目录 GPT-5:人工智能的新篇章,未来已来 引言 1.人工智能的快速发展和对现代社会的影响 2.OpenAI首席技术官米拉穆拉蒂关于GPT-5发布的消息 3.GPT-5对AI领域的潜在影响和期待 4.迎接GPT-5时代的准备 方向一:GPT-5技术突破预测 1.1 GPT-…

百度大模型安全荣获2024世界智能产业博览会“Find智能科技创新应用典型案例”

6月20日,2024世界智能产业博览会在天津开幕。会议聚焦人工智能、智能网联汽车、智能制造等年度热点议题,由世界智能产业博览会组委会指导,世界智能产业博览会组委会秘书处、中国新一代人工智能战略发展研究院、中国软件行业协会、中国网络空间…

第二证券:港交所上市24周年 市值增长38倍

香港交易及结算所有限公司(下称香港交易所)于近来举办庆典活动,庆祝上市24周年。 据介绍,自2000年起,香港交易所逐步发展成为全球领先的商场营运机构,也成为连接中国内地与国际商场的主要桥梁。到2024年6月…

3 话题通信-API的使用

目录 (一)常用API 1 初始化 1.1 初始化函数(c++) (1)函数一般表达式: (2)使用 (3)举例(c++) 案例1:argc与argv使用 要求 cmakelists.txt配置 代码 效果图 案例2:options的使用 要求 cmakelists.txt配置 代码 效果图 1.2 初始化函数(python) (…

如何绘制网络安全运营的“谷歌地图”?

正如Google Maps(谷歌地图)彻底改变了驾车出行时的导航模式一样,通过流程映射绘制一张指导网络安全运营的“电子地图”,可以彻底改变组织理解和管理网络安全运营工作的方式。 现代企业网络安全运营的核心并不是部署防火墙和杀毒软…

如何系统学习机器学习?

我不是计算机专业,第一次接触机器学习还是在研一的时候,当时是看到机器学习可以做号码识别,就觉得好厉害,想学这个。 首次了解到Python这门语言,知道了机器学习可以做什么后,就感觉打开了新世界一样。再后来…

数据质量管理-准确性管理

前情提要 根据GB/T 36344-2018《信息技术 数据质量评价指标》的标准文档,当前数据质量评价指标框架中包含6评价指标,在实际的数据治理过程中,存在一个关联性指标。7个指标中存在4个定性指标,3个定量指标; 定性指标&am…

IT入门知识第六部分《后端开发》(6/10)

目录 后端开发:构建强大的服务端逻辑 1.引言 2.后端技术概述 2.1 数据库 2.2 服务器 2.3 API 2.4 安全性 3.服务器和API 3.1 服务器的作用 3.2 API的作用 4.后端框架 4.1 Node.js 4.1.1 特点 4.1.2 用途 4.1.3 代码案例分析 4.2 Django 4.2.1 特点 …

《Redis设计与实现》阅读总结-1

第 2 章 简单动态字符串(SDS) 1. Redis使用自己构建一种名为简单动态字符串(simple dynamic string ,SDS)的抽象类型,作为Redis的默认字符串。 2. SDS的结构: free属性:表示这个SDS没有分配任何…

【SQL Server数据库】熟悉DBMS的基本操作及数据库的创建

目录 一、SQL SERVER基本操作 二、用Management Studio创建数据库 1、使用Management Studio创建数据库bookdb,各项参数采用默认设置。 2、使用Management Studio创建数据库EDUC 3. 在EDUC中创建三个表,根据下面要求创建Student,Course&am…

C语言 | Leetcode C语言题解之第190题颠倒二进制位

题目: 题解: const uint32_t M1 0x55555555; // 01010101010101010101010101010101 const uint32_t M2 0x33333333; // 00110011001100110011001100110011 const uint32_t M4 0x0f0f0f0f; // 00001111000011110000111100001111 const uint32_t M8…

django学习入门系列之第三点《小米商城头标总结》

文章目录 总结往期回顾 总结 body标签,默认有一个边框,造成页面四边都有白色的间距,那该如何去除呢? body{margin: 0; }文本居中 文本水平居中,文本会在这个区域中居中text-align作为HTML元素属性其主要是用来文本水平居中的。 &…

一键模板生成视频解决方案,海量模板,满足多样需求

视频已经成为企业营销、宣传、培训的重要手段,高昂的制作成本、复杂的技术门槛以及繁琐的制作流程,往往让许多企业望而却步。美摄科技凭借其深厚的技术积累和创新能力,推出了面向企业的智能一键模板生成视频解决方案,为企业视频制…

电梯开关状态人员进出检测数据集VOC+YOLO格式2220张4类别

数据集格式:Pascal VOC格式YOLO格式(不包含分割路径的txt文件,仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数):2220 标注数量(xml文件个数):2220 标注数量(txt文件个数):2220 标注…