2
$\begingroup$

I have looked through previous questions on this and many other boards and I cannot seem to find a previous answer.

I have a largish Numpy generated ndarray that represents a harmonograph output (40000,3) using coords_list=np.column_stack((x,y,z)) of the individual axis outputs. Its all in one plane at the moment but this may change. Snippet shown below.

[[ 9.66087215e-01  1.78218213e-01  0.00000000e+00]
 [ 9.81957877e-01  2.04711827e-01  0.00000000e+00]
 [ 9.97284974e-01  2.31680099e-01  0.00000000e+00]
 ...
 [-5.26862572e-07 -5.59294782e-05  0.00000000e+00]
 [ 4.18313552e-07 -3.48825009e-05  0.00000000e+00]
 [ 5.71013430e-07 -1.62274906e-05  0.00000000e+00]]

Is blender to be able to read this array to create a curve. I've seen a number of questions that are similar but when I replace the list with an array I get errors as a list was expected rather than an array.

For example - ( How to make a curve path from scratch given a list of (x, y, z) points?). Many others seem to casually say that the lists can be replaced by an array but with no examples, I am a bit flummoxed.

I have also looked at using the foreach_set method to extract vertices from the NumPy array. But it's way over my head at the moment.

Do I need to convert my array to another format so they can define a curve?

$\endgroup$
1
  • $\begingroup$ I have also looked at this. Note the comment regarding the array replacement. link $\endgroup$
    – Terela02
    Commented May 27, 2020 at 15:40

1 Answer 1

6
$\begingroup$

Create POLY type curve from numpy array

Script below creates a POLY type curve from 4d SplinePoint.co numpy array.

enter image description here Script result in edit mode

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

# emulate numpy data
x = np.arange(0, 10, 0.1)
y = 2 * np.sin(x)
z = np.cos(4 * x)
w = np.ones(len(x))

cu = bpy.data.curves.new(name="poly", type='CURVE')
cu.dimensions = '3D'

spline = cu.splines.new('POLY') # 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))

ob = bpy.data.objects.new("Poly", cu)     
context.collection.objects.link(ob)

For a simple two point NURBS curve from local coordinates (0, 0, 0) to (1, 1, 1) the coordinates can be defined

NURBS

For NURBS required to define the end_path_u How to specify Nurbs path vertices in python?

Have introduced for each point having radius of r and setting this as well.

# emulate numpy data
x, y, z, w, r = np.array(
    (
        (0, 0, 0, 1, 0.5),
        (1, 1, 1, 1, 3.0),
    )
).T
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.points.foreach_set("radius", r.ravel())
spline.use_endpoint_u = True
ob = bpy.data.objects.new("Poly", cu)     
context.collection.objects.link(ob)
context.view_layer.objects.active = ob
ob.select_set(True)

Notice in the foreach_ methods require us to ravel (or flatten) the array. Flattening data as shown in https://blender.stackexchange.com/a/172973/15543 the stackoverflow link suggests slicing is quickest.

$\endgroup$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .