Import Bezier curves from Blender

Need help, or want to share a macro? Post here!
Forum rules
Be nice to others! Respect the FreeCAD code of conduct!
Post Reply
User avatar
Chris_G
Veteran
Posts: 2602
Joined: Tue Dec 31, 2013 4:10 pm
Location: France
Contact:

Import Bezier curves from Blender

Post by Chris_G »

Hi,
I needed to import Bezier curves from Blender yesterday, so I modified the script mentioned in this post to add this feature.
It may not be really clean code, but it works for me.
Here it is :

Code: Select all

#!/usr/bin/env python

freecadfunctions="""#!/usr/env/bin python
#python 2
import FreeCAD,Part
from FreeCAD import Vector
def pointstopoles1D(points):
    return zip(*[(FreeCAD.Vector(point[0:3]),point[3]) for point in points])

def pointstopoles(points,cu):
    poles=[]
    weights=[]
    for dontcare in xrange(cu):
        poles.append([])
        weights.append([])
    for i,point in enumerate(points):
        u = i % cu
        v = i // cu
        poles[u].append(FreeCAD.Vector(point[0:3]))
        weights[u].append(point[3])
    return poles,weights

def mults(npoles,degree,isperiodic=False,bezier=False,endpoint=False):
    if isperiodic: #and uniform
        multv = (1,) * (npoles +1)
    elif endpoint: #quasi-uniform
        multv=(degree+1,)+(1,)*(npoles - degree-1)+(degree+1,)
    elif bezier:
       #what OCC describes as picewise bezier
       k = 1 + (npoles -1) / degree
       multv=(degree+1,)+(degree,)*(k-2)+(degree+1,)
    else: #uniform
        multv=(1,)*(npoles+degree+1)
    #print '%s deg=%d pol=%d sum=%d' % (multv ,degree, npoles, (sum(multv)-degree-1))
    return multv

def importblenderspline(d1,doc=None,name=None,showpoles=False):
    import FreeCAD
    if name is None:
        name = 'Surface' if d1['order_v']>0 else 'Curve'
    doc = doc or FreeCAD.activeDocument() or FreeCAD.newDocument()
    obj = doc.addObject('Part::Spline',name)
    obj.Shape = blendersplinecurve(d1).toShape()
    if showpoles:
        obj.ViewObject.ControlPoints = True

def importblendercurve(d1,doc=None,name=None,showpoles=False):
    import FreeCAD
    import Part
    from FreeCAD import Vector
    if name is None:
        name = 'Curve'
    doc = doc or FreeCAD.activeDocument() or FreeCAD.newDocument()
    obj = doc.addObject('Part::Feature',name)
    c = Part.BezierCurve()
    c.increase(3)
    for i in range(len(d1)):
        c.setPole(i+1,FreeCAD.Vector(d1[i]))
    obj.Shape = c.toShape()
    if showpoles:
        obj.ViewObject.ControlPoints = True

def blendersplinecurve(d1):
    points=d1['points']
    cu=d1['point_count_u']
    cv=d1['point_count_v']
    degu=d1['order_u']-1
    degv=d1['order_v']-1
    uperiodic=d1['use_cyclic_u']
    vperiodic=d1['use_cyclic_v']
    if degv != -1:
        poles,weights= pointstopoles(points,cu)
        bss=Part.BSplineSurface()
        umults=mults(cu,degu,uperiodic,d1['use_bezier_u'],d1['use_endpoint_u'])
        vmults=mults(cv,degv,vperiodic,d1['use_bezier_v'],d1['use_endpoint_v'])
        if d1['use_bezier_u'] and (sum(umults)-degu-1) != cu or d1['use_bezier_v'] and (sum(vmults)-degv-1) != cv:
             raise ValueError#would fail later because of mults and points mismatch
        bss.buildFromPolesMultsKnots(poles,umults, vmults,uperiodic=uperiodic, vperiodic=vperiodic, udegree=degu, vdegree=degv, weights=weights)
        return bss
    else:
        poles,weights = pointstopoles1D(points)
        bsc=Part.BSplineCurve()
        if d1['use_bezier_u'] and degu==3: #blender is doing something very strange
            poles=poles[1:]
            weights=weights[1:]
            cu-=1
        umults=mults(cu,degu,uperiodic,d1['use_bezier_u'],d1['use_endpoint_u'])
        if d1['use_bezier_u'] and (sum(umults)-degu-1) != cu: #to many poles, 
            cu=sum(umults)-degu-1
            poles = poles[:cu]
            weights = weights[:cu]
        try:
            bsc.buildFromPolesMultsKnots(poles,umults,periodic=uperiodic,degree=degu,weights=weights)
        except:
            print umults,' ',len(poles)
            raise
        return bsc

"""
def spline2dict(spline):
    d1={}
    for attr in ('order_u', 'order_v', 'point_count_u', 'point_count_v',\
        'use_bezier_u', 'use_bezier_v', 'use_cyclic_u', 'use_cyclic_v', \
        'use_endpoint_u', 'use_endpoint_v'):
        d1[attr]=spline.__getattribute__(attr)
    d1['points']=tuple((tuple(p.co) for p in spline.points))
    return d1

def selection2dictionary():
    import bpy
    nurbslist=[]
    for ob in bpy.context.selected_objects:
        if ob.type == 'SURFACE':
            name = ob.name
            data = ob.data
            if len(data.splines) == 1:
                nurbslist.append((name,spline2dict(data.splines[0])))
            else:
                raise ValueError("Not one spline")
    return nurbslist

def selection2curvearray():
    import bpy
    curvelist=[]
    for ob in bpy.context.selected_objects:
        if ob.type == 'CURVE':
            name = ob.name
            data = ob.data
            for s in data.splines:
                for p in range(0, len(s.bezier_points)-1):
                    n = name+str(p)
                    curvelist.append((n,[s.bezier_points[p].co,s.bezier_points[p].handle_right,s.bezier_points[p+1].handle_left,s.bezier_points[p+1].co]))
    return curvelist

def writeFreeCADMacro(nurbslist,curvelist,filename):
    outfile=open(filename,'w')
    outfile.write(freecadfunctions)
    for name,d1 in nurbslist:
        outfile.write('importblenderspline(%s,name="%s")\n' % (repr(d1),name))
    for name,d1 in curvelist:
        outfile.write('importblendercurve(%s,name="%s")\n' % (repr(d1),name))
    outfile.close()

if __name__ == '__main__':
    writeFreeCADMacro(selection2dictionary(),selection2curvearray(),'importnurbstofreecad.py')

Post Reply