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                   = new SpringMesh();
            List <Circle> iCircles                      = new List <Circle>();
            double        iBendingStiffness             = double.NaN;
            double        iStiffness                    = double.NaN;
            List <double> iPlanarRegionBendingStiffness = new List <double>();
            List <double> iPlanarRegionStiffness        = new List <double>();

            DA.GetData <SpringMesh>(0, ref iSpringMesh);
            DA.GetDataList <Circle>(1, iCircles);
            DA.GetData <double>(2, ref iBendingStiffness);
            DA.GetData <double>(3, ref iStiffness);
            DA.GetDataList <double>(4, iPlanarRegionBendingStiffness);
            DA.GetDataList <double>(5, iPlanarRegionStiffness);

            SpringMesh oSpringMesh = new SpringMesh(iSpringMesh);

            foreach (Edge edge in iSpringMesh.Edges)
            {
                edge.RestLength = Utils.Distance(oSpringMesh.Vertices[edge.FirstVertexIndex].Position, oSpringMesh.Vertices[edge.SecondVertexIndex].Position);
                edge.Stiffness  = iStiffness;
                if (edge.SecondTriangleIndex >= 0)
                {
                    edge.RestAngle = Utils.AngleBetweenTwoTriangles(
                        iSpringMesh.Vertices[edge.FirstVertexIndex].Position,
                        iSpringMesh.Vertices[edge.SecondVertexIndex].Position,
                        iSpringMesh.Vertices[edge.FirstAdjacentVertexIndex].Position,
                        iSpringMesh.Vertices[edge.SecondAdjacentVertexIndex].Position
                        );
                }
                edge.BendingStiffness = iBendingStiffness;
            }

            for (int i = 0; i < oSpringMesh.Vertices.Count; i++)
            {
                for (int j = 0; j < iCircles.Count; j++)
                {
                    if (Utils.Distance(iCircles[j].Center, oSpringMesh.Vertices[i].Position) <= iCircles[j].Radius)
                    {
                        foreach (Edge edge in oSpringMesh.Edges)
                        {
                            if (edge.FirstVertexIndex == i || edge.SecondVertexIndex == i)
                            {
                                edge.Stiffness        = iPlanarRegionStiffness[j];
                                edge.RestAngle        = Math.PI;
                                edge.BendingStiffness = iPlanarRegionBendingStiffness[j];
                            }
                        }
                        break;
                    }
                }
            }
            DA.SetData(0, oSpringMesh);
        }
        protected override void SolveInstance(IGH_DataAccess DA)
        {
            SpringMesh iSpringMesh = new SpringMesh();
            List<Circle> iCircles = new List<Circle>();
            double iBendingStiffness = double.NaN;
            double iStiffness = double.NaN;
            List<double> iPlanarRegionBendingStiffness = new List<double>();
            List<double> iPlanarRegionStiffness = new List<double>();

            DA.GetData<SpringMesh>(0, ref iSpringMesh);
            DA.GetDataList<Circle>(1, iCircles);
            DA.GetData<double>(2, ref iBendingStiffness);
            DA.GetData<double>(3, ref iStiffness);
            DA.GetDataList<double>(4, iPlanarRegionBendingStiffness);
            DA.GetDataList<double>(5, iPlanarRegionStiffness);

            SpringMesh oSpringMesh = new SpringMesh(iSpringMesh);

            foreach (Edge edge in iSpringMesh.Edges)
            {
                edge.RestLength = Utils.Distance(oSpringMesh.Vertices[edge.FirstVertexIndex].Position, oSpringMesh.Vertices[edge.SecondVertexIndex].Position);
                edge.Stiffness = iStiffness;
                if (edge.SecondTriangleIndex >= 0)
                {
                    edge.RestAngle = Utils.AngleBetweenTwoTriangles(
                        iSpringMesh.Vertices[edge.FirstVertexIndex].Position,
                        iSpringMesh.Vertices[edge.SecondVertexIndex].Position,
                        iSpringMesh.Vertices[edge.FirstAdjacentVertexIndex].Position,
                        iSpringMesh.Vertices[edge.SecondAdjacentVertexIndex].Position
                        );
                }
                edge.BendingStiffness = iBendingStiffness;
            }

            for (int i = 0; i < oSpringMesh.Vertices.Count; i++)
                for (int j = 0; j < iCircles.Count; j++ )
                    if (Utils.Distance(iCircles[j].Center, oSpringMesh.Vertices[i].Position) <= iCircles[j].Radius)
                    {
                        foreach (Edge edge in oSpringMesh.Edges)
                            if (edge.FirstVertexIndex == i || edge.SecondVertexIndex == i)
                            {
                                edge.Stiffness = iPlanarRegionStiffness[j];
                                edge.RestAngle = Math.PI;
                                edge.BendingStiffness = iPlanarRegionBendingStiffness[j];
                            }
                        break;
                    }
            DA.SetData(0, oSpringMesh);
        }
        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
        }
        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;
        }
        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;
        }
        public 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 centreLeft = sMesh.ComputeTriangleCenter(triLeft);
                    //Point3d centreRight = sMesh.ComputeTriangleCenter(triRight);

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

                    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;
        }
        /// <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);
        }
        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;
        }
        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 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>();
            iAttractors = new List<Point3d>();
            iVertexPanel2 = new List<bool>();
            //ManualValueTree = new GH_Structure<GH_Number>();

            // output
            oInfo = string.Empty;
            oDebugList = new List<Vector3d>();
            oTriLoop = new DataTree<Brep>();
            oTriLoopID = new DataTree<string>();
            oTriLoopCurves = new DataTree<Curve>();
            oDualLoop1 = new DataTree<Brep>();
            oDualLoop2 = new DataTree<Brep>();
            oDualLoop1ID = new DataTree<string>();
            oDualLoop2ID = new DataTree<string>();
            oDualLoop1Curves = new DataTree<Curve>();
            oDualLoop2Curves = new DataTree<Curve>();
            oClosedPanel = new DataTree<Brep>();
            oTriLoopPlanCrv = new DataTree<Curve>();
            oTriLoopEffectorHoles = new DataTree<Point3d>();

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

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

            indexSortPolygon = new List<int[]>();   // array is reference type in csharp

            verticesValues = new List<double>();
            curveVerticesValues = new List<double>();
            planarVerticesValues = new List<double>();
            openingWidthVerticesValues = new List<double>();
            pointinessValues = new List<double>();
            ManualAdjustedVertexIndexies = new List<int>();
        }
        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);
        }