Beispiel #1
0
 private void TraverseRelationshipsAndMarkColumns(LatticeNode ln, int DistanceFromKey)
 {
     for (int i = ln.DistanceFromKey + 1; i <= maxDistanceFromKey; i++) //enumerate the levels above this node
     {
         List <int> loopOrder = new List <int>();
         if (LayoutMethod == VisualizeAttributeLattice.LatticeLayoutMethod.ShortSingleLevelRelationshipsFirst)
         {
             for (int j = i; j <= maxDistanceFromKey; j++) //enumerate the distance from the next node to the top... helps to start with a bunch of short relationships
             {
                 loopOrder.Add(j);
             }
         }
         else
         {
             int lastJ = -1;
             for (int j = i + 1; lastJ != i; j = (j >= maxDistanceFromKey ? i : j + 1)) //enumerate the distance from the next node to the top... helps to start with a bunch of short relationships
             {
                 lastJ = j;
                 loopOrder.Add(j);
             }
         }
         foreach (int j in loopOrder) //enumerate the distance from the next node to the top... helps to start with a bunch of short relationships
         {
             foreach (LatticeRelationship lr in ln.Relationships)
             {
                 LatticeNode r = lr.node;
                 if (r.DistanceFromKey == i && r.DistanceFromKey + r.MinRelationshipDistance == j)
                 {
                     if (ln.MinRelationshipColumnDistance < Math.Abs(ln.MinColumnPosition - r.MinColumnPosition))
                     {
                         ln.MinRelationshipColumnDistance = Math.Abs(ln.MinColumnPosition - r.MinColumnPosition);
                     }
                     if (r.DistanceFromKey >= DistanceFromKey)
                     {
                         if (r.MaxColumnPosition == arColumnsUsed[DistanceFromKey - 1] && ln.MaxColumnPosition > r.MaxColumnPosition)
                         {
                             if (r.MinColumnPosition == 0)
                             {
                                 r.MinColumnPosition = ln.MinColumnPosition;
                             }
                             arColumnsUsed[DistanceFromKey - 1] = ln.MaxColumnPosition;
                             r.MaxColumnPosition = arColumnsUsed[DistanceFromKey - 1];
                             TraverseRelationshipsAndMarkColumns(r, DistanceFromKey + 1);
                         }
                         else if (r.MinColumnPosition == 0)
                         {
                             r.MinColumnPosition = Math.Max(arColumnsUsed[DistanceFromKey - 1] + 1, ln.MinColumnPosition);
                             r.MaxColumnPosition = Math.Max(arColumnsUsed[DistanceFromKey - 1] + 1, ln.MaxColumnPosition);
                             arColumnsUsed[DistanceFromKey - 1] = r.MaxColumnPosition;
                             TraverseRelationshipsAndMarkColumns(r, DistanceFromKey + 1);
                         }
                     }
                 }
             }
         }
     }
 }
Beispiel #2
0
    private void TraverseRelationshipsAndDraw(LatticeNode ln, Graphics g)
    {
        if (ln.IsKey)
        {
            ln.x = canvas.Width / 2 - NODE_WIDTH / 2;
        }
        else if (ln.MinColumnPosition == ln.MaxColumnPosition)
        {
            ln.x = ln.MinColumnPosition * NODE_SPACING + (ln.MinColumnPosition - 1) * NODE_WIDTH;
        }
        else
        {
            ln.x = (((float)ln.MaxColumnPosition - ln.MinColumnPosition) / 2 + ln.MinColumnPosition) * NODE_SPACING + ((((float)ln.MaxColumnPosition - ln.MinColumnPosition) / 2 + ln.MinColumnPosition) - 1) * NODE_WIDTH;
        }
        ln.y = canvas.Height - (maxNodeHeight + NODE_SPACING) * (ln.DistanceFromKey + 1);

        ln.Rendered = true;

        foreach (LatticeRelationship lr in ln.Relationships)
        {
            LatticeNode r = lr.node;
            if (!r.Rendered)
            {
                TraverseRelationshipsAndDraw(r, g);
            }
            Pen pen = new Pen((lr.Visible ? Color.Green : Color.Gray), 1.55F);
            pen.DashStyle = (lr.RelationshipType == RelationshipType.Rigid ? DashStyle.Solid : DashStyle.Dash);
            if (lr.RelationshipType != RelationshipType.Rigid)
            {
                pen.DashPattern = new float[] { 1F, 1.55F };
                //pen.DashOffset = (int)((new Random()).NextDouble()*10);
            }
            if (r.DistanceFromKey - ln.DistanceFromKey > 1 && ln.x == r.x)
            {
                //multilevel relationships which are completely vertical could never be seen
                pen.Width       = 5;
                pen.Color       = Color.Red;
                pen.DashStyle   = DashStyle.Dash;
                pen.DashPattern = new float[] { 0.4F, 1.5F };
            }

            //purposefully don't put an end cap on it... we could note the cardinality, but according to http://msdn2.microsoft.com/en-us/library/ms176124.aspx that has no impact
            //GraphicsPath hPath = new GraphicsPath();
            //hPath.AddLine(new Point(-2, -2), new Point(2, -2));
            //CustomLineCap cap = new CustomLineCap(null, hPath);
            //pen.CustomEndCap = cap;

            //g.DrawLine(new Pen(Color.White, 7), ln.x + NODE_WIDTH / 2, ln.y, r.x + NODE_WIDTH / 2, r.y + maxNodeHeight); //if we get a bunch of redundant relationships with crossing lines, we might want to turn this on
            g.DrawLine(pen, ln.x + NODE_WIDTH / 2, ln.y, r.x + NODE_WIDTH / 2, r.y + maxNodeHeight);
        }
    }
Beispiel #3
0
    private int TraverseRelationshipsAndMarkMaxDepth(LatticeNode ln, int DistanceFromKey)
    {
        int depth = DistanceFromKey;

        foreach (LatticeRelationship lr in ln.Relationships)
        {
            LatticeNode r = lr.node;
            if (r.DistanceFromKey >= DistanceFromKey)
            {
                depth = Math.Max(depth, TraverseRelationshipsAndMarkMaxDepth(r, DistanceFromKey + 1));
            }
        }
        ln.MaxRelationshipDepth = depth;
        return(depth);
    }
Beispiel #4
0
 private void TraverseRelationshipsAndMarkMinDistance(LatticeNode ln, int DistanceFromKey)
 {
     foreach (LatticeRelationship lr in ln.Relationships)
     {
         LatticeNode r = lr.node;
         if (r.DistanceFromKey == DistanceFromKey)
         {
             TraverseRelationshipsAndMarkMinDistance(r, DistanceFromKey + 1);
         }
         if (ln.MinRelationshipDistance < r.DistanceFromKey - ln.DistanceFromKey)
         {
             ln.MinRelationshipDistance = r.DistanceFromKey - ln.DistanceFromKey;
         }
     }
 }
Beispiel #5
0
 private void TraverseRelationshipsAndMarkDistance(LatticeNode ln, int DistanceFromKey)
 {
     foreach (LatticeRelationship lr in ln.Relationships)
     {
         LatticeNode r = lr.node;
         if (r.DistanceFromKey < DistanceFromKey)
         {
             r.DistanceFromKey = DistanceFromKey;
         }
         if (DistanceFromKey + 1 < Nodes.Count) //prevent circular references from causing an infinite loop
         {
             TraverseRelationshipsAndMarkDistance(r, DistanceFromKey + 1);
         }
     }
 }
 private int TraverseRelationshipsAndMarkMaxDepth(LatticeNode ln, int DistanceFromKey)
 {
     int depth = DistanceFromKey;
     foreach (LatticeRelationship lr in ln.Relationships)
     {
         LatticeNode r = lr.node;
         if (r.DistanceFromKey >= DistanceFromKey)
         {
             depth = Math.Max(depth, TraverseRelationshipsAndMarkMaxDepth(r, DistanceFromKey + 1));
         }
     }
     ln.MaxRelationshipDepth = depth;
     return depth;
 }
 private void TraverseRelationshipsAndMarkMinDistance(LatticeNode ln, int DistanceFromKey)
 {
     foreach (LatticeRelationship lr in ln.Relationships)
     {
         LatticeNode r = lr.node;
         if (r.DistanceFromKey == DistanceFromKey)
         {
             TraverseRelationshipsAndMarkMinDistance(r, DistanceFromKey + 1);
         }
         if (ln.MinRelationshipDistance < r.DistanceFromKey - ln.DistanceFromKey)
         {
             ln.MinRelationshipDistance = r.DistanceFromKey - ln.DistanceFromKey;
         }
     }
 }
 private void TraverseRelationshipsAndMarkDistance(LatticeNode ln, int DistanceFromKey)
 {
     foreach (LatticeRelationship lr in ln.Relationships)
     {
         LatticeNode r = lr.node;
         if (r.DistanceFromKey < DistanceFromKey) r.DistanceFromKey = DistanceFromKey;
         if (DistanceFromKey + 1 < Nodes.Count) //prevent circular references from causing an infinite loop
         {
             TraverseRelationshipsAndMarkDistance(r, DistanceFromKey + 1);
         }
     }
 }
Beispiel #9
0
 public LatticeRelationship(LatticeNode ln, RelationshipType rt, bool visible)
 {
     this.node             = ln;
     this.RelationshipType = rt;
     this.Visible          = visible;
 }
