Пример #1
0
        /// <summary>
        /// This is the method that actually does the work.
        /// </summary>
        /// <param name="DA">The DA object is used to retrieve from inputs and store in outputs.</param>
        protected override void SolveInstance(IGH_DataAccess DA)
        {
            Surface S = null;

            if (!DA.GetData(0, ref S))
            {
                return;
            }

            Point3d P = Point3d.Unset;

            if (!DA.GetData(1, ref P))
            {
                P = S.PointAt(S.Domain(0).Mid, S.Domain(1).Mid);
            }

            double R = Rhino.RhinoMath.UnsetValue;

            if (!DA.GetData(2, ref R))
            {
                return;
            }

            double A = Rhino.RhinoMath.UnsetValue;

            if (!DA.GetData(3, ref A))
            {
                return;
            }

            int max = 0;

            if (!DA.GetData(4, ref max))
            {
                return;
            }

            Boolean extend = false;

            if (!DA.GetData(5, ref extend))
            {
                return;
            }

            if (R <= 0)
            {
                this.AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Mesh edge length must be a positive, non-zero number.");
                return;
            }

            // Extend surface beyond boundaries to get a better coverage from the net
            if (extend)
            {
                S = S.Extend(IsoStatus.North, R, true);
                S = S.Extend(IsoStatus.East, R, true);
                S = S.Extend(IsoStatus.South, R, true);
                S = S.Extend(IsoStatus.West, R, true);
            }


            // starting point
            double u0, v0;

            S.ClosestPoint(P, out u0, out v0);
            // get two (four) orthogonal directions (in plane of surface at starting point)
            Plane plane = new Plane(S.PointAt(u0, v0), S.NormalAt(u0, v0));

            plane.Rotate(Rhino.RhinoMath.ToRadians(A), S.NormalAt(u0, v0));
            Vector3d[] dir = new Vector3d[] {
                plane.XAxis *  R,
                plane.YAxis *  R,
                plane.XAxis * -R,
                       plane.YAxis * -R
            };


            // for each direction, walk out (and store list of points)
            double u, v;

            List <Point3d>[] axis = new List <Point3d> [4];
            for (int i = 0; i < 4; i++)
            {
                // set u and v to starting point
                u = u0;
                v = v0;
                List <Point3d> pts = new List <Point3d>();
                for (int j = 0; j < max + 1; j++)
                {
                    // get point and normal for uv
                    Point3d  pt = S.PointAt(u, v);
                    Vector3d n  = S.NormalAt(u, v);
                    n *= R;
                    // add point to list
                    pts.Add(pt);
                    // create forward facing arc and find intersection point with surface (as uv)
                    Arc arc = new Arc(pt + n, pt + dir[i], pt - n);
                    CurveIntersections isct =
                        Intersection.CurveSurface(arc.ToNurbsCurve(), S, 0.01, 0.01);
                    if (isct.Count > 0)
                    {
                        isct[0].SurfacePointParameter(out u, out v);
                    }
                    else
                    {
                        break;
                    }
                    // adjust direction vector (new position - old position)
                    dir[i] = S.PointAt(u, v) - pt;
                }
                axis[i] = pts;
            }


            // now that we have the axes, start to build up the mesh quads in between
            GH_PreviewUtil preview = new GH_PreviewUtil(GetValue("Animate", false));

            Rhino.Geometry.Mesh mesh = new Rhino.Geometry.Mesh(); // target mesh
            for (int k = 0; k < 4; k++)
            {
                int k0      = (k + 1) % 4;
                int padding = 10;
                Rhino.Geometry.Mesh qmesh = new Rhino.Geometry.Mesh();                            // local mesh for quadrant
                Point3d[,] quad = new Point3d[axis[k].Count + padding, axis[k0].Count + padding]; // 2d array of points
                int[,] qindex   = new int[axis[k].Count + padding, axis[k0].Count + padding];     // 2d array of points' indices in local mesh
                int count = 0;
                for (int i = 0; i < axis[k0].Count; i++)
                {
                    // add axis vertex to mesh and store point and index in corresponding 2d arrays
                    quad[0, i] = axis[k0][i];
                    qmesh.Vertices.Add(axis[k0][i]);
                    qindex[0, i] = count++;
                }

                for (int i = 1; i < quad.GetLength(0); i++)
                {
                    if (i < axis[k].Count)
                    {
                        // add axis vertex
                        quad[i, 0] = axis[k][i];
                        qmesh.Vertices.Add(axis[k][i]);
                        qindex[i, 0] = count++;
                    }
                    // for each column attempt to locate a new vertex in the grid
                    for (int j = 1; j < quad.GetLength(1); j++)
                    {
                        // if quad[i - 1, j] doesn't exist, try to add it and continue (or else break the current row)
                        if (quad[i - 1, j] == new Point3d())
                        {
                            if (j < 2)
                            {
                                break;
                            }
                            CurveIntersections isct = this.ArcIntersect(S, quad[i - 1, j - 1], quad[i - 1, j - 2], R);
                            if (isct.Count > 0)
                            {
                                quad[i - 1, j] = isct[0].PointB;
                                qmesh.Vertices.Add(quad[i - 1, j]);
                                qindex[i - 1, j] = count++;
                            }
                            else
                            {
                                break;
                            }
                        }
                        // if quad[i, j - 1] doesn't exist, try to create quad[i, j] by projection and skip mesh face creation
                        if (quad[i, j - 1] == new Point3d())
                        {
                            if (i < 2)
                            {
                                break;
                            }
                            CurveIntersections isct = this.ArcIntersect(S, quad[i - 1, j], quad[i - 2, j], R);
                            if (isct.Count > 0)
                            {
                                quad[i, j] = isct[0].PointB;
                                qmesh.Vertices.Add(quad[i, j]);
                                qindex[i, j] = count++;
                                continue;
                            }
                        }
                        // construct a sphere at each neighbouring vertex ([i,j-1] and [i-1,j]) and intersect
                        Sphere sph1 = new Sphere(quad[i, j - 1], R);
                        Sphere sph2 = new Sphere(quad[i - 1, j], R);
                        Circle cir;
                        if (Intersection.SphereSphere(sph1, sph2, out cir) == SphereSphereIntersection.Circle)
                        {
                            // intersect circle with surface
                            CurveIntersections cin =
                                Intersection.CurveSurface(NurbsCurve.CreateFromCircle(cir), S, 0.01, 0.01);
                            // attempt to find the new vertex (i.e not [i-1,j-1])
                            foreach (IntersectionEvent ie in cin)
                            {
                                if ((ie.PointA - quad[i - 1, j - 1]).Length > 0.2 * R) // compare with a tolerance, rather than exact comparison
                                {
                                    quad[i, j] = ie.PointA;
                                    qmesh.Vertices.Add(quad[i, j]);
                                    qindex[i, j] = count++;
                                    // create quad-face
                                    qmesh.Faces.AddFace(qindex[i, j], qindex[i - 1, j], qindex[i - 1, j - 1], qindex[i, j - 1]);
                                    break;
                                }
                            }
                            if (preview.Enabled)
                            {
                                preview.Clear();
                                preview.AddMesh(mesh);
                                preview.AddMesh(qmesh);
                                preview.Redraw();
                            }
                        }
                    }
                }
                // add local mesh to target
                mesh.Append(qmesh);
            }

            // weld mesh to remove duplicate vertices along axes
            mesh.Weld(Math.PI);
            mesh.Compact();
            mesh.Normals.ComputeNormals();


            DA.SetData(0, mesh);

            preview.Clear();
        }
