Пример #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)
        {
            IGH_GeometricGoo shape = null;

            if (!DA.GetData <IGH_GeometricGoo>(0, ref shape))
            {
                return;
            }

            GeometryBase geo = null;

            if (shape is Mesh || shape is GH_Mesh ||
                shape is Brep || shape is GH_Brep ||
                shape is Surface || shape is GH_Surface ||
                shape is Curve || shape is GH_Curve ||
                shape is GH_Box || shape is GH_Line)
            {
                geo = GH_Convert.ToGeometryBase(shape);
            }
            else
            {
                return;
            }

            var bbox = geo.GetBoundingBox(true);

            DA.SetData(0, bbox.Center);
        }
        //This method creates a bounding box to a geometry in a given plane and returns the min and max coordinates of that box in the plane coordinates.
        private static Tuple <Point3d, Point3d> getMinAndMax(GeometryBase geometry, Plane plane)
        {
            Transform   vali     = Transform.PlaneToPlane(Plane.WorldXY, plane);
            BoundingBox box      = geometry.GetBoundingBox(plane);
            Point3d     minPoint = box.Min;
            Point3d     maxPoint = box.Max;

            return(Tuple.Create(minPoint, maxPoint));
        }
Пример #3
0
        /// <summary>
        /// Extract bounding Z frames -- slice planes -- of a given geometry.
        /// </summary>
        /// <param name="G"></param>
        /// <param name="XSpan"></param>
        /// <param name="YSpan"></param>
        /// <param name="ZSpan"></param>
        /// <param name="DXSpan"></param>
        /// <param name="DYSpan"></param>
        /// <param name="AngleDegrees"></param>
        /// <returns></returns>
        public static List <Plane> SlicePlanes(
            GeometryBase G,
            double LayerHeight,
            double OffsetBottomGlobal = 0,
            double OffsetBottom       = 0,
            double OffsetTop          = 0,
            bool ShouldForceTop       = false)
        {
            List <Plane> Frames = new List <Plane>();

            // Default BoundingBox
            BoundingBox bb = G.GetBoundingBox(true);

            Point3d[] corners     = bb.GetCorners();
            Line      ZLine       = new Line(corners[0], corners[4]);
            double    ZLineLength = ZLine.Length;

            // Safety
            int FrameCap = 150;

            if (ZLineLength / LayerHeight > FrameCap - 1)
            {
                LayerHeight = ZLine.Length / (FrameCap - 1);
            }

            // Z Frames
            double ZAmount     = ZLineLength / LayerHeight;
            bool   HasTopLayer = false;

            for (double i = 0; i <= ZAmount; i++)
            {
                double distance = i * LayerHeight + OffsetBottomGlobal;
                if (i == 0)
                {
                    distance += OffsetBottom;
                }
                if (distance == ZLineLength)
                {
                    HasTopLayer = true;
                }
                if (distance == ZLineLength || !ShouldForceTop && LayerHeight * (i + 1) + OffsetBottomGlobal > ZLineLength)
                {
                    distance += -OffsetTop;
                }
                double param = distance / ZLineLength;
                if (param <= 1)
                {
                    Plane pl;
                    ZLine.ToNurbsCurve().PerpendicularFrameAt(param, out pl);
                    Frames.Add(pl);
                }
            }
            if (ShouldForceTop && !HasTopLayer)
            {
                Plane  pl;
                double param = 1 - OffsetTop / ZLineLength;
                if (param > 1)
                {
                    param = 1;
                }
                ZLine.ToNurbsCurve().PerpendicularFrameAt(param, out pl);
                Frames.Add(pl);
            }
            return(Frames);
        }
