271 lines
12 KiB
Python
271 lines
12 KiB
Python
|
|
#***************************************************************************
|
|
#* *
|
|
#* Copyright (c) 2012 Keith Sloan <keith@sloan-home.co.uk> *
|
|
#* *
|
|
#* This program is free software; you can redistribute it and/or modify *
|
|
#* it under the terms of the GNU Lesser General Public License (LGPL) *
|
|
#* as published by the Free Software Foundation; either version 2 of *
|
|
#* the License, or (at your option) any later version. *
|
|
#* for detail see the LICENCE text file. *
|
|
#* *
|
|
#* This program is distributed in the hope that it will be useful, *
|
|
#* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
#* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
|
#* GNU Library General Public License for more details. *
|
|
#* *
|
|
#* You should have received a copy of the GNU Library General Public *
|
|
#* License along with this program; if not, write to the Free Software *
|
|
#* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
|
#* USA *
|
|
#* *
|
|
#* Acknowledgements : *
|
|
#* *
|
|
#* Thanks to shoogen on the FreeCAD forum for programming advice *
|
|
#* and some code. *
|
|
#* *
|
|
#***************************************************************************
|
|
__title__="FreeCAD OpenSCAD Workbench - CSG exporter Version"
|
|
__author__ = "Keith Sloan <keith@sloan-home.co.uk>"
|
|
__url__ = ["http://www.sloan-home.co.uk/Export/Export.html"]
|
|
|
|
import FreeCAD, os, Part, math
|
|
from FreeCAD import Vector
|
|
|
|
try: import FreeCADGui
|
|
except ValueError: gui = False
|
|
else: gui = True
|
|
|
|
#***************************************************************************
|
|
# Tailor following to your requirements ( Should all be strings ) *
|
|
global fafs
|
|
#fafs = '$fa = 12, $fs = 2'
|
|
#convexity = 'convexity = 10'
|
|
params = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/OpenSCAD")
|
|
fa = params.GetFloat('exportFa',12.0)
|
|
fs = params.GetFloat('exportFs',2.0)
|
|
conv = params.GetInt('exportConvexity',10)
|
|
fafs = '$fa = %f, $fs = %f' % (fa,fs)
|
|
convexity = 'convexity = %d' % conv
|
|
#***************************************************************************
|
|
# Radius values not fixed for value apart from cylinder & Cone
|
|
# no doubt there will be a problem when they do implement Value
|
|
if open.__module__ == '__builtin__':
|
|
pythonopen = open
|
|
|
|
def center(b):
|
|
if b == 2:
|
|
return 'true'
|
|
else:
|
|
return 'false'
|
|
|
|
def check_multmatrix(csg,ob,x,y,z):
|
|
b = FreeCAD.Vector(x,y,z)
|
|
if ob.Placement.isNull():
|
|
return 0 # center = false no mm
|
|
elif ob.Placement.Rotation.isNull() and \
|
|
(ob.Placement.Base - b).Length < 1e-6:
|
|
return 2 # center = true and no mm
|
|
else:
|
|
m = ob.Placement.toMatrix()
|
|
# adjust position for center displacments
|
|
csg.write("multmatrix([["+str(m.A11)+", "+str(m.A12)+", "+str(m.A13)+",\
|
|
"+str(m.A14)+"], ["\
|
|
+str(m.A21)+", "+str(m.A22)+", "+str(m.A23)+", "+str(m.A24)+"], ["\
|
|
+str(m.A31)+", "+str(m.A32)+", "+str(m.A33)+", "+str(m.A34)+"], [\
|
|
0, 0, 0, 1]]){\n")
|
|
return 1 # center = false and mm
|
|
|
|
def mesh2polyhedron(mesh):
|
|
pointstr=','.join(['[%f,%f,%f]' % tuple(vec) for vec in mesh.Topology[0]])
|
|
trianglestr=','.join(['[%d,%d,%d]' % tuple(tri) for tri in mesh.Topology[1]])
|
|
return 'polyhedron ( points = [%s], triangles = [%s]);' % (pointstr,trianglestr)
|
|
|
|
def vector2d(v):
|
|
return [v[0],v[1]]
|
|
|
|
def vertexs2polygon(vertex):
|
|
pointstr=','.join(['[%f, %f]' % tuple(vector2d(v.Point)) for v in vertex])
|
|
return 'polygon ( points = [%s], paths = undef, convexity = 1);}' % pointstr
|
|
|
|
def shape2polyhedron(shape):
|
|
import MeshPart
|
|
return mesh2polyhedron(MeshPart.meshFromShape(Shape=shape,\
|
|
Deflection= params.GetFloat('meshdeflection',0.0)))
|
|
|
|
def process_object(csg,ob):
|
|
|
|
print("Placement")
|
|
print("Pos : "+str(ob.Placement.Base))
|
|
print("axis : "+str(ob.Placement.Rotation.Axis))
|
|
print("angle : "+str(ob.Placement.Rotation.Angle))
|
|
|
|
if ob.TypeId == "Part::Sphere" :
|
|
print("Sphere Radius : "+str(ob.Radius))
|
|
check_multmatrix(csg,ob,0,0,0)
|
|
csg.write("sphere($fn = 0, "+fafs+", r = "+str(ob.Radius)+");\n")
|
|
|
|
elif ob.TypeId == "Part::Box" :
|
|
print("cube : ("+ str(ob.Length)+","+str(ob.Width)+","+str(ob.Height)+")")
|
|
mm = check_multmatrix(csg,ob,-ob.Length/2,-ob.Width/2,-ob.Height/2)
|
|
csg.write("cube (size = ["+str(ob.Length.Value)+", "+str(ob.Width.Value)+", "+str(ob.Height.Value)+"], center = "+center(mm)+");\n")
|
|
if mm == 1 : csg.write("}\n")
|
|
|
|
elif ob.TypeId == "Part::Cylinder" :
|
|
print("cylinder : Height "+str(ob.Height)+ " Radius "+str(ob.Radius))
|
|
mm = check_multmatrix(csg,ob,0,0,-ob.Height/2)
|
|
csg.write("cylinder($fn = 0, "+fafs+", h = "+str(ob.Height.Value)+ ", r1 = "+str(ob.Radius.Value)+\
|
|
", r2 = " + str(ob.Radius.Value) + ", center = "+center(mm)+");\n")
|
|
if mm == 1 : csg.write("}\n")
|
|
|
|
elif ob.TypeId == "Part::Cone" :
|
|
print("cone : Height "+str(ob.Height)+ " Radius1 "+str(ob.Radius1)+" Radius2 "+str(ob.Radius2))
|
|
mm = check_multmatrix(csg,ob,0,0,-ob.Height/2)
|
|
csg.write("cylinder($fn = 0, "+fafs+", h = "+str(ob.Height.Value)+ ", r1 = "+str(ob.Radius1.Value)+\
|
|
", r2 = "+str(ob.Radius2.Value)+", center = "+center(mm)+");\n")
|
|
if mm == 1 : csg.write("}\n")
|
|
|
|
elif ob.TypeId == "Part::Torus" :
|
|
print("Torus")
|
|
print(ob.Radius1)
|
|
print(ob.Radius2)
|
|
if ob.Angle3 == 360.00 :
|
|
mm = check_multmatrix(csg,ob,0,0,0)
|
|
csg.write("rotate_extrude("+convexity+", $fn = 0, "+fafs+")\n")
|
|
csg.write("multmatrix([[1, 0, 0, "+str(ob.Radius1)+"], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]])\n")
|
|
csg.write("circle($fn = 0, "+fafs+", r = "+str(ob.Radius2)+");\n")
|
|
if mm == 1 : csg.write("}\n")
|
|
else : # Cannot convert to rotate extrude so best effort is polyhedron
|
|
csg.write('%s\n' % shape2polyhedron(ob.Shape))
|
|
|
|
elif ob.TypeId == "Part::Prism":
|
|
import math
|
|
f = str(ob.Polygon)
|
|
# r = str(ob.Length/2.0/math.sin(math.pi/ob.Polygon))
|
|
r = str(ob.Circumradius) # length seems to be the outer radius
|
|
h = str(ob.Height.Value)
|
|
mm = check_multmatrix(csg,ob,0,0,-float(h)/2)
|
|
csg.write("cylinder($fn = "+f+", "+fafs+", h = "+h+", r1 = "+r+\
|
|
", r2 = "+r+", center = "+center(mm)+");\n")
|
|
if mm == 1: csg.write("}\n")
|
|
|
|
elif ob.TypeId == "Part::RegularPolygon":
|
|
mm = check_multmatrix(csg,ob,0,0,-float(h)/2)
|
|
csg.write("circle($fn = "+str(ob.NumberOfSides)+", "+fafs+", r = "+str(ob.Radius)+");\n")
|
|
if mm == 1: csg.write("}\n")
|
|
|
|
elif ob.TypeId == "Part::Extrusion" :
|
|
print("Extrusion")
|
|
print(ob.Base)
|
|
print(ob.Base.Name)
|
|
if ob.Base.isDerivedFrom('Part::Part2DObjectPython') and \
|
|
hasattr(ob.Base,'Proxy') and hasattr(ob.Base.Proxy,'TypeId'):
|
|
ptype=ob.Base.Proxy.TypeId
|
|
if ptype == "Polygon" :
|
|
f = str(ob.Base.FacesNumber)
|
|
r = str(ob.Base.Radius)
|
|
h = str(ob.Dir[2])
|
|
print("Faces : " + f)
|
|
print("Radius : " + r)
|
|
print("Height : " + h)
|
|
mm = check_multmatrix(csg,ob,0,0,-float(h)/2)
|
|
csg.write("cylinder($fn = "+f+", "+fafs+", h = "+h+", r1 = "+r+\
|
|
", r2 = "+r+", center = "+center(mm)+");\n")
|
|
if mm == 1: csg.write("}\n")
|
|
|
|
elif ptype == "Circle" :
|
|
r = str(ob.Base.Radius)
|
|
h = str(ob.Dir[2])
|
|
print("Radius : " + r)
|
|
print("Height : " + h)
|
|
mm = check_multmatrix(csg,ob,0,0,-float(h)/2)
|
|
csg.write("cylinder($fn = 0, "+fafs+", h = "+h+", r1 = "+r+\
|
|
", r2 = "+r+", center = "+center(mm)+");\n")
|
|
if mm == 1: csg.write("}\n")
|
|
|
|
elif ptype == "Wire" :
|
|
print("Wire extrusion")
|
|
print(ob.Base)
|
|
mm = check_multmatrix(csg,ob,0,0,0)
|
|
csg.write("linear_extrude(height = "+str(ob.Dir[2])+", center = "+center(mm)+", "+convexity+", twist = 0, slices = 2, $fn = 0, "+fafs+")\n{\n")
|
|
csg.write(vertexs2polygon(ob.Base.Shape.Vertexes))
|
|
if mm == 1: csg.write("}\n")
|
|
|
|
elif ob.Base.isDerivedFrom('Part::Plane'):
|
|
mm = check_multmatrix(csg,ob,0,0,0)
|
|
csg.write("linear_extrude(height = "+str(ob.Dir[2])+", center = true, "+convexity+", twist = 0, slices = 2, $fn = 0, "+fafs+")\n{\n")
|
|
csg.write("square (size = ["+str(ob.Base.Length.Value)+", "+str(ob.Base.Width.Value)+"], center = "+center(mm)+");\n}\n")
|
|
if mm == 1: csg.write("}\n")
|
|
elif ob.Base.Name.startswith('this_is_a_bad_idea'):
|
|
pass
|
|
else:
|
|
pass # There should be a fallback solution
|
|
|
|
elif ob.TypeId == "Part::Cut" :
|
|
print("Cut")
|
|
csg.write("difference() {\n")
|
|
process_object(csg,ob.Base)
|
|
process_object(csg,ob.Tool)
|
|
csg.write("}\n")
|
|
|
|
elif ob.TypeId == "Part::Fuse" :
|
|
print("union")
|
|
csg.write("union() {\n")
|
|
process_object(csg,ob.Base)
|
|
process_object(csg,ob.Tool)
|
|
csg.write("}\n")
|
|
|
|
elif ob.TypeId == "Part::Common" :
|
|
print("intersection")
|
|
csg.write("intersection() {\n")
|
|
process_object(csg,ob.Base)
|
|
process_object(csg,ob.Tool)
|
|
csg.write("}\n")
|
|
|
|
elif ob.TypeId == "Part::MultiFuse" :
|
|
print("Multi Fuse / union")
|
|
csg.write("union() {\n")
|
|
for subobj in ob.Shapes:
|
|
process_object(csg,subobj)
|
|
csg.write("}\n")
|
|
|
|
elif ob.TypeId == "Part::MultiCommon" :
|
|
print("Multi Common / intersection")
|
|
csg.write("intersection() {\n")
|
|
for subobj in ob.Shapes:
|
|
process_object(csg,subobj)
|
|
csg.write("}\n")
|
|
|
|
elif ob.isDerivedFrom('Part::Feature') :
|
|
print("Part::Feature")
|
|
mm = check_multmatrix(csg,ob,0,0,0)
|
|
csg.write('%s\n' % shape2polyhedron(ob.Shape))
|
|
if mm == 1 : csg.write("}\n")
|
|
|
|
def export(exportList,filename):
|
|
"called when FreeCAD exports a file"
|
|
|
|
# process Objects
|
|
print("\nStart Export 0.1d\n")
|
|
print("Open Output File")
|
|
csg = pythonopen(filename,'w')
|
|
print("Write Initial Output")
|
|
# Not sure if comments as per scad are allowed in csg file
|
|
csg.write("// CSG file generated from FreeCAD %s\n" % \
|
|
'.'.join(FreeCAD.Version()[0:3]))
|
|
#write initial group statements - not sure if required
|
|
csg.write("group() {\n group(){\n")
|
|
for ob in exportList:
|
|
print(ob)
|
|
print("Name : "+ob.Name)
|
|
print("Type : "+ob.TypeId)
|
|
print("Shape : ")
|
|
print(ob.Shape)
|
|
process_object(csg,ob)
|
|
|
|
# write closing group braces
|
|
csg.write("}\n}\n")
|
|
# close file
|
|
csg.close()
|
|
FreeCAD.Console.PrintMessage("successfully exported "+filename)
|