Merge branch 'review-openscad'
This commit is contained in:
commit
1de8259968
|
@ -46,3 +46,6 @@ endif(FREECAD_BUILD_SANDBOX)
|
|||
|
||||
add_subdirectory(Surfaces)
|
||||
add_subdirectory(Ship)
|
||||
add_subdirectory(OpenSCAD)
|
||||
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#SUBDIRS=Part Mesh Points Raytracing Image Drawing Complete Draft Test TemplatePyMod
|
||||
SUBDIRS=Points Complete Draft Test TemplatePyMod Web Start Idf Arch Surfaces Ship
|
||||
SUBDIRS=Points Complete Draft Test TemplatePyMod Web Start Idf Arch Surfaces Ship OpenSCAD
|
||||
|
||||
#if HAVE_OPENCV
|
||||
SUBDIRS += Image
|
||||
|
|
45
src/Mod/OpenSCAD/CMakeLists.txt
Normal file
45
src/Mod/OpenSCAD/CMakeLists.txt
Normal file
|
@ -0,0 +1,45 @@
|
|||
SET(OpenSCAD_SRCS
|
||||
Init.py
|
||||
InitGui.py
|
||||
OpenSCAD_rc.py
|
||||
OpenSCAD2Dgeom.py
|
||||
OpenSCADFeatures.py
|
||||
OpenSCADUtils.py
|
||||
OpenSCADCommands.py
|
||||
exportCSG.py
|
||||
importCSG.py
|
||||
prototype.py
|
||||
tokrules.py
|
||||
colorcodeshapes.py
|
||||
expandplacements.py
|
||||
replaceobj.py
|
||||
)
|
||||
SOURCE_GROUP("" FILES ${OpenSCAD_SRCS})
|
||||
|
||||
SET(ply_SRCS
|
||||
ply/lex.py
|
||||
ply/README
|
||||
ply/yacc.py
|
||||
ply/__init__.py
|
||||
)
|
||||
SOURCE_GROUP("ply" FILES ${ply_SRCS})
|
||||
|
||||
set(all_files ${OpenSCAD_SRCS} ${ply_SRCS})
|
||||
|
||||
ADD_CUSTOM_TARGET(OpenSCAD ALL
|
||||
SOURCES ${allfiles}
|
||||
)
|
||||
fc_copy_sources(OpenSCAD "${CMAKE_BINARY_DIR}/Mod/OpenSCAD" ${all_files})
|
||||
|
||||
INSTALL(
|
||||
FILES
|
||||
${ply_SRCS}
|
||||
DESTINATION
|
||||
Mod/OpenSCAD/ply
|
||||
)
|
||||
INSTALL(
|
||||
FILES
|
||||
${OpenSCAD_SRCS}
|
||||
DESTINATION
|
||||
Mod/OpenSCAD
|
||||
)
|
26
src/Mod/OpenSCAD/Init.py
Normal file
26
src/Mod/OpenSCAD/Init.py
Normal file
|
@ -0,0 +1,26 @@
|
|||
# FreeCAD init script of the OpenSCAD module
|
||||
# (c) 2001 Juergen Riegel
|
||||
|
||||
#***************************************************************************
|
||||
#* (c) Juergen Riegel (juergen.riegel@web.de) 2002 *
|
||||
#* *
|
||||
#* This file is part of the FreeCAD CAx development system. *
|
||||
#* *
|
||||
#* This program is free software; you can redistribute it and/or modify *
|
||||
#* it under the terms of the GNU Lesser General Public License (LGPL) *
|
||||
#* as published by the Free Software Foundation; either version 2 of *
|
||||
#* the License, or (at your option) any later version. *
|
||||
#* for detail see the LICENCE text file. *
|
||||
#* *
|
||||
#* FreeCAD is distributed in the hope that it will be useful, *
|
||||
#* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
#* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
#* GNU Lesser General Public License for more details. *
|
||||
#* *
|
||||
#* You should have received a copy of the GNU Library General Public *
|
||||
#* License along with FreeCAD; if not, write to the Free Software *
|
||||
#* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
#* USA *
|
||||
#* *
|
||||
#* Juergen Riegel 2002 *
|
||||
#***************************************************************************/
|
129
src/Mod/OpenSCAD/InitGui.py
Normal file
129
src/Mod/OpenSCAD/InitGui.py
Normal file
|
@ -0,0 +1,129 @@
|
|||
# OpenSCAD gui init module
|
||||
#
|
||||
# Gathering all the information to start FreeCAD
|
||||
# This is the second one of three init scripts, the third one
|
||||
# runs when the gui is up
|
||||
|
||||
#***************************************************************************
|
||||
#* (c) Juergen Riegel (juergen.riegel@web.de) 2002
|
||||
#* *
|
||||
#* This file is part of the FreeCAD CAx development system. *
|
||||
#* *
|
||||
#* This program is free software; you can redistribute it and/or modify *
|
||||
#* it under the terms of the GNU General Public License (GPL) *
|
||||
#* as published by the Free Software Foundation; either version 2 of *
|
||||
#* the License, or (at your option) any later version. *
|
||||
#* for detail see the LICENCE text file. *
|
||||
#* *
|
||||
#* FreeCAD is distributed in the hope that it will be useful, *
|
||||
#* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
#* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
#* GNU Library General Public License for more details. *
|
||||
#* *
|
||||
#* You should have received a copy of the GNU Library General Public *
|
||||
#* License along with FreeCAD; if not, write to the Free Software *
|
||||
#* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
#* USA *
|
||||
#* *
|
||||
#* Juergen Riegel 2002 *
|
||||
#***************************************************************************/
|
||||
|
||||
import FreeCAD
|
||||
param = FreeCAD.ParamGet(\
|
||||
"User parameter:BaseApp/Preferences/Mod/OpenSCAD")
|
||||
openscadfilename = param.GetString('openscadexecutable')
|
||||
|
||||
|
||||
class OpenSCADWorkbench ( Workbench ):
|
||||
"OpenSCAD workbench object"
|
||||
Icon = """
|
||||
/* XPM */
|
||||
static char * openscadlogo_xpm[] = {
|
||||
"16 16 33 1",
|
||||
" c None",
|
||||
". c #61320B",
|
||||
"+ c #5D420B",
|
||||
"@ c #4F4C09",
|
||||
"# c #564930",
|
||||
"$ c #754513",
|
||||
"% c #815106",
|
||||
"& c #666509",
|
||||
"* c #875F55",
|
||||
"= c #6E7000",
|
||||
"- c #756A53",
|
||||
"; c #717037",
|
||||
"> c #946637",
|
||||
", c #92710E",
|
||||
"' c #797A0A",
|
||||
") c #7C7720",
|
||||
"! c #8A8603",
|
||||
"~ c #88886F",
|
||||
"{ c #AF8181",
|
||||
"] c #999908",
|
||||
"^ c #BB8D8D",
|
||||
"/ c #AAAA00",
|
||||
"( c #A9A880",
|
||||
"_ c #B5B419",
|
||||
": c #C1A9A9",
|
||||
"< c #B1B19A",
|
||||
"[ c #BEBE00",
|
||||
"} c #B9B8B4",
|
||||
"| c #CACC00",
|
||||
"1 c #D4D4BC",
|
||||
"2 c #DBD2D0",
|
||||
"3 c #EEEEED",
|
||||
"4 c None",
|
||||
"4444444444444444",
|
||||
"4444443113444444",
|
||||
"4444<;']]!;<^^24",
|
||||
"444(&@!]]]=&#^{3",
|
||||
"44<']')@++)!&*{^",
|
||||
"44)]/[|//[/]'@{{",
|
||||
"42=/_|||||[]!&*{",
|
||||
"4(&][|||||[/'@#}",
|
||||
"3-..,|||||[)&&~4",
|
||||
"^*$%.!|||[!+/](4",
|
||||
"^{%%%._[[_&/[_14",
|
||||
":{>%%.!//])_[_44",
|
||||
"2{{%%+!]!!)]]344",
|
||||
"4:{{#@&=&&@#3444",
|
||||
"44224}~--~}44444",
|
||||
"4444444444444444"};
|
||||
"""
|
||||
MenuText = "OpenSCAD"
|
||||
ToolTip = "OpenSCAD workbench"
|
||||
def Initialize(self):
|
||||
import OpenSCAD_rc,OpenSCADCommands
|
||||
commands=["ColorCodeShape",'RefineShapeFeature','ReplaceObject',"Edgestofaces",'ExpandPlacements','RemoveSubtree']
|
||||
import FreeCAD
|
||||
param = FreeCAD.ParamGet(\
|
||||
"User parameter:BaseApp/Preferences/Mod/OpenSCAD")
|
||||
openscadfilename = param.GetString('openscadexecutable')
|
||||
if openscadfilename:
|
||||
commands.extend(['AddOpenSCADElement'])
|
||||
self.appendToolbar("OpenSCADTools",["ColorCodeShape",'RefineShapeFeature','ReplaceObject','RemoveSubtree'])
|
||||
self.appendMenu('OpenSCAD',commands)
|
||||
#self.appendMenu('OpenSCAD',["AddOpenSCADElement"])
|
||||
###self.appendCommandbar("&Generic Tools",["ColorCodeShape"])
|
||||
FreeCADGui.addIconPath(":/icons")
|
||||
#FreeCADGui.addLanguagePath(":/translations")
|
||||
FreeCADGui.addPreferencePage(":/ui/openscadprefs-base.ui","OpenSCAD")
|
||||
def GetClassName(self):
|
||||
#return "OpenSCADGui::Workbench"
|
||||
return "Gui::PythonWorkbench"
|
||||
|
||||
|
||||
Gui.addWorkbench(OpenSCADWorkbench())
|
||||
App.addImportType("OpenSCAD CSG Format (*.csg)","importCSG")
|
||||
App.addExportType("OpenSCAD CSG Format (*.csg)","exportCSG")
|
||||
App.addExportType("OpenSCAD Format (*.scad)","exportCSG")
|
||||
import os
|
||||
openscadbin = openscadfilename and os.path.isfile(openscadfilename)
|
||||
if openscadbin:
|
||||
App.addImportType("OpenSCAD Format (*.scad)","importCSG")
|
||||
|
||||
if param.GetBool('debugRegisterPrototype'):
|
||||
App.addImportType("OpenSCAD CSG prototype (*.csg)","prototype") #prototype
|
||||
if openscadbin:
|
||||
App.addImportType("OpenSCAD prototype (*.scad)","prototype") #prototype
|
||||
|
32
src/Mod/OpenSCAD/Makefile.am
Normal file
32
src/Mod/OpenSCAD/Makefile.am
Normal file
|
@ -0,0 +1,32 @@
|
|||
#SUBDIRS=App Gui
|
||||
|
||||
# Change data dir from default ($(prefix)/share) to $(prefix)
|
||||
datadir = $(prefix)/Mod/OpenSCAD
|
||||
data_DATA = \
|
||||
Init.py InitGui.py \
|
||||
OpenSCAD_rc.py \
|
||||
OpenSCAD2Dgeom.py \
|
||||
OpenSCADFeatures.py \
|
||||
OpenSCADUtils.py \
|
||||
OpenSCADCommands.py \
|
||||
exportCSG.py \
|
||||
importCSG.py \
|
||||
prototype.py \
|
||||
tokrules.py \
|
||||
colorcodeshapes.py \
|
||||
expandplacements.py \
|
||||
replaceobj.py
|
||||
|
||||
nobase_data_DATA = \
|
||||
ply/lex.py \
|
||||
ply/README \
|
||||
ply/yacc.py \
|
||||
ply/__init__.py
|
||||
|
||||
|
||||
EXTRA_DIST = \
|
||||
$(data_DATA) $(nobase_data_DATA) \
|
||||
CMakeLists.txt \
|
||||
OpenSCAD.dox \
|
||||
exportVersions.txt \
|
||||
importVersions.txt
|
3
src/Mod/OpenSCAD/OpenSCAD.dox
Normal file
3
src/Mod/OpenSCAD/OpenSCAD.dox
Normal file
|
@ -0,0 +1,3 @@
|
|||
/** \defgroup TEMPLATE OpenSCAD
|
||||
* \ingroup WORKBENCHES */
|
||||
|
460
src/Mod/OpenSCAD/OpenSCAD2Dgeom.py
Normal file
460
src/Mod/OpenSCAD/OpenSCAD2Dgeom.py
Normal file
|
@ -0,0 +1,460 @@
|
|||
#***************************************************************************
|
||||
#* *
|
||||
#* Copyright (c) 2012 Sebastian Hoogen <github@sebastianhoogen.de> *
|
||||
#* *
|
||||
#* This program is free software; you can redistribute it and/or modify *
|
||||
#* it under the terms of the GNU Lesser General Public License (LGPL) *
|
||||
#* as published by the Free Software Foundation; either version 2 of *
|
||||
#* the License, or (at your option) any later version. *
|
||||
#* for detail see the LICENCE text file. *
|
||||
#* *
|
||||
#* This program is distributed in the hope that it will be useful, *
|
||||
#* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
#* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
#* GNU Library General Public License for more details. *
|
||||
#* *
|
||||
#* You should have received a copy of the GNU Library General Public *
|
||||
#* License along with this program; if not, write to the Free Software *
|
||||
#* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
#* USA *
|
||||
#* *
|
||||
#***************************************************************************
|
||||
|
||||
__title__="FreeCAD OpenSCAD Workbench - 2D helper fuctions"
|
||||
__author__ = "Sebastian Hoogen"
|
||||
__url__ = ["http://free-cad.sourceforge.net"]
|
||||
|
||||
'''
|
||||
This Script includes python functions to convert imported dxf geometry to Faces
|
||||
'''
|
||||
|
||||
class Overlappingfaces():
|
||||
'''combines overlapping faces together'''
|
||||
def __init__(self,facelist):
|
||||
self.sortedfaces = sorted(facelist,key=(lambda shape: shape.Area),reverse=True)
|
||||
self.builddepdict()
|
||||
#self.faceindex = {}
|
||||
#for idx,face in enumerate(self.sortesfaces):
|
||||
# self.faceindex[face.hashCode()] = idx
|
||||
|
||||
# def __len__(self):
|
||||
# return len(self.sortedfaces)
|
||||
|
||||
@staticmethod
|
||||
def dofacesoverlapboundbox(bigface,smallface):
|
||||
return bigface.BoundBox.isIntersection(smallface.BoundBox)
|
||||
|
||||
@staticmethod
|
||||
def dofacesoverlapallverts(bigface,smallface):
|
||||
def vertsinface(f1,verts,tol=0.001,inface=True):
|
||||
'''check if all given verts are inside shape f1'''
|
||||
return all([f1.isInside(vert.Point,tol,inface) for vert in verts])
|
||||
return vertsinface(bigface,smallface.Vertexes)
|
||||
|
||||
@staticmethod
|
||||
def dofacesoverlapboolean(bigface,smallface):
|
||||
#import FreeCAD,FreeCADGui
|
||||
#FreeCAD.Console.PrintLog('intersecting %d %d\n'%(bigfacei,smallfacei))
|
||||
#FreeCADGui.updateGui()
|
||||
return bigface.common(smallface).Area > 0
|
||||
|
||||
def builddepdict(self):
|
||||
import itertools
|
||||
#isinsidelist = []
|
||||
self.isinsidedict = {}
|
||||
#for bigface, smallface in itertools.combinations(sortedfaces,2):
|
||||
for bigfacei, smallfacei in itertools.combinations(range(len(self.sortedfaces)),2):
|
||||
try:
|
||||
overlap = Overlappingfaces.dofacesoverlapboolean(\
|
||||
self.sortedfaces[bigfacei],self.sortedfaces[smallfacei])
|
||||
except:
|
||||
overlap = Overlappingfaces.dofacesoverlapallverts(\
|
||||
self.sortedfaces[bigfacei],self.sortedfaces[smallfacei])
|
||||
if overlap:
|
||||
#isinsidelist.append((bigfacei,smallfacei))
|
||||
smallinbig = self.isinsidedict.get(bigfacei,[])
|
||||
smallinbig.append(smallfacei)
|
||||
if len(smallinbig) == 1:
|
||||
self.isinsidedict[bigfacei] = smallinbig
|
||||
|
||||
@staticmethod
|
||||
def finddepth(dict1,faceidx,curdepth=0):
|
||||
if faceidx not in dict1:
|
||||
return curdepth+1
|
||||
else:
|
||||
#print dict1[faceidx],[(finddepth(dict1,childface,curdepth)) for childface in dict1[faceidx]]
|
||||
return max([(Overlappingfaces.finddepth(dict1,childface,curdepth+1)) for childface in dict1[faceidx]])
|
||||
|
||||
def findrootdepth(self):
|
||||
return max([Overlappingfaces.finddepth(self.isinsidedict,fi) for fi in range(len(self.sortedfaces))])
|
||||
|
||||
def hasnoparent(self,faceindex):
|
||||
return Overlappingfaces.hasnoparentstatic(self.isinsidedict,faceindex)
|
||||
|
||||
@staticmethod
|
||||
def hasnoparentstatic(isinsidedict,faceindex):
|
||||
for smalllist in isinsidedict.itervalues():
|
||||
if faceindex in smalllist:
|
||||
return False
|
||||
return True
|
||||
|
||||
#@staticmethod
|
||||
#def subtreedict(rootface,parantdict):
|
||||
# '''biuld a subtree dictinary'''
|
||||
# newdict = parantdict.copy()
|
||||
# del newdict[rootface]
|
||||
# return newdict
|
||||
|
||||
@staticmethod
|
||||
def directchildren(isinsidedict,parent):
|
||||
#return [child for child in isinsidedict.get(parent,[]) if child not in isinsidedict]
|
||||
dchildren=[]
|
||||
for child in isinsidedict.get(parent,[]):
|
||||
direct = True
|
||||
for key, value in isinsidedict.iteritems():
|
||||
if key != parent and child in value and parent not in value:
|
||||
direct = False
|
||||
if direct:
|
||||
dchildren.append(child)
|
||||
return dchildren
|
||||
|
||||
#@staticmethod
|
||||
#def indirectchildren(isinsidedict,parent):
|
||||
# return [child for child in isinsidedict.get(parent,[]) if child in isinsidedict]
|
||||
|
||||
@staticmethod
|
||||
def printtree(isinsidedict,facenum):
|
||||
def printtreechild(isinsidedict,facenum,parent):
|
||||
children=Overlappingfaces.directchildren(isinsidedict,parent)
|
||||
print 'parent %d directchild %s' % (parent,children)
|
||||
if children:
|
||||
subdict=isinsidedict.copy()
|
||||
del subdict[parent]
|
||||
for child in children:
|
||||
printtreechild(subdict,facenum,child)
|
||||
|
||||
rootitems=[fi for fi in range(facenum) if Overlappingfaces.hasnoparentstatic(isinsidedict,fi)]
|
||||
for rootitem in rootitems:
|
||||
printtreechild(isinsidedict,facenum,rootitem)
|
||||
|
||||
def makefeatures(self,doc):
|
||||
import FreeCAD
|
||||
def addshape(faceindex):
|
||||
obj=doc.addObject('Part::Feature','facefromedges_%d' % faceindex)
|
||||
obj.Shape = self.sortedfaces[faceindex]
|
||||
obj.ViewObject.hide()
|
||||
return obj
|
||||
|
||||
def addfeature(faceindex,isinsidedict):
|
||||
directchildren = Overlappingfaces.directchildren(isinsidedict,faceindex)
|
||||
if len(directchildren) == 0:
|
||||
obj=addshape(faceindex)
|
||||
else:
|
||||
subdict=isinsidedict.copy()
|
||||
del subdict[faceindex]
|
||||
obj=doc.addObject("Part::Cut","facesfromedges_%d" % faceindex)
|
||||
obj.Base= addshape(faceindex) #we only do subtraction
|
||||
if len(directchildren) == 1:
|
||||
obj.Tool = addfeature(directchildren[0],subdict)
|
||||
else:
|
||||
obj.Tool = doc.addObject("Part::MultiFuse","facesfromedges_union")
|
||||
obj.Tool.Shapes = [addfeature(child,subdict) for child in directchildren]
|
||||
obj.Tool.ViewObject.hide()
|
||||
obj.ViewObject.hide()
|
||||
return obj
|
||||
|
||||
rootitems = [fi for fi in range(len(self.sortedfaces)) if self.hasnoparent(fi)]
|
||||
for rootitem in rootitems:
|
||||
addfeature(rootitem,self.isinsidedict).ViewObject.show()
|
||||
|
||||
|
||||
def makeshape(self):
|
||||
def removefaces(rfaces):
|
||||
for tfi in directchildren[::-1]:
|
||||
finishedwith.append(tfi)
|
||||
#del faces[tfi]
|
||||
if tfi in isinsidedict:
|
||||
del isinsidedict[tfi]
|
||||
for key,value in isinsidedict.iteritems():
|
||||
if tfi in value:
|
||||
newlist=value[:] #we work on a shallow copy of isinsidedict
|
||||
newlist.remove(tfi)
|
||||
isinsidedict[key]=newlist
|
||||
|
||||
def hasnoparent(faceindex):
|
||||
for smalllist in self.isinsidedict.itervalues():
|
||||
if faceindex in smalllist:
|
||||
return False
|
||||
return True
|
||||
|
||||
faces=self.sortedfaces[:]
|
||||
isinsidedict=self.isinsidedict.copy()
|
||||
finishedwith=[]
|
||||
while not all([Overlappingfaces.hasnoparentstatic(isinsidedict,fi) for fi in range(len(faces))]):
|
||||
#print [(Overlappingfaces.hasnoparentstatic(isinsidedict,fi),\
|
||||
#Overlappingfaces.directchildren(isinsidedict,fi)) for fi in range(len(faces))]
|
||||
for fi in range(len(faces))[::-1]:
|
||||
directchildren = Overlappingfaces.directchildren(isinsidedict,fi)
|
||||
if not directchildren:
|
||||
continue
|
||||
elif len(directchildren) == 1:
|
||||
faces[fi]=faces[fi].cut(faces[directchildren[0]])
|
||||
#print fi,'-' ,directchildren[0], faces[fi],faces[directchildren[0]]
|
||||
removefaces(directchildren)
|
||||
else:
|
||||
toolface=fusefaces([faces[tfi] for tfi in directchildren])
|
||||
faces[fi]=faces[fi].cut(toolface)
|
||||
#print fi, '- ()', directchildren, [faces[tfi] for tfi in directchildren]
|
||||
removefaces(directchildren)
|
||||
#print fi,directchildren
|
||||
faces =[face for index,face in enumerate(faces) if index not in finishedwith]
|
||||
# return faces
|
||||
return fusefaces(faces)
|
||||
|
||||
def findConnectedEdges(edgelist,eps=1e-6,debug=False):
|
||||
'''returns a list of list of connected edges'''
|
||||
|
||||
def vertequals(v1,v2,eps=1e-6):
|
||||
'''check two vertices for equality'''
|
||||
#return all([abs(c1-c2)<eps for c1,c2 in zip(v1.Point,v2.Point)])
|
||||
return v1.Point.sub(v2.Point).Length<eps
|
||||
|
||||
def vertindex(forward):
|
||||
'''return index of last or first element'''
|
||||
return -1 if forward else 0
|
||||
|
||||
freeedges = edgelist[:]
|
||||
retlist = []
|
||||
debuglist = []
|
||||
while freeedges:
|
||||
startwire = freeedges.pop(0)
|
||||
forward = True
|
||||
newedge = [(startwire,True)]
|
||||
for forward in (True, False):
|
||||
found = True
|
||||
while found:
|
||||
lastvert = newedge[vertindex(forward)][0].Vertexes[vertindex(forward == newedge[vertindex(forward)][1])]
|
||||
for ceindex, checkedge in enumerate(freeedges):
|
||||
found = False
|
||||
for cvindex, cvert in enumerate([checkedge.Vertexes[0],checkedge.Vertexes[-1]]):
|
||||
if vertequals(lastvert,cvert,eps):
|
||||
if forward:
|
||||
newedge.append((checkedge,cvindex == 0))
|
||||
else:
|
||||
newedge.insert(0,(checkedge,cvindex == 1))
|
||||
del freeedges[ceindex]
|
||||
found = True
|
||||
break
|
||||
else:
|
||||
found = False
|
||||
if found:
|
||||
break
|
||||
else:
|
||||
found = False
|
||||
#we are finished for this edge
|
||||
debuglist.append(newedge)
|
||||
retlist.append([item[0] for item in newedge]) #strip off direction
|
||||
#print debuglist
|
||||
if debug:
|
||||
return retlist,debuglist
|
||||
else:
|
||||
return retlist
|
||||
|
||||
def endpointdistance(edges):
|
||||
'''return the distance of of vertices in path (list of edges) as
|
||||
maximum, mininum and distance between start and endpoint
|
||||
it expects the edges to be traversed forward from starting from Vertex 0'''
|
||||
numedges=len(edges)
|
||||
if numedges == 1 and len(edges[0].Vertexes) == 1:
|
||||
return 0.0,0.0,0.0
|
||||
outerdistance = edges[0].Vertexes[0].Point.sub(\
|
||||
edges[-1].Vertexes[-1].Point).Length
|
||||
if numedges > 1:
|
||||
innerdistances=[edges[i].Vertexes[-1].Point.sub(edges[i+1].\
|
||||
Vertexes[0].Point).Length for i in range(numedges-1)]
|
||||
return max(innerdistances),min(innerdistances),outerdistance
|
||||
else:
|
||||
return 0.0,0.0,outerdistance
|
||||
|
||||
def endpointdistancedebuglist(debuglist):
|
||||
'''return the distance of of vertices in path (list of edges) as
|
||||
maximum, mininum and distance between start and endpoint
|
||||
it it expects a 'not reversed' flag for every edge'''
|
||||
numedges=len(debuglist)
|
||||
if numedges == 1 and len(debuglist[0][0].Vertexes) == 1:
|
||||
return 0.0,0.0,0.0
|
||||
outerdistance = debuglist[0][0].Vertexes[(not debuglist[0][1])*-1].\
|
||||
Point.sub(debuglist[-1][0].Vertexes[(debuglist[-1][1])*-1].\
|
||||
Point).Length
|
||||
if numedges > 1:
|
||||
innerdistances=[debuglist[i][0].Vertexes[debuglist[i][1]*-1].\
|
||||
Point.sub(debuglist[i+1][0].Vertexes[(not debuglist[i+1][1])*\
|
||||
-1].Point).Length for i in range(numedges-1)]
|
||||
return max(innerdistances),min(innerdistances),outerdistance
|
||||
else:
|
||||
return 0.0,0.0,outerdistance
|
||||
|
||||
def edgestowires(edgelist,eps=0.001):
|
||||
'''takes list of edges and returns a list of wires'''
|
||||
import Part, Draft
|
||||
# todo remove double edges
|
||||
wirelist=[]
|
||||
#for path in findConnectedEdges(edgelist,eps=eps):
|
||||
for path,debug in zip(*findConnectedEdges(edgelist,eps=eps,debug=True)):
|
||||
maxd,mind,outerd = endpointdistancedebuglist(debug)
|
||||
assert(maxd <= eps*2) # Assume the input to be broken
|
||||
if maxd < eps*2 and maxd > 0.000001: #OCC wont like it if maxd > 0.02:
|
||||
print 'endpointdistance max:%f min:%f, ends:%f' %(maxd,mind,outerd)
|
||||
|
||||
if True:
|
||||
tobeclosed = outerd < eps*2
|
||||
# OpenSCAD uses 0.001 for corase grid
|
||||
#from draftlibs import fcvec, fcgeo
|
||||
#w2=fcgeo.superWire(path,tobeclosed)
|
||||
w2=superWireReverse(debug,tobeclosed)
|
||||
wirelist.append(w2)
|
||||
else:#this locks up FreeCAD
|
||||
comp=Part.Compound(path)
|
||||
wirelist.append(comp.connectEdgesToWires(False,eps).Wires[0])
|
||||
#wirelist.append(comp.connectEdgesToWires(False,0.1).Wires[0])
|
||||
else:
|
||||
done = False
|
||||
try:
|
||||
wire=Part.Wire(path)
|
||||
#if not close or wire.isClosed or outerd > 0.0001:
|
||||
wirelist.append(Part.Wire(path))
|
||||
done = True
|
||||
except:
|
||||
pass
|
||||
if not done:
|
||||
comp=Part.Compound(path)
|
||||
wirelist.append(comp.connectEdgesToWires(False,eps).Wires[0])
|
||||
return wirelist
|
||||
|
||||
def subtractfaces(faces):
|
||||
'''searches for the biggest face and subtracts all smaller ones from the
|
||||
first. Only makes sense if all faces overlap.'''
|
||||
if len(faces)==1:
|
||||
return faces[0]
|
||||
else:
|
||||
facelist=sorted(faces,key=(lambda shape: shape.Area),reverse=True)
|
||||
base=facelist[0]
|
||||
tool=reduce(lambda p1,p2: p1.fuse(p2),facelist[1:])
|
||||
return base.cut(tool)
|
||||
|
||||
def fusefaces(faces):
|
||||
if len(faces)==1:
|
||||
return faces[0]
|
||||
else:
|
||||
return reduce(lambda p1,p2: p1.fuse(p2),faces)
|
||||
|
||||
def subtractfaces2(faces):
|
||||
'''Sort faces, check if they overlap. Subtract overlapping face and fuse
|
||||
nonoverlapping groups.'''
|
||||
return fusefaces([subtractfaces(facegroup) for facegroup in findoverlappingfaces(faces)])
|
||||
|
||||
def edgestofaces(edges,algo=3,eps=0.001):
|
||||
#edges=[]
|
||||
#for shapeobj in (objs):
|
||||
# edges.extend(shapeobj.Shape.Edges)
|
||||
#taken from Drafttools
|
||||
#from draftlibs import fcvec, fcgeo
|
||||
import Part
|
||||
#wires = fcgeo.findWires(edges)
|
||||
wires = edgestowires(edges,eps)
|
||||
facel=[]
|
||||
for w in wires:
|
||||
#assert(len(w.Edges)>1)
|
||||
if not w.isClosed():
|
||||
p0 = w.Vertexes[0].Point
|
||||
p1 = w.Vertexes[-1].Point
|
||||
edges2 = w.Edges[:]
|
||||
try:
|
||||
edges2.append(Part.Line(p1,p0).toShape())
|
||||
w = Part.Wire(edges2)
|
||||
#w = Part.Wire(fcgeo.sortEdges(edges2))
|
||||
except:
|
||||
comp=Part.Compound(edges2)
|
||||
w = comp.connectEdgesToWires(False,eps).Wires[0]
|
||||
facel.append(Part.Face(w))
|
||||
#if w.isValid: #debuging
|
||||
# facel.append(Part.Face(w))
|
||||
#else:
|
||||
# Part.show(w)
|
||||
if algo is None:
|
||||
return facel
|
||||
elif algo == 1: #stabale behavior
|
||||
return subtractfaces(facel)
|
||||
elif algo == 0: #return all faces
|
||||
return Part.Compound(facel)
|
||||
elif algo == 2:
|
||||
return subtractfaces2(facel)
|
||||
elif algo == 3:
|
||||
return Overlappingfaces(facel).makeshape()
|
||||
|
||||
def superWireReverse(debuglist,closed=False):
|
||||
'''superWireReverse(debuglist,[closed]): forces a wire between edges
|
||||
that don't necessarily have coincident endpoints. If closed=True, wire
|
||||
will always be closed. debuglist has a tuple for every edge.The first
|
||||
entry is the edge, the second is the flag 'does not nedd to be inverted'
|
||||
'''
|
||||
#taken from draftlibs
|
||||
def median(v1,v2):
|
||||
vd = v2.sub(v1)
|
||||
vd.scale(.5,.5,.5)
|
||||
return v1.add(vd)
|
||||
try:
|
||||
from DraftGeomUtils import findMidpoint
|
||||
except ImportError: #workaround for Version 0.12
|
||||
from draftlibs.fcgeo import findMidpoint #workaround for Version 0.12
|
||||
import Part
|
||||
#edges = sortEdges(edgeslist)
|
||||
print debuglist
|
||||
newedges = []
|
||||
for i in range(len(debuglist)):
|
||||
curr = debuglist[i]
|
||||
if i == 0:
|
||||
if closed:
|
||||
prev = debuglist[-1]
|
||||
else:
|
||||
prev = None
|
||||
else:
|
||||
prev = debuglist[i-1]
|
||||
if i == (len(debuglist)-1):
|
||||
if closed:
|
||||
nexte = debuglist[0]
|
||||
else:
|
||||
nexte = None
|
||||
else:
|
||||
nexte = debuglist[i+1]
|
||||
print i,prev,curr,nexte
|
||||
if prev:
|
||||
if curr[0].Vertexes[-1*(not curr[1])].Point == \
|
||||
prev[0].Vertexes[-1*prev[1]].Point:
|
||||
p1 = curr[0].Vertexes[-1*(not curr[1])].Point
|
||||
else:
|
||||
p1 = median(curr[0].Vertexes[-1*(not curr[1])].Point,\
|
||||
prev[0].Vertexes[-1*prev[1]].Point)
|
||||
else:
|
||||
p1 = curr[0].Vertexes[-1*(not curr[1])].Point
|
||||
if nexte:
|
||||
if curr[0].Vertexes[-1*curr[1]].Point == \
|
||||
nexte[0].Vertexes[-1*(not nexte[1])].Point:
|
||||
p2 = nexte[0].Vertexes[-1*(not nexte[1])].Point
|
||||
else:
|
||||
p2 = median(curr[0].Vertexes[-1*(curr[1])].Point,\
|
||||
nexte[0].Vertexes[-1*(not nexte[1])].Point)
|
||||
else:
|
||||
p2 = curr[0].Vertexes[-1*(curr[1])].Point
|
||||
if isinstance(curr[0].Curve,Part.Line):
|
||||
print "line",p1,p2
|
||||
newedges.append(Part.Line(p1,p2).toShape())
|
||||
elif isinstance(curr[0].Curve,Part.Circle):
|
||||
p3 = findMidpoint(curr[0])
|
||||
print "arc",p1,p3,p2
|
||||
newedges.append(Part.Arc(p1,p3,p2).toShape())
|
||||
else:
|
||||
print "Cannot superWire edges that are not lines or arcs"
|
||||
return None
|
||||
print newedges
|
||||
return Part.Wire(newedges)
|
173
src/Mod/OpenSCAD/OpenSCADCommands.py
Normal file
173
src/Mod/OpenSCAD/OpenSCADCommands.py
Normal file
|
@ -0,0 +1,173 @@
|
|||
import FreeCAD,FreeCADGui
|
||||
from PyQt4 import QtGui, QtCore
|
||||
|
||||
class ColorCodeShape:
|
||||
"Change the Color of selected or all Shapes based on their validity"
|
||||
def Activated(self):
|
||||
import colorcodeshapes
|
||||
selection=FreeCADGui.Selection.getSelectionEx()
|
||||
if len(selection) > 0:
|
||||
objs=[selobj.Object for selobj in selection]
|
||||
|
||||
else:
|
||||
objs=FreeCAD.ActiveDocument.Objects
|
||||
colorcodeshapes.colorcodeshapes(objs)
|
||||
def GetResources(self):
|
||||
return {'Pixmap' : 'OpenSCAD_ColorCodeShape', 'MenuText': 'Color Shapes', 'ToolTip': 'Color Shapes by validity and type'}
|
||||
|
||||
class Edgestofaces:
|
||||
def Activated(self):
|
||||
from OpenSCAD2Dgeom import edgestofaces,Overlappingfaces
|
||||
selection=FreeCADGui.Selection.getSelectionEx()
|
||||
edges=[]
|
||||
for selobj in selection:
|
||||
edges.extend(selobj.Object.Shape.Edges)
|
||||
Overlappingfaces(edgestofaces(edges,None)).makefeatures(FreeCAD.ActiveDocument)
|
||||
for selobj in selection:
|
||||
selobj.Object.ViewObject.hide()
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
|
||||
def GetResources(self):
|
||||
return {'Pixmap' : 'python', 'MenuText': 'EdgesToFaces', 'ToolTip': 'Convert Edges to Faces'}
|
||||
|
||||
class RefineShapeFeature:
|
||||
def Activated(self):
|
||||
import Part,OpenSCADFeatures
|
||||
selection=FreeCADGui.Selection.getSelectionEx()
|
||||
for selobj in selection:
|
||||
#newobj=FreeCAD.ActiveDocument.addObject("Part::FeaturePython",'refine')
|
||||
newobj=selobj.Document.addObject("Part::FeaturePython",'refine')
|
||||
OpenSCADFeatures.RefineShape(newobj,selobj.Object)
|
||||
OpenSCADFeatures.ViewProviderTree(newobj.ViewObject)
|
||||
newobj.Label='refine_%s' % selobj.Object.Label
|
||||
selobj.Object.ViewObject.hide()
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
def GetResources(self):
|
||||
return {'Pixmap' : 'OpenSCAD_RefineShapeFeature', 'MenuText': \
|
||||
'Refine Shape Feature', 'ToolTip': 'Create Refine Shape Feature'}
|
||||
|
||||
|
||||
class ExpandPlacements:
|
||||
'''This should aid interactive repair in the future
|
||||
but currently it breaks extrusions, as axis, base and so on have to be
|
||||
recalculated'''
|
||||
def Activated(self):
|
||||
import expandplacements
|
||||
selobj=FreeCADGui.Selection.getSelectionEx()[0]
|
||||
expandplacements.expandplacements(selobj.Object,FreeCAD.Placement())
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
def GetResources(self):
|
||||
return {'Pixmap' : 'python', 'MenuText': 'Expand Placements', 'ToolTip': 'Expand all placements downwards the FeatureTree'}
|
||||
|
||||
class ReplaceObject:
|
||||
def Activated(self):
|
||||
import replaceobj
|
||||
#objs=[selobj.Object for selobj in FreeCADGui.Selection.getSelectionEx()]
|
||||
objs=FreeCADGui.Selection.getSelection()
|
||||
if len(objs)==3:
|
||||
replaceobj.replaceobjfromselection(objs)
|
||||
else:
|
||||
FreeCAD.Console.PrintError('please select 3 objects first')
|
||||
def GetResources(self):
|
||||
return {'Pixmap' : 'OpenSCAD_ReplaceObject', 'MenuText': \
|
||||
'Replace Object', 'ToolTip': \
|
||||
'Replace an object in the Feature Tree select old, new and parent object'}
|
||||
|
||||
|
||||
class RemoveSubtree:
|
||||
def Activated(self):
|
||||
def addsubobjs(obj,toremoveset):
|
||||
toremove.add(obj)
|
||||
for subobj in obj.OutList:
|
||||
addsubobjs(subobj,toremoveset)
|
||||
|
||||
import FreeCAD,FreeCADGui
|
||||
objs=FreeCADGui.Selection.getSelection()
|
||||
toremove=set()
|
||||
for obj in objs:
|
||||
addsubobjs(obj,toremove)
|
||||
checkinlistcomplete =False
|
||||
while not checkinlistcomplete:
|
||||
for obj in toremove:
|
||||
if (obj not in objs) and (frozenset(obj.InList) - toremove):
|
||||
toremove.remove(obj)
|
||||
break
|
||||
else:
|
||||
checkinlistcomplete = True
|
||||
for obj in toremove:
|
||||
obj.Document.removeObject(obj.Name)
|
||||
def GetResources(self):
|
||||
return {'Pixmap' : 'OpenSCAD_RemoveSubtree', 'MenuText': \
|
||||
'Remove Objects and thier Children', 'ToolTip': \
|
||||
'Removes the selected Objects and all Children that are not referenced from other objects'}
|
||||
|
||||
class AddSCADWidget(QtGui.QWidget):
|
||||
def __init__(self,*args):
|
||||
QtGui.QWidget.__init__(self,*args)
|
||||
self.textEdit=QtGui.QTextEdit()
|
||||
self.buttonadd = QtGui.QPushButton(u'Add')
|
||||
self.buttonclear = QtGui.QPushButton(u'Clear')
|
||||
self.checkboxmesh = QtGui.QCheckBox(u'as Mesh')
|
||||
layouth=QtGui.QHBoxLayout()
|
||||
layouth.addWidget(self.buttonadd)
|
||||
layouth.addWidget(self.buttonclear)
|
||||
layout= QtGui.QVBoxLayout()
|
||||
layout.addLayout(layouth)
|
||||
layout.addWidget(self.checkboxmesh)
|
||||
layout.addWidget(self.textEdit)
|
||||
self.setLayout(layout)
|
||||
self.setWindowTitle(u'Add OpenSCAD Element')
|
||||
self.textEdit.setText(u'cube();')
|
||||
self.buttonclear.clicked.connect(self.textEdit.clear)
|
||||
|
||||
class AddSCADTask:
|
||||
def __init__(self):
|
||||
self.form = AddSCADWidget()
|
||||
self.form.buttonadd.clicked.connect(self.addelement)
|
||||
def getStandardButtons(self):
|
||||
return int(QtGui.QDialogButtonBox.Close)
|
||||
|
||||
def isAllowedAlterSelection(self):
|
||||
return True
|
||||
|
||||
def isAllowedAlterView(self):
|
||||
return True
|
||||
|
||||
def isAllowedAlterDocument(self):
|
||||
return True
|
||||
|
||||
def addelement(self):
|
||||
scadstr=unicode(self.form.textEdit.toPlainText())
|
||||
asmesh=self.form.checkboxmesh.checkState()
|
||||
import OpenSCADUtils, os
|
||||
extension= 'stl' if asmesh else 'csg'
|
||||
tmpfilename=OpenSCADUtils.callopenscadstring(scadstr,extension)
|
||||
if tmpfilename:
|
||||
doc=FreeCAD.activeDocument() or FreeCAD.newDocument()
|
||||
if asmesh:
|
||||
import Mesh
|
||||
Mesh.insert(tmpfilename,doc.Name)
|
||||
else:
|
||||
import importCSG
|
||||
importCSG.insert(tmpfilename,doc.Name)
|
||||
os.unlink(tmpfilename)
|
||||
else:
|
||||
FreeCAD.Console.PrintError('Running OpenSCAD failed\n')
|
||||
|
||||
class AddOpenSCADElement:
|
||||
def Activated(self):
|
||||
panel = AddSCADTask()
|
||||
FreeCADGui.Control.showDialog(panel)
|
||||
def GetResources(self):
|
||||
return {'Pixmap' : 'python', 'MenuText': \
|
||||
'Add OpenSCAD Element...', 'ToolTip': \
|
||||
'Add an OpenSCAD Element by entering OpenSCAD Code and executing the OpenSCAD binary'}
|
||||
|
||||
|
||||
FreeCADGui.addCommand('ColorCodeShape',ColorCodeShape())
|
||||
FreeCADGui.addCommand('Edgestofaces',Edgestofaces())
|
||||
FreeCADGui.addCommand('RefineShapeFeature',RefineShapeFeature())
|
||||
FreeCADGui.addCommand('ExpandPlacements',ExpandPlacements())
|
||||
FreeCADGui.addCommand('ReplaceObject',ReplaceObject())
|
||||
FreeCADGui.addCommand('RemoveSubtree',RemoveSubtree())
|
||||
FreeCADGui.addCommand('AddOpenSCADElement',AddOpenSCADElement())
|
433
src/Mod/OpenSCAD/OpenSCADFeatures.py
Normal file
433
src/Mod/OpenSCAD/OpenSCADFeatures.py
Normal file
|
@ -0,0 +1,433 @@
|
|||
#***************************************************************************
|
||||
#* *
|
||||
#* Copyright (c) 2012 Sebastian Hoogen <github@sebastianhoogen.de> *
|
||||
#* *
|
||||
#* This program is free software; you can redistribute it and/or modify *
|
||||
#* it under the terms of the GNU Lesser General Public License (LGPL) *
|
||||
#* as published by the Free Software Foundation; either version 2 of *
|
||||
#* the License, or (at your option) any later version. *
|
||||
#* for detail see the LICENCE text file. *
|
||||
#* *
|
||||
#* This program is distributed in the hope that it will be useful, *
|
||||
#* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
#* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
#* GNU Library General Public License for more details. *
|
||||
#* *
|
||||
#* You should have received a copy of the GNU Library General Public *
|
||||
#* License along with this program; if not, write to the Free Software *
|
||||
#* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
#* USA *
|
||||
#* *
|
||||
#***************************************************************************
|
||||
|
||||
__title__="FreeCAD OpenSCAD Workbench - Parametric Features"
|
||||
__author__ = "Sebastian Hoogen"
|
||||
__url__ = ["http://free-cad.sourceforge.net"]
|
||||
|
||||
'''
|
||||
This Script includes python Features to represent OpenSCAD Operations
|
||||
'''
|
||||
class ViewProviderTree:
|
||||
"A generic View Provider for Elements with Children"
|
||||
|
||||
def __init__(self, obj):
|
||||
obj.Proxy = self
|
||||
self.Object = obj.Object
|
||||
|
||||
def attach(self, obj):
|
||||
self.Object = obj.Object
|
||||
return
|
||||
|
||||
def updateData(self, fp, prop):
|
||||
return
|
||||
|
||||
def getDisplayModes(self,obj):
|
||||
modes=[]
|
||||
return modes
|
||||
|
||||
def setDisplayMode(self,mode):
|
||||
return mode
|
||||
|
||||
def onChanged(self, vp, prop):
|
||||
return
|
||||
|
||||
def __getstate__(self):
|
||||
# return {'ObjectName' : self.Object.Name}
|
||||
return None
|
||||
|
||||
def __setstate__(self,state):
|
||||
if state is not None:
|
||||
try:
|
||||
import FreeCAD
|
||||
doc = FreeCAD.ActiveDocument #crap
|
||||
self.Object = doc.getObject(state['ObjectName'])
|
||||
except:
|
||||
raise
|
||||
# return None
|
||||
|
||||
def claimChildren(self):
|
||||
objs = []
|
||||
if hasattr(self.Object.Proxy,"Base"):
|
||||
objs.append(self.Object.Proxy.Base)
|
||||
if hasattr(self.Object,"Base"):
|
||||
objs.append(self.Object.Base)
|
||||
if hasattr(self.Object,"Objects"):
|
||||
objs.extend(self.Object.Objects)
|
||||
if hasattr(self.Object,"Components"):
|
||||
objs.extend(self.Object.Components)
|
||||
return objs
|
||||
|
||||
def getIcon(self):
|
||||
#if self.Object.Proxy.__class__ == MatrixTransform:
|
||||
if isinstance(self.Object.Proxy,MatrixTransform):
|
||||
return """/* XPM */
|
||||
static char * matrix_xpm[] = {
|
||||
"16 16 3 1",
|
||||
" c #0079FF",
|
||||
". c #FFFFFF",
|
||||
"+ c #000000",
|
||||
" ......... .",
|
||||
" ............. .",
|
||||
" . . . . . .",
|
||||
" . . . . . .",
|
||||
" ............. .",
|
||||
" . . . . . .",
|
||||
" . . . . . .",
|
||||
" ............. .",
|
||||
" . . . . . .",
|
||||
" . . . . . .",
|
||||
" ............. .",
|
||||
" ...........+. .",
|
||||
" ..+..+..+..+. .",
|
||||
" ............. .",
|
||||
" ......... .",
|
||||
"................"};"""
|
||||
elif False:
|
||||
return """/* XPM */
|
||||
static char * qm_xpm[] = {
|
||||
"16 16 37 1",
|
||||
" c None",
|
||||
". c #FFFFFF",
|
||||
"+ c #CBE3FF",
|
||||
"@ c #70B3FF",
|
||||
"# c #3092FF",
|
||||
"$ c #0D7FFF",
|
||||
"% c #047BFF",
|
||||
"& c #1885FF",
|
||||
"* c #56A6FF",
|
||||
"= c #CFE5FF",
|
||||
"- c #0079FF",
|
||||
"; c #067CFF",
|
||||
"> c #B9DAFF",
|
||||
", c #88C0FF",
|
||||
"' c #CAE3FF",
|
||||
") c #F2F8FF",
|
||||
"! c #FAFCFF",
|
||||
"~ c #CEE5FF",
|
||||
"{ c #459DFF",
|
||||
"] c #2D90FF",
|
||||
"^ c #EEF6FF",
|
||||
"/ c #077CFF",
|
||||
"( c #B1D6FF",
|
||||
"_ c #3494FF",
|
||||
": c #90C4FF",
|
||||
"< c #037AFF",
|
||||
"[ c #BCDBFF",
|
||||
"} c #6EB2FF",
|
||||
"| c #087DFF",
|
||||
"1 c #A8D1FF",
|
||||
"2 c #8AC1FF",
|
||||
"3 c #1C87FF",
|
||||
"4 c #CCE4FF",
|
||||
"5 c #1F89FF",
|
||||
"6 c #CDE4FF",
|
||||
"7 c #027AFF",
|
||||
"8 c #FDFDFF",
|
||||
"....+@#$%&*=....",
|
||||
"....-------;>...",
|
||||
"....#,')!~{-]...",
|
||||
"..........^-/...",
|
||||
"..........(-_...",
|
||||
".........:/<[...",
|
||||
"........}-|1....",
|
||||
".......2-34.....",
|
||||
".......5-6......",
|
||||
".......7-8......",
|
||||
".......--.......",
|
||||
"................",
|
||||
"................",
|
||||
".......--.......",
|
||||
".......--.......",
|
||||
".......--......."};
|
||||
"""
|
||||
else:
|
||||
return """/* XPM */
|
||||
static char * openscadlogo_xpm[] = {
|
||||
"16 16 33 1",
|
||||
" c None",
|
||||
". c #61320B",
|
||||
"+ c #5D420B",
|
||||
"@ c #4F4C09",
|
||||
"# c #564930",
|
||||
"$ c #754513",
|
||||
"% c #815106",
|
||||
"& c #666509",
|
||||
"* c #875F55",
|
||||
"= c #6E7000",
|
||||
"- c #756A53",
|
||||
"; c #717037",
|
||||
"> c #946637",
|
||||
", c #92710E",
|
||||
"' c #797A0A",
|
||||
") c #7C7720",
|
||||
"! c #8A8603",
|
||||
"~ c #88886F",
|
||||
"{ c #AF8181",
|
||||
"] c #999908",
|
||||
"^ c #BB8D8D",
|
||||
"/ c #AAAA00",
|
||||
"( c #A9A880",
|
||||
"_ c #B5B419",
|
||||
": c #C1A9A9",
|
||||
"< c #B1B19A",
|
||||
"[ c #BEBE00",
|
||||
"} c #B9B8B4",
|
||||
"| c #CACC00",
|
||||
"1 c #D4D4BC",
|
||||
"2 c #DBD2D0",
|
||||
"3 c #EEEEED",
|
||||
"4 c #FDFFFC",
|
||||
"4444444444444444",
|
||||
"4444443113444444",
|
||||
"4444<;']]!;<^^24",
|
||||
"444(&@!]]]=&#^{3",
|
||||
"44<']')@++)!&*{^",
|
||||
"44)]/[|//[/]'@{{",
|
||||
"42=/_|||||[]!&*{",
|
||||
"4(&][|||||[/'@#}",
|
||||
"3-..,|||||[)&&~4",
|
||||
"^*$%.!|||[!+/](4",
|
||||
"^{%%%._[[_&/[_14",
|
||||
":{>%%.!//])_[_44",
|
||||
"2{{%%+!]!!)]]344",
|
||||
"4:{{#@&=&&@#3444",
|
||||
"44224}~--~}44444",
|
||||
"4444444444444444"};
|
||||
"""
|
||||
|
||||
|
||||
class MatrixTransform:
|
||||
def __init__(self, obj,matrix=None,child=None):
|
||||
obj.addProperty("App::PropertyLink","Base","Base",
|
||||
"The base object that must be tranfsformed")
|
||||
obj.addProperty("App::PropertyMatrix","Matrix","Matrix", "Transformation Matrix")
|
||||
obj.Proxy = self
|
||||
obj.Matrix = matrix
|
||||
obj.Base = child
|
||||
|
||||
def onChanged(self, fp, prop):
|
||||
"Do something when a property has changed"
|
||||
pass
|
||||
|
||||
def updateProperty(self, fp, prop, value):
|
||||
epsilon = 0.0001
|
||||
if abs(getattr(fp, prop) - value) > epsilon:
|
||||
setattr(fp, prop, value)
|
||||
|
||||
def execute(self, fp):
|
||||
pass
|
||||
if fp.Matrix and fp.Base:
|
||||
sh=fp.Base.Shape#.copy()
|
||||
m=sh.Placement.toMatrix().multiply(fp.Matrix)
|
||||
fp.Shape = sh.transformGeometry(m)
|
||||
#else:
|
||||
#FreeCAD.Console.PrintMessage('base %s\nmat %s/n' % (fp.Base,fp.Matrix))
|
||||
|
||||
class ImportObject:
|
||||
def __init__(self, obj,child=None):
|
||||
obj.addProperty("App::PropertyLink","Base","Base",
|
||||
"The base object that must be tranfsformed")
|
||||
obj.Proxy = self
|
||||
obj.Base = child
|
||||
|
||||
def onChanged(self, fp, prop):
|
||||
"Do something when a property has changed"
|
||||
pass
|
||||
|
||||
def execute(self, fp):
|
||||
pass
|
||||
# if fp.Base:
|
||||
# fp.Shape = fp.Base.Shape.copy()
|
||||
|
||||
class RefineShape:
|
||||
'''return a refined shape'''
|
||||
def __init__(self, obj,child=None):
|
||||
obj.addProperty("App::PropertyLink","Base","Base",
|
||||
"The base object that must be refined")
|
||||
obj.Proxy = self
|
||||
obj.Base = child
|
||||
|
||||
def onChanged(self, fp, prop):
|
||||
"Do something when a property has changed"
|
||||
pass
|
||||
|
||||
def execute(self, fp):
|
||||
if fp.Base and fp.Base.Shape.isValid():
|
||||
sh=fp.Base.Shape.removeSplitter()
|
||||
if sh.Placement.isNull():
|
||||
fp.Shape=sh
|
||||
else:
|
||||
fp.Shape=sh.transformGeometry(sh.Placement.toMatrix())
|
||||
|
||||
class GetWire:
|
||||
'''return the first wire from a given shape'''
|
||||
def __init__(self, obj,child=None):
|
||||
obj.addProperty("App::PropertyLink","Base","Base",
|
||||
"The base object that wire must be extracted")
|
||||
obj.Proxy = self
|
||||
obj.Base = child
|
||||
|
||||
def onChanged(self, fp, prop):
|
||||
"Do something when a property has changed"
|
||||
pass
|
||||
|
||||
def execute(self, fp):
|
||||
if fp.Base:
|
||||
#fp.Shape=fp.Base.Shape.Wires[0]
|
||||
fp.Shape=fp.Base.Shape.Wires[0].transformGeometry(\
|
||||
fp.Base.Shape.Placement.toMatrix())
|
||||
|
||||
class Frustum:
|
||||
def __init__(self, obj,r1=1,r2=2,n=3,h=4):
|
||||
obj.addProperty("App::PropertyInteger","FacesNumber","Base","Number of faces")
|
||||
obj.addProperty("App::PropertyDistance","Radius1","Base","Radius of lower the inscribed control circle")
|
||||
obj.addProperty("App::PropertyDistance","Radius2","Base","Radius of upper the inscribed control circle")
|
||||
obj.addProperty("App::PropertyDistance","Height","Base","Height of the Frustum")
|
||||
|
||||
obj.FacesNumber = n
|
||||
obj.Radius1 = r1
|
||||
obj.Radius2= r2
|
||||
obj.Height= h
|
||||
obj.Proxy = self
|
||||
|
||||
def execute(self, fp):
|
||||
self.createGeometry(fp)
|
||||
|
||||
def onChanged(self, fp, prop):
|
||||
if prop in ["FacesNumber","Radius1","Radius2","Height"]:
|
||||
self.createGeometry(fp)
|
||||
|
||||
def createGeometry(self,fp):
|
||||
if all((fp.Radius1,fp.Radius2,fp.FacesNumber,fp.Height)):
|
||||
import math
|
||||
import FreeCAD,Part
|
||||
#from draftlibs import fcgeo
|
||||
plm = fp.Placement
|
||||
wires=[]
|
||||
faces=[]
|
||||
for ir,r in enumerate((fp.Radius1,fp.Radius2)):
|
||||
angle = (math.pi*2)/fp.FacesNumber
|
||||
pts = [FreeCAD.Vector(r,0,ir*fp.Height)]
|
||||
for i in range(fp.FacesNumber-1):
|
||||
ang = (i+1)*angle
|
||||
pts.append(FreeCAD.Vector(\
|
||||
r*math.cos(ang),r*math.sin(ang),ir*fp.Height))
|
||||
pts.append(pts[0])
|
||||
shape = Part.makePolygon(pts)
|
||||
face = Part.Face(shape)
|
||||
wires.append(shape)
|
||||
faces.append(face)
|
||||
#shellperi=Part.makeRuledSurface(*wires)
|
||||
shellperi=Part.makeLoft(wires)
|
||||
shell=Part.Shell(shellperi.Faces+faces)
|
||||
fp.Shape = Part.Solid(shell)
|
||||
fp.Placement = plm
|
||||
|
||||
class Twist:
|
||||
def __init__(self, obj,child=None,h=1.0,angle=0.0):
|
||||
obj.addProperty("App::PropertyLink","Base","Base",
|
||||
"The base object that must be tranfsformed")
|
||||
obj.addProperty("App::PropertyAngle","Angle","Base","Twist Angle in degrees") #degree or rad
|
||||
obj.addProperty("App::PropertyDistance","Height","Base","Height of the Extrusion")
|
||||
|
||||
obj.Base = child
|
||||
obj.Angle = angle
|
||||
obj.Height = h
|
||||
obj.Proxy = self
|
||||
|
||||
def execute(self, fp):
|
||||
self.createGeometry(fp)
|
||||
|
||||
def onChanged(self, fp, prop):
|
||||
pass
|
||||
#if prop in ["Angle","Height"]:
|
||||
# self.createGeometry(fp)
|
||||
|
||||
def createGeometry(self,fp):
|
||||
import FreeCAD,Part,math
|
||||
#tangle = -twist #openscad uses degrees clockwise
|
||||
if fp.Base and fp.Angle and fp.Height and \
|
||||
fp.Base.Shape.isValid():
|
||||
#wire=fp.Base.Shape.Wires[0].transformGeometry(fp.Base.Placement.toMatrix())
|
||||
solids=[]
|
||||
for faceb in fp.Base.Shape.Faces:
|
||||
#fp.Base.Shape.Faces[0].check()
|
||||
|
||||
#faceb=fp.Base.Shape.Faces[0]
|
||||
#faceb=fp.Base.Shape.removeSplitter().Faces[0]
|
||||
faceu=faceb.copy()
|
||||
facetransform=FreeCAD.Matrix()
|
||||
facetransform.rotateZ(math.radians(fp.Angle))
|
||||
facetransform.move(FreeCAD.Vector(0,0,fp.Height))
|
||||
faceu.transformShape(facetransform)
|
||||
step = 2 + int(fp.Angle // 90) #resolution in z direction
|
||||
zinc = fp.Height/(step-1.0)
|
||||
angleinc = math.radians(fp.Angle)/(step-1.0)
|
||||
spine = Part.makePolygon([(0,0,i*zinc) \
|
||||
for i in range(step)])
|
||||
auxspine = Part.makePolygon([(math.cos(i*angleinc),\
|
||||
math.sin(i*angleinc),i*fp.Height/(step-1)) \
|
||||
for i in range(step)])
|
||||
faces=[faceb,faceu]
|
||||
for wire in faceb.Wires:
|
||||
pipeshell=Part.BRepOffsetAPI.MakePipeShell(spine)
|
||||
pipeshell.setSpineSupport(spine)
|
||||
pipeshell.add(wire)
|
||||
pipeshell.setAuxiliarySpine(auxspine,True,False)
|
||||
print pipeshell.getStatus()
|
||||
assert(pipeshell.isReady())
|
||||
#fp.Shape=pipeshell.makeSolid()
|
||||
pipeshell.build()
|
||||
faces.extend(pipeshell.shape().Faces)
|
||||
try:
|
||||
fullshell=Part.Shell(faces)
|
||||
solid=Part.Solid(fullshell)
|
||||
if solid.Volume < 0:
|
||||
solid.reverse()
|
||||
assert(solid.Volume >= 0)
|
||||
solids.append(solid)
|
||||
except:
|
||||
solids.append(Part.Compound(faces))
|
||||
fp.Shape=Part.Compound(solids)
|
||||
|
||||
class OffsetShape:
|
||||
def __init__(self, obj,child=None,offset=1.0):
|
||||
obj.addProperty("App::PropertyLink","Base","Base",
|
||||
"The base object that must be tranfsformed")
|
||||
obj.addProperty("App::PropertyDistance","Offset","Base","Offset outwards")
|
||||
|
||||
obj.Base = child
|
||||
obj.Offset = offset
|
||||
obj.Proxy = self
|
||||
|
||||
def execute(self, fp):
|
||||
self.createGeometry(fp)
|
||||
|
||||
def onChanged(self, fp, prop):
|
||||
pass
|
||||
#if prop in ["Offset"]:
|
||||
# self.createGeometry(fp)
|
||||
|
||||
def createGeometry(self,fp):
|
||||
if fp.Base and fp.Offset:
|
||||
fp.Shape=fp.Base.Shape.makeOffsetShape(self.Offset,1e-6)
|
115
src/Mod/OpenSCAD/OpenSCADUtils.py
Normal file
115
src/Mod/OpenSCAD/OpenSCADUtils.py
Normal file
|
@ -0,0 +1,115 @@
|
|||
#***************************************************************************
|
||||
#* *
|
||||
#* Copyright (c) 2012 Sebastian Hoogen <github@sebastianhoogen.de> *
|
||||
#* *
|
||||
#* This program is free software; you can redistribute it and/or modify *
|
||||
#* it under the terms of the GNU Lesser General Public License (LGPL) *
|
||||
#* as published by the Free Software Foundation; either version 2 of *
|
||||
#* the License, or (at your option) any later version. *
|
||||
#* for detail see the LICENCE text file. *
|
||||
#* *
|
||||
#* This program is distributed in the hope that it will be useful, *
|
||||
#* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
#* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
#* GNU Library General Public License for more details. *
|
||||
#* *
|
||||
#* You should have received a copy of the GNU Library General Public *
|
||||
#* License along with this program; if not, write to the Free Software *
|
||||
#* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
#* USA *
|
||||
#* *
|
||||
#***************************************************************************
|
||||
|
||||
__title__="FreeCAD OpenSCAD Workbench - Utility Fuctions"
|
||||
__author__ = "Sebastian Hoogen"
|
||||
__url__ = ["http://free-cad.sourceforge.net"]
|
||||
|
||||
'''
|
||||
This Script includes various pyhton helper functions that are shared across
|
||||
the module
|
||||
'''
|
||||
def callopenscad(inputfilename,outputfilename=None,outputext='csg',keepname=False):
|
||||
'''call the open scad binary
|
||||
returns the filename of the result (or None),
|
||||
please delete the file afterwards'''
|
||||
import FreeCAD,os,subprocess,tempfile,time
|
||||
osfilename = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/OpenSCAD").\
|
||||
GetString('openscadexecutable')
|
||||
if osfilename and os.path.isfile(osfilename):
|
||||
if not outputfilename:
|
||||
dir1=tempfile.gettempdir()
|
||||
if keepname:
|
||||
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()*10) % 1000000,outputext))
|
||||
if subprocess.call([osfilename,'-o',outputfilename,inputfilename]) == 0:
|
||||
return outputfilename
|
||||
|
||||
def callopenscadstring(scadstr,outputext='csg'):
|
||||
'''create a tempfile and call the open scad binary
|
||||
returns the filename of the result (or None),
|
||||
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))
|
||||
inputfile = open(inputfilename,'w')
|
||||
inputfile.write(scadstr)
|
||||
inputfile.close()
|
||||
outputfilename = callopenscad(inputfilename,outputext=outputext,keepname=True)
|
||||
os.unlink(inputfilename)
|
||||
return outputfilename
|
||||
|
||||
def reverseimporttypes():
|
||||
'''allows to search for supported filetypes by module'''
|
||||
|
||||
def getsetfromdict(dict1,index):
|
||||
if index in dict1:
|
||||
return dict1[index]
|
||||
else:
|
||||
set1=set()
|
||||
dict1[index]=set1
|
||||
return set1
|
||||
|
||||
importtypes={}
|
||||
import FreeCAD
|
||||
for key,value in FreeCAD.getImportType().iteritems():
|
||||
if type(value) is str:
|
||||
getsetfromdict(importtypes,value).add(key)
|
||||
else:
|
||||
for vitem in value:
|
||||
getsetfromdict(importtypes,vitem).add(key)
|
||||
return importtypes
|
||||
|
||||
|
||||
def fcsubmatrix(m):
|
||||
"""Extracts the 3x3 Submatrix from a freecad Matrix Object
|
||||
as a list of row vectors"""
|
||||
return [[m.A11,m.A12,m.A13],[m.A21,m.A22,m.A23],[m.A31,m.A32,m.A33]]
|
||||
|
||||
def multiplymat(l,r):
|
||||
"""multiply matrices given as lists of row vectors"""
|
||||
rt=zip(*r) #transpose r
|
||||
mat=[]
|
||||
for y in range(len(rt)):
|
||||
mline=[]
|
||||
for x in range(len(l)):
|
||||
mline.append(sum([le*re for le,re in zip(l[y],rt[x])]))
|
||||
mat.append(mline)
|
||||
return mat
|
||||
|
||||
def isorthogonal(submatrix,precision=4):
|
||||
"""checking if 3x3 Matrix is ortogonal (M*Transp(M)==I)"""
|
||||
prod=multiplymat(submatrix,zip(*submatrix))
|
||||
return [[round(f,precision) for f in line] for line in prod]==[[1,0,0],[0,1,0],[0,0,1]]
|
||||
|
||||
def detsubmatrix(s):
|
||||
"""get the determinant of a 3x3 Matrix given as list of row vectors"""
|
||||
return s[0][0]*s[1][1]*s[2][2]+s[0][1]*s[1][2]*s[2][0]+s[0][2]*s[1][0]*s[2][1]\
|
||||
-s[2][0]*s[1][1]*s[0][2]-s[2][1]*s[1][2]*s[0][0]-s[2][2]*s[1][0]*s[0][1]
|
||||
|
||||
def isspecialorthogonalpython(submat,precision=4):
|
||||
return isorthogonal(submat,precision) and round(detsubmatrix(submat),precision)==1
|
||||
|
||||
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)
|
8268
src/Mod/OpenSCAD/OpenSCAD_rc.py
Normal file
8268
src/Mod/OpenSCAD/OpenSCAD_rc.py
Normal file
File diff suppressed because it is too large
Load Diff
10
src/Mod/OpenSCAD/Resources/OpenSCAD.qrc
Normal file
10
src/Mod/OpenSCAD/Resources/OpenSCAD.qrc
Normal file
|
@ -0,0 +1,10 @@
|
|||
<RCC>
|
||||
<qresource>
|
||||
<file>icons/preferences-openscad.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>ui/openscadprefs-base.ui</file>
|
||||
</qresource>
|
||||
</RCC>
|
136
src/Mod/OpenSCAD/Resources/icons/OpenSCAD_ColorCodeShape.svg
Normal file
136
src/Mod/OpenSCAD/Resources/icons/OpenSCAD_ColorCodeShape.svg
Normal file
|
@ -0,0 +1,136 @@
|
|||
<?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:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="64px"
|
||||
height="64px"
|
||||
id="svg2980"
|
||||
sodipodi:version="0.32"
|
||||
inkscape:version="0.48.3.1 r9886"
|
||||
sodipodi:docname="Tree_Part.svg"
|
||||
inkscape:output_extension="org.inkscape.output.svg.inkscape"
|
||||
version="1.1">
|
||||
<defs
|
||||
id="defs2982">
|
||||
<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>
|
||||
<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="perspective2988" />
|
||||
</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="-2.8181818"
|
||||
inkscape:cy="32"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="true"
|
||||
inkscape:document-units="px"
|
||||
inkscape:grid-bbox="true"
|
||||
inkscape:window-width="1366"
|
||||
inkscape:window-height="706"
|
||||
inkscape:window-x="-8"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1" />
|
||||
<metadata
|
||||
id="metadata2985">
|
||||
<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="g3845"
|
||||
transform="matrix(0.58306143,0,0,0.58306143,-12.65478,-77.438442)"
|
||||
style="fill:#008000;stroke-width:3.45138597;stroke-miterlimit:4;stroke-dasharray:none">
|
||||
<path
|
||||
style="fill:#008000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:3.45138597;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
d="m 96.18444,141.44968 -19.81441,7.17921 29.4349,3.97209 -0.72357,36.12665 17.25881,-10.94388 0.57587,-34.38485 -26.7316,-1.94922 z"
|
||||
id="path3823"
|
||||
sodipodi:nodetypes="ccccccc"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="fill:#008000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:3.45138597;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
d="m 75.57941,148.6589 30.70884,3.36562 0,36.47719 -31.12383,-5.06479 0.41499,-34.77802 z"
|
||||
id="path3825"
|
||||
sodipodi:nodetypes="ccccc"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="fill:#008000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:3.45138597;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
d="m 106.05435,152.06948 16.72598,-8.4088"
|
||||
id="path3827"
|
||||
inkscape:connector-curvature="0" />
|
||||
</g>
|
||||
<path
|
||||
sodipodi:type="arc"
|
||||
style="fill:#ffff00;stroke:#000000;stroke-width:1.61374438;stroke-miterlimit:4;stroke-dasharray:none"
|
||||
id="path3759"
|
||||
sodipodi:cx="48.090908"
|
||||
sodipodi:cy="27.636364"
|
||||
sodipodi:rx="7.5454545"
|
||||
sodipodi:ry="4.3636365"
|
||||
d="m 55.636363,27.636364 a 7.5454545,4.3636365 0 1 1 -15.090909,0 7.5454545,4.3636365 0 1 1 15.090909,0 z"
|
||||
transform="matrix(1.3960176,0.45054535,-0.42447321,1.4817643,-39.495773,-47.031115)" />
|
||||
<g
|
||||
style="fill:#ff0000;stroke-width:4.24927664;stroke-miterlimit:4;stroke-dasharray:none"
|
||||
transform="matrix(0.53484593,0,0,0.54597261,-35.993942,-44.385404)"
|
||||
id="g3761">
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccccc"
|
||||
id="path3765"
|
||||
d="m 75.57941,148.6589 30.70884,3.36562 0,36.47719 -31.12383,-5.06479 0.41499,-34.77802 z"
|
||||
style="fill:#ff0000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:4.24927664;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path3767"
|
||||
d="m 106.05435,152.06948 16.72598,-8.4088"
|
||||
style="fill:#ff0000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:4.24927664;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
|
||||
</g>
|
||||
<g
|
||||
style="fill:#008000;stroke-width:3.45138597;stroke-miterlimit:4;stroke-dasharray:none"
|
||||
transform="matrix(0.58306143,0,0,0.58306143,-13.200235,-47.256624)"
|
||||
id="g3769">
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccccc"
|
||||
id="path3771"
|
||||
d="m 92.130602,151.42836 -17.943408,16.22238 32.553236,12.70344 9.62711,-18.24526 z"
|
||||
style="fill:#ffff00;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:3.45138597000000000;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 6.3 KiB |
402
src/Mod/OpenSCAD/Resources/icons/OpenSCAD_RefineShapeFeature.svg
Normal file
402
src/Mod/OpenSCAD/Resources/icons/OpenSCAD_RefineShapeFeature.svg
Normal file
|
@ -0,0 +1,402 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:i="http://ns.adobe.com/AdobeIllustrator/10.0/"
|
||||
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="svg2980"
|
||||
sodipodi:version="0.32"
|
||||
inkscape:version="0.48.3.1 r9886"
|
||||
sodipodi:docname="Tree_Part.svg"
|
||||
inkscape:output_extension="org.inkscape.output.svg.inkscape"
|
||||
version="1.1">
|
||||
<defs
|
||||
id="defs2982">
|
||||
<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="#linearGradient3864"
|
||||
id="radialGradient3850"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.6028459,1.0471639,-1.9794021,1.1395295,127.9588,-74.456907)"
|
||||
cx="51.328892"
|
||||
cy="31.074146"
|
||||
fx="51.328892"
|
||||
fy="31.074146"
|
||||
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="perspective2988" />
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="1.6160967"
|
||||
inkscape:cx="16.57935"
|
||||
inkscape:cy="-46.748843"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="true"
|
||||
inkscape:document-units="px"
|
||||
inkscape:grid-bbox="true"
|
||||
inkscape:window-width="911"
|
||||
inkscape:window-height="684"
|
||||
inkscape:window-x="177"
|
||||
inkscape:window-y="19"
|
||||
inkscape:window-maximized="0" />
|
||||
<metadata
|
||||
id="metadata2985">
|
||||
<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="g3845"
|
||||
transform="matrix(0.49611692,0,0,0.49611692,-6.2336536,-40.712112)">
|
||||
<path
|
||||
style="fill:#0034ff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:4;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
d="m 96.18444,141.44968 -19.81441,7.17921 29.4349,3.97209 -0.72357,36.12665 17.25881,-10.94388 0.57587,-34.38485 -26.7316,-1.94922 z"
|
||||
id="path3823"
|
||||
sodipodi:nodetypes="ccccccc"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="fill:#0034ff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:4;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
d="m 75.57941,148.6589 30.70884,3.36562 0,36.47719 -31.12383,-5.06479 0.41499,-34.77802 z"
|
||||
id="path3825"
|
||||
sodipodi:nodetypes="ccccc"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="fill:url(#radialGradient3850);fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
d="m 106.05435,152.06948 16.72598,-8.4088"
|
||||
id="path3827"
|
||||
inkscape:connector-curvature="0" />
|
||||
</g>
|
||||
<g
|
||||
style="stroke:#000000;stroke-width:1.97789347;stroke-miterlimit:10;stroke-dasharray:none;overflow:visible"
|
||||
id="g3981"
|
||||
transform="matrix(0.34530072,-0.0459555,0.0459555,0.34530072,-43.228956,-7.238134)">
|
||||
<g
|
||||
id="Layer_1"
|
||||
i:rgbTrio="#4F008000FFFF"
|
||||
i:layer="yes"
|
||||
i:dimmedPercent="50"
|
||||
style="stroke:#000000;stroke-width:1.97789347;stroke-miterlimit:10;stroke-dasharray:none">
|
||||
<g
|
||||
id="g3891"
|
||||
transform="matrix(-0.32435514,0.13754467,-0.13754467,-0.32435514,270.902,139.40876)"
|
||||
style="stroke:#000000;stroke-width:5.61401606;stroke-miterlimit:10;stroke-dasharray:none">
|
||||
<path
|
||||
id="path3893"
|
||||
stroke-miterlimit="10"
|
||||
i:knockout="Off"
|
||||
d="m 348.426,49.113 c 15.516,-4.14 30.348,-8.028 45.469,-11.664 15.084,-3.852 34.055,-8.46 44.135,-10.332 9.938,-1.872 10.621,-1.116 15.084,-0.36 4.32,0.648 8.244,3.492 10.801,4.932 2.34,1.296 3.527,0.648 3.564,3.744 -0.18,3.096 -1.477,11.34 -3.889,15.156 -2.447,3.708 -6.553,5.364 -10.367,7.488 -3.889,2.088 -7.668,3.132 -12.602,5.076 -5.039,1.872 -4.248,0.72 -17.207,5.976 -13.213,5.148 -44.461,18.072 -60.264,24.876 -15.732,6.66 -22.932,9.36 -33.553,15.192 -10.764,5.795 -21.889,15.588 -30.313,19.26 -8.459,3.492 -13.859,1.477 -19.943,2.16 -6.084,0.611 -8.711,-0.145 -16.775,1.764 -8.316,1.871 -22.248,5.939 -32.221,9.432 -10.116,3.492 -20.988,8.172 -27.216,10.98 -6.192,2.629 -9.432,4.213 -9.72,4.896 -0.18,3.131 -2.016,6.119 -5.508,9.107 -3.6,2.988 -6.516,4.176 -15.552,8.713 -9.216,4.428 -26.964,12.096 -38.952,17.855 -12.168,5.725 -23.544,11.557 -32.76,16.127 -9.144,4.43 -16.236,7.957 -21.816,10.584 -5.688,2.592 -7.596,4.43 -11.952,4.969 -4.392,0.359 -8.1,0.324 -14.616,-2.629 -6.732,-3.131 -17.388,-10.367 -25.02,-15.443 -7.704,-5.111 -16.2,-10.512 -20.484,-14.832 -4.248,-4.32 -3.852,-6.588 -4.932,-11.088 -1.224,-4.68 -2.52,-11.988 -1.8,-16.236 0.612,-4.355 2.556,-6.984 5.976,-9.395 3.492,-2.412 8.064,-4.141 14.4,-5.041 0.432,-9.791 0.18,-19.477 -0.612,-29.34 -0.972,-9.972 -3.24,-21.636 -4.428,-29.736 -1.152,-8.172 -2.052,-14.184 -2.556,-18.576 1.8,-4.104 4.068,-6.804 6.804,-8.532 2.664,-1.764 6.336,-1.656 9.36,-1.62 2.916,-0.072 5.724,0.468 8.28,1.476 1.8,-4.788 4.608,-7.56 8.568,-8.316 3.852,-0.756 8.856,0.396 14.868,3.6 1.836,-3.96 4.5,-6.084 7.992,-6.516 3.492,-0.432 7.704,0.828 12.78,3.924 1.548,-3.024 3.708,-4.788 6.624,-5.148 2.88,-0.396 6.48,0.468 10.8,2.736 1.908,-2.952 4.428,-4.536 7.56,-4.896 3.132,-0.432 6.732,0.504 11.088,2.664 0.18,-1.44 1.224,-2.412 3.672,-2.52 2.268,-0.216 7.128,0.612 10.296,1.368 3.096,0.612 4.644,1.368 8.388,2.664 3.6,1.26 9.252,3.096 13.5,4.932 4.248,1.728 9.288,2.556 11.628,5.4 2.196,2.772 1.764,4.788 1.764,11.34 -0.036,6.588 -1.8,20.268 -1.836,27.576 -0.18,7.236 0.18,12.204 0.936,15.444 13.068,-4.32 25.056,-8.748 36.504,-13.824 11.412,-5.148 23.688,-11.556 31.536,-16.308 7.596,-4.896 9.035,-9.432 14.473,-12.348 5.398,-2.916 10.295,-3.24 17.748,-5.148 7.379,-2.052 16.416,-4.212 26.279,-6.768 9.684,-2.772 22.393,-6.372 31.859,-8.856 9.398,-2.483 17.318,-4.463 24.158,-5.939 z"
|
||||
clip-rule="evenodd"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill-rule:evenodd;stroke:#000000;stroke-width:5.61401606;stroke-miterlimit:10;stroke-dasharray:none" />
|
||||
<path
|
||||
id="path3895"
|
||||
stroke-miterlimit="10"
|
||||
i:knockout="Off"
|
||||
d="m 259.326,74.709 c 13.104,-2.7 26.855,-5.94 42.084,-10.008 15.191,-4.212 31.68,-9.684 48.348,-14.184 16.633,-4.536 34.92,-8.712 50.4,-12.384 15.264,-3.816 31.463,-8.496 40.824,-9.72 9.18,-1.26 10.764,0.936 14.471,2.412 3.637,1.368 9.721,3.996 7.416,6.084 -2.447,1.944 -9.684,3.096 -21.852,6.372 -12.348,3.24 -34.523,8.856 -51.119,13.536 -16.705,4.68 -31.393,9.108 -47.953,14.4 -16.631,5.22 -38.195,11.988 -50.939,16.812 -12.744,4.752 -12.707,6.084 -25.164,11.772 -12.707,5.58 -35.82,15.768 -49.752,21.816 -13.932,6.047 -25.38,12.24 -32.832,14.004 -7.488,1.477 -8.928,-2.305 -11.664,-4.393 -2.916,-2.123 -4.536,-4.68 -5.256,-7.955 11.484,-4.141 22.572,-8.605 33.66,-13.537 11.052,-5.004 24.3,-10.944 32.364,-15.876 7.884,-5.04 10.621,-10.404 15.156,-13.608 4.5,-3.203 8.388,-5.003 11.808,-5.543 z"
|
||||
clip-rule="evenodd"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#0034ff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:5.61401606;stroke-miterlimit:10;stroke-dasharray:none" />
|
||||
<path
|
||||
id="path3897"
|
||||
i:knockout="Off"
|
||||
d="m 170.154,126.621 c 15.156,-6.553 27.72,-12.133 38.376,-17.028 10.548,-4.824 18.432,-8.46 24.768,-12.024 6.155,-3.816 8.243,-9.036 12.384,-9.972 4.141,-0.9 9.9,2.916 12.023,4.644 1.98,1.62 2.305,3.708 0,5.292 -2.52,1.332 -7.848,1.584 -14.328,3.528 -6.551,2.052 -16.307,5.616 -24.263,8.604 -7.992,2.772 -15.336,5.292 -23.292,8.677 -8.1,3.42 -16.092,7.199 -24.516,11.627 -0.36,-1.115 -0.756,-2.233 -1.152,-3.348 z"
|
||||
clip-rule="evenodd"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#0034ff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:5.61401606;stroke-miterlimit:10;stroke-dasharray:none" />
|
||||
<path
|
||||
id="path3899"
|
||||
stroke-miterlimit="10"
|
||||
i:knockout="Off"
|
||||
d="m 463.158,40.797 c 0.828,3.924 -0.396,7.236 -4.068,10.224 -3.744,2.844 -10.332,4.356 -17.676,7.308 -7.488,2.916 -16.057,6.048 -26.244,10.08 -10.332,3.888 -24.191,9.072 -34.633,13.464 -10.439,4.32 -17.711,7.524 -27.646,12.384 -10.152,4.716 -24.084,10.836 -32.365,15.876 -8.279,4.896 -11.736,10.908 -17.172,13.465 -5.652,2.412 -9.287,0.863 -15.768,1.584 -6.553,0.684 -12.527,0.252 -22.787,2.592 -10.514,2.268 -28.945,7.523 -38.917,10.908 -9.972,3.311 -13.824,6.119 -20.16,8.818 -6.336,2.594 -12.024,4.896 -17.46,6.912 0.756,4.141 -0.216,7.668 -3.312,10.729 -3.096,2.953 -8.1,3.996 -15.012,7.309 -7.128,3.203 -16.416,7.236 -27.036,12.24 -10.764,4.967 -25.92,12.492 -36.576,17.568 -10.764,5.074 -19.692,9.287 -27.072,12.348 -7.416,2.879 -9.756,6.443 -16.884,5.146 -7.236,-1.367 -17.568,-8.1 -25.992,-13.104 -8.676,-5.111 -19.296,-10.332 -24.624,-17.027 -5.22,-6.805 -8.604,-20.34 -6.66,-23.111 1.908,-2.773 10.512,2.916 17.748,6.516 7.056,3.42 17.496,11.592 24.66,14.4 7.056,2.844 10.548,3.6 17.712,2.268 7.056,-1.549 13.788,-6.336 24.66,-11.016 10.944,-4.789 27.108,-11.412 40.032,-17.102 12.816,-5.76 26.748,-13.428 36.108,-16.775 9.216,-3.313 15.336,-4.248 18.756,-2.951 4.068,-3.133 12.384,-7.561 25.092,-13.428 12.744,-6.086 36.792,-15.408 50.759,-21.709 13.896,-6.264 19.477,-10.728 32.148,-15.48 12.529,-4.896 24.625,-7.632 42.949,-13.212 18.359,-5.688 44.818,-14.004 66.311,-20.232 21.385,-6.336 41.438,-11.772 61.129,-16.992 z"
|
||||
clip-rule="evenodd"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#0034ff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:5.61401606;stroke-miterlimit:10;stroke-dasharray:none" />
|
||||
<path
|
||||
id="path3901"
|
||||
i:knockout="Off"
|
||||
d="m 52.758,212.877 c -4.104,-0.973 -20.844,-10.656 -27.432,-15.049 -6.624,-4.391 -9,-6.912 -11.7,-11.303 -2.844,-4.609 -6.228,-13.861 -4.464,-15.408 1.908,-1.404 11.52,2.592 15.516,6.732 3.888,4.066 3.348,12.887 7.56,17.279 4.068,4.176 13.284,5.111 16.812,8.1 3.384,3.024 7.632,10.405 3.708,9.649 z"
|
||||
clip-rule="evenodd"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#0034ff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:5.61401606;stroke-miterlimit:10;stroke-dasharray:none" />
|
||||
<path
|
||||
id="path3903"
|
||||
i:knockout="Off"
|
||||
d="m 263.395,124.82 c -8.137,1.477 -17.354,4.105 -28.08,7.885 -10.765,3.816 -27.792,11.195 -35.964,14.795 -8.28,3.422 -12.456,5.365 -13.068,5.832 1.08,2.484 0.684,4.752 -1.188,7.236 -1.944,2.34 -3.708,3.961 -10.152,7.092 -6.696,3.168 -27.36,12.709 -28.8,11.701 -1.296,-1.332 16.992,-14.076 20.844,-18.648 3.636,-4.535 -0.756,-6.48 1.26,-8.207 1.872,-1.729 8.712,-0.9 10.368,-2.232 1.62,-1.477 1.44,-3.385 -0.54,-6.121 1.08,-0.143 2.16,-0.072 3.672,0.072 1.404,0.145 2.952,0.359 4.788,0.793 1.908,-2.844 6.048,-5.904 12.564,-9.324 6.552,-3.457 17.64,-7.525 26.316,-11.088 8.568,-3.637 20.916,-10.477 24.84,-10.404 3.779,0.035 -4.32,8.496 -2.088,10.404 2.231,1.726 7.163,1.798 15.228,0.214 z"
|
||||
clip-rule="evenodd"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#0034ff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:5.61401606;stroke-miterlimit:10;stroke-dasharray:none" />
|
||||
<path
|
||||
id="path3905"
|
||||
i:knockout="Off"
|
||||
d="m 461.43,42.777 c 2.447,-0.288 -0.576,3.636 -2.268,5.508 -1.801,1.692 -1.656,2.52 -7.74,4.86 -6.229,2.268 -20.557,5.76 -28.549,8.676 -7.955,2.772 -8.891,4.032 -18.756,8.244 -10.043,4.176 -34.02,15.156 -40.391,16.848 -6.264,1.476 -3.564,-3.744 2.807,-7.308 6.373,-3.672 25.453,-10.224 34.885,-13.824 9.145,-3.6 13.535,-5.148 20.557,-7.704 7.02,-2.736 15.156,-5.4 21.779,-7.992 6.623,-2.628 15.012,-7.056 17.676,-7.308 z"
|
||||
clip-rule="evenodd"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#0034ff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:5.61401606;stroke-miterlimit:10;stroke-dasharray:none" />
|
||||
<path
|
||||
id="path3907"
|
||||
i:knockout="Off"
|
||||
d="m 442.781,39.465 c 6.625,-1.368 7.525,-0.756 9.109,-1.908 1.512,-1.296 2.916,-4.536 0.035,-5.292 -3.096,-0.792 -6.912,-1.368 -17.965,0.756 -11.268,2.088 -44.314,9.684 -48.311,11.556 -3.744,1.62 20.447,-1.332 25.092,-1.224 4.428,0.072 -3.961,2.52 1.477,1.944 5.471,-0.792 23.761,-4.5 30.563,-5.832 z"
|
||||
clip-rule="evenodd"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#0034ff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:5.61401606;stroke-miterlimit:10;stroke-dasharray:none" />
|
||||
<path
|
||||
id="path3909"
|
||||
stroke-miterlimit="10"
|
||||
i:knockout="Off"
|
||||
d="m 77.454,83.061 c 0.36,1.512 -7.776,3.168 -10.656,3.312 -2.988,0.144 -6.228,-0.756 -6.66,-2.304 -0.432,-1.656 0.936,-7.38 3.96,-7.452 2.916,-0.18 12.78,4.752 13.356,6.444 z"
|
||||
clip-rule="evenodd"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#edecf1;fill-rule:evenodd;stroke:#000000;stroke-width:5.61401606;stroke-miterlimit:10;stroke-dasharray:none" />
|
||||
<path
|
||||
id="path3911"
|
||||
stroke-miterlimit="10"
|
||||
i:knockout="Off"
|
||||
d="m 38.43,67.185 c -0.108,2.016 -6.588,9.072 -10.152,9.648 -3.564,0.432 -10.476,-4.788 -10.584,-6.768 -0.144,-2.16 6.48,-4.572 10.008,-5.148 3.456,-0.504 10.548,0.252 10.728,2.268 z"
|
||||
clip-rule="evenodd"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#edecf1;fill-rule:evenodd;stroke:#000000;stroke-width:5.61401606;stroke-miterlimit:10;stroke-dasharray:none" />
|
||||
<path
|
||||
id="path3913"
|
||||
stroke-miterlimit="10"
|
||||
i:knockout="Off"
|
||||
d="m 57.33,75.429 c 0.432,2.304 -3.132,9.036 -6.372,9.108 -3.42,0 -12.708,-6.696 -13.284,-8.964 -0.504,-2.448 6.588,-5.184 10.008,-5.148 3.348,-0.036 8.964,2.556 9.648,5.004 z"
|
||||
clip-rule="evenodd"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#edecf1;fill-rule:evenodd;stroke:#000000;stroke-width:5.61401606;stroke-miterlimit:10;stroke-dasharray:none" />
|
||||
<path
|
||||
id="path3915"
|
||||
stroke-miterlimit="10"
|
||||
i:knockout="Off"
|
||||
d="m 58.122,61.281 c 0.972,1.944 -0.756,7.2 -3.384,7.992 -2.736,0.612 -11.772,-2.088 -12.672,-3.924 -1.044,-1.944 4.104,-6.768 6.84,-7.38 2.664,-0.648 8.136,1.332 9.216,3.312 z"
|
||||
clip-rule="evenodd"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#edecf1;fill-rule:evenodd;stroke:#000000;stroke-width:5.61401606;stroke-miterlimit:10;stroke-dasharray:none" />
|
||||
<path
|
||||
id="path3917"
|
||||
stroke-miterlimit="10"
|
||||
i:knockout="Off"
|
||||
d="m 93.654,79.605 c 0.828,1.476 -2.664,3.24 -4.932,3.348 -2.448,-0.036 -7.992,-1.692 -8.856,-3.168 -0.864,-1.512 1.224,-5.796 3.636,-5.76 2.34,0.072 9.108,3.924 10.152,5.58 z"
|
||||
clip-rule="evenodd"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#edecf1;fill-rule:evenodd;stroke:#000000;stroke-width:5.61401606;stroke-miterlimit:10;stroke-dasharray:none" />
|
||||
<path
|
||||
id="path3919"
|
||||
stroke-miterlimit="10"
|
||||
i:knockout="Off"
|
||||
d="m 110.43,75.681 c 0.072,1.548 -5.4,4.752 -7.812,4.752 -2.7,-0.288 -6.804,-4.176 -7.02,-5.688 -0.144,-1.548 3.888,-3.528 6.408,-3.312 2.412,0.144 8.28,2.664 8.424,4.248 z"
|
||||
clip-rule="evenodd"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#edecf1;fill-rule:evenodd;stroke:#000000;stroke-width:5.61401606;stroke-miterlimit:10;stroke-dasharray:none" />
|
||||
<path
|
||||
id="path3921"
|
||||
stroke-miterlimit="10"
|
||||
i:knockout="Off"
|
||||
d="m 125.91,73.809 c 0,1.116 -4.716,3.852 -6.948,3.888 -2.376,-0.108 -6.66,-2.628 -6.732,-3.816 -0.108,-1.26 4.104,-3.276 6.408,-3.276 2.304,0.072 7.092,1.836 7.272,3.204 z"
|
||||
clip-rule="evenodd"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#edecf1;fill-rule:evenodd;stroke:#000000;stroke-width:5.61401606;stroke-miterlimit:10;stroke-dasharray:none" />
|
||||
<path
|
||||
id="path3923"
|
||||
stroke-miterlimit="10"
|
||||
i:knockout="Off"
|
||||
d="m 142.434,70.317 c -0.036,1.26 -4.14,4.824 -6.48,5.004 -2.448,0.036 -7.092,-3.096 -7.272,-4.392 -0.18,-1.404 4.104,-3.204 6.444,-3.312 2.304,-0.108 7.056,1.296 7.308,2.7 z"
|
||||
clip-rule="evenodd"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#edecf1;fill-rule:evenodd;stroke:#000000;stroke-width:5.61401606;stroke-miterlimit:10;stroke-dasharray:none" />
|
||||
<path
|
||||
id="path3925"
|
||||
stroke-miterlimit="10"
|
||||
i:knockout="Off"
|
||||
d="m 162.918,67.689 c 0.18,1.476 -4.716,3.6 -7.452,3.888 -2.844,0.108 -8.424,-1.26 -8.82,-2.736 -0.36,-1.584 4.032,-6.084 6.804,-6.264 2.808,-0.144 8.928,3.456 9.468,5.112 z"
|
||||
clip-rule="evenodd"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#edecf1;fill-rule:evenodd;stroke:#000000;stroke-width:5.61401606;stroke-miterlimit:10;stroke-dasharray:none" />
|
||||
<path
|
||||
id="path3927"
|
||||
stroke-miterlimit="10"
|
||||
i:knockout="Off"
|
||||
d="m 164.538,70.389 c -3.744,2.304 -6.948,3.492 -10.008,3.708 -3.024,0.144 -5.796,-0.684 -8.172,-2.628 0.18,9.504 0.468,19.44 0.72,30.636 0.252,11.088 0.54,22.825 0.864,35.639 3.816,1.908 6.912,2.377 9.684,1.549 2.7,-0.863 4.788,-3.168 6.408,-6.768 -0.828,-11.736 -1.188,-22.428 -1.08,-32.904 0.036,-10.512 0.612,-19.98 1.584,-29.232 z"
|
||||
clip-rule="evenodd"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#edecf1;fill-rule:evenodd;stroke:#000000;stroke-width:5.61401606;stroke-miterlimit:10;stroke-dasharray:none" />
|
||||
<path
|
||||
id="path3929"
|
||||
stroke-miterlimit="10"
|
||||
i:knockout="Off"
|
||||
d="m 144.09,72.801 c -1.98,2.376 -4.248,3.816 -6.66,4.32 -2.448,0.468 -5.184,0 -8.064,-1.404 -1.044,9.36 -1.62,19.368 -1.728,30.456 -0.18,11.052 0.108,22.788 0.864,35.604 3.816,1.871 6.912,2.447 9.684,1.584 2.7,-0.936 4.788,-3.061 6.408,-6.768 0.432,-9.721 0.612,-19.656 0.54,-30.349 -0.144,-10.799 -0.396,-21.671 -1.044,-33.443 z"
|
||||
clip-rule="evenodd"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#edecf1;fill-rule:evenodd;stroke:#000000;stroke-width:5.61401606;stroke-miterlimit:10;stroke-dasharray:none" />
|
||||
<path
|
||||
id="path3931"
|
||||
stroke-miterlimit="10"
|
||||
i:knockout="Off"
|
||||
d="m 126.306,77.013 c -1.44,1.512 -3.132,2.448 -5.076,2.664 -2.016,0.216 -4.176,-0.252 -6.624,-1.404 -1.584,11.664 -2.772,23.076 -3.42,35.064 -0.72,11.952 -0.972,23.651 -0.756,35.929 3.744,1.979 6.984,2.375 9.72,1.584 2.7,-0.9 4.788,-3.168 6.408,-6.805 -0.648,-10.871 -1.152,-21.6 -1.116,-32.868 -0.072,-11.304 0.216,-22.464 0.864,-34.164 z"
|
||||
clip-rule="evenodd"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#edecf1;fill-rule:evenodd;stroke:#000000;stroke-width:5.61401606;stroke-miterlimit:10;stroke-dasharray:none" />
|
||||
<path
|
||||
id="path3933"
|
||||
stroke-miterlimit="10"
|
||||
i:knockout="Off"
|
||||
d="m 111.834,79.461 c -2.268,1.692 -4.536,2.556 -6.948,2.988 -2.448,0.36 -4.968,0.036 -7.56,-0.828 -1.8,14.076 -2.772,27.288 -3.06,40.176 -0.36,12.889 0.108,24.805 1.26,36.432 2.592,1.08 4.86,1.008 7.236,-0.072 2.268,-1.15 4.356,-3.455 6.408,-6.768 -1.188,-10.008 -1.548,-20.879 -1.08,-32.904 0.468,-12.096 1.62,-24.912 3.744,-39.024 z"
|
||||
clip-rule="evenodd"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#edecf1;fill-rule:evenodd;stroke:#000000;stroke-width:5.61401606;stroke-miterlimit:10;stroke-dasharray:none" />
|
||||
<path
|
||||
id="path3935"
|
||||
stroke-miterlimit="10"
|
||||
i:knockout="Off"
|
||||
d="m 95.13,81.441 c -0.648,2.34 -2.124,3.528 -4.428,3.96 -2.376,0.36 -5.508,-0.288 -9.54,-1.8 -0.684,11.016 -1.188,22.896 -1.512,36.215 -0.36,13.357 -0.54,27.469 -0.54,43.164 2.988,1.908 5.76,2.449 8.172,1.764 2.376,-0.756 4.536,-2.879 6.336,-6.227 -0.828,-10.117 -1.044,-21.42 -0.792,-34.309 0.252,-13.031 0.972,-26.963 2.304,-42.767 z"
|
||||
clip-rule="evenodd"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#edecf1;fill-rule:evenodd;stroke:#000000;stroke-width:5.61401606;stroke-miterlimit:10;stroke-dasharray:none" />
|
||||
<path
|
||||
id="path3937"
|
||||
stroke-miterlimit="10"
|
||||
i:knockout="Off"
|
||||
d="m 78.714,86.193 c -3.96,1.908 -7.488,2.7 -11.016,2.52 -3.528,-0.216 -6.768,-1.44 -9.864,-3.672 0.468,18.792 0.792,34.848 1.116,48.996 0.324,14.111 0.504,25.488 0.684,34.955 4.32,2.773 7.848,3.744 10.728,3.205 2.88,-0.648 4.968,-2.809 6.408,-6.768 -1.08,-8.893 -1.44,-19.584 -1.08,-32.904 0.288,-13.32 1.296,-28.584 3.024,-46.332 z"
|
||||
clip-rule="evenodd"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#edecf1;fill-rule:evenodd;stroke:#000000;stroke-width:5.61401606;stroke-miterlimit:10;stroke-dasharray:none" />
|
||||
<path
|
||||
id="path3939"
|
||||
stroke-miterlimit="10"
|
||||
i:knockout="Off"
|
||||
d="m 53.082,87.633 c -3.852,0.468 -7.092,0.252 -9.864,-0.792 -2.808,-1.152 -5.004,-2.844 -6.732,-5.508 1.404,17.64 2.484,32.761 3.096,46.188 0.612,13.355 0.9,24.336 0.72,33.516 2.412,4.031 4.86,6.408 7.488,7.127 2.628,0.648 5.184,-0.215 8.064,-2.879 C 55.458,152.9 55.026,140.59 54.558,127.521 54.09,114.488 53.55,101.385 53.082,87.633 z"
|
||||
clip-rule="evenodd"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#edecf1;fill-rule:evenodd;stroke:#000000;stroke-width:5.61401606;stroke-miterlimit:10;stroke-dasharray:none" />
|
||||
<path
|
||||
id="path3941"
|
||||
stroke-miterlimit="10"
|
||||
i:knockout="Off"
|
||||
d="m 32.202,79.857 c -2.844,1.8 -5.472,2.304 -8.172,1.116 -2.736,-1.188 -5.256,-3.78 -7.848,-7.92 2.808,18.576 4.536,34.272 5.724,48.061 1.08,13.68 1.26,24.66 0.684,33.516 2.412,3.961 4.86,6.191 7.488,7.129 2.556,0.826 5.148,0.07 7.92,-2.125 C 37.602,148.222 36.81,136.054 35.91,122.698 34.974,109.269 33.642,95.265 32.202,79.857 z"
|
||||
clip-rule="evenodd"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#edecf1;fill-rule:evenodd;stroke:#000000;stroke-width:5.61401606;stroke-miterlimit:10;stroke-dasharray:none" />
|
||||
<path
|
||||
id="path3943"
|
||||
stroke-miterlimit="10"
|
||||
i:knockout="Off"
|
||||
d="m 80.01,59.841 c 0.72,1.332 -2.124,3.78 -4.788,4.572 -2.844,0.72 -10.44,0.684 -11.268,-0.504 -0.648,-1.404 3.996,-6.732 6.84,-7.38 2.736,-0.684 8.352,1.908 9.216,3.312 z"
|
||||
clip-rule="evenodd"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#edecf1;fill-rule:evenodd;stroke:#000000;stroke-width:5.61401606;stroke-miterlimit:10;stroke-dasharray:none" />
|
||||
<path
|
||||
id="path3945"
|
||||
stroke-miterlimit="10"
|
||||
i:knockout="Off"
|
||||
d="m 98.082,56.097 c 0.612,1.584 -2.232,5.472 -4.932,6.228 -2.808,0.612 -10.404,-0.612 -11.124,-2.16 -0.648,-1.656 3.996,-6.696 6.84,-7.344 2.736,-0.72 8.352,1.62 9.216,3.276 z"
|
||||
clip-rule="evenodd"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#edecf1;fill-rule:evenodd;stroke:#000000;stroke-width:5.61401606;stroke-miterlimit:10;stroke-dasharray:none" />
|
||||
<path
|
||||
id="path3947"
|
||||
stroke-miterlimit="10"
|
||||
i:knockout="Off"
|
||||
d="m 116.298,55.053 c 0.396,1.656 -4.104,5.472 -6.696,6.3 -2.808,0.648 -8.892,-0.648 -9.36,-2.232 -0.396,-1.728 3.96,-6.732 6.804,-7.38 2.7,-0.684 8.748,1.584 9.252,3.312 z"
|
||||
clip-rule="evenodd"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#edecf1;fill-rule:evenodd;stroke:#000000;stroke-width:5.61401606;stroke-miterlimit:10;stroke-dasharray:none" />
|
||||
<path
|
||||
id="path3949"
|
||||
stroke-miterlimit="10"
|
||||
i:knockout="Off"
|
||||
d="m 135.126,54.369 c 0.54,1.224 -2.628,4.104 -5.472,4.752 -2.844,0.36 -10.8,-0.54 -11.376,-1.728 -0.54,-1.332 4.644,-4.896 7.632,-5.436 2.772,-0.576 8.568,1.152 9.216,2.412 z"
|
||||
clip-rule="evenodd"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#edecf1;fill-rule:evenodd;stroke:#000000;stroke-width:5.61401606;stroke-miterlimit:10;stroke-dasharray:none" />
|
||||
<path
|
||||
id="path3951"
|
||||
stroke-miterlimit="10"
|
||||
i:knockout="Off"
|
||||
d="m 77.742,70.353 c 1.008,1.728 -3.564,5.76 -5.94,6.264 -2.484,0.288 -7.884,-2.232 -8.856,-3.96 -1.044,-1.836 0,-6.156 2.556,-6.552 2.448,-0.324 11.16,2.34 12.24,4.248 z"
|
||||
clip-rule="evenodd"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#edecf1;fill-rule:evenodd;stroke:#000000;stroke-width:5.61401606;stroke-miterlimit:10;stroke-dasharray:none" />
|
||||
<path
|
||||
id="path3953"
|
||||
stroke-miterlimit="10"
|
||||
i:knockout="Off"
|
||||
d="m 95.85,67.401 c 1.008,1.548 -2.052,5.256 -4.32,5.724 -2.304,0.252 -7.848,-2.232 -9,-3.708 -1.116,-1.512 -0.288,-5.04 2.088,-5.328 2.196,-0.36 10.008,1.764 11.232,3.312 z"
|
||||
clip-rule="evenodd"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#edecf1;fill-rule:evenodd;stroke:#000000;stroke-width:5.61401606;stroke-miterlimit:10;stroke-dasharray:none" />
|
||||
<path
|
||||
id="path3955"
|
||||
stroke-miterlimit="10"
|
||||
i:knockout="Off"
|
||||
d="m 113.13,66.933 c 0.972,1.404 -3.096,3.492 -5.4,3.636 -2.448,0.036 -7.344,-1.692 -8.46,-3.096 -1.116,-1.476 -0.288,-5.256 2.088,-5.364 2.232,-0.18 10.692,3.42 11.772,4.824 z"
|
||||
clip-rule="evenodd"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#edecf1;fill-rule:evenodd;stroke:#000000;stroke-width:5.61401606;stroke-miterlimit:10;stroke-dasharray:none" />
|
||||
<path
|
||||
id="path3957"
|
||||
stroke-miterlimit="10"
|
||||
i:knockout="Off"
|
||||
d="m 128.286,63.729 c 0.792,1.476 -2.808,4.716 -4.824,5.148 -2.16,0.252 -6.336,-1.8 -7.272,-3.24 -0.936,-1.548 0.036,-5.004 2.088,-5.364 1.98,-0.324 9.072,1.944 10.008,3.456 z"
|
||||
clip-rule="evenodd"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#edecf1;fill-rule:evenodd;stroke:#000000;stroke-width:5.61401606;stroke-miterlimit:10;stroke-dasharray:none" />
|
||||
<path
|
||||
id="path3959"
|
||||
stroke-miterlimit="10"
|
||||
i:knockout="Off"
|
||||
d="m 148.338,60.057 c 0.864,1.476 -2.916,4.716 -4.824,5.148 -2.16,0.252 -6.372,-1.8 -7.236,-3.24 -0.828,-1.548 -0.036,-5.004 2.088,-5.364 2.016,-0.324 9,1.944 9.972,3.456 z"
|
||||
clip-rule="evenodd"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#edecf1;fill-rule:evenodd;stroke:#000000;stroke-width:5.61401606;stroke-miterlimit:10;stroke-dasharray:none" />
|
||||
<path
|
||||
id="path3961"
|
||||
i:knockout="Off"
|
||||
d="m 168.282,133.102 c -1.116,3.455 -3.312,5.76 -6.876,7.055 -3.564,1.225 -8.352,1.441 -14.364,0.504 -2.664,2.197 -5.4,3.744 -8.208,4.5 -2.844,0.756 -5.76,0.865 -8.748,0.182 -0.396,3.059 -2.124,5.184 -5.184,6.658 -3.168,1.441 -7.416,1.945 -13.176,1.801 -1.296,2.916 -3.024,5.111 -5.724,6.588 -2.628,1.369 -6.048,2.016 -10.116,1.943 -1.728,3.602 -3.924,5.725 -6.588,6.66 -2.7,0.9 -5.868,0.324 -9.504,-1.439 -4.392,5.148 -8.532,7.848 -12.276,8.389 -3.888,0.432 -7.236,-1.297 -10.476,-5.473 -4.86,1.297 -8.64,1.439 -11.88,0.576 -3.204,-0.936 -5.616,-3.023 -7.236,-6.119 -5.22,1.402 -9.396,1.295 -12.672,-0.469 -3.312,-1.764 -5.616,-5.076 -6.912,-9.936 -3.132,-0.252 -5.364,0.072 -6.696,1.115 -1.44,0.936 -3.744,2.771 -1.512,4.824 2.268,1.871 7.38,3.24 14.652,7.164 7.092,3.959 18.216,14.615 27.828,16.271 9.396,1.439 15.984,-2.303 28.944,-6.912 13.068,-4.643 35.676,-15.084 48.384,-20.484 12.384,-5.398 18.432,-9.252 26.064,-12.131 7.56,-3.096 13.968,-4.896 19.368,-5.832 -2.268,-0.793 -3.924,-1.584 -5.112,-2.52 -1.224,-0.937 -1.836,-1.908 -1.98,-2.915 z"
|
||||
clip-rule="evenodd"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#000080;fill-rule:evenodd;stroke:#000000;stroke-width:5.61401606;stroke-miterlimit:10;stroke-dasharray:none" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 30 KiB |
461
src/Mod/OpenSCAD/Resources/icons/OpenSCAD_RemoveSubtree.svg
Normal file
461
src/Mod/OpenSCAD/Resources/icons/OpenSCAD_RemoveSubtree.svg
Normal file
|
@ -0,0 +1,461 @@
|
|||
<?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="svg3612"
|
||||
version="1.1"
|
||||
inkscape:version="0.48.3.1 r9886"
|
||||
sodipodi:docname="OpenSCAD_ReplaceObject.svg">
|
||||
<defs
|
||||
id="defs3614">
|
||||
<marker
|
||||
inkscape:stockid="Arrow1Mend"
|
||||
orient="auto"
|
||||
refY="0.0"
|
||||
refX="0.0"
|
||||
id="Arrow1Mend"
|
||||
style="overflow:visible;">
|
||||
<path
|
||||
id="path3835"
|
||||
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
|
||||
style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;"
|
||||
transform="scale(0.4) rotate(180) translate(10,0)" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:stockid="Arrow1Mstart"
|
||||
orient="auto"
|
||||
refY="0.0"
|
||||
refX="0.0"
|
||||
id="Arrow1Mstart"
|
||||
style="overflow:visible">
|
||||
<path
|
||||
id="path3832"
|
||||
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
|
||||
style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt"
|
||||
transform="scale(0.4) translate(10,0)" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:stockid="Arrow1Lstart"
|
||||
orient="auto"
|
||||
refY="0.0"
|
||||
refX="0.0"
|
||||
id="Arrow1Lstart"
|
||||
style="overflow:visible">
|
||||
<path
|
||||
id="path3826"
|
||||
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
|
||||
style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt"
|
||||
transform="scale(0.8) translate(12.5,0)" />
|
||||
</marker>
|
||||
<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="perspective3620" />
|
||||
<inkscape:perspective
|
||||
id="perspective3588"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3692"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<linearGradient
|
||||
id="linearGradient3144-6">
|
||||
<stop
|
||||
id="stop3146-9"
|
||||
style="stop-color:#ffffff;stop-opacity:1"
|
||||
offset="0" />
|
||||
<stop
|
||||
id="stop3148-2"
|
||||
style="stop-color:#ffffff;stop-opacity:0"
|
||||
offset="1" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient3701">
|
||||
<stop
|
||||
id="stop3703"
|
||||
style="stop-color:#ffffff;stop-opacity:1"
|
||||
offset="0" />
|
||||
<stop
|
||||
id="stop3705"
|
||||
style="stop-color:#ffffff;stop-opacity:0"
|
||||
offset="1" />
|
||||
</linearGradient>
|
||||
<radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3144-6"
|
||||
id="radialGradient3688"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(1,0,0,0.6985294,0,202.82863)"
|
||||
cx="225.26402"
|
||||
cy="672.79736"
|
||||
fx="225.26402"
|
||||
fy="672.79736"
|
||||
r="34.345188" />
|
||||
<linearGradient
|
||||
id="linearGradient3708">
|
||||
<stop
|
||||
id="stop3710"
|
||||
style="stop-color:#ffffff;stop-opacity:1"
|
||||
offset="0" />
|
||||
<stop
|
||||
id="stop3712"
|
||||
style="stop-color:#ffffff;stop-opacity:0"
|
||||
offset="1" />
|
||||
</linearGradient>
|
||||
<inkscape:perspective
|
||||
id="perspective3805"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<linearGradient
|
||||
id="linearGradient3864-0-0">
|
||||
<stop
|
||||
id="stop3866-5-7"
|
||||
offset="0"
|
||||
style="stop-color:#0619c0;stop-opacity:1;" />
|
||||
<stop
|
||||
id="stop3868-7-6"
|
||||
offset="1"
|
||||
style="stop-color:#379cfb;stop-opacity:1;" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient3377">
|
||||
<stop
|
||||
id="stop3379"
|
||||
offset="0"
|
||||
style="stop-color:#ffaa00;stop-opacity:1;" />
|
||||
<stop
|
||||
id="stop3381"
|
||||
offset="1"
|
||||
style="stop-color:#faff2b;stop-opacity:1;" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient3864-0">
|
||||
<stop
|
||||
id="stop3866-5"
|
||||
offset="0"
|
||||
style="stop-color:#0619c0;stop-opacity:1;" />
|
||||
<stop
|
||||
id="stop3868-7"
|
||||
offset="1"
|
||||
style="stop-color:#379cfb;stop-opacity:1;" />
|
||||
</linearGradient>
|
||||
<inkscape:perspective
|
||||
id="perspective3902"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<linearGradient
|
||||
id="linearGradient5048">
|
||||
<stop
|
||||
style="stop-color:black;stop-opacity:0;"
|
||||
offset="0"
|
||||
id="stop5050" />
|
||||
<stop
|
||||
id="stop5056"
|
||||
offset="0.5"
|
||||
style="stop-color:black;stop-opacity:1;" />
|
||||
<stop
|
||||
style="stop-color:black;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop5052" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient3841-0-3">
|
||||
<stop
|
||||
id="stop3843-1-3"
|
||||
offset="0"
|
||||
style="stop-color:#0619c0;stop-opacity:1;" />
|
||||
<stop
|
||||
id="stop3845-0-8"
|
||||
offset="1"
|
||||
style="stop-color:#379cfb;stop-opacity:1;" />
|
||||
</linearGradient>
|
||||
<radialGradient
|
||||
gradientUnits="userSpaceOnUse"
|
||||
fy="114.5684"
|
||||
fx="20.892099"
|
||||
r="5.256"
|
||||
cy="114.5684"
|
||||
cx="20.892099"
|
||||
id="aigrd2">
|
||||
<stop
|
||||
id="stop15566"
|
||||
style="stop-color:#F0F0F0"
|
||||
offset="0" />
|
||||
<stop
|
||||
id="stop15568"
|
||||
style="stop-color:#9a9a9a;stop-opacity:1.0000000;"
|
||||
offset="1.0000000" />
|
||||
</radialGradient>
|
||||
<radialGradient
|
||||
gradientUnits="userSpaceOnUse"
|
||||
fy="64.567902"
|
||||
fx="20.892099"
|
||||
r="5.257"
|
||||
cy="64.567902"
|
||||
cx="20.892099"
|
||||
id="aigrd3">
|
||||
<stop
|
||||
id="stop15573"
|
||||
style="stop-color:#F0F0F0"
|
||||
offset="0" />
|
||||
<stop
|
||||
id="stop15575"
|
||||
style="stop-color:#9a9a9a;stop-opacity:1.0000000;"
|
||||
offset="1.0000000" />
|
||||
</radialGradient>
|
||||
<linearGradient
|
||||
id="linearGradient15662">
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:1.0000000;"
|
||||
offset="0.0000000"
|
||||
id="stop15664" />
|
||||
<stop
|
||||
style="stop-color:#f8f8f8;stop-opacity:1.0000000;"
|
||||
offset="1.0000000"
|
||||
id="stop15666" />
|
||||
</linearGradient>
|
||||
<radialGradient
|
||||
r="86.70845"
|
||||
fy="35.736916"
|
||||
fx="33.966679"
|
||||
cy="35.736916"
|
||||
cx="33.966679"
|
||||
gradientTransform="matrix(0.96049297,0,0,1.041132,-52.144249,-702.33158)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient4452"
|
||||
xlink:href="#linearGradient259"
|
||||
inkscape:collect="always" />
|
||||
<linearGradient
|
||||
id="linearGradient259">
|
||||
<stop
|
||||
style="stop-color:#fafafa;stop-opacity:1.0000000;"
|
||||
offset="0.0000000"
|
||||
id="stop260" />
|
||||
<stop
|
||||
style="stop-color:#bbbbbb;stop-opacity:1.0000000;"
|
||||
offset="1.0000000"
|
||||
id="stop261" />
|
||||
</linearGradient>
|
||||
<radialGradient
|
||||
r="37.751713"
|
||||
fy="3.7561285"
|
||||
fx="8.824419"
|
||||
cy="3.7561285"
|
||||
cx="8.824419"
|
||||
gradientTransform="matrix(0.96827297,0,0,1.032767,-48.790699,-701.68513)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient4454"
|
||||
xlink:href="#linearGradient269"
|
||||
inkscape:collect="always" />
|
||||
<linearGradient
|
||||
id="linearGradient269">
|
||||
<stop
|
||||
style="stop-color:#a3a3a3;stop-opacity:1.0000000;"
|
||||
offset="0.0000000"
|
||||
id="stop270" />
|
||||
<stop
|
||||
style="stop-color:#4c4c4c;stop-opacity:1.0000000;"
|
||||
offset="1.0000000"
|
||||
id="stop271" />
|
||||
</linearGradient>
|
||||
<inkscape:perspective
|
||||
id="perspective4947"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<linearGradient
|
||||
id="linearGradient4095">
|
||||
<stop
|
||||
style="stop-color:#005bff;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop4097" />
|
||||
<stop
|
||||
style="stop-color:#c1e3f7;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop4099" />
|
||||
</linearGradient>
|
||||
<inkscape:perspective
|
||||
id="perspective5027"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective5076"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient4247"
|
||||
id="linearGradient4253"
|
||||
x1="394.15784"
|
||||
y1="185.1304"
|
||||
x2="434.73947"
|
||||
y2="140.22731"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.94231826,0,0,0.94231826,23.727549,8.8262536)" />
|
||||
<linearGradient
|
||||
id="linearGradient4247">
|
||||
<stop
|
||||
style="stop-color:#2e8207;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop4249" />
|
||||
<stop
|
||||
style="stop-color:#52ff00;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop4251" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
y2="140.22731"
|
||||
x2="434.73947"
|
||||
y1="185.1304"
|
||||
x1="394.15784"
|
||||
gradientTransform="matrix(0.94231826,0,0,0.94231826,23.727549,8.8262536)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="linearGradient5087"
|
||||
xlink:href="#linearGradient4247"
|
||||
inkscape:collect="always" />
|
||||
<inkscape:perspective
|
||||
id="perspective5141"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
</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="13.473807"
|
||||
inkscape:cy="32"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="true"
|
||||
inkscape:document-units="px"
|
||||
inkscape:grid-bbox="true"
|
||||
inkscape:window-width="1280"
|
||||
inkscape:window-height="962"
|
||||
inkscape:window-x="-8"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1" />
|
||||
<metadata
|
||||
id="metadata3617">
|
||||
<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
|
||||
transform="translate(-259.85207,-132.78349)"
|
||||
id="g4670">
|
||||
<rect
|
||||
ry="0"
|
||||
rx="0"
|
||||
y="179.57144"
|
||||
x="280.71429"
|
||||
height="9.2792215"
|
||||
width="24.688311"
|
||||
id="rect4258"
|
||||
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
|
||||
<rect
|
||||
ry="0"
|
||||
rx="0"
|
||||
y="151.57144"
|
||||
x="280.71429"
|
||||
height="9.6428576"
|
||||
width="24.688311"
|
||||
id="rect4258-1-7"
|
||||
style="color:#000000;fill:#0042ff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
|
||||
<rect
|
||||
ry="0"
|
||||
rx="0"
|
||||
y="165.38962"
|
||||
x="285.80521"
|
||||
height="9.6428576"
|
||||
width="24.324675"
|
||||
id="rect4258-1"
|
||||
style="color:#000000;fill:#9fb7ff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
|
||||
<rect
|
||||
ry="0"
|
||||
rx="0"
|
||||
y="137.57144"
|
||||
x="266.71429"
|
||||
height="9.6428576"
|
||||
width="32.142857"
|
||||
id="rect4258-1-7-4"
|
||||
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
|
||||
<path
|
||||
sodipodi:nodetypes="ccc"
|
||||
id="path5098"
|
||||
d="m 271.07143,207.42857 0,37.14286 9.28571,0"
|
||||
style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
||||
transform="translate(0,-60)" />
|
||||
<path
|
||||
transform="translate(0,-60)"
|
||||
id="path5100"
|
||||
d="m 280.89286,216.71429 -9.64286,0"
|
||||
style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
||||
d="m 275.61688,156.15584 0,14.23377 9.28571,0"
|
||||
id="path3050"
|
||||
sodipodi:nodetypes="ccc"
|
||||
inkscape:connector-curvature="0" />
|
||||
</g>
|
||||
<path
|
||||
style="fill:none;stroke:#d30000;stroke-width:2.39999999999999990;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
|
||||
d="M 53.090909,45.090909 24.454545,16.454545"
|
||||
id="path3061"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path3065"
|
||||
d="M 53.090909,16.454545 24.454545,45.090909"
|
||||
style="fill:none;stroke:#d30000;stroke-width:2.39999999999999990;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 15 KiB |
457
src/Mod/OpenSCAD/Resources/icons/OpenSCAD_ReplaceObject.svg
Normal file
457
src/Mod/OpenSCAD/Resources/icons/OpenSCAD_ReplaceObject.svg
Normal file
|
@ -0,0 +1,457 @@
|
|||
<?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="svg3612"
|
||||
version="1.1"
|
||||
inkscape:version="0.48.3.1 r9886"
|
||||
sodipodi:docname="Draft_AddToGroup.svg">
|
||||
<defs
|
||||
id="defs3614">
|
||||
<marker
|
||||
inkscape:stockid="Arrow1Mend"
|
||||
orient="auto"
|
||||
refY="0.0"
|
||||
refX="0.0"
|
||||
id="Arrow1Mend"
|
||||
style="overflow:visible;">
|
||||
<path
|
||||
id="path3835"
|
||||
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
|
||||
style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;"
|
||||
transform="scale(0.4) rotate(180) translate(10,0)" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:stockid="Arrow1Mstart"
|
||||
orient="auto"
|
||||
refY="0.0"
|
||||
refX="0.0"
|
||||
id="Arrow1Mstart"
|
||||
style="overflow:visible">
|
||||
<path
|
||||
id="path3832"
|
||||
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
|
||||
style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt"
|
||||
transform="scale(0.4) translate(10,0)" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:stockid="Arrow1Lstart"
|
||||
orient="auto"
|
||||
refY="0.0"
|
||||
refX="0.0"
|
||||
id="Arrow1Lstart"
|
||||
style="overflow:visible">
|
||||
<path
|
||||
id="path3826"
|
||||
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
|
||||
style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt"
|
||||
transform="scale(0.8) translate(12.5,0)" />
|
||||
</marker>
|
||||
<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="perspective3620" />
|
||||
<inkscape:perspective
|
||||
id="perspective3588"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3692"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<linearGradient
|
||||
id="linearGradient3144-6">
|
||||
<stop
|
||||
id="stop3146-9"
|
||||
style="stop-color:#ffffff;stop-opacity:1"
|
||||
offset="0" />
|
||||
<stop
|
||||
id="stop3148-2"
|
||||
style="stop-color:#ffffff;stop-opacity:0"
|
||||
offset="1" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient3701">
|
||||
<stop
|
||||
id="stop3703"
|
||||
style="stop-color:#ffffff;stop-opacity:1"
|
||||
offset="0" />
|
||||
<stop
|
||||
id="stop3705"
|
||||
style="stop-color:#ffffff;stop-opacity:0"
|
||||
offset="1" />
|
||||
</linearGradient>
|
||||
<radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3144-6"
|
||||
id="radialGradient3688"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(1,0,0,0.6985294,0,202.82863)"
|
||||
cx="225.26402"
|
||||
cy="672.79736"
|
||||
fx="225.26402"
|
||||
fy="672.79736"
|
||||
r="34.345188" />
|
||||
<linearGradient
|
||||
id="linearGradient3708">
|
||||
<stop
|
||||
id="stop3710"
|
||||
style="stop-color:#ffffff;stop-opacity:1"
|
||||
offset="0" />
|
||||
<stop
|
||||
id="stop3712"
|
||||
style="stop-color:#ffffff;stop-opacity:0"
|
||||
offset="1" />
|
||||
</linearGradient>
|
||||
<inkscape:perspective
|
||||
id="perspective3805"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<linearGradient
|
||||
id="linearGradient3864-0-0">
|
||||
<stop
|
||||
id="stop3866-5-7"
|
||||
offset="0"
|
||||
style="stop-color:#0619c0;stop-opacity:1;" />
|
||||
<stop
|
||||
id="stop3868-7-6"
|
||||
offset="1"
|
||||
style="stop-color:#379cfb;stop-opacity:1;" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient3377">
|
||||
<stop
|
||||
id="stop3379"
|
||||
offset="0"
|
||||
style="stop-color:#ffaa00;stop-opacity:1;" />
|
||||
<stop
|
||||
id="stop3381"
|
||||
offset="1"
|
||||
style="stop-color:#faff2b;stop-opacity:1;" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient3864-0">
|
||||
<stop
|
||||
id="stop3866-5"
|
||||
offset="0"
|
||||
style="stop-color:#0619c0;stop-opacity:1;" />
|
||||
<stop
|
||||
id="stop3868-7"
|
||||
offset="1"
|
||||
style="stop-color:#379cfb;stop-opacity:1;" />
|
||||
</linearGradient>
|
||||
<inkscape:perspective
|
||||
id="perspective3902"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<linearGradient
|
||||
id="linearGradient5048">
|
||||
<stop
|
||||
style="stop-color:black;stop-opacity:0;"
|
||||
offset="0"
|
||||
id="stop5050" />
|
||||
<stop
|
||||
id="stop5056"
|
||||
offset="0.5"
|
||||
style="stop-color:black;stop-opacity:1;" />
|
||||
<stop
|
||||
style="stop-color:black;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop5052" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient3841-0-3">
|
||||
<stop
|
||||
id="stop3843-1-3"
|
||||
offset="0"
|
||||
style="stop-color:#0619c0;stop-opacity:1;" />
|
||||
<stop
|
||||
id="stop3845-0-8"
|
||||
offset="1"
|
||||
style="stop-color:#379cfb;stop-opacity:1;" />
|
||||
</linearGradient>
|
||||
<radialGradient
|
||||
gradientUnits="userSpaceOnUse"
|
||||
fy="114.5684"
|
||||
fx="20.892099"
|
||||
r="5.256"
|
||||
cy="114.5684"
|
||||
cx="20.892099"
|
||||
id="aigrd2">
|
||||
<stop
|
||||
id="stop15566"
|
||||
style="stop-color:#F0F0F0"
|
||||
offset="0" />
|
||||
<stop
|
||||
id="stop15568"
|
||||
style="stop-color:#9a9a9a;stop-opacity:1.0000000;"
|
||||
offset="1.0000000" />
|
||||
</radialGradient>
|
||||
<radialGradient
|
||||
gradientUnits="userSpaceOnUse"
|
||||
fy="64.567902"
|
||||
fx="20.892099"
|
||||
r="5.257"
|
||||
cy="64.567902"
|
||||
cx="20.892099"
|
||||
id="aigrd3">
|
||||
<stop
|
||||
id="stop15573"
|
||||
style="stop-color:#F0F0F0"
|
||||
offset="0" />
|
||||
<stop
|
||||
id="stop15575"
|
||||
style="stop-color:#9a9a9a;stop-opacity:1.0000000;"
|
||||
offset="1.0000000" />
|
||||
</radialGradient>
|
||||
<linearGradient
|
||||
id="linearGradient15662">
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:1.0000000;"
|
||||
offset="0.0000000"
|
||||
id="stop15664" />
|
||||
<stop
|
||||
style="stop-color:#f8f8f8;stop-opacity:1.0000000;"
|
||||
offset="1.0000000"
|
||||
id="stop15666" />
|
||||
</linearGradient>
|
||||
<radialGradient
|
||||
r="86.70845"
|
||||
fy="35.736916"
|
||||
fx="33.966679"
|
||||
cy="35.736916"
|
||||
cx="33.966679"
|
||||
gradientTransform="matrix(0.96049297,0,0,1.041132,-52.144249,-702.33158)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient4452"
|
||||
xlink:href="#linearGradient259"
|
||||
inkscape:collect="always" />
|
||||
<linearGradient
|
||||
id="linearGradient259">
|
||||
<stop
|
||||
style="stop-color:#fafafa;stop-opacity:1.0000000;"
|
||||
offset="0.0000000"
|
||||
id="stop260" />
|
||||
<stop
|
||||
style="stop-color:#bbbbbb;stop-opacity:1.0000000;"
|
||||
offset="1.0000000"
|
||||
id="stop261" />
|
||||
</linearGradient>
|
||||
<radialGradient
|
||||
r="37.751713"
|
||||
fy="3.7561285"
|
||||
fx="8.824419"
|
||||
cy="3.7561285"
|
||||
cx="8.824419"
|
||||
gradientTransform="matrix(0.96827297,0,0,1.032767,-48.790699,-701.68513)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient4454"
|
||||
xlink:href="#linearGradient269"
|
||||
inkscape:collect="always" />
|
||||
<linearGradient
|
||||
id="linearGradient269">
|
||||
<stop
|
||||
style="stop-color:#a3a3a3;stop-opacity:1.0000000;"
|
||||
offset="0.0000000"
|
||||
id="stop270" />
|
||||
<stop
|
||||
style="stop-color:#4c4c4c;stop-opacity:1.0000000;"
|
||||
offset="1.0000000"
|
||||
id="stop271" />
|
||||
</linearGradient>
|
||||
<inkscape:perspective
|
||||
id="perspective4947"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<linearGradient
|
||||
id="linearGradient4095">
|
||||
<stop
|
||||
style="stop-color:#005bff;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop4097" />
|
||||
<stop
|
||||
style="stop-color:#c1e3f7;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop4099" />
|
||||
</linearGradient>
|
||||
<inkscape:perspective
|
||||
id="perspective5027"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective5076"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient4247"
|
||||
id="linearGradient4253"
|
||||
x1="394.15784"
|
||||
y1="185.1304"
|
||||
x2="434.73947"
|
||||
y2="140.22731"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.94231826,0,0,0.94231826,23.727549,8.8262536)" />
|
||||
<linearGradient
|
||||
id="linearGradient4247">
|
||||
<stop
|
||||
style="stop-color:#2e8207;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop4249" />
|
||||
<stop
|
||||
style="stop-color:#52ff00;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop4251" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
y2="140.22731"
|
||||
x2="434.73947"
|
||||
y1="185.1304"
|
||||
x1="394.15784"
|
||||
gradientTransform="matrix(0.94231826,0,0,0.94231826,23.727549,8.8262536)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="linearGradient5087"
|
||||
xlink:href="#linearGradient4247"
|
||||
inkscape:collect="always" />
|
||||
<inkscape:perspective
|
||||
id="perspective5141"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
</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="-2.8181818"
|
||||
inkscape:cy="32"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="true"
|
||||
inkscape:document-units="px"
|
||||
inkscape:grid-bbox="true"
|
||||
inkscape:window-width="1366"
|
||||
inkscape:window-height="706"
|
||||
inkscape:window-x="-8"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1" />
|
||||
<metadata
|
||||
id="metadata3617">
|
||||
<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
|
||||
transform="translate(-259.85207,-132.78349)"
|
||||
id="g4670">
|
||||
<rect
|
||||
ry="0"
|
||||
rx="0"
|
||||
y="179.57144"
|
||||
x="280.71429"
|
||||
height="9.2792215"
|
||||
width="24.688311"
|
||||
id="rect4258"
|
||||
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
|
||||
<rect
|
||||
ry="0"
|
||||
rx="0"
|
||||
y="151.57144"
|
||||
x="280.71429"
|
||||
height="9.6428576"
|
||||
width="24.688311"
|
||||
id="rect4258-1-7"
|
||||
style="color:#000000;fill:#0042ff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
|
||||
<rect
|
||||
ry="0"
|
||||
rx="0"
|
||||
y="165.38962"
|
||||
x="285.80521"
|
||||
height="9.6428576"
|
||||
width="24.324675"
|
||||
id="rect4258-1"
|
||||
style="color:#000000;fill:#0042ff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
|
||||
<rect
|
||||
ry="0"
|
||||
rx="0"
|
||||
y="137.57144"
|
||||
x="266.71429"
|
||||
height="9.6428576"
|
||||
width="32.142857"
|
||||
id="rect4258-1-7-4"
|
||||
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
|
||||
<path
|
||||
sodipodi:nodetypes="ccc"
|
||||
id="path5098"
|
||||
d="m 271.07143,207.42857 0,37.14286 9.28571,0"
|
||||
style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
||||
transform="translate(0,-60)" />
|
||||
<path
|
||||
transform="translate(0,-60)"
|
||||
id="path5100"
|
||||
d="m 280.89286,216.71429 -9.64286,0"
|
||||
style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
||||
d="m 275.61688,156.15584 0,14.23377 9.28571,0"
|
||||
id="path3050"
|
||||
sodipodi:nodetypes="ccc"
|
||||
inkscape:connector-curvature="0" />
|
||||
</g>
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#Arrow1Mstart);marker-end:url(#Arrow1Mend)"
|
||||
d="m 52.363636,24 c 7.198529,0.420502 8.668453,-1.886663 8.727273,6.181818 0.05882,8.068481 -0.801204,6.872738 -7.818182,6.727273"
|
||||
id="path3820"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="czc" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 15 KiB |
1368
src/Mod/OpenSCAD/Resources/icons/preferences-openscad.svg
Normal file
1368
src/Mod/OpenSCAD/Resources/icons/preferences-openscad.svg
Normal file
File diff suppressed because it is too large
Load Diff
After Width: | Height: | Size: 45 KiB |
547
src/Mod/OpenSCAD/Resources/ui/openscadprefs-base.ui
Normal file
547
src/Mod/OpenSCAD/Resources/ui/openscadprefs-base.ui
Normal file
|
@ -0,0 +1,547 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>Gui::Dialog::DlgSettingsOpenSCAD</class>
|
||||
<widget class="QWidget" name="Gui::Dialog::DlgSettingsOpenSCAD">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>575</width>
|
||||
<height>629</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>General settings</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout">
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>General OpenSCAD Settings</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QLabel" name="fclabel">
|
||||
<property name="text">
|
||||
<string>OpenSCAD executable</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Gui::PrefFileChooser" name="gui::preffilechooser" native="true">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>300</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>The path to the OpenSCAD executeable</string>
|
||||
</property>
|
||||
<property name="prefEntry" stdset="0">
|
||||
<cstring>openscadexecutable</cstring>
|
||||
</property>
|
||||
<property name="prefPath" stdset="0">
|
||||
<cstring>Mod/OpenSCAD</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_2">
|
||||
<property name="title">
|
||||
<string>OpenSCAD import</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_5">
|
||||
<item>
|
||||
<widget class="Gui::PrefCheckBox" name="gui::prefcheckboxviewtreeprovider">
|
||||
<property name="toolTip">
|
||||
<string>If this is checked, Features will claim thier children in the tree view</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Use ViewProvider in Tree View</string>
|
||||
</property>
|
||||
<property name="prefEntry" stdset="0">
|
||||
<cstring>useViewProviderTree</cstring>
|
||||
</property>
|
||||
<property name="prefPath" stdset="0">
|
||||
<cstring>Mod/OpenSCAD</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_6">
|
||||
<item>
|
||||
<widget class="Gui::PrefCheckBox" name="gui::prefcheckboxmultmatrixfeature">
|
||||
<property name="toolTip">
|
||||
<string>If this is checked, Multmatrix Object will be Parametric</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Use Multmatrix Feature</string>
|
||||
</property>
|
||||
<property name="prefEntry" stdset="0">
|
||||
<cstring>useMultmatrixFeature</cstring>
|
||||
</property>
|
||||
<property name="prefPath" stdset="0">
|
||||
<cstring>Mod/OpenSCAD</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_7">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_12">
|
||||
<property name="toolTip">
|
||||
<string>The maximum number of faces of a polygon, prism or frustum. If fn is greater than this value the object is considered to be a circular. Set to 0 for no limit</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Maximum number of faces for polygons (fn)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Gui::PrefSpinBox" name="gui::prefmaxfnsp">
|
||||
<property name="toolTip">
|
||||
<string>The maximum number of faces of a polygon, prism or frustum. If fn is greater than this value the object is considered to be a circular. Set to 0 for no limit</string>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="prefEntry" stdset="0">
|
||||
<cstring>useMaxFN</cstring>
|
||||
</property>
|
||||
<property name="prefPath" stdset="0">
|
||||
<cstring>Mod/OpenSCAD</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_8">
|
||||
<item>
|
||||
<widget class="Gui::PrefCheckBox" name="gui::prefcheckboxmultmatrixfeature">
|
||||
<property name="toolTip">
|
||||
<string>Debug: Register filetype to prototype importer</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Debug: Register filetype to prototype importer</string>
|
||||
</property>
|
||||
<property name="prefEntry" stdset="0">
|
||||
<cstring>debugRegisterPrototype</cstring>
|
||||
</property>
|
||||
<property name="prefPath" stdset="0">
|
||||
<cstring>Mod/OpenSCAD</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_3">
|
||||
<property name="title">
|
||||
<string>OpenSCAD export</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_21">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_21">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>maximum fragment size</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="toolTip">
|
||||
<string>minimum angle for a fragment</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>angular (fa)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Gui::PrefDoubleSpinBox" name="doubleSpinBox_2">
|
||||
<property name="toolTip">
|
||||
<string>minimum angle for a fragment</string>
|
||||
</property>
|
||||
<property name="suffix">
|
||||
<string>°</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<double>0.010000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>360.000000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>12.000000000000000</double>
|
||||
</property>
|
||||
<property name="prefEntry" stdset="0">
|
||||
<cstring>exportFa</cstring>
|
||||
</property>
|
||||
<property name="prefPath" stdset="0">
|
||||
<cstring>Mod/OpenSCAD</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="toolTip">
|
||||
<string>minimum size of a fragment</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>size (fs)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Gui::PrefDoubleSpinBox" name="doubleSpinBox_3">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>minimum size of a fragment</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="suffix">
|
||||
<string>mm</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<double>0.010000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>10000.000000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>2.000000000000000</double>
|
||||
</property>
|
||||
<property name="prefEntry" stdset="0">
|
||||
<cstring>exportFs</cstring>
|
||||
</property>
|
||||
<property name="prefPath" stdset="0">
|
||||
<cstring>Mod/OpenSCAD</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>convexity</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Gui::PrefSpinBox" name="spinBox">
|
||||
<property name="value">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="prefEntry" stdset="0">
|
||||
<cstring>exportConvexity</cstring>
|
||||
</property>
|
||||
<property name="prefPath" stdset="0">
|
||||
<cstring>Mod/OpenSCAD</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Mesh fallback</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<spacer name="horizontalSpacer_21">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QLabel" name="label_3m">
|
||||
<property name="toolTip">
|
||||
<string>Maxium Length</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>MaxLength</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="Gui::PrefDoubleSpinBox" name="doubleSpinBox_2l">
|
||||
<property name="toolTip">
|
||||
<string>Maximum Length</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<double>0.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>1000.000000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>1.000000000000000</double>
|
||||
</property>
|
||||
<property name="prefEntry" stdset="0">
|
||||
<cstring>meshmaxlength</cstring>
|
||||
</property>
|
||||
<property name="prefPath" stdset="0">
|
||||
<cstring>Mod/OpenSCAD</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="3">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="toolTip">
|
||||
<string>Maximum Area</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>maxArea</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="3">
|
||||
<widget class="Gui::PrefDoubleSpinBox" name="doubleSpinBox_2a">
|
||||
<property name="toolTip">
|
||||
<string>Maximum Area</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<double>0.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>1000.000000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>0.000000000000000</double>
|
||||
</property>
|
||||
<property name="prefEntry" stdset="0">
|
||||
<cstring>meshmaxarea</cstring>
|
||||
</property>
|
||||
<property name="prefPath" stdset="0">
|
||||
<cstring>Mod/OpenSCAD</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="4">
|
||||
<widget class="Gui::PrefDoubleSpinBox" name="doubleSpinBox_ll">
|
||||
<property name="toolTip">
|
||||
<string>Local Length</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<double>0.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>1000.000000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>0.000000000000000</double>
|
||||
</property>
|
||||
<property name="prefEntry" stdset="0">
|
||||
<cstring>meshlocallen</cstring>
|
||||
</property>
|
||||
<property name="prefPath" stdset="0">
|
||||
<cstring>Mod/OpenSCAD</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="4">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="toolTip">
|
||||
<string>Local Length</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>localLen</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="5">
|
||||
<widget class="Gui::PrefDoubleSpinBox" name="doubleSpinBox_2a">
|
||||
<property name="toolTip">
|
||||
<string>Deflection</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<double>0.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>1000.000000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>0.000000000000000</double>
|
||||
</property>
|
||||
<property name="prefEntry" stdset="0">
|
||||
<cstring>meshdeflection</cstring>
|
||||
</property>
|
||||
<property name="prefPath" stdset="0">
|
||||
<cstring>Mod/OpenSCAD</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="5">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="toolTip">
|
||||
<string>Deflection</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>deflection</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>Triangulation settings</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<layoutdefault spacing="6" margin="11"/>
|
||||
<pixmapfunction>qPixmapFromMimeSource</pixmapfunction>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>Gui::FileChooser</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>Gui/FileDialog.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>Gui::PrefFileChooser</class>
|
||||
<extends>Gui::FileChooser</extends>
|
||||
<header>Gui/PrefWidgets.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>Gui::PrefSpinBox</class>
|
||||
<extends>QSpinBox</extends>
|
||||
<header>Gui/PrefWidgets.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>Gui::PrefCheckBox</class>
|
||||
<extends>QCheckBox</extends>
|
||||
<header>Gui/PrefWidgets.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>Gui::PrefDoubleSpinBox</class>
|
||||
<extends>QDoubleSpinBox</extends>
|
||||
<header>Gui/PrefWidgets.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
5
src/Mod/OpenSCAD/TODO
Normal file
5
src/Mod/OpenSCAD/TODO
Normal file
|
@ -0,0 +1,5 @@
|
|||
Makefiles (get the python files included)
|
||||
Copyright notices (Ply is BSD, everything Keith did is GPL, most of the stuff from freecad is LGPL)
|
||||
Make filenames unique, e.g. prepepend module name
|
||||
Add a gui command for the Refine Shape feature.
|
||||
Add a gui command for subtractfaces2.
|
81
src/Mod/OpenSCAD/colorcodeshapes.py
Normal file
81
src/Mod/OpenSCAD/colorcodeshapes.py
Normal file
|
@ -0,0 +1,81 @@
|
|||
import FreeCAD
|
||||
def shapedict(shapelst):
|
||||
return dict([(shape.hashCode(),shape) for shape in shapelst])
|
||||
|
||||
def shapeset(shapelst):
|
||||
return set([shape.hashCode() for shape in shapelst])
|
||||
|
||||
def mostbasiccompound(comp):
|
||||
'''searches fo the most basic shape in a Compound'''
|
||||
solids=shapeset(comp.Solids)
|
||||
shells=shapeset(comp.Shells)
|
||||
faces=shapeset(comp.Faces)
|
||||
wires=shapeset(comp.Wires)
|
||||
edges=shapeset(comp.Edges)
|
||||
vertexes=shapeset(comp.Vertexes)
|
||||
#FreeCAD.Console.PrintMessage('%s\n' % (str((len(solids),len(shells),len(faces),len(wires),len(edges),len(vertexes)))))
|
||||
for shape in comp.Solids:
|
||||
shells -= shapeset(shape.Shells)
|
||||
faces -= shapeset(shape.Faces)
|
||||
wires -= shapeset(shape.Wires)
|
||||
edges -= shapeset(shape.Edges)
|
||||
vertexes -= shapeset(shape.Vertexes)
|
||||
for shape in comp.Shells:
|
||||
faces -= shapeset(shape.Faces)
|
||||
wires -= shapeset(shape.Wires)
|
||||
edges -= shapeset(shape.Edges)
|
||||
vertexes -= shapeset(shape.Vertexes)
|
||||
for shape in comp.Faces:
|
||||
wires -= shapeset(shape.Wires)
|
||||
edges -= shapeset(shape.Edges)
|
||||
vertexes -= shapeset(shape.Vertexes)
|
||||
for shape in comp.Wires:
|
||||
edges -= shapeset(shape.Edges)
|
||||
vertexes -= shapeset(shape.Vertexes)
|
||||
for shape in comp.Edges:
|
||||
vertexes -= shapeset(shape.Vertexes)
|
||||
#FreeCAD.Console.PrintMessage('%s\n' % (str((len(solids),len(shells),len(faces),len(wires),len(edges),len(vertexes)))))
|
||||
#return len(solids),len(shells),len(faces),len(wires),len(edges),len(vertexes)
|
||||
if vertexes:
|
||||
return "Vertex"
|
||||
elif edges:
|
||||
return "Edge"
|
||||
elif wires:
|
||||
return "Wire"
|
||||
elif faces:
|
||||
return "Face"
|
||||
elif shells:
|
||||
return "Shell"
|
||||
elif solids:
|
||||
return "Solid"
|
||||
|
||||
def colorcodeshapes(objs):
|
||||
shapecolors={
|
||||
"Compound":(0.3,0.3,0.4),
|
||||
"CompSolid":(0.1,0.5,0.0),
|
||||
"Solid":(0.0,0.8,0.0),
|
||||
"Shell":(0.8,0.0,0.0),
|
||||
"Face":(0.6,0.6,0.0),
|
||||
"Wire":(0.1,0.1,0.1),
|
||||
"Edge":(1.0,1.0,1.0),
|
||||
"Vertex":(8.0,8.0,8.0),
|
||||
"Shape":(0.0,0.0,1.0),
|
||||
None:(0.0,0.0,0.0)}
|
||||
|
||||
for obj in objs:
|
||||
if hasattr(obj,'Shape'):
|
||||
try:
|
||||
if obj.Shape.isNull():
|
||||
continue
|
||||
if not obj.Shape.isValid():
|
||||
color=(1.0,0.4,0.4)
|
||||
else:
|
||||
st=obj.Shape.ShapeType
|
||||
if st in ["Compound","CompSolid"]:
|
||||
st = mostbasiccompound(obj.Shape)
|
||||
color=shapecolors[st]
|
||||
obj.ViewObject.ShapeColor = color
|
||||
except:
|
||||
raise
|
||||
|
||||
#colorcodeshapes(App.ActiveDocument.Objects)
|
78
src/Mod/OpenSCAD/expandplacements.py
Normal file
78
src/Mod/OpenSCAD/expandplacements.py
Normal file
|
@ -0,0 +1,78 @@
|
|||
import FreeCAD
|
||||
from OpenSCADFeatures import *
|
||||
from OpenSCADUtils import isspecialorthogonalpython,isspecialorthogonal
|
||||
import replaceobj
|
||||
|
||||
def likeprimitive(obj,extrusion=False):
|
||||
'''we can't push the matrix transformation further down'''
|
||||
return not obj.OutList or obj.isDerivedFrom('Part::Extrusion')\
|
||||
or extrusion and (obj.isDerivedFrom('Part::Revolution') \
|
||||
or obj.isDerivedFrom('Part::FeaturePython')) or \
|
||||
not obj.isDerivedFrom('Part::Feature')
|
||||
|
||||
def expandplacementsmatrix(obj,matrix):
|
||||
'''expand afine transformation down the feature tree'''
|
||||
ownmatrix=matrix.multiply(obj.Placement.toMatrix())
|
||||
if obj.isDerivedFrom('Part::Feature') and \
|
||||
isinstance(obj.Proxy,MatrixTransform):
|
||||
innermatrix=ownmatrix.multiply(obj.Matrix)
|
||||
if likeprimitive(obj.Base,True): #this matrix is needed
|
||||
obj.Placement=FreeCAD.Placement()
|
||||
obj.Matrix = innermatrix
|
||||
else: #the inner object is not a primitive
|
||||
expandplacementsmatrix(obj.Base,innermatrix)
|
||||
#remove the matrix object
|
||||
for parent in obj.Base.InList:
|
||||
replaceobj.replaceobj(parent,obj,obj.Base)
|
||||
out.Document.removeObject(obj.Name)
|
||||
elif likeprimitive(obj,True):
|
||||
#if isspecialorthogonalpython(fcsubmatrix(ownmatrix)):
|
||||
if isspecialorthogonal(ownmatrix):
|
||||
obj.Placement=FreeCAD.Placement()
|
||||
#this should never happen unless matrices cancel out
|
||||
obj.Placement=FreeCAD.Placement(ownmatrix)
|
||||
else:
|
||||
newobj=doc.addObject("Part::FeaturePython",'exp_trans')
|
||||
MatrixTransform(newobj,ownmatrix,obj) #This object is not mutable GUI
|
||||
ViewProviderTree(newobj.ViewObject)
|
||||
for parent in obj.InList:
|
||||
replaceobj.replaceobj(parent,obj,newobj) # register the new object in the feature tree
|
||||
obj.Placement=FreeCAD.Placement()
|
||||
else: #not a primitive
|
||||
for outobj in obj.OutList:
|
||||
if outobj.isDerivedFrom('Part::Feature') and \
|
||||
isinstance(obj.Proxy,MatrixTransform):
|
||||
newmatrix = ownmatrix.multiply(obj.Matrix).multiply(\
|
||||
outobj.Base.Placement.toMatrix())
|
||||
if likeprimitive(outobj.Base,True): #child of is like primtitive
|
||||
outobj.Matrix = newmatrix
|
||||
outobj.Base.Placement=FreeCAD.Placement()
|
||||
else: #remove the MatrixTranformation
|
||||
plainobj=outobj.Base
|
||||
for parent in outobj.InList:
|
||||
replaceobj.replaceobj(parent,outobj,plainobj)
|
||||
outobj.Document.removeObject(outobj.Name)
|
||||
expandplacementsmatrix(outobj,newmatrix)
|
||||
else:
|
||||
expandplacementsmatrix(outobj,ownmatrix)
|
||||
obj.Placement=FreeCAD.Placement()
|
||||
|
||||
|
||||
def expandplacements(obj,placement):
|
||||
ownplacement=placement.multiply(obj.Placement)
|
||||
if obj.isDerivedFrom('Part::FeaturePython') and isinstance(obj.Proxy,MatrixTransform):
|
||||
#expandplacementsmatrix(obj,ownplacement.toMatrix())
|
||||
expandplacementsmatrix(obj,placement.toMatrix())
|
||||
elif likeprimitive(obj,False):
|
||||
obj.Placement=ownplacement
|
||||
else:
|
||||
for outobj in obj.OutList:
|
||||
if obj.isDerivedFrom('Part::Extrusion'):
|
||||
obj.Dir=ownplacement.Rotation.multVec(obj.Dir)
|
||||
elif obj.isDerivedFrom('Part::Revolution'):
|
||||
obj.Axis=ownplacement.Rotation.multVec(obj.Axis)
|
||||
#obj.Base=ownplacement.Rotation.multVec(obj.Base)
|
||||
expandplacements(outobj,ownplacement)
|
||||
obj.Placement=FreeCAD.Placement()
|
||||
|
||||
#expandplacements(rootobj,FreeCAD.Placement())
|
260
src/Mod/OpenSCAD/exportCSG.py
Normal file
260
src/Mod/OpenSCAD/exportCSG.py
Normal file
|
@ -0,0 +1,260 @@
|
|||
|
||||
#***************************************************************************
|
||||
#* *
|
||||
#* Copyright (c) 2012 Keith Sloan <keith@sloan-home.co.uk> *
|
||||
#* *
|
||||
#* This program is free software; you can redistribute it and/or modify *
|
||||
#* it under the terms of the GNU General Public License (GPL) *
|
||||
#* as published by the Free Software Foundation; either version 2 of *
|
||||
#* the License, or (at your option) any later version. *
|
||||
#* for detail see the LICENCE text file. *
|
||||
#* *
|
||||
#* This program is distributed in the hope that it will be useful, *
|
||||
#* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
#* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
#* GNU Library General Public License for more details. *
|
||||
#* *
|
||||
#* You should have received a copy of the GNU Library General Public *
|
||||
#* License along with this program; if not, write to the Free Software *
|
||||
#* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
#* USA *
|
||||
#* *
|
||||
#* Acknowledgements : *
|
||||
#* *
|
||||
#* Thanks to shoogen on the FreeCAD forum for programming advice *
|
||||
#* and some code. *
|
||||
#* *
|
||||
#***************************************************************************
|
||||
__title__="FreeCAD OpenSCAD Workbench - CSG exporter Version 0.01c"
|
||||
__author__ = "Keith Sloan <keith@sloan-home.co.uk>"
|
||||
__url__ = ["http://www.sloan-home.co.uk/Export/Export.html"]
|
||||
|
||||
import FreeCAD, os, Part, math
|
||||
from FreeCAD import Vector
|
||||
|
||||
try: import FreeCADGui
|
||||
except ValueError: gui = False
|
||||
else: gui = True
|
||||
|
||||
#***************************************************************************
|
||||
# Tailor following to your requirements ( Should all be strings ) *
|
||||
#fafs = '$fa = 12, $fs = 2'
|
||||
#convexity = 'convexity = 10'
|
||||
params = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/OpenSCAD")
|
||||
fa = params.GetFloat('exportFa',12.0)
|
||||
fs = params.GetFloat('exportFs',2.0)
|
||||
conv = params.GetInt('exportConvexity',10)
|
||||
fafs = '$fa = %f, $fs = %f' % (fa,fs)
|
||||
convexity = 'convexity = %d' % conv
|
||||
#***************************************************************************
|
||||
if open.__module__ == '__builtin__':
|
||||
pythonopen = open
|
||||
|
||||
def check_center(ob):
|
||||
# Only say center = false if no rotation and no displacement
|
||||
if ob.Placement.isNull():
|
||||
return 'false'
|
||||
return 'true'
|
||||
|
||||
def center(b):
|
||||
if b == 0 :
|
||||
return 'false'
|
||||
return 'true'
|
||||
|
||||
def check_multmatrix(csg,ob,x,y,z):
|
||||
v = FreeCAD.Vector(0,0,1)
|
||||
b = FreeCAD.Vector(x,y,z)
|
||||
if ( ob.Placement.Base == FreeCAD.Vector(0,0,0)):
|
||||
return 0 # center = false no mm
|
||||
elif not ob.Placement.isNull():
|
||||
print "Output Multmatrix"
|
||||
m = ob.Placement.toMatrix()
|
||||
# adjust position for center displacments
|
||||
csg.write("multmatrix([["+str(m.A11)+", "+str(m.A12)+", "+str(m.A13)+", "+str(m.A14)+"], ["\
|
||||
+str(m.A21)+", "+str(m.A22)+", "+str(m.A23)+", "+str(m.A24)+"], ["\
|
||||
+str(m.A31)+", "+str(m.A32)+", "+str(m.A33)+", "+str(m.A34)+"], [ 0, 0, 0, 1]]){\n")
|
||||
return 1 # center = true and mm
|
||||
return 2 # center = true and no mm
|
||||
|
||||
def mesh2polyhedron(mesh):
|
||||
pointstr=','.join(['[%f,%f,%f]' % tuple(vec) for vec in mesh.Topology[0]])
|
||||
trianglestr=','.join(['[%d,%d,%d]' % tuple(tri) for tri in mesh.Topology[1]])
|
||||
return 'polyhedron ( points = [%s], triangles = [%s]);' % (pointstr,trianglestr)
|
||||
|
||||
def vector2d(v):
|
||||
return [v[0],v[1]]
|
||||
|
||||
def vertexs2polygon(vertex):
|
||||
pointstr=','.join(['[%f, %f]' % tuple(vector2d(v.Point)) for v in vertex])
|
||||
return 'polygon ( points = [%s], paths = undef, convexity = 1);}' % pointstr
|
||||
|
||||
def shape2polyhedron(shape):
|
||||
import MeshPart
|
||||
fa = params.GetFloat('exportFa',12.0)
|
||||
return mesh2polyhedron(MeshPart.meshFromShape(shape,params.GetFloat(\
|
||||
'meshmaxlength',1.0), params.GetFloat('meshmaxarea',0.0),\
|
||||
params.GetFloat('meshlocallen',0.0),\
|
||||
params.GetFloat('meshdeflection',0.0)))
|
||||
|
||||
def process_object(csg,ob):
|
||||
|
||||
print "Placement"
|
||||
print "Pos : "+str(ob.Placement.Base)
|
||||
print "axis : "+str(ob.Placement.Rotation.Axis)
|
||||
print "angle : "+str(ob.Placement.Rotation.Angle)
|
||||
|
||||
if ob.Type == "Part::Sphere" :
|
||||
print "Sphere Radius : "+str(ob.Radius)
|
||||
check_multmatrix(csg,ob,0,0,0)
|
||||
global fafs
|
||||
csg.write("sphere($fn = 0, "+fafs+", r = "+str(ob.Radius)+");\n")
|
||||
|
||||
elif ob.Type == "Part::Box" :
|
||||
print "cube : ("+ str(ob.Length)+","+str(ob.Width)+","+str(ob.Height)+")"
|
||||
mm = check_multmatrix(csg,ob,-ob.Length/2,-ob.Width/2,-ob.Height/2)
|
||||
csg.write("cube (size = ["+str(ob.Length)+", "+str(ob.Width)+", "+str(ob.Height)+"], center = "+center(mm)+");\n")
|
||||
if mm == 1 : csg.write("}\n")
|
||||
|
||||
elif ob.Type == "Part::Cylinder" :
|
||||
print "cylinder : Height "+str(ob.Height)+ " Radius "+str(ob.Radius)
|
||||
mm = check_multmatrix(csg,ob,0,0,-ob.Height/2)
|
||||
global fafs
|
||||
csg.write("cylinder($fn = 0, "+fafs+", h = "+str(ob.Height)+ ", r1 = "+str(ob.Radius)+\
|
||||
", r2 = " + str(ob.Radius) + ", center = "+center(mm)+");\n")
|
||||
if mm == 1 : csg.write("}\n")
|
||||
|
||||
elif ob.Type == "Part::Cone" :
|
||||
print "cone : Height "+str(ob.Height)+ " Radius1 "+str(ob.Radius1)+" Radius2 "+str(ob.Radius2)
|
||||
mm = check_multmatrix(csg,ob,0,0,-ob.Height/2)
|
||||
global fafs
|
||||
csg.write("cylinder($fn = 0, "+fafs+", h = "+str(ob.Height)+ ", r1 = "+str(ob.Radius1)+\
|
||||
", r2 = "+str(ob.Radius2)+", center = "+center(mm)+");\n")
|
||||
if mm == 1 : csg.write("}\n")
|
||||
|
||||
elif ob.Type == "Part::Torus" :
|
||||
print "Torus"
|
||||
print ob.Radius1
|
||||
print ob.Radius2
|
||||
if ob.Angle3 == 360.00 :
|
||||
mm = check_multmatrix(csg,ob,0,0,0)
|
||||
global fafs
|
||||
csg.write("rotate_extrude("+convexity+", $fn = 0, "+fafs+")\n")
|
||||
csg.write("multmatrix([[1, 0, 0, "+str(ob.Radius1)+"], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]])\n")
|
||||
csg.write("circle($fn = 0, "+fafs+", r = "+str(ob.Radius2)+");\n")
|
||||
if mm == 1 : csg.write("}\n")
|
||||
else : # Cannot convert to rotate extrude so best effort is polyhedron
|
||||
csg.write('%s\n' % shape2polyhedron(ob.Shape))
|
||||
|
||||
elif ob.Type == "Part::Extrusion" :
|
||||
print "Extrusion"
|
||||
print ob.Base
|
||||
print ob.Base.Name
|
||||
#if ( ob.Base == "Part::FeaturePython" and ob.Base.Name == "Polygon") :
|
||||
if ob.Base.Name == "Polygon" :
|
||||
f = str(ob.Base.FacesNumber)
|
||||
r = str(ob.Base.Radius)
|
||||
h = str(ob.Dir[2])
|
||||
print "Faces : " + f
|
||||
print "Radius : " + r
|
||||
print "Height : " + h
|
||||
mm = check_multmatrix(csg,ob,0,0,-float(h)/2)
|
||||
global fafs
|
||||
csg.write("cylinder($fn = "+f+", "+fafs+", h = "+h+", r1 = "+r+\
|
||||
", r2 = "+r+", center = "+center(mm)+");\n")
|
||||
if mm == 1: csg.write("}\n")
|
||||
|
||||
elif ob.Base.Name == "circle" :
|
||||
r = str(ob.Base.Radius)
|
||||
h = str(ob.Dir[2])
|
||||
print "Radius : " + r
|
||||
print "Height : " + h
|
||||
mm = check_multmatrix(csg,ob,0,0,-float(h)/2)
|
||||
global fafs
|
||||
csg.write("cylinder($fn = 0, "+fafs+", h = "+h+", r1 = "+r+\
|
||||
", r2 = "+r+", center = "+center(mm)+");\n")
|
||||
if mm == 1: csg.write("}\n")
|
||||
|
||||
elif ob.Base.Name == "Wire" :
|
||||
print "Wire extrusion"
|
||||
print ob.Base
|
||||
mm = check_multmatrix(csg,ob,0,0,0)
|
||||
global fafs
|
||||
csg.write("linear_extrude(height = "+str(ob.Dir[2])+", center = "+center(mm)+", "+convexity+", twist = 0, slices = 2, $fn = 0, "+fafs+")\n{\n")
|
||||
csg.write(vertexs2polygon(ob.Base.Shape.Vertexes))
|
||||
if mm == 1: csg.write("}\n")
|
||||
|
||||
elif ob.Base.Name == "square" :
|
||||
mm = check_multmatrix(csg,ob,0,0,0)
|
||||
global fafs
|
||||
csg.write("linear_extrude(height = "+str(ob.Dir[2])+", center = true, "+convexity+", twist = 0, slices = 2, $fn = 0, "+fafs+")\n{\n")
|
||||
csg.write("square (size = ["+str(ob.Base.Length)+", "+str(ob.Base.Width)+"],center = "+center(mm)+";\n}\n")
|
||||
if mm == 1: csg.write("}\n")
|
||||
|
||||
elif ob.Type == "Part::Cut" :
|
||||
print "Cut"
|
||||
csg.write("difference() {\n")
|
||||
process_object(csg,ob.Base)
|
||||
process_object(csg,ob.Tool)
|
||||
csg.write("}\n")
|
||||
|
||||
elif ob.Type == "Part::Fuse" :
|
||||
print "union"
|
||||
csg.write("union() {\n")
|
||||
process_object(csg,ob.Base)
|
||||
process_object(csg,ob.Tool)
|
||||
csg.write("}\n")
|
||||
|
||||
elif ob.Type == "Part::Common" :
|
||||
print "intersection"
|
||||
csg.write("intersection() {\n")
|
||||
process_object(csg,ob.Base)
|
||||
process_object(csg,ob.Tool)
|
||||
csg.write("}\n")
|
||||
|
||||
elif ob.Type == "Part::MultiFuse" :
|
||||
print "Multi Fuse / union"
|
||||
csg.write("union() {\n")
|
||||
for subobj in ob.Shapes:
|
||||
process_object(csg,subobj)
|
||||
csg.write("}\n")
|
||||
|
||||
elif ob.Type == "Part::Common" :
|
||||
print "Multi Common / intersection"
|
||||
csg.write("intersection() {\n")
|
||||
for subobj in ob.Shapes:
|
||||
process_object(csg,subobj)
|
||||
csg.write("}\n")
|
||||
|
||||
elif ob.isDerivedFrom('Part::Feature') :
|
||||
print "Part::Feature"
|
||||
mm = check_multmatrix(csg,ob,0,0,0)
|
||||
csg.write('%s\n' % shape2polyhedron(ob.Shape))
|
||||
if mm == 1 : csg.write("}\n")
|
||||
|
||||
|
||||
|
||||
def export(exportList,filename):
|
||||
"called when freecad exports a file"
|
||||
|
||||
# process Objects
|
||||
print "\nStart Export 0.1c\n"
|
||||
print "Open Output File"
|
||||
csg = pythonopen(filename,'w')
|
||||
print "Write Inital Output"
|
||||
# Not sure if comments as per scad are allowed in csg file
|
||||
csg.write("// CSG file generated from FreeCAD Export 0.1c\n")
|
||||
#write initial group statements - not sure if required
|
||||
csg.write("group() {\n group(){\n")
|
||||
for ob in exportList:
|
||||
print ob
|
||||
print "Name : "+ob.Name
|
||||
print "Type : "+ob.Type
|
||||
print "Shape : "
|
||||
print ob.Shape
|
||||
process_object(csg,ob)
|
||||
|
||||
# write closing group braces
|
||||
csg.write("}\n}\n")
|
||||
# close file
|
||||
csg.close()
|
||||
FreeCAD.Console.PrintMessage("successfully exported "+filename)
|
18
src/Mod/OpenSCAD/exportVersions.txt
Normal file
18
src/Mod/OpenSCAD/exportVersions.txt
Normal file
|
@ -0,0 +1,18 @@
|
|||
Version History
|
||||
===============
|
||||
|
||||
0.01a - First Version
|
||||
|
||||
0.01b - Added support for polyhedron ( Thanks shoogen )
|
||||
Some support for Torus
|
||||
Some support for extruded regular polygon
|
||||
|
||||
0.01c - Support for extruded polygon, square, circle
|
||||
bug fix for polyhydron floating point - Thanks shoogen
|
||||
|
||||
|
||||
|
||||
Thanks to shoogen and Peter Li for their advice, code, support and expertise.
|
||||
|
||||
Keith Sloan
|
||||
keith@sloan-home.co.uk
|
885
src/Mod/OpenSCAD/importCSG.py
Normal file
885
src/Mod/OpenSCAD/importCSG.py
Normal file
|
@ -0,0 +1,885 @@
|
|||
# -*- coding: utf8 -*-
|
||||
|
||||
#***************************************************************************
|
||||
#* *
|
||||
#* Copyright (c) 2012 Keith Sloan <keith@sloan-home.co.uk> *
|
||||
#* *
|
||||
#* This program is free software; you can redistribute it and/or modify *
|
||||
#* it under the terms of the GNU General Public License (GPL) *
|
||||
#* as published by the Free Software Foundation; either version 2 of *
|
||||
#* the License, or (at your option) any later version. *
|
||||
#* for detail see the LICENCE text file. *
|
||||
#* *
|
||||
#* This program is distributed in the hope that it will be useful, *
|
||||
#* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
#* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
#* GNU Library General Public License for more details. *
|
||||
#* *
|
||||
#* You should have received a copy of the GNU Library General Public *
|
||||
#* License along with this program; if not, write to the Free Software *
|
||||
#* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
#* USA *
|
||||
#* *
|
||||
#* Acknowledgements : *
|
||||
#* *
|
||||
#* Thanks to shoogen on the FreeCAD forum and Peter Li *
|
||||
#* for programming advice and some code. *
|
||||
#* *
|
||||
#* *
|
||||
#***************************************************************************
|
||||
__title__="FreeCAD OpenSCAD Workbench - CSG importer Version 0.05d"
|
||||
__author__ = "Keith Sloan <keith@sloan-home.co.uk>"
|
||||
__url__ = ["http://www.sloan-home.co.uk/ImportCSG"]
|
||||
|
||||
import FreeCAD, os, sys
|
||||
import ply.lex as lex
|
||||
import ply.yacc as yacc
|
||||
import Part
|
||||
|
||||
from OpenSCADFeatures import RefineShape
|
||||
from OpenSCAD2Dgeom import *
|
||||
from OpenSCADUtils import *
|
||||
isspecialorthogonaldeterminant = isspecialorthogonalpython
|
||||
from OpenSCADFeatures import Twist
|
||||
|
||||
if open.__module__ == '__builtin__':
|
||||
pythonopen = open # to distinguish python built-in open function from the one declared here
|
||||
|
||||
# Get the token map from the lexer. This is required.
|
||||
import tokrules
|
||||
from tokrules import tokens
|
||||
|
||||
#Globals
|
||||
dxfcache = {}
|
||||
|
||||
def open(filename):
|
||||
"called when freecad opens a file."
|
||||
global doc
|
||||
global pathName
|
||||
docname = os.path.splitext(os.path.basename(filename))[0]
|
||||
doc = FreeCAD.newDocument(docname)
|
||||
if filename.lower().endswith('.scad'):
|
||||
tmpfile=callopenscad(filename)
|
||||
pathName = '' #https://github.com/openscad/openscad/issues/128
|
||||
#pathName = os.getcwd() #https://github.com/openscad/openscad/issues/128
|
||||
processcsg(tmpfile)
|
||||
os.unlink(tmpfile)
|
||||
else:
|
||||
pathName = os.path.dirname(os.path.normpath(filename))
|
||||
processcsg(filename)
|
||||
return doc
|
||||
|
||||
def insert(filename,docname):
|
||||
"called when freecad imports a file"
|
||||
global doc
|
||||
global pathName
|
||||
groupname = os.path.splitext(os.path.basename(filename))[0]
|
||||
try:
|
||||
doc=FreeCAD.getDocument(docname)
|
||||
except:
|
||||
doc=FreeCAD.newDocument(docname)
|
||||
importgroup = doc.addObject("App::DocumentObjectGroup",groupname)
|
||||
if filename.lower().endswith('.scad'):
|
||||
tmpfile=callopenscad(filename)
|
||||
pathName = '' #https://github.com/openscad/openscad/issues/128
|
||||
#pathName = os.getcwd() #https://github.com/openscad/openscad/issues/128
|
||||
processcsg(tmpfile)
|
||||
os.unlink(tmpfile)
|
||||
else:
|
||||
pathName = os.path.dirname(os.path.normpath(filename))
|
||||
processcsg(filename)
|
||||
|
||||
def processcsg(filename):
|
||||
global doc
|
||||
|
||||
print 'ImportCSG Version 0.5d'
|
||||
# Build the lexer
|
||||
print 'Start Lex'
|
||||
lex.lex(module=tokrules)
|
||||
print 'End Lex'
|
||||
|
||||
# Build the parser
|
||||
print 'Load Parser'
|
||||
# No debug out otherwise Linux has protection exception
|
||||
#parser = yacc.yacc(debug=0)
|
||||
parser = yacc.yacc(debug=0)
|
||||
print 'Parser Loaded'
|
||||
# Give the lexer some input
|
||||
#f=open('test.scad', 'r')
|
||||
f = pythonopen(filename, 'r')
|
||||
#lexer.input(f.read())
|
||||
|
||||
print 'Start Parser'
|
||||
# Swap statements to enable Parser debugging
|
||||
#result = parser.parse(f.read(),debug=1)
|
||||
result = parser.parse(f.read())
|
||||
print 'End Parser'
|
||||
print result
|
||||
FreeCAD.Console.PrintMessage('End processing CSG file')
|
||||
doc.recompute()
|
||||
#import colorcodeshapes
|
||||
#colorcodeshapes.colorcodeshapes(doc.Objects)
|
||||
|
||||
def p_block_list_(p):
|
||||
'''
|
||||
block_list : statement
|
||||
| block_list statement
|
||||
'''
|
||||
print "Block List"
|
||||
print p[1]
|
||||
if(len(p) > 2) :
|
||||
print p[2]
|
||||
p[0] = p[1] + p[2]
|
||||
else :
|
||||
p[0] = p[1]
|
||||
print "End Block List"
|
||||
|
||||
def p_group_action1(p):
|
||||
'group_action1 : group LPAREN RPAREN OBRACE block_list EBRACE'
|
||||
print "Group"
|
||||
p[0] = p[5]
|
||||
|
||||
def p_group_action2(p) :
|
||||
'group_action2 : group LPAREN RPAREN SEMICOL'
|
||||
print "Group2"
|
||||
p[0] = []
|
||||
|
||||
def p_boolean(p) :
|
||||
'''
|
||||
boolean : true
|
||||
| false
|
||||
'''
|
||||
p[0] = p[1]
|
||||
|
||||
#def p_string(p):
|
||||
# 'string : QUOTE ID QUOTE'
|
||||
# p[0] = p[2]
|
||||
|
||||
def p_stripped_string(p):
|
||||
'stripped_string : STRING'
|
||||
p[0] = p[1].strip('"')
|
||||
|
||||
def p_statement(p):
|
||||
'''statement : part
|
||||
| operation
|
||||
| multmatrix_action
|
||||
| group_action1
|
||||
| group_action2
|
||||
| color_action
|
||||
| not_supported
|
||||
'''
|
||||
p[0] = p[1]
|
||||
|
||||
def p_part(p):
|
||||
'''
|
||||
part : sphere_action
|
||||
| cylinder_action
|
||||
| cube_action
|
||||
| circle_action
|
||||
| square_action
|
||||
| polygon_action_nopath
|
||||
| polygon_action_plus_path
|
||||
| polyhedron_action
|
||||
'''
|
||||
p[0] = p[1]
|
||||
|
||||
def p_2d_point(p):
|
||||
'2d_point : OSQUARE NUMBER COMMA NUMBER ESQUARE'
|
||||
global points_list
|
||||
print "2d Point"
|
||||
p[0] = [float(p[2]),float(p[4])]
|
||||
|
||||
def p_points_list_2d(p):
|
||||
'''
|
||||
points_list_2d : 2d_point COMMA
|
||||
| points_list_2d 2d_point COMMA
|
||||
| points_list_2d 2d_point
|
||||
'''
|
||||
if p[2] == ',' :
|
||||
print "Start List"
|
||||
print p[1]
|
||||
p[0] = [p[1]]
|
||||
else :
|
||||
print p[1]
|
||||
print p[2]
|
||||
p[1].append(p[2])
|
||||
p[0] = p[1]
|
||||
print p[0]
|
||||
|
||||
def p_3d_point(p):
|
||||
'3d_point : OSQUARE NUMBER COMMA NUMBER COMMA NUMBER ESQUARE'
|
||||
global points_list
|
||||
print "3d point"
|
||||
p[0] = [p[2],p[4],p[6]]
|
||||
|
||||
def p_points_list_3d(p):
|
||||
'''
|
||||
points_list_3d : 3d_point COMMA
|
||||
| points_list_3d 3d_point COMMA
|
||||
| points_list_3d 3d_point
|
||||
'''
|
||||
if p[2] == ',' :
|
||||
print "Start List"
|
||||
print p[1]
|
||||
p[0] = [p[1]]
|
||||
else :
|
||||
print p[1]
|
||||
print p[2]
|
||||
p[1].append(p[2])
|
||||
p[0] = p[1]
|
||||
print p[0]
|
||||
|
||||
def p_path_points(p):
|
||||
'''
|
||||
path_points : NUMBER COMMA
|
||||
| path_points NUMBER COMMA
|
||||
| path_points NUMBER
|
||||
'''
|
||||
print "Path point"
|
||||
if p[2] == ',' :
|
||||
print 'Start list'
|
||||
print p[1]
|
||||
p[0] = [int(p[1])]
|
||||
else :
|
||||
print p[1]
|
||||
print len(p[1])
|
||||
print p[2]
|
||||
p[1].append(int(p[2]))
|
||||
p[0] = p[1]
|
||||
print p[0]
|
||||
|
||||
|
||||
def p_path_list(p):
|
||||
'path_list : OSQUARE path_points ESQUARE'
|
||||
print 'Path List '
|
||||
print p[2]
|
||||
p[0] = p[2]
|
||||
|
||||
def p_path_set(p) :
|
||||
'''
|
||||
path_set : path_list
|
||||
| path_set COMMA path_list
|
||||
'''
|
||||
print 'Path Set'
|
||||
print len(p)
|
||||
if len(p) == 2 :
|
||||
p[0] = [p[1]]
|
||||
else :
|
||||
p[1].append(p[3])
|
||||
p[0] = p[1]
|
||||
print p[0]
|
||||
|
||||
def p_operation(p):
|
||||
'''
|
||||
operation : difference_action
|
||||
| intersection_action
|
||||
| union_action
|
||||
| rotate_extrude_action
|
||||
| linear_extrude_with_twist
|
||||
| linear_extrude_action2
|
||||
| rotate_extrude_file
|
||||
| import_file1
|
||||
| projection_action
|
||||
'''
|
||||
p[0] = p[1]
|
||||
|
||||
def p_not_supported(p):
|
||||
'''
|
||||
not_supported : hull
|
||||
| minkowski
|
||||
'''
|
||||
from PyQt4 import QtGui
|
||||
QtGui.QMessageBox.critical(None, "Unsupported Function : "+p[1], "Press OK")
|
||||
|
||||
def p_size_vector(p):
|
||||
'size_vector : OSQUARE NUMBER COMMA NUMBER COMMA NUMBER ESQUARE'
|
||||
print "size vector"
|
||||
p[0] = [p[2],p[4],p[6]]
|
||||
|
||||
def p_assign(p):
|
||||
'assign : ID EQ NUMBER'
|
||||
print "Assignment"
|
||||
print p[1] + ' : ' + p[3]
|
||||
p[0] = p[3]
|
||||
|
||||
def p_color_action(p):
|
||||
'color_action : color LPAREN vector RPAREN OBRACE block_list EBRACE'
|
||||
import math
|
||||
print "Color"
|
||||
color = tuple([float(f) for f in p[3][:3]]) #RGB
|
||||
transp = 100 - int(math.floor(100*float(p[3][3]))) #Alpha
|
||||
for obj in p[6]:
|
||||
obj.ViewObject.ShapeColor =color
|
||||
obj.ViewObject.Transparency = transp
|
||||
p[0] = p[6]
|
||||
|
||||
# Error rule for syntax errors
|
||||
def p_error(p):
|
||||
print "Syntax error in input!"
|
||||
print p
|
||||
|
||||
def fuse(list,name):
|
||||
global doc
|
||||
print "Fuse"
|
||||
print list
|
||||
# Is this Multi Fuse
|
||||
if ( len(list) > 2):
|
||||
print "Multi Fuse"
|
||||
myfuse = doc.addObject('Part::MultiFuse',name)
|
||||
myfuse.Shapes = list
|
||||
for subobj in myfuse.Shapes:
|
||||
subobj.ViewObject.hide()
|
||||
else :
|
||||
print "Single Fuse"
|
||||
myfuse = doc.addObject('Part::Fuse',name)
|
||||
myfuse.Base = list[0]
|
||||
myfuse.Tool = list[1]
|
||||
myfuse.Base.ViewObject.hide()
|
||||
myfuse.Tool.ViewObject.hide()
|
||||
return(myfuse)
|
||||
|
||||
def p_union_action(p):
|
||||
'union_action : union LPAREN RPAREN OBRACE block_list EBRACE'
|
||||
print "union"
|
||||
newpart = fuse(p[5],p[1])
|
||||
print "Push Union Result"
|
||||
p[0] = [newpart]
|
||||
print "End Union"
|
||||
|
||||
def p_difference_action(p):
|
||||
'difference_action : difference LPAREN RPAREN OBRACE block_list EBRACE'
|
||||
|
||||
print "difference"
|
||||
print len(p[5])
|
||||
print p[5]
|
||||
|
||||
mycut = doc.addObject('Part::Cut',p[1])
|
||||
# Cut using Fuse
|
||||
mycut.Base = p[5][0]
|
||||
# Can only Cut two objects do we need to fuse extras
|
||||
if (len(p[5]) > 2 ):
|
||||
print "Need to Fuse Extra First"
|
||||
mycut.Tool = fuse(p[5][1:],'union')
|
||||
else :
|
||||
mycut.Tool = p[5][1]
|
||||
mycut.Base.ViewObject.hide()
|
||||
mycut.Tool.ViewObject.hide()
|
||||
print "Push Resulting Cut"
|
||||
p[0] = [mycut]
|
||||
print "End Cut"
|
||||
|
||||
def p_intersection_action(p):
|
||||
'intersection_action : intersection LPAREN RPAREN OBRACE block_list EBRACE'
|
||||
|
||||
print "intersection"
|
||||
# Is this Multi Common
|
||||
if (len(p[5]) > 2):
|
||||
print "Multi Common"
|
||||
mycommon = doc.addObject('Part::MultiCommon',p[1])
|
||||
mycommon.Shapes = p[5]
|
||||
for subobj in mycommon.Shapes:
|
||||
subobj.ViewObject.hide()
|
||||
else :
|
||||
print "Single Common"
|
||||
mycommon = doc.addObject('Part::Common',p[1])
|
||||
mycommon.Base = p[5][0]
|
||||
mycommon.Tool = p[5][1]
|
||||
mycommon.Base.ViewObject.hide()
|
||||
mycommon.Tool.ViewObject.hide()
|
||||
|
||||
p[0] = [mycommon]
|
||||
print "End Intersection"
|
||||
|
||||
def process_rotate_extrude(obj):
|
||||
myrev = doc.addObject("Part::Revolution","RotateExtrude")
|
||||
myrev.Source = obj
|
||||
myrev.Axis = (0.00,1.00,0.00)
|
||||
myrev.Base = (0.00,0.00,0.00)
|
||||
myrev.Angle = 360.00
|
||||
myrev.Placement=FreeCAD.Placement(FreeCAD.Vector(),FreeCAD.Rotation(0,0,90))
|
||||
obj.ViewObject.hide()
|
||||
newobj=doc.addObject("Part::FeaturePython",'RefineRotateExtrude')
|
||||
RefineShape(newobj,myrev)
|
||||
if FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/OpenSCAD").\
|
||||
GetBool('useViewProviderTree'):
|
||||
from OpenSCADFeatures import ViewProviderTree
|
||||
ViewProviderTree(newobj.ViewObject)
|
||||
else:
|
||||
newobj.ViewObject.Proxy = 0
|
||||
myrev.ViewObject.hide()
|
||||
return(newobj)
|
||||
|
||||
def p_rotate_extrude_action(p):
|
||||
'rotate_extrude_action : rotate_extrude LPAREN assign COMMA assign COMMA assign COMMA assign RPAREN OBRACE block_list EBRACE'
|
||||
print "Rotate Extrude"
|
||||
if (len(p[12]) > 1) :
|
||||
part = fuse(p[12],"Rotate Extrude Union")
|
||||
else :
|
||||
part = p[12][0]
|
||||
p[0] = [process_rotate_extrude(part)]
|
||||
print "End Rotate Extrude"
|
||||
|
||||
def p_rotate_extrude_file(p):
|
||||
'rotate_extrude_file : rotate_extrude LPAREN file EQ stripped_string COMMA layer EQ stripped_string COMMA origin EQ 2d_point COMMA assign \
|
||||
COMMA assign COMMA assign COMMA assign COMMA assign RPAREN SEMICOL'
|
||||
print "Rotate Extrude File"
|
||||
filen,ext =p[5] .rsplit('.',1)
|
||||
obj = process_import_file(filen,ext,p[9])
|
||||
p[0] = [process_rotate_extrude(obj)]
|
||||
print "End Rotate Extrude File"
|
||||
|
||||
def process_linear_extrude(obj,h) :
|
||||
mylinear = doc.addObject("Part::Extrusion","LinearExtrude")
|
||||
mylinear.Base = obj
|
||||
mylinear.Dir = (0,0,h)
|
||||
mylinear.Placement=FreeCAD.Placement()
|
||||
try:
|
||||
mylinear.Solid = True
|
||||
except:
|
||||
a = 1 # Any old null statement
|
||||
obj.ViewObject.hide()
|
||||
newobj=doc.addObject("Part::FeaturePython",'RefineLinearExtrude')
|
||||
RefineShape(newobj,mylinear)
|
||||
if FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/OpenSCAD").\
|
||||
GetBool('useViewProviderTree'):
|
||||
from OpenSCADFeatures import ViewProviderTree
|
||||
ViewProviderTree(newobj.ViewObject)
|
||||
else:
|
||||
newobj.ViewObject.Proxy = 0
|
||||
mylinear.ViewObject.hide()
|
||||
return(newobj)
|
||||
|
||||
def process_linear_extrude_with_twist(base,height,twist) :
|
||||
newobj=doc.addObject("Part::FeaturePython",'twist_extrude')
|
||||
Twist(newobj,base,height,-twist) #base is an FreeCAD Object, heigth and twist are floats
|
||||
if FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/OpenSCAD").\
|
||||
GetBool('useViewProviderTree'):
|
||||
from OpenSCADFeatures import ViewProviderTree
|
||||
ViewProviderTree(newobj.ViewObject)
|
||||
else:
|
||||
newobj.ViewObject.Proxy = 0
|
||||
#import ViewProviderTree from OpenSCADFeatures
|
||||
#ViewProviderTree(obj.ViewObject)
|
||||
return(newobj)
|
||||
|
||||
def p_linear_extrude_with_twist(p):
|
||||
'linear_extrude_with_twist : linear_extrude LPAREN assign COMMA center EQ boolean COMMA assign COMMA assign COMMA assign COMMA \
|
||||
assign COMMA assign COMMA assign RPAREN OBRACE block_list EBRACE'
|
||||
print "Linear Extrude With Twist"
|
||||
h = float(p[3])
|
||||
print "Twist : "+p[11]
|
||||
t = float(p[11])
|
||||
s = int(p[13])
|
||||
if (len(p[22]) > 1) :
|
||||
obj = fuse(p[22],"Linear Extrude Union")
|
||||
else :
|
||||
obj = p[22][0]
|
||||
if t:
|
||||
p[0] = [process_linear_extrude_with_twist(obj,h,t)]
|
||||
else:
|
||||
p[0] = [process_linear_extrude(obj,h)]
|
||||
if p[7]=='true' :
|
||||
center(obj,0,0,h)
|
||||
print "End Linear Extrude with twist"
|
||||
|
||||
def p_linear_extrude_action2(p):
|
||||
'linear_extrude_action2 : linear_extrude LPAREN assign COMMA center EQ boolean COMMA assign COMMA assign COMMA assign COMMA \
|
||||
assign RPAREN OBRACE block_list EBRACE'
|
||||
print "Linear Extrude 2"
|
||||
h = float(p[3])
|
||||
if (len(p[18]) > 1) :
|
||||
obj = fuse(p[18],"Linear Extrude Union")
|
||||
else :
|
||||
obj = p[18][0]
|
||||
p[0] = [process_linear_extrude(obj,h)]
|
||||
if p[7]=='true' :
|
||||
center(obj,0,0,h)
|
||||
print "End Linear Extrude 2"
|
||||
|
||||
def p_import_file1(p):
|
||||
'import_file1 : import LPAREN file EQ stripped_string COMMA layer EQ stripped_string COMMA origin EQ 2d_point COMMA assign COMMA assign COMMA \
|
||||
assign COMMA assign COMMA assign RPAREN SEMICOL'
|
||||
print "Import File"
|
||||
filen,ext =p[5] .rsplit('.',1)
|
||||
p[0] = [process_import_file(filen,ext,p[9])]
|
||||
print "End Import File"
|
||||
|
||||
def process_import_file(fname,ext,layer):
|
||||
print "Importing : "+fname+"."+ext+" Layer : "+layer
|
||||
if ext.lower() in reverseimporttypes()['Mesh']:
|
||||
obj=process_mesh_file(fname,ext)
|
||||
elif ext=='dxf' :
|
||||
obj=processDXF(fname,layer)
|
||||
else :
|
||||
print "Unsupported file extension"
|
||||
return(obj)
|
||||
|
||||
def process_mesh_file(fname,ext):
|
||||
import Mesh
|
||||
fullname = fname+'.'+ext
|
||||
filename = os.path.join(pathName,fullname)
|
||||
mesh1 = doc.getObject(fname) #reuse imported object
|
||||
if not mesh1:
|
||||
Mesh.insert(filename)
|
||||
mesh1=doc.getObject(fname)
|
||||
mesh1.ViewObject.hide()
|
||||
sh=Part.Shape()
|
||||
sh.makeShapeFromMesh(mesh1.Mesh.Topology,0.1)
|
||||
solid = Part.Solid(sh)
|
||||
obj=doc.addObject('Part::Feature',"Mesh")
|
||||
#ImportObject(obj,mesh1) #This object is not mutable from the GUI
|
||||
#ViewProviderTree(obj.ViewObject)
|
||||
solid=solid.removeSplitter()
|
||||
if solid.Volume < 0:
|
||||
#sh.reverse()
|
||||
#sh = sh.copy()
|
||||
solid.complement()
|
||||
obj.Shape=solid#.removeSplitter()
|
||||
return(obj)
|
||||
|
||||
def processDXF(fname,layer):
|
||||
global doc
|
||||
global pathName
|
||||
print "Process DXF file"
|
||||
print "File Name : "+fname
|
||||
print "Layer : "+layer
|
||||
print "PathName : "+pathName
|
||||
dxfname = fname+'.dxf'
|
||||
filename = os.path.join(pathName,dxfname)
|
||||
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),[])
|
||||
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:
|
||||
print "Importing Layer"
|
||||
layers = importDXF.processdxf(doc,filename) or importDXF.layers
|
||||
dxfcache[id(doc)] = layers[:]
|
||||
for l in layers:
|
||||
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:
|
||||
print 'import of layer %s failed' % layer
|
||||
for shapeobj in groupobj[0].Group:
|
||||
edges.extend(shapeobj.Shape.Edges)
|
||||
f=edgestofaces(edges)
|
||||
#obj=doc.addObject("Part::FeaturePython",'import_dxf_%s_%s'%(objname,layera))
|
||||
obj=doc.addObject('Part::Feature',"dxf")
|
||||
#ImportObject(obj,groupobj[0]) #This object is not mutable from the GUI
|
||||
#ViewProviderTree(obj.ViewObject)
|
||||
obj.Shape=f
|
||||
print "DXF Diagnostics"
|
||||
print obj.Shape.ShapeType
|
||||
print "Closed : "+str(f.isClosed())
|
||||
print f.check()
|
||||
print [w.isClosed() for w in obj.Shape.Wires]
|
||||
return(obj)
|
||||
|
||||
def processSTL(fname):
|
||||
print "Process STL file"
|
||||
|
||||
def p_multmatrix_action(p):
|
||||
'multmatrix_action : multmatrix LPAREN matrix RPAREN OBRACE block_list EBRACE'
|
||||
print "MultMatrix"
|
||||
transform_matrix = FreeCAD.Matrix()
|
||||
print "Multmatrix"
|
||||
print p[3]
|
||||
transform_matrix.A11 = round(float(p[3][0][0]),12)
|
||||
transform_matrix.A12 = round(float(p[3][0][1]),12)
|
||||
transform_matrix.A13 = round(float(p[3][0][2]),12)
|
||||
transform_matrix.A14 = round(float(p[3][0][3]),12)
|
||||
transform_matrix.A21 = round(float(p[3][1][0]),12)
|
||||
transform_matrix.A22 = round(float(p[3][1][1]),12)
|
||||
transform_matrix.A23 = round(float(p[3][1][2]),12)
|
||||
transform_matrix.A24 = round(float(p[3][1][3]),12)
|
||||
transform_matrix.A31 = round(float(p[3][2][0]),12)
|
||||
transform_matrix.A32 = round(float(p[3][2][1]),12)
|
||||
transform_matrix.A33 = round(float(p[3][2][2]),12)
|
||||
transform_matrix.A34 = round(float(p[3][2][3]),12)
|
||||
print transform_matrix
|
||||
print "Apply Multmatrix"
|
||||
# If more than one object on the stack for multmatrix fuse first
|
||||
if (len(p[6]) > 1) :
|
||||
part = fuse(p[6],"Matrix Union")
|
||||
else :
|
||||
part = p[6][0]
|
||||
# part = new_part.transformGeometry(transform_matrix)
|
||||
# part = new_part.copy()
|
||||
# part.transformShape(transform_matrix)
|
||||
if (isspecialorthogonaldeterminant(fcsubmatrix(transform_matrix))) :
|
||||
print "Orthogonal"
|
||||
part.Placement=FreeCAD.Placement(transform_matrix).multiply(part.Placement)
|
||||
new_part = part
|
||||
elif FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/OpenSCAD").\
|
||||
GetBool('useMultmatrixFeature'):
|
||||
from OpenSCADFeatures import MatrixTransform
|
||||
new_part=doc.addObject("Part::FeaturePython",'Matrix Deformation')
|
||||
MatrixTransform(new_part,transform_matrix,part)
|
||||
if FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/OpenSCAD").\
|
||||
GetBool('useViewProviderTree'):
|
||||
from OpenSCADFeatures import ViewProviderTree
|
||||
ViewProviderTree(new_part.ViewObject)
|
||||
else:
|
||||
new_part.ViewObject.Proxy = 0
|
||||
part.ViewObject.hide()
|
||||
else :
|
||||
print "Transform Geometry"
|
||||
# Need to recompute to stop transformGeometry causing a crash
|
||||
doc.recompute()
|
||||
new_part = doc.addObject("Part::Feature","Matrix Deformation")
|
||||
# new_part.Shape = part.Base.Shape.transformGeometry(transform_matrix)
|
||||
new_part.Shape = part.Shape.transformGeometry(transform_matrix)
|
||||
part.ViewObject.hide()
|
||||
if False :
|
||||
# Does not fix problemfile or beltTighener although later is closer
|
||||
newobj=doc.addObject("Part::FeaturePython",'RefineMultMatrix')
|
||||
RefineShape(newobj,new_part)
|
||||
newobj.ViewObject.Proxy = 0
|
||||
new_part.ViewObject.hide()
|
||||
p[0] = [newobj]
|
||||
else :
|
||||
p[0] = [new_part]
|
||||
print "Multmatrix applied"
|
||||
|
||||
def p_matrix(p):
|
||||
'matrix : OSQUARE vector COMMA vector COMMA vector COMMA vector ESQUARE'
|
||||
print "Matrix"
|
||||
p[0] = [p[2],p[4],p[6],p[8]]
|
||||
|
||||
def p_vector(p):
|
||||
'vector : OSQUARE NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER ESQUARE'
|
||||
print "Vector"
|
||||
p[0] = [p[2],p[4],p[6],p[8]]
|
||||
|
||||
def center(obj,x,y,z):
|
||||
obj.Placement = FreeCAD.Placement(\
|
||||
FreeCAD.Vector(-x/2.0,-y/2.0,-z/2.0),\
|
||||
FreeCAD.Rotation(0,0,0,1))
|
||||
|
||||
def p_sphere_action(p):
|
||||
'sphere_action : sphere LPAREN assign COMMA assign COMMA assign COMMA assign RPAREN SEMICOL'
|
||||
print "Sphere : "+p[9]
|
||||
r = float(p[9])
|
||||
mysphere = doc.addObject("Part::Sphere",p[1])
|
||||
mysphere.Radius = r
|
||||
print "Push Sphere"
|
||||
p[0] = [mysphere]
|
||||
print "End Sphere"
|
||||
|
||||
def myPolygon(n,r1):
|
||||
# Adapted from Draft::_Polygon
|
||||
import math
|
||||
print "My Polygon"
|
||||
angle = math.pi*2/n
|
||||
nodes = [FreeCAD.Vector(r1,0,0)]
|
||||
for i in range(n-1) :
|
||||
th = (i+1) * angle
|
||||
nodes.append(FreeCAD.Vector(r1*math.cos(th),r1*math.sin(th),0))
|
||||
nodes.append(nodes[0])
|
||||
polygonwire = Part.makePolygon(nodes)
|
||||
|
||||
polygon = doc.addObject("Part::Feature","Polygon")
|
||||
polygon.Shape = Part.Face(polygonwire)
|
||||
return(polygon)
|
||||
|
||||
def p_cylinder_action(p):
|
||||
'cylinder_action : cylinder LPAREN assign COMMA assign COMMA assign COMMA assign COMMA assign COMMA assign COMMA center EQ boolean RPAREN SEMICOL'
|
||||
print "Cylinder"
|
||||
h = float(p[9])
|
||||
r1 = float(p[11])
|
||||
r2 = float(p[13])
|
||||
print p[9] + ' : ' + p[11] + ' : ' + p[13]
|
||||
if ( r1 == r2 ):
|
||||
print "Make Cylinder"
|
||||
n = int(p[3])
|
||||
fnmax = FreeCAD.ParamGet(\
|
||||
"User parameter:BaseApp/Preferences/Mod/OpenSCAD").\
|
||||
GetInt('useMaxFN')
|
||||
if n < 3 or fnmax != 0 and n > fnmax:
|
||||
mycyl=doc.addObject("Part::Cylinder",p[1])
|
||||
mycyl.Height = h
|
||||
mycyl.Radius = r1
|
||||
else :
|
||||
print "Make Prism"
|
||||
mycyl=doc.addObject("Part::Extrusion","prism")
|
||||
mycyl.Dir = (0,0,h)
|
||||
try :
|
||||
import Draft
|
||||
mycyl.Base = Draft.makePolygon(n,r1)
|
||||
except :
|
||||
# If Draft can't import (probably due to lack of Pivy on Mac and
|
||||
# Linux builds of FreeCAD), this is a fallback.
|
||||
# or old level of FreeCAD
|
||||
print "Draft makePolygon Failed, falling back on manual polygon"
|
||||
mycyl.Base = myPolygon(n,r1)
|
||||
|
||||
else :
|
||||
pass
|
||||
|
||||
mycyl.Base.ViewObject.hide()
|
||||
# mycyl.Solid = True
|
||||
|
||||
else:
|
||||
print "Make Cone"
|
||||
mycyl=doc.addObject("Part::Cone",p[1])
|
||||
mycyl.Height = h
|
||||
mycyl.Radius1 = r1
|
||||
mycyl.Radius2 = r2
|
||||
print "Center = "+str(p[17])
|
||||
if p[17]=='true' :
|
||||
center(mycyl,0,0,h)
|
||||
if False :
|
||||
# Does not fix problemfile or beltTighener although later is closer
|
||||
newobj=doc.addObject("Part::FeaturePython",'RefineCylinder')
|
||||
RefineShape(newobj,mycyl)
|
||||
if FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/OpenSCAD").\
|
||||
GetBool('useViewProviderTree'):
|
||||
from OpenSCADFeatures import ViewProviderTree
|
||||
ViewProviderTree(newobj.ViewObject)
|
||||
else:
|
||||
newobj.ViewObject.Proxy = 0
|
||||
mycyl.ViewObject.hide()
|
||||
p[0] = [newobj]
|
||||
else :
|
||||
p[0] = [mycyl]
|
||||
print "End Cylinder"
|
||||
|
||||
|
||||
def p_cube_action(p):
|
||||
'cube_action : cube LPAREN size EQ size_vector COMMA center EQ boolean RPAREN SEMICOL'
|
||||
global doc
|
||||
l = float(p[5][0])
|
||||
w = float(p[5][1])
|
||||
h = float(p[5][2])
|
||||
print "cube : "+p[5][0] + ' : ' + p[5][1] +' : '+ p[5][2]
|
||||
mycube=doc.addObject('Part::Box',p[1])
|
||||
mycube.Length=l
|
||||
mycube.Width=w
|
||||
mycube.Height=h
|
||||
print "Center = "+str(p[9])
|
||||
if p[9]=='true' :
|
||||
center(mycube,l,w,h);
|
||||
p[0] = [mycube]
|
||||
print "End Cube"
|
||||
|
||||
def p_circle_action(p) :
|
||||
'circle_action : circle LPAREN assign COMMA assign COMMA assign COMMA assign RPAREN SEMICOL'
|
||||
print "Circle : "+str(p[9])
|
||||
r = float(p[9])
|
||||
n = int(p[3])
|
||||
fnmax = FreeCAD.ParamGet(\
|
||||
"User parameter:BaseApp/Preferences/Mod/OpenSCAD").\
|
||||
GetInt('useMaxFN')
|
||||
import Draft
|
||||
if n == 0 or fnmax != 0 and n > fnmax:
|
||||
mycircle = Draft.makeCircle(r)
|
||||
#mycircle = doc.addObject('Part::Circle',p[1])
|
||||
#mycircle.Radius = r
|
||||
else :
|
||||
mycircle = Draft.makePolygon(n,r)
|
||||
print "Push Circle"
|
||||
p[0] = [mycircle]
|
||||
|
||||
def p_square_action(p) :
|
||||
'square_action : square LPAREN size EQ 2d_point COMMA center EQ boolean RPAREN SEMICOL'
|
||||
print "Square"
|
||||
x = float(p[5][0])
|
||||
y = float(p[5][1])
|
||||
mysquare = doc.addObject('Part::Plane',p[1])
|
||||
mysquare.Length=x
|
||||
mysquare.Width=y
|
||||
if p[9]=='true' :
|
||||
center(mysquare,x,y,0)
|
||||
p[0] = [mysquare]
|
||||
|
||||
def convert_points_list_to_vector(l):
|
||||
v = []
|
||||
for i in l :
|
||||
print i
|
||||
v.append(FreeCAD.Vector(i[0],i[1]))
|
||||
print v
|
||||
return(v)
|
||||
|
||||
|
||||
def p_polygon_action_nopath(p) :
|
||||
'polygon_action_nopath : polygon LPAREN points EQ OSQUARE points_list_2d ESQUARE COMMA paths EQ undef COMMA assign RPAREN SEMICOL'
|
||||
print "Polygon"
|
||||
print p[6]
|
||||
v = convert_points_list_to_vector(p[6])
|
||||
mypolygon = doc.addObject('Part::Feature',p[1])
|
||||
print "Make Parts"
|
||||
# Close Polygon
|
||||
v.append(v[0])
|
||||
parts = Part.makePolygon(v)
|
||||
print "update object"
|
||||
mypolygon.Shape = Part.Face(parts)
|
||||
p[0] = [mypolygon]
|
||||
|
||||
def p_polygon_action_plus_path(p) :
|
||||
'polygon_action_plus_path : polygon LPAREN points EQ OSQUARE points_list_2d ESQUARE COMMA paths EQ OSQUARE path_set ESQUARE COMMA assign RPAREN SEMICOL'
|
||||
print "Polygon with Path"
|
||||
print p[6]
|
||||
v = convert_points_list_to_vector(p[6])
|
||||
print "Path Set List"
|
||||
print p[12]
|
||||
for i in p[12] :
|
||||
print i
|
||||
mypolygon = doc.addObject('Part::Feature','wire')
|
||||
path_list = []
|
||||
for j in i :
|
||||
j = int(j)
|
||||
print j
|
||||
path_list.append(v[j])
|
||||
# Close path
|
||||
path_list.append(v[int(i[0])])
|
||||
print 'Path List'
|
||||
print path_list
|
||||
wire = Part.makePolygon(path_list)
|
||||
mypolygon.Shape = Part.Face(wire)
|
||||
p[0] = [mypolygon]
|
||||
# This only pushes last polygon
|
||||
|
||||
def make_face(v1,v2,v3):
|
||||
wire = Part.makePolygon([v1,v2,v3,v1])
|
||||
face = Part.Face(wire)
|
||||
return face
|
||||
|
||||
def p_polyhedron_action(p) :
|
||||
'polyhedron_action : polyhedron LPAREN points EQ OSQUARE points_list_3d ESQUARE COMMA triangles EQ OSQUARE points_list_3d ESQUARE COMMA assign RPAREN SEMICOL'
|
||||
print "Polyhedron Points"
|
||||
v = []
|
||||
for i in p[6] :
|
||||
print i
|
||||
v.append(FreeCAD.Vector(float(i[0]),float(i[1]),float(i[2])))
|
||||
print v
|
||||
print "Polyhedron triangles"
|
||||
print p[12]
|
||||
faces_list = []
|
||||
mypolyhed = doc.addObject('Part::Feature',p[1])
|
||||
for i in p[12] :
|
||||
print i
|
||||
f = make_face(v[int(i[0])],v[int(i[1])],v[int(i[2])])
|
||||
faces_list.append(f)
|
||||
shell=Part.makeShell(faces_list)
|
||||
mypolyhed.Shape=Part.Solid(shell)
|
||||
p[0] = [mypolyhed]
|
||||
|
||||
def p_projection_action(p) :
|
||||
'projection_action : projection LPAREN cut EQ boolean COMMA assign RPAREN OBRACE block_list EBRACE'
|
||||
print 'Projection'
|
||||
from PyQt4 import QtGui
|
||||
QtGui.QMessageBox.critical(None, "Projection Not yet Coded waiting for Peter Li"," Press OK")
|
||||
|
58
src/Mod/OpenSCAD/importVersions.txt
Normal file
58
src/Mod/OpenSCAD/importVersions.txt
Normal file
|
@ -0,0 +1,58 @@
|
|||
Version History
|
||||
===============
|
||||
|
||||
0.01a - First Version
|
||||
|
||||
0.01b - Fixed
|
||||
|
||||
Reset Global Variables
|
||||
Fix Multmatrix use of Shape
|
||||
|
||||
Added import Function (Untested)
|
||||
|
||||
0.02b - Rewrite to use Bojects rather than shapes.
|
||||
Objects now editible in FreeCad
|
||||
|
||||
0.02c - disable debug output on Yacc to avoid permissions problem with Linux
|
||||
|
||||
0.03a - Added support for
|
||||
|
||||
Linear Extrusion
|
||||
Rotational Extrusion
|
||||
circle
|
||||
square
|
||||
polygon
|
||||
polyhedron
|
||||
|
||||
0.04a - Change to use parser stack rather than own stack
|
||||
to fix a parsing problem
|
||||
makes code cleaner and less global variables
|
||||
parsers out SCAD comments ( Not sure if the are allowed in CSG file anyway
|
||||
other minor fixes
|
||||
|
||||
0.04b - Fixes where Multmatrix has more than one object neeed to fuse first
|
||||
Correct import function call
|
||||
|
||||
0.04c - Support for cylinders made with regular polygon ( Needs FreeCAD with fixes to Draft )
|
||||
Attempt at transformGeometry for non orthoganal Multmatrix
|
||||
|
||||
0.04d - Fix to multmatrix transformGeometry to avoid crash
|
||||
|
||||
0.04e - If problems with Draft or Draft's makePolygon because not on latest FreeCAD falls back
|
||||
to non editable polygon
|
||||
|
||||
0.04f - Fix bug with multiple intersections
|
||||
|
||||
0.05a - Attempt to add shogens's import dxf function code.
|
||||
|
||||
0.05b - Fix introduced bug with centre=true/false, ViewObject Proxy
|
||||
|
||||
0.05c - Fix for polygon with path - Changes to Polygon and polyhdron - parse projection
|
||||
|
||||
There appear to be problems with some files and these maybe as a result of bugs in FreeCAD that corrupt
|
||||
the model. If you find problem files please email them to keith@sloan-home.co.uk
|
||||
|
||||
Thanks to shoogen and Peter Li for their advice, support and expertise.
|
||||
|
||||
Keith Sloan
|
||||
keith@sloan-home.co.uk
|
40
src/Mod/OpenSCAD/ply/ANNOUNCE
Normal file
40
src/Mod/OpenSCAD/ply/ANNOUNCE
Normal file
|
@ -0,0 +1,40 @@
|
|||
February 17, 2011
|
||||
|
||||
Announcing : PLY-3.4 (Python Lex-Yacc)
|
||||
|
||||
http://www.dabeaz.com/ply
|
||||
|
||||
I'm pleased to announce PLY-3.4--a pure Python implementation of the
|
||||
common parsing tools lex and yacc. PLY-3.4 is a minor bug fix
|
||||
release. It supports both Python 2 and Python 3.
|
||||
|
||||
If you are new to PLY, here are a few highlights:
|
||||
|
||||
- PLY is closely modeled after traditional lex/yacc. If you know how
|
||||
to use these or similar tools in other languages, you will find
|
||||
PLY to be comparable.
|
||||
|
||||
- PLY provides very extensive error reporting and diagnostic
|
||||
information to assist in parser construction. The original
|
||||
implementation was developed for instructional purposes. As
|
||||
a result, the system tries to identify the most common types
|
||||
of errors made by novice users.
|
||||
|
||||
- PLY provides full support for empty productions, error recovery,
|
||||
precedence rules, and ambiguous grammars.
|
||||
|
||||
- Parsing is based on LR-parsing which is fast, memory efficient,
|
||||
better suited to large grammars, and which has a number of nice
|
||||
properties when dealing with syntax errors and other parsing
|
||||
problems. Currently, PLY can build its parsing tables using
|
||||
either SLR or LALR(1) algorithms.
|
||||
|
||||
More information about PLY can be obtained on the PLY webpage at:
|
||||
|
||||
http://www.dabeaz.com/ply
|
||||
|
||||
PLY is freely available.
|
||||
|
||||
Cheers,
|
||||
|
||||
David Beazley (http://www.dabeaz.com)
|
1093
src/Mod/OpenSCAD/ply/CHANGES
Normal file
1093
src/Mod/OpenSCAD/ply/CHANGES
Normal file
File diff suppressed because it is too large
Load Diff
22
src/Mod/OpenSCAD/ply/PKG-INFO
Normal file
22
src/Mod/OpenSCAD/ply/PKG-INFO
Normal file
|
@ -0,0 +1,22 @@
|
|||
Metadata-Version: 1.0
|
||||
Name: ply
|
||||
Version: 3.4
|
||||
Summary: Python Lex & Yacc
|
||||
Home-page: http://www.dabeaz.com/ply/
|
||||
Author: David Beazley
|
||||
Author-email: dave@dabeaz.com
|
||||
License: BSD
|
||||
Description:
|
||||
PLY is yet another implementation of lex and yacc for Python. Some notable
|
||||
features include the fact that its implemented entirely in Python and it
|
||||
uses LALR(1) parsing which is efficient and well suited for larger grammars.
|
||||
|
||||
PLY provides most of the standard lex/yacc features including support for empty
|
||||
productions, precedence rules, error recovery, and support for ambiguous grammars.
|
||||
|
||||
PLY is extremely easy to use and provides very extensive error checking.
|
||||
It is compatible with both Python 2 and Python 3.
|
||||
|
||||
Platform: UNKNOWN
|
||||
Classifier: Programming Language :: Python :: 3
|
||||
Classifier: Programming Language :: Python :: 2
|
271
src/Mod/OpenSCAD/ply/README
Normal file
271
src/Mod/OpenSCAD/ply/README
Normal file
|
@ -0,0 +1,271 @@
|
|||
PLY (Python Lex-Yacc) Version 3.4
|
||||
|
||||
Copyright (C) 2001-2011,
|
||||
David M. Beazley (Dabeaz LLC)
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* Neither the name of the David Beazley or Dabeaz LLC may be used to
|
||||
endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Introduction
|
||||
============
|
||||
|
||||
PLY is a 100% Python implementation of the common parsing tools lex
|
||||
and yacc. Here are a few highlights:
|
||||
|
||||
- PLY is very closely modeled after traditional lex/yacc.
|
||||
If you know how to use these tools in C, you will find PLY
|
||||
to be similar.
|
||||
|
||||
- PLY provides *very* extensive error reporting and diagnostic
|
||||
information to assist in parser construction. The original
|
||||
implementation was developed for instructional purposes. As
|
||||
a result, the system tries to identify the most common types
|
||||
of errors made by novice users.
|
||||
|
||||
- PLY provides full support for empty productions, error recovery,
|
||||
precedence specifiers, and moderately ambiguous grammars.
|
||||
|
||||
- Parsing is based on LR-parsing which is fast, memory efficient,
|
||||
better suited to large grammars, and which has a number of nice
|
||||
properties when dealing with syntax errors and other parsing problems.
|
||||
Currently, PLY builds its parsing tables using the LALR(1)
|
||||
algorithm used in yacc.
|
||||
|
||||
- PLY uses Python introspection features to build lexers and parsers.
|
||||
This greatly simplifies the task of parser construction since it reduces
|
||||
the number of files and eliminates the need to run a separate lex/yacc
|
||||
tool before running your program.
|
||||
|
||||
- PLY can be used to build parsers for "real" programming languages.
|
||||
Although it is not ultra-fast due to its Python implementation,
|
||||
PLY can be used to parse grammars consisting of several hundred
|
||||
rules (as might be found for a language like C). The lexer and LR
|
||||
parser are also reasonably efficient when parsing typically
|
||||
sized programs. People have used PLY to build parsers for
|
||||
C, C++, ADA, and other real programming languages.
|
||||
|
||||
How to Use
|
||||
==========
|
||||
|
||||
PLY consists of two files : lex.py and yacc.py. These are contained
|
||||
within the 'ply' directory which may also be used as a Python package.
|
||||
To use PLY, simply copy the 'ply' directory to your project and import
|
||||
lex and yacc from the associated 'ply' package. For example:
|
||||
|
||||
import ply.lex as lex
|
||||
import ply.yacc as yacc
|
||||
|
||||
Alternatively, you can copy just the files lex.py and yacc.py
|
||||
individually and use them as modules. For example:
|
||||
|
||||
import lex
|
||||
import yacc
|
||||
|
||||
The file setup.py can be used to install ply using distutils.
|
||||
|
||||
The file doc/ply.html contains complete documentation on how to use
|
||||
the system.
|
||||
|
||||
The example directory contains several different examples including a
|
||||
PLY specification for ANSI C as given in K&R 2nd Ed.
|
||||
|
||||
A simple example is found at the end of this document
|
||||
|
||||
Requirements
|
||||
============
|
||||
PLY requires the use of Python 2.2 or greater. However, you should
|
||||
use the latest Python release if possible. It should work on just
|
||||
about any platform. PLY has been tested with both CPython and Jython.
|
||||
It also seems to work with IronPython.
|
||||
|
||||
Resources
|
||||
=========
|
||||
More information about PLY can be obtained on the PLY webpage at:
|
||||
|
||||
http://www.dabeaz.com/ply
|
||||
|
||||
For a detailed overview of parsing theory, consult the excellent
|
||||
book "Compilers : Principles, Techniques, and Tools" by Aho, Sethi, and
|
||||
Ullman. The topics found in "Lex & Yacc" by Levine, Mason, and Brown
|
||||
may also be useful.
|
||||
|
||||
A Google group for PLY can be found at
|
||||
|
||||
http://groups.google.com/group/ply-hack
|
||||
|
||||
Acknowledgments
|
||||
===============
|
||||
A special thanks is in order for all of the students in CS326 who
|
||||
suffered through about 25 different versions of these tools :-).
|
||||
|
||||
The CHANGES file acknowledges those who have contributed patches.
|
||||
|
||||
Elias Ioup did the first implementation of LALR(1) parsing in PLY-1.x.
|
||||
Andrew Waters and Markus Schoepflin were instrumental in reporting bugs
|
||||
and testing a revised LALR(1) implementation for PLY-2.0.
|
||||
|
||||
Special Note for PLY-3.0
|
||||
========================
|
||||
PLY-3.0 the first PLY release to support Python 3. However, backwards
|
||||
compatibility with Python 2.2 is still preserved. PLY provides dual
|
||||
Python 2/3 compatibility by restricting its implementation to a common
|
||||
subset of basic language features. You should not convert PLY using
|
||||
2to3--it is not necessary and may in fact break the implementation.
|
||||
|
||||
Example
|
||||
=======
|
||||
|
||||
Here is a simple example showing a PLY implementation of a calculator
|
||||
with variables.
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# calc.py
|
||||
#
|
||||
# A simple calculator with variables.
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
tokens = (
|
||||
'NAME','NUMBER',
|
||||
'PLUS','MINUS','TIMES','DIVIDE','EQUALS',
|
||||
'LPAREN','RPAREN',
|
||||
)
|
||||
|
||||
# Tokens
|
||||
|
||||
t_PLUS = r'\+'
|
||||
t_MINUS = r'-'
|
||||
t_TIMES = r'\*'
|
||||
t_DIVIDE = r'/'
|
||||
t_EQUALS = r'='
|
||||
t_LPAREN = r'\('
|
||||
t_RPAREN = r'\)'
|
||||
t_NAME = r'[a-zA-Z_][a-zA-Z0-9_]*'
|
||||
|
||||
def t_NUMBER(t):
|
||||
r'\d+'
|
||||
t.value = int(t.value)
|
||||
return t
|
||||
|
||||
# Ignored characters
|
||||
t_ignore = " \t"
|
||||
|
||||
def t_newline(t):
|
||||
r'\n+'
|
||||
t.lexer.lineno += t.value.count("\n")
|
||||
|
||||
def t_error(t):
|
||||
print("Illegal character '%s'" % t.value[0])
|
||||
t.lexer.skip(1)
|
||||
|
||||
# Build the lexer
|
||||
import ply.lex as lex
|
||||
lex.lex()
|
||||
|
||||
# Precedence rules for the arithmetic operators
|
||||
precedence = (
|
||||
('left','PLUS','MINUS'),
|
||||
('left','TIMES','DIVIDE'),
|
||||
('right','UMINUS'),
|
||||
)
|
||||
|
||||
# dictionary of names (for storing variables)
|
||||
names = { }
|
||||
|
||||
def p_statement_assign(p):
|
||||
'statement : NAME EQUALS expression'
|
||||
names[p[1]] = p[3]
|
||||
|
||||
def p_statement_expr(p):
|
||||
'statement : expression'
|
||||
print(p[1])
|
||||
|
||||
def p_expression_binop(p):
|
||||
'''expression : expression PLUS expression
|
||||
| expression MINUS expression
|
||||
| expression TIMES expression
|
||||
| expression DIVIDE expression'''
|
||||
if p[2] == '+' : p[0] = p[1] + p[3]
|
||||
elif p[2] == '-': p[0] = p[1] - p[3]
|
||||
elif p[2] == '*': p[0] = p[1] * p[3]
|
||||
elif p[2] == '/': p[0] = p[1] / p[3]
|
||||
|
||||
def p_expression_uminus(p):
|
||||
'expression : MINUS expression %prec UMINUS'
|
||||
p[0] = -p[2]
|
||||
|
||||
def p_expression_group(p):
|
||||
'expression : LPAREN expression RPAREN'
|
||||
p[0] = p[2]
|
||||
|
||||
def p_expression_number(p):
|
||||
'expression : NUMBER'
|
||||
p[0] = p[1]
|
||||
|
||||
def p_expression_name(p):
|
||||
'expression : NAME'
|
||||
try:
|
||||
p[0] = names[p[1]]
|
||||
except LookupError:
|
||||
print("Undefined name '%s'" % p[1])
|
||||
p[0] = 0
|
||||
|
||||
def p_error(p):
|
||||
print("Syntax error at '%s'" % p.value)
|
||||
|
||||
import ply.yacc as yacc
|
||||
yacc.yacc()
|
||||
|
||||
while 1:
|
||||
try:
|
||||
s = raw_input('calc > ') # use input() on Python 3
|
||||
except EOFError:
|
||||
break
|
||||
yacc.parse(s)
|
||||
|
||||
|
||||
Bug Reports and Patches
|
||||
=======================
|
||||
My goal with PLY is to simply have a decent lex/yacc implementation
|
||||
for Python. As a general rule, I don't spend huge amounts of time
|
||||
working on it unless I receive very specific bug reports and/or
|
||||
patches to fix problems. I also try to incorporate submitted feature
|
||||
requests and enhancements into each new version. To contact me about
|
||||
bugs and/or new features, please send email to dave@dabeaz.com.
|
||||
|
||||
In addition there is a Google group for discussing PLY related issues at
|
||||
|
||||
http://groups.google.com/group/ply-hack
|
||||
|
||||
-- Dave
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
16
src/Mod/OpenSCAD/ply/TODO
Normal file
16
src/Mod/OpenSCAD/ply/TODO
Normal file
|
@ -0,0 +1,16 @@
|
|||
The PLY to-do list:
|
||||
|
||||
1. Finish writing the C Preprocessor module. Started in the
|
||||
file ply/cpp.py
|
||||
|
||||
2. Create and document libraries of useful tokens.
|
||||
|
||||
3. Expand the examples/yply tool that parses bison/yacc
|
||||
files.
|
||||
|
||||
4. Think of various diabolical things to do with the
|
||||
new yacc internals. For example, it is now possible
|
||||
to specify grammrs using completely different schemes
|
||||
than the reflection approach used by PLY.
|
||||
|
||||
|
4
src/Mod/OpenSCAD/ply/__init__.py
Normal file
4
src/Mod/OpenSCAD/ply/__init__.py
Normal file
|
@ -0,0 +1,4 @@
|
|||
# PLY package
|
||||
# Author: David Beazley (dave@dabeaz.com)
|
||||
|
||||
__all__ = ['lex','yacc']
|
1058
src/Mod/OpenSCAD/ply/lex.py
Normal file
1058
src/Mod/OpenSCAD/ply/lex.py
Normal file
File diff suppressed because it is too large
Load Diff
31
src/Mod/OpenSCAD/ply/setup.py
Normal file
31
src/Mod/OpenSCAD/ply/setup.py
Normal file
|
@ -0,0 +1,31 @@
|
|||
try:
|
||||
from setuptools import setup
|
||||
except ImportError:
|
||||
from distutils.core import setup
|
||||
|
||||
setup(name = "ply",
|
||||
description="Python Lex & Yacc",
|
||||
long_description = """
|
||||
PLY is yet another implementation of lex and yacc for Python. Some notable
|
||||
features include the fact that its implemented entirely in Python and it
|
||||
uses LALR(1) parsing which is efficient and well suited for larger grammars.
|
||||
|
||||
PLY provides most of the standard lex/yacc features including support for empty
|
||||
productions, precedence rules, error recovery, and support for ambiguous grammars.
|
||||
|
||||
PLY is extremely easy to use and provides very extensive error checking.
|
||||
It is compatible with both Python 2 and Python 3.
|
||||
""",
|
||||
license="""BSD""",
|
||||
version = "3.4",
|
||||
author = "David Beazley",
|
||||
author_email = "dave@dabeaz.com",
|
||||
maintainer = "David Beazley",
|
||||
maintainer_email = "dave@dabeaz.com",
|
||||
url = "http://www.dabeaz.com/ply/",
|
||||
packages = ['ply'],
|
||||
classifiers = [
|
||||
'Programming Language :: Python :: 3',
|
||||
'Programming Language :: Python :: 2',
|
||||
]
|
||||
)
|
3276
src/Mod/OpenSCAD/ply/yacc.py
Normal file
3276
src/Mod/OpenSCAD/ply/yacc.py
Normal file
File diff suppressed because it is too large
Load Diff
688
src/Mod/OpenSCAD/prototype.py
Normal file
688
src/Mod/OpenSCAD/prototype.py
Normal file
|
@ -0,0 +1,688 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License (LGPL)
|
||||
# as published by the Free Software Foundation; either version 2 of
|
||||
# the License, or (at your option) any later version.
|
||||
|
||||
import FreeCAD
|
||||
import re,math
|
||||
from OpenSCADFeatures import *
|
||||
from OpenSCAD2Dgeom import *
|
||||
from OpenSCADUtils import *
|
||||
|
||||
if open.__module__ == '__builtin__':
|
||||
pythonopen = open # to distinguish python built-in open function from the one declared here
|
||||
|
||||
def openscadmesh(doc,scadstr,objname):
|
||||
import Part,Mesh,os,OpenSCADUtils
|
||||
tmpfilename=OpenSCADUtils.callopenscadstring(scadstr,'stl')
|
||||
if tmpfilename:
|
||||
#mesh1 = doc.getObject(objname) #reuse imported object
|
||||
Mesh.insert(tmpfilename)
|
||||
os.unlink(tmpfilename)
|
||||
mesh1=doc.getObject(objname) #blog
|
||||
mesh1.ViewObject.hide()
|
||||
sh=Part.Shape()
|
||||
sh.makeShapeFromMesh(mesh1.Mesh.Topology,0.1)
|
||||
solid = Part.Solid(sh)
|
||||
obj=doc.addObject("Part::FeaturePython",objname)
|
||||
ImportObject(obj,mesh1) #This object is not mutable from the GUI
|
||||
ViewProviderTree(obj.ViewObject)
|
||||
solid=solid.removeSplitter()
|
||||
if solid.Volume < 0:
|
||||
solid.complement()
|
||||
obj.Shape=solid#.removeSplitter()
|
||||
return obj
|
||||
else:
|
||||
print scadstr
|
||||
|
||||
class Node:
|
||||
#fnmin=12 # maximal fn for implicit polygon renderfing
|
||||
fnmin= FreeCAD.ParamGet(\
|
||||
"User parameter:BaseApp/Preferences/Mod/OpenSCAD").\
|
||||
GetInt('useMaxFN')
|
||||
planedim=1e10 #size of the sqaure used as x-y-plane
|
||||
def __init__(self,name,arguments=None,children=None,):
|
||||
pass
|
||||
self.name=name
|
||||
self.arguments=arguments or {}
|
||||
self.children=children or []
|
||||
|
||||
def __repr__(self):
|
||||
str1 ='Node(name=%s' % self.name
|
||||
if self.arguments:
|
||||
str1 += ',arguments=%s' % self.arguments
|
||||
if self.children:
|
||||
str1 += ',children=%s' % self.children
|
||||
return str1+')'
|
||||
|
||||
def __nonzero__(self):
|
||||
'''a Node is not obsolent if doesn't have children. Only if as neither name children or
|
||||
arguments'''
|
||||
return bool(self.name or self.arguments or self.children)
|
||||
|
||||
def __len__(self):
|
||||
'''return the numer of children'''
|
||||
return len(self.children)
|
||||
|
||||
def __getitem__(self,key):
|
||||
'''dirct access to the children'''
|
||||
return self.children.__getitem__(key)
|
||||
|
||||
def rlen(self,checkmultmarix=False):
|
||||
'''Total number of nodes'''
|
||||
if self.children:
|
||||
return 1+sum([ch.rlen() for ch in self.children])
|
||||
else:
|
||||
return 1
|
||||
|
||||
|
||||
def addtofreecad(self,doc=None,fcpar=None):
|
||||
def center(obj,x,y,z):
|
||||
obj.Placement = FreeCAD.Placement(\
|
||||
FreeCAD.Vector(-x/2.0,-y/2.0,-z/2.0),\
|
||||
FreeCAD.Rotation(0,0,0,1))
|
||||
|
||||
import FreeCAD,Part
|
||||
if not doc:
|
||||
doc=FreeCAD.newDocument()
|
||||
namel=self.name.lower()
|
||||
multifeature={'union':"Part::MultiFuse",'imp_union':"Part::MultiFuse",
|
||||
'intersection':"Part::MultiCommon"}
|
||||
if namel in multifeature:
|
||||
if len(self.children)>1:
|
||||
obj=doc.addObject(multifeature[namel],namel)
|
||||
subobjs = [child.addtofreecad(doc,obj) for child in self.children]
|
||||
obj.Shapes = subobjs
|
||||
for subobj in subobjs:
|
||||
subobj.ViewObject.hide()
|
||||
elif len(self.children)==1:
|
||||
obj = self.children[0].addtofreecad(doc,fcpar or True)
|
||||
else:
|
||||
obj = fcpar
|
||||
elif namel == 'difference':
|
||||
if len(self.children)==1:
|
||||
obj = self.children[0].addtofreecad(doc,fcpar or True)
|
||||
else:
|
||||
obj=doc.addObject("Part::Cut",namel)
|
||||
base = self.children[0].addtofreecad(doc,obj)
|
||||
|
||||
if len(self.children)==2:
|
||||
tool = self.children[1].addtofreecad(doc,obj)
|
||||
else:
|
||||
tool = Node(name='imp_union',\
|
||||
children=self.children[1:]).addtofreecad(doc,obj)
|
||||
obj.Base = base
|
||||
obj.Tool = tool
|
||||
base.ViewObject.hide()
|
||||
tool.ViewObject.hide()
|
||||
elif namel == 'cube':
|
||||
obj=doc.addObject('Part::Box',namel)
|
||||
x,y,z=self.arguments['size']
|
||||
obj.Length=x
|
||||
obj.Width=y
|
||||
obj.Height=z
|
||||
if self.arguments['center']:
|
||||
center(obj,x,y,z)
|
||||
elif namel == 'sphere':
|
||||
obj=doc.addObject("Part::Sphere",namel)
|
||||
obj.Radius = self.arguments['r']
|
||||
elif namel == 'cylinder':
|
||||
h = self.arguments['h']
|
||||
r1 ,r2 = self.arguments['r1'], self.arguments['r2']
|
||||
if '$fn' in self.arguments and self.arguments['$fn'] > 2 \
|
||||
and self.arguments['$fn']<=Node.fnmin:
|
||||
if r1 == r2:
|
||||
import Draft
|
||||
base = Draft.makePolygon(int(self.arguments['$fn']),r1)
|
||||
obj = doc.addObject("Part::Extrusion",'prism')
|
||||
obj.Base= base
|
||||
obj.Dir = (0,0,h)
|
||||
if self.arguments['center']:
|
||||
center(obj,0,0,h)
|
||||
base.ViewObject.hide()
|
||||
elif True: #use Frustum Feature with makeRuledSurface
|
||||
obj=doc.addObject("Part::FeaturePython",'frustum')
|
||||
Frustum(obj,r1,r2,int(self.arguments['$fn']),h)
|
||||
ViewProviderTree(obj.ViewObject)
|
||||
if self.arguments['center']:
|
||||
center(obj,0,0,h)
|
||||
else: #Use Part::Loft and GetWire Feature
|
||||
obj=doc.addObject('Part::Loft','frustum')
|
||||
import Draft
|
||||
p1 = Draft.makePolygon(int(self.arguments['$fn']),r1)
|
||||
p2 = Draft.makePolygon(int(self.arguments['$fn']),r2)
|
||||
if self.arguments['center']:
|
||||
p1.Placement = FreeCAD.Placement(\
|
||||
FreeCAD.Vector(0.0,0.0,-h/2.0),FreeCAD.Rotation())
|
||||
p2.Placement = FreeCAD.Placement(\
|
||||
FreeCAD.Vector(0.0,0.0,h/2.0),FreeCAD.Rotation())
|
||||
else:
|
||||
p2.Placement = FreeCAD.Placement(\
|
||||
FreeCAD.Vector(0.0,0.0,h),FreeCAD.Rotation())
|
||||
w1=doc.addObject("Part::FeaturePython",'polygonwire1')
|
||||
w2=doc.addObject("Part::FeaturePython",'polygonwire2')
|
||||
GetWire(w1,p1)
|
||||
GetWire(w2,p2)
|
||||
ViewProviderTree(w1.ViewObject)
|
||||
ViewProviderTree(w2.ViewObject)
|
||||
obj.Sections=[w1,w2]
|
||||
obj.Solid=True
|
||||
obj.Ruled=True
|
||||
p1.ViewObject.hide()
|
||||
p2.ViewObject.hide()
|
||||
w1.ViewObject.hide()
|
||||
w2.ViewObject.hide()
|
||||
else:
|
||||
if r1 == r2:
|
||||
obj=doc.addObject("Part::Cylinder",namel)
|
||||
obj.Height = h
|
||||
obj.Radius = r1
|
||||
else:
|
||||
obj=doc.addObject("Part::Cone",'cone')
|
||||
obj.Height = h
|
||||
obj.Radius1, obj.Radius2 = r1, r2
|
||||
if self.arguments['center']:
|
||||
center(obj,0,0,h)
|
||||
elif namel == 'polyhedron':
|
||||
obj = doc.addObject("Part::Feature",namel)
|
||||
points=self.arguments['points']
|
||||
faces=self.arguments['triangles']
|
||||
shell=Part.Shell([Part.Face(Part.makePolygon(\
|
||||
[tuple(points[pointindex]) for pointindex in \
|
||||
(face+face[0:1])])) for face in faces])
|
||||
# obj.Shape=Part.Solid(shell).removeSplitter()
|
||||
solid=Part.Solid(shell).removeSplitter()
|
||||
if solid.Volume < 0:
|
||||
# solid.complement()
|
||||
solid.reverse()
|
||||
obj.Shape=solid#.removeSplitter()
|
||||
|
||||
elif namel == 'polygon':
|
||||
obj = doc.addObject("Part::Feature",namel)
|
||||
points=self.arguments['points']
|
||||
paths = self.arguments.get('paths')
|
||||
if not paths:
|
||||
faces=[Part.Face(Part.makePolygon([(x,y,0) for x,y in points+points[0:1]]))]
|
||||
else:
|
||||
faces= [Part.Face(Part.makePolygon([(points[pointindex][0],points[pointindex][1],0) for \
|
||||
pointindex in (path+path[0:1])])) for path in paths]
|
||||
obj.Shape=subtractfaces(faces)
|
||||
elif namel == 'square':
|
||||
obj = doc.addObject("Part::Plane",namel)
|
||||
x,y = self.arguments['size']
|
||||
obj.Length = x
|
||||
obj.Width = y
|
||||
if self.arguments['center']:
|
||||
center(obj,x,y,0)
|
||||
elif namel == 'circle':
|
||||
r = self.arguments['r']
|
||||
import Draft
|
||||
if '$fn' in self.arguments and self.arguments['$fn'] != 0 \
|
||||
and self.arguments['$fn']<=Node.fnmin:
|
||||
obj=Draft.makePolygon(int(self.arguments['$fn']),r)
|
||||
else:
|
||||
obj=Draft.makeCircle(r) # create a Face
|
||||
#obj = doc.addObject("Part::Circle",namel);obj.Radius = r
|
||||
elif namel == 'color':
|
||||
if len(self.children) == 1:
|
||||
obj = self.children[0].addtofreecad(doc,fcpar or True)
|
||||
else:
|
||||
obj = Node(name='imp_union',\
|
||||
children=self.children).addtofreecad(doc,fcpar or True)
|
||||
obj.ViewObject.ShapeColor = tuple([float(p) for p in self.arguments[:3]]) #RGB
|
||||
transp = 100 - int(math.floor(100*self.arguments[3])) #Alpha
|
||||
obj.ViewObject.Transparency = transp
|
||||
elif namel == 'multmatrix':
|
||||
assert(len(self.children)>0)
|
||||
m1l=[round(f,12) for f in sum(self.arguments,[])] #Thats the original matrix
|
||||
m1=FreeCAD.Matrix(*tuple(m1l)) #Thats the original matrix
|
||||
if isspecialorthogonalpython(fcsubmatrix(m1)): #a Placement can represent the transformation
|
||||
if len(self.children) == 1:
|
||||
obj = self.children[0].addtofreecad(doc,fcpar or True)
|
||||
else:
|
||||
obj = Node(name='imp_union',\
|
||||
children=self.children).addtofreecad(doc,fcpar or True)
|
||||
#FreeCAD.Console.PrintMessage('obj %s\nmat %s/n' % (obj.Placement,m1))
|
||||
obj.Placement=FreeCAD.Placement(m1).multiply(obj.Placement)
|
||||
else: #we need to apply the matrix transformation to the Shape using a custom PythonFeature
|
||||
obj=doc.addObject("Part::FeaturePython",namel)
|
||||
if len(self.children) == 1:
|
||||
child = self.children[0].addtofreecad(doc,obj)
|
||||
else:
|
||||
child = Node(name='imp_union',\
|
||||
children=self.children).addtofreecad(doc,obj)
|
||||
MatrixTransform(obj,m1,child) #This object is not mutable from the GUI
|
||||
ViewProviderTree(obj.ViewObject)
|
||||
#elif namel == 'import': pass #Custom Feature
|
||||
elif namel == 'linear_extrude':
|
||||
height = self.arguments['height']
|
||||
twist = self.arguments.get('twist')
|
||||
if not twist:
|
||||
obj = doc.addObject("Part::Extrusion",namel)
|
||||
else: #twist
|
||||
obj=doc.addObject("Part::FeaturePython",'twist_extrude')
|
||||
if len(self.children)==0:
|
||||
base= Node('import',self.arguments).addtofreecad(doc,obj)
|
||||
elif len(self.children)==1:
|
||||
base = self.children[0].addtofreecad(doc,obj)
|
||||
else:
|
||||
base = Node(name='imp_union',\
|
||||
children=self.children).addtofreecad(doc,obj)
|
||||
if False and base.isDerivedFrom('Part::MultiFuse'):
|
||||
#does not solve all the problems
|
||||
newobj=doc.addObject("Part::FeaturePython",'refine')
|
||||
RefineShape(newobj,base)
|
||||
ViewProviderTree(newobj.ViewObject)
|
||||
base.ViewObject.hide()
|
||||
base=newobj
|
||||
if not twist:
|
||||
obj.Base= base
|
||||
obj.Dir = (0,0,height)
|
||||
else: #twist
|
||||
Twist(obj,base,height,-twist)
|
||||
ViewProviderTree(obj.ViewObject)
|
||||
if self.arguments['center']:
|
||||
center(obj,0,0,height)
|
||||
base.ViewObject.hide()
|
||||
|
||||
elif namel == 'rotate_extrude':
|
||||
obj = doc.addObject("Part::Revolution",namel)
|
||||
if len(self.children)==0:
|
||||
base= Node('import',self.arguments).addtofreecad(doc,obj)
|
||||
elif len(self.children)==1:
|
||||
base = self.children[0].addtofreecad(doc,obj)
|
||||
else:
|
||||
base = Node(name='imp_union',\
|
||||
children=self.children).addtofreecad(doc,obj)
|
||||
if False and base.isDerivedFrom('Part::MultiFuse'):
|
||||
#creates 'Axe and meridian are confused' Errors
|
||||
newobj=doc.addObject("Part::FeaturePython",'refine')
|
||||
RefineShape(newobj,base)
|
||||
ViewProviderTree(newobj.ViewObject)
|
||||
base.ViewObject.hide()
|
||||
base=newobj
|
||||
obj.Source= base
|
||||
obj.Axis = (0.00,1.00,0.00)
|
||||
obj.Base = (0.00,0.00,0.00)
|
||||
obj.Angle = 360.00
|
||||
base.ViewObject.hide()
|
||||
obj.Placement=FreeCAD.Placement(FreeCAD.Vector(),FreeCAD.Rotation(0,0,90))
|
||||
elif namel == 'projection':
|
||||
if self.arguments['cut']:
|
||||
planename='xy_plane_used_for_project_cut'
|
||||
obj=doc.addObject('Part::MultiCommon','projection_cut')
|
||||
plane = doc.getObject(planename)
|
||||
if not plane:
|
||||
plane=doc.addObject("Part::Plane",planename)
|
||||
plane.Length=Node.planedim*2
|
||||
plane.Width=Node.planedim*2
|
||||
plane.Placement = FreeCAD.Placement(FreeCAD.Vector(\
|
||||
-Node.planedim,-Node.planedim,0),FreeCAD.Rotation(0,0,0,1))
|
||||
#plane.ViewObject.hide()
|
||||
subobjs = [child.addtofreecad(doc,obj) for child in self.children]
|
||||
subobjs.append(plane)
|
||||
obj.Shapes = subobjs
|
||||
for subobj in subobjs:
|
||||
subobj.ViewObject.hide()
|
||||
else:
|
||||
#Do a proper projection
|
||||
raise(NotImplementedError)
|
||||
elif namel == 'import':
|
||||
filename = self.arguments.get('file')
|
||||
scale = self.arguments.get('scale')
|
||||
origin = self.arguments.get('origin')
|
||||
if filename:
|
||||
import os
|
||||
docname=os.path.split(filename)[1]
|
||||
objname,extension = docname.split('.',1)
|
||||
if not os.path.isabs(filename):
|
||||
try:
|
||||
global lastimportpath
|
||||
filename=os.path.join(lastimportpath,filename)
|
||||
except:
|
||||
raise #no path given
|
||||
# Check for a mesh fileformat support by the Mesh mddule
|
||||
if extension.lower() in reverseimporttypes()['Mesh']:
|
||||
import Mesh
|
||||
mesh1 = doc.getObject(objname) #reuse imported object
|
||||
if not mesh1:
|
||||
Mesh.insert(filename)
|
||||
mesh1=doc.getObject(objname)
|
||||
mesh1.ViewObject.hide()
|
||||
sh=Part.Shape()
|
||||
sh.makeShapeFromMesh(mesh1.Mesh.Topology,0.1)
|
||||
solid = Part.Solid(sh)
|
||||
obj=doc.addObject("Part::FeaturePython",'import_%s_%s'%(extension,objname))
|
||||
#obj=doc.addObject('Part::Feature',)
|
||||
ImportObject(obj,mesh1) #This object is not mutable from the GUI
|
||||
ViewProviderTree(obj.ViewObject)
|
||||
solid=solid.removeSplitter()
|
||||
if solid.Volume < 0:
|
||||
#sh.reverse()
|
||||
#sh = sh.copy()
|
||||
solid.complement()
|
||||
obj.Shape=solid#.removeSplitter()
|
||||
elif extension in ['dxf']:
|
||||
layera = self.arguments.get('layer')
|
||||
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 layers:
|
||||
try:
|
||||
groupobj=[go for go in layers if (not layera) or go.Label == layera]
|
||||
except:
|
||||
groupobj= None
|
||||
else:
|
||||
groupobj= None
|
||||
if not groupobj:
|
||||
groupname=objname
|
||||
layers = importDXF.processdxf(doc,filename) or importDXF.layers
|
||||
dxfcache[id(doc)] = layers[:]
|
||||
for l in layers:
|
||||
for o in l.Group:
|
||||
o.ViewObject.hide()
|
||||
l.ViewObject.hide()
|
||||
groupobj=[go for go in layers if (not layera) or go.Label == layera]
|
||||
edges=[]
|
||||
for shapeobj in groupobj[0].Group:
|
||||
edges.extend(shapeobj.Shape.Edges)
|
||||
try:
|
||||
f=edgestofaces(edges)
|
||||
except:
|
||||
FreeCAD.Console.PrintError(\
|
||||
'processing of dxf import faild\nPlease rework \'%s\' manualy\n' % layera)
|
||||
f=Part.Shape() #empty Shape
|
||||
obj=doc.addObject("Part::FeaturePython",'import_dxf_%s_%s'%(objname,layera))
|
||||
#obj=doc.addObject('Part::Feature',)
|
||||
ImportObject(obj,groupobj[0]) #This object is not mutable from the GUI
|
||||
ViewProviderTree(obj.ViewObject)
|
||||
obj.Shape=f
|
||||
|
||||
else:
|
||||
FreeCAD.Console.ErrorMessage(\
|
||||
'Filetype of %s not supported\n' % (filename))
|
||||
raise(NotImplementedError)
|
||||
if obj: #handle origin and scale
|
||||
if scale is not None and scale !=1:
|
||||
child = obj
|
||||
m1=FreeCAD.Matrix()
|
||||
m1.scale(scale,scale,scale)
|
||||
obj=doc.addObject("Part::FeaturePython",'scale_import')
|
||||
MatrixTransform(obj,m1,child) #This object is not mutable from the GUI
|
||||
ViewProviderTree(obj.ViewObject)
|
||||
elif origin is not None and any([c != 0 for c in origin]):
|
||||
placement=FreeCAD.Placement(FreeCAD.Vector(*origin),FreeCAD.Rotation())
|
||||
obj.Placement=placement.multiply(obj.Placement)
|
||||
else:
|
||||
FreeCAD.Console.ErrorMessage('Import of %s failed\n' % (filename))
|
||||
|
||||
|
||||
elif namel == 'minkowski':
|
||||
childrennames=[child.name.lower() for child in self.children]
|
||||
if len(self.children) == 2 and \
|
||||
childrennames.count('cube')==1 and \
|
||||
(childrennames.count('sphere') + \
|
||||
childrennames.count('cylinder')) == 1:
|
||||
if self.children[0].name.lower() == 'cube':
|
||||
cube = self.children[0]
|
||||
roundobj = self.children[1]
|
||||
elif self.children[1].name.lower() == 'cube':
|
||||
cube = self.children[1]
|
||||
roundobj = self.children[0]
|
||||
roundobjname=roundobj.name.lower()
|
||||
issphere = roundobjname == 'sphere'
|
||||
cubeobj=doc.addObject('Part::Box','roundedcube')
|
||||
x,y,z=cube.arguments['size']
|
||||
r=roundobj.arguments.get('r') or \
|
||||
roundobj.arguments.get('r1')
|
||||
cubeobj.Length=x+2*r
|
||||
cubeobj.Width=y+2*r
|
||||
cubeobj.Height=z+2*r*issphere
|
||||
obj=doc.addObject("Part::Fillet","%s_%s"%(namel,roundobjname))
|
||||
obj.Base = cubeobj
|
||||
cubeobj.ViewObject.hide()
|
||||
if issphere:
|
||||
obj.Edges = [(i,r,r) for i in range(1,13)]
|
||||
else:#cylinder
|
||||
obj.Edges = [(i,r,r) for i in [1,3,5,7]]
|
||||
if cube.arguments['center']:
|
||||
center(cubeobj,x+2*r,y+2*r,z+2*r*issphere)
|
||||
else: #htandle a rotated cylinder
|
||||
#OffsetShape
|
||||
raise(NotImplementedError)
|
||||
elif childrennames.count('sphere')==1:
|
||||
sphereindex=childrennames.index('sphere')
|
||||
sphere=self.children[sphereindex]
|
||||
offset=sphere.arguments['r']
|
||||
nonsphere=self.children[0:sphereindex]+\
|
||||
self.sphere[sphereindex+1:]
|
||||
obj=doc.addObject("Part::FeaturePython",'Offset')
|
||||
if len(nonsphere) == 1:
|
||||
child = nonsphere[0].addtofreecad(doc,obj)
|
||||
else:
|
||||
child = Node(name='imp_union',\
|
||||
children=nonsphere).addtofreecad(doc,obj)
|
||||
OffsetShape(obj,child,offset)
|
||||
ViewProviderTree(obj.ViewObject)
|
||||
elif False:
|
||||
raise(NotImplementedError)
|
||||
pass # handle rotated cylinders and select edges that
|
||||
#radius = radius0 * m1.multiply(FreeCAD.Vector(0,0,1)).dot(edge.Curve.tangent(0)[0])
|
||||
else:
|
||||
raise(NotImplementedError)
|
||||
elif namel == 'surface':
|
||||
import os
|
||||
scadstr = 'surface(file = "%s", center = %s );' % \
|
||||
(self.arguments['file'], 'true' if self.arguments['center'] else 'false')
|
||||
docname=os.path.split(self.arguments['file'])[1]
|
||||
objname,extension = docname.split('.',1)
|
||||
obj = openscadmesh(doc,scadstr,objname)
|
||||
|
||||
elif namel in ['glide','hull']:
|
||||
raise(NotImplementedError)
|
||||
elif namel in ['render','subdiv'] or True:
|
||||
lenchld=len(self.children)
|
||||
if lenchld == 1:
|
||||
FreeCAD.Console.PrintMessage('Not recognized %s\n' % (self))
|
||||
obj = self.children[0].addtofreecad(doc,fcpar)
|
||||
elif lenchld >1:
|
||||
obj = Node(name='imp_union',\
|
||||
children=self.children).addtofreecad(doc,fcpar or True)
|
||||
else:
|
||||
obj = doc.addObject("Part::Feature",'Not_Impl_%s'%namel)
|
||||
if fcpar == True: #We are the last real object, our parent is not rendered.
|
||||
return obj
|
||||
|
||||
if fcpar:
|
||||
try:
|
||||
obj.ViewObject.hide()
|
||||
except:
|
||||
raise
|
||||
if True: #never refine the Shape, as it itroduces crashes
|
||||
return obj
|
||||
else: #refine Shape
|
||||
import Draft
|
||||
if obj.Type =='Part::Extrusion' and obj.Base.Type == 'Part::Part2DObjectPython' and \
|
||||
isinstance(obj.Base.Proxy,Draft._Polygon) or \
|
||||
(not obj.isDerivedFrom('Part::Extrusion') and \
|
||||
not obj.isDerivedFrom('Part::Boolean') and \
|
||||
not obj.isDerivedFrom('Part::Cut') and \
|
||||
not obj.isDerivedFrom('Part::MultiCommon') and \
|
||||
not obj.isDerivedFrom('Part::MultiFuse') and \
|
||||
not obj.isDerivedFrom('Part::Revolution') ) \
|
||||
or (obj.isDerivedFrom('Part::FeaturePython') and isinstance(obj.Proxy,RefineShape)):
|
||||
return obj
|
||||
else:
|
||||
newobj=doc.addObject("Part::FeaturePython",'refine')
|
||||
RefineShape(newobj,obj)
|
||||
ViewProviderTree(newobj.ViewObject)
|
||||
obj.ViewObject.hide()
|
||||
return newobj
|
||||
|
||||
else:
|
||||
doc.recompute()
|
||||
|
||||
def flattengroups(self,name='group'):
|
||||
"""removes group node with only one child and no arguments and empty groups"""
|
||||
node=self
|
||||
while (node.name==name and len(node.children)==1 and len(node.arguments)==0):
|
||||
node=node.children[0]
|
||||
node.children=[child for child in node.children if not (len(child.children)==0 and child.name==name)]
|
||||
if node.children:
|
||||
node.children = [child.flattengroups() for child in node.children]
|
||||
return node
|
||||
|
||||
def pprint(self,level=0):
|
||||
"""prints the indented tree"""
|
||||
if self.arguments:
|
||||
argstr = ' (%s)' % self.arguments
|
||||
else:
|
||||
argstr = ''
|
||||
print '%s %s%s' %(' '*level,self.name,argstr)
|
||||
for child in self.children:
|
||||
child.pprint(level+1)
|
||||
|
||||
def pprint2(self,path='root',pathjust=24):
|
||||
"""prints the tree. Left column contains the the systax to access a child"""
|
||||
if self.arguments:
|
||||
argstr = ' (%s)' % self.arguments
|
||||
else:
|
||||
argstr = ''
|
||||
print '%s %s%s' %(path.ljust(pathjust),self.name,argstr)
|
||||
for i,child in enumerate(self.children):
|
||||
child.pprint2('%s[%d]'%(path,i),pathjust)
|
||||
|
||||
|
||||
|
||||
|
||||
def parseexpression(e):
|
||||
e=e.strip()
|
||||
el = e.lower()
|
||||
if len(el)==0: return None
|
||||
if el == 'true': return True
|
||||
elif el == 'false': return False
|
||||
elif el == 'undef': return None
|
||||
elif e[0].isdigit() or e[0] == '-' and len(e)>1 and e[1].isdigit():
|
||||
try:
|
||||
return float(e)
|
||||
except ValueError:
|
||||
import FreeCAD
|
||||
FreeCAD.Console.PrintMessage('%s\n' % (el))
|
||||
return 1.0
|
||||
|
||||
elif el.startswith('"'): return e.strip('"') #string literal
|
||||
elif el.startswith('['):
|
||||
bopen, bclose = e.count('['), e.count(']')
|
||||
if bopen == bclose:
|
||||
return eval(el)
|
||||
else:
|
||||
import FreeCAD
|
||||
FreeCAD.Console.PrintMessage('%s\n' % (el))
|
||||
#return eval(el)
|
||||
#assert(False) #Malformed
|
||||
else:
|
||||
return e #Return the string
|
||||
|
||||
def parseargs(argstring):
|
||||
if '=' in argstring:
|
||||
level=0
|
||||
tok=[]
|
||||
a=[]
|
||||
for i,char in enumerate(argstring):
|
||||
if char=='[': level+=1
|
||||
elif char ==']': level -=1
|
||||
if level==0 and (char=='=' or char==','):
|
||||
tok.append(''.join(a).strip())
|
||||
a=[]
|
||||
else:
|
||||
a.append(char)
|
||||
tok.append(''.join(a).strip())
|
||||
#print tok
|
||||
argdict=dict(zip(tok[0::2],[parseexpression(argstring) for argstring in tok[1::2]]))
|
||||
# argdict={}
|
||||
# for key, value in re.findall(r"(\$?\w+)\s*=\s*(\[?\w+]?),?\s*",argstring):
|
||||
# argdict[key] = parseexpression(value)
|
||||
return argdict
|
||||
else:
|
||||
return parseexpression(argstring)
|
||||
|
||||
def parsenode(str1):
|
||||
name,str2=str1.strip().split('(',1)
|
||||
assert('}' not in name)
|
||||
name=name.strip('#!%* ')#remove/ignore modifiers
|
||||
args,str3=str2.split(')',1)
|
||||
str4=str3.lstrip()
|
||||
if str4.startswith(';'):
|
||||
#has no children
|
||||
nextelement=str4[1:].lstrip()
|
||||
return Node(name,parseargs(args)),nextelement
|
||||
elif str4.startswith('{'):
|
||||
#has children
|
||||
level=0
|
||||
for index,char in enumerate(str4):
|
||||
if char == '{': level += 1
|
||||
elif char == '}': level -= 1
|
||||
if level == 0:
|
||||
break
|
||||
#end of children
|
||||
childstr= str4[1:index].strip()
|
||||
nextelement = str4[index+1:].lstrip()
|
||||
bopen,bclose=childstr.count('{'),childstr.count('}')
|
||||
assert(bopen == bclose)
|
||||
children=[]
|
||||
while childstr:
|
||||
try:
|
||||
childnode,childstr=parsenode(childstr)
|
||||
children.append(childnode)
|
||||
except ValueError:
|
||||
raise
|
||||
if args:
|
||||
args=parseargs(args)
|
||||
return Node(name,args,children),nextelement
|
||||
|
||||
def readfile(filename):
|
||||
import os
|
||||
global lastimportpath
|
||||
lastimportpath,relname = os.path.split(filename)
|
||||
isopenscad = relname.lower().endswith('.scad')
|
||||
if isopenscad:
|
||||
tmpfile=callopenscad(filename)
|
||||
lastimportpath = os.getcwd() #https://github.com/openscad/openscad/issues/128
|
||||
f = pythonopen(tmpfile)
|
||||
else:
|
||||
f = pythonopen(filename)
|
||||
rootnode=parsenode(f.read())[0]
|
||||
f.close()
|
||||
if isopenscad:
|
||||
os.unlink(tmpfile)
|
||||
return rootnode.flattengroups()
|
||||
|
||||
def open(filename):
|
||||
import os
|
||||
docname=os.path.split(filename)[1]
|
||||
doc=FreeCAD.newDocument(docname)
|
||||
doc.Label = (docname.split('.',1)[0])
|
||||
readfile(filename).addtofreecad(doc)
|
||||
#doc.recompute()
|
||||
return doc
|
||||
|
||||
def insert(filename,docname):
|
||||
try:
|
||||
doc=FreeCAD.getDocument(docname)
|
||||
except:
|
||||
doc=FreeCAD.newDocument(docname)
|
||||
readfile(filename).addtofreecad(doc)
|
||||
#doc.recompute()
|
||||
|
||||
|
||||
import FreeCAD
|
||||
|
||||
global dxfcache
|
||||
dxfcache = {}
|
||||
|
||||
|
31
src/Mod/OpenSCAD/replaceobj.py
Normal file
31
src/Mod/OpenSCAD/replaceobj.py
Normal file
|
@ -0,0 +1,31 @@
|
|||
def replaceobj(parent,oldchild,newchild):
|
||||
for propname in parent.PropertiesList:
|
||||
propvalue=parent.getPropertyByName(propname)
|
||||
if type(propvalue) == list:
|
||||
for dontcare in range(propvalue.count(oldchild)):
|
||||
propvalue[propvalue.index(oldchild)] = newchild
|
||||
setattr(parent,propname,propvalue)
|
||||
#print propname, parent.getPropertyByName(propname)
|
||||
else:
|
||||
if propvalue == oldchild:
|
||||
setattr(parent,propname,newchild)
|
||||
print propname, parent.getPropertyByName(propname)
|
||||
#else: print propname,propvalue
|
||||
|
||||
def replaceobjfromselection(objs):
|
||||
assert(len(objs)==3)
|
||||
if objs[0] in objs[1].InList: parent, oldchild, newchild = objs
|
||||
elif objs[0] in objs[2].InList: parent, newchild, oldchild = objs
|
||||
elif objs[1] in objs[0].InList: oldchild, parent, newchild = objs
|
||||
elif objs[1] in objs[2].InList: newchild, parent, oldchild = objs
|
||||
elif objs[2] in objs[0].InList: oldchild, newchild, parent = objs
|
||||
elif objs[2] in objs[1].InList: newchild, oldchild, parent = objs
|
||||
else: assert(False)
|
||||
replaceobj(parent,oldchild,newchild)
|
||||
|
||||
if __name__ == '__main__':
|
||||
import FreeCAD,FreeCADGui
|
||||
objs=[selobj.Object for selobj in FreeCADGui.Selection.getSelectionEx()]
|
||||
replaceobjfromselection(objs)
|
||||
|
||||
|
132
src/Mod/OpenSCAD/tokrules.py
Normal file
132
src/Mod/OpenSCAD/tokrules.py
Normal file
|
@ -0,0 +1,132 @@
|
|||
# -*- coding: utf8 -*-
|
||||
|
||||
#***************************************************************************
|
||||
#* *
|
||||
#* Copyright (c) 2012 Keith Sloan <keith@sloan-home.co.uk> *
|
||||
#* *
|
||||
#* This program is free software; you can redistribute it and/or modify *
|
||||
#* it under the terms of the GNU General Public License (GPL) *
|
||||
#* as published by the Free Software Foundation; either version 2 of *
|
||||
#* the License, or (at your option) any later version. *
|
||||
#* for detail see the LICENCE text file. *
|
||||
#* *
|
||||
#* This program is distributed in the hope that it will be useful, *
|
||||
#* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
#* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
#* GNU Library General Public License for more details. *
|
||||
#* *
|
||||
#* You should have received a copy of the GNU Library General Public *
|
||||
#* License along with this program; if not, write to the Free Software *
|
||||
#* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
#* USA *
|
||||
#* *
|
||||
#***************************************************************************
|
||||
__title__="FreeCAD OpenSCAD Workbench - CSG importer Version 0.5c"
|
||||
__author__ = "Keith Sloan <keith@sloan-home.co.uk>"
|
||||
__url__ = ["http://www.sloan-home.co.uk/ImportCSG"]
|
||||
|
||||
# Reserved words
|
||||
reserved = (
|
||||
'group',
|
||||
'sphere',
|
||||
'cylinder',
|
||||
'cube',
|
||||
'size',
|
||||
'multmatrix',
|
||||
'intersection',
|
||||
'difference',
|
||||
'union',
|
||||
'rotate_extrude',
|
||||
'linear_extrude',
|
||||
'center',
|
||||
'true',
|
||||
'false',
|
||||
'circle',
|
||||
'square',
|
||||
'polygon',
|
||||
'paths',
|
||||
'points',
|
||||
'undef',
|
||||
'polyhedron',
|
||||
'triangles',
|
||||
'render',
|
||||
'surface',
|
||||
'subdiv',
|
||||
'glide',
|
||||
'hull',
|
||||
'minkowski',
|
||||
'projection',
|
||||
'import_stl',
|
||||
'import_dxf',
|
||||
'import',
|
||||
'origin',
|
||||
'layer',
|
||||
'file',
|
||||
'color',
|
||||
'cut',
|
||||
)
|
||||
|
||||
# List of token names. This is always required
|
||||
tokens = reserved + (
|
||||
'WORD',
|
||||
'NUMBER',
|
||||
'LPAREN',
|
||||
'RPAREN',
|
||||
'OBRACE',
|
||||
'EBRACE',
|
||||
'OSQUARE',
|
||||
'ESQUARE',
|
||||
'COMMA',
|
||||
'SEMICOL',
|
||||
'EQ',
|
||||
'STRING',
|
||||
'ID',
|
||||
'DOT'
|
||||
)
|
||||
|
||||
# Regular expression rules for simple tokens
|
||||
t_WORD = r'[$]?[a-zA-Z_]+[0-9]*'
|
||||
t_NUMBER = r'[-]?[0-9]*[\.]*[0-9]+([eE]-?[0-9]+)*'
|
||||
t_LPAREN = r'\('
|
||||
t_RPAREN = r'\)'
|
||||
t_OBRACE = r'{'
|
||||
t_EBRACE = r'\}'
|
||||
t_OSQUARE = r'\['
|
||||
t_ESQUARE = r'\]'
|
||||
t_COMMA = r','
|
||||
t_SEMICOL = r';'
|
||||
t_EQ = r'='
|
||||
t_DOT = r'\.'
|
||||
t_STRING = r'"[^"]*"'
|
||||
#t_STRING = r'["]+[a-zA-Z.]+["]+'
|
||||
# Deal with Reserved words
|
||||
reserved_map = { }
|
||||
for r in reserved:
|
||||
reserved_map[r.lower()] = r
|
||||
|
||||
# Deal with Comments
|
||||
def t_comment1(t) :
|
||||
r'//[^\r\n]*((\r\n)|<<EOF>>)'
|
||||
pass
|
||||
|
||||
def t_comment2(t) :
|
||||
r'//[^\n]*((\n)|<<EOF>>)'
|
||||
pass
|
||||
|
||||
def t_ID(t):
|
||||
r'[$]?[a-zA-Z_]+[0-9]*'
|
||||
t.type = reserved_map.get(t.value, "ID")
|
||||
return t
|
||||
|
||||
# Define a rule so we can track line numbers
|
||||
def t_newline(t):
|
||||
r'\n+'
|
||||
t.lexer.lineno += len(t.value)
|
||||
|
||||
# A string containing ignored characters (spaces and tabs)
|
||||
t_ignore = " \t\r"
|
||||
|
||||
# Error handling rule
|
||||
def t_error(t):
|
||||
print "Illegal character '%s'" % t.value[0]
|
||||
t.lexer.skip(1)
|
|
@ -159,6 +159,8 @@
|
|||
<ComponentRef Id="CompModStartLibStartPage" />
|
||||
<ComponentRef Id="CompModStartDataStartPage" />
|
||||
<ComponentRef Id="CompModWeb" />
|
||||
<ComponentRef Id="CompModOpenSCAD" />
|
||||
<ComponentRef Id="CompModOpenSCADPly" />
|
||||
<ComponentRef Id="CompExampleData" />
|
||||
|
||||
<Feature Id="FeatModImage" Title="The Image module" Description="Module to handle pictures" Level="1">
|
||||
|
|
|
@ -52,6 +52,7 @@
|
|||
<?include ModStart.wxi ?>
|
||||
<?include ModWeb.wxi ?>
|
||||
<?include ModArch.wxi ?>
|
||||
<?include ModOpenSCAD.wxi ?>
|
||||
</DirectoryRef>
|
||||
</Fragment>
|
||||
</Wix>
|
||||
|
|
51
src/WindowsInstaller/ModOpenSCAD.wxi
Normal file
51
src/WindowsInstaller/ModOpenSCAD.wxi
Normal file
|
@ -0,0 +1,51 @@
|
|||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
(c) Juergen Riegel (FreeCAD@juergen-riegel.net) 2012
|
||||
|
||||
This file is part of the FreeCAD CAx development system.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Library General Public License (LGPL)
|
||||
as published by the Free Software Foundation; either version 2 of
|
||||
the License, or (at your option) any later version.
|
||||
for detail see the LICENCE text file.
|
||||
|
||||
FreeCAD is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with FreeCAD; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
USA
|
||||
|
||||
Juergen Riegel 2012
|
||||
-->
|
||||
<Include xmlns="http://schemas.microsoft.com/wix/2006/wi">
|
||||
<Directory Id="ModOpenSCAD" Name="OpenSCAD" FileSource="../../Mod/OpenSCAD">
|
||||
<Component Id="CompModOpenSCAD" Guid="54fb73e3-7c3a-4a43-b376-008dfae6d103" Win64='$(var.Win_64)' KeyPath="yes">
|
||||
<File Id="OpenSCADInitPy" Name="Init.py" DiskId="1" />
|
||||
<File Id="OpenSCADInitGuiPy" Name="InitGui.py" DiskId="1" />
|
||||
<File Id="colorcodeshapesPy" Name="colorcodeshapes.py" DiskId="1" />
|
||||
<File Id="expandplacementspy" Name="expandplacements.py" DiskId="1" />
|
||||
<File Id="exportCSGpy" Name="exportCSG.py" DiskId="1" />
|
||||
<File Id="importCSGpy" Name="importCSG.py" DiskId="1" />
|
||||
<File Id="OpenSCAD_rcpy" Name="OpenSCAD_rc.py" DiskId="1" />
|
||||
<File Id="OpenSCAD2Dgeompy" Name="OpenSCAD2Dgeom.py" DiskId="1" />
|
||||
<File Id="OpenSCADCommandspy" Name="OpenSCADCommandspy" DiskId="1" />
|
||||
<File Id="OpenSCADFeaturespy" Name="OpenSCADFeatures.py" DiskId="1" />
|
||||
<File Id="OpenSCADUtilspy" Name="OpenSCADUtils.py" DiskId="1" />
|
||||
<File Id="prototypepy" Name="prototype.py" DiskId="1" />
|
||||
<File Id="replaceobjpy" Name="replaceobj.py" DiskId="1" />
|
||||
<File Id="tokrulespy" Name="tokrules.py" DiskId="1" />
|
||||
</Component>
|
||||
<Directory Id="ModOpenSCADPly" Name="OpenSCADPly" FileSource="../../Mod/OpenSCAD/ply">
|
||||
<Component Id="CompModOpenSCADPly" Guid="870b896b-30f8-4d3b-b923-36536c0c2859" Win64='$(var.Win_64)' KeyPath="yes">
|
||||
<File Id="OpenSCADLibInitPy" Name="__init__.py" DiskId="1" />
|
||||
<File Id="OpenSCADLibREADME" Name="README" DiskId="1" />
|
||||
<File Id="OpenSCADLibyaccpy" Name="yacc.py" DiskId="1" />
|
||||
<File Id="OpenSCADLiblexpy" Name="lex.py" DiskId="1" />
|
||||
</Component>
|
||||
</Directory>
|
||||
</Directory>
|
||||
</Include>
|
Loading…
Reference in New Issue
Block a user