Пример #4
0
        /// <summary>
        /// Extract bounding frames to slice a given geometry.
        /// </summary>
        /// <param name="G"></param>
        /// <param name="XSpan"></param>
        /// <param name="YSpan"></param>
        /// <param name="ZSpan"></param>
        /// <param name="DXSpan"></param>
        /// <param name="DYSpan"></param>
        /// <param name="AngleDegrees"></param>
        /// <returns></returns>
        public static List <List <Plane> > BoundingFrames(GeometryBase G, double XSpan, double YSpan, double ZSpan, double DXSpan, double DYSpan, double AngleDegrees = 45.0)
        {
            // Nono.Util
            // BoundingFrames
            // Nono Martínez Alonso (nono.ma)
            // 160622, Autodesk Generative Design

            List <List <Plane> > Frames = new List <List <Plane> >();

            // 1. Default BoundingBox

            BoundingBox bb = G.GetBoundingBox(true);

            Point3d[] corners = bb.GetCorners();

            Line XLine = new Line(corners[0], corners[1]);
            Line YLine = new Line(corners[0], corners[3]);
            Line ZLine = new Line(corners[0], corners[4]);

            List <Plane> XFrames = new List <Plane>();
            List <Plane> YFrames = new List <Plane>();
            List <Plane> ZFrames = new List <Plane>();

            // X Frames
            if (XSpan > 0)
            {
                double XAmount = Math.Floor(XLine.Length / XSpan);
                double XStep   = XLine.Length / XAmount;
                double Xt      = 0;
                for (double i = 0; i <= XAmount; i++)
                {
                    Plane pl;
                    Xt = i * XStep / XLine.Length;
                    XLine.ToNurbsCurve().PerpendicularFrameAt(Xt, out pl);
                    XFrames.Add(pl);
                }
            }

            // Y Frames
            if (YSpan > 0)
            {
                double YAmount = Math.Floor(YLine.Length / YSpan);
                double YStep   = YLine.Length / YAmount;
                double Yt      = 0;
                for (double i = 0; i <= YAmount; i++)
                {
                    Plane pl;
                    Yt = i * YStep / YLine.Length;
                    YLine.ToNurbsCurve().PerpendicularFrameAt(Yt, out pl);
                    YFrames.Add(pl);
                }
            }

            // Z Frames
            double ZAmount = ZLine.Length / ZSpan;

            for (double i = 0; i <= ZAmount; i++)
            {
                Plane pl;
                ZLine.ToNurbsCurve().PerpendicularFrameAt(i * ZSpan / ZLine.Length, out pl);
                ZFrames.Add(pl);
            }

            // 2. Diagonal BoundingBox

            Transform rotate     = Transform.Rotation(-V2GMath.DEGREES_TO_RADIANS * AngleDegrees, new Vector3d(0, 0, 1), bb.Center);
            Transform rotateBack = Transform.Rotation(V2GMath.DEGREES_TO_RADIANS * AngleDegrees, new Vector3d(0, 0, 1), bb.Center);

            G.Transform(rotate);

            BoundingBox Dbb       = G.GetBoundingBox(true);
            Point3d     DbbCenter = Dbb.Center;

            Point3d[] Dcorners = Dbb.GetCorners();

            Line DXLine = new Line(Dcorners[0], Dcorners[1]);
            Line DYLine = new Line(Dcorners[0], Dcorners[3]);

            List <Plane> DXFrames = new List <Plane>();
            List <Plane> DYFrames = new List <Plane>();

            // DX Frames
            if (DXSpan > 0)
            {
                double DXAmount = Math.Floor(DXLine.Length / DXSpan);
                double DXStep   = DXLine.Length / DXAmount;
                double DXt      = 0;
                for (double i = 0; i <= DXAmount; i++)
                {
                    Plane pl;
                    DXt = i * DXStep / DXLine.Length;
                    DXLine.ToNurbsCurve().PerpendicularFrameAt(DXt, out pl);
                    pl.Transform(rotateBack);

                    DXFrames.Add(pl);
                }
            }

            // DY Frames
            if (DYSpan > 0)
            {
                double DYAmount = Math.Floor(DYLine.Length / DYSpan);
                double DYStep   = DYLine.Length / DYAmount;
                double DYt      = 0;
                for (double i = 0; i <= DYAmount; i++)
                {
                    Plane pl;
                    DYt = i * DYStep / DYLine.Length;
                    DYLine.ToNurbsCurve().PerpendicularFrameAt(DYt, out pl);
                    pl.Transform(rotateBack);
                    DYFrames.Add(pl);
                }
            }

            Frames.Add(XFrames);
            Frames.Add(YFrames);
            Frames.Add(ZFrames);
            Frames.Add(DXFrames);
            Frames.Add(DYFrames);

            return(Frames);
        }
