Skip to content

Instantly share code, notes, and snippets.

@5263
Created March 23, 2012 15:51
Show Gist options
  • Save 5263/2172054 to your computer and use it in GitHub Desktop.
Save 5263/2172054 to your computer and use it in GitHub Desktop.
Mirror of Exporter of OpenSCAD CSG files for FreeCAD by Keith Sloan
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>Untitled Document</title>
</head>
<frameset rows="*" cols="147,*" framespacing="0" frameborder="no" border="0">
<frame src="../menu.html" name="leftFrame" scrolling="No" noresize="noresize" id="leftFrame" />
<frame src="Export_main.html" name="mainFrame" id="mainFrame" />
</frameset>
<noframes><body>
</body>
</noframes></html>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>RepRap</title>
<style type="text/css">
<!--
body {
background-image: url(../images/Background.gif);
}
.style1 {color: #660033}
-->
</style></head>
<body>
<div align="center">
<p align="center"><img src="../images/Export_NBanner.gif" width="383" height="70" /></p>
<h3 align="center" class="style1">&nbsp;</h3>
<h3 align="center" class="style1">Exporter of OpenSCAD CSG files for FreeCAD</h3>
<p align="center" class="style1"><strong>Version 0.1c<br />
<br />
</strong>This is an early version and only supports a limited amount of FreeCAD function.<br />
More function will be added over time so please check back for latest version<br />
. <br />
To install the following python scipts must be placed in <br />
Windows :
C:\Program Files\FreeCAD0.12\Mod\Draft<br />
Linux : /usr/lib/freecad/Mod/Draft </p>
<p align="center" class="style1"><a href="exportCSG.py">exportCSG.py</a></p>
<p align="center" class="style1"> :
The InitGui script in the above directory must be altered to add the following line</p>
<p align="center" class="style1">App.addExportType(&quot;CSG Format (*.csg)&quot;,&quot;exportCSG&quot;) </p>
<p align="center" class="style1">As CSG files are a subset of OpenSCAD scad file you may also want to add<br />
the following as this well. This then make it easier to load the csg file directly into OpenSCAD <br />
<br />
App.addExportType(&quot;SCADFormat (*.scad)&quot;,&quot;exportCSG&quot;)</p>
<p align="center" class="style1"><a href="Versions.txt">Version History</a> </p>
<p align="center" class="style1">&nbsp; </p>
<h3 align="center"><a href="Alibre-Mendel.zip" onClick="javascript: pageTracker._trackPageview('/downloads/Alibre-Mendal');"></a></h3>
<script type="text/javascript">
</script>
</a>
<script type="text/javascript">var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
</script>
<script type="text/javascript">
try {
var pageTracker = _gat._getTracker("UA-5880034-6");
pageTracker._trackPageview();
} catch(err) {}</script>
</body>
</html>
#***************************************************************************
#* *
#* 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 General Public License (GPL) *
#* 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 Draft Workbench - CSG exporter Version 0.01c"
__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 ) *
fafs = '$fa = 12, $fs = 2'
convexity = 'convexity = 10'
#***************************************************************************
pythonopen = open
params = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Draft")
def check_center(ob):
d = FreeCAD.Vector(0,0,0)
# Only say center = false if no rotation and no displacement
if ( ob.Placement.Rotation.Angle == 0 and ob.Placement.Base == d):
return 'false'
return 'true'
def center(b):
if b == 0 :
return 'false'
return 'true'
def check_multmatrix(csg,ob,x,y,z):
v = FreeCAD.Vector(0,0,1)
b = FreeCAD.Vector(x,y,z)
if ( ob.Placement.Base == FreeCAD.Vector(0,0,0)):
return 0 # center = false no mm
elif ( ob.Placement.Rotation.Axis != v or ob.Placement.Rotation.Angle != 0 or ob.Placement.Base != b) :
print "Output Multmatrix"
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 = true and mm
return 2 # center = true and no 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))
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.Type == "Part::Sphere" :
print "Sphere Radius : "+str(ob.Radius)
check_multmatrix(csg,ob,0,0,0)
global fafs
csg.write("sphere($fn = 0, "+fafs+", r = "+str(ob.Radius)+");\n")
elif ob.Type == "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)+", "+str(ob.Width)+", "+str(ob.Height)+"], center = "+center(mm)+");\n")
if mm == 1 : csg.write("}\n")
elif ob.Type == "Part::Cylinder" :
print "cylinder : Height "+str(ob.Height)+ " Radius "+str(ob.Radius)
mm = check_multmatrix(csg,ob,0,0,-ob.Height/2)
global fafs
csg.write("cylinder($fn = 0, "+fafs+", h = "+str(ob.Height)+ ", r1 = "+str(ob.Radius)+\
", r2 = " + str(ob.Radius) + ", center = "+center(mm)+");\n")
if mm == 1 : csg.write("}\n")
elif ob.Type == "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)
global fafs
csg.write("cylinder($fn = 0, "+fafs+", h = "+str(ob.Height)+ ", r1 = "+str(ob.Radius1)+\
", r2 = "+str(ob.Radius2)+", center = "+center(mm)+");\n")
if mm == 1 : csg.write("}\n")
elif ob.Type == "Part::Torus" :
print "Torus"
print ob.Radius1
print ob.Radius2
if ob.Angle3 == 360.00 :
mm = check_multmatrix(csg,ob,0,0,0)
global fafs
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.Type == "Part::Extrusion" :
print "Extrusion"
print ob.Base
print ob.Base.Name
#if ( ob.Base == "Part::FeaturePython" and ob.Base.Name == "Polygon") :
if ob.Base.Name == "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)
global fafs
csg.write("cylinder($fn = "+f+", "+fafs+", h = "+h+", r1 = "+r+\
", r2 = "+r+", center = "+center(mm)+");\n")
if mm == 1: csg.write("}\n")
elif ob.Base.Name == "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)
global fafs
csg.write("cylinder($fn = 0, "+fafs+", h = "+h+", r1 = "+r+\
", r2 = "+r+", center = "+center(mm)+");\n")
if mm == 1: csg.write("}\n")
elif ob.Base.Name == "Wire" :
print "Wire extrusion"
print ob.Base
mm = check_multmatrix(csg,ob,0,0,0)
global fafs
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.Name == "square" :
mm = check_multmatrix(csg,ob,0,0,0)
global fafs
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)+", "+str(ob.Base.Width)+"],center = "+center(mm)+";\n}\n")
if mm == 1: csg.write("}\n")
elif ob.Type == "Part::Cut" :
print "Cut"
csg.write("difference() {\n")
process_object(csg,ob.Base)
process_object(csg,ob.Tool)
csg.write("}\n")
elif ob.Type == "Part::Fuse" :
print "union"
csg.write("union() {\n")
process_object(csg,ob.Base)
process_object(csg,ob.Tool)
csg.write("}\n")
elif ob.Type == "Part::Common" :
print "intersection"
csg.write("intersection() {\n")
process_object(csg,ob.Base)
process_object(csg,ob.Tool)
csg.write("}\n")
elif ob.Type == "Part::MultiFuse" :
print "Multi Fuse / union"
csg.write("union() {\n")
for subobj in ob.Shapes:
process_object(csg,subobj)
csg.write("}\n")
elif ob.Type == "Part::Common" :
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.1c\n"
print "Open Output File"
csg = pythonopen(filename,'w')
print "Write Inital Output"
# Not sure if comments as per scad are allowed in csg file
csg.write("// CSG file generated from FreeCAD Export 0.1c\n")
#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.Type
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)
Version History
===============
0.01a - First Version
0.01b - Added support for polyhedron ( Thanks shoogen )
Some support for Torus
Some support for extruded regular polygon
0.01c - Support for extruded polygon, square, circle
bug fix for polyhydron floating point - Thanks shoogen
Thanks to shoogen and Peter Li for their advice, code, support and expertise.
Keith Sloan
keith@sloan-home.co.uk
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment