Hull and Minkowski operations using OpenSCAD
This commit is contained in:
parent
7336a31e44
commit
bcb7d02c05
|
@ -102,9 +102,10 @@ def typecheck (args_and_types, name="?"):
|
|||
def getParamType(param):
|
||||
if param in ["dimsymbol","dimPrecision","dimorientation","precision","defaultWP",
|
||||
"snapRange","gridEvery","linewidth","UiMode","modconstrain","modsnap",
|
||||
"modalt","HatchPatternResolution","snapStyle","dimstyle"]:
|
||||
"maxSnapEdges","modalt","HatchPatternResolution","snapStyle",
|
||||
"dimstyle"]:
|
||||
return "int"
|
||||
elif param in ["constructiongroupname","textfont","patternFile","template","maxSnapEdges",
|
||||
elif param in ["constructiongroupname","textfont","patternFile","template",
|
||||
"snapModes","FontFile"]:
|
||||
return "string"
|
||||
elif param in ["textheight","tolerance","gridSpacing","arrowsize","extlines","dimspacing"]:
|
||||
|
|
|
@ -1467,13 +1467,13 @@ def getWire(wire,nospline=False):
|
|||
# print "wire verts: ",points
|
||||
return points
|
||||
|
||||
def getBlock(sh,obj):
|
||||
def getBlock(sh,obj,lwPoly=False):
|
||||
"returns a dxf block with the contents of the object"
|
||||
block = dxfLibrary.Block(name=obj.Name,layer=getGroup(obj))
|
||||
writeShape(sh,obj,block)
|
||||
writeShape(sh,obj,block,lwPoly)
|
||||
return block
|
||||
|
||||
def writeShape(sh,ob,dxfobject,nospline=False):
|
||||
def writeShape(sh,ob,dxfobject,nospline=False,lwPoly=False):
|
||||
"writes the object's shape contents in the given dxf object"
|
||||
processededges = []
|
||||
for wire in sh.Wires: # polylines
|
||||
|
@ -1490,7 +1490,17 @@ def writeShape(sh,ob,dxfobject,nospline=False):
|
|||
ang1, ang2, color=getACI(ob),
|
||||
layer=getGroup(ob)))
|
||||
else:
|
||||
dxfobject.append(dxfLibrary.PolyLine(getWire(wire,nospline), [0.0,0.0,0.0],
|
||||
if (lwPoly):
|
||||
if hasattr(dxfLibrary,"LwPolyLine"):
|
||||
dxfobject.append(dxfLibrary.LwPolyLine(getWire(wire,nospline), [0.0,0.0],
|
||||
int(DraftGeomUtils.isReallyClosed(wire)), color=getACI(ob),
|
||||
layer=getGroup(ob)))
|
||||
else:
|
||||
FreeCAD.Console.PrintWarning("LwPolyLine support not found. Please delete dxfLibrary.py from your FreeCAD user directory to force auto-update\n")
|
||||
|
||||
|
||||
else :
|
||||
dxfobject.append(dxfLibrary.PolyLine(getWire(wire,nospline), [0.0,0.0,0.0],
|
||||
int(DraftGeomUtils.isReallyClosed(wire)), color=getACI(ob),
|
||||
layer=getGroup(ob)))
|
||||
if len(processededges) < len(sh.Edges): # lone edges
|
||||
|
@ -1576,8 +1586,8 @@ def writeMesh(ob,dxfobject):
|
|||
64, color=getACI(ob),
|
||||
layer=getGroup(ob)))
|
||||
|
||||
def export(objectslist,filename,nospline=False):
|
||||
"called when freecad exports a file. If nospline=True, bsplines are exported as straight segs"
|
||||
def export(objectslist,filename,nospline=False,lwPoly=False):
|
||||
"called when freecad exports a file. If nospline=True, bsplines are exported as straight segs lwPoly=True for OpenSCAD DXF"
|
||||
|
||||
if dxfLibrary:
|
||||
global exportList
|
||||
|
@ -1620,19 +1630,19 @@ def export(objectslist,filename,nospline=False):
|
|||
if (len(sh.Wires) == 1):
|
||||
# only one wire in this compound, no lone edge -> polyline
|
||||
if (len(sh.Wires[0].Edges) == len(sh.Edges)):
|
||||
writeShape(sh,ob,dxf,nospline)
|
||||
writeShape(sh,ob,dxf,nospline,lwPoly)
|
||||
else:
|
||||
# 1 wire + lone edges -> block
|
||||
block = getBlock(sh,ob)
|
||||
block = getBlock(sh,ob,lwPoly)
|
||||
dxf.blocks.append(block)
|
||||
dxf.append(dxfLibrary.Insert(name=ob.Name.upper()))
|
||||
else:
|
||||
# all other cases: block
|
||||
block = getBlock(sh,ob)
|
||||
block = getBlock(sh,ob,lwPoly)
|
||||
dxf.blocks.append(block)
|
||||
dxf.append(dxfLibrary.Insert(name=ob.Name.upper()))
|
||||
else:
|
||||
writeShape(sh,ob,dxf,nospline)
|
||||
writeShape(sh,ob,dxf,nospline,lwPoly)
|
||||
|
||||
elif Draft.getType(ob) == "Annotation":
|
||||
# texts
|
||||
|
@ -1670,7 +1680,7 @@ def exportPage(page,filename):
|
|||
import importSVG
|
||||
tempdoc = importSVG.open(page.PageResult)
|
||||
tempobj = tempdoc.Objects
|
||||
export(tempobj,filename,nospline=True)
|
||||
export(tempobj,filename,nospline=True,lwPoly=False)
|
||||
FreeCAD.closeDocument(tempdoc.Name)
|
||||
|
||||
|
||||
|
|
|
@ -115,8 +115,10 @@ static char * openscadlogo_xpm[] = {
|
|||
FreeCAD.addImportType("OpenSCAD Format (*.scad)","importCSG")
|
||||
param.SetString('openscadexecutable',openscadfilename) #save the result
|
||||
if openscadfilename:
|
||||
commands.extend(['OpenSCAD_AddOpenSCADElement'])
|
||||
toolbarcommands.extend(['OpenSCAD_AddOpenSCADElement'])
|
||||
commands.extend(['OpenSCAD_AddOpenSCADElement',
|
||||
'OpenSCAD_MeshBoolean','OpenSCAD_Hull','OpenSCAD_Minkowski'])
|
||||
toolbarcommands.extend(['OpenSCAD_AddOpenSCADElement',
|
||||
'OpenSCAD_MeshBoolean','OpenSCAD_Hull','OpenSCAD_Minkowski'])
|
||||
else:
|
||||
FreeCAD.Console.PrintWarning('OpenSCAD executable not found\n')
|
||||
|
||||
|
|
|
@ -458,3 +458,32 @@ def superWireReverse(debuglist,closed=False):
|
|||
return None
|
||||
print newedges
|
||||
return Part.Wire(newedges)
|
||||
|
||||
dxfcache = {}
|
||||
def importDXFface(filename,layer=None,doc=None):
|
||||
import FreeCAD,importDXF
|
||||
doc = doc or FreeCAD.activeDocument()
|
||||
global dxfcache
|
||||
layers=dxfcache.get(id(doc),[])
|
||||
if layers:
|
||||
try:
|
||||
groupobj=[go for go in layers if (not layer) or go.Label == layer]
|
||||
except:
|
||||
groupobj= None
|
||||
else:
|
||||
groupobj= None
|
||||
if not groupobj:
|
||||
layers = importDXF.processdxf(doc,filename) or importDXF.layers
|
||||
dxfcache[id(doc)] = layers[:]
|
||||
for l in layers:
|
||||
if FreeCAD.GuiUp:
|
||||
for o in l.Group:
|
||||
o.ViewObject.hide()
|
||||
l.ViewObject.hide()
|
||||
groupobj=[go for go in layers if (not layer) or go.Label == layer]
|
||||
edges=[]
|
||||
if not groupobj:
|
||||
raise ValueError, 'import of layer %s failed' % layer
|
||||
for shapeobj in groupobj[0].Group:
|
||||
edges.extend(shapeobj.Shape.Edges)
|
||||
return edgestofaces(edges)
|
||||
|
|
|
@ -232,6 +232,73 @@ class AddSCADTask:
|
|||
except OpenSCADUtils.OpenSCADError, e:
|
||||
FreeCAD.Console.PrintError(e.value)
|
||||
|
||||
class OpenSCADMeshBooleanWidget(QtGui.QWidget):
|
||||
def __init__(self,*args):
|
||||
QtGui.QWidget.__init__(self,*args)
|
||||
#self.textEdit=QtGui.QTextEdit()
|
||||
self.buttonadd = QtGui.QPushButton(translate('OpenSCAD','Perform'))
|
||||
self.rb_group = QtGui.QButtonGroup()
|
||||
self.rb_group_box = QtGui.QGroupBox()
|
||||
self.rb_group_box_layout = QtGui.QVBoxLayout()
|
||||
self.rb_group_box.setLayout(self.rb_group_box_layout)
|
||||
self.rb_union = QtGui.QRadioButton("Union")
|
||||
self.rb_group.addButton(self.rb_union)
|
||||
self.rb_group_box_layout.addWidget(self.rb_union)
|
||||
self.rb_intersection = QtGui.QRadioButton("Intersection")
|
||||
self.rb_group.addButton(self.rb_intersection)
|
||||
self.rb_group_box_layout.addWidget(self.rb_intersection)
|
||||
self.rb_difference = QtGui.QRadioButton("Difference")
|
||||
self.rb_group.addButton(self.rb_difference)
|
||||
self.rb_group_box_layout.addWidget(self.rb_difference)
|
||||
self.rb_hull = QtGui.QRadioButton("Hull")
|
||||
self.rb_group.addButton(self.rb_hull)
|
||||
self.rb_group_box_layout.addWidget(self.rb_hull)
|
||||
self.rb_minkowski = QtGui.QRadioButton("Minkowski")
|
||||
self.rb_group.addButton(self.rb_minkowski)
|
||||
self.rb_group_box_layout.addWidget(self.rb_minkowski)
|
||||
layouth=QtGui.QHBoxLayout()
|
||||
layouth.addWidget(self.buttonadd)
|
||||
layout= QtGui.QVBoxLayout()
|
||||
layout.addLayout(layouth)
|
||||
layout.addWidget(self.rb_group_box)
|
||||
self.setLayout(layout)
|
||||
self.setWindowTitle(translate('OpenSCAD','Mesh Boolean'))
|
||||
|
||||
def retranslateUi(self, widget=None):
|
||||
self.buttonadd.setText(translate('OpenSCAD','Perform'))
|
||||
self.setWindowTitle(translate('OpenSCAD','Mesh Boolean'))
|
||||
|
||||
class OpenSCADMeshBooleanTask:
|
||||
def __init__(self):
|
||||
pass
|
||||
self.form = OpenSCADMeshBooleanWidget()
|
||||
self.form.buttonadd.clicked.connect(self.doboolean)
|
||||
def getStandardButtons(self):
|
||||
return int(QtGui.QDialogButtonBox.Close)
|
||||
|
||||
def isAllowedAlterSelection(self):
|
||||
return False
|
||||
|
||||
def isAllowedAlterView(self):
|
||||
return False
|
||||
|
||||
def isAllowedAlterDocument(self):
|
||||
return True
|
||||
|
||||
def doboolean(self):
|
||||
from OpenSCADUtils import meshoponobjs
|
||||
if self.form.rb_intersection.isChecked(): opname = 'intersection'
|
||||
elif self.form.rb_difference.isChecked(): opname = 'difference'
|
||||
elif self.form.rb_hull.isChecked(): opname = 'hull'
|
||||
elif self.form.rb_minkowski.isChecked(): opname = 'minkowski'
|
||||
else: opname = 'union'
|
||||
newmesh,objsused = meshoponobjs(opname,FreeCADGui.Selection.getSelection())
|
||||
if len(objsused) > 0:
|
||||
newmeshobj = FreeCAD.activeDocument().addObject('Mesh::Feature',opname) #create a Feature for the result
|
||||
newmeshobj.Mesh = newmesh #assign the result to the new Feature
|
||||
for obj in objsused:
|
||||
obj.ViewObject.hide() #hide the selected Features
|
||||
|
||||
class AddOpenSCADElement:
|
||||
def IsActive(self):
|
||||
return not FreeCADGui.Control.activeDialog()
|
||||
|
@ -245,6 +312,61 @@ class AddOpenSCADElement:
|
|||
QtCore.QT_TRANSLATE_NOOP('OpenSCAD_AddOpenSCADElement',\
|
||||
'Add an OpenSCAD element by entering OpenSCAD code and executing the OpenSCAD binary')}
|
||||
|
||||
class OpenSCADMeshBoolean:
|
||||
def IsActive(self):
|
||||
return not FreeCADGui.Control.activeDialog() and \
|
||||
len(FreeCADGui.Selection.getSelection()) >= 1
|
||||
def Activated(self):
|
||||
panel = OpenSCADMeshBooleanTask()
|
||||
FreeCADGui.Control.showDialog(panel)
|
||||
def GetResources(self):
|
||||
return {'Pixmap' : 'OpenSCAD_MeshBooleans', 'MenuText': \
|
||||
QtCore.QT_TRANSLATE_NOOP('OpenSCAD_MeshBoolean',\
|
||||
'Mesh Boolean...'), 'ToolTip': \
|
||||
QtCore.QT_TRANSLATE_NOOP('OpenSCAD_MeshBoolean',\
|
||||
'Export objects as meshes and use OpenSCAD to perform a boolean operation.')}
|
||||
|
||||
class Hull:
|
||||
def IsActive(self):
|
||||
return len(FreeCADGui.Selection.getSelection()) >= 2
|
||||
|
||||
def Activated(self):
|
||||
import Part,OpenSCADFeatures
|
||||
import importCSG
|
||||
selection=FreeCADGui.Selection.getSelectionEx()
|
||||
objList = []
|
||||
for selobj in selection:
|
||||
objList.append(selobj.Object)
|
||||
selobj.Object.ViewObject.hide()
|
||||
importCSG.process_ObjectsViaOpenSCAD(FreeCAD.activeDocument(),objList,"hull")
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
def GetResources(self):
|
||||
return {'Pixmap' : 'OpenSCAD_Hull', 'MenuText': \
|
||||
QtCore.QT_TRANSLATE_NOOP('OpenSCAD_Hull',\
|
||||
'Hull'), 'ToolTip': \
|
||||
QtCore.QT_TRANSLATE_NOOP('OpenSCAD_Hull',\
|
||||
'Perform Hull')}
|
||||
|
||||
class Minkowski:
|
||||
def IsActive(self):
|
||||
return len(FreeCADGui.Selection.getSelection()) >= 2
|
||||
|
||||
def Activated(self):
|
||||
import Part,OpenSCADFeatures
|
||||
import importCSG
|
||||
selection=FreeCADGui.Selection.getSelectionEx()
|
||||
objList = []
|
||||
for selobj in selection:
|
||||
objList.append(selobj.Object)
|
||||
selobj.Object.ViewObject.hide()
|
||||
importCSG.process_ObjectsViaOpenSCAD(FreeCAD.activeDocument(),objList,"minkowski")
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
def GetResources(self):
|
||||
return {'Pixmap' : 'OpenSCAD_Minkowski', 'MenuText': \
|
||||
QtCore.QT_TRANSLATE_NOOP('OpenSCAD_Minkowski',\
|
||||
'Minkowski'), 'ToolTip': \
|
||||
QtCore.QT_TRANSLATE_NOOP('OpenSCAD_Minkowski',\
|
||||
'Perform Minkowski')}
|
||||
|
||||
FreeCADGui.addCommand('OpenSCAD_ColorCodeShape',ColorCodeShape())
|
||||
FreeCADGui.addCommand('OpenSCAD_Edgestofaces',Edgestofaces())
|
||||
|
@ -253,3 +375,6 @@ FreeCADGui.addCommand('OpenSCAD_ExpandPlacements',ExpandPlacements())
|
|||
FreeCADGui.addCommand('OpenSCAD_ReplaceObject',ReplaceObject())
|
||||
FreeCADGui.addCommand('OpenSCAD_RemoveSubtree',RemoveSubtree())
|
||||
FreeCADGui.addCommand('OpenSCAD_AddOpenSCADElement',AddOpenSCADElement())
|
||||
FreeCADGui.addCommand('OpenSCAD_MeshBoolean',OpenSCADMeshBoolean())
|
||||
FreeCADGui.addCommand('OpenSCAD_Hull',Hull())
|
||||
FreeCADGui.addCommand('OpenSCAD_Minkowski',Minkowski())
|
||||
|
|
|
@ -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')
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,11 +1,14 @@
|
|||
<RCC>
|
||||
<qresource>
|
||||
<qresource>
|
||||
<file>icons/preferences-openscad.svg</file>
|
||||
<file>icons/OpenSCAD_AddOpenSCADElement.svg</file>
|
||||
<file>icons/OpenSCAD_ColorCodeShape.svg</file>
|
||||
<file>icons/OpenSCAD_RefineShapeFeature.svg</file>
|
||||
<file>icons/OpenSCAD_ReplaceObject.svg</file>
|
||||
<file>icons/OpenSCAD_RemoveSubtree.svg</file>
|
||||
<file>icons/OpenSCAD_MeshBooleans.svg</file>
|
||||
<file>icons/OpenSCAD_Hull.svg</file>
|
||||
<file>icons/OpenSCAD_Minkowski.svg</file>
|
||||
<file>ui/openscadprefs-base.ui</file>
|
||||
<file>translations/OpenSCAD_tr.qm</file>
|
||||
<file>translations/OpenSCAD_sv-SE.qm</file>
|
||||
|
@ -31,4 +34,4 @@
|
|||
<file>translations/OpenSCAD_it.qm</file>
|
||||
<file>translations/OpenSCAD_pt-PT.qm</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
</RCC>
|
||||
|
|
207
src/Mod/OpenSCAD/Resources/icons/OpenSCAD_Hull.svg
Normal file
207
src/Mod/OpenSCAD/Resources/icons/OpenSCAD_Hull.svg
Normal file
|
@ -0,0 +1,207 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="64px"
|
||||
height="64px"
|
||||
id="svg2568"
|
||||
sodipodi:version="0.32"
|
||||
inkscape:version="0.48.2 r9819"
|
||||
sodipodi:docname="Hull.svg"
|
||||
inkscape:output_extension="org.inkscape.output.svg.inkscape"
|
||||
version="1.1">
|
||||
<defs
|
||||
id="defs2570">
|
||||
<linearGradient
|
||||
id="linearGradient3768">
|
||||
<stop
|
||||
style="stop-color:#71b2f8;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3770" />
|
||||
<stop
|
||||
style="stop-color:#002795;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop3772" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient3864">
|
||||
<stop
|
||||
id="stop3866"
|
||||
offset="0"
|
||||
style="stop-color:#71b2f8;stop-opacity:1;" />
|
||||
<stop
|
||||
id="stop3868"
|
||||
offset="1"
|
||||
style="stop-color:#002795;stop-opacity:1;" />
|
||||
</linearGradient>
|
||||
<radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3768"
|
||||
id="radialGradient3552"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="48.645836"
|
||||
cy="25.149042"
|
||||
fx="48.645836"
|
||||
fy="25.149042"
|
||||
r="19.571428" />
|
||||
<linearGradient
|
||||
id="linearGradient3593">
|
||||
<stop
|
||||
style="stop-color:#c8e0f9;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3595" />
|
||||
<stop
|
||||
style="stop-color:#637dca;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop3597" />
|
||||
</linearGradient>
|
||||
<radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3593"
|
||||
id="radialGradient3599"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="51.637894"
|
||||
cy="24.962704"
|
||||
fx="51.637894"
|
||||
fy="24.962704"
|
||||
r="19.571428" />
|
||||
<inkscape:perspective
|
||||
sodipodi:type="inkscape:persp3d"
|
||||
inkscape:vp_x="0 : 32 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_z="64 : 32 : 1"
|
||||
inkscape:persp3d-origin="32 : 21.333333 : 1"
|
||||
id="perspective2576" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3768"
|
||||
id="linearGradient3780"
|
||||
x1="8.272727"
|
||||
y1="15.363636"
|
||||
x2="32"
|
||||
y2="15.363636"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3768"
|
||||
id="linearGradient3790"
|
||||
x1="38.454544"
|
||||
y1="44"
|
||||
x2="57.090908"
|
||||
y2="44"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="11"
|
||||
inkscape:cx="17.948847"
|
||||
inkscape:cy="28.410725"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="true"
|
||||
inkscape:document-units="px"
|
||||
inkscape:grid-bbox="true"
|
||||
inkscape:window-width="1280"
|
||||
inkscape:window-height="947"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="27"
|
||||
inkscape:window-maximized="1" />
|
||||
<metadata
|
||||
id="metadata2573">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
id="layer1"
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer">
|
||||
<g
|
||||
id="g3560"
|
||||
transform="translate(8.7385455e-2,-0.7238878)">
|
||||
<path
|
||||
transform="matrix(0.9153551,0,0,0.3021994,-4.6085053,28.76682)"
|
||||
d="m 71.785715,34.571426 c 0,10.256717 -8.314712,18.571429 -18.571428,18.571429 -10.256717,0 -18.571428,-8.314712 -18.571428,-18.571429 0,-10.256716 8.314711,-18.571428 18.571428,-18.571428 10.256716,0 18.571428,8.314712 18.571428,18.571428 z"
|
||||
sodipodi:ry="18.571428"
|
||||
sodipodi:rx="18.571428"
|
||||
sodipodi:cy="34.571426"
|
||||
sodipodi:cx="53.214287"
|
||||
id="path3558"
|
||||
style="opacity:0.66523605;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.5;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
sodipodi:type="arc" />
|
||||
<path
|
||||
transform="matrix(1.0092422,0,0,1.0092422,-12.598958,-12.283801)"
|
||||
d="m 71.785715,34.571426 c 0,10.256717 -8.314712,18.571429 -18.571428,18.571429 -10.256717,0 -18.571428,-8.314712 -18.571428,-18.571429 0,-10.256716 8.314711,-18.571428 18.571428,-18.571428 10.256716,0 18.571428,8.314712 18.571428,18.571428 z"
|
||||
sodipodi:ry="18.571428"
|
||||
sodipodi:rx="18.571428"
|
||||
sodipodi:cy="34.571426"
|
||||
sodipodi:cx="53.214287"
|
||||
id="path2768"
|
||||
style="opacity:1;fill:url(#radialGradient3599);fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:2.17985344000000003;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
sodipodi:type="arc" />
|
||||
<path
|
||||
transform="matrix(1.1483533,0,0,0.3791225,-28.823086,42.536051)"
|
||||
d="m 71.785715,34.571426 c 0,10.256717 -8.314712,18.571429 -18.571428,18.571429 -10.256717,0 -18.571428,-8.314712 -18.571428,-18.571429 0,-10.256716 8.314711,-18.571428 18.571428,-18.571428 10.256716,0 18.571428,8.314712 18.571428,18.571428 z"
|
||||
sodipodi:ry="18.571428"
|
||||
sodipodi:rx="18.571428"
|
||||
sodipodi:cy="34.571426"
|
||||
sodipodi:cx="53.214287"
|
||||
id="path3554"
|
||||
style="opacity:0.66523605;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.5;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
sodipodi:type="arc" />
|
||||
<path
|
||||
transform="matrix(1.12939,0,0,1.12939,-36.028256,1.4553754)"
|
||||
d="m 71.785715,34.571426 c 0,10.256717 -8.314712,18.571429 -18.571428,18.571429 -10.256717,0 -18.571428,-8.314712 -18.571428,-18.571429 0,-10.256716 8.314711,-18.571428 18.571428,-18.571428 10.256716,0 18.571428,8.314712 18.571428,18.571428 z"
|
||||
sodipodi:ry="18.571428"
|
||||
sodipodi:rx="18.571428"
|
||||
sodipodi:cy="34.571426"
|
||||
sodipodi:cx="53.214287"
|
||||
id="path3550"
|
||||
style="opacity:1;fill:url(#radialGradient3552);fill-opacity:1.0;fill-rule:evenodd;stroke:#000137;stroke-width:1.94795417999999998;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
sodipodi:type="arc" />
|
||||
</g>
|
||||
<path
|
||||
style="fill:url(#linearGradient3780);fill-opacity:1;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
||||
d="M 9.2727273,24.818182 C 18.121559,15.994395 19.315866,14.909228 28.454545,7.9090909 26.939394,9.6060606 27.969697,7.7575757 26.727273,10.545454 c -1.606061,1.878788 -3.030304,5.666668 -2.545455,8.09091 -2.818182,0.30303 -4.636363,0.696969 -7,1.454545 -2.636363,1.030303 -5.363636,2.878788 -7.7272725,4.818182"
|
||||
id="path2998"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccccc" />
|
||||
<path
|
||||
style="fill:url(#linearGradient3790);fill-opacity:1;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
||||
d="M 39.454545,54.545455 56.090909,33.454545 C 52.80998,36.606291 49.452023,39.475597 45.454546,40 43.924449,51.42576 41.260682,49.912373 39.454545,54.545455 z"
|
||||
id="path3782"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccc" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:28px;font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-opacity:1;font-family:Century Schoolbook L;-inkscape-font-specification:Century Schoolbook L Medium"
|
||||
x="14.372282"
|
||||
y="47.264793"
|
||||
id="text3792"
|
||||
sodipodi:linespacing="125%"
|
||||
transform="scale(0.93174328,1.073257)"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3794"
|
||||
x="14.372282"
|
||||
y="47.264793"
|
||||
style="stroke-width:1;stroke:none">H</tspan></text>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 9.2 KiB |
154
src/Mod/OpenSCAD/Resources/icons/OpenSCAD_MeshBooleans.svg
Normal file
154
src/Mod/OpenSCAD/Resources/icons/OpenSCAD_MeshBooleans.svg
Normal file
|
@ -0,0 +1,154 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="64px"
|
||||
height="64px"
|
||||
id="svg2568"
|
||||
sodipodi:version="0.32"
|
||||
inkscape:version="0.48.4 r9939"
|
||||
sodipodi:docname="OpenSCAD_MeshBooleans.svg"
|
||||
inkscape:output_extension="org.inkscape.output.svg.inkscape"
|
||||
version="1.1">
|
||||
<defs
|
||||
id="defs2570">
|
||||
<linearGradient
|
||||
id="linearGradient3864">
|
||||
<stop
|
||||
id="stop3866"
|
||||
offset="0"
|
||||
style="stop-color:#71f873;stop-opacity:1;" />
|
||||
<stop
|
||||
id="stop3868"
|
||||
offset="1"
|
||||
style="stop-color:#009520;stop-opacity:1;" />
|
||||
</linearGradient>
|
||||
<radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3864"
|
||||
id="radialGradient3552"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="48.645836"
|
||||
cy="25.149042"
|
||||
fx="48.645836"
|
||||
fy="25.149042"
|
||||
r="19.571428" />
|
||||
<linearGradient
|
||||
id="linearGradient3593">
|
||||
<stop
|
||||
style="stop-color:#c8f9d7;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3595" />
|
||||
<stop
|
||||
style="stop-color:#63ca72;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop3597" />
|
||||
</linearGradient>
|
||||
<radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3593"
|
||||
id="radialGradient3599"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="51.63789367675781"
|
||||
cy="24.96270370483398"
|
||||
fx="51.63789367675781"
|
||||
fy="24.96270370483398"
|
||||
r="19.5714282989502" />
|
||||
<inkscape:perspective
|
||||
sodipodi:type="inkscape:persp3d"
|
||||
inkscape:vp_x="0 : 32 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_z="64 : 32 : 1"
|
||||
inkscape:persp3d-origin="32 : 21.333333 : 1"
|
||||
id="perspective2576" />
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="5.5"
|
||||
inkscape:cx="28.11631962809919"
|
||||
inkscape:cy="29.81818181818181"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="true"
|
||||
inkscape:document-units="px"
|
||||
inkscape:grid-bbox="true"
|
||||
inkscape:window-width="966"
|
||||
inkscape:window-height="684"
|
||||
inkscape:window-x="286"
|
||||
inkscape:window-y="142"
|
||||
inkscape:window-maximized="0" />
|
||||
<metadata
|
||||
id="metadata2573">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
id="layer1"
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer">
|
||||
<g
|
||||
id="g3780">
|
||||
<path
|
||||
transform="matrix(0.9153551,0,0,0.3021994,-4.521119845000002,28.0429322)"
|
||||
d="m 71.78571510314941,34.57142639160156 a 18.57142829895019,18.57142829895019 0 1 1 -37.14285659790039,0 18.57142829895019,18.57142829895019 0 1 1 37.14285659790039,0 z"
|
||||
sodipodi:ry="18.5714282989502"
|
||||
sodipodi:rx="18.5714282989502"
|
||||
sodipodi:cy="34.57142639160156"
|
||||
sodipodi:cx="53.21428680419922"
|
||||
id="path3558"
|
||||
style="opacity:0.6652360505;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.5;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
sodipodi:type="arc" />
|
||||
<path
|
||||
transform="matrix(1.1483533,0,0,0.3791225,-28.735700545,41.8121632)"
|
||||
d="m 71.78571510314941,34.57142639160156 a 18.57142829895019,18.57142829895019 0 1 1 -37.14285659790039,0 18.57142829895019,18.57142829895019 0 1 1 37.14285659790039,0 z"
|
||||
sodipodi:ry="18.5714282989502"
|
||||
sodipodi:rx="18.5714282989502"
|
||||
sodipodi:cy="34.57142639160156"
|
||||
sodipodi:cx="53.21428680419922"
|
||||
id="path3554"
|
||||
style="opacity:0.6652360505;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.5;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
sodipodi:type="arc" />
|
||||
<path
|
||||
sodipodi:nodetypes="cccccccccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path3772"
|
||||
d="M 59.67865278080046,26.6852017615018 52.71578497472754,39.06910016108945 38.70426737424912,44.75049625896224 23.10904762434138,37.80185807558856 17.54806378587958,26.6852017615018 20.119273174984,14.04461978738622 27.4622884574563,6.138965495725559 38.70426737424912,2.801725445859524 53.93362423880439,9.576246488586459 z"
|
||||
style="fill:#67ff67;fill-opacity:1;fill-rule:evenodd;stroke:#47a151;stroke-width:2.20000004770000010;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
|
||||
<path
|
||||
style="fill:none;stroke:#32a032;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 27.45454545454545,7.272727272727268 26.1818181818182,4.000000000000003 -33.0909090909091,4 38.90909090909092,12.36363636363638 -41.45454545454547,0 34.36363636363637,11.63636363636362 -29.0909090909091,-1.27272727272727"
|
||||
id="path3774"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="fill:#00af00;fill-opacity:1;fill-rule:evenodd;stroke:#003706;stroke-width:2.2000000477;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
d="M 45.13319823534591,42.6852017615018 38.17033042927297,55.06910016108946 24.15881282879458,60.75049625896225 8.563593078886837,53.80185807558857 3.002609240425043,42.6852017615018 5.573818629529458,30.04461978738622 l 7.343015282472313,-7.90565429166066 11.2419789167928,-3.33724004986603 15.22935686455528,6.77452104272693 z"
|
||||
id="path3768"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccccccccc" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path3770"
|
||||
d="m 12.90909090909091,22.36363636363636 26.18181818181819,4 -33.0909090909091,4 38.90909090909092,12.36363636363638 -41.454545454545467,0 L 37.81818181818182,54.36363636363636 8.727272727272726,53.0909090909091"
|
||||
style="fill:none;stroke:#002f00;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 6.8 KiB |
207
src/Mod/OpenSCAD/Resources/icons/OpenSCAD_Minkowski.svg
Normal file
207
src/Mod/OpenSCAD/Resources/icons/OpenSCAD_Minkowski.svg
Normal file
|
@ -0,0 +1,207 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="64px"
|
||||
height="64px"
|
||||
id="svg2568"
|
||||
sodipodi:version="0.32"
|
||||
inkscape:version="0.48.2 r9819"
|
||||
sodipodi:docname="Minkowski.svg"
|
||||
inkscape:output_extension="org.inkscape.output.svg.inkscape"
|
||||
version="1.1">
|
||||
<defs
|
||||
id="defs2570">
|
||||
<linearGradient
|
||||
id="linearGradient3768">
|
||||
<stop
|
||||
style="stop-color:#71b2f8;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3770" />
|
||||
<stop
|
||||
style="stop-color:#002795;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop3772" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient3864">
|
||||
<stop
|
||||
id="stop3866"
|
||||
offset="0"
|
||||
style="stop-color:#71b2f8;stop-opacity:1;" />
|
||||
<stop
|
||||
id="stop3868"
|
||||
offset="1"
|
||||
style="stop-color:#002795;stop-opacity:1;" />
|
||||
</linearGradient>
|
||||
<radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3768"
|
||||
id="radialGradient3552"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="48.645836"
|
||||
cy="25.149042"
|
||||
fx="48.645836"
|
||||
fy="25.149042"
|
||||
r="19.571428" />
|
||||
<linearGradient
|
||||
id="linearGradient3593">
|
||||
<stop
|
||||
style="stop-color:#c8e0f9;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3595" />
|
||||
<stop
|
||||
style="stop-color:#637dca;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop3597" />
|
||||
</linearGradient>
|
||||
<radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3593"
|
||||
id="radialGradient3599"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="51.637894"
|
||||
cy="24.962704"
|
||||
fx="51.637894"
|
||||
fy="24.962704"
|
||||
r="19.571428" />
|
||||
<inkscape:perspective
|
||||
sodipodi:type="inkscape:persp3d"
|
||||
inkscape:vp_x="0 : 32 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_z="64 : 32 : 1"
|
||||
inkscape:persp3d-origin="32 : 21.333333 : 1"
|
||||
id="perspective2576" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3768"
|
||||
id="linearGradient3780"
|
||||
x1="8.272727"
|
||||
y1="15.363636"
|
||||
x2="32"
|
||||
y2="15.363636"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3768"
|
||||
id="linearGradient3790"
|
||||
x1="38.454544"
|
||||
y1="44"
|
||||
x2="57.090908"
|
||||
y2="44"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="11"
|
||||
inkscape:cx="34.312483"
|
||||
inkscape:cy="28.410725"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="true"
|
||||
inkscape:document-units="px"
|
||||
inkscape:grid-bbox="true"
|
||||
inkscape:window-width="1280"
|
||||
inkscape:window-height="947"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="27"
|
||||
inkscape:window-maximized="1" />
|
||||
<metadata
|
||||
id="metadata2573">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
id="layer1"
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer">
|
||||
<g
|
||||
id="g3560"
|
||||
transform="translate(8.7385455e-2,-0.7238878)">
|
||||
<path
|
||||
transform="matrix(0.9153551,0,0,0.3021994,-4.6085053,28.76682)"
|
||||
d="M 71.785715,34.571426 A 18.571428,18.571428 0 1 1 34.642859,34.571426 A 18.571428,18.571428 0 1 1 71.785715,34.571426 z"
|
||||
sodipodi:ry="18.571428"
|
||||
sodipodi:rx="18.571428"
|
||||
sodipodi:cy="34.571426"
|
||||
sodipodi:cx="53.214287"
|
||||
id="path3558"
|
||||
style="opacity:0.66523605;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.5;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
sodipodi:type="arc" />
|
||||
<path
|
||||
transform="matrix(1.0092422,0,0,1.0092422,-12.598958,-12.283801)"
|
||||
d="M 71.785715,34.571426 A 18.571428,18.571428 0 1 1 34.642859,34.571426 A 18.571428,18.571428 0 1 1 71.785715,34.571426 z"
|
||||
sodipodi:ry="18.571428"
|
||||
sodipodi:rx="18.571428"
|
||||
sodipodi:cy="34.571426"
|
||||
sodipodi:cx="53.214287"
|
||||
id="path2768"
|
||||
style="opacity:1;fill:url(#radialGradient3599);fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:2.17985344000000003;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
sodipodi:type="arc" />
|
||||
<path
|
||||
transform="matrix(1.1483533,0,0,0.3791225,-28.823086,42.536051)"
|
||||
d="M 71.785715,34.571426 A 18.571428,18.571428 0 1 1 34.642859,34.571426 A 18.571428,18.571428 0 1 1 71.785715,34.571426 z"
|
||||
sodipodi:ry="18.571428"
|
||||
sodipodi:rx="18.571428"
|
||||
sodipodi:cy="34.571426"
|
||||
sodipodi:cx="53.214287"
|
||||
id="path3554"
|
||||
style="opacity:0.66523605;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.5;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
sodipodi:type="arc" />
|
||||
<path
|
||||
transform="matrix(1.12939,0,0,1.12939,-36.028256,1.4553754)"
|
||||
d="M 71.785715,34.571426 A 18.571428,18.571428 0 1 1 34.642859,34.571426 A 18.571428,18.571428 0 1 1 71.785715,34.571426 z"
|
||||
sodipodi:ry="18.571428"
|
||||
sodipodi:rx="18.571428"
|
||||
sodipodi:cy="34.571426"
|
||||
sodipodi:cx="53.214287"
|
||||
id="path3550"
|
||||
style="opacity:1;fill:url(#radialGradient3552);fill-opacity:1.0;fill-rule:evenodd;stroke:#000137;stroke-width:1.94795417999999998;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
sodipodi:type="arc" />
|
||||
</g>
|
||||
<path
|
||||
style="fill:url(#linearGradient3780);fill-opacity:1;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
||||
d="M 9.2727273,24.818182 C 18.121559,15.994395 22.821858,13.415923 29.363637,7.4545454 c -1.561209,1.6278839 -2.144572,2.4498097 -3,3.8181816 -1.606061,3.395973 -1.757577,5.030304 -2.181819,7.363637 -2.818182,0.30303 -4.636363,0.696969 -7,1.454545 -2.636363,1.030303 -5.363636,2.878788 -7.7272725,4.818182"
|
||||
id="path2998"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccccc" />
|
||||
<path
|
||||
style="fill:url(#linearGradient3790);fill-opacity:1;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
||||
d="M 39.454545,54.545455 56.090909,33.454545 C 52.80998,36.606291 49.452023,39.475597 45.454546,40 43.924449,51.42576 41.260682,49.912373 39.454545,54.545455 z"
|
||||
id="path3782"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccc" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:28px;font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-opacity:1;font-family:Century Schoolbook L;-inkscape-font-specification:Century Schoolbook L Medium"
|
||||
x="12.616044"
|
||||
y="47.518906"
|
||||
id="text3792"
|
||||
sodipodi:linespacing="125%"
|
||||
transform="scale(0.93174328,1.073257)"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3794"
|
||||
x="12.616044"
|
||||
y="47.518906"
|
||||
style="font-size:28px;font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;stroke-width:1;font-family:Century Schoolbook L;-inkscape-font-specification:Century Schoolbook L Medium;stroke:none">M</tspan></text>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 9.0 KiB |
|
@ -27,7 +27,7 @@
|
|||
#* *
|
||||
#* *
|
||||
#***************************************************************************
|
||||
__title__="FreeCAD OpenSCAD Workbench - CSG importer Version 0.05d"
|
||||
__title__="FreeCAD OpenSCAD Workbench - CSG importer Version 0.06a"
|
||||
__author__ = "Keith Sloan <keith@sloan-home.co.uk>"
|
||||
__url__ = ["http://www.sloan-home.co.uk/ImportCSG"]
|
||||
|
||||
|
@ -47,7 +47,7 @@ import ply.yacc as yacc
|
|||
import Part
|
||||
|
||||
from OpenSCADFeatures import RefineShape
|
||||
from OpenSCAD2Dgeom import *
|
||||
#from OpenSCAD2Dgeom import *
|
||||
from OpenSCADUtils import *
|
||||
isspecialorthogonaldeterminant = isspecialorthogonalpython
|
||||
from OpenSCADFeatures import Twist
|
||||
|
@ -59,8 +59,6 @@ if open.__module__ == '__builtin__':
|
|||
import tokrules
|
||||
from tokrules import tokens
|
||||
|
||||
#Globals
|
||||
dxfcache = {}
|
||||
def translate(context,text):
|
||||
"convenience function for Qt translator"
|
||||
from PyQt4 import QtGui
|
||||
|
@ -339,24 +337,15 @@ def p_operation(p):
|
|||
| rotate_extrude_file
|
||||
| import_file1
|
||||
| projection_action
|
||||
| hull_action
|
||||
| minkowski_action
|
||||
'''
|
||||
p[0] = p[1]
|
||||
|
||||
|
||||
def p_not_supported(p):
|
||||
'''
|
||||
not_supported : hull LPAREN keywordargument_list RPAREN OBRACE block_list EBRACE
|
||||
| minkowski LPAREN keywordargument_list RPAREN OBRACE block_list EBRACE
|
||||
| glide LPAREN keywordargument_list RPAREN OBRACE block_list EBRACE
|
||||
'''
|
||||
if gui and not FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/OpenSCAD").\
|
||||
GetBool('usePlaceholderForUnsupported'):
|
||||
from PyQt4 import QtGui
|
||||
QtGui.QMessageBox.critical(None, unicode(translate('OpenSCAD',"Unsupported Function"))+" : "+p[1],unicode(translate('OpenSCAD',"Press OK")))
|
||||
else:
|
||||
from OpenSCADFeatures import OpenSCADPlaceholder
|
||||
newobj=doc.addObject("Part::FeaturePython",p[1])
|
||||
OpenSCADPlaceholder(newobj,p[6],str(p[3]))
|
||||
|
||||
def placeholder(name,children,arguments):
|
||||
from OpenSCADFeatures import OpenSCADPlaceholder
|
||||
newobj=doc.addObject("Part::FeaturePython",name)
|
||||
OpenSCADPlaceholder(newobj,children,str(arguments))
|
||||
if gui:
|
||||
if FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/OpenSCAD").\
|
||||
GetBool('useViewProviderTree'):
|
||||
|
@ -364,10 +353,39 @@ def p_not_supported(p):
|
|||
ViewProviderTree(newobj.ViewObject)
|
||||
else:
|
||||
newobj.ViewObject.Proxy = 0
|
||||
#don't hide the children
|
||||
p[0] = [newobj]
|
||||
#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
|
||||
'''
|
||||
newobj = process_ObjectsViaOpenSCAD(doc,children,name)
|
||||
if newobj is not None :
|
||||
return newobj
|
||||
else:
|
||||
return placeholder(name,children,arguments)
|
||||
|
||||
def p_hull_action(p):
|
||||
'hull_action : hull LPAREN RPAREN OBRACE block_list EBRACE'
|
||||
p[0] = [ CGALorPlaceholder(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]) ]
|
||||
|
||||
def p_not_supported(p):
|
||||
'''
|
||||
not_supported : glide LPAREN keywordargument_list RPAREN OBRACE block_list EBRACE
|
||||
'''
|
||||
if gui and not FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/OpenSCAD").\
|
||||
GetBool('usePlaceholderForUnsupported'):
|
||||
from PyQt4 import QtGui
|
||||
QtGui.QMessageBox.critical(None, unicode(translate('OpenSCAD',"Unsupported Function"))+" : "+p[1],unicode(translate('OpenSCAD',"Press OK")))
|
||||
else:
|
||||
p[0] = [placeholder(p[1],p[6],p[3])]
|
||||
|
||||
|
||||
def p_size_vector(p):
|
||||
'size_vector : OSQUARE NUMBER COMMA NUMBER COMMA NUMBER ESQUARE'
|
||||
if printverbose: print "size vector"
|
||||
|
@ -602,10 +620,10 @@ def process_import_file(fname,ext,layer):
|
|||
if printverbose: print "Importing : "+fname+"."+ext+" Layer : "+layer
|
||||
if ext.lower() in reverseimporttypes()['Mesh']:
|
||||
obj=process_mesh_file(fname,ext)
|
||||
elif ext=='dxf' :
|
||||
elif ext.lower() == 'dxf' :
|
||||
obj=processDXF(fname,layer)
|
||||
else :
|
||||
if printverbose: print "Unsupported file extension"
|
||||
else:
|
||||
raise ValueError, "Unsupported file extension %s" % ext
|
||||
return(obj)
|
||||
|
||||
def process_mesh_file(fname,ext):
|
||||
|
@ -635,6 +653,7 @@ def process_mesh_file(fname,ext):
|
|||
def processDXF(fname,layer):
|
||||
global doc
|
||||
global pathName
|
||||
from OpenSCAD2Dgeom import importDXFface
|
||||
if printverbose: print "Process DXF file"
|
||||
if printverbose: print "File Name : "+fname
|
||||
if printverbose: print "Layer : "+layer
|
||||
|
@ -642,41 +661,12 @@ def processDXF(fname,layer):
|
|||
dxfname = fname+'.dxf'
|
||||
filename = os.path.join(pathName,dxfname)
|
||||
if printverbose: print "DXF Full path : "+filename
|
||||
#featname='import_dxf_%s_%s'%(objname,layera)
|
||||
# reusing an allready imported object does not work if the
|
||||
#shape in not yet calculated
|
||||
import importDXF
|
||||
global dxfcache
|
||||
layers=dxfcache.get(id(doc),[])
|
||||
if printverbose: print "Layers : "+str(layers)
|
||||
if layers:
|
||||
try:
|
||||
groupobj=[go for go in layers if (not layer) or go.Label == layer]
|
||||
except:
|
||||
groupobj= None
|
||||
else:
|
||||
groupobj= None
|
||||
if not groupobj:
|
||||
if printverbose: print "Importing Layer"
|
||||
layers = importDXF.processdxf(doc,filename) or importDXF.layers
|
||||
dxfcache[id(doc)] = layers[:]
|
||||
for l in layers:
|
||||
if gui:
|
||||
for o in l.Group:
|
||||
o.ViewObject.hide()
|
||||
l.ViewObject.hide()
|
||||
groupobj=[go for go in layers if (not layer) or go.Label == layer]
|
||||
edges=[]
|
||||
if not groupobj:
|
||||
if printverbose: print 'import of layer %s failed' % layer
|
||||
for shapeobj in groupobj[0].Group:
|
||||
edges.extend(shapeobj.Shape.Edges)
|
||||
f=edgestofaces(edges)
|
||||
face = importDXFface(filename,layer,doc)
|
||||
#obj=doc.addObject("Part::FeaturePython",'import_dxf_%s_%s'%(objname,layera))
|
||||
obj=doc.addObject('Part::Feature',"dxf")
|
||||
obj=doc.addObject('Part::Feature',layer or "dxf")
|
||||
#ImportObject(obj,groupobj[0]) #This object is not mutable from the GUI
|
||||
#ViewProviderTree(obj.ViewObject)
|
||||
obj.Shape=f
|
||||
obj.Shape=face
|
||||
if printverbose: print "DXF Diagnostics"
|
||||
if printverbose: print obj.Shape.ShapeType
|
||||
if printverbose: print "Closed : "+str(f.isClosed())
|
||||
|
|
Loading…
Reference in New Issue
Block a user