Merge branch 'master' of ssh://free-cad.git.sourceforge.net/gitroot/free-cad/free-cad

This commit is contained in:
wmayer 2012-07-02 15:31:43 +02:00
commit b0abbcd9c3
4 changed files with 156 additions and 57 deletions

View File

@ -154,31 +154,35 @@ def splitMesh(obj,mark=True):
def makeFace(wires,method=2,cleanup=False): def makeFace(wires,method=2,cleanup=False):
'''makeFace(wires): makes a face from a list of wires, finding which ones are holes''' '''makeFace(wires): makes a face from a list of wires, finding which ones are holes'''
#print "makeFace: start"
import Part import Part
if not isinstance(wires,list): if not isinstance(wires,list):
if len(wires.Vertexes) < 3:
raise
return Part.Face(wires) return Part.Face(wires)
elif len(wires) == 1: elif len(wires) == 1:
if len(wires[0].Vertexes) < 3:
raise
return Part.Face(wires[0]) return Part.Face(wires[0])
wires = wires[:] wires = wires[:]
print "inner wires found" #print "makeFace: inner wires found"
ext = None ext = None
max_length = 0 max_length = 0
# cleaning up rubbish in wires # cleaning up rubbish in wires
if cleanup: if cleanup:
for i in range(len(wires)): for i in range(len(wires)):
wires[i] = DraftGeomUtils.removeInterVertices(wires[i]) wires[i] = DraftGeomUtils.removeInterVertices(wires[i])
print "garbage removed" #print "makeFace: garbage removed"
for w in wires: for w in wires:
# we assume that the exterior boundary is that one with # we assume that the exterior boundary is that one with
# the biggest bounding box # the biggest bounding box
if w.BoundBox.DiagonalLength > max_length: if w.BoundBox.DiagonalLength > max_length:
max_length = w.BoundBox.DiagonalLength max_length = w.BoundBox.DiagonalLength
ext = w ext = w
print "exterior wire",ext #print "makeFace: exterior wire",ext
wires.remove(ext) wires.remove(ext)
if method == 1: if method == 1:
@ -186,23 +190,22 @@ def makeFace(wires,method=2,cleanup=False):
# all interior wires mark a hole and must reverse # all interior wires mark a hole and must reverse
# their orientation, otherwise Part.Face fails # their orientation, otherwise Part.Face fails
for w in wires: for w in wires:
print "reversing",w #print "makeFace: reversing",w
w.reverse() w.reverse()
print "reversed"
# make sure that the exterior wires comes as first in the list # make sure that the exterior wires comes as first in the list
wires.insert(0, ext) wires.insert(0, ext)
print "done sorting", wires #print "makeFace: done sorting", wires
if wires: if wires:
return Part.Face(wires) return Part.Face(wires)
else: else:
# method 2: use the cut method # method 2: use the cut method
mf = Part.Face(ext) mf = Part.Face(ext)
print "external face:",mf #print "makeFace: external face:",mf
for w in wires: for w in wires:
f = Part.Face(w) f = Part.Face(w)
print "internal face:",f #print "makeFace: internal face:",f
mf = mf.cut(f) mf = mf.cut(f)
print "final face:",mf.Faces #print "makeFace: final face:",mf.Faces
return mf.Faces[0] return mf.Faces[0]
def meshToShape(obj,mark=True): def meshToShape(obj,mark=True):

View File

@ -215,7 +215,7 @@ class _ArchDrawingView:
import ArchVRM import ArchVRM
render = ArchVRM.Renderer() render = ArchVRM.Renderer()
render.setWorkingPlane(obj.Source.Placement) render.setWorkingPlane(obj.Source.Placement)
render.addObjects(objs) render.addObjects(Draft.getGroupContents(objs))
render.cut(obj.Source.Shape) render.cut(obj.Source.Shape)
svg += render.getViewSVG(linewidth=linewidth) svg += render.getViewSVG(linewidth=linewidth)
svg += render.getSectionSVG(linewidth=linewidth*2) svg += render.getSectionSVG(linewidth=linewidth*2)

View File

