Update Points <-> Update brep Vertex | Somewhere it fails

import rhinoscriptsyntax as rs
import scriptcontext as sc
import Rhino

# Global variables to keep track of the Brep and point mappings
brep_id = None
brep = None
vertex_point_ids = []
vertex_point_mapping = {}

def extract_brep_vertices_with_update():
    global brep_id, brep, vertex_point_ids, vertex_point_mapping

    # Prompt the user to select a Brep (surface or polysurface)
    brep_id = rs.GetObject("Select a Brep (surface or polysurface)", rs.filter.polysurface | rs.filter.surface)
    if not brep_id:
        print("No Brep selected.")
        return

    # Get the Brep geometry
    brep_obj = sc.doc.Objects.FindId(brep_id)
    if not brep_obj:
        print("Unable to find the Brep in the document.")
        return

    brep = brep_obj.Geometry.Duplicate()  # Make a copy of the Brep geometry
    if not isinstance(brep, Rhino.Geometry.Brep):
        print("The selected object is not a valid Brep.")
        return

    # Initialize mappings
    vertex_point_ids = []
    vertex_point_mapping = {}

    # Iterate over all vertices in the Brep
    for i, vertex in enumerate(brep.Vertices):
        # Get the vertex location
        vertex_point = vertex.Location

        # Add the point to the document
        pt_id = rs.AddPoint(vertex_point)

        # Store the mapping from point ID to vertex index
        vertex_point_mapping[pt_id] = i

        # Keep track of the point IDs
        vertex_point_ids.append(pt_id)

    # Subscribe to the ReplaceRhinoObject event
    handler = BrepUpdateHandler()
    sc.sticky["brep_update_handler"] = handler  # Prevent garbage collection

    print("Brep vertices added as points. Move the points to adjust the Brep geometry.")

class BrepUpdateHandler:
    def __init__(self):
        # Enable the ReplaceRhinoObject event handler
        Rhino.RhinoDoc.ReplaceRhinoObject += self.OnReplaceRhinoObject

    def OnReplaceRhinoObject(self, sender, e):
        # Called when an object is replaced in the document
        if e.ObjectId in vertex_point_ids:
            # If one of our points was replaced (moved), update the Brep
            UpdateBrepGeometry()

    def Dispose(self):
        # Unsubscribe from events
        Rhino.RhinoDoc.ReplaceRhinoObject -= self.OnReplaceRhinoObject

def UpdateBrepGeometry():
    global brep_id, brep, vertex_point_ids, vertex_point_mapping

    # Create a new Brep to modify
    new_brep = brep.Duplicate()
    if not new_brep:
        return

    # Update vertex positions
    for pt_id in vertex_point_ids:
        # Get the new location of the point
        new_pt = rs.PointCoordinates(pt_id)
        if new_pt is None:
            continue

        # Get the corresponding vertex index
        vertex_index = vertex_point_mapping[pt_id]

        # Update the vertex location
        brep_vertex = new_brep.Vertices[vertex_index]
        brep_vertex.Location = new_pt

    # Rebuild edges and faces to reflect the new vertex positions
    new_brep.RebuildEdges()
    new_brep.Faces.ConvertSurfaceToNurbs()  # Ensure surfaces are NURBS for consistency

    # Replace the old Brep with the new one in the document
    sc.doc.Objects.Replace(brep_id, new_brep)
    sc.doc.Views.Redraw()

    # Update the global Brep variables
    brep = new_brep
    brep_id = sc.doc.Objects.Find(new_brep).Id

# Run the function when the script is executed
if __name__ == "__main__":
    extract_brep_vertices_with_update()

What I need :
-user selects brep
-script extract point
-subscribe to event
(works good til now)
-when the point is moved, the vertex of the solid should be moved too updating the 3d geometry

Why is the vertex moving not working? Should be all good

Maybe @dale you can help.
I see you always provide clear code and clear explanations and I’ve learnt a lot from you over the years.
If you could clarify what I’m doing wrong.
Thanks in advance,
Carletto

Could it be that brep_vertex is simply a copy and not a reference to the vertex of the brep?

This can potentially mitigate this, but I haven’t tested it:

new_brep.Vertices[vertex_index] = new_point
1 Like

You want a similar function to the rhino commad solidpoints on ?
https://developer.rhino3d.com/api/rhinocommon/rhino.geometry.brep/transformcomponent

1 Like

Similar yes.
Except the points are always visible and the user can drag a point and It updates the brep.

That wasnt it sadly :frowning:

@dale @stevebaer

Hi @Carlo_Lungiani,

Can you explain what the script is supposed to do?

Thanks,

– Dale

1 Like
  1. There are certain vertees and these are extracted and added to the model as point3d

  2. Then when the user moves the point3d (that rappresents the vertex, but its an actual point in 3d model)

  3. we hook the moving event and want to update the 3d geometry with the new point position (basically update the vertex position based on the moved point position)

Is this clear? Basically like having points ON perma active.

Context :
Doing 3d geometry is half the code, we already did update of 2d geometry. That way we update drawings and 3d at the same time.

So now we are having problem updating the vertex position based on the moved point position so that the new geometry fits the points rappresentation.
Thanks @dale @diff-arch @Tom_P for your time :heart:

As @Tom_P already pointed out, you probably want to use Brep.TransformComponent instead (for simplicity).

If I remember right changing the position of a brep vertex, doesn’t really update the brep edges, but only that specific vertex. Meaning, even if you get this to work, you’ll end up with a new problem. Breps are different, more complex geometries than meshes!
For a brep, you’d probably need to update the faces, edges, loops, and trims, too (cf. documentation).
Simply put, the brep is defined rather by faces and edges, than vertices, since it’s a boundary representation, at least that’s how I interpret this.

This video explains it better:

I understand conceptually
But without some code I am not sure I will be able to get this right.
Let’s wait and see if @dale can build something simple that does this and I integrate it into my code.
I cant find any examples to do this task I have
Thanks again @diff-arch :smiling_face_with_three_hearts:

Hi @Carlo_Lungiani,

Both @Tom_P and @diff-arch are correct. You cannot point edit a Brep like you can a Mesh or a PointCloud.

If you want to transform some component of a Brep, such as a vertex, then use Brep.TransformComponent.

Note, the above is the underlying method used by the SolidPtOn tool.

Here is a simple example of how to use it:

import Rhino.Geometry as rg
import Rhino.RhinoMath as rm
import scriptcontext as sc

def test_transform_brep_component():
    
    bbox = rg.BoundingBox(rg.Point3d.Origin, rg.Point3d(10.0, 10.0, 10.0))
    brep = rg.Brep.CreateFromBox(bbox)
    ci = rg.ComponentIndex(rg.ComponentIndexType.BrepVertex, 1)
    
    dir = rg.Vector3d(5.0, 0.0, 0.0)
    xform = rg.Transform.Translation(dir)
    tol = sc.doc.ModelAbsoluteTolerance
    
    brep.TransformComponent([ci], xform, tol, rm.UnsetValue, False)
    
    sc.doc.Objects.AddBrep(brep)
    sc.doc.Views.Redraw()

if __name__ == "__main__":
    test_transform_brep_component()

Hope this helps.

– Dale

3 Likes

Thank you Dale, I got it to work correctly :money_mouth_face:
And thank you @Tom_P and @diff-arch for your valuable time
This community is awesome :smiling_face_with_three_hearts: