Using RhinoCommon command in Python to access Brep Vertices

Hello,
I am trying to use Rhino Python (Version 7) to access and translate brep vertices. It seems like there is a RhinoCommon command to access the vertex list that returns BrepVertex objects. These objects have a Translate and Transform method. That is encouraging - it seems like the functionality is there.

But I am missing some piece of knowledge that will let me use these functions/methods on an existing brep surface. Could somebody please enlighten me on how I am supposed to use these methods in Python?

Thank you for your help.

Link to the BrepVertex class

Link to BrepVertexList class

Hi @Henry_Wede,

i guess youā€™re looking for Brep.TransformComponent. Try below with a brep box:

import Rhino
import scriptcontext
import rhinoscriptsyntax as rs
def DoSomething():
    
    brep_id = rs.GetObject("Select brep box", rs.filter.polysurface, True, False)
    if not brep_id: return
    
    brep = rs.coercebrep(brep_id, True)
    
    # vertex numbers to transform
    numbers = [2, 7]

    index_type = Rhino.Geometry.ComponentIndexType.BrepVertex
    components = [Rhino.Geometry.ComponentIndex(index_type, i) for i in numbers]
    
    xform = Rhino.Geometry.Transform.Translation(0,0,10)
    tolerance = scriptcontext.doc.ModelAbsoluteTolerance
    
    rc = brep.TransformComponent(components, xform, tolerance, 10, True)
    if rc:
        scriptcontext.doc.Objects.Replace(brep_id, brep)
        scriptcontext.doc.Views.Redraw()
        
DoSomething()

_
c.

1 Like

Hello,
That definitely changed the surface - but not the way I was hoping for. I think that I confused control points and vertices - I am out of my bubble on this project. Iā€™m sorry about that. I didnā€™t intend to waste your time.

Using the RhinoScriptSyntax, I was able to access the rs.SurfacePoints of the surface (800+ in my case). These are the same control points I am used to seeing when pressing F10/F11. So far, so good. Then the script figured out a displacement for each control point. I have a list of displacements (and a list of surface normals if needed). But I cannot find any documentation on how to move the control points.

I think the brep.TransformComponent was doing something way more profound. It also creates many more control points and ā€œbend neighbors to matchā€ which blows up the individual displacements.

Do you have any suggestions for moving the control points?

Sorry again for mixing up control points and vertices.

Henry

Some additional informationā€¦ the ā€œobject descriptionā€ of the surface displays this:

Geometry:
Valid surface.
trimmed surface.
NURBS Surface"U": degree =3 CV count = 23 (-82.2027 <= U <= 702.172)
ā€œVā€: degree =3 CV count = 36 (0 <= V <= 567.079)
Edge Tally:
6 boundary edges
Edge Tolerances: 0 to 0.0001
median = 0 average = 3.33333e-05
Vertex Tolerances: all 0
Render mesh: 1 mesh 1916 vertices 1933 polygons
Created with fast meshing parameters.
Analysis mesh: none present

I suspect the answer is in Rhino Common someplace, but I have close to zero luck finding examples or understanding the documentation. I see Rhino.Geometry.Collections.NurbsSurfacePointList that has methods that ~might~ move control points but no idea how to use that with an existing surface. A little frustrating.

Hi @Henry_Wede,

There are a couple of grip moving samples.

test_move_grips.py (803 Bytes)
test_move_grips.py (2.4 KB)
test_dynamic_move_grips.py (1.9 KB)

ā€“ Dale

Thank you Dale! I was able to move your code around a bit and make it work for my needs. Most examples here seem to use the interactive way of selecting objects and I have to find a way to make it non-interactive.

I pasted some code that worked for me and maybe will help somebody searching for this. Also look at the example scripts in the previous comment. One interesting thing is that the Add method of the TransformObjectList wanted an object reference instead of a GUID. Well, that is interesting for me because I though GUID was enough. Note that some methods return a list and I just wanted an object, so there are some [0] hiding here and there.

# For testing, just get direct references to the mesh and surface
TargetSurface = rs.ObjectsByName('upper')[0]

# Deselect everything and turn the grips on
rs.UnselectAllObjects()
rs.EnableObjectGrips(TargetSurface)

# The number of grips = rs.SurfacePointCount()
GripCount = rs.ObjectGripCount(TargetSurface)

# Return the GUID of grip number 10 (for example)
rs.SelectObjectGrip(TargetSurface, 10)
SelectedGrip = rs.SelectedObjects(False, True)

# To add the grip to the TransformObjectList, it needs an ObjRef not GUID
GripReference = Rhino.DocObjects.ObjRef(SelectedGrip[0])
ObjectList = Rhino.Collections.TransformObjectList()
ObjectList.Add(GripReference)

# Transformation +20mm in Z direction
Direction = Rhino.Geometry.Vector3d(0.0, 0.0, 20.0)
Transform = Rhino.Geometry.Transform.Translation(Direction)

# Move the grip
TheGrip = ObjectList.GripArray()[0]
TheGrip.Move(Transform)

# Let the owner of the grip (surface?) know it was moved
GripOwner = ObjectList.GripOwnerArray()[0]
sc.doc.Objects.GripUpdate(GripOwner, True)

# May be needed, maybe not
sc.doc.Views.Redraw()

If you stumble on this post looking for a solution, there is another post below that looks promising. I could not figure out how to get a Rhino.Geometry.NurbsSurface object from an existing NURBS surface. If you find a way (without using an interactive dialog box) please post it. Thank you! However, the code above should also work.

Hi @Henry_Wede

This is a bit confusing. Weā€™ll need more details.

ā€“ Dale

Hello Dale,

Sorry, let me try again.

I already have a existing surface, and I get the GUID of that surface using this:
TargetSurface = rs.ObjectsByName('upper')[0]

In practice, there will be a better method of selecting the surface but this works for testing.

In the other post, the person used this command:
Control_Points = Rebuilt_Surface.Points

where RebuiltSurface is a Rhino.Geometry.NurbsSurface object. So to follow his example I need one of those type of objects. Admittedly, the Rhino Common documentation is not intended for me as an amature Python programmer. I couldnā€™t find a way to create NurbsSurface object from my existing nurbs surface. That sounds silly when you read it, but I hope it is clear. There is no constructor that accepts a GUID from a nurbs surface.

I think this is a problem of crossing the bridge from the rs module to the Rhino module. There is some skill to go across that bridge and I donā€™t have it mastered.

Did that help explain things?

Hi @Henry_Wede, below should clear things up a bit:

import Rhino
import scriptcontext
import rhinoscriptsyntax as rs

obj_ids = rs.ObjectsByName('upper')
if obj_ids:
    obj_id = obj_ids[0]
    if rs.IsSurface(obj_id):
        
        rhino_object = rs.coercerhinoobject(obj_id)
        print rhino_object
        
        brep_face = rs.coercesurface(obj_id, True)
        print brep_face
        
        nurbs_srf = brep_face.ToNurbsSurface()
        print nurbs_srf
        print nurbs_srf.Points

All rs methods work with object ids. To access things in RhinoCommon, itā€™s best to work with Rhino objects, from them you can access the Id, ObjectAttributes or the Geometry. Having an Id, you might use one of the rs.coerce... methods to directly access what you need.

_
c.

Sorry for the delay - thank you so much for your answer.

the rs.coerceā€¦ methods are vital to using RhinoCommon in Python, but yet there is zero documentation on them. Seems like a conspiracy or something :slightly_frowning_face:

Thanks for spending your time helping people - it is appreciated.
Henry

1 Like

Well, the history behind this is that originally these methods were intended as internal-use utility tools - which are actually called by many other rhinoscriptsyntax methods. But then they became more or less public and people outside McNeel started using them.

Basically any ā€˜coerceā€¦ā€™ method tries to convert one of several possible input data types into the desired output type. If it succeeds, the correct object type is output, it it fails, you get None or a slightly more descriptive error message if the ā€˜raiseā€™ flag is set to True.

If you know how to read Python/RhinoCommon code, you can look them up here and see what they are actually doing.
C:\Users\<username>\AppData\Roaming\McNeel\Rhinoceros\(7.0 or 8.0)\Plug-ins\IronPython (814d908a-e25c-493d-97e9-ee3861957f49)\settings\lib\rhinoscript\utility.py

It is possible to do without the coerce functions, one simply has to first determine the data input type (GUID, string, etc.) and then use the appropriate method to get the RhinoCommon object. For example in the case of a GUID of an object that is in the document, one can use

obj=scriptcontext.doc.Objects.FindId(GUID)

The advantage of using the coerceā€¦ methods is that one does not need to figure out what the input data type is in advance.

Yes, I can appreciate the issues of allowing the public to flood in and see RhinoCommon interfaces. Instead of an audience of professional developers, now there are people like me looking around.

Iā€™ve been able to piece together the bits and pieces that I neededā€¦ but the pieces are scattered around various forum posts. Including the obj=scriptcontext.doc.Objects.FindId(GUID) that you mentioned above.

I do think that enough time has passed that a proper guide should be written. It would have helped me a lot and would probably help other people using the software.

Thanks for you input and insight.

Hi @Henry_Wede,

There are several Python guides here:

Have you see them?

ā€“ Dale