@ -145,12 +145,14 @@ class Renderer:
def reorient(self): def reorient(self):
"reorients the faces on the WP" "reorients the faces on the WP"
#print "VRM: start reorient"
if not self.faces: if not self.faces:
return return
self.faces = [self.projectFace(f) for f in self.faces] self.faces = [self.projectFace(f) for f in self.faces]
if self.sections: if self.sections:
self.sections = [self.projectFace(f) for f in self.sections] self.sections = [self.projectFace(f) for f in self.sections]
self.oriented = True self.oriented = True
#print "VRM: end reorient"
def removeHidden(self): def removeHidden(self):
"removes faces pointing outwards" "removes faces pointing outwards"
@ -166,7 +168,11 @@ class Renderer:
def projectFace(self,face): def projectFace(self,face):
"projects a single face on the WP" "projects a single face on the WP"
#print "VRM: projectFace start"
wires = [] wires = []
if not face[0].Wires:
if DEBUG: print "Error: Unable to project face on the WP"
return None
norm = face[0].normalAt(0,0) norm = face[0].normalAt(0,0)
for w in face[0].Wires: for w in face[0].Wires:
verts = [] verts = []
@ -177,7 +183,9 @@ class Renderer:
verts.append(v) verts.append(v)
verts.append(verts[0]) verts.append(verts[0])
if len(verts) > 2: if len(verts) > 2:
print verts
wires.append(Part.makePolygon(verts)) wires.append(Part.makePolygon(verts))
print "wires:",wires
try: try:
sh = ArchCommands.makeFace(wires) sh = ArchCommands.makeFace(wires)
except: except:
@ -188,6 +196,7 @@ class Renderer:
vnorm = self.wp.getLocalCoords(norm) vnorm = self.wp.getLocalCoords(norm)
if vnorm.getAngle(sh.normalAt(0,0)) > 1: if vnorm.getAngle(sh.normalAt(0,0)) > 1:
sh.reverse() sh.reverse()
#print "VRM: projectFace end"
return [sh]+face[1:] return [sh]+face[1:]
def flattenFace(self,face): def flattenFace(self,face):
@ -211,6 +220,7 @@ class Renderer:
def cut(self,cutplane): def cut(self,cutplane):
"Cuts through the shapes with a given cut plane and builds section faces" "Cuts through the shapes with a given cut plane and builds section faces"
if DEBUG: print "\n\n======> Starting cut\n\n"
if self.iscut: if self.iscut:
return return
if not self.shapes: if not self.shapes:
@ -277,6 +287,7 @@ class Renderer:
self.trimmed = False self.trimmed = False
self.sorted = False self.sorted = False
self.joined = False self.joined = False
if DEBUG: print "\n\n======> Finished cut\n\n"
def isInside(self,vert,face): def isInside(self,vert,face):
"Returns True if the vert is inside the face in Z projection" "Returns True if the vert is inside the face in Z projection"
@ -319,6 +330,15 @@ class Renderer:
def compare(self,face1,face2): def compare(self,face1,face2):
"zsorts two faces. Returns 1 if face1 is closer, 2 if face2 is closer, 0 otherwise" "zsorts two faces. Returns 1 if face1 is closer, 2 if face2 is closer, 0 otherwise"
#print face1,face2
if not face1:
if DEBUG: print "Warning, undefined face!"
return 31
elif not face2:
if DEBUG: print "Warning, undefined face!"
return 32
# theory from # theory from
# http://www.siggraph.org/education/materials/HyperGraph/scanline/visibility/painter.htm # http://www.siggraph.org/education/materials/HyperGraph/scanline/visibility/painter.htm
# and practical application http://vrm.ao2.it/ (blender vector renderer) # and practical application http://vrm.ao2.it/ (blender vector renderer)
@ -456,14 +476,17 @@ class Renderer:
def sort(self): def sort(self):
"projects a shape on the WP" "projects a shape on the WP"
if DEBUG: print "\n\n======> Starting sort\n\n"
if len(self.faces) <= 1: if len(self.faces) <= 1:
return return
if not self.trimmed: if not self.trimmed:
self.removeHidden() self.removeHidden()
if DEBUG: print "Done hidden face removal"
if len(self.faces) == 1: if len(self.faces) == 1:
return return
if not self.oriented: if not self.oriented:
self.reorient() self.reorient()
if DEBUG: print "Done reorientation"
faces = self.faces[:] faces = self.faces[:]
if DEBUG: print "sorting ",len(self.faces)," faces" if DEBUG: print "sorting ",len(self.faces)," faces"
sfaces = [] sfaces = []
@ -492,6 +515,7 @@ class Renderer:
for f2 in faces[1:]: for f2 in faces[1:]:
if DEBUG: print "comparing face",str(self.faces.index(f1))," with face",str(self.faces.index(f2)) if DEBUG: print "comparing face",str(self.faces.index(f1))," with face",str(self.faces.index(f2))
r = self.compare(f1,f2) r = self.compare(f1,f2)
print "comparison result:",r
if r == 1: if r == 1:
faces.remove(f2) faces.remove(f2)
sfaces.append(f2) sfaces.append(f2)
@ -506,6 +530,10 @@ class Renderer:
sfaces.append(f2) sfaces.append(f2)
notfoundstack = 0 notfoundstack = 0
break break
elif r == 31:
faces.remove(f1)
elif r == 32:
faces.remove(f2)
else: else:
# nothing found, move the face to the end of the pile # nothing found, move the face to the end of the pile
faces.remove(f1) faces.remove(f1)
@ -518,6 +546,7 @@ class Renderer:
if DEBUG: print "done Z sorting. ", len(sfaces), " faces retained, ", len(self.faces)-len(sfaces), " faces lost." if DEBUG: print "done Z sorting. ", len(sfaces), " faces retained, ", len(self.faces)-len(sfaces), " faces lost."
self.faces = sfaces self.faces = sfaces
self.sorted = True self.sorted = True
if DEBUG: print "\n\n======> Finished sort\n\n"
def buildDummy(self): def buildDummy(self):
"Builds a dummy object with faces spaced on the Z axis, for visual check" "Builds a dummy object with faces spaced on the Z axis, for visual check"
@ -566,21 +595,22 @@ class Renderer:
self.sort() self.sort()
svg = '' svg = ''
for f in self.faces: for f in self.faces:
fill = self.getFill(f[1]) if f:
svg +='<path ' fill = self.getFill(f[1])
svg += 'd="' svg +='<path '
for w in f[0].Wires: svg += 'd="'
svg += self.getPathData(w) for w in f[0].Wires:
svg += '" ' svg += self.getPathData(w)
svg += 'stroke="#000000" ' svg += '" '
svg += 'stroke-width="' + str(linewidth) + '" ' svg += 'stroke="#000000" '
svg += 'style="stroke-width:' + str(linewidth) + ';' svg += 'stroke-width="' + str(linewidth) + '" '
svg += 'stroke-miterlimit:1;' svg += 'style="stroke-width:' + str(linewidth) + ';'
svg += 'stroke-linejoin:round;' svg += 'stroke-miterlimit:1;'
svg += 'stroke-dasharray:none;' svg += 'stroke-linejoin:round;'
svg += 'fill:' + fill + ';' svg += 'stroke-dasharray:none;'
svg += 'fill-rule: evenodd' svg += 'fill:' + fill + ';'
svg += '"/>\n' svg += 'fill-rule: evenodd'
svg += '"/>\n'
return svg return svg
def getSectionSVG(self,linewidth=0.02): def getSectionSVG(self,linewidth=0.02):
@ -590,20 +620,21 @@ class Renderer:
self.reorient() self.reorient()
svg = '' svg = ''
for f in self.sections: for f in self.sections:
fill = self.getFill(f[1]) if f:
svg +='<path ' fill = self.getFill(f[1])
svg += 'd="' svg +='<path '
for w in f[0].Wires: svg += 'd="'
svg += self.getPathData(w) for w in f[0].Wires:
svg += '" ' svg += self.getPathData(w)
svg += 'stroke="#000000" ' svg += '" '
svg += 'stroke-width="' + str(linewidth) + '" ' svg += 'stroke="#000000" '
svg += 'style="stroke-width:' + str(linewidth) + ';' svg += 'stroke-width="' + str(linewidth) + '" '
svg += 'stroke-miterlimit:1;' svg += 'style="stroke-width:' + str(linewidth) + ';'
svg += 'stroke-linejoin:round;' svg += 'stroke-miterlimit:1;'
svg += 'stroke-dasharray:none;' svg += 'stroke-linejoin:round;'
svg += 'fill:' + fill + ';' svg += 'stroke-dasharray:none;'
svg += 'fill-rule: evenodd' svg += 'fill:' + fill + ';'
svg += '"/>\n' svg += 'fill-rule: evenodd'
svg += '"/>\n'
return svg return svg

