public List <Line> SubdivideThreeLines(SpringMesh sMesh, double factor)
        {
            List <Line> allLines = new List <Line>();

            foreach (Edge edge in sMesh.Edges)
            {
                if (edge.SecondTriangleIndex >= 0)
                {
                    int triangle1 = edge.FirstTriangleIndex;
                    int triangle2 = edge.SecondTriangleIndex;

                    //Point3d centreTri1 = sMesh.ComputeTriangleCenter(triangle1);
                    //Point3d centreTri2 = sMesh.ComputeTriangleCenter(triangle2);
                    Point3d centreTri1 = sMesh.ComputeCircumscribedCircleCenter(triangle1);
                    Point3d centreTri2 = sMesh.ComputeCircumscribedCircleCenter(triangle2);

                    List <Point3d> pointOnTri1 = sMesh.ComputeTriangleThreePts(triangle1, factor);
                    List <Point3d> pointOnTri2 = sMesh.ComputeTriangleThreePts(triangle2, factor);

                    foreach (Point3d IntPtr in pointOnTri1)
                    {
                        allLines.Add(new Line(centreTri1, IntPtr));
                    }
                    foreach (Point3d IntPtr in pointOnTri2)
                    {
                        allLines.Add(new Line(centreTri2, IntPtr));
                    }
                }
            }

            return(allLines);
        }
Exemplo n.º 2
0
        /// <summary>
        /// This is the method that actually does the work.
        /// </summary>
        /// <param name="DA">The DA object is used to retrieve from inputs and store in outputs.</param>
        protected override void SolveInstance(IGH_DataAccess DA)
        {
            sMesh = null;
            DA.GetData <SpringMesh>(0, ref sMesh);

            factor = 0;
            DA.GetData <double>(1, ref factor);

            thickness = 0;
            DA.GetData <double>(2, ref thickness);

            List <Line> lines = SubdivideThreeLines(sMesh, factor);

            DA.SetDataList(0, lines);


            List <Curve> curveRight = new List <Curve>();
            List <Curve> curveLeft  = new List <Curve>();

            vertexFactors = ComputeVertexFactor(sMesh);
            CalculateSurface(sMesh, thickness, curveRight, curveLeft);

            DA.SetDataList(1, curveRight);
            DA.SetDataList(2, curveLeft);

            List <Line> linesUp   = new List <Line>();
            List <Line> linesDown = new List <Line>();

            List <double> planarity = checkCoplanarity(sMesh, thickness, linesUp, linesDown);

            DA.SetDataList(3, planarity);
            DA.SetDataList(4, linesUp);
            DA.SetDataList(5, linesDown);
        }
        protected override void BeforeSolveInstance()
        {
            // input

            iSpringMesh   = new SpringMesh();
            iPolyLine     = new List <Curve>();
            iVertexStatus = new List <bool>(); // true is plate occupied, false should put triLoop
            iPolyLineID   = new List <int>();  // for vertex status access the order of polyline
            iThickness    = new List <double>();

            // output
            oInfo      = string.Empty;
            oDebugList = new List <Point3d>();
            oTriLoop   = new List <Brep>();
            oDualLoop  = new List <Brep>();

            // internal use data
            topCenterPts             = new List <Point3d>();
            bottomCenterPts          = new List <Point3d>();
            topCenterPolygonOccupied = new List <bool>(); // not use at this moment

            bottomCps = new List <Point3d>();
            topCps    = new List <Point3d>();

            indexSortPolygon = new List <int[]>();
        }
        protected override void SolveInstance(IGH_DataAccess DA)
        {
            SpringMesh iSpringMesh = null;

            DA.GetData <SpringMesh>("Spring Mesh", ref iSpringMesh);

            DA.SetData("Rhino Mesh", iSpringMesh.ConvertToRhinoMesh());
        }
Exemplo n.º 5
0
        public List <double> ComputeVertexFactor(SpringMesh sMesh)
        {
            List <double> vertexFactors = new List <double>();

            for (int i = 0; i < sMesh.Vertices.Count; i++)
            {
                vertexFactors.Add(0.5);
            }

            return(vertexFactors);
        }
