VTK编程指南<五>:VTK中的坐标系统、空间变换及VTK矩阵详解

news2024/12/23 17:31:20

1、坐标系统

  计算机图形学里常用的坐标系统主要有 4 种,分别是 Model 坐标系统、World 坐标系统、View坐标系统和 Display坐标系统(这些名词在不同的书里的中文表述均有所差别,所以直接使用英文名词表示),此外还有两种表示坐标点的方式:以屏幕像素值为单位和归一化坐标值(各坐标轴取值范围为[-1,1])。它们之间的关系如图 所示。

  Model 坐标系统是定义模型时所采用的坐标系统,通常是局部的笛卡儿坐标系。

  World坐标系统是放置Actor 的三维空间坐标系,Actor(vtkActor 类)其中的一个功能就是负责将模型从 Model 坐标系统变换到 World 坐标系统。每一个模型可以定义自己的 Model坐标系统,但World 坐标系只有一个,每一个Actor 必须通过放缩、旋转、平移等操作将 Model坐标系统转换到World 坐标系。World 坐标系同时也是灯光和相机所在的坐标系统。
在这里插入图片描述
  View 坐标系统表示的是相机所看见的坐标系统。X、Y、Z 轴取值为[-1,1],X、Y 值表示像平面上的位置,Z 值表示到相机的距离。相机负责将 World 坐标系变换到 View 坐标系。

  Display 坐标系统与 View 坐标系统类似,但是各坐标轴的取值不是[-1,1],而是使用屏幕像素值。屏幕上显示的不同窗口的大小会影响 View 坐标系的坐标值[-1,1]到 Display 坐标系的映射。可以把不同的渲染场景放在同一个窗口进行显示,例如,在一个窗口里,分为左右两个渲染场景,这左右的渲染场景(vtkRenderer)就是不同的视口(Viewport)。

  示例 Viewport实现将一个窗口分为 4个视口,用vtkRenderer::SetViewport()来设置视口的范围(取值为[0,1]):

renderer1->SetViewport(0.0,0.0,0.5,0.5);
renderer2->SetViewport(0.5,0.0,1.0,0.5);
renderer3->SetViewport(0.0,0.5,0.5,1.0);
renderer4->SetViewport(0.5,0.5,1.0,1.0);

  在VTK里,Model坐标系统用得比较少,其他三种坐标系统经常使用。它们之间的变换则是由类 vtkCoordinate 进行管理的。根据坐标值的单位、取值范围等不同,可以将坐标系统细分为如下几类。

  • DISPLAY——X、Y轴的坐标取值为渲染窗口的像素值。坐标原点位于渲染窗口的左下角,这个对于VTK里的所有二维坐标系统都是一样的,且VTK里的坐标系统都是采用右手坐标系。
  • NORMALIZED DISPLAY——X、Y 轴坐标取值范围为[0,1],跟 DISPLAY一样,也是定义在渲染窗口里的。
  • VIEWPORT——X、Y的坐标值定义在视口或者渲染器(Renderer)里。
  • NORMALIZED VIEWPORT——X、Y 坐标值定义在视口或渲染器里,取值范围为[0,1]。
  • VIEW ——X、Y、Z 坐标值定义在相机所在的坐标系统里,取值范围为[-1,1],Z值表示深度信息。
  • WORLD——X、Y、Z坐标值定义在世界坐标系统。
  • USERDEFINED——用户自定义坐标系统。

  vtkCoordinate 可以用来表示坐标系统,其内部提供了函数接口来定义坐标系统:

SetCoordinateSystemToDisplay )
SetCoordinateSystemToNormalizedDisplay ()
SetCoordinateSystemToViewport ()
SetCoordinateSystemToNormalizedViewport )
SetCoordinateSystemToView O
SetCoordinateSystemToWorld ()

  另外,该类还实现这些坐标系统之间的转换,例如下述代码实现了归一化窗口坐标与窗口坐标之间的转换:

