Hull and Minkowski operations using OpenSCAD
This commit is contained in:
committed by
Sebastian Hoogen
parent
7336a31e44
commit
bcb7d02c05
@@ -69,7 +69,7 @@ def workaroundforissue128needed():
|
||||
#return fdate < 2012.4759
|
||||
|
||||
def getopenscadversion(osfilename=None):
|
||||
import os,subprocess,tempfile,time
|
||||
import os,subprocess,time
|
||||
if not osfilename:
|
||||
import FreeCAD
|
||||
osfilename = FreeCAD.ParamGet(\
|
||||
@@ -81,6 +81,16 @@ def getopenscadversion(osfilename=None):
|
||||
p.wait()
|
||||
return p.stdout.read().strip()
|
||||
|
||||
def newtempfilename():
|
||||
import os,time
|
||||
formatstr='fc-%05d-%06d-%06d'
|
||||
count = 0
|
||||
while True:
|
||||
count+=1
|
||||
yield formatstr % (os.getpid(),int(time.time()*100) % 1000000,count)
|
||||
|
||||
tempfilenamegen=newtempfilename()
|
||||
|
||||
def callopenscad(inputfilename,outputfilename=None,outputext='csg',keepname=False):
|
||||
'''call the open scad binary
|
||||
returns the filename of the result (or None),
|
||||
@@ -107,8 +117,8 @@ def callopenscad(inputfilename,outputfilename=None,outputext='csg',keepname=Fals
|
||||
outputfilename=os.path.join(dir1,'%s.%s' % (os.path.split(\
|
||||
inputfilename)[1].rsplit('.',1)[0],outputext))
|
||||
else:
|
||||
outputfilename=os.path.join(dir1,'output-%d.%s' % \
|
||||
(int(time.time()*100) % 1000000,outputext))
|
||||
outputfilename=os.path.join(dir1,'%s.%s' % \
|
||||
(tempfilenamegen.next(),outputext))
|
||||
check_output2([osfilename,'-o',outputfilename, inputfilename],\
|
||||
stderr=subprocess.STDOUT)
|
||||
return outputfilename
|
||||
@@ -119,8 +129,7 @@ def callopenscadstring(scadstr,outputext='csg'):
|
||||
please delete the file afterwards'''
|
||||
import os,tempfile,time
|
||||
dir1=tempfile.gettempdir()
|
||||
inputfilename=os.path.join(dir1,'input-%d.scad' % \
|
||||
(int(time.time()*10) % 1000000))
|
||||
inputfilename=os.path.join(dir1,'%s.scad' % tempfilenamegen.next())
|
||||
inputfile = open(inputfilename,'w')
|
||||
inputfile.write(scadstr)
|
||||
inputfile.close()
|
||||
@@ -183,3 +192,160 @@ def isspecialorthogonalpython(submat,precision=4):
|
||||
def isspecialorthogonal(mat,precision=4):
|
||||
return abs(mat.submatrix(3).isOrthogonal(10**(-precision))-1.0) < 10**(-precision) and \
|
||||
abs(mat.submatrix(3).determinant()-1.0) < 10**(-precision)
|
||||
|
||||
def callopenscadmeshstring(scadstr):
|
||||
"""Call OpenSCAD and return the result as a Mesh"""
|
||||
import Mesh,os
|
||||
tmpfilename=callopenscadstring(scadstr,'stl')
|
||||
newmesh=Mesh.Mesh()
|
||||
newmesh.read(tmpfilename)
|
||||
try:
|
||||
os.unlink(tmpfilename)
|
||||
except OSError:
|
||||
pass
|
||||
return newmesh
|
||||
|
||||
def meshopinline(opname,iterable1):
|
||||
"""uses OpenSCAD to combine meshes
|
||||
takes the name of the CGAL operation and an iterable (tuple,list) of
|
||||
FreeCAD Mesh objects
|
||||
includes all the mesh data in the SCAD file
|
||||
"""
|
||||
from exportCSG import mesh2polyhedron
|
||||
return callopenscadmeshstring('%s(){%s}' % (opname,' '.join(\
|
||||
(mesh2polyhedron(meshobj) for meshobj in iterable1))))
|
||||
|
||||
def meshoptempfile(opname,iterable1):
|
||||
"""uses OpenSCAD to combine meshes
|
||||
takes the name of the CGAL operation and an iterable (tuple,list) of
|
||||
FreeCAD Mesh objects
|
||||
uses stl files to supply the mesh data
|
||||
"""
|
||||
import os,tempfile
|
||||
dir1=tempfile.gettempdir()
|
||||
filenames = []
|
||||
for mesh in iterable1:
|
||||
outputfilename=os.path.join(dir1,'%s.stl' % tempfilenamegen.next())
|
||||
mesh.write(outputfilename)
|
||||
filenames.append(outputfilename)
|
||||
#absolute path causes error. We rely that the scad file will be in the dame tmpdir
|
||||
meshimports = ' '.join("import(file = \"%s\");" % \
|
||||
#filename \
|
||||
os.path.split(filename)[1] for filename in filenames)
|
||||
result = callopenscadmeshstring('%s(){%s}' % (opname,meshimports))
|
||||
for filename in filenames:
|
||||
try:
|
||||
os.unlink(filename)
|
||||
except OSError:
|
||||
pass
|
||||
return result
|
||||
|
||||
def meshoponobjs(opname,inobjs):
|
||||
"""
|
||||
takes a string (operation name) and a list of Feature Objects
|
||||
returns a mesh and a list of objects that were used
|
||||
Part Objects will be meshed
|
||||
"""
|
||||
objs=[]
|
||||
meshes=[]
|
||||
for obj in inobjs:
|
||||
if obj.isDerivedFrom('Mesh::Feature'):
|
||||
objs.append(obj)
|
||||
meshes.append(obj.Mesh)
|
||||
elif obj.isDerivedFrom('Part::Feature'):
|
||||
#mesh the shape
|
||||
import FreeCAD
|
||||
params = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/OpenSCAD")
|
||||
objs.append(obj)
|
||||
if False: # disabled due to issue 1292
|
||||
import MeshPart
|
||||
meshes.append(MeshPart.meshFromShape(obj.Shape,params.GetFloat(\
|
||||
'meshmaxlength',1.0), params.GetFloat('meshmaxarea',0.0),\
|
||||
params.GetFloat('meshlocallen',0.0),\
|
||||
params.GetFloat('meshdeflection',0.0)))
|
||||
else:
|
||||
import Mesh
|
||||
meshes.append(Mesh.Mesh(obj.Shape.tessellate(params.GetFloat(\
|
||||
'meshmaxlength',1.0))))
|
||||
else:
|
||||
pass #neither a mesh nor a part
|
||||
if len(objs) > 0:
|
||||
return (meshoptempfile(opname,meshes),objs)
|
||||
else:
|
||||
return (None,[])
|
||||
|
||||
def process2D_ObjectsViaOpenSCAD(ObjList,Operation,doc=None):
|
||||
import FreeCAD,importDXF
|
||||
import os,tempfile
|
||||
#print "process2D"
|
||||
doc = doc or FreeCAD.activeDocument()
|
||||
dir1=tempfile.gettempdir()
|
||||
filenames = []
|
||||
#print "Export DXF"
|
||||
for item in ObjList :
|
||||
outputfilename=os.path.join(dir1,'%s.dxf' % tempfilenamegen.next())
|
||||
#print "Call Export : "+outputfilename
|
||||
importDXF.export([item],outputfilename,True,True)
|
||||
#print "File Exported"
|
||||
filenames.append(outputfilename)
|
||||
dxfimports = ' '.join("import(file = \"%s\");" % \
|
||||
#filename \
|
||||
os.path.split(filename)[1] for filename in filenames)
|
||||
#print "Call OpenSCAD : "+dxfimports
|
||||
tmpfilename = callopenscadstring('%s(){%s}' % (Operation,dxfimports),'dxf')
|
||||
#from importCSG import processDXF #import the result
|
||||
#obj = processDXF(tmpfilename,None)
|
||||
from OpenSCAD2Dgeom import importDXFface
|
||||
#print "Import DXF"
|
||||
face = importDXFface(tmpfilename,None,None)
|
||||
#print "Add Hull"
|
||||
obj=doc.addObject('Part::Feature',Operation)
|
||||
obj.Shape=face
|
||||
# Hide Children
|
||||
if FreeCAD.GuiUp:
|
||||
for index in ObjList :
|
||||
index.ViewObject.hide()
|
||||
#clean up
|
||||
filenames.append(tmpfilename) #delete the ouptut file as well
|
||||
try:
|
||||
os.unlink(tmpfilename)
|
||||
except OSError:
|
||||
pass
|
||||
return(obj)
|
||||
|
||||
def process3D_ObjectsViaOpenSCAD(doc,ObjList,Operation):
|
||||
import FreeCAD,Mesh,Part
|
||||
params = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/OpenSCAD")
|
||||
if False: # disabled due to issue 1292
|
||||
import MeshPart
|
||||
meshes = [MeshPart.meshFromShape(obj.Shape,params.GetFloat(\
|
||||
'meshmaxlength',1.0), params.GetFloat('meshmaxarea',0.0),\
|
||||
params.GetFloat('meshlocallen',0.0),\
|
||||
params.GetFloat('meshdeflection',0.0)) for obj in ObjList]
|
||||
else:
|
||||
meshes = [Mesh.Mesh(obj.Shape.tessellate(params.GetFloat(\
|
||||
'meshmaxlength',1.0))) for obj in ObjList]
|
||||
if max(mesh.CountPoints for mesh in meshes) < \
|
||||
params.GetInt('tempmeshmaxpoints',5000):
|
||||
stlmesh = meshoptempfile(Operation,meshes)
|
||||
sh=Part.Shape()
|
||||
sh.makeShapeFromMesh(stlmesh.Topology,0.1)
|
||||
solid = Part.Solid(sh)
|
||||
obj=doc.addObject('Part::Feature',Operation) #non parametric objec
|
||||
solid=solid.removeSplitter()
|
||||
if solid.Volume < 0:
|
||||
solid.complement()
|
||||
obj.Shape=solid#.removeSplitter()
|
||||
if FreeCAD.GuiUp:
|
||||
for index in ObjList :
|
||||
index.ViewObject.hide()
|
||||
return(obj)
|
||||
|
||||
def process_ObjectsViaOpenSCAD(doc,children,name):
|
||||
if all(obj.Shape.Volume == 0 for obj in children):
|
||||
return process2D_ObjectsViaOpenSCAD(children,name)
|
||||
elif all(obj.Shape.Volume > 0 for obj in children):
|
||||
return process3D_ObjectsViaOpenSCAD(doc,children,name)
|
||||
else:
|
||||
FreeCAD.Console.PrintError( unicode(translate('OpenSCAD',\
|
||||
"Error Both shapes must be either 2D or both must be 3D"))+u'\n')
|
||||
|
||||
Reference in New Issue
Block a user