Beispiel #10
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);
        }
    private void TraverseRelationshipsAndDraw(LatticeNode ln, Graphics g)
    {
        if (ln.IsKey)
        {
            ln.x = canvas.Width / 2 - NODE_WIDTH / 2;
        }
        else if (ln.MinColumnPosition == ln.MaxColumnPosition)
        {
            ln.x = ln.MinColumnPosition * NODE_SPACING + (ln.MinColumnPosition - 1) * NODE_WIDTH;
        }
        else
        {
            ln.x = (((float)ln.MaxColumnPosition - ln.MinColumnPosition) / 2 + ln.MinColumnPosition) * NODE_SPACING + ((((float)ln.MaxColumnPosition - ln.MinColumnPosition) / 2 + ln.MinColumnPosition) - 1) * NODE_WIDTH;
        }
        ln.y = canvas.Height - (maxNodeHeight + NODE_SPACING) * (ln.DistanceFromKey + 1);

        ln.Rendered = true;

        foreach (LatticeRelationship lr in ln.Relationships)
        {
            LatticeNode r = lr.node;
            if (!r.Rendered)
            {
                TraverseRelationshipsAndDraw(r, g);
            }
            Pen pen = new Pen((lr.Visible ? Color.Green : Color.Gray), 1.55F);
            pen.DashStyle = (lr.RelationshipType == RelationshipType.Rigid ? DashStyle.Solid : DashStyle.Dash);
            if (lr.RelationshipType != RelationshipType.Rigid)
            {
                pen.DashPattern = new float[] { 1F, 1.55F };
                //pen.DashOffset = (int)((new Random()).NextDouble()*10);
            }
            if (r.DistanceFromKey - ln.DistanceFromKey > 1 && ln.x == r.x)
            {
                //multilevel relationships which are completely vertical could never be seen
                pen.Width = 5;
                pen.Color = Color.Red;
                pen.DashStyle = DashStyle.Dash;
                pen.DashPattern = new float[] { 0.4F, 1.5F };
            }

            //purposefully don't put an end cap on it... we could note the cardinality, but according to http://msdn2.microsoft.com/en-us/library/ms176124.aspx that has no impact
            //GraphicsPath hPath = new GraphicsPath();
            //hPath.AddLine(new Point(-2, -2), new Point(2, -2));
            //CustomLineCap cap = new CustomLineCap(null, hPath);
            //pen.CustomEndCap = cap;

            //g.DrawLine(new Pen(Color.White, 7), ln.x + NODE_WIDTH / 2, ln.y, r.x + NODE_WIDTH / 2, r.y + maxNodeHeight); //if we get a bunch of redundant relationships with crossing lines, we might want to turn this on
            g.DrawLine(pen, ln.x + NODE_WIDTH / 2, ln.y, r.x + NODE_WIDTH / 2, r.y + maxNodeHeight);
        }
    }
Beispiel #12
0
    public Bitmap Render()
    {
        canvas = new Bitmap(NODE_WIDTH, 1000);
        Graphics g = Graphics.FromImage(canvas);

        g.SmoothingMode = SmoothingMode.AntiAlias;

        StringFormat centered = new StringFormat();

        centered.Alignment = StringAlignment.Center;

        //find out the max node height so that all nodes can be sized the same
        //also find the key attribute
        LatticeNode key = null;

        foreach (LatticeNode ln in this.Nodes.Values)
        {
            SizeF sz = g.MeasureString(ln.Text, NODE_FONT, NODE_WIDTH, centered);
            ln.TextHeight = sz.Height;
            if (maxNodeHeight < ln.TextHeight + 10)
            {
                maxNodeHeight = ln.TextHeight + 10;
            }
            if (ln.IsKey)
            {
                key = ln;
            }
        }
        g.Dispose();
        g = null;
        canvas.Dispose();
        canvas = null;

        //mark distance from key
        TraverseRelationshipsAndMarkDistance(key, 1);
        TraverseRelationshipsAndMarkMinDistance(key, 1);

        //throw error if any nodes aren't related to the key
        foreach (LatticeNode ln in this.Nodes.Values)
        {
            if (ln.DistanceFromKey == 0 && !ln.IsKey)
            {
                throw new Exception("Node " + ln.Text + " is not related to the key directly or indirectly!");
            }
        }

        //figure out the number of nodes wide and tall
        for (int i = 1; i < Nodes.Count; i++)
        {
            int tempCount = 0;
            foreach (LatticeNode ln in this.Nodes.Values)
            {
                if (ln.DistanceFromKey == i)
                {
                    tempCount++;
                }
            }
            if (maxNodesAcross < tempCount)
            {
                maxNodesAcross = tempCount;
            }
            if (tempCount == 0)
            {
                break;
            }
            else
            {
                maxDistanceFromKey = i;
            }
        }

        if (LayoutMethod == VisualizeAttributeLattice.LatticeLayoutMethod.DeepestPathsFirst)
        {
            arColumnsUsed = new int[maxDistanceFromKey];
            foreach (LatticeNode ln in this.Nodes.Values)
            {
                if (!ln.IsKey)
                {
                    maxNodesAcross = Math.Max(maxNodesAcross, ++arColumnsUsed[ln.DistanceFromKey - 1]);
                }
            }
            if (maxNodesAcross % 2 == 0)
            {
                maxNodesAcross++;                          //make sure it's an odd number so the center column of nodes will be in center
            }
            TraverseRelationshipsAndMarkMaxDepth(key, 1);
            arLayoutMatrix = new bool[maxDistanceFromKey, maxNodesAcross];
            for (int i = maxDistanceFromKey + 1; i >= 0; i--)
            {
                TraverseDeepestRelationshipsAndMarkColumns(key, 1, i);
            }
        }
        else
        {
            //holds the number of columns which have been used so far
            arColumnsUsed = new int[maxDistanceFromKey];
            TraverseRelationshipsAndMarkColumns(key, 1);
            for (int i = 0; i < maxDistanceFromKey; i++)
            {
                if (maxNodesAcross < arColumnsUsed[i])
                {
                    maxNodesAcross = arColumnsUsed[i];
                }
            }
        }

        canvas          = new Bitmap((int)(NODE_WIDTH * maxNodesAcross + NODE_SPACING * (maxNodesAcross + 1)), (int)(maxNodeHeight * (maxDistanceFromKey + 1) + NODE_SPACING * (maxDistanceFromKey + 2) + 50));
        g               = Graphics.FromImage(canvas);
        g.SmoothingMode = SmoothingMode.AntiAlias;
        g.FillRectangle(new SolidBrush(Color.White), 0, 0, canvas.Width, canvas.Height);

        //draw title
        Font  titleFont = new Font(FontFamily.GenericSansSerif, 14, FontStyle.Bold);
        SizeF titleSize = g.MeasureString(this.Title, titleFont, canvas.Width, centered);

        g.DrawString(this.Title, titleFont, new SolidBrush(Color.Black), new RectangleF(0, Math.Max(50 / 2 - titleSize.Height / 2, 0), canvas.Width, Math.Max(50, titleSize.Height)), centered);

        //draw the relationships
        TraverseRelationshipsAndDraw(key, g);

        //draw the nodes
        foreach (LatticeNode ln in this.Nodes.Values)
        {
            RectangleF fillRect = new RectangleF(ln.x, ln.y, NODE_WIDTH, maxNodeHeight);
            g.FillRectangle(new SolidBrush((ln.Visible ? Color.LightBlue : Color.LightGray)), fillRect);
            //Color.FromArgb(153, 204, 204) //this color is in the default palette for a GIF

            RectangleF textRect = new RectangleF(ln.x, ln.y, NODE_WIDTH, maxNodeHeight);
            textRect.Y += (maxNodeHeight - ln.TextHeight) / 2;
            g.DrawString(ln.Text, new Font(FontFamily.GenericSansSerif, 10, (ln.Enabled ? FontStyle.Regular : FontStyle.Italic)), new SolidBrush((ln.Enabled ? Color.Black : Color.Gray)), textRect, centered);
        }

        g.Dispose();
        return(canvas);
    }
