Featured post

new redirect for blender.org bpy docs.

http://www.blender.org/api/blender_python_api_current/ As of 10/11 november 2015 we can now link to the current api docs and not be worr...

Showing posts with label NURBS. Show all posts
Showing posts with label NURBS. Show all posts

April 07, 2014

Scripting NURBS surfaces

I was expecting the following code to produce something similar to the default Add NURBS Surface object. It doesn't. Any ideas?
import bpy
from mathutils import Vector

surface_data = bpy.data.curves.new('wook', 'SURFACE')
surface_data.dimensions = '3D'
spline_0 = surface_data.splines.new(type='NURBS')

# 16 coordinates
points = [
    Vector((-1.5, -1.5, 0.0, 1.0)), Vector((-1.5, -0.5, 0.0, 1.0)),
    Vector((-1.5, 0.5, 0.0, 1.0)), Vector((-1.5, 1.5, 0.0, 1.0)),
    Vector((-0.5, -1.5, 0.0, 1.0)), Vector((-0.5, -0.5, 1.0, 1.0)),
    Vector((-0.5, 0.5, 1.0, 1.0)), Vector((-0.5, 1.5, 0.0, 1.0)),
    Vector((0.5, -1.5, 0.0, 1.0)), Vector((0.5, -0.5, 1.0, 1.0)),
    Vector((0.5, 0.5, 1.0, 1.0)), Vector((0.5, 1.5, 0.0, 1.0)),
    Vector((1.5, -1.5, 0.0, 1.0)), Vector((1.5, -0.5, 0.0, 1.0)),
    Vector((1.5, 0.5, 0.0, 1.0)), Vector((1.5, 1.5, 0.0, 1.0))
]

spline_0.points.add(15)  #   already has a a default zero vector

for p, new_co in zip(spline_0.points, points):
    p.co = new_co

# 4*4 = 16 points
# spline_0.point_count_u = 4   # read only :(
# spline_0.point_count_v = 4   # read only :(
spline_0.order_v = 4
spline_0.order_u = 4
spline_0.resolution_v= 4
spline_0.resolution_u = 4

surface_object = bpy.data.objects.new('NURBS_OBJ', surface_data)

scene = bpy.context.scene    
scene.objects.link(surface_object) 
the only way I got this to work was by using bpy.ops to make_segments of separately created nurbs, which isn't too bad but may not be ideal

July 18, 2012

Blender 2.6x igs importer

At the moment it only deals with line type 126 (which is BSpline). It can be downloaded here: blender_version_igs_import.py. Warning: only deals with entity type 126.


