| | |
| | |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | __title__ = "FreeCAD OpenSCAD Workbench - CSG importer" |
| | __author__ = "Keith Sloan <keith@sloan-home.co.uk>" |
| | __url__ = ["http://www.sloan-home.co.uk/ImportCSG"] |
| |
|
| | printverbose = False |
| |
|
| | import io |
| | import os |
| |
|
| | import xml.sax |
| |
|
| | import FreeCAD |
| | import Part |
| | import Draft |
| |
|
| | from OpenSCADFeatures import * |
| | from OpenSCADUtils import * |
| |
|
| |
|
| | import ply.lex as lex |
| | import ply.yacc as yacc |
| |
|
| | params = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/OpenSCAD") |
| | printverbose = params.GetBool('printVerbose', False) |
| |
|
| | if FreeCAD.GuiUp: |
| | gui = True |
| | else: |
| | if printverbose: print("FreeCAD Gui not present.") |
| | gui = False |
| |
|
| | hassetcolor = [] |
| | alreadyhidden = [] |
| | original_root_objects = [] |
| |
|
| | |
| | import tokrules |
| | from tokrules import tokens |
| | from builtins import open as pyopen |
| |
|
| | translate = FreeCAD.Qt.translate |
| |
|
| |
|
| | def shallHide(subject): |
| | for obj in subject.OutListRecursive: |
| | if "Matrix_Union" in str(obj.FullName): |
| | return False |
| | if "Extrude" in str(obj.FullName): |
| | return True |
| | return False |
| |
|
| |
|
| | def setColorRecursively(obj, color, transp): |
| | ''' |
| | For some reason a part made by cutting or fusing other parts do not have a color |
| | unless its constituents are also colored. This code sets colors for those |
| | constituents unless already set elsewhere. |
| | ''' |
| | obj.ViewObject.ShapeColor = color |
| | obj.ViewObject.Transparency = transp |
| | |
| | boolean_features = ["Part::Fuse", "Part::MultiFuse", "Part::Cut", |
| | "Part::Common", "Part::MultiCommon"] |
| | if obj.TypeId in boolean_features: |
| | for currentObject in obj.OutList: |
| | if printverbose: print(f"Fixing up colors for: {currentObject.FullName}") |
| | if currentObject not in hassetcolor: |
| | setColorRecursively(currentObject, color, transp) |
| |
|
| |
|
| | def fixVisibility(): |
| | |
| | |
| | |
| | |
| | for root_object in FreeCAD.ActiveDocument.RootObjects: |
| | if root_object not in original_root_objects: |
| | root_object.ViewObject.Visibility = True |
| | for obj in root_object.OutListRecursive: |
| | obj.ViewObject.Visibility = False |
| |
|
| |
|
| | 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 = 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_unused = os.path.splitext(os.path.basename(filename))[0] |
| | try: |
| | doc = FreeCAD.getDocument(docname) |
| | for obj in doc.RootObjects: |
| | original_root_objects.append(obj) |
| | except NameError: |
| | doc = FreeCAD.newDocument(docname) |
| | if filename.lower().endswith('.scad'): |
| | tmpfile = callopenscad(filename) |
| | 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') |
| | |
| | if printverbose: print('Start Lex') |
| | lex.lex(module=tokrules) |
| | if printverbose: print('End Lex') |
| |
|
| | |
| | if printverbose: print('Load Parser') |
| | |
| | |
| | parser = yacc.yacc(debug=False, write_tables=False) |
| | if printverbose: print('Parser Loaded') |
| |
|
| | f = io.open(filename, 'r', encoding="utf8") |
| |
|
| | if printverbose: print('Start Parser') |
| |
|
| | result = parser.parse(f.read()) |
| | f.close() |
| | if printverbose: |
| | print('End Parser') |
| | print(result) |
| | if gui: |
| | fixVisibility() |
| | hassetcolor.clear() |
| | alreadyhidden.clear() |
| | 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(len(p) > 2): |
| | if printverbose: print(p[2]) |
| | p[0] = p[1] + p[2] |
| | else: |
| | p[0] = p[1] |
| |
|
| | 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") |
| | |
| | if p[5] is None: |
| | p[0] = [] |
| | return |
| | if len(p[5]) > 1: |
| | if printverbose: print('Fuse Group') |
| | for obj in p[5]: |
| | checkObjShape(obj) |
| | p[0] = [fuse(p[5], "Group")] |
| | else: |
| | if printverbose: print(f"Group {p[5]} type {type(p[5])}") |
| | checkObjShape(p[5]) |
| | 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_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 |
| | ''' |
| | |
| | |
| | |
| | p[0] = p[1] |
| |
|
| |
|
| | def p_statementwithmod(p): |
| | '''statementwithmod : anymodifier statement''' |
| | |
| | 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] == ',': |
| | p[0] = [p[1]] |
| | else: |
| | if printverbose: |
| | print(p[1]) |
| | print(p[2]) |
| | p[1].append(p[2]) |
| | p[0] = p[1] |
| |
|
| |
|
| | 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 p[2] == ',': |
| | p[0] = [int(p[1])] |
| | else: |
| | p[1].append(int(p[2])) |
| | p[0] = p[1] |
| |
|
| |
|
| | def p_path_list(p): |
| | 'path_list : OSQUARE path_points ESQUARE' |
| | p[0] = p[2] |
| |
|
| |
|
| | def p_path_set(p): |
| | ''' |
| | path_set : path_list |
| | | path_set COMMA path_list |
| | ''' |
| | if len(p) == 2: |
| | p[0] = [p[1]] |
| | else: |
| | p[1].append(p[3]) |
| | p[0] = p[1] |
| |
|
| | def p_operation(p): |
| | ''' |
| | operation : difference_action |
| | | intersection_action |
| | | union_action |
| | | rotate_extrude_action |
| | | linear_extrude_with_transform |
| | | rotate_extrude_file |
| | | import_file1 |
| | | resize_action |
| | | 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 |
| | |
| | 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' |
| | subobj = None |
| | if len(p[6]) == 0: |
| | newobj = placeholder('group',[],'{}') |
| | elif (len(p[6]) == 1 ): |
| | subobj = p[6][0] |
| | 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']) |
| | checkObjShape(subobj) |
| | if subobj.Shape.Volume == 0 : |
| | newobj = doc.addObject("Part::Offset2D",'Offset2D') |
| | newobj.Source = subobj |
| | 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.ViewObject.hide() |
| | p[0] = [newobj] |
| |
|
| | def checkObjShape(obj): |
| | if printverbose: print('Check Object Shape') |
| | if hasattr(obj, 'Shape'): |
| | if obj.Shape.isNull(): |
| | if printverbose: print('Shape is Null - recompute') |
| | obj.recompute() |
| | if obj.Shape.isNull(): |
| | print(f'Recompute failed : {obj.Name}') |
| | else: |
| | if hasattr(obj, 'Name'): |
| | print(f"obj {obj.Name} has no Shape") |
| | else: |
| | print(f"obj {obj} has no Name & Shape") |
| |
|
| | 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_resize_action(p): |
| | ''' |
| | resize_action : resize LPAREN keywordargument_list RPAREN OBRACE block_list EBRACE ''' |
| | new_size = p[3]['newsize'] |
| | auto = p[3]['auto'] |
| | p[6][0].recompute() |
| | if p[6][0].Shape.isNull(): |
| | doc.recompute() |
| | p[6][0].Shape.tessellate(0.05) |
| | old_bbox = p[6][0].Shape.BoundBox |
| | old_size = [old_bbox.XLength, old_bbox.YLength, old_bbox.ZLength] |
| | for r in range(0,3): |
| | if auto[r] == '1': |
| | new_size[r] = new_size[0] |
| | if new_size[r] == '0': |
| | new_size[r] = str(old_size[r]) |
| |
|
| | |
| | transform_matrix = FreeCAD.Matrix() |
| |
|
| | scale = FreeCAD.Vector(float(new_size[0])/old_size[0], |
| | float(new_size[1])/old_size[1], |
| | float(new_size[2])/old_size[2]) |
| |
|
| | transform_matrix.scale(scale) |
| |
|
| | new_part=doc.addObject("Part::FeaturePython",'Matrix Deformation') |
| | new_part.Shape = p[6][0].Shape.transformGeometry(transform_matrix) |
| | 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 |
| | p[6][0].ViewObject.hide() |
| | p[0] = [new_part] |
| |
|
| |
|
| | def p_not_supported(p): |
| | ''' |
| | not_supported : glide 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]]) |
| | transp = 100 - int(math.floor(100*float(p[3][3]))) |
| | if gui: |
| | for obj in p[6]: |
| | if shallHide(obj): |
| | if "Group" in obj.FullName: |
| | obj.ViewObject.Visibility=False |
| | alreadyhidden.append(obj) |
| | setColorRecursively(obj, color, transp) |
| | hassetcolor.append(obj) |
| | p[0] = p[6] |
| |
|
| | |
| | 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] |
| | |
| | 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] |
| | checkObjShape(myfuse.Base) |
| | checkObjShape(myfuse.Tool) |
| | myfuse.Shape = myfuse.Base.Shape.fuse(myfuse.Tool.Shape) |
| | if gui: |
| | myfuse.Base.ViewObject.hide() |
| | myfuse.Tool.ViewObject.hide() |
| | myfuse.Placement = FreeCAD.Placement() |
| | return myfuse |
| |
|
| | def p_empty_union_action(p): |
| | 'union_action : union LPAREN RPAREN SEMICOL' |
| | if printverbose: print("empty union") |
| | newpart = fuse([],p[1]) |
| | if printverbose: print("Push Union Result") |
| | p[0] = [newpart] |
| | if printverbose: print("End Union") |
| |
|
| | 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 ): |
| | mycut_unused = placeholder('group',[],'{}') |
| | elif (len(p[5]) == 1 ): |
| | p[0] = p[5] |
| | else: |
| | |
| | mycut = doc.addObject('Part::Cut',p[1]) |
| | mycut.Base = p[5][0] |
| | |
| | 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] |
| | checkObjShape(mycut.Tool) |
| | 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") |
| | |
| | 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] |
| | checkObjShape(mycommon.Base) |
| | checkObjShape(mycommon.Tool) |
| | if gui: |
| | mycommon.Base.ViewObject.hide() |
| | mycommon.Tool.ViewObject.hide() |
| | elif (len(p[5]) == 1): |
| | mycommon = p[5][0] |
| | else : |
| | mycommon = placeholder('group',[],'{}') |
| | mycommon.Shape = mycommon.Base.Shape.common(mycommon.Tool.Shape) |
| | 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 process_rotate_extrude_prism(obj, angle, n): |
| | newobj=doc.addObject("Part::FeaturePython",'PrismaticToroid') |
| | PrismaticToroid(newobj, obj, angle, n) |
| | newobj.Placement=FreeCAD.Placement(FreeCAD.Vector(),FreeCAD.Rotation(0,0,90)) |
| | 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() |
| | return newobj |
| |
|
| | def p_rotate_extrude_action(p): |
| | 'rotate_extrude_action : rotate_extrude LPAREN keywordargument_list RPAREN OBRACE block_list EBRACE' |
| | if printverbose: print("Rotate Extrude") |
| | angle = 360.0 |
| | if 'angle' in p[3]: |
| | angle = float(p[3]['angle']) |
| | n = int(round(float(p[3]['$fn']))) |
| | fnmax = FreeCAD.ParamGet(\ |
| | "User parameter:BaseApp/Preferences/Mod/OpenSCAD").\ |
| | GetInt('useMaxFN', 16) |
| | if (len(p[6]) > 1) : |
| | part = fuse(p[6],"Rotate Extrude Union") |
| | else : |
| | part = p[6][0] |
| |
|
| | if n < 3 or fnmax != 0 and n > fnmax: |
| | p[0] = [process_rotate_extrude(part,angle)] |
| | else: |
| | p[0] = [process_rotate_extrude_prism(part,angle,n)] |
| | 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") |
| | angle = 360.0 |
| | if 'angle' in p[3]: |
| | angle = float(p[3]['angle']) |
| | filen,ext = p[3]['file'] .rsplit('.',1) |
| | obj = process_import_file(filen,ext,p[3]['layer']) |
| | n = int(round(float(p[3]['$fn']))) |
| | fnmax = FreeCAD.ParamGet(\ |
| | "User parameter:BaseApp/Preferences/Mod/OpenSCAD").\ |
| | GetInt('useMaxFN', 16) |
| |
|
| | if n < 3 or fnmax != 0 and n > fnmax: |
| | p[0] = [process_rotate_extrude(obj,angle)] |
| | else: |
| | p[0] = [process_rotate_extrude_prism(obj,angle,n)] |
| | if printverbose: print("End Rotate Extrude File") |
| |
|
| | def process_linear_extrude(obj,h) : |
| | |
| | newobj = doc.addObject("Part::FeaturePython",'RefineLinearExtrude') |
| | 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() |
| | |
| | mylinear = doc.addObject("Part::Extrusion","LinearExtrude") |
| | mylinear.Base = newobj |
| | mylinear.Dir = (0,0,h) |
| | mylinear.Placement=FreeCAD.Placement() |
| | |
| | mylinear.Solid = False |
| | if gui: |
| | newobj.ViewObject.hide() |
| | return mylinear |
| |
|
| | def process_linear_extrude_with_transform(base,height,twist,scale) : |
| | newobj = doc.addObject("Part::FeaturePython",'transform_extrude') |
| | |
| | Twist(newobj,base,height,-twist,scale) |
| | 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 |
| | return newobj |
| |
|
| | def p_linear_extrude_with_transform(p): |
| | 'linear_extrude_with_transform : linear_extrude LPAREN keywordargument_list RPAREN OBRACE block_list EBRACE' |
| | if printverbose: print("Linear Extrude With Transform") |
| | h = float(p[3]['height']) |
| | if printverbose: print("Height : ",h) |
| | s = [1.0,1.0] |
| | t = 0.0 |
| | if 'scale' in p[3]: |
| | if isinstance(p[3]['scale'], str): |
| | s = [float(p[3]['scale']), float(p[3]['scale'])] |
| | else: |
| | s = [float(p[3]['scale'][0]), float(p[3]['scale'][1])] |
| | if printverbose: print ("Scale: " + str(s)) |
| | if 'twist' in p[3]: |
| | t = float(p[3]['twist']) |
| | if printverbose: print("Twist : ",t) |
| | |
| | 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] |
| | checkObjShape(obj) |
| | if t != 0.0 or s[0] != 1.0 or s[1] != 1.0: |
| | newobj = process_linear_extrude_with_transform(obj,h,t,s) |
| | else: |
| | newobj = process_linear_extrude(obj,h) |
| | if p[3].get('center','false')=='true' : |
| | center(newobj,0,0,h) |
| | p[0] = [newobj] |
| | if gui: |
| | obj.ViewObject.hide() |
| | if printverbose: print("End Linear Extrude with Transform") |
| |
|
| | 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].get('center','false') == '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) |
| | elif ext.lower() == 'svg': |
| | obj = processSVG(fname, ext) |
| | else: |
| | raise ValueError("Unsupported file extension %s" % ext) |
| | return obj |
| |
|
| | def processSVG(fname, ext): |
| | from importSVG import svgHandler |
| | if printverbose: print("SVG Handler") |
| | doc = FreeCAD.ActiveDocument |
| | docSVG = FreeCAD.newDocument(fname+'_tmp') |
| | FreeCAD.ActiveDocument = docSVG |
| |
|
| | |
| | parser = xml.sax.make_parser() |
| | parser.setFeature(xml.sax.handler.feature_external_ges, False) |
| | parser.setContentHandler(svgHandler()) |
| | parser._cont_handler.doc = docSVG |
| |
|
| | |
| | filename = os.path.join(pathName,fname+'.'+ext) |
| | |
| | parser.parse(pyopen(filename)) |
| |
|
| | |
| | shapes = [] |
| | for obj in FreeCAD.ActiveDocument.Objects: |
| | if printverbose: print(obj.Name) |
| | if printverbose: print(obj.Shape) |
| | shapes.append(obj.Shape) |
| | FreeCAD.closeDocument(docSVG.Name) |
| | FreeCAD.ActiveDocument=doc |
| | obj=doc.addObject('Part::Feature',fname) |
| | obj.Shape=Part.Compound(shapes) |
| | return obj |
| |
|
| | def process_mesh_file(fname,ext): |
| | import Mesh |
| | import Part |
| | fullname = fname+'.'+ext |
| | filename = os.path.join(pathName,fullname) |
| | objname = os.path.split(fname)[1] |
| | mesh1 = doc.getObject(objname) |
| | 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") |
| |
|
| | solid = solid.removeSplitter() |
| | if solid.Volume < 0: |
| | solid.complement() |
| | obj.Shape = solid |
| | else: |
| | 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): |
| | 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]) |
| | if gui and p[6]: |
| | parentcolor=p[6][0].ViewObject.ShapeColor |
| | parenttransparency=p[6][0].ViewObject.Transparency |
| |
|
| | m1l=sum(p[3],[]) |
| | if any('x' in me for me in m1l): |
| | m1l=[float.fromhex(me) for me in m1l] |
| | matrixisrounded=False |
| | elif max((len(me) for me in m1l)) >= 14: |
| | m1l=[float(me) for me in m1l] |
| | m1l=[(0 if (abs(me) < 1e-15) else me) for me in m1l] |
| | matrixisrounded=False |
| | else: |
| | m1l=[round(float(me),12) for me in m1l] |
| | matrixisrounded=True |
| | transform_matrix = FreeCAD.Matrix(*tuple(m1l)) |
| | if printverbose: print(transform_matrix) |
| | if printverbose: print("Apply Multmatrix") |
| | |
| | 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") |
| | part.recompute() |
| | if part.Shape.isNull(): |
| | doc.recompute() |
| | new_part = doc.addObject("Part::Feature","Matrix Deformation") |
| | new_part.Shape = part.Shape.transformGeometry(transform_matrix) |
| | if gui: |
| | part.ViewObject.hide() |
| | if False : |
| | |
| | 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 gui and p[6]: |
| | new_part.ViewObject.ShapeColor=parentcolor |
| | new_part.ViewObject.Transparency = parenttransparency |
| | 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): |
| | |
| | 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].get('center','false') |
| | h = float(p[3]['h']) |
| | r1 = float(p[3]['r1']) |
| | r2 = float(p[3]['r2']) |
| | n = int(round(float(p[3]['$fn']))) |
| | fnmax = FreeCAD.ParamGet(\ |
| | "User parameter:BaseApp/Preferences/Mod/OpenSCAD").\ |
| | GetInt('useMaxFN', 16) |
| | 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: |
| | mycyl=doc.addObject("Part::Extrusion","prism") |
| | mycyl.Dir = (0,0,h) |
| | try : |
| | import Draft |
| | mycyl.Base = Draft.makePolygon(n,r1,face=True) |
| | except Exception: |
| | |
| | |
| | |
| | if printverbose: |
| | print("Draft makePolygon Failed, falling back on manual polygon") |
| | mycyl.Base = myPolygon(n,r1) |
| |
|
| | else : |
| | pass |
| | if gui: |
| | mycyl.Base.ViewObject.hide() |
| | else: |
| | 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: |
| | FreeCAD.Console.PrintWarning('cylinder with radius zero\n') |
| | mycyl=doc.addObject("Part::Feature","emptycyl") |
| | mycyl.Shape = Part.Compound([]) |
| | else: |
| | 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 : |
| | |
| | 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].get('center','false')=='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']) |
| | |
| | if r == 0 : r = 0.00001 |
| | n = int(p[3]['$fn']) |
| | fnmax = FreeCAD.ParamGet(\ |
| | "User parameter:BaseApp/Preferences/Mod/OpenSCAD").\ |
| | GetInt('useMaxFN',16) |
| | |
| | |
| | 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) |
| | FreeCAD.ActiveDocument.recompute() |
| | else : |
| | 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].get('center','false')=='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 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) |
| | if "script" in p[3]: |
| | t = addString(t,'script',p) |
| | else: |
| | t += ', script="latin"' |
| | 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") |
| | |
| | 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]) |
| | |
| | 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] |
| | |
| |
|
| | 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] |
| | |
| | pp.append(pp[0]) |
| | try: |
| | w = Part.makePolygon(pp) |
| | f = Part.Face(w) |
| | except Exception: |
| | secWireList = w.Edges[:] |
| | f = Part.makeFilledFace(Part.__sortEdges__(secWireList)) |
| | 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') |
| |
|
| | doc.recompute() |
| | p[6][0].Shape.tessellate(0.05) |
| | bbox = p[6][0].Shape.BoundBox |
| | for shape in p[6]: |
| | shape.Shape.tessellate(0.05) |
| | bbox.add(shape.Shape.BoundBox) |
| | plane = doc.addObject("Part::Plane","xy_plane_used_for_projection") |
| | plane.Length = bbox.XLength |
| | plane.Width = bbox.YLength |
| | plane.Placement = FreeCAD.Placement(FreeCAD.Vector(\ |
| | bbox.XMin,bbox.YMin,0),FreeCAD.Rotation()) |
| | if gui: |
| | plane.ViewObject.hide() |
| |
|
| | if p[3]['cut'] == 'true' : |
| | obj = doc.addObject('Part::MultiCommon','projection_cut') |
| | 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: |
| | 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])] |
| |
|