diff --git a/src/Mod/OpenSCAD/exportDRAWEXE.py b/src/Mod/OpenSCAD/exportDRAWEXE.py index bfe7d62d2..e069f4285 100644 --- a/src/Mod/OpenSCAD/exportDRAWEXE.py +++ b/src/Mod/OpenSCAD/exportDRAWEXE.py @@ -31,7 +31,7 @@ if open.__module__ == '__builtin__': def f2s(n): '''convert to numerical value to string''' #return str(float(n)) - return ('%0.18f' % n).rstrip('0') + return ('%0.18f' % n).rstrip('0').rstrip('.') def placement2draw(placement,name='object'): """converts a FreeCAD Placement to trotate and ttranslate commands""" @@ -48,14 +48,18 @@ def placement2draw(placement,name='object'): (name,f2s(x),f2s(y),f2s(z)) return drawcommand -def saveShape(csg,filename,shape,name,hasplacement = True): +def saveShape(csg,filename,shape,name,hasplacement = True,cleanshape=False): import os spath,sname = os.path.split(filename) sname=sname.replace('.','-') uname='%s-%s' %(sname,name) breppath=os.path.join(spath,'%s.brep'%uname) - csg.write("restore %s.brep\n"%uname) - csg.write("renamevar %s %s\n"%(uname,name)) + csg.write("restore %s.brep %s\n" % (uname,name)) + if cleanshape: + try: + shape = shape.cleaned() + except: + shape = shape.copy() if hasplacement is None: # saved with placement hasplacement = False # saved with placement shape.exportBrep(breppath) @@ -64,6 +68,11 @@ def saveShape(csg,filename,shape,name,hasplacement = True): else: #remove placement sh=shape.copy() sh.Placement=FreeCAD.Placement() + # it not yet tested if changing the placement recreated the + # tesselation. but for now we simply do the cleaing once agian + # to stay on the safe side + if cleanshape: + shape = shape.cleaned() sh.exportBrep(breppath) return hasplacement @@ -71,18 +80,31 @@ def saveSweep(csg,ob,filename): import Part spine,subshapelst=ob.Spine #process_object(csg,spine,filename) - try: + explodeshape = process_object(spine) + if explodeshape: + try: + #raise NotImplementedError # hit the fallback + # currently all subshapes are edges + process_object(spine,csg,filename) + csg.write('explode %s E\n' % spine.Name ) + edgelst = ' '.join(('%s_%s' % (spine.Name,ss[4:]) for ss \ + in subshapelst)) + spinename = '%s-0-spine' % ob.Name + csg.write('wire %s %s\n' %(spinename,edgelst)) + except: + explodeshape = False # fallback + raise + if not explodeshape: # extract only the used subshape path=Part.Wire([spine.Shape.getElement(subshapename) for \ - subshapename in spine,subshapelst]) - except: # BRep_API: command not done + subshapename in subshapelst]) if spine.Shape.ShapeType == 'Edge': path = spine.Shape elif spine.Shape.ShapeType == 'Wire': path = Part.Wire(spine.Shape) else: raise ValueError('Unsuitabel Shape Type') - spinename = '%s-0-spine' % ob.Name - hasplacement = saveShape(csg,filename, path,spinename,None) # placement with shape + spinename = '%s-0-spine' % ob.Name + saveShape(csg,filename, path,spinename,None) # placement with shape #safePlacement(ob.Placement,ob.Name) csg.write('mksweep %s\n' % spinename) #setsweep @@ -110,16 +132,36 @@ def saveSweep(csg,ob,filename): #d1['basename']=subobj.Name sectionname = '%s-0-section-%02d-%s' % (ob.Name,i,subobj.Name) addoptions=[] - sh = subobj.Shape - if sh.ShapeType == 'Vertex': - pass - elif sh.ShapeType == 'Wire' or sh.ShapeType == 'Edge': - sh = Part.Wire(sh) - elif sh.ShapeType == 'Face': - sh = sh.OuterWire - else: - raise ValueError('Unrecognized Shape Type') - hasplacement = saveShape(csg,filename,sh,sectionname,None) # placement with shape + explodeshape = process_object(subobj) + if explodeshape: + sh = subobj.Shape + if sh.ShapeType == 'Wire' or sh.ShapeType == 'Edge' or \ + sh.ShapeType == 'Face' and len(sh.Wires) == 1: + process_object(subobj,csg,filename) + if sh.ShapeType == 'Wire': + #csg.write('tcopy %s %s\n' %(subobj.Name,sectionname)) + sectionname = subobj.Name + if sh.ShapeType == 'Edge': + csg.write('explode %s E\n' % subobj.Name ) + csg.write('wire %s %s_1\n' %(sectionname,subobj.Name)) + if sh.ShapeType == 'Face': + #we should use outer wire when it becomes avaiable + csg.write('explode %s W\n' % subobj.Name ) + #csg.write('tcopy %s_1 %s\n' %(subobj.Name,sectionname)) + sectionname ='%s_1' % subobj.Name + else: + explodeshape = False + if not explodeshape: # extract only the used subshape + sh = subobj.Shape + if sh.ShapeType == 'Vertex': + pass + elif sh.ShapeType == 'Wire' or sh.ShapeType == 'Edge': + sh = Part.Wire(sh) + elif sh.ShapeType == 'Face': + sh = sh.OuterWire + else: + raise ValueError('Unrecognized Shape Type') + saveShape(csg,filename,sh,sectionname,None) # placement with shape csg.write('addsweep %s %s\n' % (sectionname," ".join(addoptions))) csg.write('buildsweep %s %s\n' % (ob.Name," ".join(buildoptions))) @@ -182,39 +224,53 @@ def isDeform(ob): -def process_object(csg,ob,filename): +def process_object(ob,csg=None,filename='unnamed'): d1 = {'name':ob.Name} hasplacement = not ob.Placement.isNull() if ob.TypeId in ["Part::Cut","Part::Fuse","Part::Common","Part::Section"]: + if csg is None: + return True # The object is supported d1.update({'part':ob.Base.Name,'tool':ob.Tool.Name,\ 'command':'b%s' % ob.TypeId[6:].lower()}) - process_object(csg,ob.Base,filename) - process_object(csg,ob.Tool,filename) + process_object(ob.Base,csg,filename) + process_object(ob.Tool,csg,filename) csg.write("%(command)s %(name)s %(part)s %(tool)s\n"%d1) elif ob.TypeId == "Part::Sphere" : + if csg is None: + return True # The object is supported d1.update({'radius':f2s(ob.Radius),'angle1':f2s(ob.Angle1),\ 'angle2':f2s(ob.Angle2),'angle3':f2s(ob.Angle3)}) csg.write('psphere %(name)s %(radius)s %(angle1)s %(angle2)s '\ '%(angle3)s\n'%d1) elif ob.TypeId == "Part::Box" : + if csg is None: + return True # The object is supported d1.update({'dx':f2s(ob.Length),'dy':f2s(ob.Width),'dz':f2s(ob.Height)}) csg.write('box %(name)s %(dx)s %(dy)s %(dz)s\n'%d1) elif ob.TypeId == "Part::Cylinder" : + if csg is None: + return True # The object is supported d1.update({'radius':f2s(ob.Radius),'height':f2s(ob.Height),\ 'angle':f2s(ob.Angle)}) csg.write('pcylinder %(name)s %(radius)s %(height)s %(angle)s\n'%d1) elif ob.TypeId == "Part::Cone" : + if csg is None: + return True # The object is supported d1.update({'radius1':f2s(ob.Radius1),'radius2':f2s(ob.Radius2),\ 'height':f2s(ob.Height)}) csg.write('pcone %(name)s %(radius1)s %(radius2)s %(height)s\n'%d1) elif ob.TypeId == "Part::Torus" : + if csg is None: + return True # The object is supported d1.update({'radius1':f2s(ob.Radius1),'radius2':f2s(ob.Radius2),\ 'angle1': f2s(ob.Angle1),'angle2':f2s(ob.Angle2),\ 'angle3': f2s(ob.Angle3)}) csg.write('ptorus %(name)s %(radius1)s %(radius2)s %(angle1)s '\ '%(angle2)s %(angle3)s\n' % d1) elif ob.TypeId == "Part::Mirroring" : - process_object(csg,ob.Source,filename) + if csg is None: + return True # The object is supported + process_object(ob.Source,csg,filename) csg.write('tcopy %s %s\n'%(ob.Source.Name,d1['name'])) b=ob.Base d1['x']=f2s(ob.Base.x) @@ -229,27 +285,35 @@ def process_object(csg,ob,filename): if len(ob.Links) == 0: pass elif len(ob.Links) == 1: - process_object(csg,ob.Links[0],filename) + if csg is None: + return process_object(ob.Links[0],None,filename) + process_object(ob.Links[0],csg,filename) csg.write('tcopy %s %s\n'%(ob.Links[0].Name,d1['name'])) else: + if csg is None: + return True # The object is supported basenames=[] for i,subobj in enumerate(ob.Links): - process_object(csg,subobj,filename) + process_object(subobj,csg,filename) basenames.append(subobj.Name) csg.write('compound %s %s\n' % (' '.join(basenames),ob.Name)) elif ob.TypeId in ["Part::MultiCommon", "Part::MultiFuse"]: if len(ob.Shapes) == 0: pass elif len(ob.Shapes) == 1: - process_object(csg,ob.Shapes[0],filename) + if csg is None: + return process_object(ob.Shapes[0],None,filename) + process_object(ob.Shapes[0],csg,filename) csg.write('tcopy %s %s\n'%(ob.Shapes[0].Name,d1['name'])) else: + if csg is None: + return True # The object is supported topname = ob.Name command = 'b%s' % ob.TypeId[11:].lower() lst1=ob.Shapes[:] current=lst1.pop(0) curname=current.Name - process_object(csg,current,filename) + process_object(current,csg,filename) i=1 while lst1: if len(lst1) >= 2: @@ -257,11 +321,13 @@ def process_object(csg,ob,filename): else: nxtname=topname nxt=lst1.pop(0) - process_object(csg,nxt,filename) + process_object(nxt,csg,filename) csg.write("%s %s %s %s\n"%(command,nxtname,curname,nxt.Name)) curname=nxtname i+=1 elif ob.TypeId == "Part::Prism" : + if csg is None: + return True # The object is supported import math polyname = '%s-polyline' % d1['name'] wirename = '%s-polywire' % d1['name'] @@ -282,38 +348,90 @@ def process_object(csg,ob,filename): csg.write('mkplane %s %s\n' % (facename,polyname)) csg.write('prism %s %s 0 0 %s\n' % (d1['name'],facename,\ f2s(ob.Height.Value))) + elif ob.TypeId == "Part::Extrusion" and ob.TaperAngle.Value == 0: + if csg is None: + return True # The object is supported + process_object(ob.Base,csg,filename) + #Warning does not fully ressemle the functionallity of + #Part::Extrusion + #csg.write('tcopy %s %s\n'%(ob.Base.Name,d1['name'])) + facename=ob.Base.Name + csg.write('prism %s %s %s %s %s\n' % (d1['name'],facename,\ + f2s(ob.Dir.x),f2s(ob.Dir.y),f2s(ob.Dir.z))) + elif ob.TypeId == "Part::Fillet" and True: #disabled + if csg is None: + return True # The object is supported + process_object(ob.Base,csg,filename) + csg.write('explode %s E\n' % ob.Base.Name ) + csg.write('blend %s %s %s\n' % (d1['name'],ob.Base.Name,\ + ' '.join(('%s %s'%(f2s(e[1]),'%s_%d' % (ob.Base.Name,e[0])) \ + for e in ob.Edges)))) elif ob.TypeId == "Part::Sweep" and True: + if csg is None: + return True # The object is supported saveSweep(csg,ob,filename) elif ob.TypeId == "Part::Loft": + if csg is None: + return True # The object is supported sectionnames=[] for i,subobj in enumerate(ob.Sections): - sh = subobj.Shape - if not sh.isNull(): - if sh.ShapeType == 'Compound': - sh = sh.Shape.childShapes()[0] - if sh.ShapeType == 'Face': - sh = sh.OuterWire - elif sh.ShapeType == 'Edge': - import Part - sh = Part.Wire([sh]) - elif sh.ShapeType == 'Wire': - import Part - sh = Part.Wire(sh) - elif sh.ShapeType == 'Vertex': - pass - else: - raise ValueError('Unsuitabel Shape Type') - sectionname = '%s-%02d-section' % (ob.Name,i) - hasplacement = saveShape(csg,filename, sh,sectionname,None) - # placement with shape + explodeshape = process_object(suboobj) + if explodeshape and False: #diabled TBD + try: + raise NotImplementedError + sectionname = '%s-%02d-section' % (ob.Name,i) + sh = subobj.Shape + if sh.isNull(): + raise ValueError # hit the fallback + tempname=spine.Name + if sh.ShapeType == 'Compound': + sh = sh.childShapes()[0] + csg.write('explode %s\n' % tempname ) + tempname = '%s_1' % tempname + if sh.ShapeType == 'Face': + #sh = sh.OuterWire #not available + if len(sh.Wires) == 1: + sh=sh.Wires[0] + csg.write('explode %s\n W' % tempname ) + tempname = '%s_1' % tempname + else: + raise NotImplementedError + elif sh.ShapeType == 'Edge': + csg.write('wire %s %s\n' %(sectionname,tempname)) + tempname = sectionname + sectionname = tempname + except NotImplementedError: + explodeshape = False # fallback + if not explodeshape: # extract only the used subshape + sh = subobj.Shape + if not sh.isNull(): + if sh.ShapeType == 'Compound': + sh = sh.childShapes()[0] + if sh.ShapeType == 'Face': + sh = sh.OuterWire + elif sh.ShapeType == 'Edge': + import Part + sh = Part.Wire([sh]) + elif sh.ShapeType == 'Wire': + import Part + sh = Part.Wire(sh) + elif sh.ShapeType == 'Vertex': + pass + else: + raise ValueError('Unsuitabel Shape Type') + sectionname = '%s-%02d-section' % (ob.Name,i) + saveShape(csg,filename, sh,sectionname,None) + # placement with shape sectionnames.append(sectionname) if ob.Closed: sectionnames.append(sectionnames[0]) csg.write('thrusections %s %d %d %s\n' % (ob.Name,int(ob.Solid),\ int(ob.Ruled), ' '.join(sectionnames))) elif isDeform(ob): #non-uniform scaling + if csg is None: + return True # The object is supported m=ob.Matrix - process_object(csg,ob.Base,filename) + process_object(ob.Base,csg,filename) #csg.write('tcopy %s %s\n'%(ob.Base.Name,d1['name'])) d1['basename']=ob.Base.Name d1['cx']=f2s(m.A11) @@ -324,6 +442,8 @@ def process_object(csg,ob,filename): csg.write("ttranslate %s %s %s %s\n" % \ (ob.Name,f2s(m.A14),f2s(m.A24),f2s(m.A34))) elif isDraftCircle(ob): + if csg is None: + return True # The object is supported "circle name x y [z [dx dy dz]] [ux uy [uz]] radius" d1['radius']=ob.Radius.Value pfirst=f2s(ob.FirstAngle.getValueAs('rad').Value) @@ -341,6 +461,8 @@ def process_object(csg,ob,filename): else: csg.write("renamevar %s %s\n"%(wirename,d1['name'])) #the wire is the final object elif isDraftWire(ob): + if csg is None: + return True # The object is supported points=ob.Points if ob.Closed: points.append(points[0]) @@ -357,6 +479,8 @@ def process_object(csg,ob,filename): wirename = d1['name'] csg.write('wire %s %s\n' %(wirename,polyname)) elif isDraftClone(ob): + if csg is None: + return True # The object is supported x,y,z=ob.Scale.x if x == y == z: #uniform scaling d1['scale']=f2s(x) @@ -366,7 +490,7 @@ def process_object(csg,ob,filename): d1['cz']=f2s(z) if len(ob.Objects) == 1: d1['basename']=ob.Objects[0].Name - process_object(csg,ob.Objects[0],filename) + process_object(ob.Objects[0],csg,filename) if x == y == z: #uniform scaling csg.write('tcopy %(basename)s %(name)s\n' % d1) csg.write('pscale %(name)s 0 0 0 %(scale)s\n' % d1) @@ -376,7 +500,7 @@ def process_object(csg,ob,filename): else: #compound newnames=[] for i,subobj in enumerate(ob.Objects): - process_object(csg,subobj,filename) + process_object(subobj,csg,filename) d1['basename']=subobj.Name newname='%s-%2d' % (ob.Name,i) d1['newname']=newname @@ -394,7 +518,9 @@ def process_object(csg,ob,filename): # pass elif ob.isDerivedFrom('Part::Feature') : if ob.Shape.isNull(): #would crash in exportBrep otherwise - raise ValueError + raise ValueError('Shape of %s is Null' % ob.Name) + if csg is None: + return False # The object is not supported hasplacement = saveShape(csg,filename,ob.Shape,ob.Name,hasplacement) if hasplacement: csg.write(placement2draw(ob.Placement,ob.Name)) @@ -403,9 +529,10 @@ def export(exportList,filename): "called when freecad exports a file" # process Objects csg = pythonopen(filename,'w') - csg.write('#generated by FreeCAD\n') + import FreeCAD + csg.write('#generated by FreeCAD %s\n' % '.'.join(FreeCAD.Version()[0:3])) csg.write('pload ALL\n') for ob in exportList: - process_object(csg,ob,filename) + process_object(ob,csg,filename) csg.write('donly %s\n'%' '.join([obj.Name for obj in exportList])) csg.close()