Big cleanup in Arch vector renderer

This commit is contained in:
Yorik van Havre 2012-04-26 21:05:18 -03:00
parent 724e40627e
commit 857d9c00ad
5 changed files with 304 additions and 314 deletions

View File

@ -205,51 +205,6 @@ def makeFace(wires,method=2,cleanup=False):
print "final face:",mf.Faces
return mf.Faces[0]
def getCutVolume(objects,placement):
'''getCutVolume(objects,placement): returns a tuple with 2 objects: a face, positioned
at the given placement's position, and wide enough so the projection of all objects
in the list fits into it, and an extrusion vector, that can be used to extrude the
plane so it includes all objects in the list.'''
import Part
placement = FreeCAD.Placement(placement)
if not objects:
return None
bb = objects[0].Shape.BoundBox
for obj in objects[1:]:
bb.add(obj.Shape.BoundBox)
bb.enlarge(1)
u = placement.Rotation.multVec(FreeCAD.Vector(1,0,0))
v = placement.Rotation.multVec(FreeCAD.Vector(0,1,0))
w = placement.Rotation.multVec(FreeCAD.Vector(0,0,1))
um = vm = wm = 0
if not bb.isCutPlane(placement.Base,w):
return None
corners = [FreeCAD.Vector(bb.XMin,bb.YMin,bb.ZMin),
FreeCAD.Vector(bb.XMin,bb.YMax,bb.ZMin),
FreeCAD.Vector(bb.XMax,bb.YMin,bb.ZMin),
FreeCAD.Vector(bb.XMax,bb.YMax,bb.ZMin),
FreeCAD.Vector(bb.XMin,bb.YMin,bb.ZMax),
FreeCAD.Vector(bb.XMin,bb.YMax,bb.ZMax),
FreeCAD.Vector(bb.XMax,bb.YMin,bb.ZMax),
FreeCAD.Vector(bb.XMax,bb.YMax,bb.ZMax)]
for c in corners:
dv = c.sub(placement.Base)
um1 = fcvec.project(dv,u).Length
um = max(um,um1)
vm1 = fcvec.project(dv,v).Length
vm = max(vm,vm1)
wm1 = fcvec.project(dv,w).Length
wm = max(wm,wm1)
p1 = FreeCAD.Vector(-um,vm,0)
p2 = FreeCAD.Vector(um,vm,0)
p3 = FreeCAD.Vector(um,-vm,0)
p4 = FreeCAD.Vector(-um,-vm,0)
f = Part.makePolygon([p1,p2,p3,p4,p1])
f = Part.Face(f)
f.Placement = placement
n = fcvec.scaleTo(w,wm)
return (f,n)
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'''

View File

@ -181,77 +181,34 @@ class _ArchDrawingView:
if obj.Source.Objects:
svg = ''
# getting section plane
cp = ArchCommands.getCutVolume(obj.Source.Objects,obj.Source.Placement)
self.sections = []
if cp:
cutvolume = cp[0].extrude(cp[1])
shapes = []
colors = []
# sorting
if join:
walls = []
structs = []
objs = []
for o in obj.Source.Objects:
t = Draft.getType(o)
if t == "Wall":
walls.append(o)
elif t == "Structure":
structs.append(o)
else:
objs.append(o)
for g in [walls,structs]:
if g:
print "group:",g
col = g[0].ViewObject.DiffuseColor[0]
s = g[0].Shape
for o in g[1:]:
try:
fs = s.fuse(o.Shape)
fs = fs.removeSplitter()
except:
print "shape fusion failed"
objs.append([o.Shape,o.ViewObject.DiffuseColor[0]])
else:
s = fs
objs.append([s,col])
else:
objs = obj.Source.Objects
# shapes extraction
for o in objs:
print "object:",o
if isinstance(o,list):
shape = o[0]
color = o[1]
else:
shape = o.Shape
color = o.ViewObject.DiffuseColor[0]
if cp:
for s in shape.Solids:
shapes.append(s.cut(cutvolume))
colors.append(color)
sec = shape.section(cp[0])
if sec.Edges:
wires = fcgeo.findWires(sec.Edges)
for w in wires:
sec = Part.Wire(fcgeo.sortEdges(w.Edges))
sec = Part.Face(sec)
self.sections.append(sec)
else:
shapes.append(shape)
colors.append(color)
# generating SVG
linewidth = obj.LineWidth/obj.Scale
if obj.RenderingMode == "Solid":
svg += self.renderVRM(shapes,obj.Source.Placement,colors,linewidth)
# render using the Arch Vector Renderer
import ArchVRM
render = ArchVRM.Renderer()
render.setWorkingPlane(obj.Source.Placement)
render.addObjects(obj.Source.Objects)
render.cut(obj.Source.Shape)
svg += render.getViewSVG(linewidth=linewidth)
svg += render.getSectionSVG(linewidth=linewidth*2)
# print render.info()
else:
svg += self.renderOCC(shapes,obj.Source.Proxy.getNormal(obj.Source),linewidth)
for s in self.sections:
svg += self.renderSection(s,obj.Source.Placement,linewidth*2)
# render using the Drawing module
shapes = []
for o in obj.Source.Objects:
if o.isDerivedFrom("Part::Feature"):
shapes.append(o.Shape)
if shapes:
base = shape.pop()
for sh in shapes:
base = base.fuse(sh)
svgf = Drawing.projectToSVG(base,fcvec.neg(direction))
if svgf:
svgf = svgf.replace('stroke-width="0.35"','stroke-width="' + str(linewidth) + 'px"')
svg += svgf
result = ''
result += '<g id="' + obj.Name + '"'
result += ' transform="'
@ -261,72 +218,8 @@ class _ArchDrawingView:
result += '">\n'
result += svg
result += '</g>\n'
#print "complete node:",result
# print "complete node:",result
return result
return ''
def renderOCC(self,shapes,direction,linewidth):
"renders an SVG fragment with the OCC method"
shapes = shapes[:]
if shapes:
base = shape.pop()
for sh in shapes:
base = base.fuse(sh)
result = Drawing.projectToSVG(base,fcvec.neg(direction))
if result:
result = result.replace('stroke-width="0.35"','stroke-width="' + str(linewidth) + 'px"')
return result
return ''
def renderVRM(self,shapes,placement,colors,linewidth):
"renders an SVG fragment with the ArchVRM method"
import ArchVRM
render = ArchVRM.Renderer()
render.setWorkingPlane(FreeCAD.Placement(placement))
for i in range(len(shapes)):
if colors:
render.add(shapes[i],colors[i])
else:
render.add(shapes[i])
svg = render.getSVG(linewidth=linewidth)
#print render.info()
return svg
def renderSection(self,shape,placement,linewidth):
"renders a plane parallel to the section plane"
placement = FreeCAD.Placement(placement)
u = placement.Rotation.multVec(FreeCAD.Vector(1,0,0))
v = placement.Rotation.multVec(FreeCAD.Vector(0,1,0))
pts = []
for vt in shape.Vertexes:
vu = fcvec.project(vt.Point,u)
if vu.getAngle(u) > 1:
x = -vu.Length
else:
x = vu.Length
vv = fcvec.project(vt.Point,v)
if vv.getAngle(v) > 1:
y = -vv.Length
else:
y = vv.Length
pts.append([x,y])
svg ='<path '
svg += 'd="M '+ str(pts[0][0]) +' '+ str(pts[0][1]) + ' '
for p in pts[1:]:
svg += 'L '+ str(p[0]) +' '+ str(p[1]) + ' '
svg += 'z '
svg += '" '
svg += 'stroke="#000000" '
svg += 'stroke-width="' + str(linewidth) + 'px" '
svg += 'style="stroke-width:' + str(linewidth) + ';'
svg += 'stroke-miterlimit:1;'
svg += 'stroke-linejoin:round;'
svg += 'stroke-dasharray:none;'
svg += 'fill:#ffffff;'
svg += 'fill-rule: evenodd'
svg += '"/>\n'
return svg
FreeCADGui.addCommand('Arch_SectionPlane',_CommandSectionPlane())

View File

@ -29,6 +29,9 @@ from draftlibs import fcvec,fcgeo
DEBUG = True # if we want debug messages
MAXLOOP = 10 # the max number of loop before abort
# WARNING: in this module, faces are lists whose first item is the actual OCC face, the
# other items being additional information such as color, etc.
class Renderer:
"A renderer object"
def __init__(self,wp=None):
@ -43,22 +46,35 @@ class Renderer:
p.sort()
p.buildDummy()
"""
self.defaultFill = (0.9,0.9,0.9,1.0) # the default fill color
self.wp = wp
self.faces = []
self.fills = []
self.oriented = False
self.trimmed = False
self.sorted = False
if not self.wp:
self.reset()
if wp:
self.wp = wp
else:
import WorkingPlane
self.wp = WorkingPlane.plane()
if DEBUG: print "Renderer initialized on " + str(self.wp)
def __str__(self):
return "Arch Renderer: " + str(len(self.faces)) + " faces projected on " + str(self.wp)
def reset(self):
"removes all faces from this renderer"
self.objects = []
self.shapes = []
self.faces = []
self.resetFlags()
def resetFlags(self):
"resets all flags of this renderer"
self.oriented = False
self.trimmed = False
self.sorted = False
self.iscut = False
self.joined = False
self.sections = []
def setWorkingPlane(self,wp):
"sets a Draft WorkingPlane or Placement for this renderer"
if isinstance(wp,FreeCAD.Placement):
@ -67,52 +83,35 @@ class Renderer:
self.wp = wp
if DEBUG: print "Renderer set on " + str(self.wp)
def add(self,faces,colors=None):
"add faces, shape or object to this renderer, optionally with face colors"
def addFaces(self,faces,color=(0.9,0.9,0.9,1.0)):
"add individual faces to this renderer, optionally with a color"
if DEBUG: print "adding ", len(faces), " faces. Warning, these will get lost if using cut() or join()"
for f in faces:
self.faces.append([f,color])
self.resetFlags()
def setcolors(colors,n):
if colors:
if isinstance(colors,tuple) and len(colors) == 4:
for i in range(n):
self.fills.append(colors)
elif len(colors) == n:
self.fills.extend(colors)
else:
c = []
for i in range(n):
c.append(colors[0])
self.fills.extend(c)
else:
c = []
for i in range(n):
c.append(self.defaultFill)
self.fills.extend(c)
if isinstance(faces,list):
f = faces
setcolors(colors,len(f))
elif hasattr(faces,"Faces"):
f = faces.Faces
setcolors(colors,len(f))
elif hasattr(faces,"Shape"):
f = faces.Shape.Faces
if hasattr(faces,"ViewObject") and not colors:
colors = faces.ViewObject.DiffuseColor
setcolors(colors,len(f))
if DEBUG: print "adding ", len(f), " faces"
self.faces.extend(f)
self.oriented = False
self.trimmed = False
self.sorted = False
def clean(self):
"removes all faces from this renderer"
self.faces = []
self.fills = []
self.oriented = False
self.trimmed = False
self.sorted = False
def addObjects(self,objs):
"add objects to this renderer"
for o in objs:
if o.isDerivedFrom("Part::Feature"):
self.objects.append(o)
color = o.ViewObject.ShapeColor
if o.Shape.Faces:
self.shapes.append([o.Shape,color])
for f in o.Shape.Faces:
self.faces.append([f,color])
self.resetFlags()
if DEBUG: print "adding ", len(self.objects), " objects, ", len(self.faces), " faces"
def addShapes(self,shapes,color=(0.9,0.9,0.9,1.0)):
"add shapes to this renderer, optionally with a color. Warning, these will get lost if using join()"
if DEBUG: print "adding ", len(shapes), " shapes"
for s in shapes:
if s.Faces:
self.shapes.append([s,color])
for f in s.Faces:
self.faces.append([f,color])
self.resetFlags()
def info(self):
"Prints info about the contents of this renderer"
@ -122,10 +121,10 @@ class Renderer:
r += "sorted: " + str(self.sorted) + "\n"
r += "contains " + str(len(self.faces)) + " faces\n"
for i in range(len(self.faces)):
r += " face " + str(i) + " : center " + str(self.faces[i].CenterOfMass)
r += " : normal " + str(self.faces[i].normalAt(0,0))
r += ", " + str(len(self.faces[i].Vertexes)) + " verts"
r += ", color: " + self.getFill(self.fills[i]) + "\n"
r += " face " + str(i) + " : center " + str(self.faces[i][0].CenterOfMass)
r += " : normal " + str(self.faces[i][0].normalAt(0,0))
r += ", " + str(len(self.faces[i][0].Vertexes)) + " verts"
r += ", color: " + self.getFill(self.faces[i][1]) + "\n"
return r
def addLabels(self):
@ -133,13 +132,13 @@ class Renderer:
c = 0
for f in self.faces:
l = FreeCAD.ActiveDocument.addObject("App::AnnotationLabel","facelabel")
l.BasePosition = f.CenterOfMass
l.BasePosition = f[0].CenterOfMass
l.LabelText = str(c)
c += 1
def isVisible(self,face):
"returns True if the given face points in the view direction"
normal = face.normalAt(0,0)
normal = face[0].normalAt(0,0)
if DEBUG: print "checking face normal ", normal, " against ", self.wp.axis, " : ", math.degrees(normal.getAngle(self.wp.axis))
if normal.getAngle(self.wp.axis) < math.pi/2:
return True
@ -150,6 +149,8 @@ class Renderer:
if not self.faces:
return
self.faces = [self.projectFace(f) for f in self.faces]
if self.sections:
self.sections = [self.projectFace(f) for f in self.sections]
self.oriented = True
def removeHidden(self):
@ -157,21 +158,18 @@ class Renderer:
if not self.faces:
return
faces = []
fills = []
for i in range(len(self.faces)):
if self.isVisible(self.faces[i]):
faces.append(self.faces[i])
fills.append(self.fills[i])
for f in self.faces:
if self.isVisible(f):
faces.append(f)
if DEBUG: print len(self.faces)-len(faces) , " faces removed, ", len(faces), " faces retained"
self.faces = faces
self.fills = fills
self.trimmed = True
def projectFace(self,face):
"projects a single face on the WP"
wires = []
norm = face.normalAt(0,0)
for w in face.Wires:
norm = face[0].normalAt(0,0)
for w in face[0].Wires:
verts = []
edges = fcgeo.sortEdges(w.Edges)
for e in edges:
@ -190,12 +188,12 @@ class Renderer:
vnorm = self.wp.getLocalCoords(norm)
if vnorm.getAngle(sh.normalAt(0,0)) > 1:
sh.reverse()
return sh
return [sh]+face[1:]
def flattenFace(self,face):
"Returns a face where all vertices have Z = 0"
wires = []
for w in face.Wires:
for w in face[0].Wires:
verts = []
edges = fcgeo.sortEdges(w.Edges)
for e in edges:
@ -209,29 +207,113 @@ class Renderer:
if DEBUG: print "Error: Unable to flatten face"
return None
else:
return sh
return [sh]+face[1:]
def cut(self,cutplane):
"Cuts through the shapes with a given cut plane and builds section faces"
if self.iscut:
return
if not self.shapes:
if DEBUG: print "No objects to make sections"
else:
fill = (1.0,1.0,1.0,1.0)
placement = FreeCAD.Placement(cutplane.Placement)
# building boundbox
bb = self.shapes[0][0].BoundBox
for sh in self.shapes[1:]:
bb.add(sh[0].BoundBox)
bb.enlarge(1)
um = vm = wm = 0
if not bb.isCutPlane(placement.Base,self.wp.axis):
if DEBUG: print "No objects are cut by the plane"
else:
corners = [FreeCAD.Vector(bb.XMin,bb.YMin,bb.ZMin),
FreeCAD.Vector(bb.XMin,bb.YMax,bb.ZMin),
FreeCAD.Vector(bb.XMax,bb.YMin,bb.ZMin),
FreeCAD.Vector(bb.XMax,bb.YMax,bb.ZMin),
FreeCAD.Vector(bb.XMin,bb.YMin,bb.ZMax),
FreeCAD.Vector(bb.XMin,bb.YMax,bb.ZMax),
FreeCAD.Vector(bb.XMax,bb.YMin,bb.ZMax),
FreeCAD.Vector(bb.XMax,bb.YMax,bb.ZMax)]
for c in corners:
dv = c.sub(placement.Base)
um1 = fcvec.project(dv,self.wp.u).Length
um = max(um,um1)
vm1 = fcvec.project(dv,self.wp.v).Length
vm = max(vm,vm1)
wm1 = fcvec.project(dv,self.wp.axis).Length
wm = max(wm,wm1)
p1 = FreeCAD.Vector(-um,vm,0)
p2 = FreeCAD.Vector(um,vm,0)
p3 = FreeCAD.Vector(um,-vm,0)
p4 = FreeCAD.Vector(-um,-vm,0)
cutface = Part.makePolygon([p1,p2,p3,p4,p1])
cutface = Part.Face(cutface)
cutface.Placement = placement
cutnormal = fcvec.scaleTo(self.wp.axis,wm)
cutvolume = cutface.extrude(cutnormal)
shapes = []
faces = []
sections = []
for sh in self.shapes:
for sol in sh[0].Solids:
c = sol.cut(cutvolume)
shapes.append([c]+sh[1:])
for f in c.Faces:
faces.append([f]+sh[1:])
sec = sol.section(cutface)
if sec.Edges:
wires = fcgeo.findWires(sec.Edges)
for w in wires:
sec = Part.Face(w)
sections.append([sec,fill])
self.shapes = shapes
self.faces = faces
self.sections = sections
if DEBUG: print "Built ",len(self.sections)," sections, ", len(self.faces), " faces retained"
self.iscut = True
self.oriented = False
self.trimmed = False
self.sorted = False
self.joined = False
def isInside(self,vert,face):
"Returns True if the vert is inside the face in Z projection"
# http://paulbourke.net/geometry/insidepoly/
count = 0
p = self.wp.getLocalCoords(vert.Point)
for e in face[0].Edges:
p1 = e.Vertexes[0].Point
p2 = e.Vertexes[-1].Point
if p.y > min(p1.y,p2.y):
if p.y <= max(p1.y,p2.y):
if p.x <= max(p1.x,p2.x):
if p1.y != p2.y:
xinters = (p.y-p1.y)*(p2.x-p1.x)/(p2.y-p1.y)+p1.x
if (p1.x == p2.x) or (p.x <= xinters):
count += 1
if count % 2 == 0:
return False
else:
return True
def zOverlaps(self,face1,face2):
"Checks if face1 overlaps face2 in Z direction"
face1 = self.flattenFace(face1)
face2 = self.flattenFace(face2)
# first we check if one of the verts is inside the other face
for v in face1.Vertexes:
for v in face1[0].Vertexes:
if self.isInside(v,face2):
return True
# even so, faces can still overlap if their edges cross each other
for e1 in face1.Edges:
for e2 in face2.Edges:
for e1 in face1[0].Edges:
for e2 in face2[0].Edges:
if fcgeo.findIntersection(e1,e2):
return True
return False
def compare(self,face1,face2):
@ -241,8 +323,8 @@ class Renderer:
# http://www.siggraph.org/education/materials/HyperGraph/scanline/visibility/painter.htm
# and practical application http://vrm.ao2.it/ (blender vector renderer)
b1 = face1.BoundBox
b2 = face2.BoundBox
b1 = face1[0].BoundBox
b2 = face2[0].BoundBox
# test 1: if faces don't overlap, no comparison possible
if DEBUG: print "doing test 1"
@ -266,11 +348,11 @@ class Renderer:
# test 3: all verts of face1 are in front or behind the plane of face2
if DEBUG: print "doing test 3"
norm = face2.normalAt(0,0)
norm = face2[0].normalAt(0,0)
behind = 0
front = 0
for v in face1.Vertexes:
dv = v.Point.sub(face2.Vertexes[0].Point)
for v in face1[0].Vertexes:
dv = v.Point.sub(face2[0].Vertexes[0].Point)
dv = fcvec.project(dv,norm)
if fcvec.isNull(dv):
behind += 1
@ -281,19 +363,19 @@ class Renderer:
else:
front += 1
if DEBUG: print "front: ",front," behind: ",behind
if behind == len(face1.Vertexes):
if behind == len(face1[0].Vertexes):
return 2
elif front == len(face1.Vertexes):
elif front == len(face1[0].Vertexes):
return 1
if DEBUG: print "failed, cannot say if face 1 is in front or behind"
# test 4: all verts of face2 are in front or behind the plane of face1
if DEBUG: print "doing test 4"
norm = face1.normalAt(0,0)
norm = face1[0].normalAt(0,0)
behind = 0
front = 0
for v in face2.Vertexes:
dv = v.Point.sub(face1.Vertexes[0].Point)
for v in face2[0].Vertexes:
dv = v.Point.sub(face1[0].Vertexes[0].Point)
dv = fcvec.project(dv,norm)
if fcvec.isNull(dv):
behind += 1
@ -304,9 +386,9 @@ class Renderer:
else:
front += 1
if DEBUG: print "front: ",front," behind: ",behind
if behind == len(face2.Vertexes):
if behind == len(face2[0].Vertexes):
return 1
elif front == len(face2.Vertexes):
elif front == len(face2[0].Vertexes):
return 2
if DEBUG: print "failed, cannot say if face 2 is in front or behind"
@ -321,6 +403,35 @@ class Renderer:
if DEBUG: print "Houston, all tests passed, and still no results"
return 0
def join(self,otype):
"joins the objects of same type"
walls = []
structs = []
objs = []
for o in obj.Source.Objects:
t = Draft.getType(o)
if t == "Wall":
walls.append(o)
elif t == "Structure":
structs.append(o)
else:
objs.append(o)
for g in [walls,structs]:
if g:
print "group:",g
col = g[0].ViewObject.DiffuseColor[0]
s = g[0].Shape
for o in g[1:]:
try:
fs = s.fuse(o.Shape)
fs = fs.removeSplitter()
except:
print "shape fusion failed"
objs.append([o.Shape,o.ViewObject.DiffuseColor[0]])
else:
s = fs
objs.append([s,col])
def findPosition(self,f1,faces):
"Finds the position of a face in a list of faces"
l = None
@ -345,24 +456,22 @@ class Renderer:
def sort(self):
"projects a shape on the WP"
if not self.faces:
return
if len(self.faces) == 1:
if len(self.faces) <= 1:
return
if not self.trimmed:
self.removeHidden()
if len(self.faces) == 1:
return
if not self.oriented:
self.reorient()
faces = self.faces[:]
if DEBUG: print "sorting ",len(self.faces)," faces"
sfaces = []
sfills = []
loopcount = 0
notfoundstack = 0
while faces:
if DEBUG: print "loop ", loopcount
f1 = faces[0]
fi1 = self.fills[self.faces.index(f1)]
if sfaces and (notfoundstack < len(faces)):
if DEBUG: print "using ordered stack, notfound = ",notfoundstack
p = self.findPosition(f1,sfaces)
@ -375,32 +484,26 @@ class Renderer:
# position found, we insert it
faces.remove(f1)
sfaces.insert(p,f1)
sfills.insert(p,fi1)
notfoundstack = 0
else:
# either there is no stack, or no more face can be compared
# find a root, 2 faces that can be compared
if DEBUG: print "using unordered stack, notfound = ",notfoundstack
for f2 in faces[1:]:
fi2 = self.fills[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)
if r == 1:
faces.remove(f2)
sfaces.append(f2)
sfills.append(fi2)
faces.remove(f1)
sfaces.append(f1)
sfills.append(fi1)
notfoundstack = 0
break
elif r == 2:
faces.remove(f1)
sfaces.append(f1)
sfills.append(fi1)
faces.remove(f2)
sfaces.append(f2)
sfills.append(fi2)
notfoundstack = 0
break
else:
@ -414,7 +517,6 @@ class Renderer:
if DEBUG: print "done Z sorting. ", len(sfaces), " faces retained, ", len(self.faces)-len(sfaces), " faces lost."
self.faces = sfaces
self.fills = sfills
self.sorted = True
def buildDummy(self):
@ -424,7 +526,7 @@ class Renderer:
self.sort()
faces = []
for f in self.faces[:]:
ff = self.flattenFace(f)
ff = self.flattenFace(f)[0]
ff.translate(FreeCAD.Vector(0,0,z))
faces.append(ff)
z += 1
@ -440,30 +542,35 @@ class Renderer:
col = "#"+r+g+b
return col
def getSVG(self,linewidth=0.01):
"Returns a SVG fragment"
if DEBUG: print len(self.faces), " faces and ", len(self.fills), " fills."
def getPathData(self,w):
"Returns a SVG path data string from a 2D wire"
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 '
return svg
def getViewSVG(self,linewidth=0.01):
"Returns a SVG fragment from viewed faces"
if DEBUG: print "Printing ", len(self.faces), " faces"
if not self.sorted:
self.sort()
svg = ''
for i in range(len(self.faces)):
fill = self.getFill(self.fills[i])
for f in self.faces:
fill = self.getFill(f[1])
svg +='<path '
svg += 'd="'
for w in self.faces[i].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 '
for w in f[0].Wires:
svg += self.getPathData(w)
svg += '" '
svg += 'stroke="#000000" '
svg += 'stroke-width="' + str(linewidth) + '" '
@ -475,3 +582,28 @@ class Renderer:
svg += 'fill-rule: evenodd'
svg += '"/>\n'
return svg
def getSectionSVG(self,linewidth=0.02):
"Returns a SVG fragment from cut faces"
if DEBUG: print "Printing ", len(self.sections), " cutfaces"
if not self.oriented:
self.reorient()
svg = ''
for f in self.sections:
fill = self.getFill(f[1])
svg +='<path '
svg += 'd="'
for w in f[0].Wires:
svg += self.getPathData(w)
svg += '" '
svg += 'stroke="#000000" '
svg += 'stroke-width="' + str(linewidth) + '" '
svg += 'style="stroke-width:0.01;'
svg += 'stroke-miterlimit:1;'
svg += 'stroke-linejoin:round;'
svg += 'stroke-dasharray:none;'
svg += 'fill:' + fill + ';'
svg += 'fill-rule: evenodd'
svg += '"/>\n'
return svg

View File

@ -176,7 +176,7 @@ class plane:
def setFromPlacement(self,pl):
"sets the working plane from a placement (rotaton ONLY)"
rot= pl.Rotation
rot = FreeCAD.Placement(pl).Rotation
self.u = rot.multVec(FreeCAD.Vector(1,0,0))
self.v = rot.multVec(FreeCAD.Vector(0,1,0))
self.axis = rot.multVec(FreeCAD.Vector(0,0,1))

View File

@ -559,6 +559,7 @@ def findWires(edgeslist):
edges = edgeslist[:]
wires = []
lost = []
while edges:
e = edges[0]
if not wires:
@ -568,19 +569,28 @@ def findWires(edgeslist):
else:
found = False
for w in wires:
if found:
break
for we in w:
if touches(e,we):
edges.remove(e)
w.append(e)
found = True
break
else:
# edge doesn't connect with any existing group
edges.remove(e)
wires.append([e])
return wires
if not found:
for we in w:
if touches(e,we):
edges.remove(e)
w.append(e)
found = True
break
if not found:
if e in lost:
# we already tried this edge, and still nothing
edges.remove(e)
wires.append([e])
lost = []
else:
# put to the end of the list
edges.remove(e)
edges.append(e)
lost.append(e)
nwires = []
for w in wires:
nwires.append(Part.Wire(w))
return nwires
def superWire(edgeslist,closed=False):
'''superWire(edges,[closed]): forces a wire between edges that don't necessarily
@ -993,7 +1003,7 @@ def isPlanar(shape):
return False
return True
def findWires(edges):
def findWiresOld(edges):
'''finds connected edges in the list, and returns a list of lists containing edges
that can be connected'''
def verts(shape):