Skip to content

Instantly share code, notes, and snippets.

@5263
Last active March 20, 2023 12:07
Show Gist options
  • Save 5263/2376960 to your computer and use it in GitHub Desktop.
Save 5263/2376960 to your computer and use it in GitHub Desktop.
NURBS export for Blender and import for FreeCAD
#!/usr/bin/env python
freecadfunctions="""#!/usr/env/bin python
#python 2
import FreeCAD,Part
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 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 writeFreeCADMacro(nurbslist,filename):
outfile=open(filename,'w')
outfile.write(freecadfunctions)
for name,d1 in nurbslist:
outfile.write('importblenderspline(%s,name="%s")\n' % (repr(d1),name))
outfile.close()
if __name__ == '__main__':
writeFreeCADMacro(selection2dictionary(),'importnurbstofreecad.py')
@gara01
Copy link

gara01 commented Oct 15, 2016

Hello,
this Code works always well, but today gives me an error in Blender (you can see it in the image). Do you have an idea for resolve it
immagine

@Worufu3D
Copy link

@gara01, I get the same error. Start Blender with administrator rights, then instead of filename write a path inside quotation marks as "C:\myExportedNurbs.py".
After that open this file as Macro inside Freecad et voilat ;)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment