有时候,三维空间的点需要投影到某一特定的平面。比如说,一个点集,连接成一个平面,如果不进行投影,直接连接,可能会出现怪异的现象。
为了简单,示例只用到了一个点的投影。多个点的投影,延伸一下就可以了。
需求:将p点投影到x0y平面。
怎样做
方法一
需求是投影到x0y平面,不难理解,这个平面z=0.
double p[] = {11.0, 8.3, 5.7};
p[2] = 0;
方法一属于偷懒的做法,有很大的局限性,如果想投影到空间中的任意平面,可以用下面的方法二,更通用的办法。
方法二
该方法是借助vtkPlane来进行投影,一个原点和一根法向量可以确定一个平面。有了平面以后,再使用ProjectPoint方法得到投影点。
vtkSmartPointer<vtkPlane> plane =
vtkSmartPointer<vtkPlane>::New();
double origin[] = { 0, 0, 0 };
double normal[] = { 0, 0, 1 };
plane->SetOrigin(origin);
plane->SetNormal(normal);
double p[] = {11.0, 8.3, 5.7};
double projected[3];
plane->ProjectPoint(p, origin, normal, projected);
效果:
示例代码
#include <vtkSmartPointer.h>
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkRenderWindow.h>
#include <vtkRenderer.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkProperty.h>
#include <vtkPlane.h>
#include <vtkSphereSource.h>
#include <vtkPoints.h>
#include <vtkPolyData.h>
#include <vtkGlyph3DMapper.h>
#include <vtkAxesActor.h>
#include <vtkTextActor.h>
#include <vtkTextProperty.h>
int main(int, char *[])
{
vtkSmartPointer<vtkPlane> plane =
vtkSmartPointer<vtkPlane>::New();
double origin[] = { 0, 0, 0 };
double normal[] = { 0, 0, 1 };
plane->SetOrigin(origin);
plane->SetNormal(normal);
double p[] = {11.0, 8.3, 5.7};
double projected[3];
plane->ProjectPoint(p, origin, normal, projected);
char outputMsg[256] = {0};
//sprintf_s(outputMsg, sizeof(outputMsg), "p(%f, %f, %f)", p[0], p[1], p[2]);
sprintf_s(outputMsg, sizeof(outputMsg), "p(%f, %f, %f)\nprojected(%f, %f, %f)", p[0], p[1], p[2],
projected[0], projected[1], projected[2]);
vtkSmartPointer<vtkTextActor> textActor =
vtkSmartPointer<vtkTextActor>::New();
textActor->SetPosition2(100, 40);
textActor->GetTextProperty()->SetFontSize(24);
textActor->GetTextProperty()->SetColor(0, 1, 0);
textActor->SetInput(outputMsg);
vtkSmartPointer<vtkSphereSource> pointsSphere =
vtkSmartPointer<vtkSphereSource>::New();
pointsSphere->SetPhiResolution(21);
pointsSphere->SetThetaResolution(21);
pointsSphere->SetRadius(.5);
vtkSmartPointer<vtkPoints> points =
vtkSmartPointer<vtkPoints>::New();
points->InsertNextPoint(p);
points->InsertNextPoint(projected);
vtkSmartPointer<vtkPolyData> pointsData =
vtkSmartPointer<vtkPolyData>::New();
pointsData->SetPoints(points);
vtkSmartPointer<vtkGlyph3DMapper> pointsMapper =
vtkSmartPointer<vtkGlyph3DMapper>::New();
pointsMapper->SetInputData(pointsData);
pointsMapper->SetSourceConnection(pointsSphere->GetOutputPort());
vtkSmartPointer<vtkActor> pointsActor =
vtkSmartPointer<vtkActor>::New();
pointsActor->SetMapper(pointsMapper);
pointsActor->GetProperty()->SetColor(1, 0, 0);
#define LINE_LEN 10.
vtkSmartPointer<vtkAxesActor> axesActor =
vtkSmartPointer<vtkAxesActor>::New();
axesActor->SetPosition(0, 0, 0);
axesActor->SetTotalLength(LINE_LEN, LINE_LEN, LINE_LEN);
axesActor->SetShaftType(0);
axesActor->SetAxisLabels(0);
axesActor->SetCylinderRadius(0.02);
vtkSmartPointer<vtkRenderer> renderer =
vtkSmartPointer<vtkRenderer>::New();
vtkSmartPointer<vtkRenderWindow> renderWindow =
vtkSmartPointer<vtkRenderWindow>::New();
renderWindow->SetSize(600, 600);
renderWindow->AddRenderer(renderer);
vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor =
vtkSmartPointer<vtkRenderWindowInteractor>::New();
renderWindowInteractor->SetRenderWindow(renderWindow);
renderer->AddActor2D(textActor);
renderer->AddActor(pointsActor);
renderer->AddActor(axesActor);
renderWindow->Render();
renderWindowInteractor->Start();
return EXIT_SUCCESS;
}
向量投影
向量投影和点投影类似,不同的是用ProjectVector方法。
vtkSmartPointer<vtkPlane> plane =
vtkSmartPointer<vtkPlane>::New();
double origin[] = { 0, 0, 0 };
double normal[] = { 0, 0, 1 };
plane->SetOrigin(origin);
plane->SetNormal(normal);
double vector[] = { 3.4, 8.3, 5.7 };
plane->ProjectVector(vector, vector);
Reference
ProjectPointPlane
vtk学习笔记 — 投影点集合到指定的平面
vtkPlane Class Reference