vtk实现三点确定一个平面

逃离我推掉我的手 2022-06-09 10:06 343阅读 0赞

如何在vtk中根据三点提取一个切面,一直知道根据三点就能表示一个面,但是怎么在vtk中实现,对于我这种菜鸟真是要想好久。首先说说现在的思路,知道vtkImagepalne中可以根据一个点和一个面法向量获得一个面。现在我有三个点,需要获得一个面法向量,那么需要通过叉乘得到,再然后根据一个点和得到的面法向量显示一个切面。

之前看过vtkresliceImage得到的切面方法,感觉对变换的理解很差,尤其对Matrix(矩阵基本变换)的理解又不那么到位:
double center[3]; center[0] = origin[0] + spacing[0] * 0.5 * (extent[0] + extent[1]); center[1] = origin[1] + spacing[1] * 0.5 * (extent[2] + extent[3]); center[2] = origin[2] + spacing[2] * 0.5 * (extent[4] + extent[5]); static double axialElements[16] = { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 }; vtkSmartPointer<vtkMatrix4x4> resliceAxes = vtkSmartPointer<vtkMatrix4x4>::New(); resliceAxes->DeepCopy(axialElements); resliceAxes->SetElement(0, 3, center[0]); resliceAxes->SetElement(1, 3, center[1]); resliceAxes->SetElement(2, 3, center[2]);
根据代码的理解,vtkMatrix4x4应该包含一个面和一个点,但是这个面是由static double axialElements[16] = { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 };
决定的,根据定义,这个矩阵左上方3x3的矩阵是X、Y、Z方向的三个矢量,第四列三个做透视变换用的,根据水灵书中提的,这里好像是切面的坐标系原点(我没有看过透视变换的相关信息,不太了解)。第四行左三个别控制其在x轴y轴z轴上的平移单位.,第四个表示缩放比例。

再理解一下叉乘,叉乘(cross product)或者外积,它的计算结果是一个向量而非标量。叉积所在的向量与参与运算的两个向量都正交,也即正交于原来的两个向两边所决定的平面,也即两向量所决定的平面的法向量可通过计算叉积的方式得以确定。当参与运算的两向量是平行的两个向量时,得到的叉积为0,也即可通过计算叉积的方式判断两向量是否平行。
代数定义
二维时
x×y=x1y2−x2y1
三维时
这里写图片描述

这里写图片描述
根据如图的计算方法可得:

这里写图片描述
几何定义

x×y=∥x∥∥y∥sinθn⃗
n⃗ 表示叉积方向上的单位向量。

中学知识告诉我们三角形的面积计算公式为:

S=∥x∥∥y∥sinθ2=∥z∥h2

其中θ表示的是x,y之间的夹角,由以上两个公式我们可得到三角形的高或者点到其所对的边的距离,也即点到直线的距离,的计算公式:
h=∥x×y∥/∥z∥

  1. double operator*(const Vec& x, const Vec& y)
  2. {
  3. assert(x.size() == y.size()); // #include <cassert>
  4. double sum = 0.;
  5. for (size_t i = 0; i < x.size(); ++i)
  6. sum += x[i]*y[i];
  7. return sum;
  8. }
  9. // 三维的情况
  10. Vec operator^(const Vec& x, const Vec& y)
  11. {
  12. assert(x.size() == y.size() && x.size() == 3);
  13. return Vec{x[1]*y[2]-x[2]*y[1],
  14. x[2]*y[0]-x[0]*y[2],
  15. x[0]*y[1]-x[1]*y[0]};
  16. // uniform initialization, C++11新特性
  17. }
  18. // 二维就姑且返回其模长吧
  19. double twoDCrossProd(const Vec& x, const Vec& y)
  20. {
  21. return x[0]*y[1]-x[1]*y[0];
  22. }

现在贴一段代码[C++实现叉乘],并感谢作者提供。(http://blog.sina.com.cn/s/blog_4e24d9c50100ttvz.html)

  1. #include <iostream>
  2. #define M 3
  3. #define N 4
  4. #define P 3
  5. using namespace std;
  6. void getmt(int* m,int r,int c) //获取矩阵
  7. {
  8. for(int i=0;i<r;++i)
  9. {
  10. for(int j=0;j<c;++j) cin>>*(m+i*c+j);
  11. }
  12. }
  13. void showmt(const int* m,int r,int c) //显示矩阵
  14. {
  15. for(int i=0;i<r;++i)
  16. {
  17. for(int j=0;j<c;++j) cout<<*(m+i*c+j)<<"\t";
  18. cout<<endl;
  19. }
  20. }
  21. void mmt(const int* m1,const int* m2,int* m3,int m,int n,int p)
  22. {
  23. for(int i=0;i<m;++i) //叉乘运算
  24. {
  25. for(int j=0;j<p;++j)
  26. {
  27. for(int k=0;k<n;++k)
  28. {
  29. (*(m3+i*p+j))+=(*(m1+i*n+k))*(*(m2+k*p+j));
  30. }
  31. }
  32. }
  33. }
  34. int main(int argc, char *argv[])
  35. {
  36. int m1[M][N];
  37. int m2[N][P];
  38. int m3[M][P];
  39. memset(m3, 0, sizeof(m3)); //注意不能用int m3[M][P]={0};来初始化为0,这样可能并没有将m3中的元素赋0
  40. cout<<"为矩阵1输入"<<M<<"*"<<N<<"个数:"<<endl;
  41. getmt(&m1[0][0],M,N); //获取矩阵m1
  42. cout<<"为矩阵2输入"<<N<<"*"<<P<<"个数:"<<endl;
  43. getmt(&m2[0][0],N,P); //获取矩阵m2
  44. mmt(&m1[0][0],&m2[0][0],&m3[0][0],M,N,P); //叉乘运算
  45. cout<<"矩阵1:"<<endl;
  46. showmt(&m1[0][0],M,N);
  47. cout<<"矩阵2:"<<endl;
  48. showmt(&m2[0][0],N,P);
  49. cout<<"结果:"<<endl;
  50. showmt(&m3[0][0],M,P);
  51. system("PAUSE");
  52. return EXIT_SUCCESS;
  53. }

搜了一下在图形学中表示向量的方法,看来这里面学问挺多的,贴两个实用的帖子,感谢作者提供宝贵的知识图形学中向量操作类、图像学中向量说明。

vtkImagePlaneWidget中不能直接设置SetNormal和SetCenter,只能设置初始点位置,那么这样就需要写一个类来继承vtkImagePlaneWidget,并且添加这两个功能。最后,继承了vtkPlaneSource中SetNormal和SetCenter这两个功能,可以提取经过三个点的切面:

  1. ImagePlaneWidget *mplanewidget = ImagePlaneWidget::New();
  2. mplanewidget->SetInteractor(iren);
  3. mplanewidget->SetPicker(picker); //定义 内部选择器
  4. mplanewidget->SetTexturePlaneProperty(ipwProp);//给切片设定纹理属性
  5. mplanewidget->TextureInterpolateOff();
  6. mplanewidget->GetPlaneProperty()->SetColor(1, 0, 0); //设置平面属性
  7. mplanewidget->SetResliceInterpolateToLinear();//差值方法
  8. mplanewidget->SetInputConnection(reader->GetOutputPort());//
  9. //mplanewidget->RestrictPlaneToVolumeOn(); //确保平面在容器范围之内
  10. mplanewidget->SetNormal(mnormalize); //设定切面法向方向
  11. mplanewidget->SetOrigin(moriginpoint); //设定切面的初始点位置
  12. mplanewidget->SetCenter(moriginpoint); //设定切面所在位置中心
  13. mplanewidget->On();
  14. mplanewidget->InteractionOn();
  15. //mplanewidget->PlaceWidget(polyData->GetBounds());//获得polydata中的边界,最大最小值

发表评论

表情:
评论列表 (有 0 条评论,343人围观)

还没有评论,来说两句吧...

相关阅读

    相关 平面最近

    一,平面最近点对 问题:在给n个平面上的点,让你找到最近的一对点。 暴力n\n做法肯定超时。 我们考虑分治。 1-n这个区间,我们可以先找到A=(1-mid)和B=(m

    相关 平面分离架构

    引子 开始正文之前先来看两个前沿技术的架构。 1、SDN 软件定义网络 软件定义网络(Software Defined Network,SDN)是由美国斯坦福大学c

    相关 平面排序(一)

    题目:平面上有n个点,坐标均为整数。请按与坐标原点(0,0)距离的远近将所有点排序输出。可以自己写排序函数,也可以用qsort库函数排序。 输入:输入有两行,第一行是整数n(