How can I use Python to select one (spline control) point of a NURBS curve? I want to select and then move each point to a desired location. If this is not possible, I am happy to start with the locations and create a NURBS curve that ‘joins the dots’.


IMO would join the dots.

I want to select and then move each point to a desired location.

If the idea is to take a set of points and "join the dots" it is quite possibly a lot simpler to to create the spline.

Here is an example using NURBS answser from Create curve from Numpy Array using Python

enter image description here Result displayed in EDIT mode, after running script in OBJECT mode

Set the coordinates as desired, run the script in object mode, creates a curve object with control points at the input coordinates. Removes need to select points, mode toggle, and use operators.

Using numpy and in particular foreach_get(set) is going to be way quicker for a lot of points.

In this example have given each 4D NURB coordinate a weight w of 1.

import bpy
import numpy as np

def flatten(*args):
    c = np.empty(sum(arg.size for arg in args))
    l = len(args)
    for i, arg in enumerate(args):
        c[i::l] = arg
    return c

context = bpy.context

x, y, z = np.array(
        (0, 0, 0),
        (1, 1, 1),
        (0, 1, 1),
        (0, 0, 1),

w = np.ones(len(x))
cu = bpy.data.curves.new(name="poly", type='CURVE')
cu.dimensions = '3D'

spline = cu.splines.new('NURBS') # poly type
# spline is created with one point add more to match data
spline.points.add(x.size - 1)
spline.points.foreach_set("co", flatten(x, y, z, w))

spline.use_endpoint_v = True
spline.use_endpoint_u = True
ob = bpy.data.objects.new("NURBS", cu)     
context.view_layer.objects.active = ob

And for example sake,

enter image description here

running a loop and changing the weight assigned to the 4th coordinate

for j in range(1, 100, 10):
    w = np.ones(len(x))
    w[3] = j


If the desired result is to have the curve pass through the control points, it may be an idea to choose a curve type other than NURBS.

  • $\begingroup$ I agree. Joining the dots is much more sensible.I asked the wrong question (cf The XY Problem). I came up with something that has a similar structure as your code but is far less sophisticated. I used from mathutils import Vector. I would share it but don't seem to be able to use the mini-Markdown formatting in a comment. $\endgroup$ – Paul St George May 1 at 17:56
import bpy
for p in bpy.context.object.data.splines.active.points:
    p.co.z = p.co.z + 1

This works.

UPDATE: (only change selected points)

counter = 0
for p in bpy.context.object.data.splines.active.points:
    print("counter = ",counter)
    if p.select == True:
        p.co.z = p.co.z - 1
    counter = counter + 1
  • $\begingroup$ Thanks! I must be doing something wrong. I assume I start in Object Mode, with the curve selected. I am then trying your code by pasting into Python Console. From: the_curve_data = bpy.context.scene.objects.active.data I get: AttributeError: 'bpy_prop_collection' object has no attribute 'active' $\endgroup$ – Paul St George May 1 at 8:20
  • $\begingroup$ i am sorry - my mistake. i update the answer. this time i tested it ;) $\endgroup$ – Chris May 1 at 9:03
  • $\begingroup$ Almost there. I think. I have tried your code with the last line indented (is that right?). No errors, but it does not select just one point. The curve is selected, not just a point. What do I add to say which point should be selected? $\endgroup$ – Paul St George May 1 at 10:08
  • $\begingroup$ Yes, it moves all points, but hopefully you can add an if Statement in the for loop yourself. Can you? $\endgroup$ – Chris May 1 at 10:34
  • $\begingroup$ I can't! Could you please show the point selection and the translation?? $\endgroup$ – Paul St George May 1 at 10:47

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.