How to move mesh vertices in script?

I am working on a script that makes a road based on a spline, on a mesh terrain.
I could not find a move vertices function, so the only way I found to do this was to make a new mesh based on the unchanged and changed vertices.

It works ok, but is there a move vertices function that I could use instead, so I don’t have to duplicate the object properties? (material, unweld value, display modes etc.)

Thanks!

To move a mesh vertex, you:

1.) Get the mesh geometry
2.) Find the vertex (in the mesh)
3.) Modify the vertex
4.) Replace the original mesh with the modified one.

Ok, then I have done it the right way.

Is there a fast way to duplicate all the object settings? Or do I have to read out all those settings manually (Layer, material, mapping, display mode etc.)

Thanks again.

Rhinoscript has ReplaceObject()

Sorry should be:

Rhino.ReplaceGeometry (strTarget, strSource [, blnDelete])

-Willem

Ah, superb, thanks, I’ll test it out right away.

I could not use or find that, and I could not find any info about it either, neither in help or on web. Could you help me out on where to find info about it?

Hi Jorgen

It’s a RhinoScript Method:

HTH
_willem

This hasn’t yet been implemented in Python rhinoscriptsyntax. For RhinoCommon base methods look in the [SDK][1] under ObjectTable.Replace Method. This can be addressed via scriptcontext.Objects.Replace()

–Mitch
[1]: http://4.rhino3d.com/5/rhinocommon/

Hi Jorgen,

I was curious and did some testing for myself.
Below is a script to create an animated waving mesh. It manipulates the vertices of a mesh object and than sets the manipulated mesh via doc.Objects.Replace
test file with a plane mesh:wavemesh.3dm (66.8 KB)

import rhinoscriptsyntax as rs
import scriptcontext as sc
import math

def DirectMeshVertexSet():
    #get mesh object
    mesh_id = rs.GetObject("select mesh",rs.filter.mesh)
    if (mesh_id == None) : return
    #get mesh object in document
    mesh_obj = rs.coercemesh(mesh_id)
    #direct link to the vertex list of the object
    vertices = mesh_obj.Vertices
    
    #create a set of frames
    for frame in range(100):
        #for each frame loop through the vertices and set the Z value accordingly
        for index, vertex in enumerate(vertices):
            vertex.Z = math.sin((vertex.X**2+vertex.Y**2)**0.5-frame/5)
            # set the new vertex 
            vertices.SetVertex(index,vertex)
        #clearing Previous Normals
        mesh_obj.Normals.Clear()
        mesh_obj.FaceNormals.Clear()
        #replace intial mesh with the edited mesh object 
        sc.doc.Objects.Replace(mesh_id,mesh_obj)
        
        #Sleep to catch view manipulations
        rs.Sleep(0)
        #Redraw the viewports
        rs.Redraw()

DirectMeshVertexSet()
3 Likes

Thanks, your curiosity is great!
Because I would never have figured that out by my self :smile:
I managed to implement what you did into my script and it works.

I would like to edit the mesh vertex colors in the same manner, and I am trying to figure out how to get info about stuf like this, but all I find is:
http://4.rhino3d.com/5/rhinocommon/html/AllMembers_T_Rhino_Geometry_Mesh.htm
And that doesn’t make too much sense to me.

Can I add something like “vertex.Color=(0,0,255)”

And where can I find info about what values “vertex” has, like .X, .Y and .Z
Does it have a color value?

And the same about SetVertex. How can I find out what I can add?

Hi Jorgen

a little short in time at the moment but here goes:

For me it’s a lot of trail and error runs, here’s how I’d get to finding how to set the colors for a mesh
(instead of the vertices)

EDIT for some reason the image do not scale automatically, try CTRL and + to zoom in

HTH
-Willem

1 Like

This is for you!!!

http://img.thesun.co.uk/aidemitlum/archive/01611/SNN0150PINT-620_1611775a.jpg

1 Like

Hi Dale, Jørgen, Willem,
I encountered the very same problem as the OP… how to move mesh vertices with a script. As usual I first searched discourse and found this post. I see Dale’s list of steps but I get stuck on point 3:

I just cannot find a way to modify the coordinates of a vertex.
Can anyone of you point me in the right direction?

I’m working in RhinoScript for Rhino 5…

thanks, Tobias

Well, as the first posts in the thread covered, you cannot directly modify yhe vertices of a mesh. You need to modify the point locations and then recreate an entirely new mesh based on the new vertex locations and the original face list.

Working backwards, to add a new mesh it wants this:

The first two arguments are required, the last three are optional. All 5 can be gotten via Rhinoscript for an existing mesh if you look at the Rhinoscript methods.

  • So, for your existing mesh, get at least MeshVertices and MeshFaceVertices.
  • Then, you are going to need to change the point coordinates of each the mesh vertices you want to modify, but without changing the index at which the mesh vertex is stored in the array.
  • Then you can re-create a new mesh with the modified array of mesh vertices and the existing array of face vertices, plus any of the other three optional arguments that you want to transfer over from the original mesh.
  • Then delete the original mesh.

Oh… ok. Thanks a lot. Now I get it :slight_smile: makes perfect sense

In Rhino.Geometry.Collections under MeshVertexList there is the method SetVertex that says you can directly modify a vertex in the geometry of a mesh.

SetVertex(self: MeshVertexList, index: int, vertex: Point3f) -> bool

Sets or adds a vertex to the Vertex List.     If [index] is less than 
 [Count], the existing vertex at [index] will be modified.If [index] equals 
 [Count], a new vertex is appended to the end of the vertex list.If [index] is 
 larger than [Count], the function will return false.

You do need to know the index of the vertex that you want to modify. If you have a mesh ID and the index (an integer) you could use SetVertex like this:

from scriptcontext import doc
from Rhino.Geometry import Point3f
def getGeo(id):
    obj = doc.Objects.Find(id)
    return obj.Geometry

meshGeo = getGeo(mesh)
meshGeo.Vertices.SetVertex(index, Point3f(x,y,z))
doc.Objects.Replace(mesh, meshGeo)

Maybe SetVertex is in Rhino 6 and not Rhino5? I tested this in Rhino 6 and it works. You will have to test it in Rhino 5. But in Rhino 6 there is no need to define a whole new mesh just to modify some vertices.

Thanks Terry, but I am on RhinoScript. Your code looks like RhinoCommon…?
And btw generate a new mesh and replacing the old one works perfectly.

Maybe I got it wrong, but doesn’t this also create a new mesh with the modified vertices and replace the original?

https://developer.rhino3d.com/api/RhinoCommon/html/M_Rhino_DocObjects_Tables_ObjectTable_Replace_18.htm

I agree.
I think this is the way Rhino works

RhinoObject.Geometry gives you a duplicate of the object’s geometry
and ObjectTable.Replace() replaces the original geometry with what you provide.

EDIT

Actually the docs say that what the object receives from ObjectTable.Replace() is a duplicate of the mesh you give to the method.
Then I think we cannot edit a mesh (or any other geometry) in a RhinoObject without duplicating it twice …