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

@@ -95,10 +95,12 @@ static char * openscadlogo_xpm[] = {
def Initialize(self):
import OpenSCAD_rc,OpenSCADCommands
commands=['OpenSCAD_ReplaceObject','OpenSCAD_RemoveSubtree',\
'OpenSCAD_RefineShapeFeature',"OpenSCAD_Edgestofaces",\
'OpenSCAD_ExpandPlacements']
'OpenSCAD_RefineShapeFeature',\
'OpenSCAD_IncreaseToleranceFeature', 'OpenSCAD_Edgestofaces', \
'OpenSCAD_ExpandPlacements','OpenSCAD_ExplodeGroup']
toolbarcommands=['OpenSCAD_ReplaceObject','OpenSCAD_RemoveSubtree',\
'OpenSCAD_RefineShapeFeature']
'OpenSCAD_ExplodeGroup','OpenSCAD_RefineShapeFeature']
#'OpenSCAD_IncreaseToleranceFeature' #icon still missing
import PartGui
parttoolbarcommands = ['Part_CheckGeometry',"Part_Primitives",\
"Part_Builder",'Part_Cut','Part_Fuse','Part_Common',\

View File

@@ -37,6 +37,50 @@ def translate(context,text):
def utf8(unio):
return unicode(unio).encode('UTF8')
class ExplodeGroup:
"Ungroup Objects"
def IsActive(self):
return FreeCADGui.Selection.countObjectsOfType('Part::Feature') > 0
def Activated(self):
def isgrey(shapecolor):
defaultcolor=(float.fromhex('0x1.99999ap-1'),float.fromhex('0x1.99999ap-1'),\
float.fromhex('0x1.99999ap-1'),0.0)
return all(facecolor == defaultcolor for facecolor in shapecolor)
def randomcolor(transp=0.0):
import random
return (random.random(),random.random(),random.random(),transp)
def explode(obj,color=True):
if obj.isDerivedFrom('Part::Fuse') or obj.isDerivedFrom('Part::MultiFuse'):
plm = obj.Placement
outlist = obj.OutList[:]
if plm.isNull() or all(len(oo.InList)==1 for oo in obj.OutList):
obj.Document.removeObject(obj.Name)
for oo in outlist:
if not plm.isNull():
oo.Placement=plm.multiply(oo.Placement)
if FreeCAD.GuiUp:
import FreeCADGui
oo.ViewObject.show()
if color and isgrey(oo.ViewObject.DiffuseColor):
if color == True:
oo.ViewObject.DiffuseColor=randomcolor()
else:
oo.ViewObject.DiffuseColor=color
for obj in FreeCADGui.Selection.getSelection():
if len(obj.InList) == 0: # allowed only for for top level objects
explode(obj)
def GetResources(self):
return {'Pixmap' : 'OpenSCAD_Explode_Group', 'MenuText': \
QtCore.QT_TRANSLATE_NOOP('OpenSCAD_ExplodeGroup',\
'Explode Group'), 'ToolTip': \
QtCore.QT_TRANSLATE_NOOP('OpenSCAD_ExplodeGroup',\
'remove fusion, apply placement to children and color randomly')}
class ColorCodeShape:
"Change the Color of selected or all Shapes based on their validity"
def Activated(self):
@@ -57,7 +101,7 @@ class ColorCodeShape:
class Edgestofaces:
def IsActive(self):
return bool(FreeCADGui.Selection.getSelectionEx())
return FreeCADGui.Selection.countObjectsOfType('Part::Feature') > 0
def Activated(self):
from OpenSCAD2Dgeom import edgestofaces,Overlappingfaces
@@ -78,13 +122,12 @@ class Edgestofaces:
class RefineShapeFeature:
def IsActive(self):
return bool(FreeCADGui.Selection.getSelectionEx())
return FreeCADGui.Selection.countObjectsOfType('Part::Feature') > 0
def Activated(self):
import Part,OpenSCADFeatures
selection=FreeCADGui.Selection.getSelectionEx()
for selobj in selection:
#newobj=FreeCAD.ActiveDocument.addObject("Part::FeaturePython",'refine')
newobj=selobj.Document.addObject("Part::FeaturePython",'refine')
OpenSCADFeatures.RefineShape(newobj,selobj.Object)
OpenSCADFeatures.ViewProviderTree(newobj.ViewObject)
@@ -98,13 +141,34 @@ class RefineShapeFeature:
QtCore.QT_TRANSLATE_NOOP('OpenSCAD_RefineShapeFeature',\
'Create Refine Shape Feature')}
class IncreaseToleranceFeature:
def IsActive(self):
return FreeCADGui.Selection.countObjectsOfType('Part::Feature') > 0
def Activated(self):
import Part,OpenSCADFeatures
selection=FreeCADGui.Selection.getSelectionEx()
for selobj in selection:
newobj=selobj.Document.addObject("Part::FeaturePython",'tolerance')
OpenSCADFeatures.IncreaseTolerance(newobj,selobj.Object)
OpenSCADFeatures.ViewProviderTree(newobj.ViewObject)
newobj.Label='tolerance_%s' % selobj.Object.Label
selobj.Object.ViewObject.hide()
FreeCAD.ActiveDocument.recompute()
def GetResources(self):
return {'Pixmap' : 'OpenSCAD_IncreaseToleranceFeature', 'MenuText': \
QtCore.QT_TRANSLATE_NOOP('OpenSCAD_IncreaseToleranceFeature',\
'Increase Tolerance Feature'), 'ToolTip': \
QtCore.QT_TRANSLATE_NOOP('OpenSCAD_IncreaseToleranceFeature',\
'Create Feature that allows to increase the tolerance')}
class ExpandPlacements:
'''This should aid interactive repair in the future
but currently it breaks extrusions, as axis, base and so on have to be
recalculated'''
def IsActive(self):
return bool(FreeCADGui.Selection.getSelectionEx())
return FreeCADGui.Selection.countObjectsOfType('Part::Feature') > 0
def Activated(self):
import expandplacements
@@ -119,7 +183,7 @@ class ExpandPlacements:
class ReplaceObject:
def IsActive(self):
return len(FreeCADGui.Selection.getSelection()) == 3
return FreeCADGui.Selection.countObjectsOfType('Part::Feature') == 3
def Activated(self):
import replaceobj
#objs=[selobj.Object for selobj in FreeCADGui.Selection.getSelectionEx()]
@@ -139,28 +203,11 @@ class ReplaceObject:
class RemoveSubtree:
def IsActive(self):
return bool(FreeCADGui.Selection.getSelectionEx())
return FreeCADGui.Selection.countObjectsOfType('Part::Feature') > 0
def Activated(self):
def addsubobjs(obj,toremoveset):
toremove.add(obj)
for subobj in obj.OutList:
addsubobjs(subobj,toremoveset)
import OpenSCADUtils,FreeCADGui
OpenSCADUtils.removesubtree(FreeCADGui.Selection.getSelection())
import FreeCAD,FreeCADGui
objs=FreeCADGui.Selection.getSelection()
toremove=set()
for obj in objs:
addsubobjs(obj,toremove)
checkinlistcomplete =False
while not checkinlistcomplete:
for obj in toremove:
if (obj not in objs) and (frozenset(obj.InList) - toremove):
toremove.remove(obj)
break
else:
checkinlistcomplete = True
for obj in toremove:
obj.Document.removeObject(obj.Name)
def GetResources(self):
return {'Pixmap' : 'OpenSCAD_RemoveSubtree', 'MenuText': \
QtCore.QT_TRANSLATE_NOOP('OpenSCAD_RemoveSubtree',\
@@ -368,8 +415,10 @@ class Minkowski:
'Perform Minkowski')}
FreeCADGui.addCommand('OpenSCAD_ColorCodeShape',ColorCodeShape())
FreeCADGui.addCommand('OpenSCAD_ExplodeGroup',ExplodeGroup())
FreeCADGui.addCommand('OpenSCAD_Edgestofaces',Edgestofaces())
FreeCADGui.addCommand('OpenSCAD_RefineShapeFeature',RefineShapeFeature())
FreeCADGui.addCommand('OpenSCAD_IncreaseToleranceFeature',IncreaseToleranceFeature())
FreeCADGui.addCommand('OpenSCAD_ExpandPlacements',ExpandPlacements())
FreeCADGui.addCommand('OpenSCAD_ReplaceObject',ReplaceObject())
FreeCADGui.addCommand('OpenSCAD_RemoveSubtree',RemoveSubtree())

