diff --git a/src/Mod/.gitattributes b/src/Mod/.gitattributes
index def8d8355a..dd95476174 100644
--- a/src/Mod/.gitattributes
+++ b/src/Mod/.gitattributes
@@ -53,6 +53,7 @@ JtReader export-ignore
# Draft/** -text
# Fem/** -text
# Material/** -text
+# OpenSCAD/** -text
# Show/** -text
# Tux/** -text
@@ -60,7 +61,7 @@ JtReader export-ignore
# line endings of the modules NOT commented will NOT be normalized
# Be carefully changes here could affect a lot of files automatically!
-# Complete, Idf, OpenSCAD makes sense to normalize
+# Complete, Idf makes sense to normalize
Assembly/** -text
Cam/** -text
@@ -75,7 +76,6 @@ JtReader/** -text
Measure/** -text
Mesh/** -text
MeshPart/** -text
-OpenSCAD/** -text
Part/** -text
PartDesign/** -text
Path/** -text
diff --git a/src/Mod/OpenSCAD/Init.py b/src/Mod/OpenSCAD/Init.py
index da643fbf01..9f3d6d0df2 100644
--- a/src/Mod/OpenSCAD/Init.py
+++ b/src/Mod/OpenSCAD/Init.py
@@ -1,37 +1,37 @@
-# 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 *
-#***************************************************************************/
-import FreeCAD,os
-FreeCAD.addImportType("OpenSCAD CSG Format (*.csg)","importCSG")
-param = FreeCAD.ParamGet(\
- "User parameter:BaseApp/Preferences/Mod/OpenSCAD")
-openscadfilename = param.GetString('openscadexecutable')
-openscadbin = openscadfilename and os.path.isfile(openscadfilename)
-if openscadbin:
- FreeCAD.addImportType("OpenSCAD Format (*.scad)","importCSG")
-FreeCAD.addExportType("OpenSCAD CSG Format (*.csg)","exportCSG")
-FreeCAD.addExportType("OpenSCAD Format (*.scad)","exportCSG")
-
+# 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 *
+#***************************************************************************/
+import FreeCAD,os
+FreeCAD.addImportType("OpenSCAD CSG Format (*.csg)","importCSG")
+param = FreeCAD.ParamGet(\
+ "User parameter:BaseApp/Preferences/Mod/OpenSCAD")
+openscadfilename = param.GetString('openscadexecutable')
+openscadbin = openscadfilename and os.path.isfile(openscadfilename)
+if openscadbin:
+ FreeCAD.addImportType("OpenSCAD Format (*.scad)","importCSG")
+FreeCAD.addExportType("OpenSCAD CSG Format (*.csg)","exportCSG")
+FreeCAD.addExportType("OpenSCAD Format (*.scad)","exportCSG")
+
diff --git a/src/Mod/OpenSCAD/OpenSCAD.dox b/src/Mod/OpenSCAD/OpenSCAD.dox
index 7b437f1e3d..9bae93322c 100644
--- a/src/Mod/OpenSCAD/OpenSCAD.dox
+++ b/src/Mod/OpenSCAD/OpenSCAD.dox
@@ -1,5 +1,5 @@
-/** \defgroup OPENSCAD OpenSCAD
- * \ingroup PYTHONWORKBENCHES
- * \brief Interface with OpenSCAD
- */
-
+/** \defgroup OPENSCAD OpenSCAD
+ * \ingroup PYTHONWORKBENCHES
+ * \brief Interface with OpenSCAD
+ */
+
diff --git a/src/Mod/OpenSCAD/Resources/OpenSCAD.qrc b/src/Mod/OpenSCAD/Resources/OpenSCAD.qrc
index 0d9a62388b..52e78016d5 100644
--- a/src/Mod/OpenSCAD/Resources/OpenSCAD.qrc
+++ b/src/Mod/OpenSCAD/Resources/OpenSCAD.qrc
@@ -1,54 +1,54 @@
-
-
- icons/preferences-openscad.svg
- icons/OpenSCAD_AddOpenSCADElement.svg
- icons/OpenSCAD_ColorCodeShape.svg
- icons/OpenSCAD_RefineShapeFeature.svg
- icons/OpenSCAD_IncreaseToleranceFeature.svg
- icons/OpenSCAD_ReplaceObject.svg
- icons/OpenSCAD_RemoveSubtree.svg
- icons/OpenSCAD_Explode_Group.svg
- icons/OpenSCAD_MeshBooleans.svg
- icons/OpenSCAD_Hull.svg
- icons/OpenSCAD_Minkowski.svg
- icons/OpenSCADWorkbench.svg
- ui/openscadprefs-base.ui
- translations/OpenSCAD_tr.qm
- translations/OpenSCAD_sv-SE.qm
- translations/OpenSCAD_de.qm
- translations/OpenSCAD_pl.qm
- translations/OpenSCAD_fi.qm
- translations/OpenSCAD_zh-TW.qm
- translations/OpenSCAD_no.qm
- translations/OpenSCAD_nl.qm
- translations/OpenSCAD_pt-BR.qm
- translations/OpenSCAD_uk.qm
- translations/OpenSCAD_cs.qm
- translations/OpenSCAD_sk.qm
- translations/OpenSCAD_fr.qm
- translations/OpenSCAD_ru.qm
- translations/OpenSCAD_af.qm
- translations/OpenSCAD_hr.qm
- translations/OpenSCAD_es-ES.qm
- translations/OpenSCAD_zh-CN.qm
- translations/OpenSCAD_ja.qm
- translations/OpenSCAD_ro.qm
- translations/OpenSCAD_hu.qm
- translations/OpenSCAD_it.qm
- translations/OpenSCAD_pt-PT.qm
- translations/OpenSCAD_sr.qm
- translations/OpenSCAD_el.qm
- translations/OpenSCAD_sl.qm
- translations/OpenSCAD_eu.qm
- translations/OpenSCAD_ca.qm
- translations/OpenSCAD_gl.qm
- translations/OpenSCAD_kab.qm
- translations/OpenSCAD_ko.qm
- translations/OpenSCAD_fil.qm
- translations/OpenSCAD_id.qm
- translations/OpenSCAD_lt.qm
- translations/OpenSCAD_val-ES.qm
- translations/OpenSCAD_ar.qm
- translations/OpenSCAD_vi.qm
-
-
+
+
+ icons/preferences-openscad.svg
+ icons/OpenSCAD_AddOpenSCADElement.svg
+ icons/OpenSCAD_ColorCodeShape.svg
+ icons/OpenSCAD_RefineShapeFeature.svg
+ icons/OpenSCAD_IncreaseToleranceFeature.svg
+ icons/OpenSCAD_ReplaceObject.svg
+ icons/OpenSCAD_RemoveSubtree.svg
+ icons/OpenSCAD_Explode_Group.svg
+ icons/OpenSCAD_MeshBooleans.svg
+ icons/OpenSCAD_Hull.svg
+ icons/OpenSCAD_Minkowski.svg
+ icons/OpenSCADWorkbench.svg
+ ui/openscadprefs-base.ui
+ translations/OpenSCAD_tr.qm
+ translations/OpenSCAD_sv-SE.qm
+ translations/OpenSCAD_de.qm
+ translations/OpenSCAD_pl.qm
+ translations/OpenSCAD_fi.qm
+ translations/OpenSCAD_zh-TW.qm
+ translations/OpenSCAD_no.qm
+ translations/OpenSCAD_nl.qm
+ translations/OpenSCAD_pt-BR.qm
+ translations/OpenSCAD_uk.qm
+ translations/OpenSCAD_cs.qm
+ translations/OpenSCAD_sk.qm
+ translations/OpenSCAD_fr.qm
+ translations/OpenSCAD_ru.qm
+ translations/OpenSCAD_af.qm
+ translations/OpenSCAD_hr.qm
+ translations/OpenSCAD_es-ES.qm
+ translations/OpenSCAD_zh-CN.qm
+ translations/OpenSCAD_ja.qm
+ translations/OpenSCAD_ro.qm
+ translations/OpenSCAD_hu.qm
+ translations/OpenSCAD_it.qm
+ translations/OpenSCAD_pt-PT.qm
+ translations/OpenSCAD_sr.qm
+ translations/OpenSCAD_el.qm
+ translations/OpenSCAD_sl.qm
+ translations/OpenSCAD_eu.qm
+ translations/OpenSCAD_ca.qm
+ translations/OpenSCAD_gl.qm
+ translations/OpenSCAD_kab.qm
+ translations/OpenSCAD_ko.qm
+ translations/OpenSCAD_fil.qm
+ translations/OpenSCAD_id.qm
+ translations/OpenSCAD_lt.qm
+ translations/OpenSCAD_val-ES.qm
+ translations/OpenSCAD_ar.qm
+ translations/OpenSCAD_vi.qm
+
+
diff --git a/src/Mod/OpenSCAD/importCSG.py b/src/Mod/OpenSCAD/importCSG.py
index 8154875e59..f59e1285b4 100644
--- a/src/Mod/OpenSCAD/importCSG.py
+++ b/src/Mod/OpenSCAD/importCSG.py
@@ -1,1207 +1,1207 @@
-# -*- coding: utf8 -*-
-
-#***************************************************************************
-#* *
-#* Copyright (c) 2012 Keith Sloan *
-#* *
-#* 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 *
-#* *
-#* Acknowledgements : *
-#* *
-#* Thanks to shoogen on the FreeCAD forum and Peter Li *
-#* for programming advice and some code. *
-#* *
-#* *
-#***************************************************************************
-__title__="FreeCAD OpenSCAD Workbench - CSG importer"
-__author__ = "Keith Sloan "
-__url__ = ["http://www.sloan-home.co.uk/ImportCSG"]
-
-printverbose = False
-
-import FreeCAD, io, os, sys
-if FreeCAD.GuiUp:
- import FreeCADGui
- gui = True
-else:
- if printverbose: print("FreeCAD Gui not present.")
- gui = False
-
-
-import ply.lex as lex
-import ply.yacc as yacc
-import Part
-
-from OpenSCADFeatures import *
-from OpenSCADUtils import *
-
-params = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/OpenSCAD")
-printverbose = params.GetBool('printVerbose',False)
-
-# Get the token map from the lexer. This is required.
-import tokrules
-from tokrules import tokens
-
-try:
- _encoding = QtGui.QApplication.UnicodeUTF8
- def translate(context, text):
- "convenience function for Qt translator"
- from PySide import QtGui
- return QtGui.QApplication.translate(context, text, None, _encoding)
-except AttributeError:
- def translate(context, text):
- "convenience function for Qt translator"
- from PySide import QtGui
- return QtGui.QApplication.translate(context, text, None)
-
-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)
- if workaroundforissue128needed():
- pathName = '' #https://github.com/openscad/openscad/issues/128
- #pathName = os.getcwd() #https://github.com/openscad/openscad/issues/128
- else:
- pathName = os.path.dirname(os.path.normpath(filename))
- processcsg(tmpfile)
- try:
- os.unlink(tmpfile)
- except OSError:
- pass
- 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 NameError:
- doc=FreeCAD.newDocument(docname)
- #importgroup = doc.addObject("App::DocumentObjectGroup",groupname)
- if filename.lower().endswith('.scad'):
- tmpfile=callopenscad(filename)
- if workaroundforissue128needed():
- pathName = '' #https://github.com/openscad/openscad/issues/128
- #pathName = os.getcwd() #https://github.com/openscad/openscad/issues/128
- else:
- pathName = os.path.dirname(os.path.normpath(filename))
- processcsg(tmpfile)
- try:
- os.unlink(tmpfile)
- except OSError:
- pass
- else:
- pathName = os.path.dirname(os.path.normpath(filename))
- processcsg(filename)
-
-def processcsg(filename):
- global doc
-
- if printverbose: print ('ImportCSG Version 0.6a')
- # Build the lexer
- if printverbose: print('Start Lex')
- lex.lex(module=tokrules)
- if printverbose: print('End Lex')
-
- # Build the parser
- if printverbose: print('Load Parser')
- # No debug out otherwise Linux has protection exception
- parser = yacc.yacc(debug=0)
- if printverbose: print('Parser Loaded')
- # Give the lexer some input
- #f=open('test.scad', 'r')
- f = io.open(filename, 'r', encoding="utf8")
- #lexer.input(f.read())
-
- if printverbose: print('Start Parser')
- # Swap statements to enable Parser debugging
- #result = parser.parse(f.read(),debug=1)
- result = parser.parse(f.read())
- f.close()
- if printverbose:
- print('End Parser')
- print(result)
- FreeCAD.Console.PrintMessage('End processing CSG file\n')
- doc.recompute()
-
-def p_block_list_(p):
- '''
- block_list : statement
- | block_list statement
- | statementwithmod
- | block_list statementwithmod
- '''
- #if printverbose: print("Block List")
- #if printverbose: print(p[1])
- if(len(p) > 2) :
- if printverbose: print(p[2])
- p[0] = p[1] + p[2]
- else :
- p[0] = p[1]
- #if printverbose: print("End Block List")
-
-def p_render_action(p):
- 'render_action : render LPAREN keywordargument_list RPAREN OBRACE block_list EBRACE'
- if printverbose: print("Render (ignored)")
- p[0] = p[6]
-
-def p_group_action1(p):
- 'group_action1 : group LPAREN RPAREN OBRACE block_list EBRACE'
- if printverbose: print("Group")
-# Test if need for implicit fuse
- if (len(p[5]) > 1) :
- p[0] = [fuse(p[5],"Group")]
- else :
- p[0] = p[5]
-
-def p_group_action2(p) :
- 'group_action2 : group LPAREN RPAREN SEMICOL'
- if printverbose: 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
- | render_action
- | not_supported
- '''
- p[0] = p[1]
-
-def p_anymodifier(p):
- '''anymodifier : MODIFIERBACK
- | MODIFIERDEBUG
- | MODIFIERROOT
- | MODIFIERDISABLE
- '''
- #just return the plain modifier for now
- #has to be changed when the modifiers are implemented
- #please note that disabled objects usually are stripped of the CSG output during compilation
- p[0] = p[1]
-
-def p_statementwithmod(p):
- '''statementwithmod : anymodifier statement'''
- #ignore the modifiers but add them to the label
- modifier = p[1]
- obj = p[2]
- if hasattr(obj,'Label'):
- obj.Label = modifier + obj.Label
- p[0] = obj
-
-def p_part(p):
- '''
- part : sphere_action
- | cylinder_action
- | cube_action
- | circle_action
- | square_action
- | text_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
- if printverbose: 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] == ',' :
- #if printverbose:
- # print("Start List")
- # print(p[1])
- p[0] = [p[1]]
- else :
- if printverbose:
- print(p[1])
- print(p[2])
- p[1].append(p[2])
- p[0] = p[1]
- #if printverbose: print(p[0])
-
-def p_3d_point(p):
- '3d_point : OSQUARE NUMBER COMMA NUMBER COMMA NUMBER ESQUARE'
- global points_list
- if printverbose: 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] == ',' :
- if printverbose: print("Start List")
- if printverbose: print(p[1])
- p[0] = [p[1]]
- else :
- if printverbose: print(p[1])
- if printverbose: print(p[2])
- p[1].append(p[2])
- p[0] = p[1]
- if printverbose: print(p[0])
-
-def p_path_points(p):
- '''
- path_points : NUMBER COMMA
- | path_points NUMBER COMMA
- | path_points NUMBER
- '''
- #if printverbose: print("Path point")
- if p[2] == ',' :
- #if printverbose: print('Start list')
- #if printverbose: print(p[1])
- p[0] = [int(p[1])]
- else :
- #if printverbose: print(p[1])
- #if printverbose: print(len(p[1]))
- #if printverbose: print(p[2])
- p[1].append(int(p[2]))
- p[0] = p[1]
- #if printverbose: print(p[0])
-
-
-def p_path_list(p):
- 'path_list : OSQUARE path_points ESQUARE'
- #if printverbose: print('Path List ')
- #if printverbose: print(p[2])
- p[0] = p[2]
-
-def p_path_set(p) :
- '''
- path_set : path_list
- | path_set COMMA path_list
- '''
- #if printverbose: print('Path Set')
- #if printverbose: print(len(p))
- if len(p) == 2 :
- p[0] = [p[1]]
- else :
- p[1].append(p[3])
- p[0] = p[1]
- #if printverbose: print(p[0])
-
-def p_operation(p):
- '''
- operation : difference_action
- | intersection_action
- | union_action
- | rotate_extrude_action
- | linear_extrude_with_twist
- | rotate_extrude_file
- | import_file1
- | surface_action
- | projection_action
- | hull_action
- | minkowski_action
- | offset_action
- '''
- p[0] = p[1]
-
-def placeholder(name,children,arguments):
- from OpenSCADFeatures import OpenSCADPlaceholder
- newobj=doc.addObject("Part::FeaturePython",name)
- OpenSCADPlaceholder(newobj,children,str(arguments))
- if gui:
- if FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/OpenSCAD").\
- GetBool('useViewProviderTree'):
- from OpenSCADFeatures import ViewProviderTree
- ViewProviderTree(newobj.ViewObject)
- else:
- newobj.ViewObject.Proxy = 0
- #don't hide the children
- return newobj
-
-def CGALFeatureObj(name,children,arguments=[]):
- myobj=doc.addObject("Part::FeaturePython",name)
- CGALFeature(myobj,name,children,str(arguments))
- if gui:
- for subobj in children:
- subobj.ViewObject.hide()
- if FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/OpenSCAD").\
- GetBool('useViewProviderTree'):
- from OpenSCADFeatures import ViewProviderTree
- ViewProviderTree(myobj.ViewObject)
- else:
- myobj.ViewObject.Proxy = 0
- return myobj
-
-def p_offset_action(p):
- 'offset_action : offset LPAREN keywordargument_list RPAREN OBRACE block_list EBRACE'
- if len(p[6]) == 0:
- newobj = placeholder('group',[],'{}')
- elif (len(p[6]) == 1 ): #single object
- subobj = p[6]
- else:
- subobj = fuse(p[6],"Offset Union")
- if 'r' in p[3] :
- offset = float(p[3]['r'])
- if 'delta' in p[3] :
- offset = float(p[3]['delta'])
- if subobj[0].Shape.Volume == 0 :
- newobj=doc.addObject("Part::Offset2D",'Offset2D')
- newobj.Source = subobj[0]
- newobj.Value = offset
- if 'r' in p[3] :
- newobj.Join = 0
- else :
- newobj.Join = 2
- else :
- newobj=doc.addObject("Part::Offset",'offset')
- newobj.Shape = subobj[0].Shape.makeOffset(offset)
- newobj.Document.recompute()
- if gui:
- subobj[0].ViewObject.hide()
-# if FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/OpenSCAD").\
-# GetBool('useViewProviderTree'):
-# from OpenSCADFeatures import ViewProviderTree
-# ViewProviderTree(newobj.ViewObject)
-# else:
-# newobj.ViewObject.Proxy = 0
- p[0] = [newobj]
-
-def p_hull_action(p):
- 'hull_action : hull LPAREN RPAREN OBRACE block_list EBRACE'
- p[0] = [ CGALFeatureObj(p[1],p[5]) ]
-
-def p_minkowski_action(p):
- '''
- minkowski_action : minkowski LPAREN keywordargument_list RPAREN OBRACE block_list EBRACE'''
- p[0] = [ CGALFeatureObj(p[1],p[6],p[3]) ]
-
-def p_not_supported(p):
- '''
- not_supported : glide LPAREN keywordargument_list RPAREN OBRACE block_list EBRACE
- | resize LPAREN keywordargument_list RPAREN OBRACE block_list EBRACE
- | subdiv LPAREN keywordargument_list RPAREN OBRACE block_list EBRACE
- '''
- if gui and not FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/OpenSCAD").\
- GetBool('usePlaceholderForUnsupported'):
- from PySide import QtGui
- QtGui.QMessageBox.critical(None, translate('OpenSCAD',"Unsupported Function")+" : "+p[1],translate('OpenSCAD',"Press OK"))
- else:
- p[0] = [placeholder(p[1],p[6],p[3])]
-
-def p_size_vector(p):
- 'size_vector : OSQUARE NUMBER COMMA NUMBER COMMA NUMBER ESQUARE'
- if printverbose: print("size vector")
- p[0] = [p[2],p[4],p[6]]
-
-def p_keywordargument(p):
- '''keywordargument : ID EQ boolean
- | ID EQ NUMBER
- | ID EQ size_vector
- | ID EQ vector
- | ID EQ 2d_point
- | text EQ stripped_string
- | ID EQ stripped_string
- '''
- p[0] = (p[1],p[3])
- if printverbose: print(p[0])
-
-def p_keywordargument_list(p):
- '''
- keywordargument_list : keywordargument
- | keywordargument_list COMMA keywordargument
- '''
- if len(p) == 2:
- p[0] = {p[1][0] : p[1][1]}
- else:
- p[1][p[3][0]] = p[3][1]
- p[0]=p[1]
-
-def p_color_action(p):
- 'color_action : color LPAREN vector RPAREN OBRACE block_list EBRACE'
- import math
- if printverbose: print("Color")
- color = tuple([float(f) for f in p[3][:3]]) #RGB
- transp = 100 - int(math.floor(100*float(p[3][3]))) #Alpha
- if gui:
- 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):
- if printverbose: print("Syntax error in input!")
- if printverbose: print(p)
-
-def fuse(lst,name):
- global doc
- if printverbose: print("Fuse")
- if printverbose: print(lst)
- if len(lst) == 0:
- myfuse = placeholder('group',[],'{}')
- elif len(lst) == 1:
- return lst[0]
- # Is this Multi Fuse
- elif len(lst) > 2:
- if printverbose: print("Multi Fuse")
- myfuse = doc.addObject('Part::MultiFuse',name)
- myfuse.Shapes = lst
- if gui:
- for subobj in myfuse.Shapes:
- subobj.ViewObject.hide()
- else:
- if printverbose: print("Single Fuse")
- myfuse = doc.addObject('Part::Fuse',name)
- myfuse.Base = lst[0]
- myfuse.Tool = lst[1]
- if gui:
- myfuse.Base.ViewObject.hide()
- myfuse.Tool.ViewObject.hide()
- return(myfuse)
-
-def p_union_action(p):
- 'union_action : union LPAREN RPAREN OBRACE block_list EBRACE'
- if printverbose: print("union")
- newpart = fuse(p[5],p[1])
- if printverbose: print("Push Union Result")
- p[0] = [newpart]
- if printverbose: print("End Union")
-
-def p_difference_action(p):
- 'difference_action : difference LPAREN RPAREN OBRACE block_list EBRACE'
-
- if printverbose: print("difference")
- if printverbose: print(len(p[5]))
- if printverbose: print(p[5])
- if (len(p[5]) == 0 ): #nochild
- mycut = placeholder('group',[],'{}')
- elif (len(p[5]) == 1 ): #single object
- p[0] = p[5]
- else:
-# Cut using Fuse
- mycut = doc.addObject('Part::Cut',p[1])
- mycut.Base = p[5][0]
-# Can only Cut two objects do we need to fuse extras
- if (len(p[5]) > 2 ):
- if printverbose: print("Need to Fuse Extra First")
- mycut.Tool = fuse(p[5][1:],'union')
- else :
- mycut.Tool = p[5][1]
- if gui:
- mycut.Base.ViewObject.hide()
- mycut.Tool.ViewObject.hide()
- if printverbose: print("Push Resulting Cut")
- p[0] = [mycut]
- if printverbose: print("End Cut")
-
-def p_intersection_action(p):
- 'intersection_action : intersection LPAREN RPAREN OBRACE block_list EBRACE'
-
- if printverbose: print("intersection")
- # Is this Multi Common
- if (len(p[5]) > 2):
- if printverbose: print("Multi Common")
- mycommon = doc.addObject('Part::MultiCommon',p[1])
- mycommon.Shapes = p[5]
- if gui:
- for subobj in mycommon.Shapes:
- subobj.ViewObject.hide()
- elif (len(p[5]) == 2):
- if printverbose: print("Single Common")
- mycommon = doc.addObject('Part::Common',p[1])
- mycommon.Base = p[5][0]
- mycommon.Tool = p[5][1]
- if gui:
- mycommon.Base.ViewObject.hide()
- mycommon.Tool.ViewObject.hide()
- elif (len(p[5]) == 1):
- mycommon = p[5][0]
- else : # 1 child
- mycommon = placeholder('group',[],'{}')
- p[0] = [mycommon]
- if printverbose: print("End Intersection")
-
-def process_rotate_extrude(obj,angle):
- newobj=doc.addObject("Part::FeaturePython",'RefineRotateExtrude')
- RefineShape(newobj,obj)
- if gui:
- if FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/OpenSCAD").\
- GetBool('useViewProviderTree'):
- from OpenSCADFeatures import ViewProviderTree
- ViewProviderTree(newobj.ViewObject)
- else:
- newobj.ViewObject.Proxy = 0
- obj.ViewObject.hide()
- myrev = doc.addObject("Part::Revolution","RotateExtrude")
- myrev.Source = newobj
- myrev.Axis = (0.00,1.00,0.00)
- myrev.Base = (0.00,0.00,0.00)
- myrev.Angle = angle
- myrev.Placement=FreeCAD.Placement(FreeCAD.Vector(),FreeCAD.Rotation(0,0,90))
- if gui:
- newobj.ViewObject.hide()
- return(myrev)
-
-def p_rotate_extrude_action(p):
- 'rotate_extrude_action : rotate_extrude LPAREN keywordargument_list RPAREN OBRACE block_list EBRACE'
- if printverbose: print("Rotate Extrude")
- if (len(p[6]) > 1) :
- part = fuse(p[6],"Rotate Extrude Union")
- else :
- part = p[6][0]
- angle = float(p[3]['angle'])
- p[0] = [process_rotate_extrude(part,angle)]
- if printverbose: print("End Rotate Extrude")
-
-def p_rotate_extrude_file(p):
- 'rotate_extrude_file : rotate_extrude LPAREN keywordargument_list RPAREN SEMICOL'
- if printverbose: print("Rotate Extrude File")
- filen,ext =p[3]['file'] .rsplit('.',1)
- obj = process_import_file(filen,ext,p[3]['layer'])
- p[0] = [process_rotate_extrude(obj)]
- if printverbose: print("End Rotate Extrude File")
-
-def process_linear_extrude(obj,h) :
- #if gui:
- newobj=doc.addObject("Part::FeaturePython",'RefineLinearExtrude')
- RefineShape(newobj,obj)#mylinear)
- if gui:
- if FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/OpenSCAD").\
- GetBool('useViewProviderTree'):
- from OpenSCADFeatures import ViewProviderTree
- ViewProviderTree(newobj.ViewObject)
- else:
- newobj.ViewObject.Proxy = 0
- obj.ViewObject.hide()
- #mylinear.ViewObject.hide()
- mylinear = doc.addObject("Part::Extrusion","LinearExtrude")
- mylinear.Base = newobj #obj
- mylinear.Dir = (0,0,h)
- mylinear.Placement=FreeCAD.Placement()
- # V17 change to False mylinear.Solid = True
- mylinear.Solid = False
- if gui:
- newobj.ViewObject.hide()
- return(mylinear)
-
-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, height and twist are floats
- if gui:
- 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 keywordargument_list RPAREN OBRACE block_list EBRACE'
- if printverbose: print("Linear Extrude With Twist")
- h = float(p[3]['height'])
- if printverbose: print("Twist : ",p[3])
- if 'twist' in p[3]:
- t = float(p[3]['twist'])
- else:
- t = 0
- # Test if null object like from null text
- if (len(p[6]) == 0) :
- p[0] = []
- return
- if (len(p[6]) > 1) :
- obj = fuse(p[6],"Linear Extrude Union")
- else :
- obj = p[6][0]
- if t:
- newobj = process_linear_extrude_with_twist(obj,h,t)
- else:
- newobj = process_linear_extrude(obj,h)
- if p[3]['center']=='true' :
- center(newobj,0,0,h)
- p[0] = [newobj]
- if printverbose: print("End Linear Extrude with twist")
-
-def p_import_file1(p):
- 'import_file1 : import LPAREN keywordargument_list RPAREN SEMICOL'
- if printverbose: print("Import File")
- filen,ext =p[3]['file'].rsplit('.',1)
- p[0] = [process_import_file(filen,ext,p[3]['layer'])]
- if printverbose: print("End Import File")
-
-def p_surface_action(p):
- 'surface_action : surface LPAREN keywordargument_list RPAREN SEMICOL'
- if printverbose: print("Surface")
- obj = doc.addObject("Part::Feature",'surface')
- obj.Shape,xoff,yoff=makeSurfaceVolume(p[3]['file'])
- if p[3]['center']=='true' :
- center(obj,xoff,yoff,0.0)
- p[0] = [obj]
- if printverbose: print("End surface")
-
-def process_import_file(fname,ext,layer):
- if printverbose: print("Importing : "+fname+"."+ext+" Layer : "+layer)
- if ext.lower() in reverseimporttypes()['Mesh']:
- obj=process_mesh_file(fname,ext)
- elif ext.lower() == 'dxf' :
- obj=processDXF(fname,layer)
- else:
- raise ValueError("Unsupported file extension %s" % ext)
- return(obj)
-
-def process_mesh_file(fname,ext):
- import Mesh,Part
- fullname = fname+'.'+ext
- filename = os.path.join(pathName,fullname)
- objname = os.path.split(fname)[1]
- mesh1 = doc.getObject(objname) #reuse imported object
- if not mesh1:
- Mesh.insert(filename)
- mesh1=doc.getObject(objname)
- if mesh1 is not None:
- if gui:
- 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()
- else: #mesh1 is None
- FreeCAD.Console.PrintError('Mesh not imported %s.%s %s\n' % \
- (objname,ext,filename))
- import Part
- obj=doc.addObject('Part::Feature',"FailedMeshImport")
- obj.Shape=Part.Compound([])
- return(obj)
-
-
-def processTextCmd(t):
- import os
- from OpenSCADUtils import callopenscadstring
- tmpfilename = callopenscadstring(t,'dxf')
- from OpenSCAD2Dgeom import importDXFface
- face = importDXFface(tmpfilename,None,None)
- obj=doc.addObject('Part::Feature','text')
- obj.Shape=face
- try:
- os.unlink(tmpfilename)
- except OSError:
- pass
- return(obj)
-
-def processDXF(fname,layer):
- global doc
- global pathName
- from OpenSCAD2Dgeom import importDXFface
- if printverbose: print("Process DXF file")
- if printverbose: print("File Name : "+fname)
- if printverbose: print("Layer : "+layer)
- if printverbose: print("PathName : "+pathName)
- dxfname = fname+'.dxf'
- filename = os.path.join(pathName,dxfname)
- shortname = os.path.split(fname)[1]
- if printverbose: print("DXF Full path : "+filename)
- face = importDXFface(filename,layer,doc)
- obj=doc.addObject('Part::Feature','dxf_%s_%s' % (shortname,layer or "all"))
- obj.Shape=face
- if printverbose: print("DXF Diagnostics")
- if printverbose: print(obj.Shape.ShapeType)
- if printverbose: print("Closed : "+str(obj.Shape.isClosed()))
- if printverbose: print(obj.Shape.check())
- if printverbose: print([w.isClosed() for w in obj.Shape.Wires])
- return(obj)
-
-def processSTL(fname):
- if printverbose: print("Process STL file")
-
-def p_multmatrix_action(p):
- 'multmatrix_action : multmatrix LPAREN matrix RPAREN OBRACE block_list EBRACE'
- if printverbose: print("MultMatrix")
- transform_matrix = FreeCAD.Matrix()
- if printverbose: print("Multmatrix")
- if printverbose: print(p[3])
- m1l=sum(p[3],[])
- if any('x' in me for me in m1l): #hexfloats
- m1l=[float.fromhex(me) for me in m1l]
- matrixisrounded=False
- elif max((len(me) for me in m1l)) >= 14: #might have double precision
- m1l=[float(me) for me in m1l] # assume precise output
- m1l=[(0 if (abs(me) < 1e-15) else me) for me in m1l]
- matrixisrounded=False
- else: #trucanted numbers
- m1l=[round(float(me),12) for me in m1l] #round
- matrixisrounded=True
- transform_matrix = FreeCAD.Matrix(*tuple(m1l))
- if printverbose: print(transform_matrix)
- if printverbose: print("Apply Multmatrix")
-# If more than one object on the stack for multmatrix fuse first
- if (len(p[6]) == 0) :
- part = placeholder('group',[],'{}')
- elif (len(p[6]) > 1) :
- part = fuse(p[6],"Matrix Union")
- else :
- part = p[6][0]
- if (isspecialorthogonalpython(fcsubmatrix(transform_matrix))) :
- if printverbose: print("special orthogonal")
- if matrixisrounded:
- if printverbose: print("rotation rounded")
- plm=FreeCAD.Placement(transform_matrix)
- plm=FreeCAD.Placement(plm.Base,roundrotation(plm.Rotation))
- part.Placement=plm.multiply(part.Placement)
- else:
- part.Placement=FreeCAD.Placement(transform_matrix).multiply(\
- part.Placement)
- new_part = part
- elif isrotoinversionpython(fcsubmatrix(transform_matrix)):
- if printverbose: print("orthogonal and inversion")
- cmat,axisvec = decomposerotoinversion(transform_matrix)
- new_part=doc.addObject("Part::Mirroring",'mirr_%s'%part.Name)
- new_part.Source=part
- new_part.Normal=axisvec
- if matrixisrounded:
- if printverbose: print("rotation rounded")
- plm=FreeCAD.Placement(cmat)
- new_part.Placement=FreeCAD.Placement(plm.Base,roundrotation(plm.Rotation))
- else:
- new_part.Placement=FreeCAD.Placement(cmat)
- new_part.Label="mirrored %s" % part.Label
- if gui:
- part.ViewObject.hide()
- 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 gui:
- 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 :
- if printverbose: 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)
- if gui:
- 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)
- if gui:
- newobj.ViewObject.Proxy = 0
- new_part.ViewObject.hide()
- p[0] = [newobj]
- else :
- p[0] = [new_part]
- if printverbose: print("Multmatrix applied")
-
-def p_matrix(p):
- 'matrix : OSQUARE vector COMMA vector COMMA vector COMMA vector ESQUARE'
- if printverbose: 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'
- if printverbose: 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 keywordargument_list RPAREN SEMICOL'
- if printverbose: print("Sphere : ",p[3])
- r = float(p[3]['r'])
- mysphere = doc.addObject("Part::Sphere",p[1])
- mysphere.Radius = r
- if printverbose: print("Push Sphere")
- p[0] = [mysphere]
- if printverbose: print("End Sphere")
-
-def myPolygon(n,r1):
- # Adapted from Draft::_Polygon
- import math
- if printverbose: 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 keywordargument_list RPAREN SEMICOL'
- if printverbose: print("Cylinder")
- tocenter = p[3]['center']
- h = float(p[3]['h'])
- r1 = float(p[3]['r1'])
- r2 = float(p[3]['r2'])
- #n = int(p[3]['$fn'])
- n = int(round(float(p[3]['$fn'])))
- fnmax = FreeCAD.ParamGet(\
- "User parameter:BaseApp/Preferences/Mod/OpenSCAD").\
- GetInt('useMaxFN')
- if printverbose: print(p[3])
- if h > 0:
- if ( r1 == r2 and r1 > 0):
- if printverbose: print("Make Cylinder")
- if n < 3 or fnmax != 0 and n > fnmax:
- mycyl=doc.addObject("Part::Cylinder",p[1])
- mycyl.Height = h
- mycyl.Radius = r1
- else :
- if printverbose: print("Make Prism")
- if False: #user Draft Polygon
- mycyl=doc.addObject("Part::Extrusion","prism")
- mycyl.Dir = (0,0,h)
- try :
- import Draft
- mycyl.Base = Draft.makePolygon(n,r1,face=True)
- 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
- if printverbose: print("Draft makePolygon Failed, falling back on manual polygon")
- mycyl.Base = myPolygon(n,r1)
- # mycyl.Solid = True
-
- else :
- pass
- if gui:
- mycyl.Base.ViewObject.hide()
- else: #Use Part::Prism primitive
- mycyl=doc.addObject("Part::Prism","prism")
- mycyl.Polygon = n
- mycyl.Circumradius = r1
- mycyl.Height = h
-
- elif (r1 != r2):
- if n < 3 or fnmax != 0 and n > fnmax:
- if printverbose: print("Make Cone")
- mycyl=doc.addObject("Part::Cone",p[1])
- mycyl.Height = h
- mycyl.Radius1 = r1
- mycyl.Radius2 = r2
- else:
- if printverbose: print("Make Frustum")
- mycyl=doc.addObject("Part::FeaturePython",'frustum')
- Frustum(mycyl,r1,r2,n,h)
- if gui:
- if FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/OpenSCAD").\
- GetBool('useViewProviderTree'):
- from OpenSCADFeatures import ViewProviderTree
- ViewProviderTree(mycyl.ViewObject)
- else:
- mycyl.ViewObject.Proxy = 0
- else: # r1 == r2 == 0
- FreeCAD.Console.PrintWarning('cylinder with radius zero\n')
- mycyl=doc.addObject("Part::Feature","emptycyl")
- mycyl.Shape = Part.Compound([])
- else: # h == 0
- FreeCAD.Console.PrintWarning('cylinder with height <= zero\n')
- mycyl=doc.addObject("Part::Feature","emptycyl")
- mycyl.Shape = Part.Compound([])
- if printverbose: print("Center = ",tocenter)
- if tocenter=='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 gui:
- 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]
- if printverbose: print("End Cylinder")
-
-def p_cube_action(p):
- 'cube_action : cube LPAREN keywordargument_list RPAREN SEMICOL'
- global doc
- l,w,h = [float(str1) for str1 in p[3]['size']]
- if (l > 0 and w > 0 and h >0):
- if printverbose: print("cube : ",p[3])
- mycube=doc.addObject('Part::Box',p[1])
- mycube.Length=l
- mycube.Width=w
- mycube.Height=h
- else:
- FreeCAD.Console.PrintWarning('cube with radius zero\n')
- mycube=doc.addObject("Part::Feature","emptycube")
- mycube.Shape = Part.Compound([])
- if p[3]['center']=='true' :
- center(mycube,l,w,h);
- p[0] = [mycube]
- if printverbose: print("End Cube")
-
-def p_circle_action(p) :
- 'circle_action : circle LPAREN keywordargument_list RPAREN SEMICOL'
- if printverbose: print("Circle : "+str(p[3]))
- r = float(p[3]['r'])
- # Avoid zero radius
- if r == 0 : r = 0.00001
- n = int(p[3]['$fn'])
- fnmax = FreeCAD.ParamGet(\
- "User parameter:BaseApp/Preferences/Mod/OpenSCAD").\
- GetInt('useMaxFN',50)
- # Alter Max polygon to control if polygons are circles or polygons
- # in the modules preferences
- import Draft
- if n == 0 or fnmax != 0 and n >= fnmax:
- mycircle = FreeCAD.ActiveDocument.addObject("Part::Part2DObjectPython",'circle')
- Draft._Circle(mycircle)
- mycircle.Radius = r
- mycircle.MakeFace = True
- #mycircle = Draft.makeCircle(r,face=True) # would call doc.recompute
- #mycircle = doc.addObject('Part::Circle',p[1]) #would not create a face
- #mycircle.Radius = r
- else :
- #mycircle = Draft.makePolygon(n,r) # would call doc.recompute
- mycircle = FreeCAD.ActiveDocument.addObject("Part::Part2DObjectPython",'polygon')
- Draft._Polygon(mycircle)
- mycircle.FacesNumber = n
- mycircle.Radius = r
- mycircle.DrawMode = "inscribed"
- mycircle.MakeFace = True
- if gui:
- Draft._ViewProviderDraft(mycircle.ViewObject)
- if printverbose: print("Push Circle")
- p[0] = [mycircle]
-
-def p_square_action(p) :
- 'square_action : square LPAREN keywordargument_list RPAREN SEMICOL'
- if printverbose: print("Square")
- size = p[3]['size']
- x = float(size[0])
- y = float(size[1])
- mysquare = doc.addObject('Part::Plane',p[1])
- mysquare.Length=x
- mysquare.Width=y
- if p[3]['center']=='true' :
- center(mysquare,x,y,0)
- p[0] = [mysquare]
-
-def addString(t,s,p):
- return(t + ', ' +s+' = "'+p[3][s]+'"')
-
-def addValue(t,v,p):
- return(t + ', ' +v+' = '+p[3][v])
-
-def p_text_action(p) :
- 'text_action : text LPAREN keywordargument_list RPAREN SEMICOL'
- # If text string is null ignore
- if p[3]['text'] == "" or p[3]['text'] == " " :
- p[0] = []
- return
- t = 'text ( text="'+p[3]['text']+'"'
- t = addValue(t,'size',p)
- t = addString(t,'spacing',p)
- t = addString(t,'font',p)
- t = addString(t,'direction',p)
- t = addString(t,'language',p)
- t = addString(t,'script',p)
- t = addString(t,'halign',p)
- t = addString(t,'valign',p)
- t = addValue(t,'$fn',p)
- t = addValue(t,'$fa',p)
- t = addValue(t,'$fs',p)
- t = t+');'
-
- FreeCAD.Console.PrintMessage("textmsg : "+t+"\n")
- p[0] = [processTextCmd(t)]
-
-def convert_points_list_to_vector(l):
- v = []
- for i in l :
- if printverbose: print(i)
- v.append(FreeCAD.Vector(i[0],i[1]))
- if printverbose: 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 keywordargument_list RPAREN SEMICOL'
- if printverbose: print("Polygon")
- if printverbose: print(p[6])
- v = convert_points_list_to_vector(p[6])
- mypolygon = doc.addObject('Part::Feature',p[1])
- if printverbose: print("Make Parts")
- # Close Polygon
- v.append(v[0])
- parts = Part.makePolygon(v)
- if printverbose: 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 keywordargument_list RPAREN SEMICOL'
- if printverbose: print("Polygon with Path")
- if printverbose: print(p[6])
- v = convert_points_list_to_vector(p[6])
- if printverbose: print("Path Set List")
- if printverbose: print(p[12])
- for i in p[12] :
- if printverbose: print(i)
- mypolygon = doc.addObject('Part::Feature','wire')
- path_list = []
- for j in i :
- j = int(j)
- if printverbose: print(j)
- path_list.append(v[j])
-# Close path
- path_list.append(v[int(i[0])])
- if printverbose: print('Path List')
- if printverbose: 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 faces EQ OSQUARE path_set ESQUARE COMMA keywordargument_list RPAREN SEMICOL
- | polyhedron LPAREN points EQ OSQUARE points_list_3d ESQUARE COMMA triangles EQ OSQUARE points_list_3d ESQUARE COMMA keywordargument_list RPAREN SEMICOL'''
- if printverbose: print("Polyhedron Points")
- v = []
- for i in p[6] :
- if printverbose: print(i)
- v.append(FreeCAD.Vector(float(i[0]),float(i[1]),float(i[2])))
- if printverbose:
- print(v)
- print ("Polyhedron "+p[9])
- print (p[12])
- faces_list = []
- mypolyhed = doc.addObject('Part::Feature',p[1])
- for i in p[12] :
- if printverbose: print(i)
- v2 = FreeCAD.Vector
- pp =[v2(v[k]) for k in i]
- # Add first point to end of list to close polygon
- pp.append(pp[0])
- print("pp")
- print(pp)
- w = Part.makePolygon(pp)
- print("w")
- print(w)
- try:
- f = Part.Face(w)
- except:
- secWireList = w.Edges[:]
- f = Part.makeFilledFace(Part.__sortEdges__(secWireList))
- #f = make_face(v[int(i[0])],v[int(i[1])],v[int(i[2])])
- faces_list.append(f)
- shell=Part.makeShell(faces_list)
- solid=Part.Solid(shell).removeSplitter()
- if solid.Volume < 0:
- solid.reverse()
- mypolyhed.Shape=solid
- p[0] = [mypolyhed]
-
-def p_projection_action(p) :
- 'projection_action : projection LPAREN keywordargument_list RPAREN OBRACE block_list EBRACE'
- if printverbose: print('Projection')
- if p[3]['cut']=='true' :
- planedim=1e9 # large but finite
- #infinite planes look bad in the GUI
- 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=planedim*2
- plane.Width=planedim*2
- plane.Placement = FreeCAD.Placement(FreeCAD.Vector(\
- -planedim,-planedim,0),FreeCAD.Rotation())
- if gui:
- plane.ViewObject.hide()
- if (len(p[6]) > 1):
- subobj = [fuse(p[6],"projection_cut_implicit_group")]
- else:
- subobj = p[6]
- obj.Shapes = [plane]+subobj
- if gui:
- subobj[0].ViewObject.hide()
- p[0] = [obj]
- else: # cut == 'false' => true projection
- if gui and not FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/OpenSCAD").\
- GetBool('usePlaceholderForUnsupported'):
- from PySide import QtGui
- QtGui.QMessageBox.critical(None, translate('OpenSCAD',"Unsupported Function")+" : "+p[1],translate('OpenSCAD',"Press OK"))
- else:
- p[0] = [placeholder(p[1],p[6],p[3])]
+# -*- coding: utf8 -*-
+
+#***************************************************************************
+#* *
+#* Copyright (c) 2012 Keith Sloan *
+#* *
+#* 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 *
+#* *
+#* Acknowledgements : *
+#* *
+#* Thanks to shoogen on the FreeCAD forum and Peter Li *
+#* for programming advice and some code. *
+#* *
+#* *
+#***************************************************************************
+__title__="FreeCAD OpenSCAD Workbench - CSG importer"
+__author__ = "Keith Sloan "
+__url__ = ["http://www.sloan-home.co.uk/ImportCSG"]
+
+printverbose = False
+
+import FreeCAD, io, os, sys
+if FreeCAD.GuiUp:
+ import FreeCADGui
+ gui = True
+else:
+ if printverbose: print("FreeCAD Gui not present.")
+ gui = False
+
+
+import ply.lex as lex
+import ply.yacc as yacc
+import Part
+
+from OpenSCADFeatures import *
+from OpenSCADUtils import *
+
+params = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/OpenSCAD")
+printverbose = params.GetBool('printVerbose',False)
+
+# Get the token map from the lexer. This is required.
+import tokrules
+from tokrules import tokens
+
+try:
+ _encoding = QtGui.QApplication.UnicodeUTF8
+ def translate(context, text):
+ "convenience function for Qt translator"
+ from PySide import QtGui
+ return QtGui.QApplication.translate(context, text, None, _encoding)
+except AttributeError:
+ def translate(context, text):
+ "convenience function for Qt translator"
+ from PySide import QtGui
+ return QtGui.QApplication.translate(context, text, None)
+
+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)
+ if workaroundforissue128needed():
+ pathName = '' #https://github.com/openscad/openscad/issues/128
+ #pathName = os.getcwd() #https://github.com/openscad/openscad/issues/128
+ else:
+ pathName = os.path.dirname(os.path.normpath(filename))
+ processcsg(tmpfile)
+ try:
+ os.unlink(tmpfile)
+ except OSError:
+ pass
+ 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 NameError:
+ doc=FreeCAD.newDocument(docname)
+ #importgroup = doc.addObject("App::DocumentObjectGroup",groupname)
+ if filename.lower().endswith('.scad'):
+ tmpfile=callopenscad(filename)
+ if workaroundforissue128needed():
+ pathName = '' #https://github.com/openscad/openscad/issues/128
+ #pathName = os.getcwd() #https://github.com/openscad/openscad/issues/128
+ else:
+ pathName = os.path.dirname(os.path.normpath(filename))
+ processcsg(tmpfile)
+ try:
+ os.unlink(tmpfile)
+ except OSError:
+ pass
+ else:
+ pathName = os.path.dirname(os.path.normpath(filename))
+ processcsg(filename)
+
+def processcsg(filename):
+ global doc
+
+ if printverbose: print ('ImportCSG Version 0.6a')
+ # Build the lexer
+ if printverbose: print('Start Lex')
+ lex.lex(module=tokrules)
+ if printverbose: print('End Lex')
+
+ # Build the parser
+ if printverbose: print('Load Parser')
+ # No debug out otherwise Linux has protection exception
+ parser = yacc.yacc(debug=0)
+ if printverbose: print('Parser Loaded')
+ # Give the lexer some input
+ #f=open('test.scad', 'r')
+ f = io.open(filename, 'r', encoding="utf8")
+ #lexer.input(f.read())
+
+ if printverbose: print('Start Parser')
+ # Swap statements to enable Parser debugging
+ #result = parser.parse(f.read(),debug=1)
+ result = parser.parse(f.read())
+ f.close()
+ if printverbose:
+ print('End Parser')
+ print(result)
+ FreeCAD.Console.PrintMessage('End processing CSG file\n')
+ doc.recompute()
+
+def p_block_list_(p):
+ '''
+ block_list : statement
+ | block_list statement
+ | statementwithmod
+ | block_list statementwithmod
+ '''
+ #if printverbose: print("Block List")
+ #if printverbose: print(p[1])
+ if(len(p) > 2) :
+ if printverbose: print(p[2])
+ p[0] = p[1] + p[2]
+ else :
+ p[0] = p[1]
+ #if printverbose: print("End Block List")
+
+def p_render_action(p):
+ 'render_action : render LPAREN keywordargument_list RPAREN OBRACE block_list EBRACE'
+ if printverbose: print("Render (ignored)")
+ p[0] = p[6]
+
+def p_group_action1(p):
+ 'group_action1 : group LPAREN RPAREN OBRACE block_list EBRACE'
+ if printverbose: print("Group")
+# Test if need for implicit fuse
+ if (len(p[5]) > 1) :
+ p[0] = [fuse(p[5],"Group")]
+ else :
+ p[0] = p[5]
+
+def p_group_action2(p) :
+ 'group_action2 : group LPAREN RPAREN SEMICOL'
+ if printverbose: 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
+ | render_action
+ | not_supported
+ '''
+ p[0] = p[1]
+
+def p_anymodifier(p):
+ '''anymodifier : MODIFIERBACK
+ | MODIFIERDEBUG
+ | MODIFIERROOT
+ | MODIFIERDISABLE
+ '''
+ #just return the plain modifier for now
+ #has to be changed when the modifiers are implemented
+ #please note that disabled objects usually are stripped of the CSG output during compilation
+ p[0] = p[1]
+
+def p_statementwithmod(p):
+ '''statementwithmod : anymodifier statement'''
+ #ignore the modifiers but add them to the label
+ modifier = p[1]
+ obj = p[2]
+ if hasattr(obj,'Label'):
+ obj.Label = modifier + obj.Label
+ p[0] = obj
+
+def p_part(p):
+ '''
+ part : sphere_action
+ | cylinder_action
+ | cube_action
+ | circle_action
+ | square_action
+ | text_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
+ if printverbose: 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] == ',' :
+ #if printverbose:
+ # print("Start List")
+ # print(p[1])
+ p[0] = [p[1]]
+ else :
+ if printverbose:
+ print(p[1])
+ print(p[2])
+ p[1].append(p[2])
+ p[0] = p[1]
+ #if printverbose: print(p[0])
+
+def p_3d_point(p):
+ '3d_point : OSQUARE NUMBER COMMA NUMBER COMMA NUMBER ESQUARE'
+ global points_list
+ if printverbose: 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] == ',' :
+ if printverbose: print("Start List")
+ if printverbose: print(p[1])
+ p[0] = [p[1]]
+ else :
+ if printverbose: print(p[1])
+ if printverbose: print(p[2])
+ p[1].append(p[2])
+ p[0] = p[1]
+ if printverbose: print(p[0])
+
+def p_path_points(p):
+ '''
+ path_points : NUMBER COMMA
+ | path_points NUMBER COMMA
+ | path_points NUMBER
+ '''
+ #if printverbose: print("Path point")
+ if p[2] == ',' :
+ #if printverbose: print('Start list')
+ #if printverbose: print(p[1])
+ p[0] = [int(p[1])]
+ else :
+ #if printverbose: print(p[1])
+ #if printverbose: print(len(p[1]))
+ #if printverbose: print(p[2])
+ p[1].append(int(p[2]))
+ p[0] = p[1]
+ #if printverbose: print(p[0])
+
+
+def p_path_list(p):
+ 'path_list : OSQUARE path_points ESQUARE'
+ #if printverbose: print('Path List ')
+ #if printverbose: print(p[2])
+ p[0] = p[2]
+
+def p_path_set(p) :
+ '''
+ path_set : path_list
+ | path_set COMMA path_list
+ '''
+ #if printverbose: print('Path Set')
+ #if printverbose: print(len(p))
+ if len(p) == 2 :
+ p[0] = [p[1]]
+ else :
+ p[1].append(p[3])
+ p[0] = p[1]
+ #if printverbose: print(p[0])
+
+def p_operation(p):
+ '''
+ operation : difference_action
+ | intersection_action
+ | union_action
+ | rotate_extrude_action
+ | linear_extrude_with_twist
+ | rotate_extrude_file
+ | import_file1
+ | surface_action
+ | projection_action
+ | hull_action
+ | minkowski_action
+ | offset_action
+ '''
+ p[0] = p[1]
+
+def placeholder(name,children,arguments):
+ from OpenSCADFeatures import OpenSCADPlaceholder
+ newobj=doc.addObject("Part::FeaturePython",name)
+ OpenSCADPlaceholder(newobj,children,str(arguments))
+ if gui:
+ if FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/OpenSCAD").\
+ GetBool('useViewProviderTree'):
+ from OpenSCADFeatures import ViewProviderTree
+ ViewProviderTree(newobj.ViewObject)
+ else:
+ newobj.ViewObject.Proxy = 0
+ #don't hide the children
+ return newobj
+
+def CGALFeatureObj(name,children,arguments=[]):
+ myobj=doc.addObject("Part::FeaturePython",name)
+ CGALFeature(myobj,name,children,str(arguments))
+ if gui:
+ for subobj in children:
+ subobj.ViewObject.hide()
+ if FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/OpenSCAD").\
+ GetBool('useViewProviderTree'):
+ from OpenSCADFeatures import ViewProviderTree
+ ViewProviderTree(myobj.ViewObject)
+ else:
+ myobj.ViewObject.Proxy = 0
+ return myobj
+
+def p_offset_action(p):
+ 'offset_action : offset LPAREN keywordargument_list RPAREN OBRACE block_list EBRACE'
+ if len(p[6]) == 0:
+ newobj = placeholder('group',[],'{}')
+ elif (len(p[6]) == 1 ): #single object
+ subobj = p[6]
+ else:
+ subobj = fuse(p[6],"Offset Union")
+ if 'r' in p[3] :
+ offset = float(p[3]['r'])
+ if 'delta' in p[3] :
+ offset = float(p[3]['delta'])
+ if subobj[0].Shape.Volume == 0 :
+ newobj=doc.addObject("Part::Offset2D",'Offset2D')
+ newobj.Source = subobj[0]
+ newobj.Value = offset
+ if 'r' in p[3] :
+ newobj.Join = 0
+ else :
+ newobj.Join = 2
+ else :
+ newobj=doc.addObject("Part::Offset",'offset')
+ newobj.Shape = subobj[0].Shape.makeOffset(offset)
+ newobj.Document.recompute()
+ if gui:
+ subobj[0].ViewObject.hide()
+# if FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/OpenSCAD").\
+# GetBool('useViewProviderTree'):
+# from OpenSCADFeatures import ViewProviderTree
+# ViewProviderTree(newobj.ViewObject)
+# else:
+# newobj.ViewObject.Proxy = 0
+ p[0] = [newobj]
+
+def p_hull_action(p):
+ 'hull_action : hull LPAREN RPAREN OBRACE block_list EBRACE'
+ p[0] = [ CGALFeatureObj(p[1],p[5]) ]
+
+def p_minkowski_action(p):
+ '''
+ minkowski_action : minkowski LPAREN keywordargument_list RPAREN OBRACE block_list EBRACE'''
+ p[0] = [ CGALFeatureObj(p[1],p[6],p[3]) ]
+
+def p_not_supported(p):
+ '''
+ not_supported : glide LPAREN keywordargument_list RPAREN OBRACE block_list EBRACE
+ | resize LPAREN keywordargument_list RPAREN OBRACE block_list EBRACE
+ | subdiv LPAREN keywordargument_list RPAREN OBRACE block_list EBRACE
+ '''
+ if gui and not FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/OpenSCAD").\
+ GetBool('usePlaceholderForUnsupported'):
+ from PySide import QtGui
+ QtGui.QMessageBox.critical(None, translate('OpenSCAD',"Unsupported Function")+" : "+p[1],translate('OpenSCAD',"Press OK"))
+ else:
+ p[0] = [placeholder(p[1],p[6],p[3])]
+
+def p_size_vector(p):
+ 'size_vector : OSQUARE NUMBER COMMA NUMBER COMMA NUMBER ESQUARE'
+ if printverbose: print("size vector")
+ p[0] = [p[2],p[4],p[6]]
+
+def p_keywordargument(p):
+ '''keywordargument : ID EQ boolean
+ | ID EQ NUMBER
+ | ID EQ size_vector
+ | ID EQ vector
+ | ID EQ 2d_point
+ | text EQ stripped_string
+ | ID EQ stripped_string
+ '''
+ p[0] = (p[1],p[3])
+ if printverbose: print(p[0])
+
+def p_keywordargument_list(p):
+ '''
+ keywordargument_list : keywordargument
+ | keywordargument_list COMMA keywordargument
+ '''
+ if len(p) == 2:
+ p[0] = {p[1][0] : p[1][1]}
+ else:
+ p[1][p[3][0]] = p[3][1]
+ p[0]=p[1]
+
+def p_color_action(p):
+ 'color_action : color LPAREN vector RPAREN OBRACE block_list EBRACE'
+ import math
+ if printverbose: print("Color")
+ color = tuple([float(f) for f in p[3][:3]]) #RGB
+ transp = 100 - int(math.floor(100*float(p[3][3]))) #Alpha
+ if gui:
+ 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):
+ if printverbose: print("Syntax error in input!")
+ if printverbose: print(p)
+
+def fuse(lst,name):
+ global doc
+ if printverbose: print("Fuse")
+ if printverbose: print(lst)
+ if len(lst) == 0:
+ myfuse = placeholder('group',[],'{}')
+ elif len(lst) == 1:
+ return lst[0]
+ # Is this Multi Fuse
+ elif len(lst) > 2:
+ if printverbose: print("Multi Fuse")
+ myfuse = doc.addObject('Part::MultiFuse',name)
+ myfuse.Shapes = lst
+ if gui:
+ for subobj in myfuse.Shapes:
+ subobj.ViewObject.hide()
+ else:
+ if printverbose: print("Single Fuse")
+ myfuse = doc.addObject('Part::Fuse',name)
+ myfuse.Base = lst[0]
+ myfuse.Tool = lst[1]
+ if gui:
+ myfuse.Base.ViewObject.hide()
+ myfuse.Tool.ViewObject.hide()
+ return(myfuse)
+
+def p_union_action(p):
+ 'union_action : union LPAREN RPAREN OBRACE block_list EBRACE'
+ if printverbose: print("union")
+ newpart = fuse(p[5],p[1])
+ if printverbose: print("Push Union Result")
+ p[0] = [newpart]
+ if printverbose: print("End Union")
+
+def p_difference_action(p):
+ 'difference_action : difference LPAREN RPAREN OBRACE block_list EBRACE'
+
+ if printverbose: print("difference")
+ if printverbose: print(len(p[5]))
+ if printverbose: print(p[5])
+ if (len(p[5]) == 0 ): #nochild
+ mycut = placeholder('group',[],'{}')
+ elif (len(p[5]) == 1 ): #single object
+ p[0] = p[5]
+ else:
+# Cut using Fuse
+ mycut = doc.addObject('Part::Cut',p[1])
+ mycut.Base = p[5][0]
+# Can only Cut two objects do we need to fuse extras
+ if (len(p[5]) > 2 ):
+ if printverbose: print("Need to Fuse Extra First")
+ mycut.Tool = fuse(p[5][1:],'union')
+ else :
+ mycut.Tool = p[5][1]
+ if gui:
+ mycut.Base.ViewObject.hide()
+ mycut.Tool.ViewObject.hide()
+ if printverbose: print("Push Resulting Cut")
+ p[0] = [mycut]
+ if printverbose: print("End Cut")
+
+def p_intersection_action(p):
+ 'intersection_action : intersection LPAREN RPAREN OBRACE block_list EBRACE'
+
+ if printverbose: print("intersection")
+ # Is this Multi Common
+ if (len(p[5]) > 2):
+ if printverbose: print("Multi Common")
+ mycommon = doc.addObject('Part::MultiCommon',p[1])
+ mycommon.Shapes = p[5]
+ if gui:
+ for subobj in mycommon.Shapes:
+ subobj.ViewObject.hide()
+ elif (len(p[5]) == 2):
+ if printverbose: print("Single Common")
+ mycommon = doc.addObject('Part::Common',p[1])
+ mycommon.Base = p[5][0]
+ mycommon.Tool = p[5][1]
+ if gui:
+ mycommon.Base.ViewObject.hide()
+ mycommon.Tool.ViewObject.hide()
+ elif (len(p[5]) == 1):
+ mycommon = p[5][0]
+ else : # 1 child
+ mycommon = placeholder('group',[],'{}')
+ p[0] = [mycommon]
+ if printverbose: print("End Intersection")
+
+def process_rotate_extrude(obj,angle):
+ newobj=doc.addObject("Part::FeaturePython",'RefineRotateExtrude')
+ RefineShape(newobj,obj)
+ if gui:
+ if FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/OpenSCAD").\
+ GetBool('useViewProviderTree'):
+ from OpenSCADFeatures import ViewProviderTree
+ ViewProviderTree(newobj.ViewObject)
+ else:
+ newobj.ViewObject.Proxy = 0
+ obj.ViewObject.hide()
+ myrev = doc.addObject("Part::Revolution","RotateExtrude")
+ myrev.Source = newobj
+ myrev.Axis = (0.00,1.00,0.00)
+ myrev.Base = (0.00,0.00,0.00)
+ myrev.Angle = angle
+ myrev.Placement=FreeCAD.Placement(FreeCAD.Vector(),FreeCAD.Rotation(0,0,90))
+ if gui:
+ newobj.ViewObject.hide()
+ return(myrev)
+
+def p_rotate_extrude_action(p):
+ 'rotate_extrude_action : rotate_extrude LPAREN keywordargument_list RPAREN OBRACE block_list EBRACE'
+ if printverbose: print("Rotate Extrude")
+ if (len(p[6]) > 1) :
+ part = fuse(p[6],"Rotate Extrude Union")
+ else :
+ part = p[6][0]
+ angle = float(p[3]['angle'])
+ p[0] = [process_rotate_extrude(part,angle)]
+ if printverbose: print("End Rotate Extrude")
+
+def p_rotate_extrude_file(p):
+ 'rotate_extrude_file : rotate_extrude LPAREN keywordargument_list RPAREN SEMICOL'
+ if printverbose: print("Rotate Extrude File")
+ filen,ext =p[3]['file'] .rsplit('.',1)
+ obj = process_import_file(filen,ext,p[3]['layer'])
+ p[0] = [process_rotate_extrude(obj)]
+ if printverbose: print("End Rotate Extrude File")
+
+def process_linear_extrude(obj,h) :
+ #if gui:
+ newobj=doc.addObject("Part::FeaturePython",'RefineLinearExtrude')
+ RefineShape(newobj,obj)#mylinear)
+ if gui:
+ if FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/OpenSCAD").\
+ GetBool('useViewProviderTree'):
+ from OpenSCADFeatures import ViewProviderTree
+ ViewProviderTree(newobj.ViewObject)
+ else:
+ newobj.ViewObject.Proxy = 0
+ obj.ViewObject.hide()
+ #mylinear.ViewObject.hide()
+ mylinear = doc.addObject("Part::Extrusion","LinearExtrude")
+ mylinear.Base = newobj #obj
+ mylinear.Dir = (0,0,h)
+ mylinear.Placement=FreeCAD.Placement()
+ # V17 change to False mylinear.Solid = True
+ mylinear.Solid = False
+ if gui:
+ newobj.ViewObject.hide()
+ return(mylinear)
+
+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, height and twist are floats
+ if gui:
+ 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 keywordargument_list RPAREN OBRACE block_list EBRACE'
+ if printverbose: print("Linear Extrude With Twist")
+ h = float(p[3]['height'])
+ if printverbose: print("Twist : ",p[3])
+ if 'twist' in p[3]:
+ t = float(p[3]['twist'])
+ else:
+ t = 0
+ # Test if null object like from null text
+ if (len(p[6]) == 0) :
+ p[0] = []
+ return
+ if (len(p[6]) > 1) :
+ obj = fuse(p[6],"Linear Extrude Union")
+ else :
+ obj = p[6][0]
+ if t:
+ newobj = process_linear_extrude_with_twist(obj,h,t)
+ else:
+ newobj = process_linear_extrude(obj,h)
+ if p[3]['center']=='true' :
+ center(newobj,0,0,h)
+ p[0] = [newobj]
+ if printverbose: print("End Linear Extrude with twist")
+
+def p_import_file1(p):
+ 'import_file1 : import LPAREN keywordargument_list RPAREN SEMICOL'
+ if printverbose: print("Import File")
+ filen,ext =p[3]['file'].rsplit('.',1)
+ p[0] = [process_import_file(filen,ext,p[3]['layer'])]
+ if printverbose: print("End Import File")
+
+def p_surface_action(p):
+ 'surface_action : surface LPAREN keywordargument_list RPAREN SEMICOL'
+ if printverbose: print("Surface")
+ obj = doc.addObject("Part::Feature",'surface')
+ obj.Shape,xoff,yoff=makeSurfaceVolume(p[3]['file'])
+ if p[3]['center']=='true' :
+ center(obj,xoff,yoff,0.0)
+ p[0] = [obj]
+ if printverbose: print("End surface")
+
+def process_import_file(fname,ext,layer):
+ if printverbose: print("Importing : "+fname+"."+ext+" Layer : "+layer)
+ if ext.lower() in reverseimporttypes()['Mesh']:
+ obj=process_mesh_file(fname,ext)
+ elif ext.lower() == 'dxf' :
+ obj=processDXF(fname,layer)
+ else:
+ raise ValueError("Unsupported file extension %s" % ext)
+ return(obj)
+
+def process_mesh_file(fname,ext):
+ import Mesh,Part
+ fullname = fname+'.'+ext
+ filename = os.path.join(pathName,fullname)
+ objname = os.path.split(fname)[1]
+ mesh1 = doc.getObject(objname) #reuse imported object
+ if not mesh1:
+ Mesh.insert(filename)
+ mesh1=doc.getObject(objname)
+ if mesh1 is not None:
+ if gui:
+ 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()
+ else: #mesh1 is None
+ FreeCAD.Console.PrintError('Mesh not imported %s.%s %s\n' % \
+ (objname,ext,filename))
+ import Part
+ obj=doc.addObject('Part::Feature',"FailedMeshImport")
+ obj.Shape=Part.Compound([])
+ return(obj)
+
+
+def processTextCmd(t):
+ import os
+ from OpenSCADUtils import callopenscadstring
+ tmpfilename = callopenscadstring(t,'dxf')
+ from OpenSCAD2Dgeom import importDXFface
+ face = importDXFface(tmpfilename,None,None)
+ obj=doc.addObject('Part::Feature','text')
+ obj.Shape=face
+ try:
+ os.unlink(tmpfilename)
+ except OSError:
+ pass
+ return(obj)
+
+def processDXF(fname,layer):
+ global doc
+ global pathName
+ from OpenSCAD2Dgeom import importDXFface
+ if printverbose: print("Process DXF file")
+ if printverbose: print("File Name : "+fname)
+ if printverbose: print("Layer : "+layer)
+ if printverbose: print("PathName : "+pathName)
+ dxfname = fname+'.dxf'
+ filename = os.path.join(pathName,dxfname)
+ shortname = os.path.split(fname)[1]
+ if printverbose: print("DXF Full path : "+filename)
+ face = importDXFface(filename,layer,doc)
+ obj=doc.addObject('Part::Feature','dxf_%s_%s' % (shortname,layer or "all"))
+ obj.Shape=face
+ if printverbose: print("DXF Diagnostics")
+ if printverbose: print(obj.Shape.ShapeType)
+ if printverbose: print("Closed : "+str(obj.Shape.isClosed()))
+ if printverbose: print(obj.Shape.check())
+ if printverbose: print([w.isClosed() for w in obj.Shape.Wires])
+ return(obj)
+
+def processSTL(fname):
+ if printverbose: print("Process STL file")
+
+def p_multmatrix_action(p):
+ 'multmatrix_action : multmatrix LPAREN matrix RPAREN OBRACE block_list EBRACE'
+ if printverbose: print("MultMatrix")
+ transform_matrix = FreeCAD.Matrix()
+ if printverbose: print("Multmatrix")
+ if printverbose: print(p[3])
+ m1l=sum(p[3],[])
+ if any('x' in me for me in m1l): #hexfloats
+ m1l=[float.fromhex(me) for me in m1l]
+ matrixisrounded=False
+ elif max((len(me) for me in m1l)) >= 14: #might have double precision
+ m1l=[float(me) for me in m1l] # assume precise output
+ m1l=[(0 if (abs(me) < 1e-15) else me) for me in m1l]
+ matrixisrounded=False
+ else: #trucanted numbers
+ m1l=[round(float(me),12) for me in m1l] #round
+ matrixisrounded=True
+ transform_matrix = FreeCAD.Matrix(*tuple(m1l))
+ if printverbose: print(transform_matrix)
+ if printverbose: print("Apply Multmatrix")
+# If more than one object on the stack for multmatrix fuse first
+ if (len(p[6]) == 0) :
+ part = placeholder('group',[],'{}')
+ elif (len(p[6]) > 1) :
+ part = fuse(p[6],"Matrix Union")
+ else :
+ part = p[6][0]
+ if (isspecialorthogonalpython(fcsubmatrix(transform_matrix))) :
+ if printverbose: print("special orthogonal")
+ if matrixisrounded:
+ if printverbose: print("rotation rounded")
+ plm=FreeCAD.Placement(transform_matrix)
+ plm=FreeCAD.Placement(plm.Base,roundrotation(plm.Rotation))
+ part.Placement=plm.multiply(part.Placement)
+ else:
+ part.Placement=FreeCAD.Placement(transform_matrix).multiply(\
+ part.Placement)
+ new_part = part
+ elif isrotoinversionpython(fcsubmatrix(transform_matrix)):
+ if printverbose: print("orthogonal and inversion")
+ cmat,axisvec = decomposerotoinversion(transform_matrix)
+ new_part=doc.addObject("Part::Mirroring",'mirr_%s'%part.Name)
+ new_part.Source=part
+ new_part.Normal=axisvec
+ if matrixisrounded:
+ if printverbose: print("rotation rounded")
+ plm=FreeCAD.Placement(cmat)
+ new_part.Placement=FreeCAD.Placement(plm.Base,roundrotation(plm.Rotation))
+ else:
+ new_part.Placement=FreeCAD.Placement(cmat)
+ new_part.Label="mirrored %s" % part.Label
+ if gui:
+ part.ViewObject.hide()
+ 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 gui:
+ 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 :
+ if printverbose: 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)
+ if gui:
+ 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)
+ if gui:
+ newobj.ViewObject.Proxy = 0
+ new_part.ViewObject.hide()
+ p[0] = [newobj]
+ else :
+ p[0] = [new_part]
+ if printverbose: print("Multmatrix applied")
+
+def p_matrix(p):
+ 'matrix : OSQUARE vector COMMA vector COMMA vector COMMA vector ESQUARE'
+ if printverbose: 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'
+ if printverbose: 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 keywordargument_list RPAREN SEMICOL'
+ if printverbose: print("Sphere : ",p[3])
+ r = float(p[3]['r'])
+ mysphere = doc.addObject("Part::Sphere",p[1])
+ mysphere.Radius = r
+ if printverbose: print("Push Sphere")
+ p[0] = [mysphere]
+ if printverbose: print("End Sphere")
+
+def myPolygon(n,r1):
+ # Adapted from Draft::_Polygon
+ import math
+ if printverbose: 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 keywordargument_list RPAREN SEMICOL'
+ if printverbose: print("Cylinder")
+ tocenter = p[3]['center']
+ h = float(p[3]['h'])
+ r1 = float(p[3]['r1'])
+ r2 = float(p[3]['r2'])
+ #n = int(p[3]['$fn'])
+ n = int(round(float(p[3]['$fn'])))
+ fnmax = FreeCAD.ParamGet(\
+ "User parameter:BaseApp/Preferences/Mod/OpenSCAD").\
+ GetInt('useMaxFN')
+ if printverbose: print(p[3])
+ if h > 0:
+ if ( r1 == r2 and r1 > 0):
+ if printverbose: print("Make Cylinder")
+ if n < 3 or fnmax != 0 and n > fnmax:
+ mycyl=doc.addObject("Part::Cylinder",p[1])
+ mycyl.Height = h
+ mycyl.Radius = r1
+ else :
+ if printverbose: print("Make Prism")
+ if False: #user Draft Polygon
+ mycyl=doc.addObject("Part::Extrusion","prism")
+ mycyl.Dir = (0,0,h)
+ try :
+ import Draft
+ mycyl.Base = Draft.makePolygon(n,r1,face=True)
+ 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
+ if printverbose: print("Draft makePolygon Failed, falling back on manual polygon")
+ mycyl.Base = myPolygon(n,r1)
+ # mycyl.Solid = True
+
+ else :
+ pass
+ if gui:
+ mycyl.Base.ViewObject.hide()
+ else: #Use Part::Prism primitive
+ mycyl=doc.addObject("Part::Prism","prism")
+ mycyl.Polygon = n
+ mycyl.Circumradius = r1
+ mycyl.Height = h
+
+ elif (r1 != r2):
+ if n < 3 or fnmax != 0 and n > fnmax:
+ if printverbose: print("Make Cone")
+ mycyl=doc.addObject("Part::Cone",p[1])
+ mycyl.Height = h
+ mycyl.Radius1 = r1
+ mycyl.Radius2 = r2
+ else:
+ if printverbose: print("Make Frustum")
+ mycyl=doc.addObject("Part::FeaturePython",'frustum')
+ Frustum(mycyl,r1,r2,n,h)
+ if gui:
+ if FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/OpenSCAD").\
+ GetBool('useViewProviderTree'):
+ from OpenSCADFeatures import ViewProviderTree
+ ViewProviderTree(mycyl.ViewObject)
+ else:
+ mycyl.ViewObject.Proxy = 0
+ else: # r1 == r2 == 0
+ FreeCAD.Console.PrintWarning('cylinder with radius zero\n')
+ mycyl=doc.addObject("Part::Feature","emptycyl")
+ mycyl.Shape = Part.Compound([])
+ else: # h == 0
+ FreeCAD.Console.PrintWarning('cylinder with height <= zero\n')
+ mycyl=doc.addObject("Part::Feature","emptycyl")
+ mycyl.Shape = Part.Compound([])
+ if printverbose: print("Center = ",tocenter)
+ if tocenter=='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 gui:
+ 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]
+ if printverbose: print("End Cylinder")
+
+def p_cube_action(p):
+ 'cube_action : cube LPAREN keywordargument_list RPAREN SEMICOL'
+ global doc
+ l,w,h = [float(str1) for str1 in p[3]['size']]
+ if (l > 0 and w > 0 and h >0):
+ if printverbose: print("cube : ",p[3])
+ mycube=doc.addObject('Part::Box',p[1])
+ mycube.Length=l
+ mycube.Width=w
+ mycube.Height=h
+ else:
+ FreeCAD.Console.PrintWarning('cube with radius zero\n')
+ mycube=doc.addObject("Part::Feature","emptycube")
+ mycube.Shape = Part.Compound([])
+ if p[3]['center']=='true' :
+ center(mycube,l,w,h);
+ p[0] = [mycube]
+ if printverbose: print("End Cube")
+
+def p_circle_action(p) :
+ 'circle_action : circle LPAREN keywordargument_list RPAREN SEMICOL'
+ if printverbose: print("Circle : "+str(p[3]))
+ r = float(p[3]['r'])
+ # Avoid zero radius
+ if r == 0 : r = 0.00001
+ n = int(p[3]['$fn'])
+ fnmax = FreeCAD.ParamGet(\
+ "User parameter:BaseApp/Preferences/Mod/OpenSCAD").\
+ GetInt('useMaxFN',50)
+ # Alter Max polygon to control if polygons are circles or polygons
+ # in the modules preferences
+ import Draft
+ if n == 0 or fnmax != 0 and n >= fnmax:
+ mycircle = FreeCAD.ActiveDocument.addObject("Part::Part2DObjectPython",'circle')
+ Draft._Circle(mycircle)
+ mycircle.Radius = r
+ mycircle.MakeFace = True
+ #mycircle = Draft.makeCircle(r,face=True) # would call doc.recompute
+ #mycircle = doc.addObject('Part::Circle',p[1]) #would not create a face
+ #mycircle.Radius = r
+ else :
+ #mycircle = Draft.makePolygon(n,r) # would call doc.recompute
+ mycircle = FreeCAD.ActiveDocument.addObject("Part::Part2DObjectPython",'polygon')
+ Draft._Polygon(mycircle)
+ mycircle.FacesNumber = n
+ mycircle.Radius = r
+ mycircle.DrawMode = "inscribed"
+ mycircle.MakeFace = True
+ if gui:
+ Draft._ViewProviderDraft(mycircle.ViewObject)
+ if printverbose: print("Push Circle")
+ p[0] = [mycircle]
+
+def p_square_action(p) :
+ 'square_action : square LPAREN keywordargument_list RPAREN SEMICOL'
+ if printverbose: print("Square")
+ size = p[3]['size']
+ x = float(size[0])
+ y = float(size[1])
+ mysquare = doc.addObject('Part::Plane',p[1])
+ mysquare.Length=x
+ mysquare.Width=y
+ if p[3]['center']=='true' :
+ center(mysquare,x,y,0)
+ p[0] = [mysquare]
+
+def addString(t,s,p):
+ return(t + ', ' +s+' = "'+p[3][s]+'"')
+
+def addValue(t,v,p):
+ return(t + ', ' +v+' = '+p[3][v])
+
+def p_text_action(p) :
+ 'text_action : text LPAREN keywordargument_list RPAREN SEMICOL'
+ # If text string is null ignore
+ if p[3]['text'] == "" or p[3]['text'] == " " :
+ p[0] = []
+ return
+ t = 'text ( text="'+p[3]['text']+'"'
+ t = addValue(t,'size',p)
+ t = addString(t,'spacing',p)
+ t = addString(t,'font',p)
+ t = addString(t,'direction',p)
+ t = addString(t,'language',p)
+ t = addString(t,'script',p)
+ t = addString(t,'halign',p)
+ t = addString(t,'valign',p)
+ t = addValue(t,'$fn',p)
+ t = addValue(t,'$fa',p)
+ t = addValue(t,'$fs',p)
+ t = t+');'
+
+ FreeCAD.Console.PrintMessage("textmsg : "+t+"\n")
+ p[0] = [processTextCmd(t)]
+
+def convert_points_list_to_vector(l):
+ v = []
+ for i in l :
+ if printverbose: print(i)
+ v.append(FreeCAD.Vector(i[0],i[1]))
+ if printverbose: 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 keywordargument_list RPAREN SEMICOL'
+ if printverbose: print("Polygon")
+ if printverbose: print(p[6])
+ v = convert_points_list_to_vector(p[6])
+ mypolygon = doc.addObject('Part::Feature',p[1])
+ if printverbose: print("Make Parts")
+ # Close Polygon
+ v.append(v[0])
+ parts = Part.makePolygon(v)
+ if printverbose: 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 keywordargument_list RPAREN SEMICOL'
+ if printverbose: print("Polygon with Path")
+ if printverbose: print(p[6])
+ v = convert_points_list_to_vector(p[6])
+ if printverbose: print("Path Set List")
+ if printverbose: print(p[12])
+ for i in p[12] :
+ if printverbose: print(i)
+ mypolygon = doc.addObject('Part::Feature','wire')
+ path_list = []
+ for j in i :
+ j = int(j)
+ if printverbose: print(j)
+ path_list.append(v[j])
+# Close path
+ path_list.append(v[int(i[0])])
+ if printverbose: print('Path List')
+ if printverbose: 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 faces EQ OSQUARE path_set ESQUARE COMMA keywordargument_list RPAREN SEMICOL
+ | polyhedron LPAREN points EQ OSQUARE points_list_3d ESQUARE COMMA triangles EQ OSQUARE points_list_3d ESQUARE COMMA keywordargument_list RPAREN SEMICOL'''
+ if printverbose: print("Polyhedron Points")
+ v = []
+ for i in p[6] :
+ if printverbose: print(i)
+ v.append(FreeCAD.Vector(float(i[0]),float(i[1]),float(i[2])))
+ if printverbose:
+ print(v)
+ print ("Polyhedron "+p[9])
+ print (p[12])
+ faces_list = []
+ mypolyhed = doc.addObject('Part::Feature',p[1])
+ for i in p[12] :
+ if printverbose: print(i)
+ v2 = FreeCAD.Vector
+ pp =[v2(v[k]) for k in i]
+ # Add first point to end of list to close polygon
+ pp.append(pp[0])
+ print("pp")
+ print(pp)
+ w = Part.makePolygon(pp)
+ print("w")
+ print(w)
+ try:
+ f = Part.Face(w)
+ except:
+ secWireList = w.Edges[:]
+ f = Part.makeFilledFace(Part.__sortEdges__(secWireList))
+ #f = make_face(v[int(i[0])],v[int(i[1])],v[int(i[2])])
+ faces_list.append(f)
+ shell=Part.makeShell(faces_list)
+ solid=Part.Solid(shell).removeSplitter()
+ if solid.Volume < 0:
+ solid.reverse()
+ mypolyhed.Shape=solid
+ p[0] = [mypolyhed]
+
+def p_projection_action(p) :
+ 'projection_action : projection LPAREN keywordargument_list RPAREN OBRACE block_list EBRACE'
+ if printverbose: print('Projection')
+ if p[3]['cut']=='true' :
+ planedim=1e9 # large but finite
+ #infinite planes look bad in the GUI
+ 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=planedim*2
+ plane.Width=planedim*2
+ plane.Placement = FreeCAD.Placement(FreeCAD.Vector(\
+ -planedim,-planedim,0),FreeCAD.Rotation())
+ if gui:
+ plane.ViewObject.hide()
+ if (len(p[6]) > 1):
+ subobj = [fuse(p[6],"projection_cut_implicit_group")]
+ else:
+ subobj = p[6]
+ obj.Shapes = [plane]+subobj
+ if gui:
+ subobj[0].ViewObject.hide()
+ p[0] = [obj]
+ else: # cut == 'false' => true projection
+ if gui and not FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/OpenSCAD").\
+ GetBool('usePlaceholderForUnsupported'):
+ from PySide import QtGui
+ QtGui.QMessageBox.critical(None, translate('OpenSCAD',"Unsupported Function")+" : "+p[1],translate('OpenSCAD',"Press OK"))
+ else:
+ p[0] = [placeholder(p[1],p[6],p[3])]