OpenSCAD Module: bugfixes and improvements

if more than 14 digits are given don round in general,
but test for <eps only.
refine before extrusion
support polyhedron faces which replaces polyhedron faces
importCSG round rotations
don't call Draft.makecircle and makeprism as they trigger a recompute
use group placholder for objects with no children
move removesubtree to OpenSCADUtils
add resize and offset keywords
add OpenSCAD_ExplodeGroup command
add OpenSCAD_IncreaseToleranceFeature
change refine shape logo
This commit is contained in:
Sebastian Hoogen
2014-02-21 16:24:14 +01:00
parent 040c19b1c1
commit b58d1caea7
13 changed files with 1288 additions and 522 deletions

View File

@@ -27,7 +27,7 @@
#* *
#* *
#***************************************************************************
__title__="FreeCAD OpenSCAD Workbench - CSG importer Version 0.06a"
__title__="FreeCAD OpenSCAD Workbench - CSG importer"
__author__ = "Keith Sloan <keith@sloan-home.co.uk>"
__url__ = ["http://www.sloan-home.co.uk/ImportCSG"]
@@ -47,9 +47,7 @@ import ply.yacc as yacc
import Part
from OpenSCADFeatures import *
#from OpenSCAD2Dgeom import *
from OpenSCADUtils import *
isspecialorthogonaldeterminant = isspecialorthogonalpython
if open.__module__ == '__builtin__':
pythonopen = open # to distinguish python built-in open function from the one declared here
@@ -370,6 +368,25 @@ def CGALFeatureObj(name,children,arguments=[]):
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[5]) == 0:
# mycut = placeholder('group',[],'{}')
# elif (len(p[5]) == 1 ): #single object
# subobj = p[5]
# else:
# subobj = fuse(p[6],"Offset Union")
# newobj=doc.addObject("Part::FeaturePython",'offset')
# OffsetShape(newobj,subobj,p[3]['delta'])
# 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_hull_action(p):
'hull_action : hull LPAREN RPAREN OBRACE block_list EBRACE'
p[0] = [ CGALFeatureObj(p[1],p[5]) ]
@@ -382,6 +399,8 @@ def p_minkowski_action(p):
def p_not_supported(p):
'''
not_supported : glide LPAREN keywordargument_list RPAREN OBRACE block_list EBRACE
| offset LPAREN keywordargument_list RPAREN OBRACE block_list EBRACE
| resize LPAREN keywordargument_list RPAREN OBRACE block_list EBRACE
'''
if gui and not FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/OpenSCAD").\
GetBool('usePlaceholderForUnsupported'):
@@ -439,8 +458,7 @@ def fuse(lst,name):
if printverbose: print "Fuse"
if printverbose: print lst
if len(lst) == 0:
myfuse = doc.addObject("Part::Feature","emptyfuse")
myfuse.Shape = Part.Compound([])
myfuse = placeholder('group',[],'{}')
elif len(lst) == 1:
return lst[0]
# Is this Multi Fuse
@@ -476,8 +494,7 @@ def p_difference_action(p):
if printverbose: print len(p[5])
if printverbose: print p[5]
if (len(p[5]) == 0 ): #nochild
mycut = doc.addObject("Part::Feature","emptycut")
mycut.Shape = Part.Compound([])
mycut = placeholder('group',[],'{}')
elif (len(p[5]) == 1 ): #single object
p[0] = p[5]
else:
@@ -520,22 +537,13 @@ def p_intersection_action(p):
elif (len(p[5]) == 1):
mycommon = p[5][0]
else : # 1 child
mycommon = doc.addObject("Part::Feature","emptyintersection")
mycommon.Shape = Part.Compound([])
mycommon = placeholder('group',[],'{}')
p[0] = [mycommon]
if printverbose: print "End Intersection"
def process_rotate_extrude(obj):
myrev = doc.addObject("Part::Revolution","RotateExtrude")
myrev.Source = obj
myrev.Axis = (0.00,1.00,0.00)
myrev.Base = (0.00,0.00,0.00)
myrev.Angle = 360.00
myrev.Placement=FreeCAD.Placement(FreeCAD.Vector(),FreeCAD.Rotation(0,0,90))
if gui:
obj.ViewObject.hide()
newobj=doc.addObject("Part::FeaturePython",'RefineRotateExtrude')
RefineShape(newobj,myrev)
RefineShape(newobj,obj)
if gui:
if FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/OpenSCAD").\
GetBool('useViewProviderTree'):
@@ -543,8 +551,16 @@ def process_rotate_extrude(obj):
ViewProviderTree(newobj.ViewObject)
else:
newobj.ViewObject.Proxy = 0
myrev.ViewObject.hide()
return(newobj)
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 = 360.00
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'
@@ -565,18 +581,9 @@ def p_rotate_extrude_file(p):
if printverbose: 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
if gui:
obj.ViewObject.hide()
#if gui:
newobj=doc.addObject("Part::FeaturePython",'RefineLinearExtrude')
RefineShape(newobj,mylinear)
RefineShape(newobj,obj)#mylinear)
if gui:
if FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/OpenSCAD").\
GetBool('useViewProviderTree'):
@@ -584,8 +591,19 @@ def process_linear_extrude(obj,h) :
ViewProviderTree(newobj.ViewObject)
else:
newobj.ViewObject.Proxy = 0
mylinear.ViewObject.hide()
return(newobj)
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()
try:
mylinear.Solid = True
except:
pass
if gui:
newobj.ViewObject.hide()
return(mylinear)
def process_linear_extrude_with_twist(base,height,twist) :
newobj=doc.addObject("Part::FeaturePython",'twist_extrude')
@@ -715,38 +733,50 @@ def p_multmatrix_action(p):
transform_matrix = FreeCAD.Matrix()
if printverbose: print "Multmatrix"
if printverbose: 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)
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]) > 1) :
if (len(p[6]) == 0) :
part = placeholder('group',[],'{}')
elif (len(p[6]) > 1) :
part = fuse(p[6],"Matrix Union")
else :
else :
part = p[6][0]
# part = new_part.transformGeometry(transform_matrix)
# part = new_part.copy()
# part.transformShape(transform_matrix)
if (isspecialorthogonaldeterminant(fcsubmatrix(transform_matrix))) :
if printverbose: print "Orthogonal"
part.Placement=FreeCAD.Placement(transform_matrix).multiply(part.Placement)
new_part = part
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
new_part.Placement=FreeCAD.Placement(cmat)
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()
@@ -922,12 +952,12 @@ def p_cube_action(p):
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
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')
FreeCAD.Console.PrintWarning('cube with radius zero\n')
mycube=doc.addObject("Part::Feature","emptycube")
mycube.Shape = Part.Compound([])
if p[3]['center']=='true' :
@@ -947,11 +977,21 @@ def p_circle_action(p) :
# in the modules preferences
import Draft
if n == 0 or fnmax != 0 and n >= fnmax:
mycircle = Draft.makeCircle(r)
#mycircle = doc.addObject('Part::Circle',p[1])
#mycircle.Radius = r
mycircle = FreeCAD.ActiveDocument.addObject("Part::Part2DObjectPython",'circle')
Draft._Circle(mycircle)
mycircle.Radius = r
#mycircle = Draft.makeCircle(r) # 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)
#mycircle = Draft.makePolygon(n,r) # would call doc.recompute
mycircle = FreeCAD.ActiveDocument.addObject("Part::Part2DObjectPython",'polygon')
Draft._Polygon(mycricle)
mycircle.FacesNumber = n
mycircle.Radius = r
mycircle.DrawMode = "inscribed"
if gui:
Draft._ViewProviderDraft(mycircle.ViewObject)
if printverbose: print "Push Circle"
p[0] = [mycircle]
@@ -1021,7 +1061,8 @@ def make_face(v1,v2,v3):
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 keywordargument_list RPAREN SEMICOL'
'''polyhedron_action : polyhedron LPAREN points EQ OSQUARE points_list_3d ESQUARE COMMA faces EQ OSQUARE points_list_3d 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] :