diff --git a/src/Mod/Arch/ArchCommands.py b/src/Mod/Arch/ArchCommands.py index 83b84d620..342e0f1f9 100644 --- a/src/Mod/Arch/ArchCommands.py +++ b/src/Mod/Arch/ArchCommands.py @@ -146,6 +146,59 @@ def splitMesh(obj,mark=True): return nlist return [obj] +def makeFace(wires,method=2,cleanup=False): + '''makeFace(wires): makes a face from a list of wires, finding which ones are holes''' + + import Part + + if not isinstance(wires,list): + return Part.Face(wires) + elif len(wires) == 1: + return Part.Face(wires[0]) + + wires = wires[:] + + print "inner wires found" + ext = None + max_length = 0 + # cleaning up rubbish in wires + if cleanup: + for i in range(len(wires)): + wires[i] = fcgeo.removeInterVertices(wires[i]) + print "garbage removed" + for w in wires: + # we assume that the exterior boundary is that one with + # the biggest bounding box + if w.BoundBox.DiagonalLength > max_length: + max_length = w.BoundBox.DiagonalLength + ext = w + print "exterior wire",ext + wires.remove(ext) + + if method == 1: + # method 1: reverse inner wires + # all interior wires mark a hole and must reverse + # their orientation, otherwise Part.Face fails + for w in wires: + print "reversing",w + w.reverse() + print "reversed" + # make sure that the exterior wires comes as first in the list + wires.insert(0, ext) + print "done sorting", wires + if wires: + return Part.Face(wires) + else: + # method 2: use the cut method + mf = Part.Face(ext) + print "external face:",mf + for w in wires: + f = Part.Face(w) + print "internal face:",f + mf = mf.cut(f) + print "final face:",mf.Faces + return mf.Faces[0] + def meshToShape(obj,mark=True): '''meshToShape(object,[mark]): turns a mesh into a shape, joining coplanar facets. If mark is True (default), non-solid objects will be marked in red''' @@ -165,33 +218,8 @@ def meshToShape(obj,mark=True): wires = MeshPart.wireFromSegment(mesh, i) print "wire done" print wires - if len(wires) > 1: - # a segment can have inner holes - print "inner wires found" - ext = None - max_length = 0 - # cleaning up rubbish in wires - for i in range(len(wires)): - wires[i] = fcgeo.removeInterVertices(wires[i]) - for w in wires: - # we assume that the exterior boundary is that one with - # the biggest bounding box - if w.BoundBox.DiagonalLength > max_length: - max_length = w.BoundBox.DiagonalLength - ext = w - print "exterior wire",ext - wires.remove(ext) - # all interior wires mark a hole and must reverse - # their orientation, otherwise Part.Face fails - for w in wires: - print "reversing",w - #w.reverse() - print "reversed" - # make sure that the exterior wires comes as first in the list - wires.insert(0, ext) - print "done sorting", wires if wires: - faces.append(Part.Face(wires)) + faces.append(makeFace(wires)) print "done facing" print "faces",faces diff --git a/src/Mod/Arch/ArchVRM.py b/src/Mod/Arch/ArchVRM.py index 40c4da63c..ef7b0892b 100644 --- a/src/Mod/Arch/ArchVRM.py +++ b/src/Mod/Arch/ArchVRM.py @@ -23,7 +23,7 @@ "The FreeCAD Arch Vector Rendering Module" -import FreeCAD,math,Part +import FreeCAD,math,Part,ArchCommands from draftlibs import fcvec,fcgeo DEBUG = True # if we want debug messages @@ -137,17 +137,19 @@ class Renderer: def projectFace(self,face): "projects a single face on the WP" - verts = [] - edges = fcgeo.sortEdges(face.Edges) + wires = [] norm = face.normalAt(0,0) - for e in edges: - v = e.Vertexes[0].Point - v = self.wp.getLocalCoords(v) - verts.append(v) - verts.append(verts[0]) + for w in face.Wires: + verts = [] + edges = fcgeo.sortEdges(w.Edges) + for e in edges: + v = e.Vertexes[0].Point + v = self.wp.getLocalCoords(v) + verts.append(v) + verts.append(verts[0]) + wires.append(Part.makePolygon(verts)) try: - sh = Part.makePolygon(verts) - sh = Part.Face(sh) + sh = ArchCommands.makeFace(wires) except: if DEBUG: print "Error: Unable to project face on the WP" return None @@ -160,15 +162,17 @@ class Renderer: def flattenFace(self,face): "Returns a face where all vertices have Z = 0" - verts = [] - edges = fcgeo.sortEdges(face.Edges) - for e in edges: - v = e.Vertexes[0].Point - verts.append(FreeCAD.Vector(v.x,v.y,0)) - verts.append(verts[0]) + wires = [] + for w in face.Wires: + verts = [] + edges = fcgeo.sortEdges(w.Edges) + for e in edges: + v = e.Vertexes[0].Point + verts.append(FreeCAD.Vector(v.x,v.y,0)) + verts.append(verts[0]) + wires.append(Part.makePolygon(verts)) try: - sh = Part.makePolygon(verts) - sh = Part.Face(sh) + sh = Part.Face(wires) except: if DEBUG: print "Error: Unable to flatten face" return None @@ -394,24 +398,29 @@ class Renderer: svg = '' for f in self.faces: svg +='