C# VTK 自定义封装 vtkwPipeline 多边形管道建模

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]);
            }
        }

    }

  • 9
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值