Using Mesh in Grasshopper - and upcoming plans


(Giulio Piacentino) #1

@bobmcneel suggested that we post this discussion here, on the upcoming Serengeti project forum, as this is material that McNeel employees are actively working on. @stevebaer set up this category for us to start using. @DanielPiker started this discussion. He copied in also @robert_vier and David Stasiuk, as well as @DavidRutten and @piac

_Posted by @DanielPiker _

Hi David, Steve and Giulio,

Dave Stasiuk and I have been working on a new Grasshopper component (an update of our wireframe thickening tool - https://github.com/davestasiuk/Exoskeleton2), and coming up against some problems with loading additional libraries.
I’m also including Robert Vierlinger, as I heard he has also encountered some similar issues, and Will Pearson, as we have been working together on the library in question (https://github.com/Dan-Piker/Plankton).

The Plankton library is split into Plankton.dll, which contains the core, and PlanktonGh.dll which gets renamed as Plankton.gha, and contains the grasshopper specific functions (including a custom parameter type, following Giulio’s example with Turtle) and also some Grasshopper components.

For part of Exoskeleton I wanted to use functions from Plankton, but can’t easily reference the gha in visual studio. Will showed a way of manually editing the .csproj file to get around this, but this doesn’t seem an ideal solution (and it also seems to be more difficult when using the library in Python - see Anders’ comments at the bottom of this page).
If I keep a copy of both PlanktonGh.dll and Plankton.gha (the same file saved with different extensions), then it is possible to reference the dll in other projects, and still have the plankton grasshopper components load, but this only works if COFF loading is switched off. If it is on it gives this strange error:

We want to make the libraries and components easy for others to use, but I fear I am confusing matters, and I would appreciate some guidance on what is best practice here.

I’m guessing the better solution might be to separate the functions we want to re-use in other components into a dll, and have only the actual grasshopper components in the gha, but then I’m not sure what would happen with loading the custom parameter type at grasshopper startup.

Is there a good example to look at for the correct way of organizing this sort of thing?

Thanks,

(signed by @DanielPiker )


(Giulio Piacentino) #2

Hi Daniel

I’d like to take a step back and, for a moment, have a look at where this is development more in general is really becoming problematic. There might be some technical solutions to add band-aids here and there and one-at-the-time cosmetic fixes, but it’s very important that now people who develop for meshes get some better common tools. I think this is especially vital, because if we do not do it now, it will become too complicated to maintain and good spaghetti will grow into a jungle. Hours and hours of installation problems might be in front of us.

I think it is not a too wise idea to add an implementation that is similar to Turtle’s to add yet another type of mesh. By doing that, the very problem that the library was meant to alleviate - less interop - will be exacerbated. That implementation has its own disadvantages, too. Especially, if that implementation is applied onto a “live” library, it will quickly become a nightmare to synchronize which library gets loaded when, especially with different add-ons needing and distributing different libraries, users overriding files, etc. You are starting to see what will happen as soon as other people need to load the same libraries, in another version. Two different .dlls with the same code are still recognized as fully different. That’s the error you see above. When I released Turtle, it was structured in a way which would need the least changes in the future (please keep on reading, I’m also going to deprecate Turtle for ngons).

I think we discussed this once in person. The same ideas are still valid: it would be wiser to just standardize to one interop-reference library that can be used to store any type of mesh. That type of mesh should probably be a face-vertex implementation, as all other implementations are either more complicated and heavier to maintain, or do not allow all forms of meshes. Usually the ones with edge links also have problems dealing with all types of manifolds while keeping on being valid or unique, or quickly lose their attractiveness because the very computational model they are meant to make easy, becomes complicated.

There is also some good news, though. With this Rhino Serengeti project approaching, there will no longer be any need to even use Turtle. Following our conversations in London as well, Rhino will have an addition to the Mesh class that will provide every Grasshopper and Rhino user with vertex-face meshes with ngons. Developers in Seattle are already working on this. No need to translate and no need to install. Just provided and ready to use like Meshes today. There will be some need to “filter” these for use with some specific implementation, or for 3D print, or reverse engineer, or… etc. But I think it will truly be wiser to use that class for interchangeability (do we really need 3, 4, etc. types of meshes, all visually identical, with different parameters, that all really are useful only as polylines?).

That being said, I believe that a library like Plankton should be easy to load in Rhino, and from many add-ons. To make the problem tiny, my suggestion would be to make it as essential as possible. And all functionality be provided in plug-ins that reference that .dll. In the best of the world, all complicated and crazy things should happen in each component, with the result passed out in the most interchangeable format available. I would say, in the upcoming Mesh+Ngon class.

What do you think?

Giulio

Giulio Piacentino
for Robert McNeel & Associates
giulio@mcneel.com


(Daniel Piker) #3

Hi Giulio,
Thanks for the input - I agree that it good to keep the bigger picture in mind and plan ahead.
However I think there are a couple of different issues mixed together here.

One is my original question about referencing the same libraries from different components, and the other is the topic of how to pass ngon meshes between components.

The first question is more of a short term thing - I’ve already released this remeshing tool and also the edge thickening component. These components are out there and being used by people now, it is just this one problem with the multiple loading that I want to resolve so that people can install and use the components without having to fiddle too much with the loading settings, or assembly locations. Perhaps splitting Plankton’s gha components from the other parts of its library will resolve most of this. However, I’d still like to know about the correct way to deal with loading custom parameter types at Grasshopper startup and referencing them from multiple separate projects.

As for the longer term issue of passing ngons between components, I certainly agree that having something standard and already installed with Rhino would be an advantage (though we still need solutions for in the meantime). I can also see the argument for having this be something more general like face-vertex because of the extra flexibility it allows such as non-orientable and non-manifold meshes.

However, I do think there are certain areas where the edge-based representations might allow things that are difficult or impossible with only face-vertex meshes. In particular edge ordering and directions, which are not given in a face-vertex mesh. For architectural applications, such as where each mesh edge is a beam or mullion, consistency here can be an advantage. Having to deduce this ordering afresh every time we pass the mesh from one component to the next can be problematic. If we keep converting internally from face-vertex to edge-based representation in exactly the same way each time, we might be okay as long as no connectivity changes in between, but then what happens if a row of faces just got deleted, and we no longer know which beam number is which?

Daniel


(Steve Baer) #4

Why are you referencing the GHA? In the previous sentance you mentioned that you have a library already. Wouldn’t it make sense to place the reusable functionality in the library?


(Daniel Piker) #5

At the moment there is one dll containing the core half-edge mesh functionality, and all the Rhino/Grasshopper specific parts (including the custom parameter class) are in the gha (here)
This was probably a mistake - as you say, keeping all the reusable functionality separate makes more sense.
I’ll have a go at splitting it into a gha with just the components and another dll with everything else.


(Will Pearson) #6

But the custom parameter in the GHA is what Daniel is trying to reference in these other projects.

This allows us to pass our custom mesh around between components from different projects, without losing ngons by converting to the current Rhino mesh or having to deal with polyline representations as Giulio has done with Weaverbird.


(Steve Baer) #7

Can you point me to the “custom parameter” that you are referring to?

I agree that eventually we should be able to have everything in a single assembly and it would be the responsibility of Grasshopper and the RhinoCommon plug-in manager to construct component/plugin/command classes at the appropriate times, but that is not how things are currently structured.


(Daniel Piker) #8

The classes we are talking about are here:
GH_PlanktonMesh.cs
PlanktonMeshParam.cs


(Will Pearson) #9

(Steve Baer) #10

@DavidRutten, is this a class that must be defined in the GHA for things like reflection discovery and instantiation or could it be placed in a library DLL?


(Giulio Piacentino) #11

The case you mention would not be actually a problem if the component that deletes the row keeps track of telling which edges it edited or deleted, or where they ended up. This would essentially be what is done when any “generic” mesh ideally deletes a row. However, in cases such as the ones that you mention (e.g., remembering/noting directions), probably passing a reference of additional ordering (even, possibly the whole half-edge mesh) as an attribute will make sense and be practical. This always needs careful consideration, though, as components that do not understand that item will not have a way to update it.


(Giulio Piacentino) #12

Leaving aside additional edge information that at times could be useful (and that could be passed additionally, in some scenarios): you might for now use an existing, working implementation by referencing Turtle.dll and just using that library to pass meshes around? Weaverbird is able to load those, even today. There is no need to use polylines, although that method was retained for backward compatibility.


(Daniel Piker) #13

Yes, I think that if the face-vertex mesh also contained just an additional pair of lists of vertex indices for the starts and ends of the edges, that should be enough information to determine a unique conversion from face-vertex to half-edge (whenever such a conversion is possible), while also allowing non-manifold meshes. So then there might not be any need to have a different parameter type for half-edge meshes.

Also - one other related thing (which I couldn’t remember whether we’d discussed already) about the new Rhino ngon class is how is it going to handle duplicate points in the vertex list?


(Giulio Piacentino) #14

Is this to retain the list order of edges, or the direction (A-to-B rather than B-to-A flip) of the edge? Or for something else?

Talking with the developer(s) developing this, I think that the idea is to keep it exactly as it is today. This way, normals can be attached for each vertex to each face (or “edge”, if you want), when necessary.


(Daniel Piker) #15

Both. The directions are necessary for the conversion to be unique, because then we can take the first half-edge of the pair corresponding to each edge as the one which matches its direction.


(Giulio Piacentino) #16

Ok, then actually just storing an additional list of booleans telling whether the edge is flipped would be enough to transport that information. The order can be maintained, for example, by just noting down the edge the first time that the edge appears in the face list. This has the advantage that transforming the mesh will not change the order of edges. This is what Weaverbird’s invariant mesh edge tool was doing. The other option, on the other hand, follows Rhino’s original mesh topology edge ordering. That order is not transformation-invariant, but has also advantages (for example, swapping two faces will not change the edge order).

So far so good. But then these directions cannot be autonomously flipped (they would essentially be taken from the right-handed order of the first face in the face list). This is why we would have to store that “flip” information in an extra array, or in “something extra”.


(Daniel Piker) #17

Yes - this sounds like a good solution. Thanks Giulio


(David Rutten) #18

Grasshopper will only load classes from GHA assemblies. There may be ways to tell GH to load additional assemblies, it depends on what function is needed and whether that function is public.


(Giulio Piacentino) #19

What’s the best course of action? Do you want to add that feature to Turtle yourself?


(Steve Baer) #20

Sure I understand that :slight_smile: I was looking to see if Grasshopper used reflection to load classes that derive from GH_PersistentGeometryParam. In other words, could the class GH_PlanktonMeshParam be located in a library DLL without making any special changes to GH?