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’.
2 Answers
import bpy
for p in bpy.context.object.data.splines.active.points:
p.co.z = p.co.z + 1
bpy.ops.object.mode_set(mode='EDIT')
This works.
UPDATE: (only change selected points)
bpy.ops.object.mode_set(mode='OBJECT')
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
print("selected")
counter = counter + 1
bpy.ops.object.mode_set(mode='EDIT')
- 59,454
- 6
- 30
- 84
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
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),
)
).T
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.collection.objects.link(ob)
context.view_layer.objects.active = ob
ob.select_set(True)
And for example sake,
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
Note.
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.
- 84,216
- 10
- 108
- 233
-
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. – Paul St George May 01 '21 at 17:56

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.dataI get:
– Paul St George May 01 '21 at 08:20AttributeError: 'bpy_prop_collection' object has no attribute 'active'bpy.ops.transform.translate(value=(2,0,0)) # insertafterprint("selected")and cycle through selecting and moving the points like that? – Paul St George May 01 '21 at 13:11