View File

@@ -292,6 +292,31 @@ class RefineShape:
sh=fp.Base.Shape.removeSplitter()
fp.Shape=sh
class IncreaseTolerance:
'''increase the tolerance of every vertex
in the current implementation its' placement is linked'''
def __init__(self,obj,child,tolerance=0):
obj.addProperty("App::PropertyLink","Base","Base",
"The base object that wire must be extracted")
obj.addProperty("App::PropertyDistance","Tolerance","Base","Tolerance")
obj.Base = child
obj.Tolerance = tolerance
obj.Proxy = self
def onChanged(self, fp, prop):
if prop in ["Tolerance"]:
self.createGeometry(fp)
def execute(self, fp):
self.createGeometry(fp)
def createGeometry(self,fp):
if fp.Base:
sh=fp.Base.Shape.copy()
for vertex in sh.Vertexes:
vertex.Tolerance = max(vertex.Tolerance,fp.Tolerance.Value)
fp.Shape = sh
fp.Placement = sh.Placement
class GetWire:
'''return the first wire from a given shape'''
def __init__(self, obj,child=None):

View File

@@ -109,7 +109,7 @@ def callopenscad(inputfilename,outputfilename=None,outputext='csg',keepname=Fals
p=subprocess.Popen(*args,**kwargs)
stdoutd,stderrd = p.communicate()
if p.returncode != 0:
raise OpenSCADError('%s %s\n' % (stdoutd.strip(),stderr.strip()))
raise OpenSCADError('%s %s\n' % (stdoutd.strip(),stderrd.strip()))
#raise Exception,'stdout %s\n stderr%s' %(stdoutd,stderrd)
if stderrd.strip():
FreeCAD.Console.PrintWarning(stderrd+u'\n')
@@ -188,12 +188,14 @@ def multiplymat(l,r):
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]]
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]
return s[0][0]*s[1][1]*s[2][2]+s[0][1]*s[1][2]*s[2][0]+\
s[0][2]*s[1][0]*s[2][1]-s[2][0]*s[1][1]*s[0][2]-\
s[2][1]*s[1][2]*s[0][0]-s[2][2]*s[1][0]*s[0][1]
def isspecialorthogonalpython(submat,precision=4):
return isorthogonal(submat,precision) and round(detsubmatrix(submat),precision)==1
@@ -202,7 +204,8 @@ def isrotoinversionpython(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 \
return abs(mat.submatrix(3).isOrthogonal(10**(-precision))-1.0) < \
10**(-precision) and \
abs(mat.submatrix(3).determinant()-1.0) < 10**(-precision)
def decomposerotoinversion(m,precision=4):
@@ -241,6 +244,123 @@ def vec2householder(nv):
nv.z*nv.x*l,nv.z*nv.y*l,nv.z*nv.z*l,0,0,0,0,0)
return FreeCAD.Matrix()-hh
def angneg(d):
return d if (d <= 180.0) else (d-360)
def shorthexfloat(f):
s=f.hex()
mantisse, exponent = f.hex().split('p',1)
return '%sp%s' % (mantisse.rstrip('0'),exponent)
def comparerotations(r1,r2):
import FreeCAD
'''compares two rotations
a value of zero means that they are identical'''
r2c=FreeCAD.Rotation(r2)
r2c.invert()
return r1.multiply(r2c).Angle
def findbestmatchingrotation(r1):
import FreeCAD
vangl = \
(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 11.25, 12.0, 13.0,
14.0, 15.0, 16.0, (180.0/11.0), 17.0, 18.0, 19.0, 20.0, 21.0, 22.0, 22.5,
23.0, 24.0, 25.0, 26.0, 27.0, 28.0, 29.0, 30.0, 31.0, 32.0, (360.0/11.0),
33.0, 33.75, 34.0, 35.0, 36.0, 37.0, 38.0, 39.0, 40.0, 41.0, 42.0, 43.0,
44.0, 45.0, 46.0, 47.0, 48.0, 49.0,(540.0/11.0), 50.0, 51.0, (360.0/7.0),
52.0, 53.0, 54.0, 55.0, 56.0, 56.25, 57.0, 58.0, 59.0, 60.0, 61.0, 62.0,
63.0, 64.0, 65.0,(720.0/11.0), 66.0, 67.0, 67.5, 68.0, 69.0, 70.0, 71.0,
72.0, 73.0, 74.0, 75.0, 76.0, 77.0, 78.0, 78.75, 79.0, 80.0, 81.0,(900.0/11.0),
82.0, 83.0, 84.0, 85.0, 86.0, 87.0, 88.0, 89.0, 90.0, 91.0, 92.0, 93.0, 94.0,
95.0, 96.0, 97.0, 98.0,(1080.0/11.0), 99.0, 100.0, 101.0, 101.25, 102.0,
(720.0/7.0), 103.0, 104.0, 105.0, 106.0, 107.0, 108.0, 109.0, 110.0, 111.0,
112.0, 112.5, 113.0, 114.0, (1260.0/11), 115.0, 116.0, 117.0, 118.0, 119.0,
120.0, 121.0, 122.0, 123.0, 123.75, 124.0, 125.0, 126.0, 127.0, 128.0,
129.0, 130.0,(1440.0/11.0), 131.0, 132.0, 133.0, 134.0, 135.0, 136.0,
137.0, 138.0, 139.0, 140.0, 141.0, 142.0, 143.0, 144.0, 145.0, 146.0, 146.25,
147.0, (1620.0/11.0), 148.0, 149.0, 150.0, 151.0, 152.0, 153.0, 154.0,
(1080.0/7.0), 155.0, 156.0, 157.0, 157.5, 158.0, 159.0, 160.0, 161.0, 162.0,
163.0, (1800.0/11.0), 164.0, 165.0, 166.0, 167.0, 168.0, 168.75, 169.0, 170.0,
171.0, 172.0, 173.0, 174.0, 175.0, 176.0, 177.0,178.0, 179.0,180.0,
-179.0, -178.0, -177.0, -176.0, -175.0, -174.0, -173.0, -172.0, -171.0, -170.0,
-169.0, -168.75, -168.0, -167.0, -166.0, -165.0, -164.0, (-1800.0/11.0),
-163.0, -162.0, -161.0, -160.0, -159.0, -158.0, -157.5, -157.0, -156.0,
-155.0, (-1080.0/7.0), -154.0, -153.0, -152.0, -151.0, -150.0, -149.0, -148.0,
(-1620.0/11.0), -147.0, -146.25, -146.0, -145.0, -144.0, -143.0, -142.0,
-141.0, -140.0, -139.0,-138.0, -137.0, -136.0, -135.0, -134.0, -133.0, -132.0,
-131.0, (-1440/11.0), -130.0, -129.0, -128.0,-127.0, -126.0, -125.0, -124.0,
-123.75, -123.0, -122.0, -121.0, -120.0, -119.0, -118.0, -117.0, -116.0,
-115.0,(-1260.0/11.0), -114.0, -113.0, -112.5, -112.0, -111.0, -110.0, -109.0,
-108.0, -107.0, -106.0, -105.0,-104.0, -103.0,(-720.0/7.0), -102.0, -101.25,
-101.0, -100.0, -99.0, (-1080.0/11.0), -98.0, -97.0, -96.0, -95.0, -94.0,
-93.0, -92.0, -91.0, -90.0, -89.0, -88.0, -87.0, -86.0, -85.0, -84.0, -83.0,
-82.0,(-900.0/11.0), -81.0, -80.0, -79.0, -78.75, -78.0, -77.0, -76.0, -75.0,
-74.0, -73.0, -72.0, -71.0, -70.0, -69.0, -68.0, -67.5, -67.0, -66.0,
(-720.0/11.0), -65.0, -64.0, -63.0, -62.0, -61.0, -60.0, -59.0, -58.0, -57.0,
-56.25, -56.0, -55.0, -54.0, -53.0, -52.0,(-360.0/7.0), -51.0, -50.0,
(-540.0/11.0), -49.0, -48.0, -47.0, -46.0, -45.0, -44.0, -43.0, -42.0, -41.0,
-40.0, -39.0, -38.0, -37.0, -36.0, -35.0, -34.0, -33.75, -33.0,(-360.0/11.0),
-32.0, -31.0, -30.0, -29.0, -28.0, -27.0, -26.0, -25.0, -24.0, -23.0, -22.5,
-22.0, -21.0, -20.0, -19.0, -18.0, -17.0,(-180.0/11.0), -16.0, -15.0, -14.0,
-13.0, -12.0, -11.25, -11.0, -10.0, -9.0, -8.0, -7.0, -6.0, -5.0, -4.0, -3.0,
-2.0, -1.0)
def tup2nvect(tup):
"""convert a tuple to a normalized vector"""
v=FreeCAD.Vector(*tup)
v.normalize()
return v
def wkaxes():
"""well known axes for rotations"""
vtupl=((1,0,0),(0,1,0),(0,0,1),
(1,1,0),(1,0,1),(0,1,1),(-1,1,0),(-1,0,1),(0,1,-1),
(1,1,1),(1,1,-1),(1,-1,1),(-1,1,1))
return tuple(tup2nvect(tup) for tup in vtupl)
bestrot=FreeCAD.Rotation()
dangle = comparerotations(r1,bestrot)
for axis in wkaxes():
for angle in vangl:
for axissign in (1.0,-1.0):
r2=FreeCAD.Rotation(axis*axissign,angle)
dangletest = comparerotations(r1,r2)
if dangletest < dangle:
bestrot = r2
dangle = dangletest
return (bestrot,dangle)
def roundrotation(rot,maxangulardistance=1e-5):
'''guess the rotation axis and angle for a rotation
recreated from rounded floating point values
(from a quaterion or transformation matrix)'''
def teststandardrot(r1,maxangulardistance=1e-5):
'''test a few common rotations beforehand'''
import FreeCAD,itertools
eulers = []
for angle in (90,-90,180,45,-45,135,-135):
for euler in itertools.permutations((0,0,angle)):
eulers.append(euler)
for euler in itertools.product((0,45,90,135,180,-45,-90,-135),repeat=3):
eulers.append(euler)
for euler in eulers:
r2 = FreeCAD.Rotation(*euler)
if comparerotations(r1,r2) < maxangulardistance:
return r2
if rot.isNull():
return rot
firstguess = teststandardrot(rot,maxangulardistance)
if firstguess is not None:
return firstguess
#brute force
bestguess,angulardistance = findbestmatchingrotation(rot)
if angulardistance < maxangulardistance: #use guess
return bestguess
else: #use original
return rot
def callopenscadmeshstring(scadstr):
"""Call OpenSCAD and return the result as a Mesh"""
import Mesh,os
@@ -414,3 +534,24 @@ def process_ObjectsViaOpenSCAD(doc,children,name):
import FreeCAD
FreeCAD.Console.PrintError( unicode(translate('OpenSCAD',\
"Error all shapes must be either 2D or both must be 3D"))+u'\n')
def removesubtree(objs):
def addsubobjs(obj,toremoveset):
toremove.add(obj)
for subobj in obj.OutList:
addsubobjs(subobj,toremoveset)
import FreeCAD
toremove=set()
for obj in objs:
addsubobjs(obj,toremove)
checkinlistcomplete =False
while not checkinlistcomplete:
for obj in toremove:
if (obj not in objs) and (frozenset(obj.InList) - toremove):
toremove.remove(obj)
break
else:
checkinlistcomplete = True
for obj in toremove:
obj.Document.removeObject(obj.Name)

