Creating sinusoidal struts using bpy I want to use Blender and bpy to create sinusoidal struts. I have been using Python with VTK in the past, but it is causing some trouble and I feel Blender might be the better solution.

An example of what I want to create is depicted below. It is planar in a sense that only one axis is modified with a sin (or in this case cos) function. It is also tilted by 45°, but that's not the big hurdle.



Since I am very new to Blender, I googled around a bit and found this: http://wiki.theprovingground.org/blender-py-mathmesh

It contains the following code that creates a surface that is modified with sin:

import bpy
import math

# mesh arrays
verts = []
faces = []

# mesh variables
numX = 10
numY = 10

# wave variables
freq = 1
amp = 1
scale = 1

#fill verts array
for i in range (0, numX):
    for j in range(0,numY):

        x = scale * i
        y = scale * j
        z = scale*((amp*math.cos(i*freq))+(amp*math.sin(j*freq)))

        vert = (x,y,z) 
        verts.append(vert)

#fill faces array
count = 0
for i in range (0, numY *(numX-1)):
    if count &lt; numY-1:
        A = i
        B = i+1
        C = (i+numY)+1
        D = (i+numY)

        face = (A,B,C,D)
        faces.append(face)
        count = count + 1
    else:
        count = 0

#create mesh and object
mesh = bpy.data.meshes.new("wave")
object = bpy.data.objects.new("wave",mesh)

#set mesh location
object.location = bpy.context.scene.cursor_location
bpy.context.scene.objects.link(object)

#create mesh from python data
mesh.from_pydata(verts,[],faces)
mesh.update(calc_edges=True)


I just can't rewrite it to just creating a strut, though. Originally, I created the points using the following approach with numpy + vtk, but when I try this in Blender I get error messages ('Unsupported operand type(s) for /: "tuple" and "int"' on the line where I define y in the function).

def strut(x, node_dist=5, amp=1):
    """Takes 1D array x, creates shape and normalizes it to fit the length of the cosine function."""
    x = x * 2 / node_dist * np.pi  # normalize length to fit [-4pi; 4pi]
    y = amp / 2 * np.cos(x) + amp / 2  # adjusting position and amplitude
    return y

a = np.linspace(-2 * node_dist, 2 * node_dist, points_per_line)
b = strut(a, node_dist, amp) - node_dist / 2.
c = strut(a, node_dist, amp) + node_dist / 2.

for i in range(0, a.shape[0], 1):
    if strut_number == 1:
        x = a[i]
        y = b[i]
        z = c[i]


If I could just get some help with being able to define how many points on the line I want(-> smoothness) and how to define the shape (ideally quadratic) around the strut I could figure the rest out myself. I hope my question is specific enough and not too odd. Thanks for any help!
Got it to work with Bmesh (not necessary but easier to work with IMHO).
Had to add several chunks of code that will generate 4 waves as the main longitudinal edge loops, and add faces to the mesh.



This can be fairly easily expanded to generate other shapes, or non-quad based struts. Here you can control the width (thickness) of the 3D strut via the width global and zw / xw variables within the loop.

I also changed the strut function a tiny bit. Instead of normalizing between -4 to +4 X pi, I just use the Y values provided. In this example I'm providing the minimum and maximum Y values as multiples of pi directly, so I removed the normalization to open up the possibility to create a wave in whichever length and number of peaks you want.

Here's the code:

import bpy, bmesh, math
from mathutils import Vector
import numpy as np

numPoints  = 100
yMin       = -3 * np.pi 
yMax       = 1 * np.pi
width      = 0.5

def strut( x, node_dist = 5, amp = 1 ):
    """ Takes 1D array x, creates shape y values """
    return amp / 2 * np.cos(x) + amp / 2  # adjusting position and amplitude

bm    = bmesh.new() # Generate bmesh object
loops = []          # Strut major longitudinal loops array

# Calculate vertex coordinates
# Essentially generate 4 longitudinal loops that represent the top, bottom. left and right edge loops of the strut
y = np.linspace( yMin, yMax, numPoints )
for zw, xw in zip( [1, 0, -1, 0], [0, -1, 0, 1] ):
    z = strut( y, amp = 2 ) + zw * width
    x = strut( y, amp = 0 ) + xw * width

    loop = [ 
        bm.verts.new( Vector(( xi, yi, zi )) ) 
        for xi, yi, zi in zip( x, y, z ) 
    ]

    loops.append( loop )

# Add faces
for i in range( len( loops ) ):
    for j in range( len( loops[i] ) - 1 ):
        verts = []
        if i == len( loops ) - 1:
            verts.append( loops[0][j] )
            verts.append( loops[0][j+1] )
            verts.append( loops[i][j + 1] )
            verts.append( loops[i][j] )
        else:
            verts.append( loops[i][j] )
            verts.append( loops[i][j + 1] )
            verts.append( loops[i+1][j+1] )
            verts.append( loops[i+1][j] )

        bm.faces.new(verts)

# Add caps faces
for i in [0, len( loops[0] ) - 1 ]:
    bm.faces.new([ loops[j][i] for j in range(len(loops)) ])

# Generate mesh data and object, and link to scene
m = bpy.data.meshes.new('strut')
bm.to_mesh(m)

o = bpy.data.objects.new('strut', m)
bpy.context.scene.objects.link( o )