Пример #2
0
        /// <summary>
        /// This is the method that actually does the work.
        /// </summary>
        /// <param name="DA">The DA object is used to retrieve from inputs and store in outputs.</param>
        protected override void SolveInstance(IGH_DataAccess DA)
        {
            double span = 0;
            List <VariableSection> vSect = new List <VariableSection>();

            if (!DA.GetData(0, ref span))
            {
                return;
            }
            if (!DA.GetDataList(1, vSect))
            {
                return;
            }

            int N = vSect.Count;

            if (N < 2)
            {
                AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "VSect needs at least 2 inputs");
                return;
            }

            Transform mirrorYZ = Transform.Mirror(Plane.WorldYZ);
            Transform mirrorXZ = Transform.Mirror(Plane.WorldZX);

            Point3d spPtA    = new Point3d(-span * 0.5, 0, 0);
            Curve   spCrv    = new Line(spPtA, Plane.WorldXY.XAxis, span).ToNurbsCurve();
            Curve   spCrvHlf = new Line(spPtA, Plane.WorldXY.XAxis, span * 0.5).ToNurbsCurve();

            //if (N < 2) { N = 3; }
            double[] spCrvDiv = spCrv.DivideByCount(N - 1, true);
            Plane[]  spCrvPln = spCrv.GetPerpendicularFrames(spCrvDiv);
            for (int i = 0; i < spCrvPln.Length; i++) //reorient planes to align with z-axis
            {
                Plane pl = spCrvPln[i];
                pl.Rotate(-Math.PI * 0.5, Plane.WorldXY.XAxis);
                spCrvPln[i] = pl;
            }

            List <Point3d> allPts = new List <Point3d>();
            List <Curve>   crvs   = new List <Curve>();

            int ptCnt = vSect[0].sctPts.Count;

            Point3d[,] crvPts = new Point3d[ptCnt, vSect.Count];
            //for(int i = 0; i < vSect.Count; i++) { Point3d[] crvPt = new Point3d[vSect.Count]; }


            for (int i = 0; i < vSect.Count; i++) //moves and reorients points from input i indicates number section, j number curve/point in section
            {
                List <Point3d> sctPts = vSect[i].sctPts;
                Plane          sctPln = vSect[i].sctPln;

                if (sctPts.Count != ptCnt)
                {
                    AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Each section needs the same number of points"); return;
                }

                Transform reorient = Transform.PlaneToPlane(sctPln, spCrvPln[i]);
                //foreach (Point3d pt in sctPts) { pt.Transform(reorient); allPts.Add(pt); } //remove when workaround is figured out

                for (int j = 0; j < sctPts.Count; j++) //separate points to each "row" in a list of arrays
                {
                    Point3d pt = sctPts[j];
                    pt.Transform(reorient);
                    crvPts[j, i] = pt;
                }
            }

            int degree = 3;

            for (int i = 0; i < crvPts.GetLength(0); i++) //creates curves through points
            {
                Point3d[] aCrvPts = new Point3d[vSect.Count];
                for (int j = 0; j < crvPts.GetLength(1); j++)
                {
                    aCrvPts[j] = crvPts[i, j];
                }
                Curve crv = Curve.CreateInterpolatedCurve(aCrvPts, degree);
                crvs.Add(crv);
            }

            List <Brep> faces = new List <Brep>();

            Brep[] loftFace = Brep.CreateFromLoft(crvs, Point3d.Unset, Point3d.Unset, LoftType.Straight, false);
            //Brep face1 = new Brep();
            //foreach(Brep face in loftFace) { face1 = face.DuplicateBrep(); }
            Brep face1 = loftFace[0].DuplicateBrep();
            Brep face2 = face1.DuplicateBrep(); face2.Transform(mirrorXZ);

            faces.Add(face1); faces.Add(face2);

            Curve[] naked1 = face1.DuplicateNakedEdgeCurves(true, false); Curve[] naked2 = face2.DuplicateNakedEdgeCurves(true, false);
            Curve[] loftCrv1 = new Curve[] { naked1[1], naked2[1] }; Curve[] loftCrv2 = new Curve[] { naked1[3], naked2[3] };
            Brep[]  face3 = Brep.CreateFromLoft(loftCrv1, Point3d.Unset, Point3d.Unset, LoftType.Straight, false);
            Brep[]  face4 = Brep.CreateFromLoft(loftCrv2, Point3d.Unset, Point3d.Unset, LoftType.Straight, false);
            faces.Add(face3[0]); faces.Add(face4[0]);

            Brep[] beamBreps = Brep.JoinBreps(faces, DocumentTolerance());
            Brep   beam      = beamBreps[0].CapPlanarHoles(DocumentTolerance());

            int intersects = 0;
            int a          = crvs.Count;

            for (int i = 0; i < (a - 1); i++)
            {
                for (int j = (i + 1); j < a; j++)
                {
                    Rhino.Geometry.Intersect.CurveIntersections crvCheck = Rhino.Geometry.Intersect.Intersection.CurveCurve(
                        crvs[i], crvs[j], DocumentTolerance(), 0.0);

                    intersects += crvCheck.Count;
                }
            }

            if (intersects > 0)
            {
                AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Beam volume is invalid.");
                return;
            }

            DA.SetDataList(0, spCrvPln);
            DA.SetDataList(1, crvPts);
            DA.SetDataList(2, crvs);
            DA.SetData(3, beam);
            DA.SetData(4, spCrv);
        }