Beispiel #13
0
        /// <summary>
        /// This is the method that actually does the work.
        /// </summary>
        /// <param name="DA">The DA object can be used to retrieve data from input parameters and
        /// to store data in output parameters.</param>
        protected override void SolveInstance(IGH_DataAccess DA)
        {
            // 1. Declare placeholder variables and assign initial invalid data.
            //    This way, if the input parameters fail to supply valid data, we know when to abort
            var    cell      = new UnitCell();
            double xCellSize = 0;
            double yCellSize = 0;
            double zCellSize = 0;
            int    nX        = 0;
            int    nY        = 0;
            int    nZ        = 0;

            // 2. Retrieve input data.
            if (!DA.GetData(0, ref cell))
            {
                return;
            }
            if (!DA.GetData(1, ref xCellSize))
            {
                return;
            }
            if (!DA.GetData(2, ref yCellSize))
            {
                return;
            }
            if (!DA.GetData(3, ref zCellSize))
            {
                return;
            }
            if (!DA.GetData(4, ref nX))
            {
                return;
            }
            if (!DA.GetData(5, ref nY))
            {
                return;
            }
            if (!DA.GetData(6, ref nZ))
            {
                return;
            }

            // 3. If data is invalid, we need to abort.
            if (!cell.isValid)
            {
                return;
            }
            if (xCellSize == 0)
            {
                return;
            }
            if (yCellSize == 0)
            {
                return;
            }
            if (zCellSize == 0)
            {
                return;
            }
            if (nX == 0)
            {
                return;
            }
            if (nY == 0)
            {
                return;
            }
            if (nZ == 0)
            {
                return;
            }

            // 4. Initialise the lattice object
            var lattice = new Lattice();

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

            // 6. Define BasePlane and directional iteration vectors
            Plane    basePlane = Plane.WorldXY;
            Vector3d vectorX   = xCellSize * basePlane.XAxis;
            Vector3d vectorY   = yCellSize * basePlane.YAxis;
            Vector3d vectorZ   = zCellSize * basePlane.ZAxis;

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

            // 7. 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] * vectorX + uvw[1] * vectorY + uvw[2] * vectorZ;
                                // Instantiate new node
                                var newNode = new LatticeNode(basePlane.Origin + V);
                                // Add new node to tree
                                nodeList.Add(newNode);
                            }
                        }
                    }
                }
            }

            // 8. Map struts to the node tree
            lattice.ConformMapping(cell, N);

            // 9. Set output
            DA.SetDataList(0, lattice.Struts);
        }
