We’re designing lightweight space frames from tubes and 3d printed connectors. We have simple mesh files with stacked cubes with some diagonals. These come out of another 3d program, we want to use this as input. Below is a visual of the test structure in the attached GH file, the final structures are more complex and feature a maximum of 350 connectors in each structure.
We’re using Grasshopper for generating the connectors and to help us organise production. This is the definition that generates a single connector by feeding in a list of angles and performing rotations.
Now we want to be able to identify - based on the cube mesh - how many unique connectors there are in the whole construction and how many of copies of each unique connector we need to 3d print.
Since the configuration of vectors is what makes each connector unique, I figured it would be best to look at those as finger prints for identification. Since vectors are relative, it should be doable no? Attached is a definition that I made that extracts the vectors of the edges connected to any given node point. This was a great learning opportunity but now I’m reaching a bit my limits so I’m looking for guidance. Only Lunchbox is used as extra components. 20200512-Principles_v3_cleaned.gh (27.7 KB)
Problem one is a data tree issue I believe. While I succeed in extracting the vectors for a single point (and learned some data tree lessons there) I fail at generating a list of vectors for all points. A garbled mess comes out at best when I input multiple nodes instead of one.
Once I solve that, the main issue for which I don’t even have a conceptual approach, is how to compare alle these sets of vectors with each other. The issue is that they can be oriented in all variations of 90 degree angles around X, Y & Z. Regardless of orientation (but NOT when mirrored) they should be labeled the same part. Is this doable? My only hunch was something like Anemone to loop through all different orientations and compare at each angle.
But maybe this is a stupid approach and I should do it differently altogether. Input both ways appreciated!
ps. another option we’re exploring in paralel is to generate all connectors in place within the space frame and find a way to pack the efficiently as one 3d print batch.
I was already wondering, part of this must be a very common issue… So I managed to solve my first question (Listing all edges per node) by completely rebuilding my definition around Weaverbird & Lunchbox components. Now I’m left with the main part of my question: How to compare and label all unique vector configurations regardless of their orientation.
I found this discussion: Find similar nodes in framework of lines - #4 by HiMyNameIs which lead me to Weaverbird & Sandbox (Thanks @HS_Kim!). I also thought it would be my magic bullet for IDing the nodes in my mesh but after tinkering a long evening I can’t get HS_Kim’s example to work on even a basic sample mesh with 3 cubes. Too many false positives and negatives.
Another discussion I stumbled upon was this one: compare objects to verify their identity - Grasshopper. So what I understand from that conversation (Especially @DavidRutten’s point about finding a hash) is that I should find some unique fingerprint that I can compare instead of trying to compare all vectors to all vectors? So was playing around with computing an average vector from all vectors but that’s not unique enough, multiple configurations share the same average vector. Maybe combined with bounding box? But in all situations I fail to find a way to separate mirrored configurations… So is there a way to compare all vectors at all possible 90° rotations and label the unique ones or should I go further finding simpler ‘fingerprints’. This part is a bit too far in unknown territory as Grasshopper novice so all input welcome!
Thanks @rajeev_pulari for the suggestion. TT Toolbox doesn’t load well on Rhino 7 WIP on Mac in which I build this definition. But as mentioned in my second post above, I actually managed to completely rebuild my definition around the Sandbox Line Topology component which outputs all nodes and per node the attached lines (amongst other things). So that I got figured out.
But the main question was, how can I identify and label all the unique line configurations per node. So for example label all nodes A that are a 3 line, 90 degree corner regardless of their orientation. See below for an example of what I’m trying to achieve. All 4 A nodes are the same corner. All nodes B are also similar but C & D are mirrored and not the same when rotated. So the thing I’m trying to figure out is how many unique connectors do I have and how many of each are in the model.
I’ve no idea where to start on that quest.
For each node in a given mesh/brep get the neighbors. This yields the local connections (some axis of the candidate connector). Store the neighbors in a List. Find the mesh/brep that is adjacent and the prox node. Add to the List the prox node neighbors (after filtering the ones that yield same directions). Add the new neighbors in the List. Repeat for all the rest adjacent objects/nodes. Now you have all the candidate connector axis.
But … what to do next? That’s the 1M question.
Here’s the trick: get the aggregate vector (sum or all unitized connection directions [ie the connector axis]) and sample in a List all the angles - or better the tip distances (i.e that vector against all the local and neighbor nodes). This List of doubles is a unique ID of your node topology (so to speak). If another node in another place has a List with the same items (Plan B: use a sequential equality List check [after sorting]) this means that you have the same connector on hand.
Each connector has properties (so to speak) like the parent(s) mesh/node (and propably clash info and other stuff). This begs for using a custom class that samples all the information required: the classic way to deal with similar things.
Using code for all the above is rather the best way by a huge margin to solve that puzzle (most notably if you use classes or later on various queries via LINQ/PLINQ etc etc).
There is a component by Daniel Piker called “Topologizer” which creates a topology for line structures.
I tried this with a simplified structure and so far it looks like I get the desired result. I calculated the average of the neighbours for each point. A vector from that average to the point is used to orient the points with their neighbours on the XY plane. Sometimes the plane goes the wrong way and I figured out that I can simply rotate the oriented geometry 180 degrees. Then I searched for closest points. Equal nodes share all points thus all distances need to be zero. I extracted the sets with a C# skript I think David Rutten posted a while ago. In my example there are also a few unique nodes.
Nice approach. Won’t this have issues though when the length of that vector from average to the point is zero? (eg when the node is surrounded in all 6 directions, or 4 in the same plane)
Thanks all for the input! Happy with the sudden burst of responses after few weeks of silence Will look more in depth at the different suggestions. Quite new to GH so often takes me a while to get a good understanding of what is said. Need to play around a bit.
@martinsiegrist, thanks for taking a shot! Would you mind sending me your test mesh/lines as GH file or to internalise it?
This requires the neighbours to be standard orthogonal distances apart, eg on a 10x10x10 grid. If you can have different unit sizes then a 20x10x10 unit should have corner connectors that are identical to a 10x10x10 unit. I think you would need to unitise the vectors before averaging to get this (my apologies if you already included this in your script - I’m not at a computer, so only have your description to go on!).
Or include a count of the orthogonal vectors and a count of the non-orthogonal ones in the comparison. That is, I think, sufficient to distinguish the sets of zero length vector connectors.
Thanks a lot for this @martinsiegrist! Have played around with it the whole morning and started dissecting and understanding how it works. It’s a great way for me to learn GH. To quote Enrico Fermi: I am still confused, but on a much higher level.
Glad to see I was at least a tiny step in the right direction by generating an average vector. But I was thinking about comparing the vector itself instead of using it as a way to orient the neighbouring points. Much smarter. What I am still surprised about is that when you orient the sets of node points like this they are always rotated the same way regardless their original orientation? You flip them once 180 but I would have thought you would have to do that for each quadrant so 90-180-270 degrees.
Few observations so far when looking at a slightly more complex structure (mirrored, removed duplicate edges & some manual mods):
-I will need to unitise the vectors as @jeremy5 points out, not only because I use two cube sizes (which introduces other problems since small cube nodes connect in the middle of large cube edges) but also because in some cases a connector is still identical if edge & diagonal are flipped. For example in 8 & 18.
-As @DanielPiker pointed out, the zero length avg vectors are an issue (simulated in 27 & 33). Closest Point generates some nulls which give an error in Mass Addition & Equality.
-Some connectors are not recognised as equal. 15 & 20 for example are the same but register as different. I’m not sure why.
Thinking about it a little more, it isn’t just null vectors: if you take any connector with a pair of opposing vectors not included, and create a new connector by adding the opposing vectors, the new connector will have the same average as the old. Hence the need for further differentiation, e.g. adding a node count.
A point of clarification: if you have a connector with, say, vectors (1,0,0) and (0,1,0), is that the same as one with vectors (0.707,0.707,0) and (-0.707,0.707,0), or are the diagonal connections different from the orthogonal ones?
In my case the diagonal and orthogonal are interchangeable, they generate the same geometry in the connector. You can see this in the original post where I attached the connector file too. Also the length of the tubes should have no influence on the geometry of the connector. So {1,0,0} and {0,1,0} should indeed be the same as {0.707,0.707,0} and {-0.707,0.707,0}.
Good points @jeremy5 - if 2 diagonals at right angles to each other are considered the same as 2 orthogonals at right angles to each other, then there are more than 24 possible rotations to consider.
I was going to suggest a script using an IEqualityComparer, which for any pair of vector lists, sees if any of the 24 rotations allow a zero distance 1-to-1 matching (with an appropriate hash function to rule out early ones that clearly can’t match). This avoids the challenge of trying to find a canonical orientation and ordering for any node.
@PeterFotiadis - interesting approach, but doesn’t this rely on the sorting by angle inside GetNodeInfo matching? What about cases where there are multiple vectors at the same angle to the average?
I was also looking a bit at the general case, where you consider all rotations, not just 90° or 45°.
I thinkg it may be equivalent to one of the below, though I’m not clear which of these assume you already know the matching ordering between your sets of vectors