Пример #5
0
 public Primitive(Mesh m, Part p)
 {
     geometry = m; ClippingBox = geometry.GetBoundingBox(false); part = p;
 }
Пример #6
0
 public Primitive(Curve c)
 {
     geometry = c; ClippingBox = geometry.GetBoundingBox(false);
 }
Пример #7
0
 public Primitive(PointCloud pc, Part p)
 {
     geometry = pc; ClippingBox = geometry.GetBoundingBox(false); part = p;
 }
Пример #8
0
 public Primitive(Point p)
 {
     geometry = p; ClippingBox = geometry.GetBoundingBox(false);
 }
Пример #9
0
        private List <string> SaveAdobeDocument(string savePath, List <GeometryBase> objs, AdobeDocType type)
        {
            SortedDictionary <string, List <GeometryBase> > geometries = new SortedDictionary <string, List <GeometryBase> >();
            GeometryBase boundObj = null;

            List <string> outputFiles = new List <string>();

            DebugEvent($"{type}_BOUND");

            foreach (var obj in objs)
            {
                if (obj.GetUserString($"{type}_BOUND") == $"{type}_BOUND")
                {
                    boundObj = obj;
                    DebugEvent($"{type}文档找到边界");
                    continue;
                }

                string page = obj.GetUserString($"{type}_PAGE");

                if (type == AdobeDocType.EPS && Directory.Exists(savePath))
                {
                    page = Path.Combine(savePath, page + ".eps");
                    outputFiles.Add(page);
                }

                if (!geometries.ContainsKey(page))
                {
                    geometries.Add(page, new List <GeometryBase>());
                }

                geometries[page].Add(obj);
            }

            if (geometries.Count == 0 || boundObj == null)
            {
                return(null);
            }

            boundObj.GetBoundingBox(Plane.WorldXY, out Box boundBox);

            try
            {
                var eps = new EncapsulatedPostScript(boundBox, savePath);

                if (type == AdobeDocType.PDF)
                {
                    eps.SavePDF(geometries);
                    outputFiles.Add(savePath);
                }
                else if (type == AdobeDocType.EPS)
                {
                    eps.SaveEPS(geometries);
                }
            }
            catch (Exception ex)
            {
                ErrorEvent(this, ex.Message);
            }

            return(outputFiles);
        }
        /// <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)
        {
            IGH_GeometricGoo shape    = null;
            int            num        = -1;
            int            ite        = -1;
            List <Point3d> attractors = new List <Point3d>();
            List <double>  radiuses   = new List <double>();
            List <double>  weights    = new List <double>();

            if (!DA.GetData <IGH_GeometricGoo>(0, ref shape))
            {
                return;
            }
            if (!DA.GetData(1, ref num))
            {
                return;
            }
            if (!DA.GetData(2, ref ite))
            {
                return;
            }
            DA.GetDataList(3, attractors);
            DA.GetDataList(4, radiuses);
            DA.GetDataList(5, weights);

            GeometryBase geo = GH_Convert.ToGeometryBase(shape);

            var points   = new Point3dList();
            var attracts = new Point3dList(attractors);
            var rnd      = new Random();

            var bbox = geo.GetBoundingBox(true);

            for (int i = 0; i < num; i++)
            {
                if (points.Count == 0)
                {
                    var rndpt = CreateRandomPoint(rnd, geo, bbox);
                    points.Add(rndpt);
                }
                else
                {
                    double  fdist = -1;
                    Point3d fpos  = new Point3d();
                    for (int t = 0; t < Math.Max(Math.Min(ite, i), 10); t++)
                    {
                        var nrndpt = CreateRandomPoint(rnd, geo, bbox);

                        double nattractdist = 1;
                        for (int n = 0; n < attracts.Count; n++)
                        {
                            var nattract = attracts[n];
                            var rad      = radiuses[Math.Min(n, radiuses.Count - 1)];
                            var pow      = weights[Math.Min(n, radiuses.Count - 1)];

                            var ntdist = Math.Pow(JellyUtility.Remap(Math.Min(nattract.DistanceTo(nrndpt), rad), 0, rad, 0, 1.0), pow);
                            nattractdist *= ntdist;
                        }

                        var nindex = points.ClosestIndex(nrndpt);
                        var npos   = points[nindex];

                        var ndist = npos.DistanceTo(nrndpt) * nattractdist;

                        if (fdist < ndist)
                        {
                            fdist = ndist;
                            fpos  = nrndpt;
                        }
                    }
                    points.Add(fpos);
                }
            }


            DA.SetDataList(0, points);
        }
        ///<summary>The only instance of this command.</summary>
        ///<param name="doc" RhinoDoc></param>
        ///<param name="mode" Run mode></param>
        ///<returns>returns sucess if doc is successfully created </returns>
        protected override Result RunCommand(RhinoDoc doc, RunMode mode)
        {
            #region set all the file parameters

            pdfOptionForm = new PDFOptionForm();
            Application.Run(pdfOptionForm);
            getSelectedOption = PDFOptionForm.optionsSelected;

            myUniqueFileName = string.Format(@"{0}" + ext, Guid.NewGuid());
            string logFilePath = Rhino.ApplicationSettings.FileSettings.WorkingFolder + "\\Log-" + DateTime.Now.GetHashCode().ToString() + ".txt";
            string curveType   = "C";
            try
            {
                string[] checkFileName = Rhino.ApplicationSettings.FileSettings.RecentlyOpenedFiles()[0].ToString().Split('\\');
                int      checklength   = checkFileName.Length;
                rhinoFile = Rhino.ApplicationSettings.FileSettings.RecentlyOpenedFiles()[0].ToString().Split('\\')[--checklength];
            }
            catch (FileNotFoundException fnf) { logFile(fnf.Message); }
            catch (IndexOutOfRangeException ioor) { logFile(ioor.Message); }

            string rhinoFileName = rhinoFile.Split('.')[0];
            string filename      = Rhino.ApplicationSettings.FileSettings.WorkingFolder + '\\' + rhinoFileName + "-" + myUniqueFileName;

            #endregion

            Rhino.RhinoApp.RunScript("-_Save Enter", false);

            logFile("Process started for ---> " + rhinoFileName + "-" + myUniqueFileName);

            PdfDocument document = new PdfDocument();
            PdfPage     page     = document.AddPage();

            XGraphics gfx  = XGraphics.FromPdfPage(page);
            XFont     font = new XFont("Verdana", 20, XFontStyle.Bold);

            #region Check the selected curve
            GetObject go = new GetObject();

            go.GroupSelect     = true;
            go.SubObjectSelect = false;
            go.EnableClearObjectsOnEntry(false);
            go.EnableUnselectObjectsOnExit(false);
            go.DeselectAllBeforePostSelect = false;
            go.EnableSelPrevious(true);
            go.EnablePreSelect(true, false);
            go.GeometryFilter = ObjectType.AnyObject;

            GetResult result = go.GetMultiple(1, -1);

            if (go.CommandResult() != Rhino.Commands.Result.Success)
            {
                return(go.CommandResult());
            }

            RhinoApp.WriteLine("{0} objects are selected.", go.ObjectCount);

            #endregion

            // Process the list of objects
            logFile("Processing List of Object");

            #region set the paramenters for Xgraph to process shapes

            List <GeometryBase> geoList = new List <GeometryBase>();

            double minX, minY, maxX, maxY;
            minX = double.MaxValue;
            minY = double.MaxValue;

            maxX = double.MinValue;
            maxY = double.MinValue;

            List <Curve>      curveList      = new List <Curve>();
            List <TextEntity> textEntityList = new List <TextEntity>();

            List <Circle>   circleList = new List <Circle>();
            List <Polyline> polyList   = new List <Polyline>();
            Circle          circleCurve;
            Polyline        polygon;

            #endregion

            for (int i = 0; i < go.ObjectCount; i++)
            {
                // Check the type of the Object and process differently
                Curve curve = go.Object(i).Curve();

                if (go.Object(i).Curve().TryGetCircle(out circleCurve))
                {
                    circleList.Add(circleCurve);
                }
                if (go.Object(i).Curve().TryGetPolyline(out polygon))
                {
                    polyList.Add(polygon);
                }
                if (curve != null)
                {
                    curveList.Add(curve);
                }

                TextEntity te = go.Object(i).TextEntity();

                if (te != null)
                {
                    textEntityList.Add(te);
                }

                GeometryBase geo  = go.Object(i).Geometry();
                BoundingBox  bbox = geo.GetBoundingBox(Rhino.Geometry.Plane.WorldXY);

                if (bbox.Min.X < minX)
                {
                    minX = bbox.Min.X;
                }
                if (bbox.Min.Y < minY)
                {
                    minY = bbox.Min.Y;
                }
                if (bbox.Max.X > maxX)
                {
                    maxX = bbox.Max.X;
                }
                if (bbox.Max.Y > maxY)
                {
                    maxY = bbox.Max.Y;
                }

                geoList.Add(geo);
            }

            page.Height = maxY - minY;
            page.Width  = maxX - minX;


            foreach (GeometryBase g in geoList)
            {
                if (g.GetType().Equals(typeof(PolyCurve)))
                {
                    //System.Windows.Forms.MessageBox.Show("PolyCurve changed");
                    PolyCurve polyCurve = (PolyCurve)g;
                    curveType = "NC";
                    break;
                }
                else if (g.GetType().Equals(typeof(Curve)))
                {
                    System.Windows.Forms.MessageBox.Show("Curve");
                    Curve curve = (Curve)g;
                }
                else if (g.GetType().Equals(typeof(TextEntity)))
                {
                    System.Windows.Forms.MessageBox.Show("TextEntity");
                    TextEntity textEntity = (TextEntity)g;
                    curveType = "T";
                }
            }

            logFile("Checking the pattern");
            if (curveType.Equals("C") || curveType.Equals("T"))
            {
                logFile("Objects processed sucessfully");

                double x1, y1, width, height;

                logFile("Creating Circles on the PDF");
                //Loop to draw the circles
                foreach (Circle c in circleList)
                {
                    XPen pen = new XPen(XColors.Black, 0.5);
                    x1     = c.BoundingBox.Min.X - minX;
                    y1     = maxY - c.BoundingBox.Max.Y;
                    width  = c.BoundingBox.Max.X - c.BoundingBox.Min.X;
                    height = c.BoundingBox.Max.Y - c.BoundingBox.Min.Y;
                    gfx.DrawEllipse(XBrushes.Black, x1, y1, width, height);
                }

                //Loop used to draw rectangles
                foreach (Polyline p in polyList)
                {
                    XPen pen = new XPen(XColors.Black, 0.5);
                    x1     = p.BoundingBox.Min.X - minX;
                    y1     = maxY - p.BoundingBox.Max.Y;
                    width  = p.BoundingBox.Max.X - p.BoundingBox.Min.X;
                    height = p.BoundingBox.Max.Y - p.BoundingBox.Min.Y;
                    XPoint   p1     = new XPoint(x1, y1);
                    XPoint   p2     = new XPoint(x1 + width, y1);
                    XPoint   p3     = new XPoint(x1, y1 + height);
                    XPoint   p4     = new XPoint(x1 + width, y1 + height);
                    XRect    rect   = new XRect(x1, y1, width, height);
                    XPoint[] xPoint = new XPoint[] { p1, p2, p4, p3 };
                    //XPoint mid = new XPoint( (x1 + x1)/2);
                    XGraphicsState gs = gfx.Save();
                    gfx.RotateAtTransform(-45, p1);
                    gfx.DrawPolygon(pen, XBrushes.Black, xPoint, XFillMode.Alternate);
                    gfx.Restore(gs);
                }



                #region Print the PDF as per the option selected
                if (getSelectedOption.Equals('N'))
                {
                    logFile("Normal PDF feature was selected");
                    document.Save(filename);
                    logFile("Document saved successfully - " + Rhino.ApplicationSettings.FileSettings.WorkingFolder);
                }
                if (getSelectedOption.Equals('C'))
                {
                    logFile("Compressed PDF feature was selected");
                    CompressMyPdf(document);
                    string compressedFileName = Rhino.ApplicationSettings.FileSettings.WorkingFolder + '\\' + "C-" + rhinoFileName + "-" + myUniqueFileName;
                    document.Save(compressedFileName);
                }
                if (getSelectedOption.Equals('E'))
                {
                    logFile("Encrypted PDF feature was selected");
                    EncryptMyPdf(document);
                    string encryptPdf = Rhino.ApplicationSettings.FileSettings.WorkingFolder + '\\' + "E-" + rhinoFileName + "-" + myUniqueFileName;
                    document.Save(encryptPdf);
                }
                if (getSelectedOption.Equals('P'))
                {
                    logFile("Password Protection PDF feature was selected");
                    PasswordProtectMyPdf(document);
                    string passwordProtectPdf = Rhino.ApplicationSettings.FileSettings.WorkingFolder + '\\' + "PP-" + rhinoFileName + "-" + myUniqueFileName;
                    document.Save(passwordProtectPdf);
                }

                #endregion

                logFile("Document saved successfully - " + Rhino.ApplicationSettings.FileSettings.WorkingFolder);

                logFile("Panel perforated successfully. Check File --> " + rhinoFileName + "-" + myUniqueFileName);
                System.Windows.Forms.MessageBox.Show("         <----SUCCESS---->       " + Environment.NewLine + Environment.NewLine + " Pannels perforated Successfully. ");
            }
            else
            {
                System.Windows.Forms.MessageBox.Show("                           ERROR!     " + Environment.NewLine + Environment.NewLine + "The curve you have selected contains some invalid shape." + Environment.NewLine + " Please select the appropriate patterns. ");
                logFile("Please select the appropriate pattern");
            }

            logFile("----------------- WAITING FOR THE NEXT PANEL PERFORATION ---------------------");

            return(Result.Success);
        }
Пример #12
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)
        {
            // 1. Retrieve and validate data
            var          cell             = new UnitCell();
            GeometryBase designSpace      = null;
            Plane        orientationPlane = Plane.Unset;
            double       xCellSize        = 0;
            double       yCellSize        = 0;
            double       zCellSize        = 0;
            double       minLength        = 0; // the trim tolerance (i.e. minimum strut length)
            double       maxLength        = 0;
            bool         strictlyIn       = false;

            if (!DA.GetData(0, ref cell))
            {
                return;
            }
            if (!DA.GetData(1, ref designSpace))
            {
                return;
            }
            if (!DA.GetData(2, ref orientationPlane))
            {
                return;
            }
            if (!DA.GetData(3, ref xCellSize))
            {
                return;
            }
            if (!DA.GetData(4, ref yCellSize))
            {
                return;
            }
            if (!DA.GetData(5, ref zCellSize))
            {
                return;
            }
            if (!DA.GetData(6, ref minLength))
            {
                return;
            }
            if (!DA.GetData(7, ref maxLength))
            {
                return;
            }
            if (!DA.GetData(8, ref strictlyIn))
            {
                return;
            }

            if (!cell.isValid)
            {
                return;
            }
            if (!designSpace.IsValid)
            {
                return;
            }
            if (!orientationPlane.IsValid)
            {
                return;
            }
            if (xCellSize == 0)
            {
                return;
            }
            if (yCellSize == 0)
            {
                return;
            }
            if (zCellSize == 0)
            {
                return;
            }
            if (minLength >= xCellSize || minLength >= yCellSize || minLength >= zCellSize)
            {
                AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Tolerance parameter cannot be larger than the unit cell dimensions.");
                return;
            }
            // 2. Validate the design space
            int spaceType = FrameTools.ValidateSpace(ref designSpace);

            if (spaceType == 0)
            {
                AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Design space must be a closed Brep, Mesh or Surface");
                return;
            }

            double tol = RhinoDoc.ActiveDoc.ModelAbsoluteTolerance;

            // 3. Compute oriented bounding box and its corner points
            Box bBox = new Box();

            designSpace.GetBoundingBox(orientationPlane, out bBox);
            Point3d[] bBoxCorners = bBox.GetCorners();
            //    Set basePlane based on the bounding box
            Plane basePlane = new Plane(bBoxCorners[0], bBoxCorners[1], bBoxCorners[3]);

            // 4. Determine number of iterations required to fill the box, and package into array
            double xLength = bBoxCorners[0].DistanceTo(bBoxCorners[1]);
            double yLength = bBoxCorners[0].DistanceTo(bBoxCorners[3]);
            double zLength = bBoxCorners[0].DistanceTo(bBoxCorners[4]);
            int    nX      = (int)Math.Ceiling(xLength / xCellSize); // Roundup to next integer if non-integer
            int    nY      = (int)Math.Ceiling(yLength / yCellSize);
            int    nZ      = (int)Math.Ceiling(zLength / zCellSize);

            float[] N = new float[3] {
                nX, nY, nZ
            };

            // 5. Initialize nodeTree
            var lattice = new Lattice();

            // 6. Prepare cell (this is a UnitCell object)
            cell = cell.Duplicate();
            cell.FormatTopology();

            // 7. Define iteration vectors in each direction (accounting for Cell Size)
            Vector3d vectorU = xCellSize * basePlane.XAxis;
            Vector3d vectorV = yCellSize * basePlane.YAxis;
            Vector3d vectorW = zCellSize * basePlane.ZAxis;

            // 8. Map nodes to design space
            //    Loop through the uvw cell grid
            for (int u = 0; u <= N[0]; u++)
            {
                for (int v = 0; v <= N[1]; v++)
                {
                    for (int w = 0; w <= N[2]; w++)
                    {
                        // Construct cell path in tree
                        GH_Path treePath = new GH_Path(u, v, w);
                        // Fetch the list of nodes to append to, or initialise it
                        var nodeList = lattice.Nodes.EnsurePath(treePath);

                        // This loop maps each node in the cell
                        for (int i = 0; i < cell.Nodes.Count; i++)
                        {
                            double   usub = cell.Nodes[i].X;                  // u-position within unit cell (local)
                            double   vsub = cell.Nodes[i].Y;                  // v-position within unit cell (local)
                            double   wsub = cell.Nodes[i].Z;                  // w-position within unit cell (local)
                            double[] uvw  = { u + usub, v + vsub, w + wsub }; // uvw-position (global)

                            // Check if the node belongs to another cell (i.e. it's relative path points outside the current cell)
                            bool isOutsideCell = (cell.NodePaths[i][0] > 0 || cell.NodePaths[i][1] > 0 || cell.NodePaths[i][2] > 0);

                            // Check if current uvw-position is beyond the upper boundary
                            bool isOutsideSpace = (uvw[0] > N[0] || uvw[1] > N[1] || uvw[2] > N[2]);

                            if (isOutsideCell || isOutsideSpace)
                            {
                                nodeList.Add(null);
                            }
                            else
                            {
                                // Compute position vector
                                Vector3d V       = uvw[0] * vectorU + uvw[1] * vectorV + uvw[2] * vectorW;
                                var      newNode = new LatticeNode(basePlane.Origin + V);

                                // Check if point is inside - use unstrict tolerance, meaning it can be outside the surface by the specified tolerance
                                bool isInside = FrameTools.IsPointInside(designSpace, newNode.Point3d, spaceType, tol, strictlyIn);

                                // Set the node state (it's location wrt the design space)
                                if (isInside)
                                {
                                    newNode.State = LatticeNodeState.Inside;
                                }
                                else
                                {
                                    newNode.State = LatticeNodeState.Outside;
                                }

                                // Add node to tree
                                nodeList.Add(newNode);
                            }
                        }
                    }
                }
            }

            // 9. Map struts to the node tree
            lattice.UniformMapping(cell, designSpace, spaceType, N, minLength, maxLength);

            // 10. Set output
            DA.SetDataList(0, lattice.Struts);
        }