Arch vector renderer now supports faces with holes
This commit is contained in:
parent
e3a648ea03
commit
300cd877b6
|
@ -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
|
||||
|
||||
|
|
|
@ -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 +='<path '
|
||||
edges = fcgeo.sortEdges(f.Edges)
|
||||
v = edges[0].Vertexes[0].Point
|
||||
svg += 'd="M '+ str(v.x) +' '+ str(v.y) + ' '
|
||||
for e in edges:
|
||||
if isinstance(e.Curve,Part.Line) or isinstance(e.Curve,Part.BSplineCurve):
|
||||
v = e.Vertexes[-1].Point
|
||||
svg += 'L '+ str(v.x) +' '+ str(v.y) + ' '
|
||||
elif isinstance(e.Curve,Part.Circle):
|
||||
r = e.Curve.Radius
|
||||
v = e.Vertexes[-1].Point
|
||||
svg += 'A '+ str(r) + ' '+ str(r) +' 0 0 1 '+ str(v.x) +' '
|
||||
svg += str(v.y) + ' '
|
||||
svg += 'd="'
|
||||
for w in f.Wires:
|
||||
edges = fcgeo.sortEdges(w.Edges)
|
||||
v = edges[0].Vertexes[0].Point
|
||||
svg += 'M '+ str(v.x) +' '+ str(v.y) + ' '
|
||||
for e in edges:
|
||||
if isinstance(e.Curve,Part.Line) or isinstance(e.Curve,Part.BSplineCurve):
|
||||
v = e.Vertexes[-1].Point
|
||||
svg += 'L '+ str(v.x) +' '+ str(v.y) + ' '
|
||||
elif isinstance(e.Curve,Part.Circle):
|
||||
r = e.Curve.Radius
|
||||
v = e.Vertexes[-1].Point
|
||||
svg += 'A '+ str(r) + ' '+ str(r) +' 0 0 1 '+ str(v.x) +' '
|
||||
svg += str(v.y) + ' '
|
||||
svg += 'z '
|
||||
svg += '" '
|
||||
svg += 'stroke="#000000" '
|
||||
svg += 'stroke-width="0.01 px" '
|
||||
svg += 'style="stroke-width:0.01;'
|
||||
svg += 'stroke-miterlimit:1;'
|
||||
svg += 'stroke-linejoin:round;'
|
||||
svg += 'stroke-dasharray:none;'
|
||||
svg += 'fill:#aaaaaa"'
|
||||
svg += '/>\n'
|
||||
svg += 'fill:#aaaaaa;'
|
||||
svg += 'fill-rule: evenodd'
|
||||
svg += '"/>\n'
|
||||
return svg
|
||||
|
|
Loading…
Reference in New Issue
Block a user