def update(self,point): "sets the opposite (diagonal) point of the rectangle" diagonal = point.sub(self.origin) inpoint1 = self.origin.add(fcvec.project(diagonal,self.v)) inpoint2 = self.origin.add(fcvec.project(diagonal,self.u)) self.coords.point.set1Value(1,inpoint1.x,inpoint1.y,inpoint1.z) self.coords.point.set1Value(2,point.x,point.y,point.z) self.coords.point.set1Value(3,inpoint2.x,inpoint2.y,inpoint2.z)
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 getLocalCoords(self, point): "returns the coordinates of a given point on the working plane" xv = fcvec.project(point, self.u) x = xv.Length if xv.getAngle(self.u) > 1: x = -x yv = fcvec.project(point, self.v) y = yv.Length if yv.getAngle(self.v) > 1: y = -y zv = fcvec.project(point, self.axis) z = zv.Length if zv.getAngle(self.axis) > 1: z = -z return Vector(x, y, z)
def getLocalCoords(self,point): "returns the coordinates of a given point on the working plane" xv = fcvec.project(point,self.u) x = xv.Length if xv.getAngle(self.u) > 1: x = -x yv = fcvec.project(point,self.v) y = yv.Length if yv.getAngle(self.v) > 1: y = -y zv = fcvec.project(point,self.axis) z = zv.Length if zv.getAngle(self.axis) > 1: z = -z return Vector(x,y,z)
def constrain(self,point,basepoint=None,axis=None): '''constrain(point,basepoint=None,axis=None: Returns a constrained point. Axis can be "x","y" or "z" or a custom vector. If None, the closest working plane axis will be picked. Basepoint is the base point used to figure out from where the point must be constrained. If no basepoint is given, the current point is used as basepoint.''' # without the Draft module fully loaded, no axes system!" if not hasattr(FreeCAD,"DraftWorkingPlane"): return point point = Vector(point) # setup trackers if needed if not self.constrainLine: self.constrainLine = DraftTrackers.lineTracker(dotted=True) # setting basepoint if not basepoint: if not self.basepoint: self.basepoint = point else: self.basepoint = basepoint delta = point.sub(self.basepoint) # setting constraint axis if not self.affinity: self.affinity = FreeCAD.DraftWorkingPlane.getClosestAxis(delta) if isinstance(axis,FreeCAD.Vector): self.constraintAxis = axis elif axis == "x": self.constraintAxis = FreeCAD.DraftWorkingPlane.u elif axis == "y": self.constraintAxis = FreeCAD.DraftWorkingPlane.v elif axis == "z": self.constraintAxis = FreeCAD.DraftWorkingPlane.axis else: if self.affinity == "x": self.constraintAxis = FreeCAD.DraftWorkingPlane.u elif self.affinity == "y": self.constraintAxis = FreeCAD.DraftWorkingPlane.v else: self.constraintAxis = FreeCAD.DraftWorkingPlane.axis # calculating constrained point cdelta = fcvec.project(delta,self.constraintAxis) npoint = self.basepoint.add(cdelta) # setting constrain line if self.constrainLine: if point != npoint: self.constrainLine.p1(point) self.constrainLine.p2(npoint) self.constrainLine.on() else: self.constrainLine.off() return npoint
def getClosestNode(self,point): "returns the closest node from the given point" # get the 2D coords. point = FreeCAD.DraftWorkingPlane.projectPoint(point) u = fcvec.project(point,FreeCAD.DraftWorkingPlane.u) lu = u.Length if u.getAngle(FreeCAD.DraftWorkingPlane.u) > 1.5: lu = -lu v = fcvec.project(point,FreeCAD.DraftWorkingPlane.v) lv = v.Length if v.getAngle(FreeCAD.DraftWorkingPlane.v) > 1.5: lv = -lv # print "u = ",u," v = ",v # find nearest grid node pu = (round(lu/self.space,0))*self.space pv = (round(lv/self.space,0))*self.space rot = FreeCAD.Rotation() rot.Q = self.trans.rotation.getValue().getValue() return rot.multVec(Vector(pu,pv,0))
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 getPerpendicular(self,edge,pt): "returns a point on an edge, perpendicular to the given point" dv = pt.sub(edge.Vertexes[0].Point) nv = fcvec.project(dv,fcgeo.vec(edge)) np = (edge.Vertexes[0].Point).add(nv) return np
def sortFaces(self, face1, face2): "zsorts two faces. Returns 1 if face1 is closer, 2 if face2 is closer, 0 otherwise" # theory from # http://www.siggraph.org/education/materials/HyperGraph/scanline/visibility/painter.htm # and practical application http://vrm.ao2.it/ (blender vector renderer) b1 = face1.BoundBox b2 = face2.BoundBox if DEBUG: print "comparing face1: normal ", face1.normalAt( 0, 0), " with face2: normal ", face2.normalAt(0, 0) # test 1: if faces don't overlap, no comparison possible if DEBUG: print "doing test 1" if b1.XMax < b2.XMin: return 0 if b1.XMin > b2.XMax: return 0 if b1.YMax < b2.YMin: return 0 if b1.YMin > b2.YMax: return 0 if DEBUG: print "passed, faces are overlapping" # test 2: if Z bounds dont overlap, it's easy to know the closest if DEBUG: print "doing test 2" if b1.ZMax < b2.ZMin: return 2 if b2.ZMax < b1.ZMin: return 1 if DEBUG: print "passed, faces Z are crossed" # test 3: all verts of face1 are behind the plane of face2 if DEBUG: print "doing test 3" norm = face2.normalAt(0, 0) behind = 0 for v in face1.Vertexes: dv = v.Point.sub(face2.Vertexes[0].Point) dv = fcvec.project(dv, norm) if dv.Length: if dv.getAngle(norm) > 0.1: behind += 1 if behind == len(face1.Vertexes): return 2 if DEBUG: print "passed, face 1 is not behind" # test 4: all verts of face2 are in front of the plane of face1 if DEBUG: print "doing test 4" norm = face1.normalAt(0, 0) front = 0 for v in face2.Vertexes: dv = v.Point.sub(face1.Vertexes[0].Point) dv = fcvec.project(dv, norm) if dv.Length: if dv.getAngle(norm) < 0.1: front += 1 if front == len(face2.Vertexes): return 2 if DEBUG: print "passed, face 2 is not in front" # test 5: see if faces projections don't overlap, vertexwise if DEBUG: print "doing test 5" if not self.zOverlaps(face1, face2): return 0 elif not self.zOverlaps(face2, face1): return 0 if DEBUG: print "passed, faces are overlapping" if DEBUG: print "Houston, all tests passed, and still no results" return 0
def compare(self,face1,face2): "zsorts two faces. Returns 1 if face1 is closer, 2 if face2 is closer, 0 otherwise" # theory from # http://www.siggraph.org/education/materials/HyperGraph/scanline/visibility/painter.htm # and practical application http://vrm.ao2.it/ (blender vector renderer) b1 = face1[0].BoundBox b2 = face2[0].BoundBox # test 1: if faces don't overlap, no comparison possible if DEBUG: print "doing test 1" if b1.XMax < b2.XMin: return 0 if b1.XMin > b2.XMax: return 0 if b1.YMax < b2.YMin: return 0 if b1.YMin > b2.YMax: return 0 if DEBUG: print "failed, faces bboxes are not distinct" # test 2: if Z bounds dont overlap, it's easy to know the closest if DEBUG: print "doing test 2" if b1.ZMax < b2.ZMin: return 2 if b2.ZMax < b1.ZMin: return 1 if DEBUG: print "failed, faces Z are not distinct" # test 3: all verts of face1 are in front or behind the plane of face2 if DEBUG: print "doing test 3" norm = face2[0].normalAt(0,0) behind = 0 front = 0 for v in face1[0].Vertexes: dv = v.Point.sub(face2[0].Vertexes[0].Point) dv = fcvec.project(dv,norm) if fcvec.isNull(dv): behind += 1 front += 1 else: if dv.getAngle(norm) > 1: behind += 1 else: front += 1 if DEBUG: print "front: ",front," behind: ",behind if behind == len(face1[0].Vertexes): return 2 elif front == len(face1[0].Vertexes): return 1 if DEBUG: print "failed, cannot say if face 1 is in front or behind" # test 4: all verts of face2 are in front or behind the plane of face1 if DEBUG: print "doing test 4" norm = face1[0].normalAt(0,0) behind = 0 front = 0 for v in face2[0].Vertexes: dv = v.Point.sub(face1[0].Vertexes[0].Point) dv = fcvec.project(dv,norm) if fcvec.isNull(dv): behind += 1 front += 1 else: if dv.getAngle(norm) > 1: behind += 1 else: front += 1 if DEBUG: print "front: ",front," behind: ",behind if behind == len(face2[0].Vertexes): return 1 elif front == len(face2[0].Vertexes): return 2 if DEBUG: print "failed, cannot say if face 2 is in front or behind" # test 5: see if faces projections don't overlap, vertexwise if DEBUG: print "doing test 5" if not self.zOverlaps(face1,face2): return 0 elif not self.zOverlaps(face2,face1): return 0 if DEBUG: print "failed, faces are overlapping" if DEBUG: print "Houston, all tests passed, and still no results" return 0
def cut(self,cutplane): "Cuts through the shapes with a given cut plane and builds section faces" if self.iscut: return if not self.shapes: if DEBUG: print "No objects to make sections" else: fill = (1.0,1.0,1.0,1.0) placement = FreeCAD.Placement(cutplane.Placement) # building boundbox bb = self.shapes[0][0].BoundBox for sh in self.shapes[1:]: bb.add(sh[0].BoundBox) bb.enlarge(1) um = vm = wm = 0 if not bb.isCutPlane(placement.Base,self.wp.axis): if DEBUG: print "No objects are cut by the plane" else: corners = [FreeCAD.Vector(bb.XMin,bb.YMin,bb.ZMin), FreeCAD.Vector(bb.XMin,bb.YMax,bb.ZMin), FreeCAD.Vector(bb.XMax,bb.YMin,bb.ZMin), FreeCAD.Vector(bb.XMax,bb.YMax,bb.ZMin), FreeCAD.Vector(bb.XMin,bb.YMin,bb.ZMax), FreeCAD.Vector(bb.XMin,bb.YMax,bb.ZMax), FreeCAD.Vector(bb.XMax,bb.YMin,bb.ZMax), FreeCAD.Vector(bb.XMax,bb.YMax,bb.ZMax)] for c in corners: dv = c.sub(placement.Base) um1 = fcvec.project(dv,self.wp.u).Length um = max(um,um1) vm1 = fcvec.project(dv,self.wp.v).Length vm = max(vm,vm1) wm1 = fcvec.project(dv,self.wp.axis).Length wm = max(wm,wm1) p1 = FreeCAD.Vector(-um,vm,0) p2 = FreeCAD.Vector(um,vm,0) p3 = FreeCAD.Vector(um,-vm,0) p4 = FreeCAD.Vector(-um,-vm,0) cutface = Part.makePolygon([p1,p2,p3,p4,p1]) cutface = Part.Face(cutface) cutface.Placement = placement cutnormal = fcvec.scaleTo(self.wp.axis,wm) cutvolume = cutface.extrude(cutnormal) shapes = [] faces = [] sections = [] for sh in self.shapes: for sol in sh[0].Solids: c = sol.cut(cutvolume) shapes.append([c]+sh[1:]) for f in c.Faces: faces.append([f]+sh[1:]) sec = sol.section(cutface) if sec.Edges: wires = fcgeo.findWires(sec.Edges) for w in wires: sec = Part.Face(w) sections.append([sec,fill]) self.shapes = shapes self.faces = faces self.sections = sections if DEBUG: print "Built ",len(self.sections)," sections, ", len(self.faces), " faces retained" self.iscut = True self.oriented = False self.trimmed = False self.sorted = False self.joined = False
def getSize(self): "returns (length,width) of the rectangle" p1 = Vector(self.coords.point.getValues()[0].getValue()) p2 = Vector(self.coords.point.getValues()[2].getValue()) diag = p2.sub(p1) return ((fcvec.project(diag,self.u)).Length,(fcvec.project(diag,self.v)).Length)