Arch Vector renderer now supports face colors

This commit is contained in:
Yorik van Havre 2012-04-19 20:00:18 -03:00
parent dd8a44e103
commit d12fbc632a
2 changed files with 92 additions and 29 deletions

View File

@ -157,9 +157,11 @@ class _ViewProviderSectionPlane(ArchComponent.ViewProviderComponent):
class _ArchDrawingView: class _ArchDrawingView:
def __init__(self, obj): def __init__(self, obj):
obj.addProperty("App::PropertyLink","Source","Base","The linked object") obj.addProperty("App::PropertyLink","Source","Base","The linked object")
obj.addProperty("App::PropertyEnumeration","RenderingMode","Base","The rendering mode to use") obj.addProperty("App::PropertyEnumeration","RenderingMode","Drawing View","The rendering mode to use")
obj.addProperty("App::PropertyFloat","LineWidth","Drawing View","The line width of the rendered objects")
obj.RenderingMode = ["Solid","Wireframe"] obj.RenderingMode = ["Solid","Wireframe"]
obj.RenderingMode = "Solid" obj.RenderingMode = "Solid"
obj.LineWidth = 0.35
obj.Proxy = self obj.Proxy = self
self.Type = "DrawingView" self.Type = "DrawingView"
@ -179,14 +181,18 @@ class _ArchDrawingView:
if obj.Source.Objects: if obj.Source.Objects:
svg = '' svg = ''
cp = ArchCommands.getCutVolume(obj.Source.Objects,obj.Source.Placement) cp = ArchCommands.getCutVolume(obj.Source.Objects,obj.Source.Placement)
print "cp:",cp
sections = [] sections = []
if cp: if cp:
cutvolume = cp[0].extrude(cp[1]) cutvolume = cp[0].extrude(cp[1])
shapes = [] shapes = []
colors = []
for o in obj.Source.Objects: for o in obj.Source.Objects:
color = o.ViewObject.DiffuseColor[0]
print "adding ",o.Name," with color ",color
if cp: if cp:
shapes.append(o.Shape.cut(cutvolume)) for s in o.Shape.Solids:
shapes.append(s.cut(cutvolume))
colors.append(color)
sec = o.Shape.section(cp[0]) sec = o.Shape.section(cp[0])
if sec.Edges: if sec.Edges:
sec = Part.Wire(fcgeo.sortEdges(sec.Edges)) sec = Part.Wire(fcgeo.sortEdges(sec.Edges))
@ -194,13 +200,14 @@ class _ArchDrawingView:
sections.append(sec) sections.append(sec)
else: else:
shapes.append(o.Shape) shapes.append(o.Shape)
colors.append(color)
linewidth = obj.LineWidth/obj.Scale
if obj.RenderingMode == "Solid": if obj.RenderingMode == "Solid":
svg += self.renderVRM(shapes,obj.Source.Placement) svg += self.renderVRM(shapes,obj.Source.Placement,colors,linewidth)
else: else:
svg += self.renderOCC(shapes,obj.Source.Proxy.getNormal(obj.Source)) svg += self.renderOCC(shapes,obj.Source.Proxy.getNormal(obj.Source),linewidth)
print "sections:",sections
for s in sections: for s in sections:
svg += self.renderSection(s,obj.Source.Placement) svg += self.renderSection(s,obj.Source.Placement,linewidth*2)
result = '' result = ''
result += '<g id="' + obj.Name + '"' result += '<g id="' + obj.Name + '"'
result += ' transform="' result += ' transform="'
@ -214,7 +221,7 @@ class _ArchDrawingView:
return result return result
return '' return ''
def renderOCC(self,shapes,direction): def renderOCC(self,shapes,direction,linewidth):
"renders an SVG fragment with the OCC method" "renders an SVG fragment with the OCC method"
shapes = shapes[:] shapes = shapes[:]
if shapes: if shapes:
@ -223,21 +230,25 @@ class _ArchDrawingView:
base = base.fuse(sh) base = base.fuse(sh)
result = Drawing.projectToSVG(base,fcvec.neg(direction)) result = Drawing.projectToSVG(base,fcvec.neg(direction))
if result: if result:
result = result.replace('stroke-width="0.35"','stroke-width="0.01 px"') result = result.replace('stroke-width="0.35"','stroke-width="' + str(linewidth) + 'px"')
return result return result
return '' return ''
def renderVRM(self,shapes,placement): def renderVRM(self,shapes,placement,colors,linewidth):
"renders an SVG fragment with the ArchVRM method" "renders an SVG fragment with the ArchVRM method"
import ArchVRM import ArchVRM
render = ArchVRM.Renderer() render = ArchVRM.Renderer(debug=False)
render.setWorkingPlane(FreeCAD.Placement(placement)) render.setWorkingPlane(FreeCAD.Placement(placement))
for s in shapes: for i in range(len(shapes)):
render.add(s) if colors:
svg = render.getSVG() render.add(shapes[i],colors[i])
else:
render.add(shapes[i])
svg = render.getSVG(linewidth=linewidth)
print render.info()
return svg return svg
def renderSection(self,shape,placement): def renderSection(self,shape,placement,linewidth):
"renders a plane parallel to the section plane" "renders a plane parallel to the section plane"
placement = FreeCAD.Placement(placement) placement = FreeCAD.Placement(placement)
u = placement.Rotation.multVec(FreeCAD.Vector(1,0,0)) u = placement.Rotation.multVec(FreeCAD.Vector(1,0,0))
@ -262,8 +273,8 @@ class _ArchDrawingView:
svg += 'z ' svg += 'z '
svg += '" ' svg += '" '
svg += 'stroke="#000000" ' svg += 'stroke="#000000" '
svg += 'stroke-width="0.02 px" ' svg += 'stroke-width="' + str(linewidth) + 'px" '
svg += 'style="stroke-width:0.01;' svg += 'style="stroke-width:' + str(linewidth) + ';'
svg += 'stroke-miterlimit:1;' svg += 'stroke-miterlimit:1;'
svg += 'stroke-linejoin:round;' svg += 'stroke-linejoin:round;'
svg += 'stroke-dasharray:none;' svg += 'stroke-dasharray:none;'