Exemplo n.º 6
0
        protected override void BeforeSolveInstance()
        {
            // input
            iID = new List <int>();
            iAttrThicknessPts = new List <Point3d>();
            iClosedPanelPts   = new List <Point3d>();

            // output
            oInfo         = string.Empty;
            oDebugList    = new List <Curve>();
            oSMeshLine    = new List <Curve>();
            oSpringMesh   = new SpringMesh();
            oPolyLine     = new List <Curve>();
            oVertexStatus = new List <bool>(); // true is plate occupied, false should put triLoop
            oPolyLineID   = new List <int>();  // for vertex status access the order of polyline
            othickness    = new List <double>();
            oVertexPanel2 = new List <bool>();

            // internal use data
        }
        private List <double> checkCoplanarity(SpringMesh sMesh, double thickness, List <Line> linesUp, List <Line> linesDown)
        {
            List <double> coplanarity = new List <double>();

            foreach (Edge edge in sMesh.Edges)
            {
                if (edge.SecondTriangleIndex >= 0)
                {
                    int triLeft  = edge.FirstTriangleIndex;
                    int triRight = edge.SecondTriangleIndex;

                    Point3d centreLeftO  = sMesh.ComputeTriangleCentroid(triLeft);
                    Point3d centreRightO = sMesh.ComputeTriangleCentroid(triRight);

                    Point3d centreLeft  = sMesh.ComputeTPI(triLeft);
                    Point3d centreRight = sMesh.ComputeTPI(triRight);

                    if (ICD.Utils.Distance(centreLeftO, centreLeft) < iMaxThickness && ICD.Utils.Distance(centreRightO, centreRight) < iMaxThickness)
                    {
                        Vector3d normalLeft  = sMesh.ComputeTriangleNormal(triLeft);
                        Vector3d normalRight = sMesh.ComputeTriangleNormal(triRight);

                        Point3d centreLeftUp  = centreLeft + normalLeft * thickness;
                        Point3d centreRightUp = centreRight + normalRight * thickness;

                        Point3d centreLeftDown  = centreLeft - normalLeft * thickness;
                        Point3d centreRightDown = centreRight - normalRight * thickness;

                        linesUp.Add(new Line(centreLeftUp, centreRightUp));
                        linesDown.Add(new Line(centreLeftDown, centreRightDown));

                        Line planarCheckLine01 = new Line(centreLeftUp, centreRightDown);
                        Line planarCheckLine02 = new Line(centreRightUp, centreLeftDown);

                        double dist = planarCheckLine01.MinimumDistanceTo(planarCheckLine02);
                        coplanarity.Add(dist);
                    }
                }
            }
            return(coplanarity);
        }
Exemplo n.º 8
0
        public SpringMesh(SpringMesh springMesh)
        {
            Vertices = new List <Vertex>();
            foreach (Vertex vertex in springMesh.Vertices)
            {
                Vertices.Add(new Vertex(vertex));
            }

            Edges = new List <Edge>();
            foreach (Edge edge in springMesh.Edges)
            {
                Edges.Add(new Edge(edge));
            }

            Triangles = new List <Triangle>();
            foreach (Triangle triangle in springMesh.Triangles)
            {
                Triangles.Add(new Triangle(triangle));
            }

            iteration = 0;
        }