(model credit: siggraphSpacecraft48.igs -- i have no idea who made it.


At the moment the igs importer probably doesn't do much good beyond importing BSplines. But it happens to do a remarkable job at importing .igs files from
http://www.dgp.toronto.edu/~shbae/ilovesketch.htm, which is why i wrote it.

Behind the scenes

After staring at the .igs files for a while some patterns emerged. It became clear that a relatively uncomplicated extraction pattern would probably suffice to get things started. Without reading through the official file specs i tend to write code for whatever gets flinged my way, until a meta pattern emerges and then things become more sophisticated. Right now the code is procedural, and easily lets me implement new entities as they occur.

After several hours manual labour

I manage to squeeze this one out. Blender has NURBS surfaces but the interface for NURBS specifically is very weak and probably hasn't changed much in the past 4 years. Anyway. here it is (model 83 from the iLOVESKETCH page:
some more hours.

May 17, 2011

Blender 2.5x Python Curve from a List of Coordinates.

Given a list of coordinates in the form of Vector((x,y,z)) it is possible to string them together to get a curve shape. Each Point on a curve is has 4 values (x,y,z,w). W=weight and is a value between 0.010 and 100.

It took me a while to get some intuition in this part of blender bpy. This post is my effort to clear it up for myself and hopefully for others who may struggle with it in the future.
import bpy
from mathutils import Vector

w = 1 # weight
cList = [Vector((0,0,0)),Vector((1,0,0)),Vector((2,0,0)),Vector((2,3,0)),
        Vector((0,2,1))]

curvedata = bpy.data.curves.new(name='Curve', type='CURVE')
curvedata.dimensions = '3D'

objectdata = bpy.data.objects.new("ObjCurve", curvedata)
objectdata.location = (0,0,0) #object origin
bpy.context.scene.objects.link(objectdata)

polyline = curvedata.splines.new('POLY')
polyline.points.add(len(cList)-1)
for num in range(len(cList)):
    x, y, z = cList[num]
    polyline.points[num].co = (x, y, z, w)

or a slightly modified version, for turning it into a reusable function
import bpy
from mathutils import Vector

w = 1 # weight
listOfVectors = [Vector((0,0,0)),Vector((1,0,0)),Vector((2,0,0)),Vector((2,3,0)),
        Vector((0,2,1))]

def MakePolyLine(objname, curvename, cList):
    curvedata = bpy.data.curves.new(name=curvename, type='CURVE')
    curvedata.dimensions = '3D'

    objectdata = bpy.data.objects.new(objname, curvedata)
    objectdata.location = (0,0,0) #object origin
    bpy.context.scene.objects.link(objectdata)

    polyline = curvedata.splines.new('POLY')
    polyline.points.add(len(cList)-1)
    for num in range(len(cList)):
        x, y, z = cList[num]
        polyline.points[num].co = (x, y, z, w)

MakePolyLine("NameOfMyCurveObject", "NameOfMyCurve", listOfVectors)

If the list of vectors has only one Vector, then the curve will use one predefined zero vector (Vector((0,0,0))) and draw a straight line from 0,0,0 to your single Vector. Go into edit mode to see where the points are placed.

Each object can have multiple curves associated with it, they are accessed like this
# returns the number of curves associated with this object
>>> len(bpy.context.active_object.data.splines)

# returns the curve information associated with the first spline (index = 0) 
>>> bpy.context.active_object.data.splines[0]
bpy.data.curves["NameOfMyCurve"].splines[0]

# this returns the coordinates on that curve as a list.
>>> [point.co for point in bpy.context.active_object.data.splines[0].points]
if you want a smooth curve from these points, declare at the time of creation what type from these options ('POLY', 'BEZIER', 'BSPLINE', 'CARDINAL', 'NURBS')
import bpy  
from mathutils import Vector  
  
w = 1 # weight  
listOfVectors = [Vector((0,0,0)),Vector((1,0,0)),Vector((2,0,0)),Vector((2,3,0)),  
        Vector((0,2,1))]  
  
def MakePolyLine(objname, curvename, cList):  
    curvedata = bpy.data.curves.new(name=curvename, type='CURVE')  
    curvedata.dimensions = '3D'  
  
    objectdata = bpy.data.objects.new(objname, curvedata)  
    objectdata.location = (0,0,0) #object origin  
    bpy.context.scene.objects.link(objectdata)  
  
    polyline = curvedata.splines.new('NURBS')  
    polyline.points.add(len(cList)-1)  
    for num in range(len(cList)):  
        x, y, z = cList[num]  
        polyline.points[num].co = (x, y, z, w)  
  
    polyline.order_u = len(polyline.points)-1
    polyline.use_endpoint_u = True
    
  
MakePolyLine("NameOfMyCurveObject", "NameOfMyCurve", listOfVectors)
And here a more stripped down version
import bpy  
from mathutils import Vector  

# weight  
w = 1 

# we don't have to use the Vector() notation.  
listOfVectors = [(0,0,0),(1,0,0),(2,0,0),(2,3,0),(0,2,1)]  
  
def MakePolyLine(objname, curvename, cList):  
    curvedata = bpy.data.curves.new(name=curvename, type='CURVE')  
    curvedata.dimensions = '3D'  
  
    objectdata = bpy.data.objects.new(objname, curvedata)  
    objectdata.location = (0,0,0) #object origin  
    bpy.context.scene.objects.link(objectdata)  
  
    polyline = curvedata.splines.new('NURBS')  
    polyline.points.add(len(cList)-1)  
    for num in range(len(cList)):  
        polyline.points[num].co = (cList[num])+(w,)  
  
    polyline.order_u = len(polyline.points)-1
    polyline.use_endpoint_u = True
    
  
MakePolyLine("NameOfMyCurveObject", "NameOfMyCurve", listOfVectors)