Arch: Lots of bugfixes in vector rendering

This commit is contained in:
Yorik van Havre 2012-07-03 11:07:54 -03:00
parent f8c299c858
commit 322260c61b
6 changed files with 171 additions and 159 deletions

View File

@ -154,7 +154,7 @@ def splitMesh(obj,mark=True):
def makeFace(wires,method=2,cleanup=False): def makeFace(wires,method=2,cleanup=False):
'''makeFace(wires): makes a face from a list of wires, finding which ones are holes''' '''makeFace(wires): makes a face from a list of wires, finding which ones are holes'''
#print "makeFace: start" #print "makeFace: start:", wires
import Part import Part
if not isinstance(wires,list): if not isinstance(wires,list):
@ -162,6 +162,7 @@ def makeFace(wires,method=2,cleanup=False):
raise raise
return Part.Face(wires) return Part.Face(wires)
elif len(wires) == 1: elif len(wires) == 1:
import Draft;Draft.printShape(wires[0])
if len(wires[0].Vertexes) < 3: if len(wires[0].Vertexes) < 3:
raise raise
return Part.Face(wires[0]) return Part.Face(wires[0])

View File

@ -62,6 +62,7 @@ def addToComponent(compobject,addobject,mod=None):
l = getattr(compobject,mod) l = getattr(compobject,mod)
l.append(addobject) l.append(addobject)
setattr(compobject,mod,l) setattr(compobject,mod,l)
if mod != "Objects":
addobject.ViewObject.hide() addobject.ViewObject.hide()
else: else:
for a in attribs[:3]: for a in attribs[:3]:

View File

@ -215,7 +215,7 @@ class _ArchDrawingView:
import ArchVRM import ArchVRM
render = ArchVRM.Renderer() render = ArchVRM.Renderer()
render.setWorkingPlane(obj.Source.Placement) render.setWorkingPlane(obj.Source.Placement)
render.addObjects(Draft.getGroupContents(objs)) render.addObjects(Draft.getGroupContents(objs,walls=True))
render.cut(obj.Source.Shape) render.cut(obj.Source.Shape)
svg += render.getViewSVG(linewidth=linewidth) svg += render.getViewSVG(linewidth=linewidth)
svg += render.getSectionSVG(linewidth=linewidth*2) svg += render.getSectionSVG(linewidth=linewidth*2)

View File

