Arch Vector renderer now supports face colors
This commit is contained in:
parent
dd8a44e103
commit
d12fbc632a
|
@ -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;'
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue
Block a user