File diff suppressed because one or more lines are too long

View File

@@ -6,6 +6,7 @@
<file>icons/OpenSCAD_RefineShapeFeature.svg</file>
<file>icons/OpenSCAD_ReplaceObject.svg</file>
<file>icons/OpenSCAD_RemoveSubtree.svg</file>
<file>icons/OpenSCAD_Explode_Group.svg</file>
<file>icons/OpenSCAD_MeshBooleans.svg</file>
<file>icons/OpenSCAD_Hull.svg</file>
<file>icons/OpenSCAD_Minkowski.svg</file>

View File

@@ -0,0 +1,588 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="64px"
height="64px"
id="svg2980"
sodipodi:version="0.32"
inkscape:version="0.48.3.1 r9886"
sodipodi:docname="OpenSCAD_Explode_Group_9.svg"
inkscape:output_extension="org.inkscape.output.svg.inkscape"
version="1.1"
inkscape:export-filename="/home/user/Downloads/cad/mystuff/icons/OpenSCAD_workbench/OpenSCAD_Explode_Group_9_32px.png"
inkscape:export-xdpi="45"
inkscape:export-ydpi="45">
<defs
id="defs2982">
<linearGradient
id="linearGradient4287">
<stop
id="stop4289"
offset="0"
style="stop-color:#f87c71;stop-opacity:1;" />
<stop
id="stop4291"
offset="1"
style="stop-color:#ff0000;stop-opacity:1;" />
</linearGradient>
<linearGradient
id="linearGradient3864">
<stop
id="stop3866"
offset="0"
style="stop-color:#71b2f8;stop-opacity:1;" />
<stop
id="stop3868"
offset="1"
style="stop-color:#002795;stop-opacity:1;" />
</linearGradient>
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient3864"
id="radialGradient3850"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.6028459,1.0471639,-1.9794021,1.1395295,127.9588,-74.456907)"
cx="51.328892"
cy="31.074146"
fx="51.328892"
fy="31.074146"
r="19.571428" />
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 32 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="64 : 32 : 1"
inkscape:persp3d-origin="32 : 21.333333 : 1"
id="perspective2988" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient3377-6"
id="radialGradient3699"
gradientUnits="userSpaceOnUse"
cx="76.383331"
cy="94.369568"
fx="76.383331"
fy="94.369568"
r="19.467436"
gradientTransform="matrix(0.9818943,0.1894295,-0.4109427,2.1300924,40.163453,-121.11559)" />
<linearGradient
id="linearGradient3377">
<stop
id="stop3379"
offset="0"
style="stop-color:#faff2b;stop-opacity:1;" />
<stop
id="stop3381"
offset="1"
style="stop-color:#ffaa00;stop-opacity:1;" />
</linearGradient>
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient3377"
id="radialGradient3701"
gradientUnits="userSpaceOnUse"
cx="84.883324"
cy="77.042847"
fx="84.883324"
fy="77.042847"
r="19.467436"
gradientTransform="matrix(2.8492421,1.2585119,-0.4040415,0.9147407,-125.84131,-100.25805)" />
<linearGradient
id="linearGradient3007">
<stop
id="stop3009"
offset="0"
style="stop-color:#faff2b;stop-opacity:1;" />
<stop
id="stop3011"
offset="1"
style="stop-color:#ffaa00;stop-opacity:1;" />
</linearGradient>
<radialGradient
r="19.467436"
fy="77.042847"
fx="84.883324"
cy="77.042847"
cx="84.883324"
gradientTransform="matrix(2.8492421,1.2585119,-0.4040415,0.9147407,-125.84131,-100.25805)"
gradientUnits="userSpaceOnUse"
id="radialGradient3017"
xlink:href="#linearGradient3377-6"
inkscape:collect="always" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient3377-6"
id="radialGradient3699-2"
gradientUnits="userSpaceOnUse"
cx="76.383331"
cy="94.369568"
fx="76.383331"
fy="94.369568"
r="19.467436"
gradientTransform="matrix(0.9818943,0.1894295,-0.4109427,2.1300924,40.163453,-121.11559)" />
<linearGradient
id="linearGradient3377-6">
<stop
id="stop3379-2"
offset="0"
style="stop-color:#00afff;stop-opacity:1;" />
<stop
id="stop3381-4"
offset="1"
style="stop-color:#0034ff;stop-opacity:1;" />
</linearGradient>
<radialGradient
r="19.467436"
fy="77.042847"
fx="84.883324"
cy="77.042847"
cx="84.883324"
gradientTransform="matrix(2.8492421,1.2585119,-0.4040415,0.9147407,-125.84131,-100.25805)"
gradientUnits="userSpaceOnUse"
id="radialGradient3017-8"
xlink:href="#linearGradient3377-6"
inkscape:collect="always" />
<linearGradient
id="linearGradient3835">
<stop
id="stop3837"
offset="0"
style="stop-color:#faff2b;stop-opacity:1;" />
<stop
id="stop3839"
offset="1"
style="stop-color:#ffaa00;stop-opacity:1;" />
</linearGradient>
<radialGradient
r="19.467436"
fy="77.042847"
fx="84.883324"
cy="77.042847"
cx="84.883324"
gradientTransform="matrix(2.8492421,1.2585119,-0.4040415,0.9147407,-125.84131,-100.25805)"
gradientUnits="userSpaceOnUse"
id="radialGradient3844"
xlink:href="#linearGradient3377-6"
inkscape:collect="always" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient3377-6"
id="radialGradient3699-7"
gradientUnits="userSpaceOnUse"
cx="76.383331"
cy="94.369568"
fx="76.383331"
fy="94.369568"
r="19.467436"
gradientTransform="matrix(0.9818943,0.1894295,-0.4109427,2.1300924,40.163453,-121.11559)" />
<linearGradient
id="linearGradient3377-2">
<stop
id="stop3379-7"
offset="0"
style="stop-color:#faff2b;stop-opacity:1;" />
<stop
id="stop3381-8"
offset="1"
style="stop-color:#ffaa00;stop-opacity:1;" />
</linearGradient>
<radialGradient
r="19.467436"
fy="77.042847"
fx="84.883324"
cy="77.042847"
cx="84.883324"
gradientTransform="matrix(2.8492421,1.2585119,-0.4040415,0.9147407,-125.84131,-100.25805)"
gradientUnits="userSpaceOnUse"
id="radialGradient3017-6"
xlink:href="#linearGradient3377-2"
inkscape:collect="always" />
<linearGradient
id="linearGradient3835-1">
<stop
id="stop3837-0"
offset="0"
style="stop-color:#faff2b;stop-opacity:1;" />
<stop
id="stop3839-9"
offset="1"
style="stop-color:#ffaa00;stop-opacity:1;" />
</linearGradient>
<radialGradient
r="19.467436"
fy="77.042847"
fx="84.883324"
cy="77.042847"
cx="84.883324"
gradientTransform="matrix(2.8492421,1.2585119,-0.4040415,0.9147407,-125.84131,-100.25805)"
gradientUnits="userSpaceOnUse"
id="radialGradient3844-7"
xlink:href="#linearGradient3377-6"
inkscape:collect="always" />
<linearGradient
id="linearGradient4032">
<stop
style="stop-color:#71b2f8;stop-opacity:1;"
offset="0"
id="stop4034" />
<stop
style="stop-color:#002795;stop-opacity:1;"
offset="1"
id="stop4036" />
</linearGradient>
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient4032"
id="radialGradient4114"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.19036833,-0.61386357,1.99853,-0.19092801,-47.133199,165.45559)"
cx="113.50187"
cy="65.849281"
fx="113.50187"
fy="65.849281"
r="19.467436" />
<linearGradient
id="linearGradient3171">
<stop
style="stop-color:#71b2f8;stop-opacity:1;"
offset="0"
id="stop3173" />
<stop
style="stop-color:#002795;stop-opacity:1;"
offset="1"
id="stop3175" />
</linearGradient>
<linearGradient
id="linearGradient4032-7">
<stop
style="stop-color:#71b2f8;stop-opacity:1;"
offset="0"
id="stop4034-3" />
<stop
style="stop-color:#002795;stop-opacity:1;"
offset="1"
id="stop4036-6" />
</linearGradient>
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient4032-7"
id="radialGradient4114-3"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.19036833,-0.61386357,1.99853,-0.19092801,-47.133199,165.45559)"
cx="113.50187"
cy="65.849281"
fx="113.50187"
fy="65.849281"
r="19.467436" />
<linearGradient
id="linearGradient3171-9">
<stop
style="stop-color:#71b2f8;stop-opacity:1;"
offset="0"
id="stop3173-7" />
<stop
style="stop-color:#002795;stop-opacity:1;"
offset="1"
id="stop3175-5" />
</linearGradient>
<linearGradient
id="linearGradient4032-8">
<stop
style="stop-color:#71b2f8;stop-opacity:1;"
offset="0"
id="stop4034-4" />
<stop
style="stop-color:#002795;stop-opacity:1;"
offset="1"
id="stop4036-3" />
</linearGradient>
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient4032-8"
id="radialGradient4114-9"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.19036833,-0.61386357,1.99853,-0.19092801,-47.133199,165.45559)"
cx="113.50187"
cy="65.849281"
fx="113.50187"
fy="65.849281"
r="19.467436" />
<linearGradient
id="linearGradient3171-1">
<stop
style="stop-color:#71b2f8;stop-opacity:1;"
offset="0"
id="stop3173-0" />
<stop
style="stop-color:#002795;stop-opacity:1;"
offset="1"
id="stop3175-3" />
</linearGradient>
<linearGradient
id="linearGradient4032-0">
<stop
style="stop-color:#71b2f8;stop-opacity:1;"
offset="0"
id="stop4034-37" />
<stop
style="stop-color:#002795;stop-opacity:1;"
offset="1"
id="stop4036-1" />
</linearGradient>
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient4032-0"
id="radialGradient3703"
gradientUnits="userSpaceOnUse"
cx="132.70454"
cy="90.193245"
fx="132.70454"
fy="90.193245"
r="19.467436"
gradientTransform="matrix(-0.08162339,1.3949072,-1.1572569,-0.26963374,245.22773,-105.44363)" />
<linearGradient
id="linearGradient3284">
<stop
style="stop-color:#71b2f8;stop-opacity:1;"
offset="0"
id="stop3286" />
<stop
style="stop-color:#002795;stop-opacity:1;"
offset="1"
id="stop3288" />
</linearGradient>
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient3593"
id="radialGradient3599"
gradientUnits="userSpaceOnUse"
cx="51.637894"
cy="24.962704"
fx="51.637894"
fy="24.962704"
r="19.571428" />
<linearGradient
id="linearGradient3593">
<stop
style="stop-color:#c8e0f9;stop-opacity:1;"
offset="0"
id="stop3595" />
<stop
style="stop-color:#637dca;stop-opacity:1;"
offset="1"
id="stop3597" />
</linearGradient>
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient3864-9"
id="radialGradient3552"
gradientUnits="userSpaceOnUse"
cx="48.645836"
cy="25.149042"
fx="48.645836"
fy="25.149042"
r="19.571428" />
<linearGradient
id="linearGradient3864-9">
<stop
id="stop3866-3"
offset="0"
style="stop-color:#71b2f8;stop-opacity:1;" />
<stop
id="stop3868-3"
offset="1"
style="stop-color:#002795;stop-opacity:1;" />
</linearGradient>
<radialGradient
r="19.571428"
fy="25.149042"
fx="48.645836"
cy="25.149042"
cx="48.645836"
gradientUnits="userSpaceOnUse"
id="radialGradient3304"
xlink:href="#linearGradient3864-9"
inkscape:collect="always" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient4287"
id="radialGradient4285"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(-0.54355955,-0.69959567,1.0924249,-0.61410558,95.667642,203.16161)"
cx="112.7718"
cy="66.255531"
fx="112.7718"
fy="66.255531"
r="19.467436" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4287"
id="linearGradient4293"
x1="25.559771"
y1="48.403759"
x2="31.477535"
y2="52.710686"
gradientUnits="userSpaceOnUse" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="12.390625"
inkscape:cx="31.919294"
inkscape:cy="32"
inkscape:current-layer="layer1"
showgrid="true"
inkscape:document-units="px"
inkscape:grid-bbox="true"
inkscape:window-width="1280"
inkscape:window-height="1004"
inkscape:window-x="1278"
inkscape:window-y="-3"
inkscape:window-maximized="1"
inkscape:snap-global="false" />
<metadata
id="metadata2985">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
id="layer1"
inkscape:label="Layer 1"
inkscape:groupmode="layer">
<g
id="g3560"
transform="matrix(0.91273618,0,0,0.90349515,7.8537384,-1.1996367)">
<path
transform="matrix(0.9153551,0,0,0.3021994,-4.6085053,28.76682)"
d="m 71.785715,34.571426 c 0,10.256717 -8.314712,18.571429 -18.571428,18.571429 -10.256717,0 -18.571428,-8.314712 -18.571428,-18.571429 0,-10.256716 8.314711,-18.571428 18.571428,-18.571428 10.256716,0 18.571428,8.314712 18.571428,18.571428 z"
sodipodi:ry="18.571428"
sodipodi:rx="18.571428"
sodipodi:cy="34.571426"
sodipodi:cx="53.214287"
id="path3558"
style="opacity:0.66523605;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.5;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
sodipodi:type="arc" />
<path
transform="matrix(1.0092422,0,0,1.0092422,-12.598958,-12.283801)"
d="m 71.785715,34.571426 c 0,10.256717 -8.314712,18.571429 -18.571428,18.571429 -10.256717,0 -18.571428,-8.314712 -18.571428,-18.571429 0,-10.256716 8.314711,-18.571428 18.571428,-18.571428 10.256716,0 18.571428,8.314712 18.571428,18.571428 z"
sodipodi:ry="18.571428"
sodipodi:rx="18.571428"
sodipodi:cy="34.571426"
sodipodi:cx="53.214287"
id="path2768"
style="fill:url(#radialGradient3599);fill-opacity:1;fill-rule:evenodd;stroke:#4b4dba;stroke-width:2.17985344;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
sodipodi:type="arc" />
<path
transform="matrix(1.1483533,0,0,0.3791225,-28.823086,42.536051)"
d="m 71.785715,34.571426 c 0,10.256717 -8.314712,18.571429 -18.571428,18.571429 -10.256717,0 -18.571428,-8.314712 -18.571428,-18.571429 0,-10.256716 8.314711,-18.571428 18.571428,-18.571428 10.256716,0 18.571428,8.314712 18.571428,18.571428 z"
sodipodi:ry="18.571428"
sodipodi:rx="18.571428"
sodipodi:cy="34.571426"
sodipodi:cx="53.214287"
id="path3554"
style="opacity:0.66523605;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.5;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
sodipodi:type="arc" />
<path
transform="matrix(1.12939,0,0,1.12939,-36.028256,1.4553754)"
d="m 71.785715,34.571426 c 0,10.256717 -8.314712,18.571429 -18.571428,18.571429 -10.256717,0 -18.571428,-8.314712 -18.571428,-18.571429 0,-10.256716 8.314711,-18.571428 18.571428,-18.571428 10.256716,0 18.571428,8.314712 18.571428,18.571428 z"
sodipodi:ry="18.571428"
sodipodi:rx="18.571428"
sodipodi:cy="34.571426"
sodipodi:cx="53.214287"
id="path3550"
style="fill:url(#radialGradient3304);fill-opacity:1;fill-rule:evenodd;stroke:#000137;stroke-width:1.94795418;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
sodipodi:type="arc" />
</g>
<g
id="g3760-8"
transform="matrix(0.4215621,-0.05553169,-0.07935438,0.54086525,28.000485,-15.81317)" />
<g
id="g3080"
transform="matrix(0.84096804,-0.46792735,0.48377141,0.79640302,-35.221278,20.515799)">
<path
sodipodi:nodetypes="ccccc"
id="path3727-0"
d="M 32.018051,65.595741 C 36.744064,58.001751 42.050792,48.459568 47.711504,38.38254 L 29.593262,29.441251 15.069181,54.973283 c -1.037712,5.511601 6.035212,12.3496 16.94887,10.622458 z"
style="fill:url(#linearGradient4293);fill-opacity:1;fill-rule:evenodd;stroke:#170b0b;stroke-width:3.09920310999999993;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
inkscape:transform-center-y="7.1498714"
inkscape:transform-center-x="-3.804363"
transform="matrix(-0.37252959,-0.2637647,0.95315141,-0.45225642,-5.3109174,97.4746)"
d="m 118.01777,83.5 a 21.589199,5.3571429 0 1 1 -43.178395,0 21.589199,5.3571429 0 1 1 43.178395,0 z"
sodipodi:ry="5.3571429"
sodipodi:rx="21.589199"
sodipodi:cy="83.5"
sodipodi:cx="96.428574"
id="path3725-5"
style="fill:url(#radialGradient4285);fill-opacity:1;fill-rule:evenodd;stroke:#120a0a;stroke-width:4.22300577000000033;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
sodipodi:type="arc" />
</g>
<path
style="fill:none;stroke:#ff0000;stroke-width:2.78663731;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="M 13.064488,29.714001 C 13.807605,23.213426 7.0460579,17.714565 14.178417,11.130255"
id="path3908"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<g
id="g3457"
transform="translate(-5.9389499,0.85958486)">
<path
style="fill:none;stroke:#ff0000;stroke-width:1.40416193;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="M 8.1193963,12.314307 14.372272,11.461474"
id="path3086"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
sodipodi:nodetypes="cc"
inkscape:connector-curvature="0"
id="path3856"
d="M 19.736155,5.6372344 19.467228,0.63586316"
style="fill:none;stroke:#ff0000;stroke-width:1.40416193;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
<path
sodipodi:nodetypes="cc"
inkscape:connector-curvature="0"
id="path3856-0"
d="M 24.79896,9.8372572 32.712828,8.6932319"
style="fill:none;stroke:#ff0000;stroke-width:1.40416193;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
<path
sodipodi:nodetypes="cc"
inkscape:connector-curvature="0"
id="path3856-4"
d="M 23.649368,6.3602312 28.463769,0.96777073"
style="fill:none;stroke:#ff0000;stroke-width:1.40416193;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
<path
style="fill:none;stroke:#ff0000;stroke-width:1.40416193;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="M 15.472346,6.7195999 9.6977995,2.8114355"
id="path3894"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#ff0000;stroke-width:1.40416193;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="M 25.398229,16.704601 22.971518,12.441529"
id="path3896"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 21 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View File

