很高兴在雪易的CSDN遇见你 ,给你糖糖![]()
![]()
![]()
欢迎大家加入雪易社区-CSDN社区云
本文主要介绍vtkImplicitFunction接口及其子类的实现原理和用途。希望对各位小伙伴有所帮助!
感谢各位小伙伴的点赞+关注,小易会继续努力分享,一起进步!
你的点赞就是我的动力(^U^)ノ~YO
目录
描述:vtkPlane提供了各种平面的计算方法,包括点到面的投影,计算点到面的距离及面的法向量等。
EvaluateFunction: 返回点到平面的距离(正数表示点在平面法向量一侧;反之相反)。
描述:vtkPolyPlane是vtkPolyLine在Z轴方向的拉伸,可以在vtkCutter中使用。
核心算法实现:
ComputeNormals-->计算每条直线所构成的Plane的法向量
EvaluateFunction实现原理:
x点在无限直线p1p2上的投影点在p1p2之间

x点在无限直线p1p2上的投影点在p1的左侧


x点在无限直线p1p2上的投影点在p1的右侧


for循环:针对每条线
a. 获取该线的两点p1,p2;
b. 计算x点到直线p1,p2的距离(采用点到有限直线距离的计算方法,参考 vtk基础知识 博客);
c. 若x点到直线的最近点在p1,p2之间,则最小距离为x点到直线的距离;计算x点在直线的左侧or右侧。
d. 若x点在无限直线p1p2上的投影点在p1的左侧,则最小距离为x点到p1点的距离;计算x点在直线与前一条直线的左侧or右侧。
e. 若x点在无限直线p1p2上的投影点在p1的右侧,则最小距离为x点到p2点的距离;计算x点在直线与后一条直线的左侧or右侧。
返回x点到vtkPolyPlane的最近距离,以及方向(左侧为正,右侧为负)。
注意:计算的结果存在的问题,详见VTK裁剪【3】-vtkClipPolyData&vtkPolyPlane问题_雪易的博客-CSDN博客
描述:vtkPlanes计算平面集的函数值和梯度值,其中平面集必须是凸区域。
函数值为每个平面函数值的最大值,梯度值为函数值处的平面的法向量。
核心算法实现:计算平面集中的最大函数值
- // Evaluate plane equations. Return the largest value.
- double vtkPlanes::EvaluateFunction(double x[3])
- {
- int numPlanes, i;
- double val, maxVal;
- double normal[3], point[3];
-
- if (!this->Points || !this->Normals)
- {
- vtkErrorMacro(<< "Please define points and/or normals!");
- return VTK_DOUBLE_MAX;
- }
-
- if ((numPlanes = this->Points->GetNumberOfPoints()) != this->Normals->GetNumberOfTuples())
- {
- vtkErrorMacro(<< "Number of normals/points inconsistent!");
- return VTK_DOUBLE_MAX;
- }
-
- for (maxVal = -VTK_DOUBLE_MAX, i = 0; i < numPlanes; i++)
- {
- this->Normals->GetTuple(i, normal);
- this->Points->GetPoint(i, point);
- val = this->Plane->Evaluate(normal, point, x);
- if (val > maxVal)
- {
- maxVal = val;
- }
- }
-
- return maxVal;
- }
vtkPlanes的定义方法
1. 通过点集和法向量来进行定义
注意:vtkPlanes为几个平面的集合,但采用vtkClipPolyData进行切割,并不能得到平面包围区域的集合。
- vtkPoints* planesPoints = vtkPoints::New();
- vtkDoubleArray* Normals = vtkDoubleArray::New();
- Normals->SetNumberOfComponents(3);
- Normals->Allocate(3 * countOfHandles);
- Normals->SetName("Normals");
- Normals->SetNumberOfTuples(countOfHandles);
- double v[3], p1[3], p2[3], n[3], n2[3];
- for (int i = 0; i < countOfHandles; ++i)
- {
- rep->GetHandlePosition(i, p1);
- rep->GetHandlePosition((i + 1) % countOfHandles, p2);
- // The line direction vector
- v[0] = p2[0] - p1[0];
- v[1] = p2[1] - p1[1];
- v[2] = p2[2] - p1[2];
-
- double middlePt[3];
- middlePt[0] = (p1[0] + p2[0]) / 2;
- middlePt[1] = (p1[1] + p2[1]) / 2;
- middlePt[2] = (p1[2] + p2[2]) / 2;
-
- // 'n' is the computed normal.
- vtkMath::Cross(v, eye_look, n);
- vtkMath::Normalize(n);
-
- planesPoints->InsertNextPoint(middlePt);
- Normals->SetTuple(i, n);
- }
1. 通过相机进行定义:
- // Position the camera so that we can see the frustum
- double viewUp[3] = {0.0,1.0,0.0};
- double position[3] = {1.0,0.0,0.0};
- PositionCamera(renderer, viewUp, position);
- renderer->GetActiveCamera()->Elevation(30);
- renderer->GetActiveCamera()->SetViewAngle(10.0);
-
- double planesArray[24];
- renderer->GetActiveCamera()->GetFrustumPlanes(1.0, planesArray);
-
- vtkSmartPointer
planes = - vtkSmartPointer
::New(); - planes->SetFrustumPlanes(planesArray);
2. 通过BoundingBox定义
- vtkSmartPointer
sphereSource = - vtkSmartPointer
::New(); - sphereSource->Update();
-
- double bounds[6];
- sphereSource->GetOutput()->GetBounds(bounds);
-
- vtkSmartPointer
box = - vtkSmartPointer
::New(); -
- box->SetNumberOfPoints(8);
-
- double xMin, xMax, yMin, yMax, zMin, zMax;
- xMin = bounds[0]; xMax = bounds[1];
- yMin = bounds[2]; yMax = bounds[3];
- zMin = bounds[4]; zMax = bounds[5];
-
- box->SetPoint(0, xMax, yMin, zMax);
- box->SetPoint(1, xMax, yMin, zMin);
- box->SetPoint(2, xMax, yMax, zMin);
- box->SetPoint(3, xMax, yMax, zMax);
- box->SetPoint(4, xMin, yMin, zMax);
- box->SetPoint(5, xMin, yMin, zMin);
- box->SetPoint(6, xMin, yMax, zMin);
- box->SetPoint(7, xMin, yMax, zMax);
-
- vtkSmartPointer
planesIntersection = - vtkSmartPointer
::New(); - planesIntersection->SetBounds(bounds);
-
- int intersects = planesIntersection->IntersectsRegion(box);
描述:vtkImplicitSelectionLoop由一组点构成的不规则的环路,可以计算隐函数的函数值和梯度值。环路可以是凹多边形,构成环路的点集也不需要共面。但是当环路投影到环路定义的平面上时,环路必须是非自相交的。
核心算法实现(计算点x的隐函数值):
a. 计算Loop中点集的法线normal;
b. 定义法线normal和点集构成的平面;
c. 将循环的每个点投影到上述平面上,形成多边形;
d. 计算点x到多边形边界的距离,以及是否在多边形内(负值为多边形内;正值为多边形外);
- // Evaluate plane equations. Return smallest absolute value.
- double vtkImplicitSelectionLoop::EvaluateFunction(double x[3])
- {
- int i, numPts;
- double xProj[3];
- double t, dist2, minDist2, closest[3];
- int inside = 0;
-
- if (this->InitializationTime < this->GetMTime())
- {
- this->Initialize();
- }
- // Initialize may change the number of points
- numPts = this->Polygon->Points->GetNumberOfPoints();
-
- // project point onto plane
- vtkPlane::ProjectPoint(x, this->Origin, this->Normal, xProj);
-
- // determine whether it's in the selection loop and then evaluate point
- // in polygon only if absolutely necessary.
- if (xProj[0] >= this->Bounds[0] && xProj[0] <= this->Bounds[1] && xProj[1] >= this->Bounds[2] &&
- xProj[1] <= this->Bounds[3] && xProj[2] >= this->Bounds[4] && xProj[2] <= this->Bounds[5] &&
- this->Polygon->PointInPolygon(xProj, numPts,
- vtkArrayDownCast
(this->Polygon->Points->GetData())->GetPointer(0), - this->Bounds, this->Normal) == 1)
- {
- inside = 1;
- }
-
- // determine distance to boundary
- for (minDist2 = VTK_DOUBLE_MAX, i = 0; i < numPts; i++)
- {
- double p1[3], p2[3];
- this->Polygon->Points->GetPoint(i, p1);
- this->Polygon->Points->GetPoint((i + 1) % numPts, p2);
- dist2 = vtkLine::DistanceToLine(xProj, p1, p2, t, closest);
- if (dist2 < minDist2)
- {
- minDist2 = dist2;
- }
- }
-
- minDist2 = static_cast<double>(sqrt(minDist2));
- return (inside ? -minDist2 : minDist2);
- }
应用实例:
对vtkPolyData数据进行剪切,并没有获取良好的边界,如下图所示。

描述:vtkBox是由轴对齐的边界框构成,并由此计算隐函数值和梯度值。Box的每条边都正交与所有其他边,所有面都正交与x-y-z轴。也可以通过vtkImplicitFunction支持的转换矩阵来定位不同方向的定位框。
描述:vtkCone是通过圆锥来计算隐函数值和梯度值。圆锥顶点位于原点,其旋转轴与x轴重合;角度是指旋转轴与锥体边的夹角。也可以通过vtkImplicitFunction支持的转换矩阵来定位不同方向的定位框。
描述:vtkCylinder使用F(r)=r^2- radius ^2计算的圆柱来计算隐式函数和函数梯度。默认情况下,圆柱体以原点为中心,旋转轴沿着y轴。可以通过设置center和axis来重新定义旋转的中心和轴。
注意:圆柱体的范围是无限的。要在建模操作中截断圆柱体,请结合使用vtkImplicitBoolean和剪切平面来进行操作。
描述:
应用实例1. 将多个平面进行求交,对PolyData进行Clip和Cutter,但得到的结果不太理想,如下图所示。并没有获得整齐的边界。

应用实例2. 将多个平面放入到vtkPlanes中,仍不能得到整齐的边界。

-
- vtkPoints* planesPoints = vtkPoints::New();
- vtkDoubleArray* Normals = vtkDoubleArray::New();
- Normals->SetNumberOfComponents(3);
- Normals->Allocate(3 * countOfHandles);
- Normals->SetName("Normals");
- Normals->SetNumberOfTuples(countOfHandles);
- double v[3], p1[3], p2[3], n[3], n2[3];
-
- auto boolean =
- vtkSmartPointer
::New(); - boolean->SetOperationTypeToUnion();
- for (int i = 0; i < countOfHandles; ++i)
- {
- rep->GetHandlePosition(i, p1);
- rep->GetHandlePosition((i + 1) % countOfHandles, p2);
- // The line direction vector
- v[0] = p2[0] - p1[0];
- v[1] = p2[1] - p1[1];
- v[2] = p2[2] - p1[2];
-
- double middlePt[3];
- middlePt[0] = (p1[0] + p2[0]) / 2;
- middlePt[1] = (p1[1] + p2[1]) / 2;
- middlePt[2] = (p1[2] + p2[2]) / 2;
-
- // 'n' is the computed normal.
- vtkMath::Cross(v, eye_look, n);
- vtkMath::Normalize(n);
-
- planesPoints->InsertNextPoint(middlePt);
- Normals->SetTuple(i, n);
-
- vtkPlane* tmpPlane = vtkPlane::New();
- tmpPlane->SetNormal(n);
- tmpPlane->SetOrigin(middlePt);
- boolean->AddFunction(tmpPlane);
- }
-
- vtkNew
planes; - planes->SetPoints(planesPoints);
- planes->SetNormals(Normals);
-
-
- vtkSmartPointer
planesClipper = vtkSmartPointer::New(); - planesClipper->SetInputData(m_selectObject->GetPolyData());
- planesClipper->SetClipFunction(boolean);
- //planesClipper->SetValue(0.);
- planesClipper->Update();
-
- if (planesClipper->GetOutput())
- {
- emit sendTrimResult(planesClipper->GetOutput());
- }
-
-
-
本文主要介绍vtkImplicitFunction接口及其子类的实现原理和用途。
感谢各位小伙伴的点赞+关注,小易会继续努力分享,一起进步!
你的赞赏是我的最最最最大的动力(^U^)ノ~YO