@ -168,7 +168,7 @@ class Renderer:
def projectFace(self,face): def projectFace(self,face):
"projects a single face on the WP" "projects a single face on the WP"
#print "VRM: projectFace start" #print "VRM: projectFace start: ",len(face[0].Vertexes)," verts, ",len(face[0].Edges)," edges"
wires = [] wires = []
if not face[0].Wires: if not face[0].Wires:
if DEBUG: print "Error: Unable to project face on the WP" if DEBUG: print "Error: Unable to project face on the WP"
@ -177,15 +177,16 @@ class Renderer:
for w in face[0].Wires: for w in face[0].Wires:
verts = [] verts = []
edges = DraftGeomUtils.sortEdges(w.Edges) edges = DraftGeomUtils.sortEdges(w.Edges)
#print len(edges)," edges after sorting"
for e in edges: for e in edges:
v = e.Vertexes[0].Point v = e.Vertexes[0].Point
#print v
v = self.wp.getLocalCoords(v) v = self.wp.getLocalCoords(v)
verts.append(v) verts.append(v)
verts.append(verts[0]) verts.append(verts[0])
if len(verts) > 2: if len(verts) > 2:
print verts #print "new wire with ",len(verts)
wires.append(Part.makePolygon(verts)) wires.append(Part.makePolygon(verts))
print "wires:",wires
try: try:
sh = ArchCommands.makeFace(wires) sh = ArchCommands.makeFace(wires)
except: except:
@ -196,7 +197,7 @@ class Renderer:
vnorm = self.wp.getLocalCoords(norm) vnorm = self.wp.getLocalCoords(norm)
if vnorm.getAngle(sh.normalAt(0,0)) > 1: if vnorm.getAngle(sh.normalAt(0,0)) > 1:
sh.reverse() sh.reverse()
#print "VRM: projectFace end" #print "VRM: projectFace end: ",len(sh.Vertexes)," verts"
return [sh]+face[1:] return [sh]+face[1:]
def flattenFace(self,face): def flattenFace(self,face):
@ -272,12 +273,8 @@ class Renderer:
shapes.append([c]+sh[1:]) shapes.append([c]+sh[1:])
for f in c.Faces: for f in c.Faces:
faces.append([f]+sh[1:]) faces.append([f]+sh[1:])
sec = sol.section(cutface) if DraftGeomUtils.isCoplanar([f,cutface]):
if sec.Edges: sections.append([f,fill])
wires = DraftGeomUtils.findWires(sec.Edges)
for w in wires:
sec = Part.Face(w)
sections.append([sec,fill])
self.shapes = shapes self.shapes = shapes
self.faces = faces self.faces = faces
self.sections = sections self.sections = sections
@ -573,19 +570,21 @@ class Renderer:
def getPathData(self,w): def getPathData(self,w):
"Returns a SVG path data string from a 2D wire" "Returns a SVG path data string from a 2D wire"
def tostr(val):
return str(round(val,DraftVecUtils.precision()))
edges = DraftGeomUtils.sortEdges(w.Edges) edges = DraftGeomUtils.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 '+ tostr(v.x) +' '+ tostr(v.y) + ' '
for e in edges: for e in edges:
if isinstance(e.Curve,Part.Line) or isinstance(e.Curve,Part.BSplineCurve): if isinstance(e.Curve,Part.Line) or isinstance(e.Curve,Part.BSplineCurve):
v = e.Vertexes[-1].Point v = e.Vertexes[-1].Point
svg += 'L '+ str(v.x) +' '+ str(v.y) + ' ' svg += 'L '+ tostr(v.x) +' '+ tostr(v.y) + ' '
elif isinstance(e.Curve,Part.Circle): elif isinstance(e.Curve,Part.Circle):
r = e.Curve.Radius r = e.Curve.Radius
v = e.Vertexes[-1].Point v = e.Vertexes[-1].Point
svg += 'A '+ str(r) + ' '+ str(r) +' 0 0 1 '+ str(v.x) +' ' svg += 'A '+ tostr(r) + ' '+ tostr(r) +' 0 0 1 '+ tostr(v.x) +' '
svg += str(v.y) + ' ' svg += tostr(v.y) + ' '
svg += 'z ' svg += 'Z '
return svg return svg
def getViewSVG(self,linewidth=0.01): def getViewSVG(self,linewidth=0.01):
@ -625,6 +624,7 @@ class Renderer:
svg +='<path ' svg +='<path '
svg += 'd="' svg += 'd="'
for w in f[0].Wires: for w in f[0].Wires:
#print "wire with ",len(w.Vertexes)," verts"
svg += self.getPathData(w) svg += self.getPathData(w)
svg += '" ' svg += '" '
svg += 'stroke="#000000" ' svg += 'stroke="#000000" '

View File

@ -1540,7 +1540,7 @@ def makeSketch(objectslist,autoconstraints=False,addTo=None,name="Sketch"):
ok = False ok = False
tp = getType(obj) tp = getType(obj)
if tp == "BSpline": if tp == "BSpline":
pass print "makeSketch: BSplines not supported"
elif tp == "Circle": elif tp == "Circle":
if obj.FirstAngle == obj.LastAngle: if obj.FirstAngle == obj.LastAngle:
nobj.addGeometry(obj.Shape.Edges[0].Curve) nobj.addGeometry(obj.Shape.Edges[0].Curve)
@ -1586,32 +1586,16 @@ def makeSketch(objectslist,autoconstraints=False,addTo=None,name="Sketch"):
nobj.addConstraint(Constraint("Coincident",last-1,EndPoint,segs[0],StartPoint)) nobj.addConstraint(Constraint("Coincident",last-1,EndPoint,segs[0],StartPoint))
ok = True ok = True
if (not ok) and obj.isDerivedFrom("Part::Feature"): if (not ok) and obj.isDerivedFrom("Part::Feature"):
if DraftGeomUtils.hasOnlyWires(obj.Shape): if not DraftGeomUtils.isPlanar(obj.Shape):
for w in obj.Shape.Wires: print "Error: The given object is not planar and cannot be converted into a sketch."
for edge in DraftGeomUtils.sortEdges(w.Edges): return None
g = DraftGeomUtils.geom(edge) if not addTo:
nobj.Placement.Rotation = DraftGeomUtils.calculatePlacement(obj.Shape).Rotation
edges = []
for e in obj.Shape.Edges:
g = (DraftGeomUtils.geom(e,nobj.Placement))
if g: if g:
nobj.addGeometry(g) nobj.addGeometry(g)
if autoconstraints:
last = nobj.GeometryCount
segs = range(last-len(w.Edges),last-1)
for seg in segs:
nobj.addConstraint(Constraint("Coincident",seg,EndPoint,seg+1,StartPoint))
if DraftGeomUtils.isAligned(nobj.Geometry[seg],"x"):
nobj.addConstraint(Constraint("Vertical",seg))
elif DraftGeomUtils.isAligned(nobj.Geometry[seg],"y"):
nobj.addConstraint(Constraint("Horizontal",seg))
if w.isClosed:
nobj.addConstraint(Constraint("Coincident",last-1,EndPoint,segs[0],StartPoint))
else:
for edge in obj.Shape.Edges:
nobj.addGeometry(DraftGeomUtils.geom(edge))
if autoconstraints:
last = nobj.GeometryCount - 1
if DraftGeomUtils.isAligned(nobj.Geometry[last],"x"):
nobj.addConstraint(Constraint("Vertical",last))
elif DraftGeomUtils.isAligned(nobj.Geometry[last],"y"):
nobj.addConstraint(Constraint("Horizontal",last))
ok = True ok = True
if ok: if ok:
FreeCAD.ActiveDocument.removeObject(obj.Name) FreeCAD.ActiveDocument.removeObject(obj.Name)