@@ -25,7 +25,7 @@
#* and some code. *
#* *
#***************************************************************************
__title__="FreeCAD OpenSCAD Workbench - CSG exporter Version 0.01c"
__title__="FreeCAD OpenSCAD Workbench - CSG exporter Version"
__author__ = "Keith Sloan <keith@sloan-home.co.uk>"
__url__ = ["http://www.sloan-home.co.uk/Export/Export.html"]
@@ -231,7 +231,7 @@ def process_object(csg,ob):
process_object(csg,subobj)
csg.write("}\n")
elif ob.TypeId == "Part::Common" :
elif ob.TypeId == "Part::MultiCommon" :
print "Multi Common / intersection"
csg.write("intersection() {\n")
for subobj in ob.Shapes:

View File

@@ -1,18 +0,0 @@
Version History
===============
0.01a - First Version
0.01b - Added support for polyhedron ( Thanks shoogen )
Some support for Torus
Some support for extruded regular polygon
0.01c - Support for extruded polygon, square, circle
bug fix for polyhydron floating point - Thanks shoogen
Thanks to shoogen and Peter Li for their advice, code, support and expertise.
Keith Sloan
keith@sloan-home.co.uk

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] :

View File

@@ -1,61 +0,0 @@
Version History
===============
0.01a - First Version
0.01b - Fixed
Reset Global Variables
Fix Multmatrix use of Shape
Added import Function (Untested)
0.02b - Rewrite to use Bojects rather than shapes.
Objects now editible in FreeCad
0.02c - disable debug output on Yacc to avoid permissions problem with Linux
0.03a - Added support for
Linear Extrusion
Rotational Extrusion
circle
square
polygon
polyhedron
0.04a - Change to use parser stack rather than own stack
to fix a parsing problem
makes code cleaner and less global variables
parsers out SCAD comments ( Not sure if the are allowed in CSG file anyway
other minor fixes
0.04b - Fixes where Multmatrix has more than one object neeed to fuse first
Correct import function call
0.04c - Support for cylinders made with regular polygon ( Needs FreeCAD with fixes to Draft )
Attempt at transformGeometry for non orthoganal Multmatrix
0.04d - Fix to multmatrix transformGeometry to avoid crash
0.04e - If problems with Draft or Draft's makePolygon because not on latest FreeCAD falls back
to non editable polygon
0.04f - Fix bug with multiple intersections
0.05a - Attempt to add shogens's import dxf function code.
0.05b - Fix introduced bug with centre=true/false, ViewObject Proxy
0.05c - Fix for polygon with path - Changes to Polygon and polyhdron - parse projection
0.05d - Fix for implicit fuse for groups
global max_polygon parameter to control cylinder or prism
There appear to be problems with some files and these maybe as a result of bugs in FreeCAD that corrupt
the model. If you find problem files please email them to keith@sloan-home.co.uk
Thanks to shoogen and Peter Li for their advice, support and expertise.
Keith Sloan
keith@sloan-home.co.uk

View File

@@ -47,6 +47,7 @@ reserved = (
'undef',
'polyhedron',
'triangles',
'faces',
'render',
'surface',
'subdiv',
@@ -59,6 +60,8 @@ reserved = (
'import',
'color',
'cut',
'offset',
'resize',
)
# List of token names. This is always required