Beispiel #14
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 inputs
            var     cell    = new UnitCell();
            Surface surface = null;
            Point3d pt      = Point3d.Unset;
            int     nU      = 0;
            int     nV      = 0;
            int     nW      = 0;
            bool    morphed = false;

            if (!DA.GetData(0, ref cell))
            {
                return;
            }
            if (!DA.GetData(1, ref surface))
            {
                return;
            }
            if (!DA.GetData(2, ref pt))
            {
                return;
            }
            if (!DA.GetData(3, ref nU))
            {
                return;
            }
            if (!DA.GetData(4, ref nV))
            {
                return;
            }
            if (!DA.GetData(5, ref nW))
            {
                return;
            }
            if (!DA.GetData(6, ref morphed))
            {
                return;
            }

            if (!cell.isValid)
            {
                return;
            }
            if (!surface.IsValid)
            {
                return;
            }
            if (!pt.IsValid)
            {
                return;
            }
            if (nU == 0)
            {
                return;
            }
            if (nV == 0)
            {
                return;
            }
            if (nW == 0)
            {
                return;
            }

            // 2. Initialize the node tree, derivative tree and morphed space tree
            var lattice   = new Lattice();
            var spaceTree = new DataTree <GeometryBase>(); // will contain the morphed uv spaces (as surface-surface, surface-axis or surface-point)

            // 3. Package the number of cells in each direction into an array
            float[] N = new float[3] {
                nU, nV, nW
            };

            // 4. Normalize the UV-domain
            Interval unitDomain = new Interval(0, 1);

            surface.SetDomain(0, unitDomain); // surface u-direction
            surface.SetDomain(1, unitDomain); // surface v-direction

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

            // 6. 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 onto the UV-surface map
                        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
                            {
                                Point3d pt1;
                                // Initialize for surface 2
                                Point3d pt2; Vector3d[] derivatives;

                                // Set pt1 (on point)
                                pt1 = pt;
                                // Compute pt2 (on surface)
                                surface.Evaluate(uvw[0] / N[0], uvw[1] / N[1], 2, out pt2, out derivatives);

                                // Create vector joining the two points (this is our w-range)
                                Vector3d wVect = pt2 - pt1;

                                // Create the node, accounting for the position along the w-direction
                                var newNode = new LatticeNode(pt1 + wVect * uvw[2] / N[2]);
                                // Add node to tree
                                nodeList.Add(newNode);
                            }
                        }
                    }

                    // Define the uv space tree (used for morphing)
                    if (morphed && u < N[0] && v < N[1])
                    {
                        GH_Path spacePath = new GH_Path(u, v);
                        // Set trimming interval
                        var uInterval = new Interval((u) / N[0], (u + 1) / N[0]);
                        var vInterval = new Interval((v) / N[1], (v + 1) / N[1]);
                        // Create sub-surface and point (never changes)
                        Surface ss1 = surface.Trim(uInterval, vInterval);
                        Point   ss2 = new Point(pt);
                        // Unitize domain
                        ss1.SetDomain(0, unitDomain); ss1.SetDomain(1, unitDomain);
                        // Save to the space tree
                        spaceTree.Add(ss1, spacePath);
                        spaceTree.Add(ss2, spacePath);
                    }
                }
            }

            // 7. Map struts to the node tree
            if (morphed)
            {
                lattice.MorphMapping(cell, spaceTree, N);
            }
            else
            {
                lattice.ConformMapping(cell, N);
            }

            // 8. Set output
            DA.SetDataList(0, lattice.Struts);
        }
        /// <summary>
        /// Do unit selection.
        /// </summary>
        /// <param name="searchConfig">Search configuration.</param>
        /// <returns>The best path.</returns>
        public List<PathNodeInfo> UnitSelecting(SearchConfig searchConfig)
        {
            ILatticeProvider latticeProvider = searchConfig.LatticeProvider;
            ITargetCostCalculator targetCostCalculator = searchConfig.TargetCostCalculator;
            IJoinCalculator joinCostCalculator = searchConfig.JoinCostCalculator;

            int targetCount = latticeProvider.GetColumnCount();
            if (targetCount == 0)
            {
                string message = Helper.NeutralFormat("The ILatticeProvider contains 0 targets!");
                throw new InvalidDataException(message);
            }

            List<PathNodeInfo> bestPath = new List<PathNodeInfo>(targetCount);

            TargetNode[] targets = new TargetNode[targetCount];
            LatticeNode[][] lattice = new LatticeNode[targetCount][];

            for (int i = 0; i < targetCount; i++)
            {
                int candidateCount = latticeProvider.GetRowCount(i);
                if (candidateCount == 0)
                {
                    string message = Helper.NeutralFormat("The ILatticeProvider contains 0 candidates for target {0}!", i);
                    throw new InvalidDataException(message);
                }

                targets[i] = new TargetNode(latticeProvider.GetTarget(i), candidateCount);

                lattice[i] = new LatticeNode[candidateCount];
                for (int j = 0; j < candidateCount; j++)
                {
                    PathNodeInfo pathNodeInfo = new PathNodeInfo(latticeProvider.GetCandidate(i, j), float.PositiveInfinity, float.PositiveInfinity);
                    lattice[i][j] = new LatticeNode(pathNodeInfo, float.PositiveInfinity, -1);
                }
            }

            for (int i = 0; i < targets[0].CandidateCount; i++)
            {
                LatticeNode nodeCur = lattice[0][i];

                float targetCost = targetCostCalculator.GetTargetCost(targets[0].Target, nodeCur.PathNodeInfo.Candidate);
                nodeCur.BestScore = targetCost;

                nodeCur.PathNodeInfo.TargetCost = targetCost;
            }

            for (int col = 1; col < targetCount; col++)
            {
                TargetNode targetCur = targets[col];
                TargetNode targetLeft = targets[col - 1];

                for (int i = 0; i < targetCur.CandidateCount; i++)
                {
                    LatticeNode nodeCur = lattice[col][i];

                    LatticeNode nodeLeft = lattice[col - 1][0];
                    float joinCost = joinCostCalculator.GetJoinCost(targetLeft.Target, targetCur.Target,
                        nodeLeft.PathNodeInfo.Candidate, nodeCur.PathNodeInfo.Candidate);
                    float bestPreScore = nodeLeft.BestScore + joinCost;
                    int bestPreNodeIndex = 0;
                    float bestJoinCost = joinCost;

                    for (int j = 1; j < targets[col - 1].CandidateCount; j++)
                    {
                        nodeLeft = lattice[col - 1][j];
                        joinCost = joinCostCalculator.GetJoinCost(targetLeft.Target, targetCur.Target,
                            nodeLeft.PathNodeInfo.Candidate, nodeCur.PathNodeInfo.Candidate);
                        float preCost = nodeLeft.BestScore + joinCost;
                        if (preCost < bestPreScore)
                        {
                            bestPreScore = preCost;
                            bestPreNodeIndex = j;
                            bestJoinCost = joinCost;
                        }
                    }

                    float targetCost = targetCostCalculator.GetTargetCost(targetCur.Target, nodeCur.PathNodeInfo.Candidate);
                    nodeCur.BestScore = bestPreScore + targetCost;
                    nodeCur.BestPreNodeIndex = bestPreNodeIndex;

                    nodeCur.PathNodeInfo.TargetCost = targetCost;
                    nodeCur.PathNodeInfo.JoinCost = bestJoinCost;
                }
            }

            int columnIndex = targetCount - 1;
            LatticeNode bestNode = lattice[columnIndex][0];
            float bestScore = bestNode.BestScore;
            for (int i = 1; i < targets[columnIndex].CandidateCount; i++)
            {
                LatticeNode curNode = lattice[columnIndex][i];
                if (curNode.BestScore < bestScore)
                {
                    bestNode = curNode;
                    bestScore = bestNode.BestScore;
                }
            }

            while (true)
            {
                bestPath.Add(bestNode.PathNodeInfo);
                columnIndex--;
                if (columnIndex < 0)
                {
                    break;
                }

                bestNode = lattice[columnIndex][bestNode.BestPreNodeIndex];
            }

            bestPath.Reverse();

            return bestPath;
        }
    private void TraverseDeepestRelationshipsAndMarkColumns(LatticeNode ln, int DistanceFromKey, int MaxRelationshipDepth)
    {
        foreach (LatticeRelationship lr in ln.Relationships)
        {
            if (lr.node.DistanceFromKey != DistanceFromKey)
            {
                continue; //if there are redundant attribute relationships with different depths, then skip marking this if we're at the wrong depth
            }

            LatticeNode r = lr.node;
            if (r.MaxRelationshipDepth == MaxRelationshipDepth && r.MinColumnPosition == 0)
            {
                int pos = (int)Math.Round(maxNodesAcross / 2.0, MidpointRounding.AwayFromZero);
                bool bColumnSet = false;

                //start by going the only the direction (left or right) that the child node is going
                if (DistanceFromKey > 1)
                {
                    for (int j = 0; j < maxNodesAcross / 2.0; j++)
                    {
                        if (ln.MaxColumnPosition > pos && !arLayoutMatrix[DistanceFromKey - 1, pos + j - 1])
                        {
                            bColumnSet = true;
                            arLayoutMatrix[DistanceFromKey - 1, pos + j - 1] = true;
                            r.MinColumnPosition = pos + j;
                            r.MaxColumnPosition = pos + j;
                            break;
                        }
                        else if (ln.MinColumnPosition < pos && !arLayoutMatrix[DistanceFromKey - 1, pos - j - 1])
                        {
                            bColumnSet = true;
                            arLayoutMatrix[DistanceFromKey - 1, pos - j - 1] = true;
                            r.MinColumnPosition = pos - j;
                            r.MaxColumnPosition = pos - j;
                            break;
                        }
                    }
                }

                //if there's no room going the way that the child node went, then go the other way
                if (!bColumnSet)
                {
                    for (int j = 0; j < maxNodesAcross / 2.0; j++)
                    {
                        if (!arLayoutMatrix[DistanceFromKey - 1, pos + j - 1])
                        {
                            bColumnSet = true;
                            arLayoutMatrix[DistanceFromKey - 1, pos + j - 1] = true;
                            r.MinColumnPosition = pos + j;
                            r.MaxColumnPosition = pos + j;
                            break;
                        }
                        else if (!arLayoutMatrix[DistanceFromKey - 1, pos - j - 1])
                        {
                            bColumnSet = true;
                            arLayoutMatrix[DistanceFromKey - 1, pos - j - 1] = true;
                            r.MinColumnPosition = pos - j;
                            r.MaxColumnPosition = pos - j;
                            break;
                        }
                    }
                }
            }
            TraverseDeepestRelationshipsAndMarkColumns(r, DistanceFromKey + 1, MaxRelationshipDepth);
        }
    }
 private void TraverseRelationshipsAndMarkColumns(LatticeNode ln, int DistanceFromKey)
 {
     for (int i = ln.DistanceFromKey + 1; i <= maxDistanceFromKey; i++) //enumerate the levels above this node
     {
         List<int> loopOrder = new List<int>();
         if (LayoutMethod == VisualizeAttributeLattice.LatticeLayoutMethod.ShortSingleLevelRelationshipsFirst)
         {
             for (int j = i; j <= maxDistanceFromKey; j++) //enumerate the distance from the next node to the top... helps to start with a bunch of short relationships
             {
                 loopOrder.Add(j);
             }
         }
         else
         {
             int lastJ = -1;
             for (int j = i + 1; lastJ != i; j = (j >= maxDistanceFromKey ? i : j + 1)) //enumerate the distance from the next node to the top... helps to start with a bunch of short relationships
             {
                 lastJ = j;
                 loopOrder.Add(j);
             }
         }
         foreach (int j in loopOrder) //enumerate the distance from the next node to the top... helps to start with a bunch of short relationships
         {
             foreach (LatticeRelationship lr in ln.Relationships)
             {
                 LatticeNode r = lr.node;
                 if (r.DistanceFromKey == i && r.DistanceFromKey + r.MinRelationshipDistance == j)
                 {
                     if (ln.MinRelationshipColumnDistance < Math.Abs(ln.MinColumnPosition - r.MinColumnPosition))
                     {
                         ln.MinRelationshipColumnDistance = Math.Abs(ln.MinColumnPosition - r.MinColumnPosition);
                     }
                     if (r.DistanceFromKey >= DistanceFromKey)
                     {
                         if (r.MaxColumnPosition == arColumnsUsed[DistanceFromKey - 1] && ln.MaxColumnPosition > r.MaxColumnPosition)
                         {
                             if (r.MinColumnPosition == 0) r.MinColumnPosition = ln.MinColumnPosition;
                             arColumnsUsed[DistanceFromKey - 1] = ln.MaxColumnPosition;
                             r.MaxColumnPosition = arColumnsUsed[DistanceFromKey - 1];
                             TraverseRelationshipsAndMarkColumns(r, DistanceFromKey + 1);
                         }
                         else if (r.MinColumnPosition == 0)
                         {
                             r.MinColumnPosition = Math.Max(arColumnsUsed[DistanceFromKey - 1] + 1, ln.MinColumnPosition);
                             r.MaxColumnPosition = Math.Max(arColumnsUsed[DistanceFromKey - 1] + 1, ln.MaxColumnPosition);
                             arColumnsUsed[DistanceFromKey - 1] = r.MaxColumnPosition;
                             TraverseRelationshipsAndMarkColumns(r, DistanceFromKey + 1);
                         }
                     }
                 }
             }
         }
     }
 }
