vtkImplicitSelectionLoop
vtkImplicitSelectionLoop是vtkImplicitFunction类的子类,为一个不规则的圆柱形对象计算隐式函数值和函数梯度,该对象的横截面由形成循环的一组点定义。回路不必是凸多边形,也不必所有点在同一平面上。但是,当投影到由Loop周围的累积叉积(即loop的轴)定义的平面上时,环必须是非自交的(或可以指定要使用的法线。)
vtkClipPolyData的SetClipFunction使用vtkImplicitFunction的子类,其中vtkCylinder类输入到vtkClipPolyData后,会产生贯穿vtkClipPolyData的输入源数据,vtkImplicitSelectionLoop相对是在vtkCylinder类,不过它的横截面是不规则的多边形,由多个连续环绕的点组成,当前点与上一个点之间的连线互不交叉,保证能够定义一个闭合的多边形;一般情况下,外部设定的点集是在同一平面上的点, vtkImplicitSelectionLoop可以自动计算出这些点所在平面的法向量,这个法向量就是柱体的纵深向量,决定被裁剪数据那些数据被裁剪;循环的每个点首先投影到由循环法线定义的平面上,这就形成了一个多边形。然后,为了计算隐式函数值,使用inside/outside来判断确定x是否在多边形内,并计算到循环闭合多边形边界的距离(负值在循环内)。
接口
输入点集
通过调用方法SetLoop和GetLoop来设置和获取vtkPoints集合;
要求点的顺序可以形成闭合多边形,且不能自我交叉;
vtkPoints* Loop;
virtual void SetLoop(vtkPoints*);
vtkGetObjectMacro(Loop, vtkPoints);
法线向量
输入的Loop点集,构成的同一个投影平面,平面的起点和法向量由Origin和Normal成员变量记录;
double Normal[3];
vtkSetVector3Macro(Normal, double);
vtkGetVectorMacro(Normal, double, 3);
double Origin[3];
double Bounds[6]; // bounds of the projected polyon
使用AutomaticNormalGeneration控制打开/关闭自动计算法线向量;
默认情况下,法线是根据边的累积叉积计算的;也可以指定要使用的法线。
vtkTypeBool AutomaticNormalGeneration;
vtkSetMacro(AutomaticNormalGeneration, vtkTypeBool);
vtkGetMacro(AutomaticNormalGeneration, vtkTypeBool);
vtkBooleanMacro(AutomaticNormalGeneration, vtkTypeBool);
计算点与边界的距离
EvaluateFunction返回有符号数值,根据符号可以判断,点在投影平面上是否处于闭合曲线内;决定是否进行裁剪,目前用处不大;
using vtkImplicitFunction::EvaluateFunction;
double EvaluateFunction(double x[3]) override;
void EvaluateGradient(double x[3], double n[3]) override;
示例
在网格表面绘制一个循环,并使用该循环从循环中剪裁或提取单元。
#include "vtk_include.h"
#include <vtkClipPolyData.h>
#include <vtkImplicitSelectionLoop.h>
#include <vtkLODActor.h>
#include <vtkNamedColors.h>
#include <vtkNew.h>
#include <vtkPolyDataMapper.h>
#include <vtkProperty.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkRenderer.h>
#include <vtkSphereSource.h>
class Test_ImplicitSelectionLoop {
public:
static void Test() {
vtkNew<vtkNamedColors> colors;
vtkNew<vtkSphereSource> sphereSource;
sphereSource->SetPhiResolution(100);
sphereSource->SetThetaResolution(100);
sphereSource->Update();
vtkNew<vtkPoints> selectionPoints;
selectionPoints->InsertPoint(0, -0.16553, 0.135971, 0.451972);
selectionPoints->InsertPoint(1, -0.0880123, -0.134952, 0.4747);
selectionPoints->InsertPoint(2, 0.00292618, -0.134604, 0.482459);
selectionPoints->InsertPoint(3, 0.0641941, 0.067112, 0.490947);
selectionPoints->InsertPoint(4, 0.15577, 0.0734765, 0.469245);
selectionPoints->InsertPoint(5, 0.166667, -0.129217, 0.454622);
selectionPoints->InsertPoint(6, 0.241259, -0.123363, 0.420581);
selectionPoints->InsertPoint(7, 0.240334, 0.0727106, 0.432555);
selectionPoints->InsertPoint(8, 0.308529, 0.0844311, 0.384357);
selectionPoints->InsertPoint(9, 0.32672, -0.121674, 0.359187);
selectionPoints->InsertPoint(10, 0.380721, -0.117342, 0.302527);
selectionPoints->InsertPoint(11, 0.387804, 0.0455074, 0.312375);
selectionPoints->InsertPoint(12, 0.43943, -0.111673, 0.211707);
selectionPoints->InsertPoint(13, 0.470984, -0.0801913, 0.147919);
selectionPoints->InsertPoint(14, 0.436777, 0.0688872, 0.233021);
selectionPoints->InsertPoint(15, 0.44874, 0.188852, 0.109882);
selectionPoints->InsertPoint(16, 0.391352, 0.254285, 0.176943);
selectionPoints->InsertPoint(17, 0.373274, 0.154162, 0.294296);
selectionPoints->InsertPoint(18, 0.274659, 0.311654, 0.276609);
selectionPoints->InsertPoint(19, 0.206068, 0.31396, 0.329702);
selectionPoints->InsertPoint(20, 0.263789, 0.174982, 0.387308);
selectionPoints->InsertPoint(21, 0.213034, 0.175485, 0.417142);
selectionPoints->InsertPoint(22, 0.169113, 0.261974, 0.390286);
selectionPoints->InsertPoint(23, 0.102552, 0.25997, 0.414814);
selectionPoints->InsertPoint(24, 0.131512, 0.161254, 0.454705);
selectionPoints->InsertPoint(25, 0.000192443, 0.156264, 0.475307);
selectionPoints->InsertPoint(26, -0.0392091, 0.000251724, 0.499943);
selectionPoints->InsertPoint(27, -0.096161, 0.159646, 0.46438);
vtkNew<vtkImplicitSelectionLoop> loop;
loop->SetLoop(selectionPoints);
vtkNew<vtkClipPolyData> clip;
clip->SetInputConnection(sphereSource->GetOutputPort());
clip->SetClipFunction(loop);
clip->SetValue(0.0);
vtkNew<vtkPolyDataMapper> clipMapper;
clipMapper->SetInputConnection(clip->GetOutputPort());
clipMapper->ScalarVisibilityOff();
vtkNew<vtkProperty> backProp;
backProp->SetColor(colors->GetColor3d("Tomato").GetData());
vtkNew<vtkLODActor> clipActor;
clipActor->SetMapper(clipMapper);
clipActor->SetBackfaceProperty(backProp);
clipActor->GetProperty()->SetColor(colors->GetColor3d("Banana").GetData());
vtkNew<vtkRenderer> renderer;
vtkNew<vtkRenderWindow> renderWindow;
renderWindow->AddRenderer(renderer);
vtkNew<vtkRenderWindowInteractor> interactor;
interactor->SetRenderWindow(renderWindow);
// Add the actors to the renderer, set the background and size
renderer->AddActor(clipActor);
renderer->SetBackground(colors->GetColor3d("SlateGray").GetData());
renderWindow->SetSize(500, 500);
renderWindow->SetWindowName("ImplicitSelectionLoop");
renderWindow->Render();
interactor->Start();
}
};
修改selectionPoints内点坐标信息
vtkNew<vtkPoints> selectionPoints;
selectionPoints->InsertPoint(0, 0, 0, 0);
selectionPoints->InsertPoint(1, 0.25, 0, 0);
selectionPoints->InsertPoint(2, 0.25, 0.25, 0);
selectionPoints->InsertPoint(3, 0, 0.25, 0);
selectionPoints->InsertPoint(4, 0.125, 0.125, 0);
使用GetNormal获取当前点集合形成闭合多边形的法线向量;
double x[3] = { 0 };
loop->GetNormal(x);
获得x的值为(0,0,1),表示柱体的方向为Z方向,垂直于XY平面;
修改selectionPoints内点坐标信息
vtkNew<vtkPoints> selectionPoints;
selectionPoints->InsertPoint(0, 0, 0, 0);
selectionPoints->InsertPoint(1, 0, 0.25, 0);
selectionPoints->InsertPoint(2, 0, 0.25, 0.25);
selectionPoints->InsertPoint(3, 0, 0, 0.25);
selectionPoints->InsertPoint(4, 0, 0.125, 0.125);
使用GetNormal获取当前点集合形成闭合多边形的法线向量,发现法线向量仍然是(0,0,1);
在renderWindow->Render();后使用GetNormal,法线向量是(1,0,0);柱体方向是沿着X轴方向,且垂直越YZ平面;
对数据进行两次裁剪,将第一次的裁剪结果作为输入放到vtkClipPolyData中进行二次裁剪;可以实现多次累加裁剪效果。
#include "vtk_include.h"
#include <vtkClipPolyData.h>
#include <vtkImplicitSelectionLoop.h>
#include <vtkLODActor.h>
#include <vtkNamedColors.h>
#include <vtkNew.h>
#include <vtkPolyDataMapper.h>
#include <vtkProperty.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkRenderer.h>
#include <vtkSphereSource.h>
class Test_ImplicitSelectionLoop {
public:
static void Test() {
vtkNew<vtkNamedColors> colors;
vtkNew<vtkSphereSource> sphereSource;
sphereSource->SetPhiResolution(100);
sphereSource->SetThetaResolution(100);
sphereSource->Update();
vtkNew<vtkPoints> selectionPoints;
selectionPoints->InsertPoint(0, 0, 0, 0);
selectionPoints->InsertPoint(1, 0.25, 0, 0);
selectionPoints->InsertPoint(2, 0.25, 0.25, 0);
selectionPoints->InsertPoint(3, 0, 0.25, 0);
selectionPoints->InsertPoint(4, 0.125, 0.125, 0);
vtkNew<vtkImplicitSelectionLoop> loop;
loop->SetLoop(selectionPoints);
vtkNew<vtkClipPolyData> clip;
clip->SetInputConnection(sphereSource->GetOutputPort());
clip->SetClipFunction(loop);
clip->SetValue(0.0);
vtkNew<vtkPoints> selectionPoints2;
selectionPoints2->InsertPoint(0, 0, 0, 0);
selectionPoints2->InsertPoint(1, 0, 0.25, 0);
selectionPoints2->InsertPoint(2, 0, 0.25, 0.25);
selectionPoints2->InsertPoint(3, 0, 0, 0.25);
selectionPoints2->InsertPoint(4, 0, 0.125, 0.125);
vtkNew<vtkImplicitSelectionLoop> loop2;
loop2->SetLoop(selectionPoints2);
vtkNew<vtkClipPolyData> clip2;
clip2->SetInputConnection(clip->GetOutputPort());
clip2->SetClipFunction(loop2);
clip2->SetValue(0.0);
vtkNew<vtkPolyDataMapper> clipMapper;
clipMapper->SetInputConnection(clip2->GetOutputPort());
clipMapper->ScalarVisibilityOff();
vtkNew<vtkProperty> backProp;
backProp->SetColor(colors->GetColor3d("Tomato").GetData());
vtkNew<vtkLODActor> clipActor;
clipActor->SetMapper(clipMapper);
clipActor->SetBackfaceProperty(backProp);
clipActor->GetProperty()->SetColor(colors->GetColor3d("Banana").GetData());
vtkNew<vtkRenderer> renderer;
vtkNew<vtkRenderWindow> renderWindow;
renderWindow->AddRenderer(renderer);
vtkNew<vtkRenderWindowInteractor> interactor;
interactor->SetRenderWindow(renderWindow);
// Add the actors to the renderer, set the background and size
renderer->AddActor(clipActor);
renderer->SetBackground(colors->GetColor3d("SlateGray").GetData());
renderWindow->SetSize(500, 500);
renderWindow->SetWindowName("ImplicitSelectionLoop");
renderWindow->Render();
interactor->Start();
}
};
参考资料
1.ImplicitSelectionLoop示例
2.vtkImplicitSelectionLoop Class Reference