TopologyVertices - what are they used for?

hello,
i have a mesh and want to find all vertices that connect through an edge with a specific vertex.
In the mesh.Vertices members i have a (very slow) GetConnectedVertices.
But there is this whole TopologyVertices (and Edges) Class - and i tried TopologyVertices.ConnectedTopologyVertices but i dont unterstand the results. (i get some indices, but they seem very wrong)
Can someone give me a short explanation what this topologyclasses are, and what they can be used for?
thanks!

A mesh is really nothing more than class that holds a collection of points (vertices) and a collection of faces (vertex indices). There are a few other things (vertex and face normals, vertex colors, texture coordinates, etc.). But they are not important for this discussion.

When trying to dig through a mesh, the raw data structure isn’t of much help. So, Rhino can build a mesh topology from a mesh, which provides a structured approach at looking at the raw mesh data.

For example, a mesh does not have a collection of edges. But a mesh topology has topological edges, which know what faces they share. They also know their topological vertices. A topological face knows of it’s topological edges. And a topological vertex knows of it’s mesh vertices (there can be more than one). With these interconnected structures, it becomes quite easy to navigate through a mesh to discover all sorts of this.

For example, naked edges are simply edges that only have a single face reference. It is easy to find naked edges using a mesh topology, not so easy using just the raw mesh data collections.

Hope this helps.

– Dale

1 Like

I think i get it a bit better - i know that in other programms each vertex can have one or more normals, to have different smoothing appearance, but i always thought rhino is straightforward there, as welded vertices always show as smooth.
What i cant imagine is a case where a topological vertex can have more than one “real” vertex, and why / how the indices of topological vertices differ from “real” ones…
If i understand you, TopologyVertices.ConnectedTopologyVertices should give me exactly that kind of information, but it does not - what i get back is not random, it follows some subd logic (the mesh in question was subdivided in max), but it doesnt give me the neighbors i would expect looking at the mesh in my viewport…
I also converted the ConnectedTopologyVertices results with MeshVertexIndices, but still it doesnt look right

@Dale, i´ve discovered the same as Damjan when experimenting with Mesh.TopologyVertices and Edges. It was not possible to get the naked edges. In my case the edges where coincident but unwelded. ConnectedTopologyVertices reported them as connected, but they where seperated (but coincident).

any thoughts ?

c.

If anyone has a sample that does not work how they expect, I would be happy to take a look. It could be a bug in RhinoCommon that needs to be fixed

Hi Steve,

the problem i´ve been facing is that the vertex index of a topology vertex was different from the index of a regular vertex using Mesh.Vertices. After i´ve figured out that these are different in general (eg. the count) i´ve not been able to create a function to return all naked edges. Eg. How to write a function in Python which returns the vertex pairs of all naked edges ?

Note: I´m not trying to get the indices of “naked” Mesh.TopologyVertices but the ones of Mesh.Vertices, but in pairs to define the edge.

c.

This sample command will duplicate naked mesh edges. Does this help?

https://github.com/dalefugier/SampleCsCommands/blob/master/SampleCsDupMeshBorder.cs

Thanks Dale, well yes if i would work with Mesh.TopologyVertices, but no when i try to work with Mesh.Vertices and Mesh.Faces in Python.

What i´m trying to do in Python or even RhinoScript is to work with an array of Mesh.Faces first. When i iterate over the faces, i´m able to find out which Mesh.Vertices do belong to each face (i get 4 vertex indices per face). I then query for vertices surrounding a single vertex eg. for a vertex with index 5 i get a list of surrounding vertex indices 6,7,3,4.

Now my problem is, while beeing in a loop of Mesh.Faces, how can i efficiently query if the edges formed by vertex index pairs 5-6, 5-7, 5-3 and 5-4 are naked or not ? I know i can query single vertex indices for being naked using MeshNakedEdgePoints, but how to do it for pairs of vertex indices ? I´ve found cases where i eg. query vertex 6 and 7 using the MeshNakedEdgePoints function and both return beeing naked, but the edge formed between them is shared by two faces and not one. Note that i do not work with topology vertices, but with MeshVertices.

The problem why i´m not able to use topology edges in my case is that i have to run it on meshes which have unwelded but coincident edges. My solution so far has been to write all edge pairs (with ascending indices) in a dictionary, using the vertex index pair as key like 4_6 and putting the corresponding face indices as dictionary value(s). This way i can simply query an edge eg. formed by index pair 6_4 (which reads 4_6, because of ascending keys) and then read out how many faces are connected. If only one is connected, the edge is naked, similar as proposed in your example. The function looks like this in RhinoScript:

Public Sub ADD_IndexToEdgeList(ByRef v_a, ByRef v_b, ByRef intFaceIndex)
	
	If v_b > v_a Then strEdge = v_a & "_" & v_b Else strEdge = v_b & "_" & v_a

	If EdgeList.Exists(strEdge) Then
		EdgeList(strEdge) = Array(EdgeList.Item(strEdge)(0), intFaceIndex)
	Else
		EdgeList.Add(strEdge), Array(intFaceIndex)
	End If 
	
End Sub