Beispiel #18
0
    private void TraverseDeepestRelationshipsAndMarkColumns(LatticeNode ln, int DistanceFromKey, int MaxRelationshipDepth)
    {
        foreach (LatticeRelationship lr in ln.Relationships)
        {
            if (lr.node.DistanceFromKey != DistanceFromKey)
            {
                continue; //if there are redundant attribute relationships with different depths, then skip marking this if we're at the wrong depth
            }

            LatticeNode r = lr.node;
            if (r.MaxRelationshipDepth == MaxRelationshipDepth && r.MinColumnPosition == 0)
            {
                int  pos        = (int)Math.Round(maxNodesAcross / 2.0, MidpointRounding.AwayFromZero);
                bool bColumnSet = false;

                //start by going the only the direction (left or right) that the child node is going
                if (DistanceFromKey > 1)
                {
                    for (int j = 0; j < maxNodesAcross / 2.0; j++)
                    {
                        if (ln.MaxColumnPosition > pos && !arLayoutMatrix[DistanceFromKey - 1, pos + j - 1])
                        {
                            bColumnSet = true;
                            arLayoutMatrix[DistanceFromKey - 1, pos + j - 1] = true;
                            r.MinColumnPosition = pos + j;
                            r.MaxColumnPosition = pos + j;
                            break;
                        }
                        else if (ln.MinColumnPosition < pos && !arLayoutMatrix[DistanceFromKey - 1, pos - j - 1])
                        {
                            bColumnSet = true;
                            arLayoutMatrix[DistanceFromKey - 1, pos - j - 1] = true;
                            r.MinColumnPosition = pos - j;
                            r.MaxColumnPosition = pos - j;
                            break;
                        }
                    }
                }

                //if there's no room going the way that the child node went, then go the other way
                if (!bColumnSet)
                {
                    for (int j = 0; j < maxNodesAcross / 2.0; j++)
                    {
                        if (!arLayoutMatrix[DistanceFromKey - 1, pos + j - 1])
                        {
                            bColumnSet = true;
                            arLayoutMatrix[DistanceFromKey - 1, pos + j - 1] = true;
                            r.MinColumnPosition = pos + j;
                            r.MaxColumnPosition = pos + j;
                            break;
                        }
                        else if (!arLayoutMatrix[DistanceFromKey - 1, pos - j - 1])
                        {
                            bColumnSet = true;
                            arLayoutMatrix[DistanceFromKey - 1, pos - j - 1] = true;
                            r.MinColumnPosition = pos - j;
                            r.MaxColumnPosition = pos - j;
                            break;
                        }
                    }
                }
            }
            TraverseDeepestRelationshipsAndMarkColumns(r, DistanceFromKey + 1, MaxRelationshipDepth);
        }
    }
 public LatticeRelationship(LatticeNode ln, RelationshipType rt, bool visible)
 {
     this.node = ln;
     this.RelationshipType = rt;
     this.Visible = visible;
 }
        /// <summary>
        /// This is the method that actually does the work.
        /// </summary>
        /// <param name="DA">The DA object can be used to retrieve data from input parameters and
        /// to store data in output parameters.</param>
        protected override void SolveInstance(IGH_DataAccess DA)
        {
            // 1. Retrieve and validate data
            var    cell    = new UnitCell();
            double radius  = 0;
            double height  = 0;
            int    nU      = 0;
            int    nV      = 0;
            int    nW      = 0;
            bool   morphed = false;

            if (!DA.GetData(0, ref cell))
            {
                return;
            }
            if (!DA.GetData(1, ref radius))
            {
                return;
            }
            if (!DA.GetData(2, ref height))
            {
                return;
            }
            if (!DA.GetData(3, ref nU))
            {
                return;
            }
            if (!DA.GetData(4, ref nV))
            {
                return;
            }
            if (!DA.GetData(5, ref nW))
            {
                return;
            }
            if (!DA.GetData(6, ref morphed))
            {
                return;
            }

            if (!cell.isValid)
            {
                return;
            }
            if (radius == 0)
            {
                return;
            }
            if (height == 0)
            {
                return;
            }
            if (nU == 0)
            {
                return;
            }
            if (nV == 0)
            {
                return;
            }
            if (nW == 0)
            {
                return;
            }

            // 2. Initialize the lattice
            var lattice = new Lattice();
            // Will contain the morphed uv spaces (as surface-surface, surface-axis or surface-point)
            var spaceTree = new DataTree <GeometryBase>();

            // 3. Define cylinder
            Plane   basePlane = Plane.WorldXY;
            Surface cylinder  = (new Cylinder(new Circle(basePlane, radius), height)).ToNurbsSurface();

            cylinder = cylinder.Transpose();
            LineCurve axis = new LineCurve(basePlane.Origin, basePlane.Origin + height * basePlane.ZAxis);

            // 4. Package the number of cells in each direction into an array
            float[] N = new float[3] {
                nU, nV, nW
            };

            // 5. Normalize the UV-domain
            Interval unitDomain = new Interval(0, 1);

            cylinder.SetDomain(0, unitDomain); // surface u-direction
            cylinder.SetDomain(1, unitDomain); // surface v-direction
            axis.Domain = unitDomain;

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

            // 7. 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 index in the cell onto the UV-surface maps
                        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
                            {
                                Point3d    pt1, pt2;
                                Vector3d[] derivatives;

                                // Construct z-position vector
                                Vector3d vectorZ = height * basePlane.ZAxis * uvw[0] / N[0];
                                // Compute pt1 (on axis)
                                pt1 = basePlane.Origin + vectorZ;
                                // Compute pt2 (on surface)
                                cylinder.Evaluate(uvw[0] / N[0], uvw[1] / N[1], 2, out pt2, out derivatives);

                                // Create vector joining these two points
                                Vector3d wVect = pt2 - pt1;
                                // Instantiate new node
                                var newNode = new LatticeNode(pt1 + wVect * uvw[2] / N[2]);
                                // Add new node to tree
                                nodeList.Add(newNode);
                            }
                        }
                    }

                    // Define the uv space map tree (used for morphing)
                    if (morphed && u < N[0] && v < N[1])
                    {
                        GH_Path spacePath = new GH_Path(u, v);
                        // Set trimming interval
                        var uInterval = new Interval((u) / N[0], (u + 1) / N[0]);
                        var vInterval = new Interval((v) / N[1], (v + 1) / N[1]);
                        // Create sub-surface and sub axis
                        Surface ss1 = cylinder.Trim(uInterval, vInterval);
                        Curve   ss2 = axis.Trim(uInterval);
                        // Unitize domains
                        ss1.SetDomain(0, unitDomain); ss1.SetDomain(1, unitDomain);
                        ss2.Domain = unitDomain;
                        // Save to the space tree
                        spaceTree.Add(ss1, spacePath);
                        spaceTree.Add(ss2, spacePath);
                    }
                }
            }

            // 8. Map struts to the node tree
            if (morphed)
            {
                lattice.MorphMapping(cell, spaceTree, N);
            }
            else
            {
                lattice.ConformMapping(cell, N);
            }

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