I am writing a deformation command with Rhinocommon. It takes a surface (or other object) and repositions its control points, and then adds the surface back to the document. The code below doesn’t have any of the repositioning going on, it just gets the control points of a surface, and then immediately tries to recreate the surface. It works for a simple 4 sided surface.
But when I have a surface which has two sides sharing an edge, this presents a problem. I can solve it by not including the start and end points in the right direction (u or v depending on which edge is shared), but tangency at the seam is lost. How might I solve this?
I will also have to make it work with trimmed surfaces. It does some curious things to spheres too…
Perhaps there is a more robust way to gather all info from a surface that can be used to recreate it?
I’ve attached a file with a couple example surfaces to try it on. Surfaces.3dm (251.8 KB)
Thanks,
Sam
Dim rhObject As Rhino.DocObjects.ObjRef
Rhino.Input.RhinoGet.GetOneObject(“Select Surface”, True, Rhino.DocObjects.ObjectType.Brep, rhObject)
Dim Brep = TryCast(rhObject.Geometry, Rhino.Geometry.Brep)
Dim NurbsSurface = Brep.Surfaces(0).ToNurbsSurface
Dim NurbsSurfacePoints = New List(Of Rhino.Geometry.Point3d)
Dim srfU = NurbsSurface.Points.CountU
Dim srfV = NurbsSurface.Points.CountV
For u = 0 To srfU - 1
For v = 0 To srfV - 1
NurbsSurfacePoints.Add(NurbsSurface.Points.GetControlPoint(u, v).Location)
Next
Next
doc.Objects.AddPoints(NurbsSurfacePoints)
Dim NewNurbsSurface = Rhino.Geometry.NurbsSurface.CreateFromPoints(NurbsSurfacePoints, srfU, srfV, 3, 3)
doc.Objects.AddSurface(NewNurbsSurface)
Keep in mind that not all surfaces in Rhino are NURB surfaces. Your sphere is a surface of revolution, for example. But, you can get the NURB form of all non-NURB surfaces.
Also keep in mind that there is more to a NURB surface than just control points. Degree/order, rational/non-rational, weights, and knots are also part of a NURB surfaces definition. So in cloning a NURBS surface, it is not enough just to copy the control points.
And trimmed surfaces are another deal, as the trimming information in not stored on the (underlying) surface, but rather on the Brep.
If you are looking to deform a surface, you might want to consider manipulating a surface’s grip location. When grip editing a surface, the surface knows how to rebuild itself based on the updated grip locations.
Dim go As New Rhino.Input.Custom.GetObject()
go.SetCommandPrompt("Select surfaces for control point display")
go.GeometryFilter = ObjectType.Surface
go.SubObjectSelect = False
go.GroupSelect = True
go.GetMultiple(1, 0)
If (go.CommandResult() <> Result.Success) Then
Return go.CommandResult()
End If
For i As Integer = 0 To go.ObjectCount - 1
Dim objRef As Rhino.DocObjects.ObjRef = go.Object(0)
Dim rhObj As RhinoObject = objRef.Object()
If rhObj IsNot Nothing Then
rhObj.GripsOn = True
rhObj.Select(False)
End If
Next
doc.Views.Redraw()
Once on, you can use RhinoObject.GetGrips to get the grip objects.
The next step is to move the grips and have the surface update to the new position. I added to your code to get the object grips, translate them, and commit changes to the grips and the rhino object. But when I run it, I just see a yellow preview of the translated surface, but it disappears when I hit escape. How can I make it so the original surface is translated permanently?
Thanks,
Sam
Dim go As New Rhino.Input.Custom.GetObject()
go.SetCommandPrompt(“Select surfaces for control point display”)
go.GeometryFilter = Rhino.DocObjects.ObjectType.Surface
go.SubObjectSelect = False
go.GroupSelect = True
go.GetMultiple(1, 0)
If (go.CommandResult() <> Rhino.Commands.Result.Success) Then
Return go.CommandResult()
End If
For i As Integer = 0 To go.ObjectCount - 1
Dim objRef As Rhino.DocObjects.ObjRef = go.Object(0)
Dim rhObj As Rhino.DocObjects.RhinoObject = objRef.Object()
If rhObj IsNot Nothing Then
rhObj.GripsOn = True
rhObj.Select(False)
Dim Grips() = rhObj.GetGrips()
For j = 0 To Grips.Length - 1
Dim testTransform As Rhino.Geometry.Transform
testTransform = Rhino.Geometry.Transform.Translation(-3, -3, -3)
Grips(j).Move(testTransform)
Grips(j).CommitChanges()
Next
rhObj.CommitChanges()
End If
Next
doc.Views.Redraw()
Sorry to lead you on a wild goose chase. But from what I can tell, you cannot get there from here.
After moving the grips, you should (somehow) be able to ask the object’s grip controller to generate new geometry based on the new location(s). I just don’t see a way to do this (yet).
I’ve put an action item on the RhinoCommon developer’s to-do list. Hopefully we can get this figured out shortly.
Tell me if I’m wrong, but I think polysurfaces don’t have grips, so that would have messed me up anyway.
The deformation function I’m developing is kind of like an automated cage edit where the cage points are moved so as to ‘flow’ objects from a set of base points to a set of target points. Only I wasn’t using cage edit but rather my own Free Form Deformation algorithm (bernstein polynomial deformation kinda thingy…).
But I’m starting to think I should just script the movement of the cage points for a rhino cage edit, it would be a lot more straight forward and might avoid this the grip problem. I remember previously moving cage points with rhinoscript. Is there a way to move cage points with rhinocommon?
Thanks, I was able to move the grips. For moving the grips of of a cage however, they move but the object contained by the cage does not, it is just duplicated in the original position. I used to move cage points with rhinoscript “rhino.ObjectGripLocation”. What is the equivelant for RhinoCommon?
I’m debating between using rhino’s cageedit or my own FFD algorithm. The disadvantage of using cageedit is that it doesn’t do points (I believe that was on the wish list a while ago, any update on when that might be working?)… The disadvantage of my own FFD algorithm is that polysurfaces don’t have grips, so I have to move the surfaces individually and end up having to retrim them to fit each other afterwards… choices choices, just writing out loud here…
Before anyone can chime in, we’ll need to hear more about your requirements. Is this deformation any different than what you can already do in Rhino. Are there samples you can point us do?
I’ve decided to try using Rhino’s cageedit. So all I need is to be able to move the cage points with rhinocommon, how can I do this?
Mine is an iterative version of the Free Form Deformation originally proposed by Sederberg and Parry (1986). Just seems Rhino’s Cageedit is more robust for keeping everything intact…
I was going to try your code, but found I didn’t have command templates for C#. So, to get the latest wizards installed, I deleted the rhino common wizards from my program files, then removed the files from my visual studios 2010 pro installation, and then tried to install the latest rhinocommon templates for V5, but when I try to install, I get the error its already installed in all applicable products. Do you know whats going on?
I’m pretty sure Visual Studio doesn’t expect users to manually delete anything from program files. If you go to the extension manager in Visual Studio “under tools menu”, do you see RhinoCommon templates for v5 listed? If so, maybe you can click the uninstall button there to get rid of the currently installed templates.
Hi Steve, I was able to remove the previous RhinoCommon templates and then run the RC package. One curious thing I am noticing is that I am able to add a new command and drag and drop the rhp file into rhino and have the command be recognized, but when I start debugging from visual studios and rhino is opened, rhino doesn’t recognize my command. Do you know why not?
On a side note, I have always found it time consuming to be constantly opening and closing rhino as I develop and trouble shoot my plugin. Do you know if there is a way I could just leave Rhino open? (I tried building the solution while Rhino is open, but the pdb file is in use…
Dale, I’m getting an error when I try to use your C# code: “The type or namespace dictionary could not be found”. What is dictionary?