Merge branch 'review-openscad'
This commit is contained in:
commit
1de8259968
|
@ -46,3 +46,6 @@ endif(FREECAD_BUILD_SANDBOX)
|
||||||
|
|
||||||
add_subdirectory(Surfaces)
|
add_subdirectory(Surfaces)
|
||||||
add_subdirectory(Ship)
|
add_subdirectory(Ship)
|
||||||
|
add_subdirectory(OpenSCAD)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#SUBDIRS=Part Mesh Points Raytracing Image Drawing Complete Draft Test TemplatePyMod
|
#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
|
#if HAVE_OPENCV
|
||||||
SUBDIRS += Image
|
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="CompModStartLibStartPage" />
|
||||||
<ComponentRef Id="CompModStartDataStartPage" />
|
<ComponentRef Id="CompModStartDataStartPage" />
|
||||||
<ComponentRef Id="CompModWeb" />
|
<ComponentRef Id="CompModWeb" />
|
||||||
|
<ComponentRef Id="CompModOpenSCAD" />
|
||||||
|
<ComponentRef Id="CompModOpenSCADPly" />
|
||||||
<ComponentRef Id="CompExampleData" />
|
<ComponentRef Id="CompExampleData" />
|
||||||
|
|
||||||
<Feature Id="FeatModImage" Title="The Image module" Description="Module to handle pictures" Level="1">
|
<Feature Id="FeatModImage" Title="The Image module" Description="Module to handle pictures" Level="1">
|
||||||
|
|
|
@ -52,6 +52,7 @@
|
||||||
<?include ModStart.wxi ?>
|
<?include ModStart.wxi ?>
|
||||||
<?include ModWeb.wxi ?>
|
<?include ModWeb.wxi ?>
|
||||||
<?include ModArch.wxi ?>
|
<?include ModArch.wxi ?>
|
||||||
|
<?include ModOpenSCAD.wxi ?>
|
||||||
</DirectoryRef>
|
</DirectoryRef>
|
||||||
</Fragment>
|
</Fragment>
|
||||||
</Wix>
|
</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