The logic basically creates a minimum spanning tree graph based off of a mesh and creates cuts along the edges where the graph does not traverse an edge. This is very similar to what I imagine the Ivy plugin has under the hood. I am more interested in learning myself on how to implement this myself, so I decided to give it a go using Plankton.
I have managed to implement the creation of the tree graph (in blue) and have isolated the cut lines (in red) in C#.
The trouble I am having is figuring out the best way to “unweld” the edges of the plankton mesh. As opposed to other discussions on mesh clustering/stripping that I have found, my problem is unique because the mesh remains one piece with many unwelded edges as opposed to many separate mesh pieces.
To my knowledge Plankton’s data structure only lets you split edges to add vertices in the middle, so I have tried to translate it back to a rhino mesh to split it with no success. I think it has to do with the fact that the un-weld edge function has to happen multiple times around particular vertices and the face ordering gets messed up. The other alternative would be to iteratively construct a new mesh as the graph is being made, but I am also running into mesh face structure ordering problems.
Does anyone have any ideas on how best to achieve this? I am not much of a coder but I imagine the most elegant way would be to have a property stored in a custom mesh class which allows you to do this but I am stuck and curious how others would handle this.
Here is a test gh file with my best attempt, I use Plankton and weaverbird so you will need those. Any advice/pointers would be great. Even if I am going about it completely the wrong way. Once I have the split mesh I hope to implement an unroller function myself to flatten the map. I would also like to add texture unrolling at some point.
I guess that just depends on from where you look at it. Your problem could probably be tackled from either direction.
A mesh is generally structured data-wise as an indexed list of all its vertices and a collection of faces.
The faces are usually composed of three, four, or more indices of vertices from the list of vertices. Traditionally, there is usually nothing in place that keeps track of edges or any related information.
A vertex is not exclusive to a single face, but is usually a part of multiple faces.
This entails that unwelding a single edge - composed of two non-naked vertices - between two adjacent mesh faces is not feasible (that’s probably why Plankton adds a vertex when splitting).
This is why the mesh information changes while unwelding edges.
Yes, or you could finish the evaluation of the tree, and construct the new mesh from its branch data. You’d have to store or reference the required mesh data within the tree though, but there are probably many ways to do this.
For regular Rhino mesh you can use UnweldEdge with a list of indices like this: PlanktonMeshUnroll_unweld.gh (14.6 KB)
(it’s easier to build the list first then unweld them all at once, so you don’t have to worry about the edge indexing changing as you go)
Plankton doesn’t have welded and unwelded vertices. What you’d need there would be something to cut open an internal edge to make it into a boundary. Boundary half-edges in Plankton have their adjacentFace set as -1.
(Edge Splitting in Plankton is a different thing, and not relevant here)
So you’d want something that takes a linked pair of half-edges that make one internal edge, and makes a new half-edge to pair with each of them, setting the adjacent face of these new half-edges to -1.
For one isolated edge with both ends internal vertices it wouldn’t need to add any new verts, but when cutting open an edge with one end a naked vertex, it would need to create a new vertex.
I’ll look at adding a function for this. It could also be helpful to have something that takes a list of edges to cut, to avoid the issue of indexes changing as you go.
However, I think the easier way would be to make a new mesh, keeping the original unaltered. Using your list of the ‘toCut’ edges you want to open up, you could start from an arbitrary face, add it to the new mesh and get all its adjacent faces (in the original mesh) except for those which are the other side of one of your ‘toCut’ edges. Then keep iterating this until all the faces have been added.
I have something along these lines I wrote a while back for cutting slashes into meshes before relaxing for Kirigami type things in Kangaroo. I’ll dig it out and see if it can be adapted for this.
Also btw - the KPlankton that installs with Kangaroo2 is exactly the same library as Plankton, except for that K in the name of the library and some of the functions. It was just done this way so it wouldn’t cause conflicts for people that already had Plankton installed somewhere else and stuff referencing that.
Thanks Daniel! This makes much more sense, I didn’t know the unweld edge function worked on a list of edges… And yes, adding something like that to Plankton would be great, but I’m sure you have enough on your plate…
One thing I was curious about was if Plankton had any means to store custom data?
For example: If I was able to store the dihedral angle at each edge that the spanning tree traversed, I could then use that info to unfold it down the line. I know it is easy enough just to make another array but it could also be a flexible way of incorporating different functionalities (like if the edge should be unwelded or not).
Anyways this totally solves my problem in the short term and I can move on to trying out the unrolling. Thanks again!
Since Plankton is effectively a C# library, you could potentially always make a new struct or class in your C# script and make it inherit from the Plankton struct or class that you want to extend with some attribute. Your new class or struct should then have the same properties, attributes, and methods as the Plankton one, but with the extra attribute(s) that you added. In theory this should work.
Glad that helped.
About storing custom data-
As you know, Plankton uses arrays of indices for the connectivity instead of direct references to the other mesh elements.
So instead of something like
face pairFace = mesh.Halfedges[i].pairHalfEdge.AdjacentFace;
(which would probably have been the more normal way to set it up)
we have stuff like
int pairHe = mesh.Halfedges.GetPairHalfedge(i);
int pairFace = mesh.Halfedges[pairHe].AdjacentFace;
This makes using it fairly verbose, but it does mean custom properties can be very simple - eg. if you want some property per face, just make an array of matching size and use the same indices to access it.
It’s only if you want to modify the mesh topology in a way that elements get deleted or swapped after you’ve assigned your array of custom properties that this indexing approach becomes a bit more work.
As Plankton is open source, you do also have the option to make a custom build of it where you add new properties directly to the face/halfedge/vertex classes themselves.
Honestly, it was a long time ago, and if I were to start writing a halfedge library from scratch now, I’m not sure I would choose the same approach and might go with a more conventional reference structure.
I managed to get the unrolling working by eventually switching to python and using networkX. I was having trouble ordering the faces tree to parents in a tree in c#…
Anyways, I was wondering if anyone had any ideas on how best to project and image of the earth on to a mesh, whish I could maintain through the unrolling process. I would like it to look something like this: