コード例 #1
0
        protected override void SolveInstance(IGH_DataAccess DA)
        {
            try {
                ////////////////////////////////////////////////////////////////////
                //Inputs Grasshopper
                Mesh M = DA.Fetch <Mesh>("Mesh");
                DataTree <Polyline> PanelOutlines = DA.FetchTree <GH_Curve>("Panels").ToPolylineDT();
                DataTree <Vector3d> EVec          = DA.FetchTree <GH_Vector>("EdgeVectors").ToDT();
                int    D      = DA.Fetch <int>("JointDiv");
                double L      = DA.Fetch <double>("JointLen");
                double H      = DA.Fetch <double>("JointHei");
                double W      = DA.Fetch <double>("JointThi");
                bool   Center = DA.Fetch <bool>("Center");
                bool   Finger = DA.Fetch <bool>("Finger");
                double Custom = DA.Fetch <double>("Custom");
                DataTree <Polyline> CChamfer = new DataTree <Polyline>();
                int           iterations     = DA.Fetch <int>("Iterations");
                List <int>    sequence       = DA.FetchList <int>("Sequence");
                List <double> textSize       = DA.FetchList <double>("TextScale");

                if (textSize.Count < 6)
                {
                    textSize = new List <double> {
                        20, 10, 10, 0.5, 0.75, 10
                    }
                }
                ;

                DataTree <Panel> PanelGroups = DA.FetchTree <GH_Curve>("Panels").ToPanelsDT();
                DataTree <Panel> JointGroups = new DataTree <Panel>();
                ////////////////////////////////////////////////////////////////////


                ////////////////////////////////////////////////////////////////////
                //Inputs Local
                int    divisions   = Math.Max(1, D);
                double jointLength = L;//Math.Max(0.1, L);
                double height      = Math.Max(0.1, H);
                double width       = Math.Max(0.1, W);

                int[][]                 tv      = M.GetNGonsTopoBoundaries();
                int[][]                 fe      = M.GetNGonFacesEdges(tv);
                HashSet <int>           e       = M.GetAllNGonEdges(tv);
                Dictionary <int, int[]> efDict  = M.GetFE(e, false);
                Point3d[]               centers = M.GetNGonCenters();
                ////////////////////////////////////////////////////////////////////

                ////////////////////////////////////////////////////////////////////
                //      Insertion vectors
                DataTree <Vector3d> EV = M.insertionVectors(Center, EVec);
                ////////////////////////////////////////////////////////////////////

                DataTree <Polyline> diagonalConnections = new DataTree <Polyline>();
                //DataTree<Polyline> recJoints = new DataTree<Polyline>();

                //Iterate insertion edges
                Dictionary <int, int> meshEdgeDict = new Dictionary <int, int>();
                for (int i = 0; i < EV.BranchCount; i++)  // EV.BranchCount


                {
                    int meshEdge = EV.Path(i).Indices[0];//mesh edge is used as dataTree branch

                    meshEdgeDict.Add(meshEdge, i);

                    if (efDict[meshEdge].Length != 2)
                    {
                        continue;
                    }
                    int f0 = efDict[meshEdge][0];
                    int f1 = efDict[meshEdge][1];

                    //Divide line into points and create a planes on these point, following insertion direction and average face normal
                    Point3d[] pts = M.TopologyEdges.EdgeLine(meshEdge).InterpolateLine(divisions, false);

                    for (int j = 0; j < pts.Length; j++)
                    {
                        JointGroups.Add(new Panel(new Plane(pts[j], EV.Branch(EV.Path(i))[0].UnitVector(), M.GetMeshEdgePerpDir(meshEdge))), EV.Path(i));
                    }


                    //Construct joint outlines from planes
                    //Iterate number of joints per edge
                    for (int j = 0; j < pts.Length; j++)
                    {
                        JointGroups.Branch(EV.Path(i))[j].planeOffset0    = JointGroups.Branch(EV.Path(i))[j].plane.MovePlanebyAxis(W * 0.5);         //offset planes
                        JointGroups.Branch(EV.Path(i))[j].planeOffset1    = JointGroups.Branch(EV.Path(i))[j].plane.MovePlanebyAxis(-W * 0.5);        //offset planes
                        JointGroups.Branch(EV.Path(i))[j].planeRot        = new Plane(pts[j], Vector3d.CrossProduct(EV.Branch(EV.Path(i))[0].UnitVector(), M.GetMeshEdgePerpDir(meshEdge)), M.GetMeshEdgePerpDir(meshEdge));
                        JointGroups.Branch(EV.Path(i))[j].planeRotOffset0 = JointGroups.Branch(EV.Path(i))[j].planeRot.MovePlanebyAxis(jointLength);  //offset planes
                        JointGroups.Branch(EV.Path(i))[j].planeRotOffset1 = JointGroups.Branch(EV.Path(i))[j].planeRot.MovePlanebyAxis(-jointLength); //offset plane
                        JointGroups.Branch(EV.Path(i))[j].planeEdge       = new Plane(pts[j], M.TopologyEdges.EdgeLine(meshEdge).Direction, M.GetMeshEdgePerpDir(meshEdge));

                        List <Plane> planesF0 = new List <Plane>();
                        List <Plane> planesF1 = new List <Plane>();
                        for (int k = 0; k < PanelGroups.Branch(f0).Count; k++)
                        {
                            planesF0.Add(PanelGroups.Branch(f0)[k].plane);
                            planesF1.Add(PanelGroups.Branch(f1)[k].plane);
                        }



                        JointGroups.Branch(EV.Path(i))[j].planeF0 = PlaneUtil.AveragePlaneOrigin(planesF0);
                        JointGroups.Branch(EV.Path(i))[j].planeF1 = PlaneUtil.AveragePlaneOrigin(planesF1);

                        List <Plane> jointPlaneLoop = new List <Plane> {
                            JointGroups.Branch(EV.Path(i))[j].planeRotOffset0,
                            JointGroups.Branch(EV.Path(i))[j].planeF0.MovePlanebyAxis(height),
                            JointGroups.Branch(EV.Path(i))[j].planeEdge,
                            JointGroups.Branch(EV.Path(i))[j].planeF1.MovePlanebyAxis(height),  //3
                            JointGroups.Branch(EV.Path(i))[j].planeRotOffset1,
                            JointGroups.Branch(EV.Path(i))[j].planeF1.MovePlanebyAxis(-height), //5
                            JointGroups.Branch(EV.Path(i))[j].planeEdge,
                            JointGroups.Branch(EV.Path(i))[j].planeF0.MovePlanebyAxis(-height),
                        };

                        //Rhino.RhinoDoc.ActiveDoc.Objects.AddRectangle(new Rectangle3d(JointGroups.Branch(EV.Path(i))[j].planeF1, new Interval(-20, 20), new Interval(-20, 20)));
                        //Rhino.RhinoDoc.ActiveDoc.Objects.AddRectangle(new Rectangle3d(JointGroups.Branch(EV.Path(i))[j].planeF1, new Interval(-20, 20), new Interval(-20, 20)));

                        JointGroups.Branch(EV.Path(i))[j].contourNoJoints[0] = PolylineUtil.PolylineFromPlanes(JointGroups.Branch(EV.Path(i))[j].planeOffset0, jointPlaneLoop);
                        JointGroups.Branch(EV.Path(i))[j].contourNoJoints[1] = PolylineUtil.PolylineFromPlanes(JointGroups.Branch(EV.Path(i))[j].planeOffset1, jointPlaneLoop);
                        JointGroups.Branch(EV.Path(i))[j].contour[0]         = new Polyline(JointGroups.Branch(EV.Path(i))[j].contourNoJoints[0]);
                        JointGroups.Branch(EV.Path(i))[j].contour[1]         = new Polyline(JointGroups.Branch(EV.Path(i))[j].contourNoJoints[1]);
                    }


                    //Construct Cuts
                    //Iterate number of joints per edge
                    for (int j = 0; j < pts.Length; j++)
                    {
                        int localMeshEdgeF0 = Array.IndexOf(fe[f0], meshEdge);
                        int localMeshEdgeF1 = Array.IndexOf(fe[f1], meshEdge);



                        //Iterate number of panels and create cuts
                        for (int k = 0; k < PanelGroups.Branch(f0).Count; k++)
                        {
                            Panel jointPanel = JointGroups.Branch(EV.Path(i))[j];

                            jointPanel.id = f0.ToString() + "-" + f1.ToString();

                            //if(f0==f1)
                            //  Rhino.RhinoApp.WriteLine(jointPanel.id);

                            if (pts.Length > 1)
                            {
                                jointPanel.id += "-" + j.ToString();
                            }

                            bool flag = f0 == 165 && f1 == 166;
                            PanelGroups.Branch(f0)[k].CreateCut(localMeshEdgeF0, JointGroups.Branch(EV.Path(i))[j].planeOffset0, JointGroups.Branch(EV.Path(i))[j].planeOffset1, jointLength, ref jointPanel, flag); //, ref neiPanel, ref jointPanel);
                            PanelGroups.Branch(f1)[k].CreateCut(localMeshEdgeF1, JointGroups.Branch(EV.Path(i))[j].planeOffset0, JointGroups.Branch(EV.Path(i))[j].planeOffset1, jointLength, ref jointPanel, flag); //, ref neiPanel, ref jointPanel);

                            JointGroups.Branch(EV.Path(i))[j] = jointPanel;
                        }
                    }
                }


                for (int i = 0; i < JointGroups.BranchCount; i++)
                {
                    for (int j = 0; j < JointGroups.Branch(i).Count; j++)
                    {
                        if (Custom > 0)
                        {
                            JointGroups.Branch(i)[j].ChangeJoint(Custom, 0);
                        }
                        else if (Custom < 0)
                        {
                            JointGroups.Branch(i)[j].ChangeJoint(Custom, 1, textSize[7]);
                        }
                    }
                }



                ////////////////////////Output
                var dtPlates       = new DataTree <Polyline>();
                var dtJoints       = new DataTree <Polyline>();
                var dtPlatesMid    = new DataTree <Polyline>();
                var dtJointsMid    = new DataTree <Polyline>();
                var dtPlatesPlanes = new DataTree <Plane>();
                var dtJointsPlanes = new DataTree <Plane>();
                var dtPlatesTxt    = new DataTree <Curve>();
                var dtJointsTxt    = new DataTree <Curve>();

                var dtPlatesLast       = new DataTree <Polyline>();
                var dtJointsLast       = new DataTree <Polyline>();
                var dtPlatesMidLast    = new DataTree <Polyline>();
                var dtJointsMidLast    = new DataTree <Polyline>();
                var dtPlatesPlanesLast = new DataTree <Plane>();
                var dtJointsPlanesLast = new DataTree <Plane>();
                var dtPlatesTxtLast    = new DataTree <Curve>();
                var dtJointsTxtLast    = new DataTree <Curve>();

                HashSet <int> jointSequence = new HashSet <int>();

                HashSet <int> jointSequenceLast = new HashSet <int>();
                int           last = Math.Min(iterations, PanelGroups.BranchCount);
                int           prev = Math.Max(0, last - (int)textSize[6]);


                for (int i = 0; i < last; i++)  //Math.Min(iterations, sequence.Count) PanelGroups.BranchCount

                {
                    for (int j = 0; j < fe[i].Length; j++)
                    {
                        bool seq = jointSequence.Add(fe[i][j]);

                        if (i >= prev)
                        {
                            if (seq)
                            {
                                jointSequenceLast.Add(fe[i][j]);
                            }
                        }
                    }

                    for (int j = 0; j < PanelGroups.Branch(i).Count; j++)
                    {
                        dtPlates.Add(PanelGroups.Branch(i)[j].contour[0], new GH_Path(i, j));
                        dtPlates.Add(PanelGroups.Branch(i)[j].contour[1], new GH_Path(i, j));
                        dtPlatesMid.Add(PanelGroups.Branch(i)[j].MidContour(), new GH_Path(i, j));

                        if (i >= prev)
                        {
                            dtPlatesLast.Add(PanelGroups.Branch(i)[j].contour[0], new GH_Path(i, j));
                            dtPlatesLast.Add(PanelGroups.Branch(i)[j].contour[1], new GH_Path(i, j));
                            dtPlatesMidLast.Add(PanelGroups.Branch(i)[j].MidContour(), new GH_Path(i, j));
                        }



                        Plane textPlane = PanelGroups.Branch(i)[j].planeOffset0;
                        textPlane.Flip();

                        if (j == 1)
                        {
                            textPlane = PanelGroups.Branch(i)[j].planeOffset1;
                        }



                        dtPlatesPlanes.Add(textPlane, new GH_Path(i, j));

                        if (i >= prev)
                        {
                            dtPlatesPlanesLast.Add(textPlane, new GH_Path(i, j));
                        }


                        string text   = i.ToString() + "-" + j.ToString();
                        var    txtCrv = Typewriter.Regular.Write(text, textPlane, textSize[0]);
                        dtPlatesTxt.AddRange(txtCrv, new GH_Path(i, j));

                        if (i >= prev)
                        {
                            dtPlatesTxtLast.AddRange(txtCrv, new GH_Path(i, j));
                        }


                        //for(int k = 0; k < PanelGroups.Branch(i)[j].contourNoJoints.Length; k++) {


                        Line[] segments = PanelGroups.Branch(i)[j].contourNoJoints[j].GetSegments();

                        int counter = 0;
                        foreach (Line l in segments)
                        {
                            int meshEdge = fe[i][counter];

                            int neiF = M.GetOppositeNgon(meshEdge, i);


                            //Adjacent face plane
                            Point3d  origin = l.PointAt(textSize[3]);
                            Vector3d xaxis  = l.Direction;
                            Vector3d yaxis  = l.Direction;
                            origin.Transform(Transform.Scale(textPlane.Origin, textSize[4]));
                            yaxis.Rotate(Math.PI * 0.5, textPlane.ZAxis);
                            Plane ePlane = new Plane(origin, xaxis, yaxis);

                            var txtCrvF = Typewriter.Regular.Write(neiF.ToString(), ePlane, textSize[2]);
                            dtPlatesTxt.AddRange(txtCrvF, new GH_Path(i, j));

                            if (i >= prev)
                            {
                                dtPlatesTxtLast.AddRange(txtCrvF, new GH_Path(i, j));
                            }



                            //Mesh edge direction
                            Line meshEdgeLine = M.TopologyEdges.EdgeLine(meshEdge);
                            meshEdgeLine.Transform(Transform.Scale(meshEdgeLine.PointAt(0.5), textSize[4]));
                            meshEdgeLine.Transform(Transform.Scale(textPlane.Origin, textSize[4]));
                            //meshEdgeLine.Extend(-textSize[4], -textSize[4]);


                            Plane e0Plane = new Plane(ePlane.ClosestPoint(meshEdgeLine.From), xaxis, yaxis);
                            Plane e1Plane = new Plane(ePlane.ClosestPoint(meshEdgeLine.To), xaxis, yaxis);

                            var txtCrvF0 = Typewriter.Regular.Write("I", e0Plane, textSize[2]);
                            dtPlatesTxt.AddRange(txtCrvF0, new GH_Path(i, j));

                            if (i >= prev)
                            {
                                dtPlatesTxtLast.AddRange(txtCrvF0, new GH_Path(i, j));
                            }

                            var txtCrvF1 = Typewriter.Regular.Write("II", e1Plane, textSize[2]);
                            dtPlatesTxt.AddRange(txtCrvF1, new GH_Path(i, j));

                            if (i >= prev)
                            {
                                dtPlatesTxtLast.AddRange(txtCrvF1, new GH_Path(i, j));
                            }


                            counter++;
                            //
                        }
                    }
                }

                foreach (int meshEdge in jointSequence)
                {
                    //for (int i = 0; i < Math.Min(iterations, sequence.Count); i++) {//JointGroups.BranchCount
                    if (!meshEdgeDict.ContainsKey(meshEdge))
                    {
                        continue;
                    }
                    int i = meshEdgeDict[meshEdge];

                    for (int j = 0; j < JointGroups.Branch(i).Count; j++)
                    {
                        dtJoints.Add(JointGroups.Branch(i)[j].contour[0], new GH_Path(meshEdge, j));
                        dtJoints.Add(JointGroups.Branch(i)[j].contour[1], new GH_Path(meshEdge, j));
                        dtJointsMid.Add(JointGroups.Branch(i)[j].MidContour(), new GH_Path(i, j));

                        dtJointsPlanes.Add(JointGroups.Branch(i)[j].planeOffset0, new GH_Path(meshEdge, j));

                        Plane planet = new Plane(JointGroups.Branch(i)[j].planeOffset0.Origin + JointGroups.Branch(i)[j].planeOffset0.YAxis * textSize[5], JointGroups.Branch(i)[j].planeOffset0.XAxis, JointGroups.Branch(i)[j].planeOffset0.YAxis);


                        string text   = JointGroups.Branch(i)[j].id;
                        var    txtCrv = Typewriter.Regular.Write(text, planet, textSize[1]);
                        dtJointsTxt.AddRange(txtCrv, new GH_Path(meshEdge, j));
                    }
                }

                foreach (int meshEdge in jointSequenceLast)
                {
                    //for (int i = 0; i < Math.Min(iterations, sequence.Count); i++) {//JointGroups.BranchCount
                    if (!meshEdgeDict.ContainsKey(meshEdge))
                    {
                        continue;
                    }
                    int i = meshEdgeDict[meshEdge];

                    for (int j = 0; j < JointGroups.Branch(i).Count; j++)
                    {
                        dtJointsLast.Add(JointGroups.Branch(i)[j].contour[0], new GH_Path(meshEdge, j));
                        dtJointsLast.Add(JointGroups.Branch(i)[j].contour[1], new GH_Path(meshEdge, j));
                        dtJointsMidLast.Add(JointGroups.Branch(i)[j].MidContour(), new GH_Path(i, j));

                        dtJointsPlanesLast.Add(JointGroups.Branch(i)[j].planeOffset0, new GH_Path(meshEdge, j));

                        Plane planet = new Plane(JointGroups.Branch(i)[j].planeOffset0.Origin + JointGroups.Branch(i)[j].planeOffset0.YAxis * textSize[5], JointGroups.Branch(i)[j].planeOffset0.XAxis, JointGroups.Branch(i)[j].planeOffset0.YAxis);


                        string text   = JointGroups.Branch(i)[j].id;
                        var    txtCrv = Typewriter.Regular.Write(text, planet, textSize[1]);
                        dtJointsTxtLast.AddRange(txtCrv, new GH_Path(meshEdge, j));
                    }
                }


                DA.SetDataTree(0, dtPlates);
                DA.SetDataTree(1, dtJoints);

                DA.SetDataTree(2, dtPlatesMid);
                DA.SetDataTree(3, dtJointsMid);

                DA.SetDataTree(4, dtPlatesPlanes);
                DA.SetDataTree(5, dtJointsPlanes);

                DA.SetDataTree(6, dtPlatesTxt);
                DA.SetDataTree(7, dtJointsTxt);



                DA.SetDataTree(8, dtPlatesLast);
                DA.SetDataTree(9, dtJointsLast);

                DA.SetDataTree(10, dtPlatesMidLast);
                DA.SetDataTree(11, dtJointsMidLast);

                DA.SetDataTree(12, dtPlatesPlanesLast);
                DA.SetDataTree(13, dtJointsPlanesLast);

                DA.SetDataTree(14, dtPlatesTxtLast);
                DA.SetDataTree(15, dtJointsTxtLast);
            } catch (Exception e) {
                Rhino.RhinoApp.WriteLine(e.ToString());
            }
        }
コード例 #2
0
ファイル: JointsVDANew.cs プロジェクト: petrasvestartas/NGon
        protected override void SolveInstance(IGH_DataAccess DA)
        {
            try {
                ////////////////////////////////////////////////////////////////////
                //Inputs Grasshopper
                Mesh M = DA.Fetch <Mesh>("Mesh");
                DataTree <Polyline> PanelOutlines = DA.FetchTree <GH_Curve>("Panels").ToPolylineDT();

                //Create joints
                DataTree <Vector3d> order = DA.FetchTree <GH_Vector>("InsertionVec").ToVectorDT();


                ////////////////////////////////////////////////////////////////////
                //      Insertion vectors

                //DataTree<Vector3d> EV = M.insertionVectors(Center, EVec);

                bool Center = DA.Fetch <bool>("Center");
                if (order.DataCount == 0)
                {
                    order = M.insertionVectorsJoints(Center, null);//joints
                }
                DataTree <Vector3d> EV = order;
                ////////////////////////////////////////////////////////////////////

                List <Point3d> twoJoints        = DA.FetchList <Point3d>("TwoJoints");
                List <Line>    extendedJoints   = DA.FetchList <Line>("ExtendedJoints");
                List <Line>    deeperCutsJoints = DA.FetchList <Line>("DeeperCutsJoints");

                List <JointsVDAInputs> joints = GetJoints(order, M, twoJoints, extendedJoints, deeperCutsJoints);

                if (order.DataCount != 0)
                {
                    order = M.insertionVectorsJoints(Center, joints);//joints
                }
                bool Finger = DA.Fetch <bool>("Finger");
                DataTree <Polyline> CChamfer = new DataTree <Polyline>();
                int           iterations     = DA.Fetch <int>("Iterations");
                List <int>    sequence       = DA.FetchList <int>("Sequence");
                List <double> textSize       = DA.FetchList <double>("TextScale");


                if (textSize.Count != 8)
                {
                    textSize = new List <double> {
                        30, 12, 15, 0.5, 0.6, 0, 1, 5
                    }
                }
                ;

                DataTree <Panel> PanelGroups = DA.FetchTree <GH_Curve>("Panels").ToPanelsDT();
                DataTree <Panel> JointGroups = new DataTree <Panel>();

                ////////////////////////////////////////////////////////////////////


                ////////////////////////////////////////////////////////////////////

                int[][]                 tv      = M.GetNGonsTopoBoundaries();
                int[][]                 fe      = M.GetNGonFacesEdges(tv);
                HashSet <int>           e       = M.GetAllNGonEdges(tv);
                Dictionary <int, int[]> efDict  = M.GetFE(e, false);
                Point3d[]               centers = M.GetNGonCenters();

                Vector3d[] fn = M.GetNgonNormals();
                //int[][] ef = M.GetNgonsConnectedToNGonsEdges(e, true);
                ////////////////////////////////////////////////////////////////////


                DataTree <Polyline> diagonalConnections = new DataTree <Polyline>();
                //DataTree<Polyline> recJoints = new DataTree<Polyline>();

                //Iterate insertion edges
                Dictionary <int, int> meshEdgeDict = new Dictionary <int, int>();
                for (int i = 0; i < EV.BranchCount; i++)  // EV.BranchCount


                {
                    int meshEdge = EV.Path(i).Indices[0];//mesh edge is used as dataTree branch

                    meshEdgeDict.Add(meshEdge, i);

                    if (efDict[meshEdge].Length != 2)
                    {
                        continue;
                    }
                    int f0 = efDict[meshEdge][0];
                    int f1 = efDict[meshEdge][1];

                    //Divide line into points and create a planes on these point, following insertion direction and average face normal
                    // Point3d[] pts = M.TopologyEdges.EdgeLine(meshEdge).InterpolateLine(divisions, false);
                    Point3d[] pts = M.TopologyEdges.EdgeLine(meshEdge).InterpolateLine(joints[i].divisions, false);

                    Vector3d avNormal = fn[f0] + fn[f1];
                    //Vector3d jointVector = Vector3d.CrossProduct(M.TopologyEdges.EdgeLine(meshEdge).Direction, avNormal);
                    //EV.Branch(EV.Path(i))[0] = jointVector;

                    for (int j = 0; j < pts.Length; j++)
                    {
                        //(new Line(pts[j], pts[j]+ avNormal*40)).Bake();
                        //JointGroups.Add(new Panel(new Plane(pts[j], EV.Branch(EV.Path(i))[0].UnitVector(), M.GetMeshEdgePerpDir(meshEdge))), EV.Path(i));
                        Plane plane = new Plane(pts[j], avNormal, EV.Branch(EV.Path(i))[0].UnitVector());
                        // Plane plane = new Plane(pts[j],EV.Branch(EV.Path(i))[0].UnitVector(), M.GetMeshEdgePerpDir(meshEdge));

                        plane = plane.Switch("YX");
                        JointGroups.Add(new Panel(plane), EV.Path(i));
                        //plane.Bake(40);
                    }


                    //Construct joint outlines from planes
                    //Iterate number of joints per edge
                    for (int j = 0; j < pts.Length; j++)
                    {
                        JointGroups.Branch(EV.Path(i))[j].planeOffset0 = JointGroups.Branch(EV.Path(i))[j].plane.MovePlanebyAxis(joints[i].thickness * 0.5);  //offset planes

                        JointGroups.Branch(EV.Path(i))[j].planeOffset1 = JointGroups.Branch(EV.Path(i))[j].plane.MovePlanebyAxis(-joints[i].thickness * 0.5); //offset planes
                        JointGroups.Branch(EV.Path(i))[j].planeRot     = new Plane(pts[j], Vector3d.CrossProduct(EV.Branch(EV.Path(i))[0].UnitVector(), M.GetMeshEdgePerpDir(meshEdge)), M.GetMeshEdgePerpDir(meshEdge));
                        int[] ngons     = M.GetEdgeNgons(meshEdge);
                        Plane tempPlane = JointGroups.Branch(EV.Path(i))[j].planeRot.MovePlanebyAxis(joints[i].length);
                        int   sign      = tempPlane.Origin.DistanceToSquared(centers[ngons[0]]) < tempPlane.Origin.DistanceToSquared(centers[ngons[1]]) ? 1 : -1;

                        JointGroups.Branch(EV.Path(i))[j].planeRotOffset0 = JointGroups.Branch(EV.Path(i))[j].planeRot.MovePlanebyAxis(joints[i].length * sign);  //offset planes
                        JointGroups.Branch(EV.Path(i))[j].planeRotOffset1 = JointGroups.Branch(EV.Path(i))[j].planeRot.MovePlanebyAxis(-joints[i].length * sign); //offset plane
                        JointGroups.Branch(EV.Path(i))[j].planeEdge       = new Plane(pts[j], M.TopologyEdges.EdgeLine(meshEdge).Direction, M.GetMeshEdgePerpDir(meshEdge));

                        List <Plane> planesF0 = new List <Plane>();
                        List <Plane> planesF1 = new List <Plane>();
                        for (int k = 0; k < PanelGroups.Branch(f0).Count; k++)
                        {
                            planesF0.Add(PanelGroups.Branch(f0)[k].plane);
                        }
                        for (int k = 0; k < PanelGroups.Branch(f1).Count; k++)
                        {
                            planesF1.Add(PanelGroups.Branch(f1)[k].plane);
                        }



                        JointGroups.Branch(EV.Path(i))[j].planeF0 = PlaneUtil.AveragePlaneOrigin(planesF0);
                        JointGroups.Branch(EV.Path(i))[j].planeF1 = PlaneUtil.AveragePlaneOrigin(planesF1);

                        //JointGroups.Branch(EV.Path(i))[j].planeF0.MovePlanebyAxis(joints[i].height).Bake(40);
                        //JointGroups.Branch(EV.Path(i))[j].planeF1.MovePlanebyAxis(joints[i].height).Bake(40);

                        List <Plane> jointPlaneLoop = new List <Plane> {
                            JointGroups.Branch(EV.Path(i))[j].planeRotOffset0,
                            JointGroups.Branch(EV.Path(i))[j].planeF0.MovePlanebyAxis(joints[i].height),
                            JointGroups.Branch(EV.Path(i))[j].planeEdge,
                            JointGroups.Branch(EV.Path(i))[j].planeF1.MovePlanebyAxis(joints[i].height),                                   //3
                            JointGroups.Branch(EV.Path(i))[j].planeRotOffset1,
                            JointGroups.Branch(EV.Path(i))[j].planeF1.MovePlanebyAxis(-joints[i].height),                                  //5
                            JointGroups.Branch(EV.Path(i))[j].planeEdge,
                            JointGroups.Branch(EV.Path(i))[j].planeF0.MovePlanebyAxis(-joints[i].height),
                        };

                        //Rhino.RhinoDoc.ActiveDoc.Objects.AddRectangle(new Rectangle3d(JointGroups.Branch(EV.Path(i))[j].planeF1, new Interval(-20, 20), new Interval(-20, 20)));
                        //Rhino.RhinoDoc.ActiveDoc.Objects.AddRectangle(new Rectangle3d(JointGroups.Branch(EV.Path(i))[j].planeF1, new Interval(-20, 20), new Interval(-20, 20)));

                        JointGroups.Branch(EV.Path(i))[j].contourNoJoints[0] = PolylineUtil.PolylineFromPlanes(JointGroups.Branch(EV.Path(i))[j].planeOffset0, jointPlaneLoop);
                        JointGroups.Branch(EV.Path(i))[j].contourNoJoints[1] = PolylineUtil.PolylineFromPlanes(JointGroups.Branch(EV.Path(i))[j].planeOffset1, jointPlaneLoop);
                        JointGroups.Branch(EV.Path(i))[j].contour[0]         = new Polyline(JointGroups.Branch(EV.Path(i))[j].contourNoJoints[0]);
                        JointGroups.Branch(EV.Path(i))[j].contour[1]         = new Polyline(JointGroups.Branch(EV.Path(i))[j].contourNoJoints[1]);
                        //JointGroups.Branch(EV.Path(i))[j].contour[0].Bake();
                    }


                    //Construct Cuts
                    //Iterate number of joints per edge
                    for (int j = 0; j < pts.Length; j++)
                    {
                        int localMeshEdgeF0 = Array.IndexOf(fe[f0], meshEdge);
                        int localMeshEdgeF1 = Array.IndexOf(fe[f1], meshEdge);



                        //Iterate number of panels and create cuts
                        for (int k = 0; k < PanelGroups.Branch(f0).Count; k++)
                        {
                            Panel jointPanel = JointGroups.Branch(EV.Path(i))[j];
                            //Rhino.RhinoApp.WriteLine(jointPanel.contourNoJoints[0].Count.ToString());

                            jointPanel.id = f0.ToString() + "-" + f1.ToString();

                            if (pts.Length > 1)
                            {
                                jointPanel.id += "-" + j.ToString();
                            }

                            PanelGroups.Branch(f0)[k].CreateCut(localMeshEdgeF0, JointGroups.Branch(EV.Path(i))[j].planeOffset0, JointGroups.Branch(EV.Path(i))[j].planeOffset1, joints[i].length, ref jointPanel, false);//, ref neiPanel, ref jointPanel);
                            //PanelGroups.Branch(f1)[k].CreateCut(localMeshEdgeF1, JointGroups.Branch(EV.Path(i))[j].planeOffset0, JointGroups.Branch(EV.Path(i))[j].planeOffset1, joints[i].length, ref jointPanel, false);//, ref neiPanel, ref jointPanel);

                            JointGroups.Branch(EV.Path(i))[j] = jointPanel;
                        }


                        //Iterate number of panels and create cuts
                        for (int k = 0; k < PanelGroups.Branch(f1).Count; k++)
                        {
                            Panel jointPanel = JointGroups.Branch(EV.Path(i))[j];

                            jointPanel.id = f0.ToString() + "-" + f1.ToString();

                            if (pts.Length > 1)
                            {
                                jointPanel.id += "-" + j.ToString();
                            }

                            //PanelGroups.Branch(f0)[k].CreateCut(localMeshEdgeF0, JointGroups.Branch(EV.Path(i))[j].planeOffset0, JointGroups.Branch(EV.Path(i))[j].planeOffset1, joints[i].length, ref jointPanel, false);//, ref neiPanel, ref jointPanel);
                            PanelGroups.Branch(f1)[k].CreateCut(localMeshEdgeF1, JointGroups.Branch(EV.Path(i))[j].planeOffset0, JointGroups.Branch(EV.Path(i))[j].planeOffset1, joints[i].length, ref jointPanel, false);//, ref neiPanel, ref jointPanel);

                            JointGroups.Branch(EV.Path(i))[j] = jointPanel;
                        }
                    }
                }


                for (int i = 0; i < JointGroups.BranchCount; i++)
                {
                    for (int j = 0; j < JointGroups.Branch(i).Count; j++)
                    {
                        if (joints[i].custom == 0)
                        {
                            if (joints[i].custom > 0)
                            {
                                JointGroups.Branch(i)[j].ChangeJoint(joints[i].custom, 0, joints[i].cutExtend, joints[i].addExtend);
                            }
                            else if (joints[i].custom < 0)
                            {
                                JointGroups.Branch(i)[j].ChangeJoint(joints[i].custom, 1, joints[i].cutExtend, joints[i].addExtend);
                            }
                        }
                    }
                }



                ////////////////////////Output
                var dtPlates       = new DataTree <Polyline>();
                var dtJoints       = new DataTree <Polyline>();
                var dtPlatesMid    = new DataTree <Polyline>();
                var dtJointsMid    = new DataTree <Polyline>();
                var dtPlatesPlanes = new DataTree <Plane>();
                var dtJointsPlanes = new DataTree <Plane>();
                var dtPlatesTxt    = new DataTree <Curve>();
                var dtJointsTxt    = new DataTree <Curve>();

                var dtPlatesLast       = new DataTree <Polyline>();
                var dtJointsLast       = new DataTree <Polyline>();
                var dtPlatesMidLast    = new DataTree <Polyline>();
                var dtJointsMidLast    = new DataTree <Polyline>();
                var dtPlatesPlanesLast = new DataTree <Plane>();
                var dtJointsPlanesLast = new DataTree <Plane>();
                var dtPlatesTxtLast    = new DataTree <Curve>();
                var dtJointsTxtLast    = new DataTree <Curve>();

                HashSet <int> jointSequenceTemp = new HashSet <int>();
                HashSet <int> jointSequence     = new HashSet <int>();

                HashSet <int> jointSequenceLast = new HashSet <int>();
                int           last = Math.Min(iterations, PanelGroups.BranchCount);
                int           prev = Math.Max(0, last - (int)textSize[6]);



                for (int i = 0; i < last; i++)  //Math.Min(iterations, sequence.Count) PanelGroups.BranchCount

                {
                    for (int j = 0; j < fe[i].Length; j++)
                    {
                        bool seq = jointSequenceTemp.Add(fe[i][j]);

                        if (i >= prev)
                        {
                            if (seq)
                            {
                                jointSequenceLast.Add(fe[i][j]);
                            }
                            else
                            {
                                jointSequence.Add(fe[i][j]);
                            }
                        }
                        else
                        {
                            jointSequence.Add(fe[i][j]);
                        }
                    }

                    for (int j = 0; j < PanelGroups.Branch(i).Count; j++)
                    {
                        if (i >= prev)
                        {
                            dtPlatesLast.Add(PanelGroups.Branch(i)[j].contour[0], new GH_Path(i, j));
                            dtPlatesLast.Add(PanelGroups.Branch(i)[j].contour[1], new GH_Path(i, j));
                            dtPlatesMidLast.Add(PanelGroups.Branch(i)[j].MidContour(), new GH_Path(i, j));
                        }
                        else
                        {
                            dtPlates.Add(PanelGroups.Branch(i)[j].contour[0], new GH_Path(i, j));
                            dtPlates.Add(PanelGroups.Branch(i)[j].contour[1], new GH_Path(i, j));
                            dtPlatesMid.Add(PanelGroups.Branch(i)[j].MidContour(), new GH_Path(i, j));
                        }



                        Plane textPlane = PanelGroups.Branch(i)[j].planeOffset0;
                        textPlane.Flip();

                        if (j > 0)
                        {
                            textPlane = PanelGroups.Branch(i)[j].planeOffset1;
                        }



                        if (i >= prev)
                        {
                            dtPlatesPlanesLast.Add(textPlane, new GH_Path(i, j));
                        }
                        else
                        {
                            dtPlatesPlanes.Add(textPlane, new GH_Path(i, j));
                        }


                        string text   = i.ToString() + "-" + j.ToString();
                        var    txtCrv = Typewriter.Regular.Write(text, textPlane, textSize[0]);


                        if (i >= prev)
                        {
                            dtPlatesTxtLast.AddRange(txtCrv, new GH_Path(i, j));
                        }
                        else
                        {
                            dtPlatesTxt.AddRange(txtCrv, new GH_Path(i, j));
                        }


                        var a = PanelGroups.Branch(i)[j];

                        Line[] segments = PanelGroups.Branch(i)[j].contourNoJoints[Math.Min(1, j)].GetSegments();


                        int counter = 0;
                        foreach (Line l in segments)
                        {
                            int meshEdge = fe[i][counter];

                            int neiF = M.GetOppositeNgon(meshEdge, i);


                            //Adjacent face plane
                            Point3d  origin = l.PointAt(textSize[3]);
                            Vector3d xaxis  = l.Direction;
                            Vector3d yaxis  = l.Direction;
                            origin.Transform(Rhino.Geometry.Transform.Scale(textPlane.Origin, textSize[4]));
                            yaxis.Rotate(Math.PI * 0.5, textPlane.ZAxis);
                            Plane ePlane = new Plane(origin, xaxis, yaxis);

                            var txtCrvF = Typewriter.Regular.Write(neiF.ToString(), ePlane, textSize[2]);


                            if (i >= prev)
                            {
                                dtPlatesTxtLast.AddRange(txtCrvF, new GH_Path(i, j));
                            }
                            else
                            {
                                dtPlatesTxt.AddRange(txtCrvF, new GH_Path(i, j));
                            }



                            //Mesh edge direction
                            Line meshEdgeLine = M.TopologyEdges.EdgeLine(meshEdge);
                            meshEdgeLine.Transform(Rhino.Geometry.Transform.Scale(meshEdgeLine.PointAt(0.5), textSize[4]));
                            meshEdgeLine.Transform(Rhino.Geometry.Transform.Scale(textPlane.Origin, textSize[4]));
                            //meshEdgeLine.Extend(-textSize[4], -textSize[4]);


                            Plane e0Plane = new Plane(ePlane.ClosestPoint(meshEdgeLine.From), xaxis, yaxis);
                            Plane e1Plane = new Plane(ePlane.ClosestPoint(meshEdgeLine.To), xaxis, yaxis);

                            var txtCrvF0 = Typewriter.Regular.Write("I", e0Plane, textSize[2]);


                            if (i >= prev)
                            {
                                dtPlatesTxtLast.AddRange(txtCrvF0, new GH_Path(i, j));
                            }
                            else
                            {
                                dtPlatesTxt.AddRange(txtCrvF0, new GH_Path(i, j));
                            }

                            var txtCrvF1 = Typewriter.Regular.Write("II", e1Plane, textSize[2]);


                            if (i >= prev)
                            {
                                dtPlatesTxtLast.AddRange(txtCrvF1, new GH_Path(i, j));
                            }
                            else
                            {
                                dtPlatesTxt.AddRange(txtCrvF1, new GH_Path(i, j));
                            }


                            counter++;
                            //
                        }
                    }
                }

                DataTree <Vector3d> insertionVectors = new DataTree <Vector3d>();


                foreach (int meshEdge in jointSequence)
                {
                    if (!meshEdgeDict.ContainsKey(meshEdge))
                    {
                        continue;
                    }
                    int i = meshEdgeDict[meshEdge];



                    for (int j = 0; j < JointGroups.Branch(i).Count; j++)
                    {
                        GH_Path path = new GH_Path(meshEdge, j);

                        insertionVectors.Add(JointGroups.Branch(i)[j].planeOffset0.XAxis, path);


                        dtJoints.Add(JointGroups.Branch(i)[j].contour[0], path);
                        dtJoints.Add(JointGroups.Branch(i)[j].contour[1], path);
                        dtJointsMid.Add(JointGroups.Branch(i)[j].MidContour(), path);
                        dtJointsPlanes.Add(JointGroups.Branch(i)[j].planeOffset0, path);

                        Plane planet = new Plane(JointGroups.Branch(i)[j].planeOffset0.Origin + JointGroups.Branch(i)[j].planeOffset0.YAxis * textSize[5], JointGroups.Branch(i)[j].planeOffset0.XAxis, JointGroups.Branch(i)[j].planeOffset0.YAxis);



                        string text   = JointGroups.Branch(i)[j].id;
                        var    txtCrv = Typewriter.Regular.Write(text, planet, textSize[1]);
                        dtJointsTxt.AddRange(txtCrv, path);
                    }
                }



                foreach (int meshEdge in jointSequenceLast)
                {
                    if (!meshEdgeDict.ContainsKey(meshEdge))
                    {
                        continue;
                    }
                    int i = meshEdgeDict[meshEdge];



                    for (int j = 0; j < JointGroups.Branch(i).Count; j++)
                    {
                        dtJointsLast.Add(JointGroups.Branch(i)[j].contour[0], new GH_Path(meshEdge, j));
                        dtJointsLast.Add(JointGroups.Branch(i)[j].contour[1], new GH_Path(meshEdge, j));
                        dtJointsMidLast.Add(JointGroups.Branch(i)[j].MidContour(), new GH_Path(meshEdge, j));

                        dtJointsPlanesLast.Add(JointGroups.Branch(i)[j].planeOffset0, new GH_Path(meshEdge, j));

                        Plane planet = new Plane(JointGroups.Branch(i)[j].planeOffset0.Origin + JointGroups.Branch(i)[j].planeOffset0.YAxis * textSize[5], JointGroups.Branch(i)[j].planeOffset0.XAxis, JointGroups.Branch(i)[j].planeOffset0.YAxis);


                        string text   = JointGroups.Branch(i)[j].id;
                        var    txtCrv = Typewriter.Regular.Write(text, planet, textSize[1]);
                        dtJointsTxtLast.AddRange(txtCrv, new GH_Path(meshEdge, j));
                    }
                }


                DA.SetDataTree(0, dtPlates);
                DA.SetDataTree(1, dtJoints);

                DA.SetDataTree(2, dtPlatesMid);
                DA.SetDataTree(3, dtJointsMid);

                DA.SetDataTree(4, dtPlatesPlanes);
                DA.SetDataTree(5, dtJointsPlanes);

                DA.SetDataTree(6, dtPlatesTxt);
                DA.SetDataTree(7, dtJointsTxt);



                DA.SetDataTree(8, dtPlatesLast);
                DA.SetDataTree(9, dtJointsLast);

                DA.SetDataTree(10, dtPlatesMidLast);
                DA.SetDataTree(11, dtJointsMidLast);

                DA.SetDataTree(12, dtPlatesPlanesLast);
                DA.SetDataTree(13, dtJointsPlanesLast);

                DA.SetDataTree(14, dtPlatesTxtLast);
                DA.SetDataTree(15, dtJointsTxtLast);
            } catch (Exception e) {
                Rhino.RhinoApp.WriteLine(e.ToString());
            }
        }