/
UniformDSComponent.cs
239 lines (212 loc) · 11 KB
/
UniformDSComponent.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
using System;
using System.Collections.Generic;
using Grasshopper.Kernel;
using Rhino.Geometry;
using Grasshopper.Kernel.Types;
using Grasshopper.Kernel.Data;
using Rhino;
using Rhino.DocObjects;
using Rhino.Collections;
using Rhino.Geometry.Intersect;
using IntraLattice.Properties;
using Grasshopper;
using IntraLattice.CORE.Data;
using IntraLattice.CORE.Components;
using IntraLattice.CORE.Helpers;
// Summary: This component generates a uniform lattice trimmed to the shape of design space.
// ===============================================================================
// Details: - Uniform lattice grids have unmorphed unit cells, and are trimmed by the design space.
// - Design space may be a Mesh, Brep or Solid Surface.
// - Orientation plane does not need to be centered at any particular location
// ===============================================================================
// Issues: = Mesh design spaces with many coplanar faces are prone to failure.. issue with Rhino's Mesh.isInside method
// ===============================================================================
// Author(s): Aidan Kurtz (http://aidankurtz.com)
namespace IntraLattice.CORE.Components
{
public class UniformDSComponent : GH_Component
{
/// <summary>
/// Initializes a new instance of the UniformDSComponent class.
/// </summary>
public UniformDSComponent()
: base("Uniform DS", "UniformDS",
"Generates a uniform lattice within by a design space",
"IntraLattice", "Frame")
{
}
/// <summary>
/// Registers all the input parameters for this component.
/// </summary>
protected override void RegisterInputParams(GH_Component.GH_InputParamManager pManager)
{
pManager.AddGenericParameter("Topology", "Topo", "Unit cell topology", GH_ParamAccess.item);
pManager.AddGeometryParameter("Design Space", "DS", "Design Space (Brep or Mesh)", GH_ParamAccess.item);
pManager.AddPlaneParameter("Orientation Plane", "Plane", "Lattice orientation plane", GH_ParamAccess.item, Plane.WorldXY); // default is XY-plane
pManager.AddNumberParameter("Cell Size ( x )", "CSx", "Size of unit cell (x)", GH_ParamAccess.item, 5); // default is 5
pManager.AddNumberParameter("Cell Size ( y )", "CSy", "Size of unit cell (y)", GH_ParamAccess.item, 5);
pManager.AddNumberParameter("Cell Size ( z )", "CSz", "Size of unit cell (z)", GH_ParamAccess.item, 5);
pManager.AddNumberParameter("Min Strut Length", "MinL", "Minimum allowable strut length for trimmed struts.", GH_ParamAccess.item);
pManager.AddNumberParameter("Max Strut Length", "MaxL", "Maxmimum allowable strut length for trimmed struts.", GH_ParamAccess.item);
pManager.AddBooleanParameter("Strict tolerance", "Strict", "Specifies if we use a strict tolerance (i.e. strictly inside design space).", GH_ParamAccess.item, false);
}
/// <summary>
/// Registers all the output parameters for this component.
/// </summary>
protected override void RegisterOutputParams(GH_Component.GH_OutputParamManager pManager)
{
pManager.AddCurveParameter("Struts", "Struts", "Strut curve network", GH_ParamAccess.list);
}
/// <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);
}
/// <summary>
/// Sets the exposure of the component (i.e. the toolbar panel it is in)
/// </summary>
public override GH_Exposure Exposure
{
get
{
return GH_Exposure.tertiary;
}
}
/// <summary>
/// Provides an Icon for the component.
/// Icons need to be 24x24 pixels.
/// </summary>
protected override System.Drawing.Bitmap Icon
{
get
{
//You can add image files to your project resources and access them like this:
return Resources.uniformDS;
}
}
/// <summary>
/// Gets the unique ID for this component. Do not change this ID after release.
/// </summary>
public override Guid ComponentGuid
{
get { return new Guid("{d242b0c6-83a1-4795-8f8c-a32b1ac85fb3}"); }
}
}
}