Creating and Working with Kinks in RhinoCommon

I’m interested in implementing a similar functionality to Rhino’s InsertKink command. However, I’d like to be able to nominate an existing row of controls points as a kink, rather than inserting three new rows of control points, the middle of which is the kink.

Is there a way in RhinoCommon to detect if a control point / grip (or row of them) is a kink? Is there a way to create a kink in RhinoCommon? In my searching the API docs I have not found this yet.

I am aware you can create a kink one by piling three control points on top of each other, but I’d like to minimize the number of control points in the surfaces I’m working with.


Hi @bradlcampbell,

You can insert knots into a surface using the NurbsSurfaceKnotList.InsertKnot method.

To insert a kink, set the multiplicity parameter equal to the degree of the surface in the direction you are inserting the knots. For example:

nurbsurface.Knots.InsertKnot(1, v, nurbsurface.Degree(1));

– Dale

My personal experience with kinks:

  1. If you want to seamlessly work with kinks, disable splitting at kinks using CreaseSplitting Enable=No, preferably in your start-up commands.

  2. If you want to add a creased surface no matter what the CreaseSplitting setting of the user, you should use the AddBrep method that has the overload splitKinkySurfaces set to false (see link). But really, you either want to set CreaseSplitting to off programmatically, or instruct your users to do so.

  3. Lastly, you should know that the render meshes get confused by kinks and may look a bit off.

1 Like

Thanks, Dale and Menno. Good info and tips. I’ve started messing directly with the knot vector, which may be a little above my understanding of the math going on here (I may need to dig in a little further). Below is my toy problem in Python (done using mostly the RhinoCommon API and running in Rhino 6). Any recommendations on the approach to modifying the knot vector?

nurbsurface.Knots.InsertKnot inserts additional control points which I don’t want. I’m interested in setting the topology rather than maintaining the existing shape.

The script creates a base surface, adds it to the Rhino document, rebuilds it with more points, then turns a control row into a kink in the manner I am thinking about and adds the modified surface to the document. The result is what I want. Just want to make sure I don’t step on any land mines I don’t see. The ones I do see, that’s another issue :slight_smile:

import Rhino
import Rhino.DocObjects
import Rhino.Geometry as RG
import Rhino.Input as RI
import rhinoscriptsyntax as rs

doc = Rhino.RhinoDoc.ActiveDoc

# Create a base surface to mess with
srf1 = RG.NurbsSurface.CreateFromPoints([
    ], 3, 3, 2, 2)   

guid = doc.Objects.AddBrep(srf1.ToBrep(), None, None, False, False )

# Rebuild it
success = rs.RebuildSurface(guid, (3,3), (11,11))
if not success:

rhobj = Rhino.RhinoDoc.ActiveDoc.Objects.FindId(guid)

brep = rhobj.Geometry
srf1 = brep.Faces[0].ToNurbsSurface()
srf = brep.Faces[0].ToNurbsSurface()


# ---------------------------------------
# Modify the knot vector
vv = 5 # index of parameter to turn into a kink
srf.KnotsV[vv - 1] = vv - 3
srf.KnotsV[vv] = vv - 3
srf.KnotsV[vv + 1] = vv - 3

# Decrement knot values to the right of the one we are looking at
for i in range(vv + 2, srf.KnotsV.Count):
    srf.KnotsV[i] -= 2
# ---------------------------------------

print("U Knot Vector: ", " ".join(srf.KnotsU[i].ToString() for i in range(srf.KnotsU.Count)))

print("Old V Knot Vector: ", " ".join(srf1.KnotsV[i].ToString() for i in range(srf1.KnotsV.Count)))
print("New V Knot Vector: ", " ".join(srf.KnotsV[i].ToString() for i in range(srf.KnotsV.Count)))

doc.Objects.AddBrep(srf.ToBrep(), None, None, False, False )

Looks good, no landmines in sight I think.