Пример #3
0
            protected override void SolveInstance(IGH_DataAccess DA)
            {
                //Input
                Surface S = null;

                if (!DA.GetData(0, ref S))
                {
                    return;
                }

                Point3d P = Point3d.Unset;

                if (!DA.GetData(1, ref P))
                {
                    P = S.PointAt(S.Domain(0).Mid, S.Domain(1).Mid);
                }

                double R = Rhino.RhinoMath.UnsetValue;

                if (!DA.GetData(2, ref R))
                {
                    return;
                }

                double A = Rhino.RhinoMath.UnsetValue;

                if (!DA.GetData(3, ref A))
                {
                    return;
                }

                int max = 0;

                if (!DA.GetData(4, ref max))
                {
                    return;
                }

                Boolean extend = false;

                if (!DA.GetData(5, ref extend))
                {
                    return;
                }

                if (R <= 0)
                {
                    this.AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Mesh edge length must be a positive, non-zero number.");
                    return;
                }

                Surface Sold = S;

                if (extend)   //Extend more and trim edges?
                {
                    S = S.Extend(IsoStatus.North, R * 2, true);
                    S = S.Extend(IsoStatus.East, R * 2, true);
                    S = S.Extend(IsoStatus.South, R * 2, true);
                    S = S.Extend(IsoStatus.West, R * 2, true);
                }

                //----------------------------------------------------------------------------------------------------------//
                //Solution

                // starting point
                double u0, v0;

                S.ClosestPoint(P, out u0, out v0);

                //Create plane on surface by point and surface normal, plane x,y axis are directions for the net
                Plane plane = new Plane(S.PointAt(u0, v0), S.NormalAt(u0, v0));

                plane.Rotate(Rhino.RhinoMath.ToRadians(A), S.NormalAt(u0, v0));
                Vector3d[] dir = new Vector3d[] { plane.XAxis *R, plane.YAxis *R, plane.XAxis * -R, plane.YAxis * -R };

                //Surface
                Curve[] MyNakedEdges = Sold.ToBrep().DuplicateNakedEdgeCurves(true, false);
                Mesh[]  meshes       = new Mesh[] { new Mesh(), new Mesh(), new Mesh(), new Mesh() };

                //----------------------------------------------------------------------------------------------------------//
                //Create axis
                // for each direction, walk out (and store list of points)

                double u, v;

                List <Point3d>[] axis = new List <Point3d> [4];
                List <Arc>[]     arcs = new List <Arc> [4];
                polylines = new List <Polyline>();

                for (int i = 0; i < 4; i++)
                {
                    // set u and v to starting point
                    u = u0;
                    v = v0;
                    List <Point3d> pts        = new List <Point3d>();
                    List <Arc>     arcCurrent = new List <Arc>();


                    for (int j = 0; j < max + 1; j++)
                    {
                        Point3d pt = S.PointAt(u, v); // get point and normal for uv
                        pts.Add(pt);

                        Vector3d srfNormal = S.NormalAt(u, v) * R;

                        Arc arc = new Arc(pt + srfNormal, pt + dir[i], pt - srfNormal); // create forward facing arc and find intersection point with surface (as uv)
                        arcCurrent.Add(arc);
                        CurveIntersections isct = Intersection.CurveSurface(arc.ToNurbsCurve(), S, 0.01, 0.01);


                        if (isct.Count > 0)
                        {
                            isct[0].SurfacePointParameter(out u, out v);
                        }
                        else
                        {
                            break;
                        }

                        // adjust direction vector (new position - old position)
                        dir[i] = S.PointAt(u, v) - pt;
                    }

                    axis[i] = pts;
                    arcs[i] = arcCurrent;
                }



                //----------------------------------------------------------------------------------------------------------//
                //Build up the mesh quads in between

                GH_PreviewUtil preview = new GH_PreviewUtil(GetValue("Animate", false));

                Mesh mesh = new Mesh();     // target mesh

                for (int k = 0; k < 4; k++) //Loop through each axis

                {
                    Mesh qmesh = new Mesh();                                                // local mesh for quadrant

                    int k0 = (k + 1) % 4;                                                   //Take neighbour id
                    Point3d[,] quad = new Point3d[axis[k].Count + 10, axis[k0].Count + 10]; // 2d array of points
                    int[,] qindex   = new int[axis[k].Count + 10, axis[k0].Count + 10];     // 2d array of points' indices in local mesh

                    int count = 0;

                    for (int i = 0; i < axis[k0].Count; i++)
                    {
                        quad[0, i] = axis[k0][i];        //store 2nd axis points in point array
                        qmesh.Vertices.Add(axis[k0][i]); //also add 2nd axis points to mesh
                        qindex[0, i] = count++;          //store indicies
                    }


                    for (int i = 1; i < quad.GetLength(0); i++)
                    {
                        if (i < axis[k].Count)              // add axis vertex
                        {
                            quad[i, 0] = axis[k][i];        //store 1st axis points in point array
                            qmesh.Vertices.Add(axis[k][i]); //also add 1st axis points to mesh
                            qindex[i, 0] = count++;         //store indicies
                        }

                        // for each column attempt to locate a new vertex in the grid
                        for (int j = 1; j < quad.GetLength(1); j++)
                        {
                            // if quad[i - 1, j] doesn't exist, try to add it and continue (or else break the current row)
                            if (quad[i - 1, j] == new Point3d())
                            {
                                if (j < 2)
                                {
                                    break;
                                }

                                CurveIntersections isct = this.ArcIntersect(S, quad[i - 1, j - 1], quad[i - 1, j - 2], R);

                                if (isct.Count > 0)
                                {
                                    quad[i - 1, j] = isct[0].PointB;
                                    qmesh.Vertices.Add(quad[i - 1, j]);

                                    qindex[i - 1, j] = count++;
                                }
                                else
                                {
                                    break;
                                }
                            }

                            // if quad[i, j - 1] doesn't exist, try to create quad[i, j] by projection and skip mesh face creation
                            if (quad[i, j - 1] == new Point3d())
                            {
                                if (i < 2)
                                {
                                    break;
                                }

                                CurveIntersections isct = this.ArcIntersect(S, quad[i - 1, j], quad[i - 2, j], R);

                                if (isct.Count > 0)
                                {
                                    quad[i, j] = isct[0].PointB;
                                    qmesh.Vertices.Add(quad[i, j]);
                                    qindex[i, j] = count++;

                                    continue;
                                }
                            }

                            // construct a sphere at each neighbouring vertex ([i,j-1] and [i-1,j]) and intersect

                            Sphere sph1 = new Sphere(quad[i, j - 1], R);
                            Sphere sph2 = new Sphere(quad[i - 1, j], R);
                            Circle cir;

                            if (Intersection.SphereSphere(sph1, sph2, out cir) == SphereSphereIntersection.Circle)
                            {
                                CurveIntersections cin = Intersection.CurveSurface(NurbsCurve.CreateFromCircle(cir), S, 0.01, 0.01);// intersect circle with surface

                                // attempt to find the new vertex (i.e not [i-1,j-1])

                                foreach (IntersectionEvent ie in cin)
                                {
                                    if ((ie.PointA - quad[i - 1, j - 1]).Length > 0.2 * R)  // compare with a tolerance, rather than exact comparison

                                    {
                                        quad[i, j] = ie.PointA;
                                        qmesh.Vertices.Add(quad[i, j]);
                                        qindex[i, j] = count++;

                                        Point3d[] facePt = new Point3d[] { quad[i, j], quad[i - 1, j], quad[i - 1, j - 1], quad[i, j - 1] };

                                        Sold.ClosestPoint(quad[i, j], out double u1, out double v1);
                                        Sold.ClosestPoint(quad[i - 1, j], out double u2, out double v2);
                                        Sold.ClosestPoint(quad[i - 1, j - 1], out double u3, out double v3);
                                        Sold.ClosestPoint(quad[i, j - 1], out double u4, out double v4);

                                        double tolerance = 0.01;
                                        bool[] flag      = new bool[] {
                                            Sold.PointAt(u1, v1).DistanceTo(quad[i, j]) < tolerance,
                                            Sold.PointAt(u2, v2).DistanceTo(quad[i - 1, j]) < tolerance,
                                            Sold.PointAt(u3, v3).DistanceTo(quad[i - 1, j - 1]) < tolerance,
                                            Sold.PointAt(u4, v4).DistanceTo(quad[i, j - 1]) < tolerance
                                        };



                                        if (flag[0] && flag[1] && flag[2] && flag[3])
                                        {
                                            qmesh.Faces.AddFace(qindex[i, j], qindex[i - 1, j], qindex[i - 1, j - 1], qindex[i, j - 1]);// create quad-face
                                        }
                                        else if (flag[0] || flag[1] || flag[2] || flag[3])
                                        {
                                            Polyline temp = new Polyline();

                                            for (int p = 0; p < 4; p++)
                                            {
                                                switch (Convert.ToInt32(flag[p]) * 10 + Convert.ToInt32(flag[(p + 1) % 4]))
                                                {
                                                case (11):
                                                    temp.Add(facePt[p]);
                                                    break;

                                                case (10):
                                                    temp.Add(facePt[p]);
                                                    temp.Add(ClosestPointOnNakedEdge(MyNakedEdges, facePt[p], new Line(facePt[p], facePt[(p + 1) % 4])));
                                                    break;

                                                case (1):
                                                    temp.Add(ClosestPointOnNakedEdge(MyNakedEdges, facePt[p], new Line(facePt[p], facePt[(p + 1) % 4])));
                                                    break;

                                                case (0):
                                                    Sold.ClosestPoint(facePt[p], out double u6, out double v6);
                                                    temp.Add(Sold.PointAt(u6, v6));
                                                    break;
                                                }
                                            }
                                            temp.Close();
                                            polylines.Add(temp);



                                            //qmesh.Faces.AddFace(qindex[i, j], qindex[i - 1, j], qindex[i - 1, j - 1], qindex[i, j - 1]);// create quad-face
                                        }



                                        //qmesh.Faces.AddFace(qindex[i, j], qindex[i - 1, j], qindex[i - 1, j - 1], qindex[i, j - 1]);// create quad-face
                                        break;
                                    }
                                }

                                if (preview.Enabled)
                                {
                                    preview.Clear();
                                    preview.AddMesh(mesh);
                                    preview.AddMesh(qmesh);
                                    preview.Redraw();
                                }
                            }
                        }
                    }

                    ;

                    mesh.Append(qmesh);// add local mesh to target
                }

                //----------------------------------------------------------------------------------------------------------//
                //Output
                mesh.Weld(Math.PI);
                mesh.Compact();
                mesh.Normals.ComputeNormals();

                DA.SetData(0, mesh);
                DA.SetDataTree(1, NGonsCore.GrasshopperUtil.IEOfIEToTree(axis, 0));
                DA.SetDataList(2, polylines);

                preview.Clear();
            }