vtkSmartPointer<vtkCoordinate>coordinate =
vtkSmartPointer<vtkCoordinate>::New);
coordinate->SetCoordinateSystemToNormalizedDisplay();
coordinate->SetValue(.5,.5,0);

int*val;
val =coordinate_>GetComputedDisplay Value(renderer);

  这里先调用了SetCoordinateSystemToNormalizedDisplay()设置坐标系统为归一化窗口坐标,并设置坐标值为(0.5,0.5,0),即屏幕的中心;然后通过函数 GetComputedDisplayValue()实现窗口坐标的转换。该类中坐标系统转换函数如下:

GetComputedWorldValue)
GetComputedViewportValue()
GetComputedDisplayValue)
GetComputedLocalDisplayValue()
GetComputedDoubleViewportValue()
GetComputedDoubleDisplayValue)
GetComputedUserDefinedValue()

2、空间变换

  在三维空间里定义的三维模型,最后显示时都是投影到二维平面,比如在屏幕上显示。三维到二维的投影包括透视投影(Perspective Projection)和正交投影(Orthogonal Projection)。正交投影也叫平行投影。
在这里插入图片描述
在这里插入图片描述
  VTK 里与空间变换相关的类有 vtkTransform2D,vtkTransform,vtkPerspectiveTransform,vtkGeneralTransform,vtkTransformFilter,vtkMatrix4 X 4 等。例如下面代码实现了vtkActor对象的空间变换:

vtkSmartPointer<vtkTransform>transform =
vtkSmartPointer<vtkTransform>::New);
transform->PostMultiply0;
transform->RotateZ(40);
transform->Translate(10,0,0);
cylinderActor->SetUserTransform(transform);

  先定义了vtkTransform 对象,并设置使用右乘计算变换矩阵。RotateZ()设置绕 Z 轴旋转40°,并使用Translate()设置平移大小为(10,0,0),最后通过 vtkActor::SetUserTransform()方法设置用户定义的变换矩阵,实现模型的空间变换。

3、矩阵

3.1、齐次坐标

  常见的点一般是Pt(X,Y,Z),相当于一个1×3矩阵,而矩阵相乘的话一般是第一个矩阵的列数要等于第二个矩阵的行数。此处需要引入齐次坐标的概念:从广义上讲,齐次坐标就是用n+1维向量表示n 维向量,即将n维空间的点用 n+1维坐标表示。例如,一般笛卡尔坐标系中的二维点向量[x y]可用齐次坐标表示为[Hx Hx H],其中最后一维坐标是一个标量,称为比例因子。利用齐次坐标可以将平移、旋转、比例、投影等几何变换统一到矩阵的乘法上来,为图形变换提供方便。

  该矩阵在右手坐标系中定义,其中左上角部分产生比例、对称、错切和旋转变换,右上角部分产生平移变换;左下角部分产生透视变换;右下角部分产生全比例变换。
在这里插入图片描述

3.2、矩阵旋转

在这里插入图片描述
有兴趣可以将上述三个旋转矩阵按照不同的顺序进行相乘,得到的结果也是不一样的,例如:
1)先旋转x轴再旋转y轴再旋转z轴;
2)先旋转y轴再旋转x轴再旋转z轴;
3)先旋转z轴再旋转y轴再旋转x轴;

3.3、vtkMatrix4x4类

3.3.1 vtkMatrix4x4初始化
matrix1:
-0.013 -0.986 0.165 -133
-0.017 0.166 0.986 -35
-1 0.01 -0.02 40
0 0 0 1
	vtkMatrix4x4* matrix1 = vtkMatrix4x4::New();
	matrix1->Identity();
	matrix1->SetElement(0, 0, -0.013);
	matrix1->SetElement(0, 1, -0.986);
	matrix1->SetElement(0, 2, 0.165);
	matrix1->SetElement(0, 3, -133);

	matrix1->SetElement(1, 0, -0.017);
	matrix1->SetElement(1, 1, 0.166);
	matrix1->SetElement(1, 2, 0.986);
	matrix1->SetElement(1, 3, -35);

	matrix1->SetElement(2, 0, -1.0);
	matrix1->SetElement(2, 1, 0.01);
	matrix1->SetElement(2, 2, -0.02);
	matrix1->SetElement(2, 3, 40);
3.3.2 vtkMatrix4x4相乘

  下面两个矩阵的结果是不一样的,也就是常说的矩阵乘法左乘和右乘不一样。

	vtkMatrix4x4::Multiply4x4(matrix1, matrix2, matrix3);
	vtkMatrix4x4::Multiply4x4(matrix2, matrix1, matrix4);

  下面是完整的结果和代码:

在这里插入图片描述

#include <iostream>
#include <vtkMatrix4x4.h>

int main()
{
    vtkMatrix4x4* matrix1 = vtkMatrix4x4::New();
	matrix1->Identity();
	matrix1->SetElement(0, 0, -0.013);
	matrix1->SetElement(0, 1, -0.986);
	matrix1->SetElement(0, 2, 0.165);
	matrix1->SetElement(0, 3, -133);

	matrix1->SetElement(1, 0, -0.017);
	matrix1->SetElement(1, 1, 0.166);
	matrix1->SetElement(1, 2, 0.986);
	matrix1->SetElement(1, 3, -35);

	matrix1->SetElement(2, 0, -1.0);
	matrix1->SetElement(2, 1, 0.01);
	matrix1->SetElement(2, 2, -0.02);
	matrix1->SetElement(2, 3, 40);

	vtkMatrix4x4* matrix2 = vtkMatrix4x4::New();
	matrix2->Identity();
	matrix2->SetElement(0, 3, -140);
	matrix2->SetElement(1, 3, -140);
	matrix2->SetElement(2, 3, -143);

	vtkMatrix4x4* matrix3 = vtkMatrix4x4::New();
	matrix3->Identity();
	vtkMatrix4x4* matrix4 = vtkMatrix4x4::New();
	matrix4->Identity();

	vtkMatrix4x4::Multiply4x4(matrix1, matrix2, matrix3);
	vtkMatrix4x4::Multiply4x4(matrix2, matrix1, matrix4);
	// 打印结果矩阵以验证

	std::cout << "matrix1: " << std::endl;
	for (int i = 0; i < 4; ++i)
	{
		for (int j = 0; j < 4; ++j)
		{
			std::cout << matrix1->GetElement(i, j) << " ";
		}
		std::cout << std::endl;
	}

	std::cout << "matrix2: " << std::endl;
	for (int i = 0; i < 4; ++i)
	{
		for (int j = 0; j < 4; ++j)
		{
			std::cout << matrix2->GetElement(i, j) << " ";
		}
		std::cout << std::endl;
	}

	std::cout << std::endl;

	std::cout << "matrix1 * matrix2: " << std::endl;
	for (int i = 0; i < 4; ++i) 
	{
		for (int j = 0; j < 4; ++j) 
		{
			std::cout << matrix3->GetElement(i, j) << " ";
		}
		std::cout << std::endl;
	}

	std::cout << std::endl;

	std::cout << "matrix2 * matrix1: " << std::endl;
	for (int i = 0; i < 4; ++i)
	{
		for (int j = 0; j < 4; ++j)
		{
			std::cout << matrix4->GetElement(i, j) << " ";
		}
		std::cout << std::endl;
	}

	// 释放内存
	matrix1->Delete();
	matrix2->Delete();
	matrix3->Delete();
	matrix4->Delete();

	return 1;
}

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

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

相关文章

MaxEnt模型在物种分布模拟中如何应用?R语言+MaxEnt模型融合物种分布模拟、参数优化方法、结果分析制图与论文写作

