Arch SectionPlane now uses the new vector renderer

This commit is contained in:
Yorik van Havre 2012-04-03 16:27:29 -03:00
parent 804c442cde
commit dafdb1fd94
6 changed files with 37 additions and 221 deletions

View File

@ -21,7 +21,7 @@
#* *
#***************************************************************************
import FreeCAD,FreeCADGui,ArchComponent,WorkingPlane,Drawing,math
import FreeCAD,FreeCADGui,ArchComponent,WorkingPlane,Drawing,math,Draft
from FreeCAD import Vector
from PyQt4 import QtCore
from pivy import coin
@ -49,7 +49,9 @@ class _CommandSectionPlane:
g.append(o)
obj.Objects = g
page = FreeCAD.ActiveDocument.addObject("Drawing::FeaturePage","Page")
template = FreeCAD.getResourceDir()+'Mod/Drawing/Templates/A3_Landscape.svg'
template = Draft.getParam("template")
if not template:
template = FreeCAD.getResourceDir()+'Mod/Drawing/Templates/A3_Landscape.svg'
page.ViewObject.HintOffsetX = 200
page.ViewObject.HintOffsetY = 100
page.ViewObject.HintScale = 20
@ -156,8 +158,8 @@ 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.RenderingMode = ["Solid","Wireframe"]
obj.RenderingMode = "Solid"
obj.Proxy = self
self.Type = "DrawingView"
@ -174,13 +176,10 @@ class _ArchDrawingView:
if obj.Source:
if obj.Source.Objects:
svg = ''
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))
if obj.RenderingMode == "Solid":
svg += self.renderVRM(obj.Source.Objects,obj.Source.Placement)
else:
svg += self.renderOCC(obj.Source.Objects,obj.Source.Proxy.getNormal(obj.Source))
result = ''
result += '<g id="' + obj.Name + '"'
result += ' transform="'
@ -194,46 +193,8 @@ class _ArchDrawingView:
return result
return ''
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):
import Part
from draftlibs import fcgeo
"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):
def renderOCC(self,objs,direction):
"renders an SVG fragment with the OCC method"
os = objs[:]
if os:
sh = os.pop().Shape
@ -245,174 +206,14 @@ class _ArchDrawingView:
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"""
def intersection(p1,p2,p3,p4):
"returns the intersection of line (p1,p2) with plane (p3,p4)"
# http://paulbourke.net/geometry/planeline/
dn = p4.dot(p2.sub(p1))
if dn != 0:
u = (p4.dot(p3.sub(p1))) / dn
p = p1.add((p2.sub(p1)).scale(u,u,u))
return p
else:
# line is parallel to normal
vp = fcvec.project(p3.sub(p1),p2.sub(p1))
l = vp.Length
if vp.getAngle(p2.sub(p1)) > 1:
l = -l
return fcvec.scaleTo(p2.sub(p1),l)
def getFirstIndex(list1,list2):
"returns the first index from list2 where there is an item of list1"
for i1 in range(len(list1)):
for i2 in range(len(list2)):
if list1[i1].hashCode() == list2[i2].hashCode():
return i2
return None
def getLastIndex(list1,list2):
"returns the last index from list2 where there is an item of list1"
i = None
for i1 in range(len(list1)):
for i2 in range(len(list2)):
if list1[i1].hashCode() == list2[i2].hashCode():
i = i2
return i
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 = 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)
rv = fcvec.neg(rv)
base = bb.Center.add(rv)
print "base:",base
# getting faces
unsortedFaces = []
notFoundFaces = []
def renderVRM(self,objs,placement):
"renders an SVG fragment with the ArchVRM method"
import ArchVRM
render = ArchVRM.Renderer()
render.setWorkingPlane(FreeCAD.Placement(placement))
for o in objs:
unsortedFaces.append(o.Name)
unsortedFaces.extend(o.Shape.Faces[:])
print "analyzing ",len(unsortedFaces)," faces"
for face in unsortedFaces:
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
fprev = 0
fnext = len(sortedFaces)
notFound = True
print "checking ",len(face.Vertexes)," verts"
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 "fprev:",fprev
print "fnext:",fnext
print "notFound",notFound
if fnext < fprev:
raise "Error, impossible index"
elif fnext == fprev:
sortedFaces.insert(fnext,face)
else:
sortedFaces.insert(fnext,face)
print len(sortedFaces)," sorted faces:",sortedFaces
# building SVG representation in correct order
svg = ''
for f in sortedFaces:
svg += self.getPath(f,plane)
render.add(o)
svg = render.getSVG()
return svg
FreeCADGui.addCommand('Arch_SectionPlane',_CommandSectionPlane())

View File

@ -58,8 +58,11 @@ class Renderer:
return "Arch Renderer: " + str(len(self.faces)) + " faces projected on " + str(self.wp)
def setWorkingPlane(self,wp):
"sets a Draft WorkingPlane for this renderer"
self.wp = wp
"sets a Draft WorkingPlane or Placement for this renderer"
if isinstance(wp,FreeCAD.Placement):
self.wp.setFromPlacement(wp)
else:
self.wp = wp
if DEBUG: print "Renderer set on " + str(self.wp)
def add(self,faces):
@ -308,6 +311,8 @@ class Renderer:
"projects a shape on the WP"
if not self.faces:
return
if len(self.faces) == 1:
return
if not self.trimmed:
self.removeHidden()
if not self.oriented:

View File

@ -19,6 +19,7 @@ SET(Arch_SRCS
importOBJ.py
ArchWindow.py
ArchAxis.py
ArchVRM.py
)
SOURCE_GROUP("" FILES ${Arch_SRCS})

View File

@ -26,7 +26,8 @@ data_DATA = \
ArchSectionPlane.py \
ArchWindow.py \
ArchCommands.py \
ArchAxis.py
ArchAxis.py \
ArchVRM.py
CLEANFILES = $(BUILT_SOURCES)

View File

@ -174,6 +174,13 @@ class plane:
0.0,0.0,0.0,1.0)
return FreeCAD.Placement(m)
def setFromPlacement(self,pl):
"sets the working plane from a placement (rotaton ONLY)"
rot= 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))
def save(self):
"stores the current plane state"
self.stored = [self.u,self.v,self.axis,self.position,self.weak]

View File

@ -44,6 +44,7 @@
<File Id="ArchSectionPlanePy" Name="ArchSectionPlane.py" DiskId="1" />
<File Id="ArchWindowPy" Name="ArchWindow.py" DiskId="1" />
<File Id="ArchAxisPy" Name="ArchAxis.py" DiskId="1" />
<File Id="ArchVRMPy" Name="ArchVRM.py" DiskId="1" />
</Component>
</Directory>
</Include>