View File

@ -253,17 +253,43 @@ def shapify(obj):
FreeCAD.ActiveDocument.recompute() FreeCAD.ActiveDocument.recompute()
return newobj return newobj
def getGroupContents(objectslist): def getGroupContents(objectslist,walls=False):
'''getGroupContents(objectlist): if any object of the given list '''getGroupContents(objectlist): if any object of the given list
is a group, its content is appened to the list, which is returned''' is a group, its content is appened to the list, which is returned'''
newlist = [] newlist = []
for obj in objectslist: for obj in objectslist:
if obj.Type == "App::DocumentObjectGroup": if obj.isDerivedFrom("App::DocumentObjectGroup"):
newlist.extend(getGroupContents(obj.Group)) newlist.extend(getGroupContents(obj.Group))
else: else:
newlist.append(obj) newlist.append(obj)
if walls:
if getType(obj) == "Wall":
for o in obj.OutList:
if (getType(o) == "Window") or isClone(o,"Window"):
newlist.append(o)
return newlist return newlist
def printShape(shape):
"""prints detailed information of a shape"""
print "solids: ", len(shape.Solids)
print "faces: ", len(shape.Faces)
print "wires: ", len(shape.Wires)
print "edges: ", len(shape.Edges)
print "verts: ", len(shape.Vertexes)
if shape.Faces:
for f in range(len(shape.Faces)):
print "face ",f,":"
for v in shape.Faces[f].Vertexes:
print " ",v.Point
elif shape.Wires:
for w in range(len(shape.Wires)):
print "wire ",w,":"
for v in shape.Wires[w].Vertexes:
print " ",v.Point
else:
for v in shape.Vertexes:
print " ",v.Point
def formatObject(target,origin=None): def formatObject(target,origin=None):
''' '''
formatObject(targetObject,[originObject]): This function applies formatObject(targetObject,[originObject]): This function applies
@ -1945,7 +1971,7 @@ class _ViewProviderDimension:
[p2.x,p2.y,p2.z], [p2.x,p2.y,p2.z],
[p3.x,p3.y,p3.z], [p3.x,p3.y,p3.z],
[p4.x,p4.y,p4.z]]) [p4.x,p4.y,p4.z]])
self.line.numVertices.setValues([4]) self.line.numVertices.setValue(4)
else: else:
ts = (len(text)*obj.ViewObject.FontSize)/4 ts = (len(text)*obj.ViewObject.FontSize)/4
rm = ((p3.sub(p2)).Length/2)-ts rm = ((p3.sub(p2)).Length/2)-ts
@ -2714,29 +2740,35 @@ class _Array:
obj.addProperty("App::PropertyEnumeration","ArrayType","Base", obj.addProperty("App::PropertyEnumeration","ArrayType","Base",
"The type of array to create") "The type of array to create")
obj.addProperty("App::PropertyVector","Axis","Base", obj.addProperty("App::PropertyVector","Axis","Base",
"The axis direction for polar arrays") "The axis direction")
obj.addProperty("App::PropertyInteger","NumberX","Base", obj.addProperty("App::PropertyInteger","NumberX","Base",
"Number of copies in X direction (ortho arrays)") "Number of copies in X direction")
obj.addProperty("App::PropertyInteger","NumberY","Base", obj.addProperty("App::PropertyInteger","NumberY","Base",
"Number of copies in Y direction (ortho arrays)") "Number of copies in Y direction")
obj.addProperty("App::PropertyInteger","NumberZ","Base",
"Number of copies in Z direction")
obj.addProperty("App::PropertyInteger","NumberPolar","Base", obj.addProperty("App::PropertyInteger","NumberPolar","Base",
"Number of copies (polar arrays)") "Number of copies")
obj.addProperty("App::PropertyVector","IntervalX","Base", obj.addProperty("App::PropertyVector","IntervalX","Base",
"Distance and orientation of intervals in X direction (ortho arrays)") "Distance and orientation of intervals in X direction")
obj.addProperty("App::PropertyVector","IntervalY","Base", obj.addProperty("App::PropertyVector","IntervalY","Base",
"Distance and orientation of intervals in Y direction (ortho arrays)") "Distance and orientation of intervals in Y direction")
obj.addProperty("App::PropertyVector","IntervalZ","Base",
"Distance and orientation of intervals in Z direction")
obj.addProperty("App::PropertyVector","Center","Base", obj.addProperty("App::PropertyVector","Center","Base",
"Center point (polar arrays)") "Center point")
obj.addProperty("App::PropertyAngle","Angle","Base", obj.addProperty("App::PropertyAngle","Angle","Base",
"Angle to cover with copies (polar arrays)") "Angle to cover with copies")
obj.Proxy = self obj.Proxy = self
self.Type = "Array" self.Type = "Array"
obj.ArrayType = ['ortho','polar'] obj.ArrayType = ['ortho','polar']
obj.NumberX = 1 obj.NumberX = 1
obj.NumberY = 1 obj.NumberY = 1
obj.NumberZ = 1
obj.NumberPolar = 1 obj.NumberPolar = 1
obj.IntervalX = Vector(1,0,0) obj.IntervalX = Vector(1,0,0)
obj.IntervalY = Vector(0,1,0) obj.IntervalY = Vector(0,1,0)
obj.IntervalZ = Vector(0,0,1)
obj.Angle = 360 obj.Angle = 360
obj.Axis = Vector(0,0,1) obj.Axis = Vector(0,0,1)
@ -2744,7 +2776,32 @@ class _Array:
self.createGeometry(obj) self.createGeometry(obj)
def onChanged(self,obj,prop): def onChanged(self,obj,prop):
if prop in ["ArrayType","NumberX","NumberY","NumberPolar","IntervalX","IntervalY","Angle","Center","Axis"]: if prop == "ArrayType":
if obj.ViewObject:
if obj.ArrayType == "ortho":
obj.ViewObject.setEditorMode('Axis',2)
obj.ViewObject.setEditorMode('NumberPolar',2)
obj.ViewObject.setEditorMode('Center',2)
obj.ViewObject.setEditorMode('Angle',2)
obj.ViewObject.setEditorMode('NumberX',0)
obj.ViewObject.setEditorMode('NumberY',0)
obj.ViewObject.setEditorMode('NumberZ',0)
obj.ViewObject.setEditorMode('IntervalX',0)
obj.ViewObject.setEditorMode('IntervalY',0)
obj.ViewObject.setEditorMode('IntervalZ',0)
else:
obj.ViewObject.setEditorMode('Axis',0)
obj.ViewObject.setEditorMode('NumberPolar',0)
obj.ViewObject.setEditorMode('Center',0)
obj.ViewObject.setEditorMode('Angle',0)
obj.ViewObject.setEditorMode('NumberX',2)
obj.ViewObject.setEditorMode('NumberY',2)
obj.ViewObject.setEditorMode('NumberY',2)
obj.ViewObject.setEditorMode('IntervalX',2)
obj.ViewObject.setEditorMode('IntervalY',2)
obj.ViewObject.setEditorMode('IntervalZ',2)
if prop in ["ArrayType","NumberX","NumberY","NumberZ","NumberPolar",
"IntervalX","IntervalY","IntervalZ","Angle","Center","Axis"]:
self.createGeometry(obj) self.createGeometry(obj)
def createGeometry(self,obj): def createGeometry(self,obj):
@ -2752,14 +2809,15 @@ class _Array:
if obj.Base: if obj.Base:
pl = obj.Placement pl = obj.Placement
if obj.ArrayType == "ortho": if obj.ArrayType == "ortho":
sh = self.rectArray(obj.Base.Shape,obj.IntervalX,obj.IntervalY,obj.NumberX,obj.NumberY) sh = self.rectArray(obj.Base.Shape,obj.IntervalX,obj.IntervalY,
obj.IntervalZ,obj.NumberX,obj.NumberY,obj.NumberZ)
else: else:
sh = self.polarArray(obj.Base.Shape,obj.Center,obj.Angle,obj.NumberPolar,obj.Axis) sh = self.polarArray(obj.Base.Shape,obj.Center,obj.Angle,obj.NumberPolar,obj.Axis)
obj.Shape = sh obj.Shape = sh
if not DraftGeomUtils.isNull(pl): if not DraftGeomUtils.isNull(pl):
obj.Placement = pl obj.Placement = pl
def rectArray(self,shape,xvector,yvector,xnum,ynum): def rectArray(self,shape,xvector,yvector,zvector,xnum,ynum,znum):
import Part import Part
base = [shape.copy()] base = [shape.copy()]
for xcount in range(xnum): for xcount in range(xnum):
@ -2769,12 +2827,19 @@ class _Array:
nshape.translate(currentxvector) nshape.translate(currentxvector)
base.append(nshape) base.append(nshape)
for ycount in range(ynum): for ycount in range(ynum):
currentxvector=FreeCAD.Vector(currentxvector) currentyvector=FreeCAD.Vector(currentxvector)
currentyvector=currentxvector.add(DraftVecUtils.scale(yvector,ycount)) currentyvector=currentyvector.add(DraftVecUtils.scale(yvector,ycount))
if not ycount==0: if not ycount==0:
nshape = shape.copy() nshape = shape.copy()
nshape.translate(currentyvector) nshape.translate(currentyvector)
base.append(nshape) base.append(nshape)
for zcount in range(znum):
currentzvector=FreeCAD.Vector(currentyvector)
currentzvector=currentzvector.add(DraftVecUtils.scale(zvector,zcount))
if not zcount==0:
nshape = shape.copy()
nshape.translate(currentzvector)
base.append(nshape)
return Part.makeCompound(base) return Part.makeCompound(base)
def polarArray(self,shape,center,angle,num,axis): def polarArray(self,shape,center,angle,num,axis):