View File

@ -31,7 +31,7 @@ MAXLOOP = 10 # the max number of loop before abort
class Renderer: class Renderer:
"A renderer object" "A renderer object"
def __init__(self,wp=None): def __init__(self,wp=None,debug=None):
""" """
Creates a renderer with a default Draft WorkingPlane Creates a renderer with a default Draft WorkingPlane
@ -44,8 +44,11 @@ class Renderer:
p.buildDummy() p.buildDummy()
""" """
if debug != None: DEBUG = debug
self.defaultFill = (0.9,0.9,0.9,1.0) # the default fill color
self.wp = wp self.wp = wp
self.faces = [] self.faces = []
self.fills = []
self.oriented = False self.oriented = False
self.trimmed = False self.trimmed = False
self.sorted = False self.sorted = False
@ -65,14 +68,39 @@ class Renderer:
self.wp = wp self.wp = wp
if DEBUG: print "Renderer set on " + str(self.wp) if DEBUG: print "Renderer set on " + str(self.wp)
def add(self,faces): def add(self,faces,colors=None):
"add faces, shape or object to this renderer" "add faces, shape or object to this renderer, optionally with face colors"
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): if isinstance(faces,list):
f = faces f = faces
setcolors(colors,len(f))
elif hasattr(faces,"Faces"): elif hasattr(faces,"Faces"):
f = faces.Faces f = faces.Faces
setcolors(colors,len(f))
elif hasattr(faces,"Shape"): elif hasattr(faces,"Shape"):
f = faces.Shape.Faces 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" if DEBUG: print "adding ", len(f), " faces"
self.faces.extend(f) self.faces.extend(f)
self.oriented = False self.oriented = False
@ -82,6 +110,7 @@ class Renderer:
def clean(self): def clean(self):
"removes all faces from this renderer" "removes all faces from this renderer"
self.faces = [] self.faces = []
self.fills = []
self.oriented = False self.oriented = False
self.trimmed = False self.trimmed = False
self.sorted = False self.sorted = False
@ -96,7 +125,8 @@ class Renderer:
for i in range(len(self.faces)): for i in range(len(self.faces)):
r += " face " + str(i) + " : center " + str(self.faces[i].CenterOfMass) r += " face " + str(i) + " : center " + str(self.faces[i].CenterOfMass)
r += " : normal " + str(self.faces[i].normalAt(0,0)) r += " : normal " + str(self.faces[i].normalAt(0,0))
r += ", " + str(len(self.faces[i].Vertexes)) + " verts\n" r += ", " + str(len(self.faces[i].Vertexes)) + " verts"
r += ", color: " + self.getFill(self.fills[i]) + "\n"
return r return r
def addLabels(self): def addLabels(self):
@ -128,11 +158,14 @@ class Renderer:
if not self.faces: if not self.faces:
return return
faces = [] faces = []
for f in (self.faces): fills = []
if self.isVisible(f): for i in range(len(self.faces)):
faces.append(f) if self.isVisible(self.faces[i]):
faces.append(self.faces[i])
fills.append(self.fills[i])
if DEBUG: print len(self.faces)-len(faces) , " faces removed, ", len(faces), " faces retained" if DEBUG: print len(self.faces)-len(faces) , " faces removed, ", len(faces), " faces retained"
self.faces = faces self.faces = faces
self.fills = fills
self.trimmed = True self.trimmed = True
def projectFace(self,face): def projectFace(self,face):
@ -324,11 +357,13 @@ class Renderer:
faces = self.faces[:] faces = self.faces[:]
if DEBUG: print "sorting ",len(self.faces)," faces" if DEBUG: print "sorting ",len(self.faces)," faces"
sfaces = [] sfaces = []
sfills = []
loopcount = 0 loopcount = 0
notfoundstack = 0 notfoundstack = 0
while faces: while faces:
if DEBUG: print "loop ", loopcount if DEBUG: print "loop ", loopcount
f1 = faces[0] f1 = faces[0]
fi1 = self.fills[self.faces.index(f1)]
if sfaces and (notfoundstack < len(faces)): if sfaces and (notfoundstack < len(faces)):
if DEBUG: print "using ordered stack, notfound = ",notfoundstack if DEBUG: print "using ordered stack, notfound = ",notfoundstack
p = self.findPosition(f1,sfaces) p = self.findPosition(f1,sfaces)
@ -341,26 +376,32 @@ class Renderer:
# position found, we insert it # position found, we insert it
faces.remove(f1) faces.remove(f1)
sfaces.insert(p,f1) sfaces.insert(p,f1)
sfills.insert(p,fi1)
notfoundstack = 0 notfoundstack = 0
else: else:
# either there is no stack, or no more face can be compared # either there is no stack, or no more face can be compared
# find a root, 2 faces that can be compared # find a root, 2 faces that can be compared
if DEBUG: print "using unordered stack, notfound = ",notfoundstack if DEBUG: print "using unordered stack, notfound = ",notfoundstack
for f2 in faces[1:]: 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)) 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)
if r == 1: if r == 1:
faces.remove(f2) faces.remove(f2)
sfaces.append(f2) sfaces.append(f2)
sfills.append(fi2)
faces.remove(f1) faces.remove(f1)
sfaces.append(f1) sfaces.append(f1)
sfills.append(fi1)
notfoundstack = 0 notfoundstack = 0
break break
elif r == 2: elif r == 2:
faces.remove(f1) faces.remove(f1)
sfaces.append(f1) sfaces.append(f1)
sfills.append(fi1)
faces.remove(f2) faces.remove(f2)
sfaces.append(f2) sfaces.append(f2)
sfills.append(fi2)
notfoundstack = 0 notfoundstack = 0
break break
else: else:
@ -374,6 +415,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.fills = sfills
self.sorted = True self.sorted = True
def buildDummy(self): def buildDummy(self):
@ -391,15 +433,25 @@ class Renderer:
c = Part.makeCompound(faces) c = Part.makeCompound(faces)
Part.show(c) Part.show(c)
def getSVG(self): def getFill(self,fill):
"Returns a SVG fill value"
r = str(hex(int(fill[0]*255)))[2:].zfill(2)
g = str(hex(int(fill[1]*255)))[2:].zfill(2)
b = str(hex(int(fill[2]*255)))[2:].zfill(2)
col = "#"+r+g+b
return col
def getSVG(self,linewidth=0.01):
"Returns a SVG fragment" "Returns a SVG fragment"
if DEBUG: print len(self.faces), " faces and ", len(self.fills), " fills."
if not self.sorted: if not self.sorted:
self.sort() self.sort()
svg = '' svg = ''
for f in self.faces: for i in range(len(self.faces)):
fill = self.getFill(self.fills[i])
svg +='<path ' svg +='<path '
svg += 'd="' svg += 'd="'
for w in f.Wires: for w in self.faces[i].Wires:
edges = fcgeo.sortEdges(w.Edges) edges = fcgeo.sortEdges(w.Edges)
v = edges[0].Vertexes[0].Point v = edges[0].Vertexes[0].Point
svg += 'M '+ str(v.x) +' '+ str(v.y) + ' ' svg += 'M '+ str(v.x) +' '+ str(v.y) + ' '
@ -415,12 +467,12 @@ class Renderer:
svg += 'z ' svg += 'z '
svg += '" ' svg += '" '
svg += 'stroke="#000000" ' svg += 'stroke="#000000" '
svg += 'stroke-width="0.01 px" ' svg += 'stroke-width="' + str(linewidth) + '" '
svg += 'style="stroke-width:0.01;' svg += 'style="stroke-width:0.01;'
svg += 'stroke-miterlimit:1;' svg += 'stroke-miterlimit:1;'
svg += 'stroke-linejoin:round;' svg += 'stroke-linejoin:round;'
svg += 'stroke-dasharray:none;' svg += 'stroke-dasharray:none;'
svg += 'fill:#aaaaaa;' svg += 'fill:' + fill + ';'
svg += 'fill-rule: evenodd' svg += 'fill-rule: evenodd'
svg += '"/>\n' svg += '"/>\n'
return svg return svg