+ better depth-sorting in the Arch SectionPlane

git-svn-id: https://free-cad.svn.sourceforge.net/svnroot/free-cad/trunk@5323 e8eeb9e2-ec13-0410-a4a9-efa5cf37419d
This commit is contained in:
yorikvanhavre 2011-12-18 20:06:48 +00:00
parent 5b1c692c21
commit 889e0a3016
2 changed files with 166 additions and 128 deletions

View File

@ -117,7 +117,7 @@ class _Cell(ArchComponent.Component):
class _ViewProviderCell(ArchComponent.ViewProviderComponent):
"A View Provider for the Cell object"
def __init__(self,vobj):
Component.ViewProviderComponent.__init__(self,vobj)
ArchComponent.ViewProviderComponent.__init__(self,vobj)
vobj.Proxy = self
self.Object = vobj.Object

View File

@ -44,7 +44,6 @@ class _SectionPlane:
obj.addProperty("App::PropertyLinkList","Objects","Base",
"The objects that must be considered by this section plane. Empty means all document")
self.Type = "SectionPlane"
self.Object = obj
def execute(self,obj):
pl = obj.Placement
@ -52,13 +51,12 @@ class _SectionPlane:
p = Part.makePlane(l,l,Vector(l/2,-l/2,0),Vector(0,0,-1))
obj.Shape = p
obj.Placement = pl
self.Object = obj
def onChanged(self,obj,prop):
pass
def getNormal(self):
return self.Object.Shape.Faces[0].normalAt(0,0)
def getNormal(self,obj):
return obj.Shape.Faces[0].normalAt(0,0)
class _ViewProviderSectionPlane(ArchComponent.ViewProviderComponent):
"A View Provider for Section Planes"
@ -133,17 +131,18 @@ class _ViewProviderSectionPlane(ArchComponent.ViewProviderComponent):
class _ArchDrawingView:
def __init__(self, obj):
obj.addProperty("App::PropertyLink","Source","Base","The linked object")
obj.addProperty("App::PropertyEnumeration","RenderingMode","Base","The rendering mode to use")
obj.RenderingMode = ["Z-sorted","Wireframe","Wireframe + shade"]
obj.RenderingMode = "Z-sorted"
obj.Proxy = self
self.Type = "DrawingView"
def execute(self, obj):
print "executing"
if obj.Source:
obj.ViewResult = self.updateSVG(obj)
def onChanged(self, obj, prop):
print "prop:",prop
if prop == "Source":
if prop in ["Source","RenderingMode"]:
obj.ViewResult = self.updateSVG(obj)
def updateSVG(self, obj):
@ -151,8 +150,13 @@ class _ArchDrawingView:
if obj.Source:
if obj.Source.Objects:
svg = ''
for o in obj.Source.Objects:
svg += self.getSVG(o,obj.Source.Proxy.getNormal())
if obj.RenderingMode == "Z-sorted":
svg += self.renderClassicSVG(obj.Source.Objects,obj.Source.Proxy.getNormal(obj.Source))
elif obj.RenderingMode == "Wireframe":
svg += self.renderWireframeSVG(obj.Source.Objects,obj.Source.Proxy.getNormal(obj.Source))
elif obj.RenderingMode == "Wireframe + shade":
svg += self.renderOutlineSVG(obj.Source.Objects,obj.Source.Proxy.getNormal(obj.Source))
svg += self.renderWireframeSVG(obj.Source.Objects,obj.Source.Proxy.getNormal(obj.Source))
result = ''
result += '<g id="' + obj.Name + '"'
result += ' transform="'
@ -166,19 +170,80 @@ class _ArchDrawingView:
return result
return ''
def getSVG(self,obj,direction,base=None):
def getProj(self,vec,plane):
"returns a vector in working plane space from the given vector"
if not plane:
return vec
nx = fcvec.project(vec,plane.u)
lx = nx.Length
if abs(nx.getAngle(plane.u)) > 0.1: lx = -lx
ny = fcvec.project(vec,plane.v)
ly = ny.Length
if abs(ny.getAngle(plane.v)) > 0.1: ly = -ly
return Vector(lx,ly,0)
def getPath(self,face,plane):
"returns a svg path from a face"
svg ='<path '
edges = fcgeo.sortEdges(face.Edges)
v = self.getProj(edges[0].Vertexes[0].Point,plane)
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 = self.getProj(e.Vertexes[-1].Point,plane)
svg += 'L '+ str(v.x) +' '+ str(v.y) + ' '
elif isinstance(e.Curve,Part.Circle):
r = e.Curve.Radius
v = self.getProj(e.Vertexes[-1].Point,plane)
svg += 'A '+ str(r) + ' '+ str(r) +' 0 0 1 '+ str(v.x) +' '
svg += str(v.y) + ' '
svg += '" '
svg += 'stroke="#000000" '
svg += 'stroke-width="0.01 px" '
svg += 'style="stroke-width:0.01;'
svg += 'stroke-miterlimit:1;'
svg += 'stroke-dasharray:none;'
svg += 'fill:#aaaaaa"'
svg += '/>\n'
return svg
def renderWireframeSVG(self,objs,direction):
os = objs[:]
if os:
sh = os.pop().Shape
for o in os:
sh = sh.fuse(o.Shape)
result = Drawing.projectToSVG(sh,fcvec.neg(direction))
if result:
result = result.replace('stroke-width="0.35"','stroke-width="0.01 px"')
return result
return ''
def renderOutlineSVG(self,objs,direction):
plane = None
plane = WorkingPlane.plane()
if direction != Vector(0,0,0):
plane.alignToPointAndAxis(Vector(0,0,0),fcvec.neg(direction),0)
else:
direction = Vector(0,0,-1)
faces = []
for obj in objs:
for face in obj.Shape.Faces:
normal = face.normalAt(0,0)
if normal.getAngle(direction) > math.pi/2:
faces.append(face)
print "faces:",faces
if faces:
base = faces.pop()
for face in faces:
base = base.oldFuse(face)
result = self.getPath(base,plane)
return result
def renderClassicSVG(self,objs,direction,base=None):
"""returns an svg fragment from a SectionPlane object,
a direction vector and optionally a base point"""
print "getting representation of ",obj.Name," at ",direction
# using Draft WorkingPlane
plane = None
if direction != Vector(0,0,0):
plane = WorkingPlane.plane()
plane.alignToPointAndAxis(Vector(0,0,0),fcvec.neg(direction),0)
print "plane:",plane
def intersection(p1,p2,p3,p4):
"returns the intersection of line (p1,p2) with plane (p3,p4)"
# http://paulbourke.net/geometry/planeline/
@ -212,46 +277,49 @@ class _ArchDrawingView:
i = i2
return i
def getProj(vec):
if not plane:
return vec
nx = fcvec.project(vec,plane.u)
lx = nx.Length
if abs(nx.getAngle(plane.u)) > 0.1: lx = -lx
ny = fcvec.project(vec,plane.v)
ly = ny.Length
if abs(ny.getAngle(plane.v)) > 0.1: ly = -ly
return Vector(lx,ly,0)
def getPath(face):
svg ='<path '
edges = fcgeo.sortEdges(face.Edges)
v = getProj(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 = getProj(e.Vertexes[-1].Point)
svg += 'L '+ str(v.x) +' '+ str(v.y) + ' '
elif isinstance(e.Curve,Part.Circle):
r = e.Curve.Radius
v = getProj(e.Vertexes[-1].Point)
svg += 'A '+ str(r) + ' '+ str(r) +' 0 0 1 '+ str(v.x) +' '
svg += str(v.y) + ' '
svg += '" '
svg += 'stroke="#000000" '
svg += 'stroke-width="0.01 px" '
svg += 'style="stroke-width:0.01;'
svg += 'stroke-miterlimit:1;'
svg += 'stroke-dasharray:none;'
svg += 'fill:#aaaaaa"'
svg += '/>\n'
return svg
def findPrevious(base,dir,faces):
"returns the highest index in faces that is crossed by the given line"
for i in range(len(faces)-1,-1,-1):
print "p1:",base," p2: ",base.add(dir)
obb = faces[i].BoundBox
print "bo: ",obb
op = intersection(base,base.add(dir),faces[i].CenterOfMass,faces[i].normalAt(0,0))
print "int:", op
if obb.isInside(op):
dv = op.sub(base)
if dv.getAngle(dir) < math.pi/2:
return i
return None
def findNext(base,dir,faces):
"returns the lowest index in faces that is crossed by the given line"
for i in range(len(faces)):
obb = faces[i].BoundBox
op = intersection(base,base.add(dir),faces[i].CenterOfMass,faces[i].normalAt(0,0))
if obb.isInside(op):
dv = op.sub(base)
if dv.getAngle(dir) > math.pi/2:
return i
return None
print "getting representation at ",direction," =======================================>"
# using Draft WorkingPlane
plane = None
plane = WorkingPlane.plane()
if direction != Vector(0,0,0):
plane.alignToPointAndAxis(Vector(0,0,0),fcvec.neg(direction),0)
else:
direction = Vector(0,0,-1)
print "plane:",plane
sortedFaces = []
if not base:
# getting the base point = first point from the bounding box
bb = obj.Shape.BoundBox
bb = FreeCAD.BoundBox()
for o in objs:
bb.add(o.Shape.BoundBox)
rad = bb.DiagonalLength/2
rv = bb.Center.add(direction)
rv = fcvec.scaleTo(rv,rad)
@ -260,95 +328,65 @@ class _ArchDrawingView:
print "base:",base
# getting faces rays
unsortedFaces = obj.Shape.Faces[:]
# getting faces
unsortedFaces = []
notFoundFaces = []
for o in objs:
unsortedFaces.append(o.Name)
unsortedFaces.extend(o.Shape.Faces[:])
print "analyzing ",len(unsortedFaces)," faces"
for face in unsortedFaces:
# testing if normal
if isinstance(face,str):
print "OBJECT ",face," =======================================>"
continue
print "testing face ",unsortedFaces.index(face)
# testing if normal points outwards
normal = face.normalAt(0,0)
if normal.getAngle(direction) <= math.pi/2:
print "normal pointing outwards"
continue
bhash = face.hashCode()
center = face.CenterOfMass
ray = center.sub(base)
ray = fcvec.project(ray,direction)
z = ray.Length
if ray.getAngle(direction) > 1:
z = -z
print "face center:",center," ray:",ray
fprev = 0
fnext = len(sortedFaces)
notFound = True
tempFaces = [face]
print "checking ",len(face.Vertexes)," verts"
# comparing with other faces crossed by the same ray
for of in sortedFaces:
obb = of.BoundBox
op = intersection(base,ray,of.CenterOfMass,of.normalAt(0,0))
if obb.isInside(op):
oray = op.sub(base)
oray = fcvec.project(oray,direction)
oz = oray.Length
if oray.getAngle(direction) > 1:
oz = -oz
if oz > 0:
if oz < z:
tempFaces.insert(0,of)
elif oz > z:
tempFaces.append(of)
for v in face.Vertexes:
vprev = findPrevious(v.Point,direction,sortedFaces)
vnext = findNext(v.Point,direction,sortedFaces)
print "temp indexes:",vprev,vnext
if (vprev != None):
notfound = False
if (vprev > fprev):
fprev = vprev
if (vnext != None):
notfound = False
if (vnext < fnext):
fnext = vnext
print "tempFaces:",tempFaces
print "fprev:",fprev
print "fnext:",fnext
print "notFound",notFound
# finding the position of the base face among others
findex = 0
if len(tempFaces) > 1:
for i in range(len(tempFaces)):
if tempFaces[i].hashCode() == bhash:
findex = i
print "face index in tempfaces:",findex
# finding the right place to insert in ordered list
oindex = 0
if not sortedFaces:
sortedFaces.append(face)
elif len(tempFaces) == 1:
sortedFaces.append(face)
if fnext < fprev:
raise "Error, impossible index"
elif fnext == fprev:
sortedFaces.insert(fnext,face)
else:
if findex == 0: # our face is the first item
ni = getFirstIndex(tempFaces[1:],sortedFaces)
if ni == None:
sortedFaces.append(face)
else:
sortedFaces.insert(ni,face)
elif findex == len(tempFaces)-1: # our face is the last item
ni = getLastIndex(tempFaces[:-1],sortedFaces)
if ni == None:
sortedFaces.append(face)
else:
sortedFaces.insert(ni+1,face)
else: # there are faces before and after
i1 = getLastIndex(tempFaces[:findex],sortedFaces)
i2 = getFirstIndex(tempFaces[findex+1:],sortedFaces)
if i1 == None:
if i2 == None:
sortedFaces.append(face)
else:
sortedFaces.insert(i2,face)
else:
sortedFaces.insert(i1+1,face)
sortedFaces.insert(fnext,face)
print "sorted faces:",len(sortedFaces)
print len(sortedFaces)," sorted faces:",sortedFaces
# building SVG representation
# building SVG representation in correct order
svg = ''
for f in sortedFaces:
svg += getPath(f)
print "result:",svg
svg += self.getPath(f,plane)
return svg
FreeCADGui.addCommand('Arch_SectionPlane',_CommandSectionPlane())