View File

@ -355,23 +355,29 @@ def findIntersection(edge1,edge2,infinite1=False,infinite2=False,ex1=False,ex2=F
else : else :
print "fcgeo: Unsupported curve type: (" + str(edge1.Curve) + ", " + str(edge2.Curve) + ")" print "fcgeo: Unsupported curve type: (" + str(edge1.Curve) + ", " + str(edge2.Curve) + ")"
def geom(edge): def geom(edge,plac=FreeCAD.Placement()):
"returns a Line, ArcOfCircle or Circle geom from the given edge" "returns a Line, ArcOfCircle or Circle geom from the given edge, according to the given placement"
if isinstance(edge.Curve,Part.Line): if isinstance(edge.Curve,Part.Line):
return edge.Curve return edge.Curve
elif isinstance(edge.Curve,Part.Circle): elif isinstance(edge.Curve,Part.Circle):
if len(edge.Vertexes) == 1: if len(edge.Vertexes) == 1:
return Part.Circle(edge.Curve.Center,edge.Curve.Axis,edge.Curve.Radius) return Part.Circle(edge.Curve.Center,edge.Curve.Axis,edge.Curve.Radius)
else: else:
ref = edge.Placement.multVec(Vector(1,0,0)) # reorienting the arc along the correct normal
ref = ref.sub(edge.Placement.Base) # we only want the orientation normal = plac.Rotation.multVec(FreeCAD.Vector(0,0,1))
v1 = edge.Vertexes[0].Point v1 = edge.Vertexes[0].Point
v2 = edge.Vertexes[-1].Point v2 = edge.Vertexes[-1].Point
c = edge.Curve.Center c = edge.Curve.Center
cu = Part.Circle(edge.Curve.Center,edge.Curve.Axis,edge.Curve.Radius) cu = Part.Circle(edge.Curve.Center,normal,edge.Curve.Radius)
a1 = -DraftVecUtils.angle(v1.sub(c),ref,edge.Curve.Axis) ref = plac.Rotation.multVec(Vector(1,0,0))
a2 = -DraftVecUtils.angle(v2.sub(c),ref,edge.Curve.Axis) a1 = math.pi + DraftVecUtils.angle(v1.sub(c),ref,normal)
print "creating sketch arc from ",cu, ", p1=",v1, " (",math.degrees(a1), "d) p2=",v2," (", math.degrees(a2),"d)" a2 = DraftVecUtils.angle(v2.sub(c),ref,normal)
# direction check
if a1 > a2:
a1,a2 = a2,a1
#print "creating sketch arc from ",cu, ", p1=",v1, " (",math.degrees(a1), "d) p2=",v2," (", math.degrees(a2),"d)"
p= Part.ArcOfCircle(cu,a1,a2) p= Part.ArcOfCircle(cu,a1,a2)
return p return p
else: else:
@ -454,13 +460,6 @@ def sortEdges(lEdges, aVertex=None):
# print "Warning: sortedges cannot treat wired containing curves yet." # print "Warning: sortedges cannot treat wired containing curves yet."
# return lEdges # return lEdges
def isSameVertex(V1, V2):
''' Test if vertexes have same coordinates with precision 10E(-precision)'''
if round(V1.X-V2.X,1)==0 and round(V1.Y-V2.Y,1)==0 and round(V1.Z-V2.Z,1)==0 :
return True
else :
return False
def lookfor(aVertex, inEdges): def lookfor(aVertex, inEdges):
''' Look for (aVertex, inEdges) returns count, the position of the instance ''' Look for (aVertex, inEdges) returns count, the position of the instance
the position in the instance and the instance of the Edge''' the position in the instance and the instance of the Edge'''
@ -468,7 +467,7 @@ def sortEdges(lEdges, aVertex=None):
linstances = [] #lists the instances of aVertex linstances = [] #lists the instances of aVertex
for i in range(len(inEdges)) : for i in range(len(inEdges)) :
for j in range(2) : for j in range(2) :
if isSameVertex(aVertex,inEdges[i].Vertexes[j-1]): if aVertex.Point == inEdges[i].Vertexes[j-1].Point:
instance = inEdges[i] instance = inEdges[i]
count += 1 count += 1
linstances += [i,j-1,instance] linstances += [i,j-1,instance]
@ -480,7 +479,7 @@ def sortEdges(lEdges, aVertex=None):
else: else:
result = lookfor(aVertex,lEdges) result = lookfor(aVertex,lEdges)
if result[0] != 0: if result[0] != 0:
if isSameVertex(aVertex,result[3].Vertexes[0]): if aVertex.Point == result[3].Vertexes[0].Point:
return lEdges return lEdges
else: else:
if isinstance(result[3].Curve,Part.Line): if isinstance(result[3].Curve,Part.Line):
@ -514,7 +513,7 @@ def sortEdges(lEdges, aVertex=None):
del lEdges[result[1]] del lEdges[result[1]]
next = sortEdges(lEdges, result[3].Vertexes[-((-result[2])^1)]) next = sortEdges(lEdges, result[3].Vertexes[-((-result[2])^1)])
#print "result ",result[3].Vertexes[0].Point," ",result[3].Vertexes[1].Point, " compared to ",aVertex.Point #print "result ",result[3].Vertexes[0].Point," ",result[3].Vertexes[1].Point, " compared to ",aVertex.Point
if isSameVertex(aVertex,result[3].Vertexes[0]): if aVertex.Point == result[3].Vertexes[0].Point:
#print "keeping" #print "keeping"
olEdges += [result[3]] + next olEdges += [result[3]] + next
else: else:
@ -787,6 +786,31 @@ def getNormal(shape):
if n.getAngle(vdir) < 0.78: n = DraftVecUtils.neg(n) if n.getAngle(vdir) < 0.78: n = DraftVecUtils.neg(n)
return n return n
def getRotation(v1,v2=FreeCAD.Vector(0,0,1)):
'''Get the rotation Quaternion between 2 vectors'''
if (v1.dot(v2) > 0.999999) or (v1.dot(v2) < -0.999999):
# vectors are opposite
return None
axis = v1.cross(v2)
axis.normalize()
angle = math.degrees(math.sqrt((v1.Length ^ 2) * (v2.Length ^ 2)) + v1.dot(v2))
return FreeCAD.Rotation(axis,angle)
def calculatePlacement(shape):
'''calculatePlacement(shape): if the given shape is planar, this function
returns a placement located at the center of gravity of the shape, and oriented
towards the shape's normal. Otherwise, it returns a null placement.'''
if not isPlanar(shape):
return FreeCAD.Placement()
pos = shape.BoundBox.Center
norm = getNormal(shape)
pla = FreeCAD.Placement()
pla.Base = pos
r = getRotation(norm)
if r:
pla.Rotation = r
return pla
def offsetWire(wire,dvec,bind=False,occ=False): def offsetWire(wire,dvec,bind=False,occ=False):
''' '''
offsetWire(wire,vector,[bind]): offsets the given wire along the offsetWire(wire,vector,[bind]): offsets the given wire along the
@ -982,10 +1006,12 @@ def isCoplanar(faces):
"checks if all faces in the given list are coplanar" "checks if all faces in the given list are coplanar"
if len(faces) < 2: if len(faces) < 2:
return True return True
base =faces[0].normalAt(.5,.5) base =faces[0].normalAt(0,0)
for i in range(1,len(faces)): for i in range(1,len(faces)):
normal = faces[i].normalAt(.5,.5) for v in faces[i].Vertexes:
if (normal.getAngle(base) > .0001) and (normal.getAngle(base) < 3.1415): chord = v.Point.sub(faces[0].Vertexes[0].Point)
dist = DraftVecUtils.project(chord,base)
if dist.Length > 0:
return False return False
return True return True