Пример #4
0
            protected override void SolveInstance(IGH_DataAccess DA)
            {
                try {
                    //Input
                    Surface S = s;
                    //if (!DA.GetData(0, ref S)) { return; }
                    DA.GetData(0, ref S);
                    Point3d P = Point3d.Unset;

                    if (!DA.GetData(1, ref P))
                    {
                        P = S.PointAt(S.Domain(0).Mid, S.Domain(1).Mid);
                    }

                    double R = Rhino.RhinoMath.UnsetValue;
                    if (!DA.GetData(2, ref R))
                    {
                        return;
                    }

                    double A = Rhino.RhinoMath.UnsetValue;
                    if (!DA.GetData(3, ref A))
                    {
                        return;
                    }

                    int max = 0;
                    if (!DA.GetData(4, ref max))
                    {
                        return;
                    }

                    Boolean extend = false;
                    if (!DA.GetData(5, ref extend))
                    {
                        return;
                    }

                    if (R <= 0)
                    {
                        this.AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Mesh edge length must be a positive, non-zero number.");
                        return;
                    }

                    Mesh cutter = new Mesh();
                    //DA.GetData(8, ref cutter);

                    Surface Sold = S;
                    Sold.SetDomain(0, new Interval(0, 1));
                    Sold.SetDomain(1, new Interval(0, 1));
                    PointCloud cornerPoints = new PointCloud(new Point3d[] { Sold.PointAt(0, 0), Sold.PointAt(0, 1), Sold.PointAt(1, 0), Sold.PointAt(1, 1) });


                    if (extend)   //Extend more and trim edges?
                    {
                        S = S.Extend(IsoStatus.North, R * 2, true);
                        S = S.Extend(IsoStatus.East, R * 2, true);
                        S = S.Extend(IsoStatus.South, R * 2, true);
                        S = S.Extend(IsoStatus.West, R * 2, true);
                    }

                    //int L = 0;
                    //int W = 0;
                    //DA.GetData(6, ref L);
                    //DA.GetData(7, ref W);

                    //----------------------------------------------------------------------------------------------------------//
                    //Solution

                    // starting point
                    double u0, v0;
                    S.ClosestPoint(P, out u0, out v0);

                    //Create plane on surface by point and surface normal, plane x,y axis are directions for the net
                    Plane plane = new Plane(S.PointAt(u0, v0), S.NormalAt(u0, v0));
                    plane.Rotate(Rhino.RhinoMath.ToRadians(A), S.NormalAt(u0, v0));
                    Vector3d[] dir = new Vector3d[] { plane.XAxis *R, plane.YAxis *R, plane.XAxis * -R, plane.YAxis * -R };

                    //Surface
                    Curve[] MyNakedEdges     = Sold.ToBrep().DuplicateNakedEdgeCurves(true, false);
                    Curve   SurfaceNakedEdge = Curve.JoinCurves(MyNakedEdges)[0];
                    Mesh[]  meshes           = new Mesh[] { new Mesh(), new Mesh(), new Mesh(), new Mesh() };

                    //----------------------------------------------------------------------------------------------------------//
                    //Create axis
                    // for each direction, walk out (and store list of points)

                    double           u, v;
                    List <Point3d>[] axis = new List <Point3d> [4];
                    List <Arc>[]     arcs = new List <Arc> [4];
                    polylines = new List <Polyline>();

                    for (int i = 0; i < 4; i++)
                    {
                        // set u and v to starting point
                        u = u0;
                        v = v0;
                        List <Point3d> pts        = new List <Point3d>();
                        List <Arc>     arcCurrent = new List <Arc>();


                        for (int j = 0; j < max + 1; j++)
                        {
                            Point3d pt = S.PointAt(u, v); // get point and normal for uv
                            pts.Add(pt);

                            Vector3d srfNormal = S.NormalAt(u, v) * R;

                            Arc arc = new Arc(pt + srfNormal, pt + dir[i], pt - srfNormal); // create forward facing arc and find intersection point with surface (as uv)
                            arcCurrent.Add(arc);
                            CurveIntersections isct = Intersection.CurveSurface(arc.ToNurbsCurve(), S, 0.01, 0.01);


                            if (isct.Count > 0)
                            {
                                isct[0].SurfacePointParameter(out u, out v);
                            }
                            else
                            {
                                break;
                            }

                            // adjust direction vector (new position - old position)
                            dir[i] = S.PointAt(u, v) - pt;
                        }

                        axis[i] = pts;
                        arcs[i] = arcCurrent;
                    }



                    //----------------------------------------------------------------------------------------------------------//
                    //Build up the mesh quads in between
                    Rhino.RhinoApp.ClearCommandHistoryWindow();

                    GH_PreviewUtil preview = new GH_PreviewUtil(GetValue("Animate", false));

                    Mesh         mesh                = new Mesh();                                                                                                                                                   // target mesh
                    Mesh[]       fourMeshes          = new Mesh[4];
                    List <int>[] faceID              = new List <int>[] { new List <int>(), new List <int>(), new List <int>(), new List <int>() };                                                                  //columns lengths
                    List <List <Polyline> >[] strips = new List <List <Polyline> >[] { new List <List <Polyline> >(), new List <List <Polyline> >(), new List <List <Polyline> >(), new List <List <Polyline> >() }; //columns lengths
                    //List<Polyline> cuts = new List<Polyline>();

                    for (int k = 0; k < 4; k++)   //Loop through each axis

                    {
                        Mesh qmesh = new Mesh();                                                         // local mesh for quadrant

                        Point3d[,] quad = new Point3d[axis[k].Count + 10, axis[(k + 1) % 4].Count + 10]; // 2d array of points
                        int[,] qindex   = new int[axis[k].Count + 10, axis[(k + 1) % 4].Count + 10];     // 2d array of points' indices in local mesh

                        int count = 0;

                        //Add 2nd axis particles
                        for (int i = 0; i < axis[(k + 1) % 4].Count; i++)
                        {
                            quad[0, i] = axis[(k + 1) % 4][i];        //store 2nd axis points in point array
                            qmesh.Vertices.Add(axis[(k + 1) % 4][i]); //also add 2nd axis points to mesh
                            qindex[0, i] = count++;                   //store indicies
                        }


                        for (int i = 1; i < quad.GetLength(0); i++)
                        {
                            if (i < axis[k].Count)              // add axis vertex
                            {
                                quad[i, 0] = axis[k][i];        //store 1st axis points in point array
                                qmesh.Vertices.Add(axis[k][i]); //also add 1st axis points to mesh
                                qindex[i, 0] = count++;         //store indicies
                            }


                            int counter = 0;

                            List <Polyline> currentStrip = new List <Polyline>();
                            // for each column attempt to locate a new vertex in the grid
                            for (int j = 1; j < quad.GetLength(1); j++)
                            {
                                // if quad[i - 1, j] doesn't exist, try to add it and continue (or else break the current row)
                                if (quad[i - 1, j] == new Point3d())
                                {
                                    if (j < 2)
                                    {
                                        break;
                                    }

                                    CurveIntersections isct = this.ArcIntersect(S, quad[i - 1, j - 1], quad[i - 1, j - 2], R);

                                    if (isct.Count > 0)
                                    {
                                        quad[i - 1, j] = isct[0].PointB;
                                        qmesh.Vertices.Add(quad[i - 1, j]);
                                        qindex[i - 1, j] = count++;
                                    }
                                    else
                                    {
                                        break;
                                    }
                                }

                                // if quad[i, j - 1] doesn't exist, try to create quad[i, j] by projection and skip mesh face creation
                                if (quad[i, j - 1] == new Point3d())
                                {
                                    if (i < 2)
                                    {
                                        break;
                                    }

                                    CurveIntersections isct = this.ArcIntersect(S, quad[i - 1, j], quad[i - 2, j], R);

                                    if (isct.Count > 0)
                                    {
                                        quad[i, j] = isct[0].PointB;
                                        qmesh.Vertices.Add(quad[i, j]);
                                        qindex[i, j] = count++;

                                        continue;
                                    }
                                }

                                // construct a sphere at each neighbouring vertex ([i,j-1] and [i-1,j]) and intersect

                                Sphere sph1 = new Sphere(quad[i, j - 1], R);
                                Sphere sph2 = new Sphere(quad[i - 1, j], R);
                                Circle cir;

                                if (Intersection.SphereSphere(sph1, sph2, out cir) == SphereSphereIntersection.Circle)
                                {
                                    CurveIntersections cin = Intersection.CurveSurface(NurbsCurve.CreateFromCircle(cir), S, 0.01, 0.01);// intersect circle with surface

                                    // attempt to find the new vertex (i.e not [i-1,j-1])

                                    foreach (IntersectionEvent ie in cin)
                                    {
                                        if ((ie.PointA - quad[i - 1, j - 1]).Length > 0.2 * R)  // compare with a tolerance, rather than exact comparison

                                        {
                                            quad[i, j] = ie.PointA;
                                            qmesh.Vertices.Add(quad[i, j]);
                                            qindex[i, j] = count++;

                                            Point3d[] facePt = new Point3d[] { quad[i, j], quad[i - 1, j], quad[i - 1, j - 1], quad[i, j - 1] };

                                            Sold.ClosestPoint(quad[i, j], out double u1, out double v1);
                                            Sold.ClosestPoint(quad[i - 1, j], out double u2, out double v2);
                                            Sold.ClosestPoint(quad[i - 1, j - 1], out double u3, out double v3);
                                            Sold.ClosestPoint(quad[i, j - 1], out double u4, out double v4);

                                            double tolerance = Rhino.RhinoDoc.ActiveDoc.ModelAbsoluteTolerance * 10;
                                            bool[] flag      = new bool[] {
                                                Sold.PointAt(u1, v1).DistanceTo(quad[i, j]) < tolerance,
                                                Sold.PointAt(u2, v2).DistanceTo(quad[i - 1, j]) < tolerance,
                                                Sold.PointAt(u3, v3).DistanceTo(quad[i - 1, j - 1]) < tolerance,
                                                Sold.PointAt(u4, v4).DistanceTo(quad[i, j - 1]) < tolerance
                                            };



                                            if (flag[0] && flag[1] && flag[2] && flag[3])
                                            {
                                                qmesh.Faces.AddFace(qindex[i, j], qindex[i - 1, j], qindex[i - 1, j - 1], qindex[i, j - 1]);// create quad-face
                                                currentStrip.Add(new Polyline()
                                                {
                                                    quad[i, j], quad[i - 1, j], quad[i - 1, j - 1], quad[i, j - 1], quad[i, j]
                                                });
                                                counter++;
                                            }
                                            else if (flag[0] || flag[1] || flag[2] || flag[3])
                                            {
                                                Polyline temp = new Polyline()
                                                {
                                                    quad[i, j], quad[i - 1, j], quad[i - 1, j - 1], quad[i, j - 1]
                                                };
                                                Polyline trimmedTemp = new Polyline();
                                                //temp = new Polyline() { quad[i, j], quad[i - 1, j], quad[i - 1, j - 1], quad[i, j - 1], quad[i, j] };

                                                double        t = R * 0.1;
                                                HashSet <int> intersectedSurfaceEdgeId = new HashSet <int>();


                                                for (int l = 0; l < 4; l++)
                                                {
                                                    //If point is ons surface
                                                    Sold.ClosestPoint(temp[l], out double cpu, out double cpv);
                                                    if (Sold.PointAt(cpu, cpv).DistanceTo(temp[l]) < Rhino.RhinoDoc.ActiveDoc.ModelAbsoluteTolerance)
                                                    {
                                                        trimmedTemp.Add(temp[l]);
                                                    }


                                                    //Intersect line segment with closed brep
                                                    Line faceSegment = new Line(temp[l], temp[MathUtil.Wrap(l + 1, 4)]);

                                                    Point3d[] meshLinePts = Intersection.MeshLine(cutter, faceSegment, out int[] faceIds);
                                                    if (meshLinePts.Length > 0)
                                                    {
                                                        trimmedTemp.Add(meshLinePts[0]);
                                                    }
                                                }


                                                trimmedTemp.Close();
                                                //cuts.Add(trimmedTemp);
                                            }

                                            break;
                                        }
                                    }

                                    if (preview.Enabled)
                                    {
                                        preview.Clear();
                                        preview.AddMesh(mesh);
                                        preview.AddMesh(qmesh);
                                        preview.Redraw();
                                    }
                                } //if sphere intersection
                            }     //for j

                            if (currentStrip.Count > 0)
                            {
                                strips[k].Add(currentStrip);
                            }
                        }//for i



                        mesh.Append(qmesh);// add local mesh to target
                        fourMeshes[k] = qmesh;
                    }//for k



                    //----------------------------------------------------------------------------------------------------------//
                    //Output



                    mesh.Weld(Math.PI);
                    mesh.Compact();
                    mesh.Normals.ComputeNormals();

                    DA.SetData(0, mesh);
                    DA.SetDataTree(1, NGonsCore.GrasshopperUtil.IE2(axis, 0));

                    this.PreparePreview(mesh, DA.Iteration, null, true, null, mesh.GetEdges());
                    //DA.SetDataList(2, cuts);
                    //DA.SetDataTree(3, NGonsCore.GrasshopperUtil.IE4(patches.ToList(), 0));
                    //DA.SetDataList(4, fourMeshes);
                    //DA.SetDataTree(5, GrasshopperUtil.IE3(strips, 0));

                    preview.Clear();
                }catch (Exception e) {
                    GrasshopperUtil.Debug(e);
                }
            }