Exemplo n.º 1
0
        public bool CalculateSurface(SpringMesh sMesh, double thickness, List <Curve> curvesRight, List <Curve> curvesLeft)
        {
            foreach (Edge edge in sMesh.Edges)
            {
                if (edge.SecondTriangleIndex >= 0)
                {
                    // first vertex
                    // first triangle
                    #region curve01

                    int firstPtId            = edge.FirstVertexIndex;
                    int firstTriangleIdRight = edge.FirstTriangleIndex;

                    Vertex firstPtVertex       = sMesh.Vertices[firstPtId];
                    double firstPtVertexFactor = vertexFactors[firstPtId];
                    //Point3d firstTriCentreRight = sMesh.ComputeTriangleCenter(firstTriangleIdRight);
                    Point3d firstTriCentreRight = sMesh.ComputeCircumscribedCircleCenter(firstTriangleIdRight);

                    Vector3d firstNormalRight = thickness * sMesh.ComputeTriangleNormal(firstTriangleIdRight);

                    Point3d firstTriCentreUpRight   = firstTriCentreRight + firstNormalRight;    // the first control point
                    Point3d firstTriCentreDownRight = firstTriCentreRight - firstNormalRight;    // the seventh control point

                    Point3d firstCPt02Right = (firstPtVertexFactor - 0.2) * firstPtVertex.Position + (1 - firstPtVertexFactor + 0.2) * firstTriCentreRight;

                    Point3d firstCPt02UpRight   = firstCPt02Right + firstNormalRight;              // the second control point
                    Point3d firstCPt02DownRight = firstCPt02Right - firstNormalRight;              // the sixth control point

                    Point3d firstCPt03Right = firstPtVertexFactor * firstPtVertex.Position + (1 - firstPtVertexFactor) * firstTriCentreRight;

                    Point3d firstCPt03UpRight   = firstCPt03Right + firstNormalRight;      // the third control point
                    Point3d firstCPt03DownRight = firstCPt03Right - firstNormalRight;      // the fifth control point

                    Point3d firstUpPtRight = firstPtVertex.Position;                       // the fourth control point

                    List <Point3d> firstControlPointRight = new List <Point3d>()
                    {
                        firstTriCentreUpRight, firstCPt02UpRight, firstCPt03UpRight, firstUpPtRight,
                        firstCPt03DownRight, firstCPt02DownRight, firstTriCentreDownRight
                    };
                    #endregion
                    NurbsCurve firstNurbCurveRight = NurbsCurve.Create(false, 5, firstControlPointRight);

                    // second triangle
                    #region curve02

                    int firstTriangleIdLeft = edge.SecondTriangleIndex;

                    //Point3d firstTriCentreLeft = sMesh.ComputeTriangleCenter(firstTriangleIdLeft);
                    Point3d firstTriCentreLeft = sMesh.ComputeCircumscribedCircleCenter(firstTriangleIdLeft);

                    Vector3d firstNormalLeft = thickness * sMesh.ComputeTriangleNormal(firstTriangleIdLeft);

                    Point3d firstTriCentreUpLeft   = firstTriCentreLeft + firstNormalLeft;    // the first control point
                    Point3d firstTriCentreDownLeft = firstTriCentreLeft - firstNormalLeft;    // the seventh control point

                    Point3d firstCPt02Left = (firstPtVertexFactor - 0.2) * firstPtVertex.Position + (1 - firstPtVertexFactor + 0.2) * firstTriCentreLeft;

                    Point3d firstCPt02UpLeft   = firstCPt02Left + firstNormalLeft;              // the second control point
                    Point3d firstCPt02DownLeft = firstCPt02Left - firstNormalLeft;              // the sixth control point

                    Point3d firstCPt03Left = firstPtVertexFactor * firstPtVertex.Position + (1 - firstPtVertexFactor) * firstTriCentreLeft;

                    Point3d firstCPt03UpLeft   = firstCPt03Left + firstNormalLeft;        // the third control point
                    Point3d firstCPt03DownLeft = firstCPt03Left - firstNormalLeft;        // the fifth control point

                    Point3d firstUpPtLeft = firstPtVertex.Position;                       // the fourth control point

                    List <Point3d> firstControlPointLeft = new List <Point3d>()
                    {
                        firstTriCentreUpLeft, firstCPt02UpLeft, firstCPt03UpLeft, firstUpPtLeft,
                        firstCPt03DownLeft, firstCPt02DownLeft, firstTriCentreDownLeft
                    };
                    #endregion
                    NurbsCurve firstNurbCurveLeft = NurbsCurve.Create(false, 5, firstControlPointLeft);

                    curvesRight.Add(firstNurbCurveRight);
                    curvesLeft.Add(firstNurbCurveLeft);

                    /*
                     * Brep[] brep1 = Brep.CreateFromLoft(
                     *  new List<Curve>() { firstNurbCurveRight, firstNurbCurveLeft },
                     *  Point3d.Unset, Point3d.Unset, LoftType.Developable, false);
                     *
                     * if (brep1.Length > 0) breps.Add(brep1[0]); */

                    // second vertex
                    // first triangle
                    #region curve03

                    int secondPtId            = edge.SecondVertexIndex;
                    int secondTriangleIdRight = edge.FirstTriangleIndex;

                    Vertex secondPtVertex       = sMesh.Vertices[secondPtId];
                    double secondPtVertexFactor = vertexFactors[secondPtId];
                    //Point3d secondTriCentreRight = sMesh.ComputeTriangleCenter(secondTriangleIdRight);
                    Point3d secondTriCentreRight = sMesh.ComputeCircumscribedCircleCenter(secondTriangleIdRight);

                    Vector3d secondNormalRight = thickness * sMesh.ComputeTriangleNormal(secondTriangleIdRight);

                    Point3d secondTriCentreUpRight   = secondTriCentreRight + secondNormalRight;    // the second control point
                    Point3d secondTriCentreDownRight = secondTriCentreRight - secondNormalRight;    // the seventh control point

                    Point3d secondCPt02Right = (secondPtVertexFactor - 0.2) * secondPtVertex.Position + (1 - secondPtVertexFactor + 0.2) * secondTriCentreRight;

                    Point3d secondCPt02UpRight   = secondCPt02Right + secondNormalRight;              // the second control point
                    Point3d secondCPt02DownRight = secondCPt02Right - secondNormalRight;              // the sixth control point

                    Point3d secondCPt03Right = secondPtVertexFactor * secondPtVertex.Position + (1 - secondPtVertexFactor) * secondTriCentreRight;

                    Point3d secondCPt03UpRight   = secondCPt03Right + secondNormalRight;     // the third control point
                    Point3d secondCPt03DownRight = secondCPt03Right - secondNormalRight;     // the fifth control point

                    Point3d secondUpPtRight = secondPtVertex.Position;                       // the fourth control point

                    List <Point3d> secondControlPointRight = new List <Point3d>()
                    {
                        secondTriCentreUpRight, secondCPt02UpRight, secondCPt03UpRight, secondUpPtRight,
                        secondCPt03DownRight, secondCPt02DownRight, secondTriCentreDownRight
                    };

                    #endregion
                    NurbsCurve secondNurbCurveRight = NurbsCurve.Create(false, 5, secondControlPointRight);

                    // second triangle
                    #region curve04

                    int secondTriangleIdLeft = edge.SecondTriangleIndex;

                    //Point3d secondTriCentreLeft = sMesh.ComputeTriangleCenter(secondTriangleIdLeft);
                    Point3d secondTriCentreLeft = sMesh.ComputeCircumscribedCircleCenter(secondTriangleIdLeft);

                    Vector3d secondNormalLeft = thickness * sMesh.ComputeTriangleNormal(secondTriangleIdLeft);

                    Point3d secondTriCentreUpLeft   = secondTriCentreLeft + secondNormalLeft;    // the second control point
                    Point3d secondTriCentreDownLeft = secondTriCentreLeft - secondNormalLeft;    // the seventh control point

                    Point3d secondCPt02Left = (secondPtVertexFactor - 0.2) * secondPtVertex.Position + (1 - secondPtVertexFactor + 0.2) * secondTriCentreLeft;

                    Point3d secondCPt02UpLeft   = secondCPt02Left + secondNormalLeft;              // the second control point
                    Point3d secondCPt02DownLeft = secondCPt02Left - secondNormalLeft;              // the sixth control point

                    Point3d secondCPt03Left = secondPtVertexFactor * secondPtVertex.Position + (1 - secondPtVertexFactor) * secondTriCentreLeft;

                    Point3d secondCPt03UpLeft   = secondCPt03Left + secondNormalLeft;       // the third control point
                    Point3d secondCPt03DownLeft = secondCPt03Left - secondNormalLeft;       // the fifth control point

                    Point3d secondUpPtLeft = secondPtVertex.Position;                       // the fourth control point

                    List <Point3d> secondControlPointLeft = new List <Point3d>()
                    {
                        secondTriCentreUpLeft, secondCPt02UpLeft, secondCPt03UpLeft, secondUpPtLeft,
                        secondCPt03DownLeft, secondCPt02DownLeft, secondTriCentreDownLeft
                    };
                    #endregion
                    NurbsCurve secondNurbCurveLeft = NurbsCurve.Create(false, 5, secondControlPointLeft);

                    curvesRight.Add(secondNurbCurveRight);
                    curvesLeft.Add(secondNurbCurveLeft);

                    /*
                     * Brep[] brep2 = Brep.CreateFromLoft(
                     *  new List<Curve>() { firstNurbCurveRight, firstNurbCurveLeft },
                     *  Point3d.Unset, Point3d.Unset, LoftType.Developable, false);
                     *
                     * if (brep2.Length > 0) breps.Add(brep2[0]);  */
                }
            }
            return(true);
        }
        protected override void SolveInstance(IGH_DataAccess DA)
        {
            iPoints = new List <Point3d>();
            DA.GetDataList <Point3d>("Points", iPoints);
            iApicals = new List <Circle>();
            DA.GetDataList <Circle>("Apicals", iApicals);
            iMasses = new List <double>();
            DA.GetDataList <double>("Masses", iMasses);
            DA.GetData <Curve>("Boundary Curve", ref iBoundaryCurve);
            DA.GetData <double>("Rest Length Scale", ref iRestLengthScale);
            DA.GetData <double>("Rest Length Offset", ref iRestLengthOffset);
            DA.GetData <double>("Stiffness", ref iStiffness);
            DA.GetData <double>("Bending Stiffness", ref iBendingStiffness);
            DA.GetData <bool>("In/Out Switch", ref iInOutSwitch);
            DA.GetData <double>("In/Out Threshold", ref iInOutThreshold);
            DA.GetData <double>("Boundary Vertex Threshold", ref iBoundaryVertexThreshold);
            iFixedPointExclusion = new List <Curve>();
            DA.GetDataList <Curve>("Fixed Point Exclusion", iFixedPointExclusion);
            iFixedPointInclusion = new List <Curve>();
            DA.GetDataList <Curve>("Fixed Point Inclusion", iFixedPointInclusion);


            // ===========================================================================================
            // Compute Delaunay Triangulation
            // ===========================================================================================

            List <DelaunayVertex> delaunayVertices = new List <DelaunayVertex>();

            foreach (Point3d point in iPoints)
            {
                delaunayVertices.Add(new DelaunayVertex(point.X, point.Y));
            }

            List <Triad> triads = new DelaunayTriangulator().Triangulation(delaunayVertices);

            HashSet <Tuple <int, int> > delaunayEdgeTuples = new HashSet <Tuple <int, int> >();


            for (int i = 0; i < triads.Count; i++)
            {
                Triad triad = triads[i];
                delaunayEdgeTuples.Add(triad.a < triad.b ? new Tuple <int, int>(triad.a, triad.b) : new Tuple <int, int>(triad.b, triad.a));
                delaunayEdgeTuples.Add(triad.b < triad.c ? new Tuple <int, int>(triad.b, triad.c) : new Tuple <int, int>(triad.c, triad.b));
                delaunayEdgeTuples.Add(triad.c < triad.a ? new Tuple <int, int>(triad.c, triad.a) : new Tuple <int, int>(triad.a, triad.c));
            }


            // ===========================================================================================
            // Convert Delaunay mesh to particle-spring mesh
            // ===========================================================================================

            oSpringMesh = new SpringMesh();
            Curve boundaryCurveXY = Curve.ProjectToPlane(iBoundaryCurve, Plane.WorldXY);

            // Create edge list -----------------------------------------------------------------------------------------------

            foreach (Tuple <int, int> delaunayEdgeTuple in delaunayEdgeTuples)
            {
                Point3d A = iPoints[delaunayEdgeTuple.Item1];
                Point3d B = iPoints[delaunayEdgeTuple.Item2];
                Point3d M = 0.5 * (A + B);

                // Skip if the edge lies outside of the boundary
                double t;
                boundaryCurveXY.ClosestPoint(M, out t);
                Point3d N = boundaryCurveXY.PointAt(t);
                if (Vector3d.CrossProduct(boundaryCurveXY.TangentAt(t), M - N).Z *(iInOutSwitch ? -1.0 : 1.0) < 0.0 &&
                    Utils.DistanceSquared(M, N) > iInOutThreshold * iInOutThreshold)
                {
                    continue;
                }

                double edgeLength = Utils.Distance(A, B);
                double restLength = iRestLengthScale * edgeLength + iRestLengthOffset;
                oSpringMesh.Edges.Add(new Edge(delaunayEdgeTuple.Item1, delaunayEdgeTuple.Item2, restLength, iStiffness, Math.PI, iBendingStiffness));
            }

            // Create vertex list -----------------------------------------------------------------------------------------------

            List <HashSet <int> > neighborVerticesSets = new List <HashSet <int> >();

            for (int i = 0; i < iPoints.Count; i++)
            {
                neighborVerticesSets.Add(new HashSet <int>());
            }

            foreach (Edge edge in oSpringMesh.Edges)
            {
                neighborVerticesSets[edge.FirstVertexIndex].Add(edge.SecondVertexIndex);
                neighborVerticesSets[edge.SecondVertexIndex].Add(edge.FirstVertexIndex);
            }

            for (int i = 0; i < iPoints.Count; i++)
            {
                Point3d p = iPoints[i];
                double  t;
                boundaryCurveXY.ClosestPoint(p, out t);

                bool vertexFixedness  = false;
                bool isBoundaryVertex = false;
                bool isColumnVertex   = false;

                if (Utils.Distance(p, boundaryCurveXY.PointAt(t)) < iBoundaryVertexThreshold)
                {
                    vertexFixedness  = true;
                    isBoundaryVertex = true;
                }
                else
                {
                    foreach (Curve curve in iFixedPointInclusion)
                    {
                        if (curve.Contains(p) == PointContainment.Inside)
                        {
                            vertexFixedness = true;
                            isColumnVertex  = true;
                            break;
                        }
                    }
                }


                Vertex vertex = new Vertex(p, Vector3d.Zero, neighborVerticesSets[i].ToList <int>(), iMasses.Count == 1 ? iMasses[0] : iMasses[i], vertexFixedness);
                vertex.IsBoundaryVertex = isBoundaryVertex;
                vertex.IsColumnVertex   = isColumnVertex;
                oSpringMesh.Vertices.Add(vertex);
            }


            // Set boundary edge -----------------------------------------------------------------------------------------------

            foreach (Edge edge in oSpringMesh.Edges)
            {
                if (oSpringMesh.Vertices[edge.FirstVertexIndex].IsBoundaryVertex && oSpringMesh.Vertices[edge.SecondVertexIndex].IsBoundaryVertex)
                {
                    edge.IsBoundaryEdge = true;
                }
                else if (oSpringMesh.Vertices[edge.FirstVertexIndex].IsColumnVertex && oSpringMesh.Vertices[edge.SecondVertexIndex].IsColumnVertex)
                {
                    edge.IsColumnEdge = true;
                }
            }

            // Create triangle list ------------------------------------------------------------------------------------------------

            Dictionary <Tuple <int, int, int>, int> tripletDict = new Dictionary <Tuple <int, int, int>, int>();

            for (int k = 0; k < oSpringMesh.Edges.Count; k++)
            {
                Edge   edge = oSpringMesh.Edges[k];
                Vertex A    = oSpringMesh.Vertices[edge.FirstVertexIndex];
                Vertex B    = oSpringMesh.Vertices[edge.SecondVertexIndex];

                for (int i = 0; i < A.NeighborVertexIndices.Count; i++)
                {
                    for (int j = 0; j < B.NeighborVertexIndices.Count; j++)
                    {
                        if (A.NeighborVertexIndices[i] == B.NeighborVertexIndices[j])
                        {
                            Tuple <int, int, int> triplet = sortTriplet(edge.FirstVertexIndex, edge.SecondVertexIndex, A.NeighborVertexIndices[i]);

                            if (tripletDict.ContainsKey(triplet))
                            {
                                if (edge.FirstTriangleIndex < 0)
                                {
                                    edge.FirstTriangleIndex       = tripletDict[triplet];
                                    edge.FirstAdjacentVertexIndex = A.NeighborVertexIndices[i];
                                }
                                else
                                {
                                    edge.SecondTriangleIndex       = tripletDict[triplet];
                                    edge.SecondAdjacentVertexIndex = A.NeighborVertexIndices[i];
                                }
                            }
                            else
                            {
                                oSpringMesh.Triangles.Add(new Triangle(triplet.Item1, triplet.Item2, triplet.Item3));

                                int triangleIndex = oSpringMesh.Triangles.Count - 1;

                                if (edge.FirstTriangleIndex < 0)
                                {
                                    edge.FirstTriangleIndex       = triangleIndex;
                                    edge.FirstAdjacentVertexIndex = A.NeighborVertexIndices[i];
                                }
                                else
                                {
                                    edge.SecondTriangleIndex       = triangleIndex;
                                    edge.SecondAdjacentVertexIndex = A.NeighborVertexIndices[i];
                                }

                                tripletDict.Add(triplet, triangleIndex);
                            }
                        }
                    }
                }
            }

            // ===========================================================================================
            // Compute edge indices for each triangle
            // ===========================================================================================

            for (int i = 0; i < oSpringMesh.Edges.Count; i++)
            {
                Edge edge = oSpringMesh.Edges[i];

                Triangle triangle = oSpringMesh.Triangles[edge.FirstTriangleIndex];
                if (triangle.FirstEdgeIndex == -1)
                {
                    triangle.FirstEdgeIndex = i;
                }
                else if (triangle.SecondEdgeIndex == -1)
                {
                    triangle.SecondEdgeIndex = i;
                }
                else
                {
                    triangle.ThirdEdgeIndex = i;
                }

                if (edge.SecondTriangleIndex == -1)
                {
                    continue;
                }

                triangle = oSpringMesh.Triangles[edge.SecondTriangleIndex];
                if (triangle.FirstEdgeIndex == -1)
                {
                    triangle.FirstEdgeIndex = i;
                }
                else if (triangle.SecondEdgeIndex == -1)
                {
                    triangle.SecondEdgeIndex = i;
                }
                else
                {
                    triangle.ThirdEdgeIndex = i;
                }
            }


            // ===========================================================================================
            // Rearange the vertex order in each triangle so the normal calculation is consistent
            // ===========================================================================================

            for (int i = 0; i < oSpringMesh.Triangles.Count; i++)
            {
                if (oSpringMesh.ComputeTriangleNormal(i).Z < 0.0)
                {
                    int temp = oSpringMesh.Triangles[i].SecondVertexIndex;
                    oSpringMesh.Triangles[i].SecondVertexIndex = oSpringMesh.Triangles[i].ThirdVertexIndex;
                    oSpringMesh.Triangles[i].ThirdVertexIndex  = temp;
                }
            }


            // ===========================================================================================
            // Rearranging edge adjacent vertex indices for consitency
            // ===========================================================================================

            foreach (Edge edge in oSpringMesh.Edges)
            {
                if (edge.SecondAdjacentVertexIndex == -1)
                {
                    Point3d A = oSpringMesh.Vertices[edge.FirstVertexIndex].Position;
                    Point3d B = oSpringMesh.Vertices[edge.SecondVertexIndex].Position;
                    Point3d M = oSpringMesh.Vertices[edge.FirstAdjacentVertexIndex].Position;

                    if (Vector3d.CrossProduct(B - A, M - A) * oSpringMesh.ComputeTriangleNormal(edge.FirstTriangleIndex) < 0.0)
                    {
                        Point3d temp = A;
                        A = B;
                        B = temp;
                    }
                }
                else
                {
                    Point3d A = oSpringMesh.Vertices[edge.FirstVertexIndex].Position;
                    Point3d B = oSpringMesh.Vertices[edge.SecondVertexIndex].Position;
                    Point3d M = oSpringMesh.Vertices[edge.FirstAdjacentVertexIndex].Position;
                    Point3d N = oSpringMesh.Vertices[edge.SecondAdjacentVertexIndex].Position;

                    if (Vector3d.CrossProduct(B - A, M - A) * oSpringMesh.ComputeTriangleNormal(edge.FirstAdjacentVertexIndex) < 0.0)
                    {
                        int temp = edge.FirstAdjacentVertexIndex;
                        edge.FirstAdjacentVertexIndex  = edge.SecondAdjacentVertexIndex;
                        edge.SecondAdjacentVertexIndex = temp;

                        temp = edge.FirstTriangleIndex;
                        edge.FirstTriangleIndex  = edge.SecondTriangleIndex;
                        edge.SecondTriangleIndex = temp;
                    }
                }
            }

            // ===========================================================================================
            // Compute adjacent vertex index for each triangle
            // ===========================================================================================

            //foreach (Triangle triangle in oSpringMesh.Triangles)
            //{
            //    Vertex firstVertex = oSpringMesh.Vertices[triangle.FirstVertexIndex];
            //    Vertex secondVertex = oSpringMesh.Vertices[triangle.SecondVertexIndex];
            //    Vertex thirdVertex = oSpringMesh.Vertices[triangle.ThirdVertexIndex];

            //    foreach (int firstNeighbourIndex in firstVertex.NeighborVertexIndices)
            //        foreach (int secondNeighbourIndex in secondVertex.NeighborVertexIndices)
            //            if (firstNeighbourIndex == secondNeighbourIndex && firstNeighbourIndex != triangle.ThirdVertexIndex)
            //                triangle.FirstSecondAdjacentVertexIndex = firstNeighbourIndex;

            //    foreach (int secondNeighbourIndex in secondVertex.NeighborVertexIndices)
            //        foreach (int thirdNeighbourIndex in thirdVertex.NeighborVertexIndices)
            //            if (secondNeighbourIndex == thirdNeighbourIndex && secondNeighbourIndex != triangle.FirstVertexIndex)
            //                triangle.SecondThirdAdjacentVertexIndex = secondNeighbourIndex;

            //    foreach (int thirdNeighbourIndex in thirdVertex.NeighborVertexIndices)
            //        foreach (int firstNeighbourIndex in firstVertex.NeighborVertexIndices)
            //            if (thirdNeighbourIndex == firstNeighbourIndex && thirdNeighbourIndex != triangle.SecondVertexIndex)
            //                triangle.ThirdFirstAdjacentVertexIndex = thirdNeighbourIndex;
            //}


            // ===========================================================================================
            // 3D Boundary Curve
            // ===========================================================================================

            //Brep brep = Brep.CreatePatch(new List<GeometryBase>() { iBoundaryCurve }, null, DocumentTolerance());

            //DA.SetDataList(2, new List<Brep>() { brep });

            foreach (Vertex vertex in oSpringMesh.Vertices)
            {
                if (vertex.IsBoundaryVertex)
                {
                    double t;
                    boundaryCurveXY.ClosestPoint(vertex.Position, out t);
                    Plane frame;
                    boundaryCurveXY.PerpendicularFrameAt(t, out frame);

                    CurveIntersections curveInteresections = Intersection.CurvePlane(iBoundaryCurve, frame, DocumentTolerance());

                    Point3d intersection = Point3d.Unset;
                    double  minDist      = 999999.0;

                    for (int i = 0; i < curveInteresections.Count; i++)
                    {
                        double d = vertex.Position.DistanceTo(curveInteresections[i].PointA);
                        if (d < minDist)
                        {
                            minDist      = d;
                            intersection = curveInteresections[i].PointA;
                        }
                    }

                    vertex.Position = intersection;
                }
                else
                {
                    //LineCurve lineCurve = new LineCurve(
                    //    new Point3d(vertex.Position.X, vertex.Position.Y, vertex.Position.Z - 10.0),
                    //    new Point3d(vertex.Position.X, vertex.Position.Y, vertex.Position.Z + 10.0)
                    //    );

                    //Curve[] overlapCurves;
                    //Point3d[] intersectionPoints;
                    //Intersection.CurveBrep(lineCurve, brep, DocumentTolerance(), out overlapCurves, out intersectionPoints);

                    //if (intersectionPoints.Length > 0)
                    //    vertex.Position = intersectionPoints[0];
                }
            }

            // ===========================================================================================
            // Initial curving bias
            // ===========================================================================================

            DA.GetData <double>("Initial Curving Bias", ref iInitialCurvingBias);
            DA.GetData <bool>("Bias Apical Regions", ref iBiasApicalRegion);

            foreach (Vertex vertex in oSpringMesh.Vertices)
            {
                if (vertex.IsBoundaryVertex || vertex.IsFixed)
                {
                    continue;
                }
                vertex.Position.Z = computeBiasHeight(vertex.Position, iBiasApicalRegion, boundaryCurveXY);
            }


            // ===========================================================================================
            // Conclusion
            // ===========================================================================================

            foreach (Edge edge in oSpringMesh.Edges)
            {
                oDebugCurves1.Add(new LineCurve(oSpringMesh.Vertices[edge.FirstVertexIndex].Position, oSpringMesh.Vertices[edge.SecondVertexIndex].Position));
            }

            DA.SetData(0, oInfo);
            DA.SetDataList(1, oDebugCurves1);
            DA.SetData(6, oSpringMesh);
        }