Exemplo n.º 9
0
        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>("Fixed Point Threshold", ref iFixedPointThreshold);
            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();

            // 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;
                iBoundaryCurve.ClosestPoint(M, out t);
                Point3d N = iBoundaryCurve.PointAt(t);
                if (Vector3d.CrossProduct(iBoundaryCurve.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;
                iBoundaryCurve.ClosestPoint(p, out t);

                bool vertexFixedness = true;

                if (Utils.Distance(p, iBoundaryCurve.PointAt(t)) > iFixedPointThreshold)
                {
                    vertexFixedness = false;
                }
                else
                {
                    foreach (Curve curve in iFixedPointExclusion)
                    {
                        if (curve.Contains(p) == PointContainment.Inside)
                        {
                            vertexFixedness = false;
                            break;
                        }
                    }
                }

                foreach (Curve curve in iFixedPointInclusion)
                {
                    if (curve.Contains(p) == PointContainment.Inside)
                    {
                        vertexFixedness = true;
                        break;
                    }
                }

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


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

            foreach (Edge edge in oSpringMesh.Edges)
            {
                if (oSpringMesh.Vertices[edge.FirstVertexIndex].IsFixed && oSpringMesh.Vertices[edge.SecondVertexIndex].IsFixed)
                {
                    edge.IsBoundaryEdge = 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;
            //}


            // ===========================================================================================
            // 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)
            {
                vertex.Position.Z = computeBiasHeight(vertex.Position, iBiasApicalRegion);
            }


            // ===========================================================================================
            // 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);
        }
        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];
                    //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 = (firstPtVertex.Factor - 0.2) * firstPtVertex.Position + (1 - firstPtVertex.Factor + 0.2) * firstTriCentreRight;

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

                    Point3d firstCPt03Right = firstPtVertex.Factor * firstPtVertex.Position + (1 - firstPtVertex.Factor) * 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 = (firstPtVertex.Factor - 0.2) * firstPtVertex.Position + (1 - firstPtVertex.Factor + 0.2) * firstTriCentreLeft;

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

                    Point3d firstCPt03Left = firstPtVertex.Factor * firstPtVertex.Position + (1 - firstPtVertex.Factor) * 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];
                    //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 = (secondPtVertex.Factor - 0.2) * secondPtVertex.Position + (1 - secondPtVertex.Factor + 0.2) * secondTriCentreRight;

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

                    Point3d secondCPt03Right = secondPtVertex.Factor * secondPtVertex.Position + (1 - secondPtVertex.Factor) * 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 = (secondPtVertex.Factor - 0.2) * secondPtVertex.Position + (1 - secondPtVertex.Factor + 0.2) * secondTriCentreLeft;

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

                    Point3d secondCPt03Left = secondPtVertex.Factor * secondPtVertex.Position + (1 - secondPtVertex.Factor) * 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)
        {
            // ==================================================================================
            // Reset
            // ==================================================================================

            DA.GetData <bool>("Reset", ref iReset);

            if (iReset)
            {
                iteration = 0;

                DA.GetData <SpringMesh>("Spring Mesh", ref iSpringMesh);
                oSpringMesh = new SpringMesh(iSpringMesh);

                DA.GetData <int>(1, ref iIntegrator);
                oSpringMesh.Integrator = iIntegrator;

                goto Conclusion;
            }

            DA.GetData <bool>("Play", ref iPlay);
            if (!iPlay)
            {
                goto Conclusion;
            }
            if ((iIterationCount != 0) && (iteration >= iIterationCount))
            {
                goto Conclusion;
            }
            iteration++;


            // ==================================================================================
            // Update the mesh
            // ==================================================================================

            DA.GetData <double>("Damping", ref iDamping);
            oSpringMesh.Damping = iDamping;

            DA.GetData <double>("Time Step", ref iTimeStep);
            oSpringMesh.DeltaT = iTimeStep;

            DA.GetData <double>("Gravity Scale", ref iGravityScale);
            oSpringMesh.GravityScale = iGravityScale;

            DA.GetData <double>("Rest Length Scale", ref iRestLengthScale);
            oSpringMesh.RestLengthScale = iRestLengthScale;

            DA.GetData <double>("Rest Length Offset", ref iRestLengthOffset);
            oSpringMesh.RestLengthOffset = iRestLengthOffset;

            DA.GetData <double>("Stiffness Offset", ref iStiffnessOffset);
            oSpringMesh.Stiffness = iStiffnessOffset;

            DA.GetData <double>("Bending Stiffness Offset", ref iBendingStiffness);
            oSpringMesh.BendingStiffness = iBendingStiffness;

            DA.GetData <bool>("Enable Boundary Bending Stiffness", ref iEnableBendingStiffnessOffset);
            oSpringMesh.EnableBoundaryBendingStiffness = iEnableBendingStiffnessOffset;

            DA.GetData <double>("Boundary Bending Stiffness", ref iBoundaryBendingStiffness);
            oSpringMesh.BoundaryBendingStiffness = iBoundaryBendingStiffness;

            DA.GetData <bool>("Enable Column Bending Stiffness", ref iEnableColumnStiffnessOffset);
            oSpringMesh.EnableColumnBendingStiffness = iEnableColumnStiffnessOffset;

            DA.GetData <double>("Column Bending Stiffness", ref iColumnBendingStiffness);
            oSpringMesh.ColumnnBendingStiffness = iColumnBendingStiffness;

            // Added by Gene   ================================================================
            DA.GetData <int>("Enable Equilateral Triangle", ref iEnableEquilateralTriangle);
            oSpringMesh.EnableEquilateralTriangle = iEnableEquilateralTriangle;

            DA.GetData <double>("Equilateral Strength", ref iEquilateralStrength);
            oSpringMesh.EquilateralStrength = iEquilateralStrength;
            // ================================================================================


            oSpringMesh.Update();


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

Conclusion:

            DA.GetData <int>("Iteration Count", ref iIterationCount);
            if (iPlay && (iteration < iIterationCount || iIterationCount == 0))
            {
                ExpireSolution(true);
            }

            oInfo += "Iteration: " + iteration.ToString();

            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.SetDataList(2, new List<Mesh> { oSpringMesh.ConvertToRhinoMesh() });
            DA.SetData(6, oSpringMesh);
        }
        protected override void SolveInstance(IGH_DataAccess DA)
        {
            Mesh iRhinoMesh = null;

            DA.GetData <Mesh>(0, ref iRhinoMesh);

            SpringMesh oSpringMesh = new SpringMesh();

            bool [] naked = iRhinoMesh.GetNakedEdgePointStatus();

            for (int i = 0; i < iRhinoMesh.Vertices.Count; i++)
            {
                Point3d vertex = iRhinoMesh.Vertices[i];
                oSpringMesh.Vertices.Add(new Vertex(vertex, Vector3d.Zero, new List <int>()));

                // boundary and fixed condition
                if (naked[i] == true)
                {
                    oSpringMesh.Vertices[i].IsBoundaryVertex = true;
                    oSpringMesh.Vertices[i].IsFixed          = true;
                }

                // vertex neighbours
                int   topoIndex    = iRhinoMesh.TopologyVertices.TopologyVertexIndex(i);
                int[] connectIndex = iRhinoMesh.TopologyVertices.ConnectedTopologyVertices(topoIndex);
                for (int j = 0; j < connectIndex.Length; j++)
                {
                    oSpringMesh.Vertices[i].NeighborVertexIndices.Add(iRhinoMesh.TopologyVertices.MeshVertexIndices(connectIndex[j])[0]);
                }
            }

            foreach (MeshFace face in iRhinoMesh.Faces)
            {
                oSpringMesh.Triangles.Add(new Triangle(face.A, face.B, face.C));
            }

            for (int i = 0; i < iRhinoMesh.TopologyEdges.Count; i++)
            {
                IndexPair indexPair = iRhinoMesh.TopologyEdges.GetTopologyVertices(i);
                // should convert TopologyVertices to mesh vertices first
                int firstIndex  = iRhinoMesh.TopologyVertices.MeshVertexIndices(indexPair.I)[0];
                int secondIndex = iRhinoMesh.TopologyVertices.MeshVertexIndices(indexPair.J)[0];

                double len = iRhinoMesh.TopologyEdges.EdgeLine(i).Length;

                oSpringMesh.Edges.Add(new Edge(firstIndex, secondIndex, len, 1.0, Math.PI * 0.8, 0.0));

                // edge vertex
                oSpringMesh.Edges[i].FirstVertexIndex  = firstIndex;
                oSpringMesh.Edges[i].SecondVertexIndex = secondIndex;
            }

            for (int i = 0; i < iRhinoMesh.TopologyEdges.Count; i++)
            {
                // connected faces
                int[] connectedFacesIndex = iRhinoMesh.TopologyEdges.GetConnectedFaces(i);
                int   firstTriIndex       = -1;
                int   secondTriIndex      = -1;

                IndexPair indexPair   = iRhinoMesh.TopologyEdges.GetTopologyVertices(i);
                int       firstIndex  = iRhinoMesh.TopologyVertices.MeshVertexIndices(indexPair.I)[0];
                int       secondIndex = iRhinoMesh.TopologyVertices.MeshVertexIndices(indexPair.J)[0];

                if (connectedFacesIndex.Length == 2)
                {
                    firstTriIndex = connectedFacesIndex[0];
                    oSpringMesh.Edges[i].FirstTriangleIndex = firstTriIndex;
                    secondTriIndex = connectedFacesIndex[1];
                    oSpringMesh.Edges[i].SecondTriangleIndex = secondTriIndex;

                    int triangleAdj01 = 0;
                    int triangleAdj02 = 0;
                    int vertex01      = oSpringMesh.Triangles[firstTriIndex].FirstVertexIndex;
                    int vertex02      = oSpringMesh.Triangles[firstTriIndex].SecondVertexIndex;
                    int vertex03      = oSpringMesh.Triangles[firstTriIndex].ThirdVertexIndex;
                    int vertex11      = oSpringMesh.Triangles[secondTriIndex].FirstVertexIndex;
                    int vertex12      = oSpringMesh.Triangles[secondTriIndex].SecondVertexIndex;
                    int vertex13      = oSpringMesh.Triangles[secondTriIndex].ThirdVertexIndex;

                    int[] triangleVertexList01 = { vertex01, vertex02, vertex03 };
                    int[] triangleVertexList02 = { vertex11, vertex12, vertex13 };

                    for (int j = 0; j < triangleVertexList01.Length; j++)
                    {
                        if (triangleVertexList01[j] != firstIndex && triangleVertexList01[j] != secondIndex)
                        {
                            triangleAdj01 = triangleVertexList01[j];
                        }
                    }
                    for (int j = 0; j < triangleVertexList02.Length; j++)
                    {
                        if (triangleVertexList02[j] != firstIndex && triangleVertexList02[j] != secondIndex)
                        {
                            triangleAdj02 = triangleVertexList02[j];
                        }
                    }

                    oSpringMesh.Edges[i].FirstAdjacentVertexIndex  = triangleAdj01;
                    oSpringMesh.Edges[i].SecondAdjacentVertexIndex = triangleAdj02;

                    oSpringMesh.Edges[i].IsBoundaryEdge = false;
                }
                if (connectedFacesIndex.Length == 1)
                {
                    firstTriIndex = connectedFacesIndex[0];
                    oSpringMesh.Edges[i].FirstTriangleIndex = firstTriIndex;

                    int triangleAdj01 = 0;
                    int vertex01      = oSpringMesh.Triangles[firstTriIndex].FirstVertexIndex;
                    int vertex02      = oSpringMesh.Triangles[firstTriIndex].SecondVertexIndex;
                    int vertex03      = oSpringMesh.Triangles[firstTriIndex].ThirdVertexIndex;

                    int[] triangleVertexList01 = { vertex01, vertex02, vertex03 };

                    for (int j = 0; j < triangleVertexList01.Length; j++)
                    {
                        if (triangleVertexList01[j] != firstIndex && triangleVertexList01[j] != secondTriIndex)
                        {
                            triangleAdj01 = triangleVertexList01[j];
                        }
                    }

                    oSpringMesh.Edges[i].FirstAdjacentVertexIndex = triangleAdj01;

                    oSpringMesh.Edges[i].IsBoundaryEdge = true;
                }
            }

            DA.SetData(1, oSpringMesh);


            List <LineCurve> oDebugCurves = new List <LineCurve>();

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

            DA.SetDataList(0, oDebugCurves);
        }