def createGeometry(self,obj): import Part from draftlibs import fcgeo pl = obj.Placement if obj.Base: if obj.Base.isDerivedFrom("Part::Feature"): if obj.WindowParts and (len(obj.WindowParts)%5 == 0): shapes = [] for i in range(len(obj.WindowParts)/5): wires = [] wstr = obj.WindowParts[(i*5)+2].split(',') for s in wstr: j = int(s[4:]) if obj.Base.Shape.Wires: if len(obj.Base.Shape.Wires) >= j: wires.append(obj.Base.Shape.Wires[j]) if wires: max_length = 0 for w in wires: if w.BoundBox.DiagonalLength > max_length: max_length = w.BoundBox.DiagonalLength ext = w wires.remove(ext) shape = Part.Face(ext) norm = shape.normalAt(0,0) thk = float(obj.WindowParts[(i*5)+3]) if thk: exv = fcvec.scaleTo(norm,thk) shape = shape.extrude(exv) for w in wires: f = Part.Face(w) f = f.extrude(exv) shape = shape.cut(f) if obj.WindowParts[(i*5)+4]: zof = float(obj.WindowParts[(i*5)+4]) if zof: zov = fcvec.scaleTo(norm,zof) shape.translate(zov) print shape shapes.append(shape) obj.Shape = Part.makeCompound(shapes) if not fcgeo.isNull(pl): obj.Placement = pl
def createGeometry(self, obj): import Part from draftlibs import fcgeo pl = obj.Placement if obj.Base: if obj.Base.isDerivedFrom("Part::Feature"): if obj.WindowParts and (len(obj.WindowParts) % 5 == 0): shapes = [] for i in range(len(obj.WindowParts) / 5): wires = [] wstr = obj.WindowParts[(i * 5) + 2].split(',') for s in wstr: j = int(s[4:]) if len(obj.Base.Shape.Wires) >= j: wires.append(obj.Base.Shape.Wires[j]) if wires: max_length = 0 for w in wires: if w.BoundBox.DiagonalLength > max_length: max_length = w.BoundBox.DiagonalLength ext = w wires.remove(ext) shape = Part.Face(ext) norm = shape.normalAt(0, 0) thk = float(obj.WindowParts[(i * 5) + 3]) if thk: exv = fcvec.scaleTo(norm, thk) shape = shape.extrude(exv) for w in wires: f = Part.Face(w) f = f.extrude(exv) shape = shape.cut(f) if obj.WindowParts[(i * 5) + 4]: zof = float(obj.WindowParts[(i * 5) + 4]) if zof: zov = fcvec.scaleTo(norm, zof) shape.translate(zov) shapes.append(shape) obj.Shape = Part.makeCompound(shapes) if not fcgeo.isNull(pl): obj.Placement = pl
def update(self, point): "this function is called by the Snapper when the mouse is moved" b = self.points[0] n = FreeCAD.DraftWorkingPlane.axis bv = point.sub(b) dv = bv.cross(n) dv = fcvec.scaleTo(dv, self.Width / 2) if self.Align == "Center": self.tracker.update([b, point]) elif self.Align == "Left": self.tracker.update([b.add(dv), point.add(dv)]) else: dv = fcvec.neg(dv) self.tracker.update([b.add(dv), point.add(dv)])
def update(self,point): "this function is called by the Snapper when the mouse is moved" b = self.points[0] n = FreeCAD.DraftWorkingPlane.axis bv = point.sub(b) dv = bv.cross(n) dv = fcvec.scaleTo(dv,self.Width/2) if self.Align == "Center": self.tracker.update([b,point]) elif self.Align == "Left": self.tracker.update([b.add(dv),point.add(dv)]) else: dv = fcvec.neg(dv) self.tracker.update([b.add(dv),point.add(dv)])
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 getSubVolume(self, base, width, delta=None): "returns a subvolume from a base object" import Part max_length = 0 for w in base.Shape.Wires: if w.BoundBox.DiagonalLength > max_length: max_length = w.BoundBox.DiagonalLength f = w f = Part.Face(f) n = f.normalAt(0, 0) v1 = fcvec.scaleTo(n, width) f.translate(v1) v2 = fcvec.neg(v1) v2 = fcvec.scale(v1, -2) f = f.extrude(v2) if delta: f.translate(delta) return f
def getSubVolume(self,base,width,delta=None): "returns a subvolume from a base object" import Part max_length = 0 for w in base.Shape.Wires: if w.BoundBox.DiagonalLength > max_length: max_length = w.BoundBox.DiagonalLength f = w f = Part.Face(f) n = f.normalAt(0,0) v1 = fcvec.scaleTo(n,width) f.translate(v1) v2 = fcvec.neg(v1) v2 = fcvec.scale(v1,-2) f = f.extrude(v2) if delta: f.translate(delta) return f
def snapToPerpendicular(self,shape,last): "returns a list of perpendicular snap locations" snaps = [] if self.isEnabled("perpendicular"): if last: if isinstance(shape,Part.Edge): if isinstance(shape.Curve,Part.Line): np = self.getPerpendicular(shape,last) elif isinstance(shape.Curve,Part.Circle): dv = last.sub(shape.Curve.Center) dv = fcvec.scaleTo(dv,shape.Curve.Radius) np = (shape.Curve.Center).add(dv) elif isinstance(shape.Curve,Part.BSplineCurve): pr = shape.Curve.parameter(last) np = shape.Curve.value(pr) else: return snaps snaps.append([np,'perpendicular',np]) return snaps
def update(self,line=None,normal=None): import WorkingPlane from draftlibs import fcgeo if not normal: normal = FreeCAD.DraftWorkingPlane.axis if line: if isinstance(line,list): bp = line[0] lvec = line[1].sub(line[0]) else: lvec = fcgeo.vec(line.Shape.Edges[0]) bp = line.Shape.Edges[0].Vertexes[0].Point elif self.baseline: lvec = fcgeo.vec(self.baseline.Shape.Edges[0]) bp = self.baseline.Shape.Edges[0].Vertexes[0].Point else: return right = lvec.cross(normal) self.cube.width.setValue(lvec.Length) p = WorkingPlane.getPlacementFromPoints([bp,bp.add(lvec),bp.add(right)]) self.trans.rotation.setValue(p.Rotation.Q) bp = bp.add(fcvec.scale(lvec,0.5)) bp = bp.add(fcvec.scaleTo(normal,self.cube.depth.getValue()/2)) self.pos(bp)
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 = [] 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) return svg
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