algorithmic modeling for Rhino
IntraLattice is an important plug-in since it affords arbitrary 3D lattices of lines or even curves to be thickened into strut/hub systems very quickly compared to marching cubes methods. It does so by turning lines into stacks of anti-prisms and then calculating a triangulated convex hull around each hub that uses the vertices of the ends of such struts. The low poly result can be subdivided (Weaverbird Loop) to smooth it.
It comes with several preset unit cell types for filling arbitrary bodies with a lattice, and also has a custom unit cell component. But it's broken.
IntraLattice has a tolerance bug that is easy to fix by just scaling your model up 10X when you notice bad mesh results. This is a separate issue.
It's as if it doesn't like lines to end on edges of the unit cell, only faces and corners. A diagonal line from edge-to-edge (and then all lines split with each other) goes missing, half missing, or oddly enough becomes zig-zag in the array when it should be straight.
I also don't like that the developer added a limitation error warning that all faces must have a line on them. This means I can't fill space with layered spaces in between trusswork, for instance.
The custom unit cell code also sadly rejects curves, yet IntraLattice itself can handle curves just fine.
I also note that that clean-up component only removes duplicate lines, fine, but it doesn't join pairs of co-linear lines, something that occurs often when playing around with unit cells. This seems to cause bad meshes since it tries to put a hub where the line segments need merely be joined or treated as one line.
There's also a bug in the nice custom mesh preview component that sometimes has the preview stuck on even if you delete the component from the Grasshopper canvas since disabling it or shutting off preview of it fails.
It's been two years since an update to this open source plug-in, so I've contacted the developers on Github since the contact form is Server Error 500: http://intralattice.com/contact/
On Github, he promises a new version in 2017 as a stand-alone application, so I hope this extends to Grasshopper in some way, if not directly, then as some way to hook into it.
In hindsight, this feature of a custom unit cell seems sort of trivial to just whip up in Grasshopper in a bounding box, then to trim the lines with the mesh or brep and cull any shorts. Rhino/Grasshopper lack a trim with mesh command though, so an intersection, shatter, and test for inclusion of midpoints is perhaps needed, which may be terribly slow. Argh, there isn't even a split command for curves, just shatter that needs a parameter, since Rhinocommon doesn't expose its real split command to programmers.
Alas, I'm having a mesh inclusion bug ruin the long winded trim routine.
Ah, looks like this is a result of how the inclusion is always calculated. Basically, a line interesects the mesh from the point to an arbitrary point outside of the mesh: if the number of strikes is even (0, 2, 4) then that means the point either never hit it, or went in and out again, meaning it's outside. If it hits an odd number of times, then it must have come from within originally.
The method implements this approach using the mesh bounding box, and then striking a polyline from your test point along a vector that is defined by the upper right corner of the bounding box + a vector of (100,100,100). In the case of your failing points, this is a result of their striking an edge very precisely, which gets counted as 2 hits instead of 1 (as it should be getting captured) and passing false:
Your best bet is probably to roll your own implementation, that tests for multiple vectors:
private void RunScript(List<Point3d> P, Mesh M, ref object A, ref object B, ref object C)
BoundingBox bb = M.GetBoundingBox(false);
List<bool> inside = new List<bool>();
for (int i = 0; i < P.Count; i++)
Polyline a = new Polyline();
Polyline b = new Polyline();
a.Add(bb.Max + new Vector3d(100, 100, 100));
b.Add(bb.Max + new Vector3d(100, 150, 150));
Point3d xa = Rhino.Geometry.Intersect.Intersection.MeshPolyline(M, new PolylineCurve(a), out fa);
Point3d xb = Rhino.Geometry.Intersect.Intersection.MeshPolyline(M, new PolylineCurve(b), out fb);
inside.Add(xa.Length % 2 == 1 || xb.Length % 2 == 1);
checkA.AddRange(xa, new GH_Path(i));
checkB.AddRange(xb, new GH_Path(i));
A = inside;
A bug in a rug, and homework too, thanks! Yes, I noticed the geometry pattern.
I've pinged them on Discourse that it's still failing in certain cases.
Here is a spaghetti mess first stab at a working IntraLattice custom unit cell script:
However, this won't work with IntraLattice, since it errors out when two co-linear lines are not joined together into a polyline. It will expand a single line or even kinky polyline just fine, in the later case by adding convex hull hubs between them. But I think it tries to do the same thing for co-linear lines and then gets a flat self-overlapping mesh as the convex hull hub that can't be joined to the struts.
When I just array a unit cell, it's not obvious how to join lines only in appropriate pairs, while not also joining inner co-linear lines that need to stay split at inner hubs. Even with its own unit cell system, when it works to array the cells, bad meshes result in the middle of struts.
It already takes ~6 seconds, without some great search for exactly two size hubs that need to be joined into a non-hub.
A kludge option: modify my unit cell before making an array, to extend lines outside of it into all adjacent cells, then cull any that touch the super bounding box, then array and cull duplicate lines since they are now dual-cell lines coming from both sides of each cell pair. This way I only have to strategically avoid joining in a single unit cell, to only join where lines touch the cell. Even that is a logistical puzzle, worth much spaghetti.
Validating my quest to learn Rhinocommon with Python, all that spaghetti is gone, as I could not for hours of work figure out any combination of grafting, simplification and flattening to get past a single case of a line having two intersections with the mesh. That mismatched my data trees, fatally. When one branch has two items in it instead of one, and a component refuses to let me graft the final branches of a tree with a simple flat list, then it's just game over for spaghetti.
It astounds me too that the simple Rhino command to split a bunch of curves with a bunch of points is not in Grasshopper because it's not even exposed in Rhinocommon. I'm back in kindergarden when that sort of 101 stuff is missing.
I haven't handled multiple intersections of lines/polylines with the mesh to have to split a given line twice or more, but that's a rare case and means I have to re-learn enumerables list Windows data format to do the Rhinocommon command right.
Next, to join lines to remove "hubs" with only two struts, though I should check co-linearity to, to allow polyline bends in unit cells.
The trick to finding the lone pairs of strut lines was Grasshopper Cull Duplicates because it also outputs the valence of each final point, how many times it appears, so if you isolate the valence two points after making a list of all endpoints of your line collection, you can then use Python to readily loop through each of those lone pair points to gather pairs of curves attached to each point, join them, and then delete the original pair.
In order to generalize to curves I may merely need to convert them to polylines within the unit cell since the Rhinocommon mesh intersection command uses a polyline. There is no mesh/curve intersection command.
...indeed, if I remove my intermediary Grasshopper line nodes from between the clusters, and I use Rhino to convert a unit cell curve into a polyline, it works fine:
It's not desirable how oddly it gives a more crude mesh of anti-prisms where my polyline has less curvature. That means I can't smooth via single subdivision to an even mesh unless I remesh the whole thing.