目录 第一章 以问题导入的方式&#xff0c;深入掌握原理基础 第二章 常用数据检索与R语言自动化下载及可视化方法 第三章 R语言数据清洗与特征变量筛选 第四章 基于ArcGIS、R数据处理与进阶 第五章 基于Maxent的物种分布建模与预测 第六章 基于R语言的模型参数优化 第七…

【JavaEE 进阶(一)】SpringBoot(上)

博主主页: 33的博客 文章专栏分类:JavaEE ??我的代码仓库: 33的代码仓库?? ???关注我带你了解更多进阶知识 目录 1.前言2.Spring3.第一个SpringBoot程序4.Spring MVC 4.1建立连接 4.1.1RequestMapping使用 4.2请求 4.2.1传递单个参数4.2.2传递多个参数4.2.3传递一个对象…

银行项目网上支付接口调用测试实例

&#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 公司最近有一个网站商城项目要开始开发了&#xff0c;这几天老板和几个同事一起开着需求会议&#xff0c;讨论了接下来的业务规划和需求策略&#xff0c;等技术需求…

手机LCD分区刷新技术介绍

分区刷新也称为分区变频&#xff0c;LCD分区刷新功能的目的是将屏幕分为上下半区&#xff0c;分区显示不同帧率&#xff0c;上方区块High Frame Rate&#xff0c;下方区块Low Frame Rate。使用者可以动态自定义上方高刷显示区的结尾位置。 当前的智能手机屏幕上&#xff0c;显示…

TesseractOCR-GUI:基于WPF/C#构建TesseractOCR简单易用的用户界面

前言 前篇文章使用Tesseract进行图片文字识别介绍了如何安装TesseractOCR与TesseractOCR的命令行使用。但在日常使用过程中&#xff0c;命令行使用还是不太方便的&#xff0c;因此今天介绍一下如何使用WPF/C#构建TesseractOCR简单易用的用户界面。 普通用户使用 参照上一篇教…

flask创建templates目录存放html文件

首先&#xff0c;创建flask项目&#xff0c;在pycharm中File --> New Project&#xff0c;选择Flask项目。 然后&#xff0c;在某一目录下&#xff0c;新建名为templates的文件夹&#xff0c;这时会是一个普通的文件夹。 然后右击templates文件夹&#xff0c;选择Unmark as …

python编程Day12-属性和方法的分类

私有和公有 在python中 定义类的时候&#xff0c;可以给 属性和方法设置 访问权限&#xff0c;即规定在什么地方可以使用。 权限一般分为两种&#xff1a;公有权限、私有权限 公有权限 定义&#xff1a;直接定义的属性和方法就是公有的特点&#xff1a; 可以在任何地方访问和使…

Moving Tables

任务内容 Description The famous ACM (Advanced Computer Maker) Company has rented a floor of a building whose shape is in the following figure. The floor has 200 rooms each on the north side and south side along the corridor. Recently the Company made a pla…

小程序 - 美食列表

小程序交互练习 - 美食列表小程序开发笔记 目录 美食列表 功能描述 准备工作 创建项目 配置页面 配置导航栏 启动本地服务器 页面初始数据 设置获取美食数据 设置onload函数 设置项目配置 页面渲染 页面样式 处理电话格式 创建处理电话格式脚本 页面引入脚本 …

Facebook广告文案流量秘诀

Facebook 广告文案是制作有效 Facebook 广告的关键方面。它侧重于伴随广告视觉元素的文本内容。今天我们的博客将深入探讨成功的 Facebook 广告文案的秘密&#xff01; 一、广告文案怎么写&#xff1f; 正文&#xff1a;这是帖子的正文&#xff0c;出现在您姓名的正下方。它可…

TEXT2SQL工具vanna本地化安装和应用