Is there a more efficient way to do this in Python or even plain old RhinoScript ?

thanks,

c.

I think I understand what you are looking for, but before I start typing I want to make sure I understand what your query function would look like. Are you searching for all faces that belong to a given index pair?

Something like

def FindFaces( vertex_a, vertex_b )

and this would return a list of faces or None if no faces are found.

Or are you looking for something else?

Thank Steve, yes this would indeed be very useful in Python and vb RhinoScript.

I wrote something as well to generate a list of connected (surrounding) vertices for a single mesh vertex in RhinoScript but doing it faster with a built in function which generates these lists (or array of arrays) in one go, would be useful too. The function looks like this in RhinoScript, the dictionary is used to remove duplicated vertex indices only:

Private Function GET_AllMeshVertexNeighbours()
	
	GET_AllMeshVertexNeighbours = Null 
	
	Dim v, arrConnectedFaces, intCBound, f, arrFV, arrEdgeNeighbours()
	Dim MiniDict
	
	Set MiniDict = CreateObject("Scripting.Dictionary")
	MiniDict.CompareMode = vbBinaryCompare
	
	ReDim arrEdgeNeighbours(UBound(arrV))
	
	For v = UBound(arrV) To 0 Step -1
		
		arrConnectedFaces = arrAllVF(v)
		
		intCBound = UBound(arrConnectedFaces)
					
		For f = intCBound To 0 Step -1
		
			arrFV = arrI(arrConnectedFaces(f))
		
			If (arrFV(2) = arrFV(3)) Then 

				Select Case v
					Case arrFV(0)
						MiniDict(arrFV(1)) = 0
						MiniDict(arrFV(2)) = 0
					Case arrFV(1) 
						MiniDict(arrFV(0)) = 0
						MiniDict(arrFV(2)) = 0
					Case arrFV(2)
						MiniDict(arrFV(0)) = 0
						MiniDict(arrFV(1)) = 0
				End Select
			Else

				Select Case v
					Case arrFV(0), arrFV(2)
						MiniDict(arrFV(1)) = 0
						MiniDict(arrFV(3)) = 0
					Case arrFV(1), arrFV(3)
						MiniDict(arrFV(0)) = 0
						MiniDict(arrFV(2)) = 0
				End Select
			End If
		
		Next
	
		arrEdgeNeighbours(v) = MiniDict.Keys()
		
		MiniDict.RemoveAll()
		
	Next
	
	GET_AllMeshVertexNeighbours = arrEdgeNeighbours
	
	Set MiniDict = Nothing
	
End Function

thanks for looking into it !

c.

@stevebaer, just for completeness and easier understanding, in the last function above the variable arrAllVF() refers to an array containing the faces connected to each vertex. The counters run backwards for more speed in RhinoScript only. :wink:

c.

Okay, so you want a function that returns face indices given a single vertex? Is that correct? I thought you wanted face indices given a vertex pair (edge).

Hi Steve, both are correct, a function to return the face indices connected to vertex pairs (if any) and a function to return face indices connected for all vertices. The latter is easy to query for a single vertex, but a bit slow for all vertices.

thanks,
c.

Hello again, one more finding regarding vertex topology -
this is a simple script that should find the neighbors of a given vertex, but it doenst work well.
If i give it a meshed nurbs-plane from rhino it woks fine, but as soon as i try it on subdivided geometry (meshsmooth geometry from 3ds max imported as obj), it fails.
here is the obj from max:
plane_subd.zip (2.6 KB)

edit: actually it only works with a “simple” meshed rhino plane, meshes from any other nurbs geo wont work either

import Rhino
import System
import rhinoscriptsyntax as rs
from Rhino import RhinoApp
from scriptcontext import doc
def RunCommand():
    mesh = getLayerMesh("Default")
    neighbors(mesh, 100)

def neighbors(mesh, n):
    doc.Objects.AddPoint(mesh.Vertices[n])
    a = mesh.TopologyVertices.ConnectedTopologyVertices(n)
    b = []
    for i in xrange(0,a.Count):
        c = mesh.TopologyVertices.MeshVertexIndices(a[i])
        b.append(c[0])
    for i in xrange(0,a.Count):
        doc.Objects.AddPoint(mesh.Vertices[b[i]])

def getLayerMesh(layer):
    temp = rs.ObjectsByLayer(layer,False)
    ref = Rhino.DocObjects.ObjRef(temp[0])
    return ref.Mesh()

if __name__ == "__main__":
    RunCommand()

Hi Damjan,

i´ve been cought by the exact same behaviour and found that it`s not rhino’s fault but me understanding some fundamental things :smile:

The most important thing to understand is that Mesh.Vertices and Mesh.TopologyVertices are not the same, they refer to different kind of vertices, they do have different indices and count. So the problem with your script is, that the vertex 100, where you add a point using

doc.Objects.AddPoint(mesh.Vertices[n])

is not vertex 100 of Mesh.TopologyVertices. It is vertex 100 of Mesh.Vertices. Try to add the point to the topology vertex 100 to see the difference.

c.

thanks alot!!
yes, totally overlooked that i have to convert the input also!