Hull and Minkowski operations using OpenSCAD

This commit is contained in:
Keith Sloan 2013-10-30 10:04:34 +01:00 committed by Sebastian Hoogen
parent 7336a31e44
commit bcb7d02c05
12 changed files with 11930 additions and 9374 deletions

View File

@ -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"]:

View File

@ -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)

View File

@ -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')

View File

@ -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)

View File

@ -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())

View File

@ -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

View File

@ -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>

View 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

View 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

View 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

View File

@ -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())