- # -*- coding: utf8 -*-
- #***************************************************************************
- #* *
- #* Copyright (c) 2012 Keith Sloan <keith@sloan-home.co.uk> *
- #* *
- #* This program is free software; you can redistribute it and/or modify *
- #* it under the terms of the GNU General Public License (GPL) *
- #* as published by the Free Software Foundation; either version 2 of *
- #* the License, or (at your option) any later version. *
- #* for detail see the LICENCE text file. *
- #* *
- #* This program is distributed in the hope that it will be useful, *
- #* but WITHOUT ANY WARRANTY; without even the implied warranty of *
- #* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- #* GNU Library General Public License for more details. *
- #* *
- #* You should have received a copy of the GNU Library General Public *
- #* License along with this program; if not, write to the Free Software *
- #* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
- #* USA *
- #* *
- #* Acknowledgements : *
- #* *
- #* Thanks to shoogen on the FreeCAD forum and Peter Li *
- #* for programming advice and some code. *
- #* *
- #* *
- #***************************************************************************
- __title__="FreeCAD Draft Workbench - CSG importer Version 0.05c"
- __author__ = "Keith Sloan <keith@sloan-home.co.uk>"
- __url__ = ["http://www.sloan-home.co.uk/ImportCSG"]
- import FreeCAD, os, sys
- import ply.lex as lex
- import ply.yacc as yacc
- import Part
- pythonopen = open # to distinguish python built-in open function from the one declared here
- # Get the token map from the lexer. This is required.
- import tokrules
- from tokrules import tokens
- #Globals
- dxfcache = {}
- def open(filename):
- "called when freecad opens a file."
- global doc
- global pathName
- pathName = os.path.dirname(os.path.normpath(filename))
- docname = os.path.splitext(os.path.basename(filename))[0]
- doc = FreeCAD.newDocument(docname)
- processcsg(filename)
- return doc
- def insert(filename,docname):
- "called when freecad imports a file"
- groupname = os.path.splitext(os.path.basename(filename))[0]
- try:
- doc=FreeCAD.getDocument(docname)
- except:
- doc=FreeCAD.newDocument(docname)
- importgroup = doc.addObject("App::DocumentObjectGroup",groupname)
- processcsg(filename)
- def processcsg(filename):
- global doc
- print 'ImportCSG Version 0.5c'
- # Build the lexer
- print 'Start Lex'
- lex.lex(module=tokrules)
- print 'End Lex'
- # Build the parser
- print 'Load Parser'
- # No debug out otherwise Linux has protection exception
- #parser = yacc.yacc(debug=0)
- parser = yacc.yacc(debug=0)
- print 'Parser Loaded'
- # Give the lexer some input
- #f=open('test.scad', 'r')
- f = pythonopen(filename, 'r')
- #lexer.input(f.read())
- print 'Start Parser'
- # Swap statements to enable Parser debugging
- #result = parser.parse(f.read(),debug=1)
- result = parser.parse(f.read())
- print 'End Parser'
- print result
- FreeCAD.Console.PrintMessage('End processing CSG file')
- doc.recompute()
- # colorcodeshapes(doc.Objects)
- def p_block_list_(p):
- '''
- block_list : statement
- | block_list statement
- '''
- print "Block List"
- print p[1]
- if(len(p) > 2) :
- print p[2]
- p[0] = p[1] + p[2]
- else :
- p[0] = p[1]
- print "End Block List"
- def p_group_action1(p):
- 'group_action1 : group LPAREN RPAREN OBRACE block_list EBRACE'
- print "Group"
- p[0] = p[5]
- def p_group_action2(p) :
- 'group_action2 : group LPAREN RPAREN SEMICOL'
- print "Group2"
- p[0] = []
- def p_boolean(p) :
- '''
- boolean : true
- | false
- '''
- p[0] = p[1]
- def p_layer_string(p) :
- '''
- layer_string : ID
- | NUMBER
- '''
- # print str(p[0]) + ' : ' + str(p[1])
- p[0] = p[1]
- def p_file_name(p):
- 'file_name : QUOTE ID DOT ID QUOTE'
- print p[2]
- print p[4]
- p[0] = [p[2],p[4]]
- #def p_string(p):
- # 'string : QUOTE ID QUOTE'
- # p[0] = p[2]
- def p_statement(p):
- '''statement : part
- | operation
- | multmatrix_action
- | group_action1
- | group_action2
- | color_action
- | not_supported
- '''
- p[0] = p[1]
- def p_part(p):
- '''
- part : sphere_action
- | cylinder_action
- | cube_action
- | circle_action
- | square_action
- | polygon_action_nopath
- | polygon_action_plus_path
- | polyhedron_action
- '''
- p[0] = p[1]
- def p_2d_point(p):
- '2d_point : OSQUARE NUMBER COMMA NUMBER ESQUARE'
- global points_list
- print "2d Point"
- p[0] = [float(p[2]),float(p[4])]
- def p_points_list_2d(p):
- '''
- points_list_2d : 2d_point COMMA
- | points_list_2d 2d_point COMMA
- | points_list_2d 2d_point
- '''
- if p[2] == ',' :
- print "Start List"
- print p[1]
- p[0] = [p[1]]
- else :
- print p[1]
- print p[2]
- p[1].append(p[2])
- p[0] = p[1]
- print p[0]
- def p_3d_point(p):
- '3d_point : OSQUARE NUMBER COMMA NUMBER COMMA NUMBER ESQUARE'
- global points_list
- print "3d point"
- p[0] = [p[2],p[4],p[6]]
- def p_points_list_3d(p):
- '''
- points_list_3d : 3d_point COMMA
- | points_list_3d 3d_point COMMA
- | points_list_3d 3d_point
- '''
- if p[2] == ',' :
- print "Start List"
- print p[1]
- p[0] = [p[1]]
- else :
- print p[1]
- print p[2]
- p[1].append(p[2])
- p[0] = p[1]
- print p[0]
- def p_path_points(p):
- '''
- path_points : NUMBER COMMA
- | path_points NUMBER COMMA
- | path_points NUMBER
- '''
- print "Path point"
- if p[2] == ',' :
- print 'Start list'
- print p[1]
- p[0] = [int(p[1])]
- else :
- print p[1]
- print len(p[1])
- print p[2]
- p[1].append(int(p[2]))
- p[0] = p[1]
- print p[0]
- def p_path_list(p):
- 'path_list : OSQUARE path_points ESQUARE'
- print 'Path List '
- print p[2]
- p[0] = p[2]
- def p_path_set(p) :
- '''
- path_set : path_list
- | path_set COMMA path_list
- '''
- print 'Path Set'
- print len(p)
- if len(p) == 2 :
- p[0] = [p[1]]
- else :
- p[1].append(p[3])
- p[0] = p[1]
- print p[0]
- def p_operation(p):
- '''
- operation : difference_action
- | intersection_action
- | union_action
- | rotate_extrude_action
- | linear_extrude_action1
- | linear_extrude_action2
- | rotate_extrude_file
- | import_file1
- | import_file2
- | projection_action
- '''
- p[0] = p[1]
- def p_not_supported(p):
- '''
- not_supported : hull
- | minkowski
- '''
- from PyQt4 import QtGui
- QtGui.QMessageBox.critical(None, "Unsupported Functon : "+p[1], "Press OK")
- def p_size_vector(p):
- 'size_vector : OSQUARE NUMBER COMMA NUMBER COMMA NUMBER ESQUARE'
- print "size vector"
- p[0] = [p[2],p[4],p[6]]
- def p_assign(p):
- 'assign : ID EQ NUMBER'
- print "Assignment"
- print p[1] + ' : ' + p[3]
- p[0] = p[3]
- def p_color_action(p):
- 'color_action : color LPAREN vector RPAREN OBRACE block_list EBRACE'
- print "Color"
- p[0] = p[6]
- # Error rule for syntax errors
- def p_error(p):
- print "Syntax error in input!"
- print p
- def fuse(list,name):
- global doc
- print "Fuse"
- print list
- # Is this Multi Fuse
- if ( len(list) > 2):
- print "Multi Fuse"
- myfuse = doc.addObject('Part::MultiFuse',name)
- myfuse.Shapes = list
- for subobj in myfuse.Shapes:
- subobj.ViewObject.hide()
- else :
- print "Single Fuse"
- myfuse = doc.addObject('Part::Fuse',name)
- myfuse.Base = list[0]
- myfuse.Tool = list[1]
- myfuse.Base.ViewObject.hide()
- myfuse.Tool.ViewObject.hide()
- return(myfuse)
- def p_union_action(p):
- 'union_action : union LPAREN RPAREN OBRACE block_list EBRACE'
- print "union"
- newpart = fuse(p[5],p[1])
- print "Push Union Result"
- p[0] = [newpart]
- print "End Union"
- def p_difference_action(p):
- 'difference_action : difference LPAREN RPAREN OBRACE block_list EBRACE'
- print "difference"
- print len(p[5])
- print p[5]
- mycut = doc.addObject('Part::Cut',p[1])
- # Cut using Fuse
- mycut.Base = p[5][0]
- # Can only Cut two objects do we need to fuse extras
- if (len(p[5]) > 2 ):
- print "Need to Fuse Extra First"
- mycut.Tool = fuse(p[5][1:],'union')
- else :
- mycut.Tool = p[5][1]
- mycut.Base.ViewObject.hide()
- mycut.Tool.ViewObject.hide()
- print "Push Resulting Cut"
- p[0] = [mycut]
- print "End Cut"
- def p_intersection_action(p):
- 'intersection_action : intersection LPAREN RPAREN OBRACE block_list EBRACE'
- print "intersection"
- # Is this Multi Common
- if (len(p[5]) > 2):
- print "Multi Common"
- mycommon = doc.addObject('Part::MultiCommon',p[1])
- mycommon.Shapes = p[5]
- for subobj in mycommon.Shapes:
- subobj.ViewObject.hide()
- else :
- print "Single Common"
- mycommon = doc.addObject('Part::Common',p[1])
- mycommon.Base = p[5][0]
- mycommon.Tool = p[5][1]
- mycommon.Base.ViewObject.hide()
- mycommon.Tool.ViewObject.hide()
- p[0] = [mycommon]
- print "End Intersection"
- class RefineShape:
- '''return a refined shape'''
- def __init__(self, obj,child=None):
- obj.addProperty("App::PropertyLink","Base","Base",
- "The base object that must be refined")
- obj.Proxy = self
- obj.ViewObject.Proxy = 0
- obj.Base = child
- def onChanged(self, fp, prop):
- "Do something when a property has changed"
- pass
- def execute(self, fp):
- if fp.Base:
- #self.Base = fp.Base
- #self.Placement = fp.Placement
- #fp.Shape=fp.Base.Shape.Wires[0]
- #fp.Shape=fp.Base.Shape.removeSplitter().transformGeometry(fp.Base.Placement.toMatrix())
- fp.Base.Shape.check() # rather raise an exception then make FreeCAD crash
- sh=fp.Base.Shape.removeSplitter()
- sh.transformShape(fp.Base.Placement.toMatrix())
- #sh.transformGeometry(fp.Base.Placement.toMatrix())
- fp.Shape=sh
- def process_rotate_extrude(obj):
- myrev = doc.addObject("Part::Revolution","RotateExtrude")
- myrev.Source = obj
- myrev.Axis = (0.00,1.00,0.00)
- myrev.Base = (0.00,0.00,0.00)
- myrev.Angle = 360.00
- myrev.Placement=FreeCAD.Placement(FreeCAD.Vector(),FreeCAD.Rotation(0,0,90))
- obj.ViewObject.hide()
- newobj=doc.addObject("Part::FeaturePython",'RefineRotateExtrude')
- RefineShape(newobj,myrev)
- myrev.ViewObject.hide()
- return(newobj)
- def p_rotate_extrude_action(p):
- 'rotate_extrude_action : rotate_extrude LPAREN assign COMMA assign COMMA assign COMMA assign RPAREN OBRACE block_list EBRACE'
- print "Rotate Extrude"
- p[0] = [process_rotate_extrude(p[12][0])]
- print "End Rotate Extrude"
- def p_rotate_extrude_file(p):
- 'rotate_extrude_file : rotate_extrude LPAREN file EQ file_name COMMA layer EQ QUOTE layer_string QUOTE COMMA origin EQ 2d_point COMMA assign \
- COMMA assign COMMA assign COMMA assign COMMA assign RPAREN SEMICOL'
- print "Rotate Extrude File"
- obj = process_import_file(p[5][0],p[5][1],p[10])
- p[0] = [process_rotate_extrude(obj)]
- print "End Rotate Extrude File"
- def process_linear_extrude(obj,h) :
- mylinear = doc.addObject("Part::Extrusion","LinearExtrude")
- mylinear.Base = obj
- mylinear.Dir = (0,0,h)
- mylinear.Placement=FreeCAD.Placement()
- try:
- mylinear.Solid = True
- except:
- a = 1 # Any old null statement
- obj.ViewObject.hide()
- newobj=doc.addObject("Part::FeaturePython",'RefineLinearExtrude')
- RefineShape(newobj,mylinear)
- mylinear.ViewObject.hide()
- return(newobj)
- def p_linear_extrude_action1(p):
- 'linear_extrude_action1 : linear_extrude LPAREN assign COMMA center EQ boolean COMMA assign COMMA assign COMMA assign COMMA \
- assign COMMA assign COMMA assign RPAREN OBRACE block_list EBRACE'
- print "Linear Extrude 1"
- h = float(p[3])
- obj = p[22][0]
- p[0] = [process_linear_extrude(obj,h)]
- if p[7]=='true' :
- center(obj,0,0,h)
- print "End Linear Extrude 1"
- def p_linear_extrude_action2(p):
- 'linear_extrude_action2 : linear_extrude LPAREN assign COMMA center EQ boolean COMMA assign COMMA assign COMMA assign COMMA \
- assign RPAREN OBRACE block_list EBRACE'
- print "Linear Extrude 2"
- h = float(p[3])
- obj = p[18][0]
- p[0] = [process_linear_extrude(obj,h)]
- if p[7]=='true' :
- center(obj,0,0,h)
- print "End Linear Extrude 2"
- def p_import_file1(p):
- 'import_file1 : import LPAREN file EQ file_name COMMA layer EQ QUOTE layer_string QUOTE COMMA origin EQ 2d_point COMMA assign COMMA assign COMMA \
- assign COMMA assign COMMA assign RPAREN SEMICOL'
- print "Import File"
- p[0] = [process_import_file(p[5][0],p[5][1],p[10])]
- print "End Import File"
- def p_import_file2(p):
- 'import_file2 : import LPAREN file EQ file_name COMMA layer EQ QUOTE QUOTE COMMA origin EQ 2d_point COMMA assign COMMA assign COMMA \
- assign COMMA assign COMMA assign RPAREN SEMICOL'
- print "Import File"
- p[0] = [process_import_file(p[5][0],p[5][1],"")]
- print "End Import File"
- def process_import_file(fname,ext,layer):
- print "Importing : "+fname+"."+ext+" Layer : "+layer
- if ext.lower() in reverseimporttypes()['Mesh']:
- obj=process_mesh_file(fname,ext)
- elif ext=='dxf' :
- obj=processDXF(fname,layer)
- else :
- print "Unsupported file extension"
- return(obj)
- def reverseimporttypes():
- '''allows to search for supported filetypes by module'''
- def getsetfromdict(dict1,index):
- if index in dict1:
- return dict1[index]
- else:
- set1=set()
- dict1[index]=set1
- return set1
- importtypes={}
- import FreeCAD
- for key,value in FreeCAD.getImportType().iteritems():
- if type(value) is str:
- getsetfromdict(importtypes,value).add(key)
- else:
- for vitem in value:
- getsetfromdict(importtypes,vitem).add(key)
- return importtypes
- def process_mesh_file(fname,ext):
- import Mesh
- fullname = fname+'.'+ext
- filename = os.path.join(pathName,fullname)
- mesh1 = doc.getObject(fname) #reuse imported object
- if not mesh1:
- Mesh.insert(filename)
- mesh1=doc.getObject(fname)
- mesh1.ViewObject.hide()
- sh=Part.Shape()
- sh.makeShapeFromMesh(mesh1.Mesh.Topology,0.1)
- solid = Part.Solid(sh)
- obj=doc.addObject('Part::Feature',"Mesh")
- #ImportObject(obj,mesh1) #This object is not mutable from the GUI
- #ViewProviderTree(obj.ViewObject)
- solid=solid.removeSplitter()
- if solid.Volume < 0:
- #sh.reverse()
- #sh = sh.copy()
- solid.complement()
- obj.Shape=solid#.removeSplitter()
- return(obj)
- def processDXF(fname,layer):
- global doc
- global pathName
- print "Process DXF file"
- print "File Name : "+fname
- print "Layer : "+layer
- print "PathName : "+pathName
- dxfname = fname+'.dxf'
- filename = os.path.join(pathName,dxfname)
- print "DXF Full path : "+filename
- #featname='import_dxf_%s_%s'%(objname,layera)
- # reusing an allready imported object does not work if the
- #shape in not yet calculated
- import importDXF
- global dxfcache
- layers=dxfcache.get(id(doc),[])
- print "Layers : "+str(layers)
- if layers:
- try:
- groupobj=[go for go in layers if (not layer) or go.Label == layer]
- except:
- groupobj= None
- else:
- groupobj= None
- if not groupobj:
- print "Importing Layer"
- layers = importDXF.processdxf(doc,filename) or importDXF.layers
- dxfcache[id(doc)] = layers[:]
- for l in layers:
- for o in l.Group:
- o.ViewObject.hide()
- l.ViewObject.hide()
- groupobj=[go for go in layers if (not layer) or go.Label == layer]
- edges=[]
- for shapeobj in groupobj[0].Group:
- edges.extend(shapeobj.Shape.Edges)
- #taken from Drafttools
- from draftlibs import fcvec, fcgeo
- #print "Edges"
- #print edges
- #wires = fcgeo.findWires(edges)
- wires = edgestowires(edges)
- facel=[]
- #print "Process Wires"
- #print wires
- for w in wires:
- #assert(len(w.Edges)>1)
- if not w.isClosed():
- p0 = w.Vertexes[0].Point
- p1 = w.Vertexes[-1].Point
- edges2 = w.Edges
- edges2.append(Part.Line(p1,p0).toShape())
- w = Part.Wire(fcgeo.sortEdges(edges2))
- facel.append(Part.Face(w))
- f=subtractfaces(facel)
- #obj=doc.addObject("Part::FeaturePython",'import_dxf_%s_%s'%(objname,layera))
- obj=doc.addObject('Part::Feature',"dxf")
- #ImportObject(obj,groupobj[0]) #This object is not mutable from the GUI
- #ViewProviderTree(obj.ViewObject)
- obj.Shape=f
- print "DXF Diagnostics"
- print obj.Shape.ShapeType
- print "Closed : "+str(f.isClosed())
- print f.check()
- print [w.isClosed() for w in obj.Shape.Wires]
- return(obj)
- def edgestowires(edgelist,eps=0.00001):
- '''takes list of edges and returns a list of wires'''
- import Part, Draft
- # todo remove double edges
- wirelist=[]
- for path in findConnectedEdges(edgelist,eps=eps):
- try:
- wirelist.append(Part.Wire(path))
- except:
- comp=Part.Compound(path)
- wirelist.append(comp.connectEdgesToWires(False,eps).Wires[0])
- return wirelist
- def findConnectedEdges(edgelist,eps=1e-6):
- '''returns a list of list of connected edges'''
- def vertequals(v1,v2,eps=1e-6):
- '''check two vertices for equality'''
- return all([abs(c1-c2)<eps for c1,c2 in zip(v1.Point,v2.Point)])
- def vertindex(forward):
- '''return index of last or first element'''
- return -1 if forward else 0
- freeedges = edgelist[:]
- retlist = []
- debuglist = []
- while freeedges:
- startwire = freeedges.pop(0)
- forward = True
- newedge = [(startwire,True)]
- for forward in (True, False):
- found = True
- while found:
- lastvert = newedge[vertindex(forward)][0].Vertexes[vertindex(forward == newedge[vertindex(forward)][1])]
- for ceindex, checkedge in enumerate(freeedges):
- found = False
- for cvindex, cvert in enumerate([checkedge.Vertexes[0],checkedge.Vertexes[-1]]):
- if vertequals(lastvert,cvert,eps):
- if forward:
- newedge.append((checkedge,cvindex == 0))
- else:
- newedge.insert(0,(checkedge,cvindex == 1))
- del freeedges[ceindex]
- found = True
- break
- else:
- found = False
- if found:
- break
- else:
- found = False
- #we are finished for this edge
- debuglist.append(newedge)
- retlist.append([item[0] for item in newedge]) #strip off direction
- #print debuglist
- return retlist
- def processSTL(fname):
- print "Process STL file"
- def fcsubmatrix(m):
- """Extracts the 3x3 Submatrix from a freecad Matrix Object
- as a list of row vectors"""
- return [[m.A11,m.A12,m.A13],[m.A21,m.A22,m.A23],[m.A31,m.A32,m.A33]]
- def multiplymat(l,r):
- """multiply matrices given as lists of row vectors"""
- rt=zip(*r) #transpose r
- mat=[]
- for y in range(len(rt)):
- mline=[]
- for x in range(len(l)):
- mline.append(sum([le*re for le,re in zip(l[y],rt[x])]))
- mat.append(mline)
- return mat
- def isorthogonal(submatrix,precision=4):
- """checking if 3x3 Matrix is ortogonal (M*Transp(M)==I)"""
- prod=multiplymat(submatrix,zip(*submatrix))
- return [[round(f,precision) for f in line] for line in prod]==[[1,0,0],[0,1,0],[0,0,1]]
- def detsubmatrix(s):
- """get the determinant of a 3x3 Matrix given as list of row vectors"""
- return s[0][0]*s[1][1]*s[2][2]+s[0][1]*s[1][2]*s[2][0]+s[0][2]*s[1][0]*s[2][1]\
- -s[2][0]*s[1][1]*s[0][2]-s[2][1]*s[1][2]*s[0][0]-s[2][2]*s[1][0]*s[0][1]
- def isspecialorthogonaldeterminant(submat,precision=4):
- return isorthogonal(submat,precision) and round(detsubmatrix(submat),precision)==1
- def isspecialorthogonal(mat,precision=4):
- return abs(mat.submatrix(3).isOrthogonal(10**(-precision))-1.0) < 10**(-precision) and \
- abs(mat.submatrix(3).determinant()-1.0) < 10**(-precision)
- def p_multmatrix_action(p):
- 'multmatrix_action : multmatrix LPAREN matrix RPAREN OBRACE block_list EBRACE'
- print "MultMatrix"
- transform_matrix = FreeCAD.Matrix()
- print "Multmatrix"
- print p[3]
- transform_matrix.A11 = round(float(p[3][0][0]),12)
- transform_matrix.A12 = round(float(p[3][0][1]),12)
- transform_matrix.A13 = round(float(p[3][0][2]),12)
- transform_matrix.A14 = round(float(p[3][0][3]),12)
- transform_matrix.A21 = round(float(p[3][1][0]),12)
- transform_matrix.A22 = round(float(p[3][1][1]),12)
- transform_matrix.A23 = round(float(p[3][1][2]),12)
- transform_matrix.A24 = round(float(p[3][1][3]),12)
- transform_matrix.A31 = round(float(p[3][2][0]),12)
- transform_matrix.A32 = round(float(p[3][2][1]),12)
- transform_matrix.A33 = round(float(p[3][2][2]),12)
- transform_matrix.A34 = round(float(p[3][2][3]),12)
- print transform_matrix
- print "Apply Multmatrix"
- # If more than one object on the stack for multmatrix fuse first
- if (len(p[6]) > 1) :
- part = fuse(p[6],"Matrix Union")
- else :
- part = p[6][0]
- # part = new_part.transformGeometry(transform_matrix)
- # part = new_part.copy()
- # part.transformShape(transform_matrix)
- if (isspecialorthogonaldeterminant(fcsubmatrix(transform_matrix))) :
- print "Orthogonal"
- part.Placement=FreeCAD.Placement(transform_matrix).multiply(part.Placement)
- new_part = part
- else :
- print "Transform Geometry"
- # Need to recompute to stop transformGeometry causing a crash
- doc.recompute()
- new_part = doc.addObject("Part::Feature","Matrix Deformation")
- # new_part.Shape = part.Base.Shape.transformGeometry(transform_matrix)
- new_part.Shape = part.Shape.transformGeometry(transform_matrix)
- part.ViewObject.hide()
- if False :
- # Does not fix problemfile or beltTighener although later is closer
- newobj=doc.addObject("Part::FeaturePython",'RefineMultMatrix')
- RefineShape(newobj,new_part)
- new_part.ViewObject.hide()
- p[0] = [newobj]
- else :
- p[0] = [new_part]
- print "Multmatrix applied"
- def p_matrix(p):
- 'matrix : OSQUARE vector COMMA vector COMMA vector COMMA vector ESQUARE'
- print "Matrix"
- p[0] = [p[2],p[4],p[6],p[8]]
- def p_vector(p):
- 'vector : OSQUARE NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER ESQUARE'
- print "Vector"
- p[0] = [p[2],p[4],p[6],p[8]]
- def center(obj,x,y,z):
- obj.Placement = FreeCAD.Placement(\
- FreeCAD.Vector(-x/2.0,-y/2.0,-z/2.0),\
- FreeCAD.Rotation(0,0,0,1))
- def p_sphere_action(p):
- 'sphere_action : sphere LPAREN assign COMMA assign COMMA assign COMMA assign RPAREN SEMICOL'
- print "Sphere : "+p[9]
- r = float(p[9])
- mysphere = doc.addObject("Part::Sphere",p[1])
- mysphere.Radius = r
- print "Push Sphere"
- p[0] = [mysphere]
- print "End Sphere"
- def myPolygon(n,r1):
- # Adapted from Draft::_Polygon
- import math
- print "My Polygon"
- angle = math.pi*2/n
- nodes = [FreeCAD.Vector(r1,0,0)]
- for i in range(n-1) :
- th = (i+1) * angle
- nodes.append(FreeCAD.Vector(r1*math.cos(th),r1*math.sin(th),0))
- nodes.append(nodes[0])
- polygonwire = Part.makePolygon(nodes)
- polygon = doc.addObject("Part::Feature","Polygon")
- polygon.Shape = Part.Face(polygonwire)
- return(polygon)
- mycyl.Base = myPolygon(n,r)
- mycyl.Dir = (0,0,h)
- mycyl.Base.ViewObject.hide()
- return(mycyl)
- def p_cylinder_action(p):
- 'cylinder_action : cylinder LPAREN assign COMMA assign COMMA assign COMMA assign COMMA assign COMMA assign COMMA center EQ boolean RPAREN SEMICOL'
- print "Cylinder"
- h = float(p[9])
- r1 = float(p[11])
- r2 = float(p[13])
- print p[9] + ' : ' + p[11] + ' : ' + p[13]
- if ( r1 == r2 ):
- print "Make Cylinder"
- n = int(p[3])
- if n < 3 :
- mycyl=doc.addObject("Part::Cylinder",p[1])
- mycyl.Height = h
- mycyl.Radius = r1
- else :
- print "Make Prism"
- mycyl=doc.addObject("Part::Extrusion","prism")
- mycyl.Dir = (0,0,h)
- try :
- import Draft
- mycyl.Base = Draft.makePolygon(n,r1)
- except :
- # If Draft can't import (probably due to lack of Pivy on Mac and
- # Linux builds of FreeCAD), this is a fallback.
- # or old level of FreeCAD
- print "Draft makePolygon Failed, falling back on manual polygon"
- mycyl.Base = myPolygon(n,r1)
- else :
- pass
- mycyl.Base.ViewObject.hide()
- mycyl.Solid = True
- else:
- print "Make Cone"
- mycyl=doc.addObject("Part::Cone",p[1])
- mycyl.Height = h
- mycyl.Radius1 = r1
- mycyl.Radius2 = r2
- print "Center = "+str(p[17])
- if p[17]=='true' :
- center(mycyl,0,0,h)
- if False :
- # Does not fix problemfile or beltTighener although later is closer
- newobj=doc.addObject("Part::FeaturePython",'RefineCylinder')
- RefineShape(newobj,mycyl)
- mycyl.ViewObject.hide()
- p[0] = [newobj]
- else :
- p[0] = [mycyl]
- print "End Cylinder"
- def p_cube_action(p):
- 'cube_action : cube LPAREN size EQ size_vector COMMA center EQ boolean RPAREN SEMICOL'
- global doc
- l = float(p[5][0])
- w = float(p[5][1])
- h = float(p[5][2])
- print "cube : "+p[5][0] + ' : ' + p[5][1] +' : '+ p[5][2]
- mycube=doc.addObject('Part::Box',p[1])
- mycube.Length=l
- mycube.Width=w
- mycube.Height=h
- print "Center = "+str(p[9])
- if p[9]=='true' :
- center(mycube,l,w,h);
- p[0] = [mycube]
- print "End Cube"
- def p_circle_action(p) :
- 'circle_action : circle LPAREN assign COMMA assign COMMA assign COMMA assign RPAREN SEMICOL'
- print "Circle : "+str(p[9])
- r = float(p[9])
- n = int(p[3])
- if n == 0 :
- mycircle = doc.addObject('Part::Circle',p[1])
- mycircle.Radius = r
- else :
- import Draft
- mycircle = Draft.makePolygon(n,r)
- # Bug in FreeCAD waiting for fix
- print "Push Circle"
- p[0] = [mycircle]
- def p_square_action(p) :
- 'square_action : square LPAREN size EQ 2d_point COMMA center EQ boolean RPAREN SEMICOL'
- print "Square"
- x = float(p[5][0])
- y = float(p[5][1])
- mysquare = doc.addObject('Part::Plane',p[1])
- mysquare.Length=x
- mysquare.Width=y
- p[0] = [mysquare]
- def subtractfaces(faces):
- if len(faces)==1:
- return faces[0]
- else:
- facelist=sorted(faces,key=(lambda shape: shape.Area),reverse=True)
- base=facelist[0]
- tool=reduce(lambda p1,p2: p1.fuse(p2),facelist[1:])
- return base.cut(tool)
- def convert_points_list_to_vector(l):
- v = []
- for i in l :
- print i
- v.append(FreeCAD.Vector(i[0],i[1]))
- print v
- return(v)
- def p_polygon_action_nopath(p) :
- 'polygon_action_nopath : polygon LPAREN points EQ OSQUARE points_list_2d ESQUARE COMMA paths EQ undef COMMA assign RPAREN SEMICOL'
- print "Polygon"
- print p[6]
- v = convert_points_list_to_vector(p[6])
- mypolygon = doc.addObject('Part::Feature',p[1])
- print "Make Parts"
- # Close Polygon
- v.append(v[0])
- parts = Part.makePolygon(v)
- print "update object"
- mypolygon.Shape = parts
- p[0] = [mypolygon]
- def p_polygon_action_plus_path(p) :
- 'polygon_action_plus_path : polygon LPAREN points EQ OSQUARE points_list_2d ESQUARE COMMA paths EQ OSQUARE path_set ESQUARE COMMA assign RPAREN SEMICOL'
- print "Polygon with Path"
- print p[6]
- v = convert_points_list_to_vector(p[6])
- print "Path Set List"
- print p[12]
- for i in p[12] :
- print i
- mypolygon = doc.addObject('Part::Feature','wire')
- path_list = []
- for j in i :
- j = int(j)
- print j
- path_list.append(v[j])
- # Close path
- path_list.append(v[int(i[0])])
- print 'Path List'
- print path_list
- wire = Part.makePolygon(path_list)
- mypolygon.Shape = wire
- p[0] = [mypolygon]
- # This only pushes last polygon
- def make_face(v1,v2,v3):
- wire = Part.makePolygon([v1,v2,v3,v1])
- face = Part.Face(wire)
- return face
- def p_polyhedron_action(p) :
- 'polyhedron_action : polyhedron LPAREN points EQ OSQUARE points_list_3d ESQUARE COMMA triangles EQ OSQUARE points_list_3d ESQUARE COMMA assign RPAREN SEMICOL'
- print "Polyhedron Points"
- v = []
- for i in p[6] :
- print i
- v.append(FreeCAD.Vector(float(i[0]),float(i[1]),float(i[2])))
- print v
- print "Polyhedron triangles"
- print p[12]
- faces_list = []
- mypolyhed = doc.addObject('Part::Feature',p[1])
- for i in p[12] :
- print i
- f = make_face(v[int(i[0])],v[int(i[1])],v[int(i[2])])
- faces_list.append(f)
- shell=Part.makeShell(faces_list)
- mypolyhed.Shape=Part.Solid(shell)
- p[0] = [mypolyhed]
- def p_projection_action(p) :
- 'projection_action : projection LPAREN cut EQ boolean COMMA assign RPAREN OBRACE block_list EBRACE'
- print 'Projection'
- from PyQt4 import QtGui
- QtGui.QMessageBox.critical(None, "Projection Not yet Coded waiting for Peter Li"," Press OK")
- def shapedict(shapelst):
- return dict([(shape.hashCode(),shape) for shape in shapelst])
- def shapeset(shapelst):
- return set([shape.hashCode() for shape in shapelst])
- def mostbasiccompound(comp):
- '''searches fo the most basic shape in a Compound'''
- solids=shapeset(comp.Solids)
- shells=shapeset(comp.Shells)
- faces=shapeset(comp.Faces)
- wires=shapeset(comp.Wires)
- edges=shapeset(comp.Edges)
- vertexes=shapeset(comp.Vertexes)
- #FreeCAD.Console.PrintMessage('%s\n' % (str((len(solids),len(shells),len(faces),len(wires),len(edges),len(vertexes)))))
- for shape in comp.Solids:
- shells -= shapeset(shape.Shells)
- faces -= shapeset(shape.Faces)
- wires -= shapeset(shape.Wires)
- edges -= shapeset(shape.Edges)
- vertexes -= shapeset(shape.Vertexes)
- for shape in comp.Shells:
- faces -= shapeset(shape.Faces)
- wires -= shapeset(shape.Wires)
- edges -= shapeset(shape.Edges)
- vertexes -= shapeset(shape.Vertexes)
- for shape in comp.Faces:
- wires -= shapeset(shape.Wires)
- edges -= shapeset(shape.Edges)
- vertexes -= shapeset(shape.Vertexes)
- for shape in comp.Wires:
- edges -= shapeset(shape.Edges)
- vertexes -= shapeset(shape.Vertexes)
- for shape in comp.Edges:
- vertexes -= shapeset(shape.Vertexes)
- #FreeCAD.Console.PrintMessage('%s\n' % (str((len(solids),len(shells),len(faces),len(wires),len(edges),len(vertexes)))))
- #return len(solids),len(shells),len(faces),len(wires),len(edges),len(vertexes)
- if vertexes:
- return "Vertex"
- elif edges:
- return "Edge"
- elif wires:
- return "Wire"
- elif faces:
- return "Face"
- elif shells:
- return "Shell"
- elif solids:
- return "Solid"
- def colorcodeshapes(objs):
- shapecolors={
- "Compound":(0.3,0.3,0.4),
- "CompSolid":(0.1,0.5,0.0),
- "Solid":(0.0,0.8,0.0),
- "Shell":(0.8,0.0,0.0),
- "Face":(0.6,0.6,0.0),
- "Wire":(0.1,0.1,0.1),
- "Edge":(1.0,1.0,1.0),
- "Vertex":(8.0,8.0,8.0),
- "Shape":(0.0,0.0,1.0)}
- for obj in objs:
- try:
- if obj.Shape.isNull():
- continue
- if not obj.Shape.isValid():
- color=(1.0,0.4,0.4)
- else:
- st=obj.Shape.ShapeType
- if st in ["Compound","CompSolid"]:
- st = mostbasiccompound(obj.Shape)
- color=shapecolors[st]
- obj.ViewObject.ShapeColor = color
- except:
- raise
- #colorcodeshapes(App.ActiveDocument.Objects)