Difference between MeshFace Vertices & TopologicalVertices?

OK, I should probably know this, but what exactly is the difference between “Vertices” “TopologicalVertices” for MeshFaces?

Technical difference or conceptual difference, or both? From a scripter’s perspective - Do I have to know, and What do I have to know, about the difference when manipulating Meshes? And, are they different data in the same Mesh or just a different perspective of the same data?

(I’ve already done some nasty mesh processing with C# but I never had a real understanding about the actual differences, and when it matters to know).

Feel stoopid.

// Rolf

If I remember well TopologicalVertices are here to fasten processing. They are ordered in x y then z. There is some information in .Grasshopper3d.com. And sure it is necessary to use then in some situations. Some examples are are on

Thank you for the link @laurent_delrieu,

Yes, the reason for topology vertices seems to be about speed.

It would be a good thing to have info in one place about how all the topology items / functions relate to each other, and when it’s relevant to regard them.

For Vertexes I found this short snippet by Daniel Piker - a good example of showing how they relate to each other.

bild

But then there are TopologyEdges as well…

There would be an immense benefit to have in one place, on one page, documentation with concrete examples of what and when the Vertex & Edge indices are disrupted, how to prevent it, and/or how and when to sync them, and exactly how (code example) to access them (see example above by Daniel Piker).

Plankton

I’ve seen several references to Plankton, and yes, why not, but then there’s all the mesh components out there that doesn’t work for plankton meshes.

So no matter what approach to take, there’s still very much in need to have some basic technical documention of Rhino Meshes. A class diagram would do wonders to begin with.

// Rolf

2 Likes

@dale Is there a good place to find such informations.
@ril I have the same problems as you. I try to put informations in a word or in text files in order to be able to find examples of scripts.

2 Likes

Bumping up this question again, just to make sure I have arrived at a 100% accurate understanding of how MeshTopologyVertexList differs from the regular MeshVerticesList,

The content of TopologyVertices can be defined as follows (?):

Would following the following rules produce the same content and array structure as the native Rhino MeshTopologyVertexList?

  1. Sort Mesh.Vertices in X, Y and Z order.
  2. Collect identical vertices in arrays (2b. tolerance?).
  3. Unique vertices in single element arrays.
  4. Insert all vertex arrays into a 2-dimensional array of vertices (Point3f[][])

Done? No other rules apply?

// Rolf

1 Like

Here is where the topology vertices are computed for a mesh.

Hm, while reading up on the structure so I can understand this loop, I also noticed one thing that got me wondering. In the code the Face corner indices seems to refer to TopologyVertex indices (m_topov_map):
image

… while the documentation seems to indicate that face corner indices refer to the regular(?) mesh vertices:

Same goes for the documentation text for MeshFace.A…D (which vertex list is meant?):
image

I’ve tried to read my way around in the documentation, but I couldn’t find anywhere where it states explicitly if the indices refer to the MeshVertexList or the MeshTopologyVertexList

(and although I have used these indices in C# code sometime before, I tend to forget which list these indices refer to, so every time I go to search for this info in the documentation I become uncertain, and I end up having to search my code somewhere on disk… hoping I got it right when I last used it…).

So, It would be very good to have the documentation stating explicitly which vertex list the face indices refer to.

Back to trying to figure out what the C++ is actually doing… at first glance populating the TopologyVertexList seems to be a bit more involved than I suggested in my points above.

// Rolf

I’d I remember correctly for UV texture mapping a face vertices need different normals and UV texture coordinates, so they are linked to topological vertices , a vertex can have more than 1 Topovertex like corners of a box where normals and UV change.
Gd

A topological vertex can have more than one ordinary vertex associated with it. The corner of a box is a good way to think of this as there is one topological vertex at the corner, but three ordinary vertices that have three different normals.

Oops,.so it’s the inverse , good to remind that

A mesh face references ordinary vertices in the MeshVertexList.

1 Like

A Mesh is a List of MeshFaces … where these MAY connect each other the way that you think (by visual inspection) … or NOT. That said SplitDisjoint yields connected Faces in the very same sence that a Graph MAY have Islands.

A Mesh Vertex (MV) is a vertex on a per Face basis while a TopoVertex (MTV) is a Vertex on a per Mesh basis. I plain English this means that given a Mesh the MV.Count may be greater than MTV.Count (LOL) - see comments for CombineIdentical below.

MTV indexing IS NOT the same as MV indexing, There’s 2 RC Methods to go from MV indexing to MTV and the other thing. Mesh.Vertices.CombineIdentical (CI) sets (on a per disjoined Mesh basis) these 2 with the same N of indices (but Indexing remains different) .

If CI is not used a MTV can “point” to more than one MV (LOL).

For Connectivity Trees and the likes ALWAYS cut the mustard using MTV.

Do a small test: Given some points find Prox Triads, do a single MeshFace, Append it (i.e. “join” the club) to some test Mesh and then do your investigations (without invoking CombineIdentical). Extract in 2 Lists the MTV/MV indices as well and … blah, blah.

And now the thing for the brave: given solely a VV connectivity can you find the disjoined Meshes? That said this is a good challenge for mastering Recursion (a proper one, mind) while is real-time since does business solely with integers.

Thank you peter for your reply.

Most of this is clear to me (I’ve written thousands of lines of code involving going from MV to MTV with code that actually works). But since there are dedicated methods for translation between the two lists (which I have used a lot, or course), only knowing how to translate between the two lists doesn’t imply knowing the rules for how the MTV list was populated in the first place. Hence the question.

Anyway …

Yup. Therefore the question is only about which rules apply for populating the MTV lists.

Yes, that’s where I asked if it’s enough to pile up similar coordinates into an array for MV’s for a given MTV.

What I did not think of though, was disjoint meshes. But as long as the “mesh-islands” are kept joined (CI) into one mesh, an array of position-similar MV’s under a given MTV should still apply, I assume.

That would be fairly involved.

Recursion doesn’t seem to be the difficulty though. Finding identical MV’s (within tolerance?) that are not part of only a single MTV would be a clue I guess, but I’m not brave enough for just that riddle to be solved today. :slight_smile:

And yes, doing small tests seems to be a good way to get to grips with how MTVs are defined.

// Rolf

I’m also trying to draw a model of how things relate, based on the code which Steve posted. Work in progress though:

// Rolf

Warning: Meshes are bad things (like smoking cheapo cigars). Don’t get lost in the rabbit hole.

Other than that … well … since (mostly) you are after #%$ Meshes (Karma, what else) the disjoin (Islands) part is paramount … since in fact a Connectivity thingy (2 dim Trees: first the index of the Mesh and the other the index of the parent item) must target a disjoined Mesh (where MTV.Count == MV.Count).

That said Mesh items MAY appear “joined” (i.e. items [MeshFaces] belonging to a List of Faces called Mesh).

That said I hate bananas Meshes, good Meshes and any Mesh in fact (plus Points, Lines, Curves, Breps etc etc).

Anyway do the disjoined task using the VV (critical in Graphs) … and then comes the ultimate challenge known to man: a Hamiltonian loop (“circle”) search on a given Mesh (viewed as Graph) that is NOT O(n!). That said this has nothing to do with Sir (LOL) Lewis Hamilton.

No … forget MV and do 2 passes: the first - using MTV - gets the VV (and V as List) like this:

Then … the 2nd pass is a recursion that gets that VV (as 1 dim tree (as shown)) and should yield a 2 dim VV tree (and a 1 dim new V as Tree). All the 1st dim path indices are your disjoined Meshes. Then finish by computing the rest of the connectivity Mesh parafernalia (up to 9 trees but not all are used in common/“ordinary” cases).

Start up tip: use a Mesh that is visibly disjoined and call the CombineIdentical Method. Then instead of invoking the MakeVVConn … as shown in the disjoined Meshes … just work on the 1 dim tree (this makes no sence in a Mesh but DOES a lot of sence in Graphs).

Is a typical case where you date the same girl twice … but we are talking a few milliseconds more … so why bother?

Although this is a bit beside the original question, all kinds of topology is interesting to figure out, but unfortunately I don’t follow you in your last post. Perhaps I’m not focused enough while dealing with other stuff, but I’d be happy to learn more if you could elaborate being more concrete.

// Rolf

Is it?

Anyway let’s use a lineList (i.e. deal with a Graph instead of a Mesh) because this is more “visual”:

So given some Line collection and using the same terminology as in Meshes we can do the V, E Lists and the classic VV, EV, VE conn Trees - without clustering (i.e. restrict/limit our results only to 1st pass). Obviously the connectivity Trees have 1 dim paths. Like:

But … as is the case with Islands on Meshes dealing with a Graph like this is 100% useless.

Enter a 2nd pass (the challenge, that is): using solely the VV thingy as above (a) find the clusters and (b) “redo” all the collections as Trees: VC, EC, VVC, EVC, VEC Trees (where C is a reminder for Clustering):

I hear you: but since the SplitDisjoined Method is available for Meshes why bother talking? Er … hmm … for various reasons (one of them been the 2 dim conn Trees). All that having AEC things in mind (trusses, envelopes and other freaky stuff).

I hear you: I’m not convinced. OK … let’s do our tricks on that Graph:

All appear OK … only to prove the other way with the 2nd pass: for some reason [tol, user error, Karma, shortage of cigars etc etc] the truss is not that OK:


So the wise computer talks and informs us that V 63, 64 + E 169 are not playing ball with the rest > panic > what to do?. Now imagine one of your Meshes (the banana ones).

Tip: here’s (metaphorically) how to cut the mustard on that VV > VVC + … thingy

Hi Ril,

do you have the link from Piker’s example?

No, unfortunately. I don’t remember from which code example that code snippet was.

But to explain that single row of code I made an illustration to show how Mesh.TopologyVertices relates to Mesh.Vertices.

TopologyVertices typically represents a “location”, say the center of the illustrated eight-faced group. The face group has altogether 8 faces, which makes for nine (9) “locations” (corners). (The illustrated faces are shown on different levels to give some room for the numbering). All the red dots should have the same coordinates, or, "stacked on top of each other).

*Fig 1. TopologyVertices stores references (red table) to the actual Vertices list via its two-dimensional arrays. The red table below is shamelessly trying to represent the Mesh.TopologyVertices.MeshVertextindices function which returns each array from the red table):

The 9:th location in the center has index 8 in the illustration (green = Topology vertices)

Now the following code example should make sense:

{
    i = 8;
    // pick first vertex in array
    Point3f p =     Mesh.Vertices[Mesh.TopologyVertices.MeshVertexIndices(i)[0]]; 

    // Or, more readable step for step:

    var TV = Mesh.TopologyVertices;
    int[] v_indices = TV.MeshVertexIndices(i);
    int vertex_at = v_indices[0];
    Point3f p = Mesh.Vertices[ vertex_at ]; 
}

TopologyVertices only references the “real” or actual vertices which are contained in the Mesh.Vertices list.

In the illustration all faces are “unwelded”, which means they do not share vertices, so each individual corner has it’s own vertex. But the number of TopologyVertices are still the same (it still has only 8 “locations”, although the underlaying vertices are stacked on top of each other).

Now, if you want to grab one actual vertex in any of the location, you do not know beforehand if the location is welded (whether all corners share one single underlaying vertex) but regardless of how many vertices are stacked on top of each other, the best bet is to always pick the first one since there will always be at least one vertex in a location. So, no matter if the index 8 of TopologyVertices has an array of 8 other index references to the “real” Vertices table, just pick the first index and you have at least one location coordinate.

// Rolf

Edit: Misspelled property

1 Like