diff --git a/src/Mod/OpenSCAD/OpenSCADFeatures.py b/src/Mod/OpenSCAD/OpenSCADFeatures.py index 977c30225..998277f6e 100644 --- a/src/Mod/OpenSCAD/OpenSCADFeatures.py +++ b/src/Mod/OpenSCAD/OpenSCADFeatures.py @@ -448,6 +448,30 @@ class OffsetShape: if fp.Base and fp.Offset: fp.Shape=fp.Base.Shape.makeOffsetShape(fp.Offset,1e-6) +class CGALFeature: + def __init__(self,obj,opname=None,children=None,arguments=None): + obj.addProperty("App::PropertyLinkList",'Children','OpenSCAD',"Base Objects") + obj.addProperty("App::PropertyString",'Arguments','OpenSCAD',"Arguments") + obj.addProperty("App::PropertyString",'Operation','OpenSCAD',"Operation") + obj.Proxy = self + if opname: + obj.Operation = opname + if children: + obj.Children = children + if arguments: + obj.Arguments = arguments + + def execute(self,fp): + #arguments are ignored + maxmeshpoints = None #TBD: add as property + import Part,OpenSCADUtils + shape = OpenSCADUtils.process_ObjectsViaOpenSCADShape(fp.Document,fp.Children,\ + fp.Operation, maxmeshpoints=maxmeshpoints) + if shape: + fp.Shape = shape + else: + raise ValueError + def makeSurfaceVolume(filename): import FreeCAD,Part f1=open(filename) diff --git a/src/Mod/OpenSCAD/OpenSCADUtils.py b/src/Mod/OpenSCAD/OpenSCADUtils.py index 646cfb69a..3e42e7374 100644 --- a/src/Mod/OpenSCAD/OpenSCADUtils.py +++ b/src/Mod/OpenSCAD/OpenSCADUtils.py @@ -110,7 +110,7 @@ def callopenscad(inputfilename,outputfilename=None,outputext='csg',keepname=Fals raise OpenSCADError('%s\n' % stdoutd.strip()) #raise Exception,'stdout %s\n stderr%s' %(stdoutd,stderrd) if stdoutd.strip(): - FreeCAD.Console.PrintWarning(stdoutd+u'\n') + FreeCAD.Console.PrintMessage(stdoutd+u'\n') return stdoutd osfilename = FreeCAD.ParamGet(\ @@ -280,46 +280,43 @@ def meshoponobjs(opname,inobjs): else: return (None,[]) -def process2D_ObjectsViaOpenSCAD(ObjList,Operation,doc=None): +def process2D_ObjectsViaOpenSCADShape(ObjList,Operation,doc): 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" + # TBD: assure the given doc is active 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 face + +def process2D_ObjectsViaOpenSCAD(ObjList,Operation,doc=None): + import FreeCAD + doc = doc or FreeCAD.activeDocument() + face=process2D_ObjectsViaOpenSCADShape(ObjList,Operation,doc) + obj=doc.addObject('Part::Feature',Operation) + obj.Shape=face + # Hide Children + if FreeCAD.GuiUp: + for index in ObjList : + index.ViewObject.hide() return(obj) -def process3D_ObjectsViaOpenSCAD(doc,ObjList,Operation): +def process3D_ObjectsViaOpenSCADShape(ObjList,Operation,maxmeshpoints=None): import FreeCAD,Mesh,Part params = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/OpenSCAD") if False: # disabled due to issue 1292 @@ -332,25 +329,42 @@ def process3D_ObjectsViaOpenSCAD(doc,ObjList,Operation): 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): + (maxmeshpoints or 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() + return solid + +def process3D_ObjectsViaOpenSCAD(doc,ObjList,Operation): + solid = process3D_ObjectsViaOpenSCADShape(ObjList,Operation) + if solid is not None: + obj=doc.addObject('Part::Feature',Operation) #non parametric objec obj.Shape=solid#.removeSplitter() if FreeCAD.GuiUp: for index in ObjList : index.ViewObject.hide() return(obj) +def process_ObjectsViaOpenSCADShape(doc,children,name,maxmeshpoints=None): + if all((not obj.Shape.isNull() and obj.Shape.Volume == 0) \ + for obj in children): + return process2D_ObjectsViaOpenSCADShape(children,name,doc) + elif all((not obj.Shape.isNull() and obj.Shape.Volume > 0) \ + for obj in children): + return process3D_ObjectsViaOpenSCADShape(children,name,maxmeshpoints) + else: + import FreeCAD + FreeCAD.Console.PrintError( unicode(translate('OpenSCAD',\ + "Error all shapes must be either 2D or both must be 3D"))+u'\n') + def process_ObjectsViaOpenSCAD(doc,children,name): if all((not obj.Shape.isNull() and obj.Shape.Volume == 0) \ for obj in children): - return process2D_ObjectsViaOpenSCAD(children,name) + return process2D_ObjectsViaOpenSCAD(children,name,doc) elif all((not obj.Shape.isNull() and obj.Shape.Volume > 0) \ for obj in children): return process3D_ObjectsViaOpenSCAD(doc,children,name) diff --git a/src/Mod/OpenSCAD/importCSG.py b/src/Mod/OpenSCAD/importCSG.py index 358dec30c..8964d74a1 100644 --- a/src/Mod/OpenSCAD/importCSG.py +++ b/src/Mod/OpenSCAD/importCSG.py @@ -46,12 +46,10 @@ import ply.lex as lex import ply.yacc as yacc import Part -from OpenSCADFeatures import RefineShape -from OpenSCADFeatures import Frustum +from OpenSCADFeatures import * #from OpenSCAD2Dgeom import * from OpenSCADUtils import * isspecialorthogonaldeterminant = isspecialorthogonalpython -from OpenSCADFeatures import Twist if open.__module__ == '__builtin__': pythonopen = open # to distinguish python built-in open function from the one declared here @@ -357,26 +355,28 @@ def placeholder(name,children,arguments): #don't hide the children return newobj -def CGALorPlaceholder(name,children,arguments=[]): - '''Tries to perform a CGAL opertion by calling scad - if it fails it creates a placeholder object to continue parsing - ''' - if any(obj.Shape.isNull() for obj in children): - doc.recompute() #we need valid shapes - newobj = process_ObjectsViaOpenSCAD(doc,children,name) - if newobj is not None : - return newobj - else: - return placeholder(name,children,arguments) +def CGALFeatureObj(name,children,arguments=[]): + myobj=doc.addObject("Part::FeaturePython",name) + CGALFeature(myobj,name,children,str(arguments)) + if gui: + for subobj in children: + subobj.ViewObject.hide() + if FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/OpenSCAD").\ + GetBool('useViewProviderTree'): + from OpenSCADFeatures import ViewProviderTree + ViewProviderTree(myobj.ViewObject) + else: + myobj.ViewObject.Proxy = 0 + return myobj def p_hull_action(p): 'hull_action : hull LPAREN RPAREN OBRACE block_list EBRACE' - p[0] = [ CGALorPlaceholder(p[1],p[5]) ] + p[0] = [ CGALFeatureObj(p[1],p[5]) ] def p_minkowski_action(p): ''' minkowski_action : minkowski LPAREN keywordargument_list RPAREN OBRACE block_list EBRACE''' - p[0] = [ CGALorPlaceholder(p[1],p[6],p[3]) ] + p[0] = [ CGALFeatureObj(p[1],p[6],p[3]) ] def p_not_supported(p): '''