vtkwPipeline 简介
public vtkwPipeline(vtkLineSource lineSource, double outR, double inR, int sides)
vtkwPipeline 是我自定义封装的C# 类 用于对管道壁建模,有内半径,外半径设置,
以及多边形边数设置。
参数
1. vtkLineSource lineSource : 建模的管道路径
2.double outR:外半径
3.double inR: 内半径
4.int sides: 多边形边数
建模逻辑步骤
1.对lineSource第一个点进行 vtkRegularPolygonSource 内外多边形点集构建。
2.利用这个初始pipeFace 一直向下一个点直线移动,直到第二点停止,然后进行节点的角度旋转。
3.构建节点的夹角plane 将两个pipeFace 对应点连接为中心对plane 求进行直线交点,生成节点的pipeFace。
public class vtkwPipeline
{
vtkCellArray Plane;
vtkPoints Points;
vtkPolyData PolyData;
double OutRadius = 2;
double InRadius = 1;
int Sides = 30;
vtkLineSource LineSource;
public vtkwPipeline(vtkLineSource lineSource, double outR, double inR, int sides)
{
LineSource = lineSource;
outR = Math.Abs(outR);
inR = Math.Abs(inR);
(OutRadius, InRadius) = outR > inR ? (outR, inR) : (inR, outR);
Sides = sides;
Plane = new vtkCellArray();
Points = new vtkPoints();
PolyData = new vtkPolyData();
}
public void Update()
{
if (LineSource == null || LineSource.GetOutput().GetNumberOfPoints() <= 1)
{
return;
}
vtkPoints linePoints = LineSource.GetOutput().GetPoints();
double[] first = linePoints.GetPoint(0);
double[] next = linePoints.GetPoint(1);
double[] norm = new double[3] { next[0] - first[0], next[1] - first[1], next[2] - first[2] };
PipeFace lastPipeFace = new PipeFace(first, norm, OutRadius, InRadius, Sides);
lastPipeFace.InsertPoints(ref Points);
lastPipeFace.CellFace(ref Plane);
PipeFace lastCalcuPipeFace = lastPipeFace;
PipeFace nextPipeFace = new PipeFace();
for (int i = 1; i < linePoints.GetNumberOfPoints(); i++)
{
nextPipeFace = new PipeFace();
if (i == linePoints.GetNumberOfPoints() - 1)
{
first = linePoints.GetPoint(i - 1);
next = linePoints.GetPoint(i);
norm = new double[3] { next[0] - first[0], next[1] - first[1], next[2] - first[2] };
double[] moveValue = norm;
nextPipeFace = new PipeFace(lastPipeFace, moveValue, 0, new double[] { 0, 0, 0 });
nextPipeFace.InsertPoints(ref Points);
nextPipeFace.CellFace(ref Plane);
}
else
{
first = linePoints.GetPoint(i - 1);
next = linePoints.GetPoint(i);
norm = new double[3] { next[0] - first[0], next[1] - first[1], next[2] - first[2] };
double[] moveValue = norm;
// 移动到末端节点
double[] trid = linePoints.GetPoint(i + 1);
PipeFace nodePipe_1 = new PipeFace(lastPipeFace, moveValue, 0, new double[] { 0, 0, 0 });
double[] normNext = new double[3] { trid[0] - next[0], trid[1] - next[1], trid[2] - next[2] };
double[] rotNorm = CrossProduct(normNext, norm);
double rotValue = CalculateAngle(normNext, norm);
PipeFace nodePipe_2 = new PipeFace(nodePipe_1, new double[] { 0, 0, 0 }, rotValue, rotNorm);
// 计算偏移
double[] norm2 = new double[3] { trid[0] - next[0], trid[1] - next[1], trid[2] - next[2] };
double dis = CalculateDistance(first, next);
norm2 = NormalizeVector(norm2);
double[] tempPoint = MovePoint(next, norm2, dis);
norm2 = new double[3] { tempPoint[0] - first[0], tempPoint[1] - first[1], tempPoint[2] - first[2] };
norm2 = NormalizeVector(norm2);
vtkPlane plane = new vtkPlane();
plane.SetNormal(norm2[0], norm2[1], norm2[2]);
plane.SetOrigin(next[0], next[1], next[2]);
vtkPoints outPoints_1 = new vtkPoints();
outPoints_1.DeepCopy(lastPipeFace.outPoints);
vtkPoints inPoints_1 = new vtkPoints();
inPoints_1.DeepCopy(lastPipeFace.intPoints);
vtkPoints outPoints_2 = new vtkPoints();
outPoints_2.DeepCopy(nodePipe_1.outPoints);
vtkPoints inPoints_2 = new vtkPoints();
inPoints_2.DeepCopy(nodePipe_1.intPoints);
// 投影到交界平面
for (int k = 0; k < outPoints_2.GetNumberOfPoints(); k++)
{
double[] pout1 = outPoints_1.GetPoint(k);
double[] pin1 = inPoints_1.GetPoint(k);
IntPtr pOut1Ptr = Marshal.AllocCoTaskMem(sizeof(double) * 3);
Marshal.Copy(pout1, 0, pOut1Ptr, 3);
IntPtr pIn1Ptr = Marshal.AllocCoTaskMem(sizeof(double) * 3);
Marshal.Copy(pin1, 0, pIn1Ptr, 3);
double[] pout2 = outPoints_2.GetPoint(k);
double[] pin2 = inPoints_2.GetPoint(k);
IntPtr pOut2Ptr = Marshal.AllocCoTaskMem(sizeof(double) * 3);
Marshal.Copy(pout2, 0, pOut2Ptr, 3);
IntPtr pIn2Ptr = Marshal.AllocCoTaskMem(sizeof(double) * 3);
Marshal.Copy(pin2, 0, pIn2Ptr, 3);
// 外圈偏移点
double t = 0;
IntPtr outPtr = Marshal.AllocCoTaskMem(sizeof(double) * 3);
plane.IntersectWithLine(pOut1Ptr, pOut2Ptr, ref t, outPtr);
Marshal.Copy(outPtr, pout2, 0, 3);
outPoints_2.SetPoint(k, pout2[0], pout2[1], pout2[2]);
// 内圈偏移点
IntPtr inPtr = Marshal.AllocCoTaskMem(sizeof(double) * 3);
plane.IntersectWithLine(pIn1Ptr, pIn2Ptr, ref t, inPtr);
Marshal.Copy(inPtr, pin2, 0, 3);
inPoints_2.SetPoint(k, pin2[0], pin2[1], pin2[2]);
}
nextPipeFace.center = next;
nextPipeFace.outPoints = outPoints_2;
nextPipeFace.intPoints = inPoints_2;
nextPipeFace.InsertPoints(ref Points);
nextPipeFace.CellFace(ref Plane);
lastPipeFace = nodePipe_2;
}
PipeFace.CellArray(lastCalcuPipeFace, nextPipeFace, ref Plane);
lastCalcuPipeFace = nextPipeFace;
}
PolyData = new vtkPolyData();
PolyData.SetPoints(Points);
PolyData.SetStrips(Plane);
}
public vtkPolyData GetOutput()
{
return PolyData;
}
public static double CalculateAngle(double[] vectorA, double[] vectorB)
{
// 检查向量长度是否相等
if (vectorA.Length != 3 || vectorB.Length != 3)
{
throw new ArgumentException("Both vectors must be 3-dimensional.");
}
// 计算点积
double dotProduct = vectorA[0] * vectorB[0] + vectorA[1] * vectorB[1] + vectorA[2] * vectorB[2];
// 计算两个向量的模
double magnitudeA = Math.Sqrt(vectorA[0] * vectorA[0] + vectorA[1] * vectorA[1] + vectorA[2] * vectorA[2]);
double magnitudeB = Math.Sqrt(vectorB[0] * vectorB[0] + vectorB[1] * vectorB[1] + vectorB[2] * vectorB[2]);
// 计算夹角的余弦值
double cosTheta = dotProduct / (magnitudeA * magnitudeB);
// 防止浮点误差引起的 Math.Acos 域错误
cosTheta = Math.Max(-1.0, Math.Min(1.0, cosTheta));
// 计算并返回夹角(以弧度为单位)
double angleInRadians = Math.Acos(cosTheta);
// 将弧度转换为度数(如果需要)
double angleInDegrees = angleInRadians * (180.0 / Math.PI);
return angleInDegrees;
}
public static double[] NormalizeVector(double[] vector)
{
// 检查向量长度是否为3
if (vector.Length != 3)
{
throw new ArgumentException("The input vector must be 3-dimensional.");
}
// 计算向量的模
double magnitude = Math.Sqrt(vector[0] * vector[0] + vector[1] * vector[1] + vector[2] * vector[2]);
// 检查向量模是否为零
if (magnitude == 0)
{
return vector;
throw new ArgumentException("The magnitude of the vector is zero, cannot normalize.");
}
// 计算单位化向量
double[] normalizedVector = new double[3];
normalizedVector[0] = vector[0] / magnitude;
normalizedVector[1] = vector[1] / magnitude;
normalizedVector[2] = vector[2] / magnitude;
return normalizedVector;
}
public static double CalculateDistance(double[] p1, double[] p2)
{
// 计算各坐标的差值
double dx = p2[0] - p1[0];
double dy = p2[1] - p1[1];
double dz = p2[2] - p1[2];
// 使用欧几里得距离公式计算距离
double distance = Math.Sqrt(dx * dx + dy * dy + dz * dz);
return distance;
}
public static double[] CrossProduct(double[] vectorA, double[] vectorB)
{
// 检查向量长度是否为3
if (vectorA.Length != 3 || vectorB.Length != 3)
{
throw new ArgumentException("Both vectors must be 3-dimensional.");
}
// 计算叉积
double[] crossProduct = new double[3];
crossProduct[0] = vectorA[1] * vectorB[2] - vectorA[2] * vectorB[1];
crossProduct[1] = vectorA[2] * vectorB[0] - vectorA[0] * vectorB[2];
crossProduct[2] = vectorA[0] * vectorB[1] - vectorA[1] * vectorB[0];
return crossProduct;
}
public static double[] MovePoint(double[] point, double[] direction, double distance)
{
if (point.Length != 3 || direction.Length != 3)
{
throw new ArgumentException("Both the point and direction vector must be 3-dimensional.");
}
// 计算方向向量的模
double magnitude = Math.Sqrt(direction[0] * direction[0] + direction[1] * direction[1] + direction[2] * direction[2]);
// 单位化方向向量
double[] unitDirection = new double[3];
unitDirection[0] = direction[0] / magnitude;
unitDirection[1] = direction[1] / magnitude;
unitDirection[2] = direction[2] / magnitude;
// 计算移动向量
double[] moveVector = new double[3];
moveVector[0] = unitDirection[0] * distance;
moveVector[1] = unitDirection[1] * distance;
moveVector[2] = unitDirection[2] * distance;
// 更新点的位置
double[] newPoint = new double[3];
newPoint[0] = point[0] + moveVector[0];
newPoint[1] = point[1] + moveVector[1];
newPoint[2] = point[2] + moveVector[2];
return newPoint;
}
public class PipeFace
{
public double[] center;
public vtkPoints outPoints;
public vtkPoints intPoints;
public List<int> outId = new List<int>();
public List<int> inId = new List<int>();
public PipeFace()
{
}
public PipeFace(double[] cen, double[] norm, double outRadius, double inRadius, int sides)
{
center = cen;
outPoints = GeneratePolygonPoints(center, norm, outRadius, sides);
intPoints = GeneratePolygonPoints(center, norm, inRadius, sides);
}
public PipeFace(PipeFace lastPipeFace, double[] moveValue, double rotValue, double[] rotNorm)
{
TransPipeFace(lastPipeFace, moveValue, rotValue, rotNorm);
}
public void TransPipeFace(PipeFace lastPipeFace, double[] moveValue, double rotValue, double[] rotNorm)
{
vtkPolyData outPointData = new vtkPolyData();
outPointData.SetPoints(lastPipeFace.outPoints);
vtkPolyData inPointData = new vtkPolyData();
inPointData.SetPoints(lastPipeFace.intPoints);
center = lastPipeFace.center;
center[0] = lastPipeFace.center[0] + moveValue[0];
center[1] = lastPipeFace.center[1] + moveValue[1];
center[2] = lastPipeFace.center[2] + moveValue[2];
rotNorm = NormalizeVector(rotNorm);
vtkTransform transform = new vtkTransform();
transform.Translate(moveValue[0], moveValue[1], moveValue[2]);
transform.Translate(center[0], center[1], center[2]);
transform.RotateWXYZ(-rotValue, rotNorm[0], rotNorm[1], rotNorm[2]);
transform.Translate(-center[0], -center[1], -center[2]);
transform.Update();
vtkTransformFilter transFilter = new vtkTransformFilter();
transFilter.SetInputData(outPointData);
transFilter.SetTransform(transform);
transFilter.Update();
outPoints = transFilter.GetOutput().GetPoints();
transFilter.SetInputData(inPointData);
transFilter.SetTransform(transform);
transFilter.Update();
intPoints = transFilter.GetOutput().GetPoints();
double[] cen2 = transFilter.GetOutput().GetCenter();
}
public void InsertPoints(ref vtkPoints points)
{
if (outPoints != null && intPoints != null)
{
for (int n = 0; n < outPoints.GetNumberOfPoints(); n++)
{
double[] pos = outPoints.GetPoint(n);
int id = (int)points.InsertNextPoint(pos[0], pos[1], pos[2]);
outId.Add(id);
}
for (int k = 0; k < intPoints.GetNumberOfPoints(); k++)
{
double[] pos = intPoints.GetPoint(k);
int id = (int)points.InsertNextPoint(pos[0], pos[1], pos[2]);
inId.Add(id);
}
}
}
public void CellFace(ref vtkCellArray plane)
{
int npts = outId.Count + inId.Count;
if (npts == 0)
{
return;
}
plane.InsertNextCell(npts + 2);
for (int n = 0; n < outId.Count; n++)
{
plane.InsertCellPoint(outId[n]);
plane.InsertCellPoint(inId[n]);
}
plane.InsertCellPoint(outId[0]);
plane.InsertCellPoint(inId[0]);
}
public vtkPoints GeneratePolygonPoints(double[] center, double[] norm, double radius, int sides)
{
vtkRegularPolygonSource polygonSource = new vtkRegularPolygonSource();
polygonSource.SetCenter(center[0], center[1], center[2]);
polygonSource.SetNormal(norm[0], norm[1], norm[2]);
polygonSource.SetRadius(radius);
polygonSource.SetNumberOfSides(sides);
polygonSource.SetGeneratePolygon(1);
polygonSource.SetGeneratePolyline(1);
polygonSource.Update();
vtkStripper stripper = new vtkStripper();
stripper.SetInputData(polygonSource.GetOutput());
stripper.JoinContiguousSegmentsOn();
stripper.Update();
return stripper.GetOutput().GetPoints();
}
public static void CellArray(PipeFace pipe1, PipeFace pipe2, ref vtkCellArray plane)
{
int inNpts = pipe1.inId.Count + pipe2.inId.Count;
// 内外条带
plane.InsertNextCell(inNpts + 2);
for (int n = 0; n < pipe1.inId.Count; n++)
{
plane.InsertCellPoint(pipe1.inId[n]);
plane.InsertCellPoint(pipe2.inId[n]);
}
plane.InsertCellPoint(pipe1.inId[0]);
plane.InsertCellPoint(pipe2.inId[0]);
int outNpts = pipe1.outId.Count + pipe2.outId.Count;
plane.InsertNextCell(outNpts + 2);
for (int n = 0; n < pipe1.outId.Count; n++)
{
plane.InsertCellPoint(pipe1.outId[n]);
plane.InsertCellPoint(pipe2.outId[n]);
}
plane.InsertCellPoint(pipe1.outId[0]);
plane.InsertCellPoint(pipe2.outId[0]);
}
}
}