TEXT2SQL工具vanna本地化安装和应用 Vanna和Text2SQL环境安装和数据准备 conda虚拟环境安装数据准备ollama环境准备 ollama安装和运行ollama下载模型测试下API方式正常使用 chromaDB的默认的embedding模型准备 vanna脚本跑起来 Vanna和Text2SQL TEXT2SQL即文本转SQL&#xf…

标书里的“废标雷区”:你踩过几个?

在投标领域&#xff0c;标书的质量不仅决定了中标的可能性&#xff0c;更是体现企业专业度的关键。但即便是经验丰富的投标人&#xff0c;也难免会在标书编制过程中踩中“废标雷区”。这些雷区可能隐藏在技术方案的细节中&#xff0c;也可能是投标文件格式的规范问题。以下&…

操作系统——I/O系统

笔记内容及图片整理自XJTUSE “操作系统” 课程ppt&#xff0c;仅供学习交流使用&#xff0c;谢谢。 概述 计算机的两个主要工作是I/O和处理。I/O系统的目标是提高设备利用率&#xff0c;尽量提高CPU与I/O设备间的并行工作程度&#xff0c;I/O主要技术包括中断技术、DMA技术、…

【 工具变量】IPCC碳排放因子数据测算表

一、数据简介&#xff1a; 排放因子法是IPCC提出的一种碳排放估算方法&#xff0c;也是目前适用范围最广、应用最为普遍的方法。将各类能源消耗的实物统计量转变为标准统计量&#xff0c;再乘以各自的碳排放因子&#xff0c;加总之后就可以得到碳排放总量。如果按照ISO14064标…

无插件直播流媒体音视频播放器EasyPlayer.js播放器的g711系列的音频,听起来为什么都是杂音

在数字化时代&#xff0c;流媒体播放器已成为信息传播和娱乐消遣的重要工具。随着技术的进步&#xff0c;流媒体播放器的核心技术和发展趋势不断演变&#xff0c;以满足用户对于无缝播放、低延迟和高画质的需求。 EasyPlayer播放器属于一款高效、精炼、稳定且免费的流媒体播放…

63 基于单片机的四个速度比较

所有仿真详情导航&#xff1a; PROTEUS专栏说明-CSDN博客 目录 一、主要功能 二、硬件资源 三、主程序编程 四、资源下载 一、主要功能 基于51单片机&#xff0c;采用四个滑动变阻器连接数模转换器模拟四个速度值&#xff0c;通过LCD1602显示&#xff0c;然后检测出最高的…

4.模块化技术之子程序

总学习目录请点击下面连接 SAP ABAP开发从0到入职&#xff0c;冷冬备战-CSDN博客 目录 ​编辑 1.模块化基础和概述 使用模块化有什么好处 两大类模块化技术 程序局部的模块化 SAP系统内全局模块化 封装有什么好处&#xff1f; 2.子程序模块化 三种传递类型 子程序结构…

利用Python实现子域名简单收集

免责申明 本文仅是用于学习研究子域名信息收集&#xff0c;请勿用在非法途径上&#xff0c;若将其用于非法目的&#xff0c;所造成的一切后果由您自行承担&#xff0c;产生的一切风险和后果与笔者无关&#xff1b;本文开始前请认真详细学习《‌中华人民共和国网络安全法》【学法…

k8s,进一步理解Pod

比如&#xff0c;凡是调度、网络、存储&#xff0c;以及安全相关的属性&#xff0c;基本上是Pod 级别的。 这些属性的共同特征是&#xff0c;它们描述的是“机器”这个整体&#xff0c;而不是里面运行的“程序”。比如&#xff0c;配置这个“机器”的网卡&#xff08;即&#…

Unity 使用LineRenderer制作模拟2d绳子

效果展示&#xff1a; 实现如下&#xff1a; 首先&#xff0c;直接上代码&#xff1a; using System.Collections; using System.Collections.Generic; using UnityEngine;public class LineFourRender : MonoBehaviour {public Transform StartNode;public Transform MidNod…