def getBase(self, obj, wire, normal, width, height): "returns a full shape from a base wire" import DraftGeomUtils, Part flat = False if hasattr(obj.ViewObject, "DisplayMode"): flat = (obj.ViewObject.DisplayMode == "Flat 2D") dvec = DraftGeomUtils.vec(wire.Edges[0]).cross(normal) if not DraftVecUtils.isNull(dvec): dvec.normalize() if obj.Align == "Left": dvec = dvec.multiply(width) w2 = DraftGeomUtils.offsetWire(wire, dvec) w1 = Part.Wire(DraftGeomUtils.sortEdges(wire.Edges)) sh = DraftGeomUtils.bind(w1, w2) elif obj.Align == "Right": dvec = dvec.multiply(width) dvec = DraftVecUtils.neg(dvec) w2 = DraftGeomUtils.offsetWire(wire, dvec) w1 = Part.Wire(DraftGeomUtils.sortEdges(wire.Edges)) sh = DraftGeomUtils.bind(w1, w2) elif obj.Align == "Center": dvec = dvec.multiply(width / 2) w1 = DraftGeomUtils.offsetWire(wire, dvec) dvec = DraftVecUtils.neg(dvec) w2 = DraftGeomUtils.offsetWire(wire, dvec) sh = DraftGeomUtils.bind(w1, w2) # fixing self-intersections sh.fix(0.1, 0, 1) if height and (not flat): norm = Vector(normal).multiply(height) sh = sh.extrude(norm) return sh
def getbase(wire): "returns a full shape from a base wire" dvec = DraftGeomUtils.vec(wire.Edges[0]).cross(normal) dvec.normalize() if obj.Align == "Left": dvec = dvec.multiply(width) w2 = DraftGeomUtils.offsetWire(wire, dvec) w1 = Part.Wire(DraftGeomUtils.sortEdges(wire.Edges)) sh = DraftGeomUtils.bind(w1, w2) elif obj.Align == "Right": dvec = dvec.multiply(width) dvec = DraftVecUtils.neg(dvec) w2 = DraftGeomUtils.offsetWire(wire, dvec) w1 = Part.Wire(DraftGeomUtils.sortEdges(wire.Edges)) sh = DraftGeomUtils.bind(w1, w2) elif obj.Align == "Center": dvec = dvec.multiply(width / 2) w1 = DraftGeomUtils.offsetWire(wire, dvec) dvec = DraftVecUtils.neg(dvec) w2 = DraftGeomUtils.offsetWire(wire, dvec) sh = DraftGeomUtils.bind(w1, w2) # fixing self-intersections sh.fix(0.1, 0, 1) if height and (not flat): norm = Vector(normal).multiply(height) sh = sh.extrude(norm) return sh
def calc(self): import Part if (self.p1 != None) and (self.p2 != None): points = [DraftVecUtils.tup(self.p1,True),DraftVecUtils.tup(self.p2,True),\ DraftVecUtils.tup(self.p1,True),DraftVecUtils.tup(self.p2,True)] if self.p3 != None: p1 = self.p1 p4 = self.p2 if DraftVecUtils.equals(p1, p4): proj = None else: base = Part.Line(p1, p4).toShape() proj = DraftGeomUtils.findDistance(self.p3, base) if not proj: p2 = p1 p3 = p4 else: p2 = p1.add(DraftVecUtils.neg(proj)) p3 = p4.add(DraftVecUtils.neg(proj)) points = [ DraftVecUtils.tup(p1), DraftVecUtils.tup(p2), DraftVecUtils.tup(p3), DraftVecUtils.tup(p4) ] self.coords.point.setValues(0, 4, points)
def snapToPolar(self,point,last): "snaps to polar lines from the given point" if self.isEnabled('ortho') and (not self.mask): if last: vecs = [] if hasattr(FreeCAD,"DraftWorkingPlane"): ax = [FreeCAD.DraftWorkingPlane.u, FreeCAD.DraftWorkingPlane.v, FreeCAD.DraftWorkingPlane.axis] else: ax = [FreeCAD.Vector(1,0,0), FreeCAD.Vector(0,1,0), FreeCAD.Vector(0,0,1)] for a in self.polarAngles: if a == 90: vecs.extend([ax[0],DraftVecUtils.neg(ax[0])]) vecs.extend([ax[1],DraftVecUtils.neg(ax[1])]) else: v = DraftVecUtils.rotate(ax[0],math.radians(a),ax[2]) vecs.extend([v,DraftVecUtils.neg(v)]) v = DraftVecUtils.rotate(ax[1],math.radians(a),ax[2]) vecs.extend([v,DraftVecUtils.neg(v)]) for v in vecs: de = Part.Line(last,last.add(v)).toShape() np = self.getPerpendicular(de,point) if ((self.radius == 0) and (point.sub(last).getAngle(v) < 0.087)) \ or ((np.sub(point)).Length < self.radius): if self.tracker: self.tracker.setCoords(np) self.tracker.setMarker(self.mk['parallel']) self.tracker.on() self.setCursor('ortho') return np,de return point,None
def getbase(wire): "returns a full shape from a base wire" dvec = DraftGeomUtils.vec(wire.Edges[0]).cross(normal) dvec.normalize() if obj.Align == "Left": dvec = dvec.multiply(width) w2 = DraftGeomUtils.offsetWire(wire,dvec) w1 = Part.Wire(DraftGeomUtils.sortEdges(wire.Edges)) sh = DraftGeomUtils.bind(w1,w2) elif obj.Align == "Right": dvec = dvec.multiply(width) dvec = DraftVecUtils.neg(dvec) w2 = DraftGeomUtils.offsetWire(wire,dvec) w1 = Part.Wire(DraftGeomUtils.sortEdges(wire.Edges)) sh = DraftGeomUtils.bind(w1,w2) elif obj.Align == "Center": dvec = dvec.multiply(width/2) w1 = DraftGeomUtils.offsetWire(wire,dvec) dvec = DraftVecUtils.neg(dvec) w2 = DraftGeomUtils.offsetWire(wire,dvec) sh = DraftGeomUtils.bind(w1,w2) # fixing self-intersections sh.fix(0.1,0,1) if height and (not flat): norm = Vector(normal).multiply(height) sh = sh.extrude(norm) return sh
def getBase(self,obj,wire,normal,width,height): "returns a full shape from a base wire" import DraftGeomUtils,Part flat = False if hasattr(obj.ViewObject,"DisplayMode"): flat = (obj.ViewObject.DisplayMode == "Flat 2D") dvec = DraftGeomUtils.vec(wire.Edges[0]).cross(normal) if not DraftVecUtils.isNull(dvec): dvec.normalize() if obj.Align == "Left": dvec = dvec.multiply(width) w2 = DraftGeomUtils.offsetWire(wire,dvec) w1 = Part.Wire(DraftGeomUtils.sortEdges(wire.Edges)) sh = DraftGeomUtils.bind(w1,w2) elif obj.Align == "Right": dvec = dvec.multiply(width) dvec = DraftVecUtils.neg(dvec) w2 = DraftGeomUtils.offsetWire(wire,dvec) w1 = Part.Wire(DraftGeomUtils.sortEdges(wire.Edges)) sh = DraftGeomUtils.bind(w1,w2) elif obj.Align == "Center": dvec = dvec.multiply(width/2) w1 = DraftGeomUtils.offsetWire(wire,dvec) dvec = DraftVecUtils.neg(dvec) w2 = DraftGeomUtils.offsetWire(wire,dvec) sh = DraftGeomUtils.bind(w1,w2) # fixing self-intersections sh.fix(0.1,0,1) if height and (not flat): norm = Vector(normal).multiply(height) sh = sh.extrude(norm) return sh
def execute(self, obj): if obj.Source: if hasattr(obj.Source.Proxy,"BaseProfile"): p = obj.Source.Proxy.BaseProfile n = obj.Source.Proxy.ExtrusionVector import Drawing svg1 = "" svg2 = "" result = "" svg1 = Drawing.projectToSVG(p,DraftVecUtils.neg(n)) if svg1: w = str(obj.LineWidth/obj.Scale) #don't let linewidth be influenced by the scale... svg1 = svg1.replace('stroke-width="0.35"','stroke-width="'+w+'"') svg1 = svg1.replace('stroke-width="1"','stroke-width="'+w+'"') svg1 = svg1.replace('stroke-width:0.01','stroke-width:'+w) svg1 = svg1.replace('scale(1,-1)','scale('+str(obj.Scale)+',-'+str(obj.Scale)+')') if obj.Source.Tag: svg2 = '<text id="tag'+obj.Name+'"' svg2 += ' fill="'+Draft.getrgb(obj.TextColor)+'"' svg2 += ' font-size="'+str(obj.FontSize)+'"' svg2 += ' style="text-anchor:start;text-align:left;' svg2 += ' font-family:'+obj.FontName+'" ' svg2 += ' transform="translate(' + str(obj.TextX) + ',' + str(obj.TextY) + ')">' svg2 += '<tspan>'+obj.Source.Tag+'</tspan></text>\n' result += '<g id="' + obj.Name + '"' result += ' transform="' result += 'rotate('+str(obj.Rotation)+','+str(obj.X)+','+str(obj.Y)+') ' result += 'translate('+str(obj.X)+','+str(obj.Y)+')' result += '">\n ' result += svg1 result += svg2 result += '</g>' obj.ViewResult = result
def updateSVG(self, obj, join=False): "encapsulates a svg fragment into a transformation node" import Part, DraftGeomUtils if hasattr(obj, "Source"): if obj.Source: if obj.Source.Objects: objs = Draft.getGroupContents(obj.Source.Objects) svg = '' # generating SVG linewidth = obj.LineWidth / obj.Scale if obj.RenderingMode == "Solid": # render using the Arch Vector Renderer import ArchVRM render = ArchVRM.Renderer() render.setWorkingPlane(obj.Source.Placement) render.addObjects( Draft.getGroupContents(objs, walls=True)) render.cut(obj.Source.Shape) svg += render.getViewSVG(linewidth=linewidth) svg += render.getSectionSVG(linewidth=linewidth * 2) # print render.info() else: # render using the Drawing module import Drawing shapes = [] for o in objs: if o.isDerivedFrom("Part::Feature"): shapes.append(o.Shape) if shapes: base = shape.pop() for sh in shapes: base = base.fuse(sh) svgf = Drawing.projectToSVG( base, DraftVecUtils.neg(direction)) if svgf: svgf = svgf.replace( 'stroke-width="0.35"', 'stroke-width="' + str(linewidth) + 'px"') svgf = svgf.replace( 'stroke-width:0.01', 'stroke-width:' + str(linewidth) + 'px') svg += svgf result = '' result += '<g id="' + obj.Name + '"' result += ' transform="' result += 'rotate(' + str(obj.Rotation) + ',' + str( obj.X) + ',' + str(obj.Y) + ') ' result += 'translate(' + str(obj.X) + ',' + str( obj.Y) + ') ' result += 'scale(' + str( obj.Scale) + ',' + str(-obj.Scale) + ')' result += '">\n' result += svg result += '</g>\n' # print "complete node:",result return result return ''
def removeShape(objs,mark=True): '''takes an arch object (wall or structure) built on a cubic shape, and removes the inner shape, keeping its length, width and height as parameters.''' import DraftGeomUtils if not isinstance(objs,list): objs = [objs] for obj in objs: if DraftGeomUtils.isCubic(obj.Shape): dims = DraftGeomUtils.getCubicDimensions(obj.Shape) if dims: name = obj.Name tp = Draft.getType(obj) print tp if tp == "Structure": FreeCAD.ActiveDocument.removeObject(name) import ArchStructure str = ArchStructure.makeStructure(length=dims[1],width=dims[2],height=dims[3],name=name) str.Placement = dims[0] elif tp == "Wall": FreeCAD.ActiveDocument.removeObject(name) import ArchWall length = dims[1] width = dims[2] v1 = Vector(length/2,0,0) v2 = DraftVecUtils.neg(v1) v1 = dims[0].multVec(v1) v2 = dims[0].multVec(v2) line = Draft.makeLine(v1,v2) wal = ArchWall.makeWall(line,width=width,height=dims[3],name=name) else: if mark: obj.ViewObject.ShapeColor = (1.0,0.0,0.0,1.0)
def makeStairsTread(self,basepoint,depthvec,widthvec,nosing=0,thickness=0): "returns the shape of a single tread" import Part if thickness: basepoint = basepoint.add(Vector(0,0,-abs(thickness))) if nosing: nosevec = DraftVecUtils.scaleTo(DraftVecUtils.neg(depthvec),nosing) else: nosevec = Vector(0,0,0) p1 = basepoint.add(nosevec) p2 = p1.add(DraftVecUtils.neg(nosevec)).add(depthvec) p3 = p2.add(widthvec) p4 = p3.add(DraftVecUtils.neg(depthvec)).add(nosevec) step = Part.Face(Part.makePolygon([p1,p2,p3,p4,p1])) if thickness: step = step.extrude(Vector(0,0,abs(thickness))) return step
def getClosestAxis(self, point): "returns which of the workingplane axes is closest from the given vector" ax = point.getAngle(self.u) ay = point.getAngle(self.v) az = point.getAngle(self.axis) bx = point.getAngle(DraftVecUtils.neg(self.u)) by = point.getAngle(DraftVecUtils.neg(self.v)) bz = point.getAngle(DraftVecUtils.neg(self.axis)) b = min(ax, ay, az, bx, by, bz) if b in [ax, bx]: return "x" elif b in [ay, by]: return "y" elif b in [az, bz]: return "z" else: return None
def calc(self): import Part if (self.p1 != None) and (self.p2 != None): points = [DraftVecUtils.tup(self.p1,True),DraftVecUtils.tup(self.p2,True),\ DraftVecUtils.tup(self.p1,True),DraftVecUtils.tup(self.p2,True)] if self.p3 != None: p1 = self.p1 p4 = self.p2 if DraftVecUtils.equals(p1,p4): proj = None else: base = Part.Line(p1,p4).toShape() proj = DraftGeomUtils.findDistance(self.p3,base) if not proj: p2 = p1 p3 = p4 else: p2 = p1.add(DraftVecUtils.neg(proj)) p3 = p4.add(DraftVecUtils.neg(proj)) points = [DraftVecUtils.tup(p1),DraftVecUtils.tup(p2),DraftVecUtils.tup(p3),DraftVecUtils.tup(p4)] self.coords.point.setValues(0,4,points)
def updateSVG(self, obj,join=False): "encapsulates a svg fragment into a transformation node" import Part, DraftGeomUtils if hasattr(obj,"Source"): if obj.Source: if obj.Source.Objects: objs = Draft.getGroupContents(obj.Source.Objects) svg = '' # generating SVG linewidth = obj.LineWidth/obj.Scale if obj.RenderingMode == "Solid": # render using the Arch Vector Renderer import ArchVRM render = ArchVRM.Renderer() render.setWorkingPlane(obj.Source.Placement) render.addObjects(Draft.getGroupContents(objs,walls=True)) render.cut(obj.Source.Shape) svg += render.getViewSVG(linewidth=linewidth) svg += render.getSectionSVG(linewidth=linewidth*2) # print render.info() else: # render using the Drawing module import Drawing shapes = [] for o in objs: if o.isDerivedFrom("Part::Feature"): shapes.append(o.Shape) if shapes: base = shape.pop() for sh in shapes: base = base.fuse(sh) svgf = Drawing.projectToSVG(base,DraftVecUtils.neg(direction)) if svgf: svgf = svgf.replace('stroke-width="0.35"','stroke-width="' + str(linewidth) + 'px"') svgf = svgf.replace('stroke-width:0.01','stroke-width:' + str(linewidth) + 'px') svg += svgf result = '' result += '<g id="' + obj.Name + '"' result += ' transform="' result += 'rotate('+str(obj.Rotation)+','+str(obj.X)+','+str(obj.Y)+') ' result += 'translate('+str(obj.X)+','+str(obj.Y)+') ' result += 'scale('+str(obj.Scale)+','+str(-obj.Scale)+')' result += '">\n' result += svg result += '</g>\n' # print "complete node:",result return result return ''
def projectPoint(self, p, direction=None): '''project point onto plane, default direction is orthogonal''' if not direction: direction = self.axis lp = self.getLocalCoords(p) gp = self.getGlobalCoords(Vector(lp.x, lp.y, 0)) a = direction.getAngle(gp.sub(p)) if a > math.pi / 2: direction = DraftVecUtils.neg(direction) a = math.pi - a ld = self.getLocalRot(direction) gd = self.getGlobalRot(Vector(ld.x, ld.y, 0)) hyp = abs(math.tan(a) * lp.z) return gp.add(DraftVecUtils.scaleTo(gd, hyp))
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 = DraftVecUtils.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 = DraftVecUtils.neg(dv) self.tracker.update([b.add(dv),point.add(dv)])
def projectPoint(self, p, direction=None): """project point onto plane, default direction is orthogonal""" if not direction: direction = self.axis lp = self.getLocalCoords(p) gp = self.getGlobalCoords(Vector(lp.x, lp.y, 0)) a = direction.getAngle(gp.sub(p)) if a > math.pi / 2: direction = DraftVecUtils.neg(direction) a = math.pi - a ld = self.getLocalRot(direction) gd = self.getGlobalRot(Vector(ld.x, ld.y, 0)) hyp = abs(math.tan(a) * lp.z) return gp.add(DraftVecUtils.scaleTo(gd, hyp))
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 = DraftVecUtils.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 = DraftVecUtils.neg(dv) self.tracker.update([b.add(dv), point.add(dv)])
def getCutVolume(cutplane, shapes): """getCutVolume(cutplane,shapes): returns a cut face and a cut volume from the given shapes and the given cutting plane""" import Part placement = FreeCAD.Placement(cutplane.Placement) # building boundbox bb = shapes[0].BoundBox for sh in shapes[1:]: bb.add(sh.BoundBox) bb.enlarge(1) um = vm = wm = 0 ax = placement.Rotation.multVec(FreeCAD.Vector(0, 0, 1)) u = placement.Rotation.multVec(FreeCAD.Vector(1, 0, 0)) v = placement.Rotation.multVec(FreeCAD.Vector(0, 1, 0)) if not bb.isCutPlane(placement.Base, ax): FreeCAD.Console.PrintMessage(str(translate("Arch", "No objects are cut by the plane"))) return None, None, None 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 = DraftVecUtils.project(dv, u).Length um = max(um, um1) vm1 = DraftVecUtils.project(dv, v).Length vm = max(vm, vm1) wm1 = DraftVecUtils.project(dv, ax).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 = DraftVecUtils.scaleTo(ax, wm) cutvolume = cutface.extrude(cutnormal) cutnormal = DraftVecUtils.neg(cutnormal) invcutvolume = cutface.extrude(cutnormal) return cutface, cutvolume, invcutvolume
def getCutVolume(cutplane, shapes): """getCutVolume(cutplane,shapes): returns a cut face and a cut volume from the given shapes and the given cutting plane""" import Part placement = FreeCAD.Placement(cutplane.Placement) # building boundbox bb = shapes[0].BoundBox for sh in shapes[1:]: bb.add(sh.BoundBox) bb.enlarge(1) um = vm = wm = 0 ax = placement.Rotation.multVec(FreeCAD.Vector(0, 0, 1)) u = placement.Rotation.multVec(FreeCAD.Vector(1, 0, 0)) v = placement.Rotation.multVec(FreeCAD.Vector(0, 1, 0)) if not bb.isCutPlane(placement.Base, ax): FreeCAD.Console.PrintMessage( str(translate("Arch", "No objects are cut by the plane"))) return None, None, None 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 = DraftVecUtils.project(dv, u).Length um = max(um, um1) vm1 = DraftVecUtils.project(dv, v).Length vm = max(vm, vm1) wm1 = DraftVecUtils.project(dv, ax).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 = DraftVecUtils.scaleTo(ax, wm) cutvolume = cutface.extrude(cutnormal) cutnormal = DraftVecUtils.neg(cutnormal) invcutvolume = cutface.extrude(cutnormal) return cutface, cutvolume, invcutvolume
def getSubVolume(self,base,width,plac=None): "returns a subvolume from a base object" import Part max_length = 0 f = None for w in base.Shape.Wires: if w.BoundBox.DiagonalLength > max_length: max_length = w.BoundBox.DiagonalLength f = w if f: f = Part.Face(f) n = f.normalAt(0,0) v1 = DraftVecUtils.scaleTo(n,width) f.translate(v1) v2 = DraftVecUtils.neg(v1) v2 = DraftVecUtils.scale(v1,-2) f = f.extrude(v2) if plac: f.Placement = plac return f return None
def getSubVolume(self, base, width, plac=None): "returns a subvolume from a base object" import Part max_length = 0 f = None for w in base.Shape.Wires: if w.BoundBox.DiagonalLength > max_length: max_length = w.BoundBox.DiagonalLength f = w if f: f = Part.Face(f) n = f.normalAt(0, 0) v1 = DraftVecUtils.scaleTo(n, width) f.translate(v1) v2 = DraftVecUtils.neg(v1) v2 = DraftVecUtils.scale(v1, -2) f = f.extrude(v2) if plac: f.Placement = plac return f return None
def getBrepFacesData(obj,scale=1): """getBrepFacesData(obj,[scale]): returns a list(0) of lists(1) of lists(2) of lists(3), list(3) being a list of vertices defining a loop, list(2) describing a face from one or more loops, list(1) being the whole solid made of several faces, list(0) being the list of solids inside the object. Scale can indicate a scaling factor""" if hasattr(obj,"Shape"): if obj.Shape: if not obj.Shape.isNull(): if obj.Shape.isValid(): sols = [] for sol in obj.Shape.Solids: s = [] for face in obj.Shape.Faces: f = [] f.append(getTuples(face.OuterWire,scale,normal=face.normalAt(0,0),close=False)) for wire in face.Wires: if wire.hashCode() != face.OuterWire.hashCode(): f.append(getTuples(wire,scale,normal=DraftVecUtils.neg(face.normalAt(0,0)),close=False)) s.append(f) sols.append(s) return sols return None
def getSubVolume(self,base,width,plac=None): "returns a subvolume from a base object" import Part,DraftVecUtils # finding biggest wire in the base shape max_length = 0 f = None for w in base.Shape.Wires: if w.BoundBox.DiagonalLength > max_length: max_length = w.BoundBox.DiagonalLength f = w if f: f = Part.Face(f) n = f.normalAt(0,0) v1 = DraftVecUtils.scaleTo(n,width*1.1) # we extrude a little more to avoid face-on-face f.translate(v1) v2 = DraftVecUtils.neg(v1) v2 = DraftVecUtils.scale(v1,-2) f = f.extrude(v2) if plac: f.Placement = plac return f return None
def getIfcBrepFacesData(obj,scale=1,tessellation=1): """getIfcBrepFacesData(obj,[scale,tesselation]): returns a list(0) of lists(1) of lists(2) of lists(3), list(3) being a list of vertices defining a loop, list(2) describing a face from one or more loops, list(1) being the whole solid made of several faces, list(0) being the list of solids inside the object. Scale can indicate a scaling factor. Tesselation is the tesselation factor to apply on curved faces.""" if hasattr(obj,"Shape"): import Part if obj.Shape: if not obj.Shape.isNull(): if obj.Shape.isValid(): sols = [] for sol in obj.Shape.Solids: s = [] curves = False for face in sol.Faces: for e in face.Edges: if not isinstance(e.Curve,Part.Line): curves = True if curves: tris = sol.tessellate(tessellation) for tri in tris[1]: f = [] for i in tri: f.append(getTuples(tris[0][i],scale)) s.append([f]) else: for face in sol.Faces: f = [] f.append(getTuples(face.OuterWire,scale,normal=face.normalAt(0,0),close=False)) for wire in face.Wires: if wire.hashCode() != face.OuterWire.hashCode(): f.append(getTuples(wire,scale,normal=DraftVecUtils.neg(face.normalAt(0,0)),close=False)) s.append(f) sols.append(s) return sols return None
def getRepresentation(ifcfile, context, obj, forcebrep=False, subtraction=False, tessellation=1): """returns an IfcShapeRepresentation object or None""" import Part, math, DraftGeomUtils, DraftVecUtils shapes = [] placement = None productdef = None shapetype = "no shape" if not forcebrep: profile = None if hasattr(obj, "Proxy"): if hasattr(obj.Proxy, "getProfiles"): p = obj.Proxy.getProfiles(obj, noplacement=True) extrusionv = obj.Proxy.getExtrusionVector(obj, noplacement=True) if (len(p) == 1) and extrusionv: p = p[0] r = obj.Proxy.getPlacement(obj) if len(p.Edges) == 1: pxvc = ifcfile.createIfcDirection((1.0, 0.0)) povc = ifcfile.createIfcCartesianPoint((0.0, 0.0)) pt = ifcfile.createIfcAxis2Placement2D(povc, pxvc) # extruded circle if isinstance(p.Edges[0].Curve, Part.Circle): profile = ifcfile.createIfcCircleProfileDef( "AREA", None, pt, p.Edges[0].Curve.Radius) # extruded ellipse elif isinstance(p.Edges[0].Curve, Part.Ellipse): profile = ifcfile.createIfcEllipseProfileDef( "AREA", None, pt, p.Edges[0].Curve.MajorRadius, p.Edges[0].Curve.MinorRadius) else: curves = False for e in p.Edges: if isinstance(e.Curve, Part.Circle): curves = True # extruded polyline if not curves: w = Part.Wire(DraftGeomUtils.sortEdges(p.Edges)) pts = [ ifcfile.createIfcCartesianPoint( tuple(v.Point)[:2]) for v in w.Vertexes + [w.Vertexes[0]] ] pol = ifcfile.createIfcPolyline(pts) # extruded composite curve else: segments = [] last = None edges = DraftGeomUtils.sortEdges(p.Edges) for e in edges: if isinstance(e.Curve, Part.Circle): follow = True if last: if not DraftVecUtils.equals( last, e.Vertexes[0].Point): follow = False last = e.Vertexes[0].Point else: last = e.Vertexes[-1].Point else: last = e.Vertexes[-1].Point p1 = math.degrees(-DraftVecUtils.angle( e.Vertexes[0].Point.sub( e.Curve.Center))) p2 = math.degrees(-DraftVecUtils.angle( e.Vertexes[-1].Point.sub( e.Curve.Center))) da = DraftVecUtils.angle( e.valueAt(e.FirstParameter + 0.1).sub( e.Curve.Center), e.Vertexes[0].Point.sub( e.Curve.Center)) if p1 < 0: p1 = 360 + p1 if p2 < 0: p2 = 360 + p2 if da > 0: follow = not (follow) xvc = ifcfile.createIfcDirection( (1.0, 0.0)) ovc = ifcfile.createIfcCartesianPoint( tuple(e.Curve.Center)[:2]) plc = ifcfile.createIfcAxis2Placement2D( ovc, xvc) cir = ifcfile.createIfcCircle( plc, e.Curve.Radius) curve = ifcfile.createIfcTrimmedCurve( cir, [ ifcfile.create_entity( "IfcParameterValue", p1) ], [ ifcfile.create_entity( "IfcParameterValue", p2) ], follow, "PARAMETER") else: verts = [ vertex.Point for vertex in e.Vertexes ] if last: if not DraftVecUtils.equals( last, verts[0]): verts.reverse() last = e.Vertexes[0].Point else: last = e.Vertexes[-1].Point else: last = e.Vertexes[-1].Point pts = [ ifcfile.createIfcCartesianPoint( tuple(v)[:2]) for v in verts ] curve = ifcfile.createIfcPolyline(pts) segment = ifcfile.createIfcCompositeCurveSegment( "CONTINUOUS", True, curve) segments.append(segment) pol = ifcfile.createIfcCompositeCurve( segments, False) profile = ifcfile.createIfcArbitraryClosedProfileDef( "AREA", None, pol) if profile: xvc = ifcfile.createIfcDirection( tuple(r.Rotation.multVec(FreeCAD.Vector(1, 0, 0)))) zvc = ifcfile.createIfcDirection( tuple(r.Rotation.multVec(FreeCAD.Vector(0, 0, 1)))) ovc = ifcfile.createIfcCartesianPoint(tuple(r.Base)) lpl = ifcfile.createIfcAxis2Placement3D(ovc, zvc, xvc) edir = ifcfile.createIfcDirection( tuple(FreeCAD.Vector(extrusionv).normalize())) shape = ifcfile.createIfcExtrudedAreaSolid(profile, lpl, edir, extrusionv.Length) shapes.append(shape) solidType = "SweptSolid" shapetype = "extrusion" if not shapes: # brep representation fcshape = None solidType = "Brep" if subtraction: if hasattr(obj, "Proxy"): if hasattr(obj.Proxy, "getSubVolume"): fcshape = obj.Proxy.getSubVolume(obj) if not fcshape: if hasattr(obj, "Shape"): if obj.Shape: if not obj.Shape.isNull(): fcshape = obj.Shape elif hasattr(obj, "Terrain"): if obj.Terrain: if hasattr(obj.Terrain, "Shape"): if obj.Terrain.Shape: if not obj.Terrain.Shape.isNull(): fcshape = obj.Terrain.Shape if fcshape: solids = [] if fcshape.Solids: dataset = fcshape.Solids else: dataset = fcshape.Shells print "Warning! object contains no solids" for fcsolid in dataset: faces = [] curves = False for fcface in fcsolid.Faces: for e in fcface.Edges: if not isinstance(e.Curve, Part.Line): curves = True if curves: tris = fcsolid.tessellate(tessellation) for tri in tris[1]: pts = [ ifcfile.createIfcCartesianPoint(tuple(tris[0][i])) for i in tri ] loop = ifcfile.createIfcPolyLoop(pts) bound = ifcfile.createIfcFaceOuterBound(loop, True) face = ifcfile.createIfcFace([bound]) faces.append(face) else: for fcface in fcsolid.Faces: loops = [] verts = [ v.Point for v in Part.Wire( DraftGeomUtils.sortEdges( fcface.OuterWire.Edges)).Vertexes ] c = fcface.CenterOfMass v1 = verts[0].sub(c) v2 = verts[1].sub(c) n = fcface.normalAt(0, 0) if DraftVecUtils.angle(v2, v1, n) >= 0: verts.reverse( ) # inverting verts order if the direction is couterclockwise pts = [ ifcfile.createIfcCartesianPoint(tuple(v)) for v in verts ] loop = ifcfile.createIfcPolyLoop(pts) bound = ifcfile.createIfcFaceOuterBound(loop, True) loops.append(bound) for wire in fcface.Wires: if wire.hashCode() != fcface.OuterWire.hashCode(): verts = [ v.Point for v in Part.Wire( DraftGeomUtils.sortEdges( wire.Edges)).Vertexes ] v1 = verts[0].sub(c) v2 = verts[1].sub(c) if DraftVecUtils.angle( v2, v1, DraftVecUtils.neg(n)) >= 0: verts.reverse() pts = [ ifcfile.createIfcCartesianPoint(tuple(v)) for v in verts ] loop = ifcfile.createIfcPolyLoop(pts) bound = ifcfile.createIfcFaceBound(loop, True) loops.append(bound) face = ifcfile.createIfcFace(loops) faces.append(face) shell = ifcfile.createIfcClosedShell(faces) shape = ifcfile.createIfcFacetedBrep(shell) shapes.append(shape) shapetype = "brep" if shapes: if FreeCAD.GuiUp and (not subtraction) and hasattr( obj.ViewObject, "ShapeColor"): rgb = obj.ViewObject.ShapeColor col = ifcfile.createIfcColourRgb(None, rgb[0], rgb[1], rgb[2]) ssr = ifcfile.createIfcSurfaceStyleRendering( col, None, None, None, None, None, None, None, "FLAT") iss = ifcfile.createIfcSurfaceStyle(None, "BOTH", [ssr]) psa = ifcfile.createIfcPresentationStyleAssignment([iss]) for shape in shapes: isi = ifcfile.createIfcStyledItem(shape, [psa], None) xvc = ifcfile.createIfcDirection((1.0, 0.0, 0.0)) zvc = ifcfile.createIfcDirection((0.0, 0.0, 1.0)) ovc = ifcfile.createIfcCartesianPoint((0.0, 0.0, 0.0)) gpl = ifcfile.createIfcAxis2Placement3D(ovc, zvc, xvc) placement = ifcfile.createIfcLocalPlacement(None, gpl) representation = ifcfile.createIfcShapeRepresentation( context, 'Body', solidType, shapes) productdef = ifcfile.createIfcProductDefinitionShape( None, None, [representation]) return productdef, placement, shapetype
def makeStraightStairs(self,obj,edge,numberofsteps=None): "builds a simple, straight staircase from a straight edge" # general data import Part,DraftGeomUtils if not numberofsteps: numberofsteps = obj.NumberOfSteps v = DraftGeomUtils.vec(edge) vLength = DraftVecUtils.scaleTo(v,float(edge.Length)/(numberofsteps-1)) vLength = Vector(vLength.x,vLength.y,0) if round(v.z,Draft.precision()) != 0: h = v.z else: h = obj.Height.Value vHeight = Vector(0,0,float(h)/numberofsteps) vWidth = DraftVecUtils.scaleTo(vLength.cross(Vector(0,0,1)),obj.Width.Value) vBase = edge.Vertexes[0].Point vNose = DraftVecUtils.scaleTo(vLength,-abs(obj.Nosing.Value)) a = math.atan(vHeight.Length/vLength.Length) #print "stair data:",vLength.Length,":",vHeight.Length # steps for i in range(numberofsteps-1): p1 = vBase.add((Vector(vLength).multiply(i)).add(Vector(vHeight).multiply(i+1))) p1 = self.align(p1,obj.Align,vWidth) p1 = p1.add(vNose).add(Vector(0,0,-abs(obj.TreadThickness.Value))) p2 = p1.add(DraftVecUtils.neg(vNose)).add(vLength) p3 = p2.add(vWidth) p4 = p3.add(DraftVecUtils.neg(vLength)).add(vNose) step = Part.Face(Part.makePolygon([p1,p2,p3,p4,p1])) if obj.TreadThickness.Value: step = step.extrude(Vector(0,0,abs(obj.TreadThickness.Value))) self.steps.append(step) else: self.pseudosteps.append(step) # structure lProfile = [] struct = None if obj.Structure == "Massive": if obj.StructureThickness.Value: for i in range(numberofsteps-1): if not lProfile: lProfile.append(vBase) last = lProfile[-1] if len(lProfile) == 1: last = last.add(Vector(0,0,-abs(obj.TreadThickness.Value))) lProfile.append(last.add(vHeight)) lProfile.append(lProfile[-1].add(vLength)) resHeight1 = obj.StructureThickness.Value/math.cos(a) lProfile.append(lProfile[-1].add(Vector(0,0,-resHeight1))) resHeight2 = ((numberofsteps-1)*vHeight.Length)-(resHeight1+obj.TreadThickness.Value) resLength = (vLength.Length/vHeight.Length)*resHeight2 h = DraftVecUtils.scaleTo(vLength,-resLength) lProfile.append(lProfile[-1].add(Vector(h.x,h.y,-resHeight2))) lProfile.append(vBase) #print lProfile pol = Part.makePolygon(lProfile) struct = Part.Face(pol) evec = vWidth if obj.StructureOffset.Value: mvec = DraftVecUtils.scaleTo(vWidth,obj.StructureOffset.Value) struct.translate(mvec) evec = DraftVecUtils.scaleTo(evec,evec.Length-(2*mvec.Length)) struct = struct.extrude(evec) elif obj.Structure in ["One stringer","Two stringers"]: if obj.StringerWidth.Value and obj.StructureThickness.Value: hyp = math.sqrt(vHeight.Length**2 + vLength.Length**2) l1 = Vector(vLength).multiply(numberofsteps-1) h1 = Vector(vHeight).multiply(numberofsteps-1).add(Vector(0,0,-abs(obj.TreadThickness.Value))) p1 = vBase.add(l1).add(h1) p1 = self.align(p1,obj.Align,vWidth) lProfile.append(p1) h2 = (obj.StructureThickness.Value/vLength.Length)*hyp lProfile.append(lProfile[-1].add(Vector(0,0,-abs(h2)))) h3 = lProfile[-1].z-vBase.z l3 = (h3/vHeight.Length)*vLength.Length v3 = DraftVecUtils.scaleTo(vLength,-l3) lProfile.append(lProfile[-1].add(Vector(0,0,-abs(h3))).add(v3)) l4 = (obj.StructureThickness.Value/vHeight.Length)*hyp v4 = DraftVecUtils.scaleTo(vLength,-l4) lProfile.append(lProfile[-1].add(v4)) lProfile.append(lProfile[0]) #print lProfile pol = Part.makePolygon(lProfile) pol = Part.Face(pol) evec = DraftVecUtils.scaleTo(vWidth,obj.StringerWidth.Value) if obj.Structure == "One stringer": if obj.StructureOffset.Value: mvec = DraftVecUtils.scaleTo(vWidth,obj.StructureOffset.Value) else: mvec = DraftVecUtils.scaleTo(vWidth,(vWidth.Length/2)-obj.StringerWidth.Value/2) pol.translate(mvec) struct = pol.extrude(evec) elif obj.Structure == "Two stringers": pol2 = pol.copy() if obj.StructureOffset.Value: mvec = DraftVecUtils.scaleTo(vWidth,obj.StructureOffset.Value) pol.translate(mvec) mvec = vWidth.add(mvec.negative()) pol2.translate(mvec) else: pol2.translate(vWidth) s1 = pol.extrude(evec) s2 = pol2.extrude(evec.negative()) struct = Part.makeCompound([s1,s2]) if struct: self.structures.append(struct)
def makeStraightLanding(self,obj,edge,numberofsteps=None): "builds a landing from a straight edge" # general data if not numberofsteps: numberofsteps = obj.NumberOfSteps import Part,DraftGeomUtils v = DraftGeomUtils.vec(edge) vLength = Vector(v.x,v.y,0) vWidth = vWidth = DraftVecUtils.scaleTo(vLength.cross(Vector(0,0,1)),obj.Width.Value) vBase = edge.Vertexes[0].Point vNose = DraftVecUtils.scaleTo(vLength,-abs(obj.Nosing.Value)) h = obj.Height.Value l = obj.Length.Value if obj.Base: if obj.Base.isDerivedFrom("Part::Feature"): l = obj.Base.Shape.Length if obj.Base.Shape.BoundBox.ZLength: h = obj.Base.Shape.BoundBox.ZLength fLength = float(l-obj.Width.Value)/(numberofsteps-2) fHeight = float(h)/numberofsteps a = math.atan(fHeight/fLength) print "landing data:",fLength,":",fHeight # step p1 = self.align(vBase,obj.Align,vWidth) p1 = p1.add(vNose).add(Vector(0,0,-abs(obj.TreadThickness.Value))) p2 = p1.add(DraftVecUtils.neg(vNose)).add(vLength) p3 = p2.add(vWidth) p4 = p3.add(DraftVecUtils.neg(vLength)).add(vNose) step = Part.Face(Part.makePolygon([p1,p2,p3,p4,p1])) if obj.TreadThickness.Value: step = step.extrude(Vector(0,0,abs(obj.TreadThickness.Value))) self.steps.append(step) else: self.pseudosteps.append(step) # structure lProfile = [] struct = None p7 = None p1 = p1.add(DraftVecUtils.neg(vNose)) p2 = p1.add(Vector(0,0,-fHeight)).add(Vector(0,0,-obj.StructureThickness.Value/math.cos(a))) resheight = p1.sub(p2).Length - obj.StructureThickness.Value reslength = resheight / math.tan(a) p3 = p2.add(DraftVecUtils.scaleTo(vLength,reslength)).add(Vector(0,0,resheight)) p6 = p1.add(vLength) if obj.TreadThickness.Value: p7 = p6.add(Vector(0,0,obj.TreadThickness.Value)) reslength = fLength + (obj.StructureThickness.Value/math.sin(a)-(fHeight-obj.TreadThickness.Value)/math.tan(a)) if p7: p5 = p7.add(DraftVecUtils.scaleTo(vLength,reslength)) else: p5 = p6.add(DraftVecUtils.scaleTo(vLength,reslength)) resheight = obj.StructureThickness.Value + obj.TreadThickness.Value reslength = resheight/math.tan(a) p4 = p5.add(DraftVecUtils.scaleTo(vLength,-reslength)).add(Vector(0,0,-resheight)) if obj.Structure == "Massive": if obj.StructureThickness.Value: if p7: struct = Part.Face(Part.makePolygon([p1,p2,p3,p4,p5,p7,p6,p1])) else: struct = Part.Face(Part.makePolygon([p1,p2,p3,p4,p5,p6,p1])) evec = vWidth if obj.StructureOffset.Value: mvec = DraftVecUtils.scaleTo(vWidth,obj.StructureOffset.Value) struct.translate(mvec) evec = DraftVecUtils.scaleTo(evec,evec.Length-(2*mvec.Length)) struct = struct.extrude(evec) elif obj.Structure in ["One stringer","Two stringers"]: if obj.StringerWidth.Value and obj.StructureThickness.Value: p1b = p1.add(Vector(0,0,-fHeight)) reslength = fHeight/math.tan(a) p1c = p1.add(DraftVecUtils.scaleTo(vLength,reslength)) p5b = None p5c = None if obj.TreadThickness.Value: reslength = obj.StructureThickness.Value/math.sin(a) p5b = p5.add(DraftVecUtils.scaleTo(vLength,-reslength)) reslength = obj.TreadThickness.Value/math.tan(a) p5c = p5b.add(DraftVecUtils.scaleTo(vLength,-reslength)).add(Vector(0,0,-obj.TreadThickness.Value)) pol = Part.Face(Part.makePolygon([p1c,p1b,p2,p3,p4,p5,p5b,p5c,p1c])) else: pol = Part.Face(Part.makePolygon([p1c,p1b,p2,p3,p4,p5,p1c])) evec = DraftVecUtils.scaleTo(vWidth,obj.StringerWidth.Value) if obj.Structure == "One stringer": if obj.StructureOffset.Value: mvec = DraftVecUtils.scaleTo(vWidth,obj.StructureOffset.Value) else: mvec = DraftVecUtils.scaleTo(vWidth,(vWidth.Length/2)-obj.StringerWidth.Value/2) pol.translate(mvec) struct = pol.extrude(evec) elif obj.Structure == "Two stringers": pol2 = pol.copy() if obj.StructureOffset.Value: mvec = DraftVecUtils.scaleTo(vWidth,obj.StructureOffset.Value) pol.translate(mvec) mvec = vWidth.add(mvec.negative()) pol2.translate(mvec) else: pol2.translate(vWidth) s1 = pol.extrude(evec) s2 = pol2.extrude(evec.negative()) struct = Part.makeCompound([s1,s2]) if struct: self.structures.append(struct)
def makeStraightStairs(self, obj, edge, numberofsteps=None): "builds a simple, straight staircase from a straight edge" # general data import Part, DraftGeomUtils if not numberofsteps: numberofsteps = obj.NumberOfSteps v = DraftGeomUtils.vec(edge) vLength = DraftVecUtils.scaleTo( v, float(edge.Length) / (numberofsteps - 1)) vLength = Vector(vLength.x, vLength.y, 0) if round(v.z, Draft.precision()) != 0: h = v.z else: h = obj.Height vHeight = Vector(0, 0, float(h) / numberofsteps) vWidth = DraftVecUtils.scaleTo(vLength.cross(Vector(0, 0, 1)), obj.Width) vBase = edge.Vertexes[0].Point vNose = DraftVecUtils.scaleTo(vLength, -abs(obj.Nosing)) a = math.atan(vHeight.Length / vLength.Length) print "stair data:", vLength.Length, ":", vHeight.Length # steps for i in range(numberofsteps - 1): p1 = vBase.add((Vector(vLength).multiply(i)).add( Vector(vHeight).multiply(i + 1))) p1 = self.align(p1, obj.Align, vWidth) p1 = p1.add(vNose).add(Vector(0, 0, -abs(obj.TreadThickness))) p2 = p1.add(DraftVecUtils.neg(vNose)).add(vLength) p3 = p2.add(vWidth) p4 = p3.add(DraftVecUtils.neg(vLength)).add(vNose) step = Part.Face(Part.makePolygon([p1, p2, p3, p4, p1])) if obj.TreadThickness: step = step.extrude(Vector(0, 0, abs(obj.TreadThickness))) self.steps.append(step) # structure lProfile = [] struct = None if obj.Structure == "Massive": if obj.StructureThickness: for i in range(numberofsteps - 1): if not lProfile: lProfile.append(vBase) last = lProfile[-1] if len(lProfile) == 1: last = last.add(Vector(0, 0, -abs(obj.TreadThickness))) lProfile.append(last.add(vHeight)) lProfile.append(lProfile[-1].add(vLength)) resHeight1 = obj.StructureThickness / math.cos(a) lProfile.append(lProfile[-1].add(Vector(0, 0, -resHeight1))) resHeight2 = ((numberofsteps - 1) * vHeight.Length) - ( resHeight1 + obj.TreadThickness) resLength = (vLength.Length / vHeight.Length) * resHeight2 h = DraftVecUtils.scaleTo(vLength, -resLength) lProfile.append(lProfile[-1].add(Vector(h.x, h.y, -resHeight2))) lProfile.append(vBase) #print lProfile pol = Part.makePolygon(lProfile) struct = Part.Face(pol) evec = vWidth if obj.StructureOffset: mvec = DraftVecUtils.scaleTo(vWidth, obj.StructureOffset) struct.translate(mvec) evec = DraftVecUtils.scaleTo( evec, evec.Length - (2 * mvec.Length)) struct = struct.extrude(evec) elif obj.Structure in ["One stringer", "Two stringers"]: if obj.StringerWidth and obj.StructureThickness: hyp = math.sqrt(vHeight.Length**2 + vLength.Length**2) l1 = Vector(vLength).multiply(numberofsteps - 1) h1 = Vector(vHeight).multiply(numberofsteps - 1).add( Vector(0, 0, -abs(obj.TreadThickness))) p1 = vBase.add(l1).add(h1) p1 = self.align(p1, obj.Align, vWidth) lProfile.append(p1) h2 = (obj.StructureThickness / vLength.Length) * hyp lProfile.append(lProfile[-1].add(Vector(0, 0, -abs(h2)))) h3 = lProfile[-1].z - vBase.z l3 = (h3 / vHeight.Length) * vLength.Length v3 = DraftVecUtils.scaleTo(vLength, -l3) lProfile.append(lProfile[-1].add(Vector(0, 0, -abs(h3))).add(v3)) l4 = (obj.StructureThickness / vHeight.Length) * hyp v4 = DraftVecUtils.scaleTo(vLength, -l4) lProfile.append(lProfile[-1].add(v4)) lProfile.append(lProfile[0]) #print lProfile pol = Part.makePolygon(lProfile) pol = Part.Face(pol) evec = DraftVecUtils.scaleTo(vWidth, obj.StringerWidth) if obj.Structure == "One stringer": if obj.StructureOffset: mvec = DraftVecUtils.scaleTo(vWidth, obj.StructureOffset) else: mvec = DraftVecUtils.scaleTo(vWidth, (vWidth.Length / 2) - obj.StringerWidth / 2) pol.translate(mvec) struct = pol.extrude(evec) elif obj.Structure == "Two stringers": pol2 = pol.copy() if obj.StructureOffset: mvec = DraftVecUtils.scaleTo(vWidth, obj.StructureOffset) pol.translate(mvec) mvec = vWidth.add(mvec.negative()) pol2.translate(mvec) else: pol2.translate(vWidth) s1 = pol.extrude(evec) s2 = pol2.extrude(evec.negative()) struct = Part.makeCompound([s1, s2]) if struct: self.structures.append(struct)
def makeMultiEdgesLanding(self, obj, edges): "builds a 'multi-edges' landing from edges" # 'copying' from makeStraightLanding() import Part, DraftGeomUtils v, vLength, vWidth, vBase = [], [], [], [] p1o, p2o, p1, p2, p3, p4 = [], [], [], [], [], [] outline, outlineP1P2, outlineP3P4 = [], [], [] enum_edges = enumerate(edges) for i, edge in enum_edges: v.append(DraftGeomUtils.vec(edge)) vLength.append(Vector(v[i].x, v[i].y, 0)) # TODO obj.Width[i].Value for different 'edges' / 'sections' of the landing vWidth.append( DraftVecUtils.scaleTo(vLength[i].cross(Vector(0, 0, 1)), obj.Width.Value)) vBase.append(edges[i].Vertexes[0].Point) vBase[i] = self.vbaseFollowLastSement(obj, vBase[i]) # step + structure # assume all left-align first # no nosing p1o.append(vBase[i].add( Vector(0, 0, -abs(obj.TreadThickness.Value)))) p2o.append(p1o[i].add(vLength[i])) p1.append( self.align(vBase[i], obj.Align, vWidth[i]).add( Vector(0, 0, -abs(obj.TreadThickness.Value)))) p2.append(p1[i].add(vLength[i])) p3.append(p2[i].add(vWidth[i])) p4.append(p3[i].add(DraftVecUtils.neg(vLength[i]))) if obj.Align == 'Left': outlineP1P2.append(p1[i]) outlineP1P2.append( p2[i] ) # can better skip 1 'supposedly' overlapping point every pair? if i > 0: print("Debug - intersection calculation") print(p3[i - 1]) print(p4[i - 1]) print(p3[i]) print(p4[i]) intersection = DraftGeomUtils.findIntersection( p3[i - 1], p4[i - 1], p3[i], p4[i], True, True) print(intersection) outlineP3P4.insert(0, intersection[0]) else: outlineP3P4.insert(0, p4[i]) elif obj.Align == 'Right': if i > 0: intersection = DraftGeomUtils.findIntersection( p1[i - 1], p2[i - 1], p1[i], p2[i], True, True) outlineP1P2.append(intersection[0]) else: outlineP1P2.append(p1[i]) outlineP3P4.insert(0, p4[i]) outlineP3P4.insert(0, p3[i]) elif obj.Align == 'Center': if i > 0: intersection = DraftGeomUtils.findIntersection( p1[i - 1], p2[i - 1], p1[i], p2[i], True, True) outlineP1P2.append(intersection[0]) intersection = DraftGeomUtils.findIntersection( p3[i - 1], p4[i - 1], p3[i], p4[i], True, True) outlineP3P4.insert(0, intersection[0]) else: outlineP1P2.append(p1[i]) outlineP3P4.insert(0, p4[i]) else: outlineP1P2.append(p1[i]) outlineP1P2.append(p2[i]) outlineP3P4.insert(0, p4[i]) outlineP3P4.insert(0, p3[i]) # add back last/first 'missing' point(s) if obj.Align in ['Left', 'Center']: outlineP3P4.insert(0, p3[i]) if obj.Align in ['Right', 'Center']: outlineP1P2.append(p2[i]) outline = outlineP1P2 + outlineP3P4 outline.append(p1[0]) print(outlineP1P2) print(outlineP3P4) print(outline) stepFace = Part.Face(Part.makePolygon(outline)) if obj.TreadThickness.Value: step = stepFace.extrude(Vector(0, 0, abs(obj.TreadThickness.Value))) self.steps.append(step) else: self.pseudosteps.append(stepFace) if obj.StructureThickness.Value: landingFace = stepFace struct = landingFace.extrude( Vector(0, 0, -abs(obj.StructureThickness.Value))) if struct: self.structures.append(struct) obj.AbsTop = vBase[1]
def getRepresentation(ifcfile,context,obj,forcebrep=False,subtraction=False,tessellation=1): """returns an IfcShapeRepresentation object or None""" import Part,math,DraftGeomUtils,DraftVecUtils shapes = [] placement = None productdef = None shapetype = "no shape" if not forcebrep: profile = None if hasattr(obj,"Proxy"): if hasattr(obj.Proxy,"getProfiles"): p = obj.Proxy.getProfiles(obj,noplacement=True) extrusionv = obj.Proxy.getExtrusionVector(obj,noplacement=True) if (len(p) == 1) and extrusionv: p = p[0] r = obj.Proxy.getPlacement(obj) if len(p.Edges) == 1: pxvc = ifcfile.createIfcDirection((1.0,0.0)) povc = ifcfile.createIfcCartesianPoint((0.0,0.0)) pt = ifcfile.createIfcAxis2Placement2D(povc,pxvc) # extruded circle if isinstance(p.Edges[0].Curve,Part.Circle): profile = ifcfile.createIfcCircleProfileDef("AREA",None,pt, p.Edges[0].Curve.Radius) # extruded ellipse elif isinstance(p.Edges[0].Curve,Part.Ellipse): profile = ifcfile.createIfcEllipseProfileDef("AREA",None,pt, p.Edges[0].Curve.MajorRadius, p.Edges[0].Curve.MinorRadius) else: curves = False for e in p.Edges: if isinstance(e.Curve,Part.Circle): curves = True # extruded polyline if not curves: w = Part.Wire(DraftGeomUtils.sortEdges(p.Edges)) pts = [ifcfile.createIfcCartesianPoint(tuple(v.Point)[:2]) for v in w.Vertexes+[w.Vertexes[0]]] pol = ifcfile.createIfcPolyline(pts) # extruded composite curve else: segments = [] last = None edges = DraftGeomUtils.sortEdges(p.Edges) for e in edges: if isinstance(e.Curve,Part.Circle): follow = True if last: if not DraftVecUtils.equals(last,e.Vertexes[0].Point): follow = False last = e.Vertexes[0].Point else: last = e.Vertexes[-1].Point else: last = e.Vertexes[-1].Point p1 = math.degrees(-DraftVecUtils.angle(e.Vertexes[0].Point.sub(e.Curve.Center))) p2 = math.degrees(-DraftVecUtils.angle(e.Vertexes[-1].Point.sub(e.Curve.Center))) da = DraftVecUtils.angle(e.valueAt(e.FirstParameter+0.1).sub(e.Curve.Center),e.Vertexes[0].Point.sub(e.Curve.Center)) if p1 < 0: p1 = 360 + p1 if p2 < 0: p2 = 360 + p2 if da > 0: follow = not(follow) xvc = ifcfile.createIfcDirection((1.0,0.0)) ovc = ifcfile.createIfcCartesianPoint(tuple(e.Curve.Center)[:2]) plc = ifcfile.createIfcAxis2Placement2D(ovc,xvc) cir = ifcfile.createIfcCircle(plc,e.Curve.Radius) curve = ifcfile.createIfcTrimmedCurve(cir,[ifcfile.create_entity("IfcParameterValue",p1)],[ifcfile.create_entity("IfcParameterValue",p2)],follow,"PARAMETER") else: verts = [vertex.Point for vertex in e.Vertexes] if last: if not DraftVecUtils.equals(last,verts[0]): verts.reverse() last = e.Vertexes[0].Point else: last = e.Vertexes[-1].Point else: last = e.Vertexes[-1].Point pts = [ifcfile.createIfcCartesianPoint(tuple(v)[:2]) for v in verts] curve = ifcfile.createIfcPolyline(pts) segment = ifcfile.createIfcCompositeCurveSegment("CONTINUOUS",True,curve) segments.append(segment) pol = ifcfile.createIfcCompositeCurve(segments,False) profile = ifcfile.createIfcArbitraryClosedProfileDef("AREA",None,pol) if profile: xvc = ifcfile.createIfcDirection(tuple(r.Rotation.multVec(FreeCAD.Vector(1,0,0)))) zvc = ifcfile.createIfcDirection(tuple(r.Rotation.multVec(FreeCAD.Vector(0,0,1)))) ovc = ifcfile.createIfcCartesianPoint(tuple(r.Base)) lpl = ifcfile.createIfcAxis2Placement3D(ovc,zvc,xvc) edir = ifcfile.createIfcDirection(tuple(FreeCAD.Vector(extrusionv).normalize())) shape = ifcfile.createIfcExtrudedAreaSolid(profile,lpl,edir,extrusionv.Length) shapes.append(shape) solidType = "SweptSolid" shapetype = "extrusion" if not shapes: # brep representation fcshape = None solidType = "Brep" if subtraction: if hasattr(obj,"Proxy"): if hasattr(obj.Proxy,"getSubVolume"): fcshape = obj.Proxy.getSubVolume(obj) if not fcshape: if hasattr(obj,"Shape"): if obj.Shape: if not obj.Shape.isNull(): fcshape = obj.Shape elif hasattr(obj,"Terrain"): if obj.Terrain: if hasattr(obj.Terrain,"Shape"): if obj.Terrain.Shape: if not obj.Terrain.Shape.isNull(): fcshape = obj.Terrain.Shape if fcshape: solids = [] if fcshape.Solids: dataset = fcshape.Solids else: dataset = fcshape.Shells print "Warning! object contains no solids" for fcsolid in dataset: faces = [] curves = False for fcface in fcsolid.Faces: for e in fcface.Edges: if not isinstance(e.Curve,Part.Line): curves = True if curves: tris = fcsolid.tessellate(tessellation) for tri in tris[1]: pts = [ifcfile.createIfcCartesianPoint(tuple(tris[0][i])) for i in tri] loop = ifcfile.createIfcPolyLoop(pts) bound = ifcfile.createIfcFaceOuterBound(loop,True) face = ifcfile.createIfcFace([bound]) faces.append(face) else: for fcface in fcsolid.Faces: loops = [] verts = [v.Point for v in Part.Wire(DraftGeomUtils.sortEdges(fcface.OuterWire.Edges)).Vertexes] c = fcface.CenterOfMass v1 = verts[0].sub(c) v2 = verts[1].sub(c) n = fcface.normalAt(0,0) if DraftVecUtils.angle(v2,v1,n) >= 0: verts.reverse() # inverting verts order if the direction is couterclockwise pts = [ifcfile.createIfcCartesianPoint(tuple(v)) for v in verts] loop = ifcfile.createIfcPolyLoop(pts) bound = ifcfile.createIfcFaceOuterBound(loop,True) loops.append(bound) for wire in fcface.Wires: if wire.hashCode() != fcface.OuterWire.hashCode(): verts = [v.Point for v in Part.Wire(DraftGeomUtils.sortEdges(wire.Edges)).Vertexes] v1 = verts[0].sub(c) v2 = verts[1].sub(c) if DraftVecUtils.angle(v2,v1,DraftVecUtils.neg(n)) >= 0: verts.reverse() pts = [ifcfile.createIfcCartesianPoint(tuple(v)) for v in verts] loop = ifcfile.createIfcPolyLoop(pts) bound = ifcfile.createIfcFaceBound(loop,True) loops.append(bound) face = ifcfile.createIfcFace(loops) faces.append(face) shell = ifcfile.createIfcClosedShell(faces) shape = ifcfile.createIfcFacetedBrep(shell) shapes.append(shape) shapetype = "brep" if shapes: if FreeCAD.GuiUp and (not subtraction) and hasattr(obj.ViewObject,"ShapeColor"): rgb = obj.ViewObject.ShapeColor col = ifcfile.createIfcColourRgb(None,rgb[0],rgb[1],rgb[2]) ssr = ifcfile.createIfcSurfaceStyleRendering(col,None,None,None,None,None,None,None,"FLAT") iss = ifcfile.createIfcSurfaceStyle(None,"BOTH",[ssr]) psa = ifcfile.createIfcPresentationStyleAssignment([iss]) for shape in shapes: isi = ifcfile.createIfcStyledItem(shape,[psa],None) xvc = ifcfile.createIfcDirection((1.0,0.0,0.0)) zvc = ifcfile.createIfcDirection((0.0,0.0,1.0)) ovc = ifcfile.createIfcCartesianPoint((0.0,0.0,0.0)) gpl = ifcfile.createIfcAxis2Placement3D(ovc,zvc,xvc) placement = ifcfile.createIfcLocalPlacement(None,gpl) representation = ifcfile.createIfcShapeRepresentation(context,'Body',solidType,shapes) productdef = ifcfile.createIfcProductDefinitionShape(None,None,[representation]) return productdef,placement,shapetype
def __init__(self, size, length, shaft_l, circle_r, circle_h, name="nemamotor", chmf=1, rshaft_l=0, bolt_depth=3, bolt_out=2, container=1, normal=VZ, pos=V0): doc = FreeCAD.ActiveDocument self.base_place = (0, 0, 0) self.size = size self.width = kcomp.NEMA_W[size] self.length = length self.shaft_l = shaft_l self.circle_r = circle_r self.circle_h = circle_h self.chmf = chmf self.rshaft_l = rshaft_l self.bolt_depth = bolt_depth self.bolt_out = bolt_out self.container = container nnormal = DraftVecUtils.scaleTo(normal, 1) self.normal = nnormal self.pos = pos nemabolt_d = kcomp.NEMA_BOLT_D[size] self.nemabolt_d = nemabolt_d mtol = kcomp.TOL - 0.1 lnormal = DraftVecUtils.scaleTo(nnormal, length) neg_lnormal = DraftVecUtils.neg(lnormal) # motor shape v1 = FreeCAD.Vector(self.width / 2. - chmf, self.width / 2., 0) v2 = FreeCAD.Vector(self.width / 2., self.width / 2. - chmf, 0) motorwire = fcfun.wire_sim_xy([v1, v2]) # motor wire normal is VZ # DraftVecUtils doesnt work as well # rot = DraftVecUtils.getRotation(VZ, nnormal) # the order matter VZ, nnormal. It seems it doent matter VZ or VZN # this is valid: #rot = DraftGeomUtils.getRotation(VZ,nnormal) #print rot rot = FreeCAD.Rotation(VZ, nnormal) print rot motorwire.Placement.Rotation = rot motorwire.Placement.Base = pos motorface = Part.Face(motorwire) shp_motorbox = motorface.extrude(neg_lnormal) # shaft shape if rshaft_l == 0: # no rear shaft shp_shaft = fcfun.shp_cyl(r=kcomp.NEMA_SHAFT_D[size] / 2., h=shaft_l, normal=nnormal, pos=pos) else: rshaft_posend = DraftVecUtils.scaleTo(neg_lnormal, rshaft_l + length) shp_shaft = fcfun.shp_cyl(r=kcomp.NEMA_SHAFT_D[size] / 2., h=shaft_l + rshaft_l + length, normal=nnormal, pos=pos + rshaft_posend) shp_motorshaft = shp_motorbox.fuse(shp_shaft) # Bolt holes # AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA # There is something wrong with the position of these bolts # bhole00_pos = FreeCAD.Vector(-kcomp.NEMA_BOLT_SEP[size]/2, # -kcomp.NEMA_BOLT_SEP[size]/2, # -bolt_depth) + pos # bhole01_pos = FreeCAD.Vector(-kcomp.NEMA_BOLT_SEP[size]/2, # kcomp.NEMA_BOLT_SEP[size]/2, # -bolt_depth) + pos # bhole10_pos = FreeCAD.Vector( kcomp.NEMA_BOLT_SEP[size]/2, # -kcomp.NEMA_BOLT_SEP[size]/2, # -bolt_depth) + pos # bhole11_pos = FreeCAD.Vector( kcomp.NEMA_BOLT_SEP[size]/2, # kcomp.NEMA_BOLT_SEP[size]/2, # -bolt_depth) + pos # bhole00_posrot = DraftVecUtils.rotate(bhole00_pos, rot.Angle, rot.Axis) # bhole01_posrot = DraftVecUtils.rotate(bhole01_pos, rot.Angle, rot.Axis) # bhole10_posrot = DraftVecUtils.rotate(bhole10_pos, rot.Angle, rot.Axis) # bhole11_posrot = DraftVecUtils.rotate(bhole11_pos, rot.Angle, rot.Axis) # shp_bolt00 = fcfun.shp_cyl ( # r=kcomp.NEMA_BOLT_D[size]/2.+kcomp.TOL/2., # h=bolt_depth + shaft_l, # normal = nnormal, # pos= bhole00_posrot) # shp_bolt01 = fcfun.shp_cyl ( # r=kcomp.NEMA_BOLT_D[size]/2.+kcomp.TOL/2., # h=bolt_depth + shaft_l, # normal = nnormal, # pos= bhole01_posrot) # shp_bolt10 = fcfun.shp_cyl ( # r=kcomp.NEMA_BOLT_D[size]/2.+kcomp.TOL/2., # h=bolt_depth + shaft_l, # normal = nnormal, # pos= bhole10_posrot) # shp_bolt11 = fcfun.shp_cyl ( # r=kcomp.NEMA_BOLT_D[size]/2.+kcomp.TOL/2., # h=bolt_depth + shaft_l, # normal = nnormal, # pos= bhole11_posrot) # shp_bolts = shp_bolt00.multiFuse([shp_bolt01, shp_bolt10, shp_bolt11]) # list of shapes to make a fusion of the container shp_contfuselist = [] # shp_contfuselist.append(shp_bolts) b2hole00_pos = FreeCAD.Vector(-kcomp.NEMA_BOLT_SEP[size] / 2, -kcomp.NEMA_BOLT_SEP[size] / 2, -bolt_depth) b2hole01_pos = FreeCAD.Vector(-kcomp.NEMA_BOLT_SEP[size] / 2, kcomp.NEMA_BOLT_SEP[size] / 2, -bolt_depth) b2hole10_pos = FreeCAD.Vector(kcomp.NEMA_BOLT_SEP[size] / 2, -kcomp.NEMA_BOLT_SEP[size] / 2, -bolt_depth) b2hole11_pos = FreeCAD.Vector(kcomp.NEMA_BOLT_SEP[size] / 2, kcomp.NEMA_BOLT_SEP[size] / 2, -bolt_depth) b2hole00 = addBolt(r_shank=nemabolt_d / 2. + mtol / 2., l_bolt=bolt_out + bolt_depth, r_head=kcomp.D912_HEAD_D[nemabolt_d] / 2. + mtol / 2., l_head=kcomp.D912_HEAD_L[nemabolt_d] + mtol, hex_head=0, extra=1, support=1, headdown=0, name="b2hole00") b2hole01 = Draft.clone(b2hole00) b2hole01.Label = "b2hole01" b2hole10 = Draft.clone(b2hole00) b2hole10.Label = "b2hole10" b2hole11 = Draft.clone(b2hole00) b2hole11.Label = "b2hole11" b2hole00.ViewObject.Visibility = False b2hole01.ViewObject.Visibility = False b2hole10.ViewObject.Visibility = False b2hole11.ViewObject.Visibility = False b2hole00.Placement.Base = b2hole00_pos b2hole01.Placement.Base = b2hole01_pos b2hole10.Placement.Base = b2hole10_pos b2hole11.Placement.Base = b2hole11_pos # it doesnt work if dont recompute here! probably the clones doc.recompute() b2holes_list = [b2hole00, b2hole01, b2hole10, b2hole11] # not an efficient way, either use shapes or fco, but not both shp_b2holes = b2hole00.Shape.multiFuse( [b2hole01.Shape, b2hole10.Shape, b2hole11.Shape]) #Part.show(shp_b2holes) b2holes = doc.addObject("Part::MultiFuse", "b2holes") b2holes.Shapes = b2holes_list b2holes.ViewObject.Visibility = False shp_b2holes.Placement.Base = pos shp_b2holes.Placement.Rotation = rot shp_contfuselist.append(shp_b2holes) # Circle on the base of the shaft if circle_r == 0: calcircle_r = kcomp.NEMA_BOLT_SEP[size] / 2. else: calcircle_r = circle_r if circle_h != 0: shp_circle = fcfun.shp_cyl( r=calcircle_r, h=circle_h + 1, #supperposition for union normal=nnormal, #supperposition for union pos=pos - nnormal) # fmotor: fused motor shp_fmotor = shp_motorshaft.fuse(shp_circle) else: shp_fmotor = shp_motorshaft #fmotor = doc.addObject("Part::Feature", "fmotor") #fmotor.Shape = shp_fmotor #shp_motor = shp_fmotor.cut(shp_bolts) shp_motor = shp_fmotor.cut(shp_b2holes) #Part.show(shp_bolts) # container if container == 1: # 2*TOL to make sure it fits v1 = FreeCAD.Vector(self.width / 2. - chmf / 2. + 2 * kcomp.TOL, self.width / 2. + 2 * kcomp.TOL, 0) v2 = FreeCAD.Vector(self.width / 2. + 2 * kcomp.TOL, self.width / 2. - chmf / 2. + 2 * kcomp.TOL, 0) cont_motorwire = fcfun.wire_sim_xy([v1, v2]) cont_motorwire.Placement.Rotation = rot cont_motorwire.Placement.Base = pos cont_motorface = Part.Face(cont_motorwire) shp_contmotor_box = cont_motorface.extrude(neg_lnormal) # the container is much wider than the shaft if rshaft_l == 0: # no rear shaft shp_contshaft = fcfun.shp_cyl(r=calcircle_r + kcomp.TOL, h=shaft_l + 1, normal=nnormal, pos=pos - nnormal) else: shp_contshaft = fcfun.shp_cyl(r=calcircle_r + kcomp.TOL, h=shaft_l + rshaft_l + length, normal=nnormal, pos=pos + rshaft_posend) shp_contfuselist.append(shp_contshaft) shp_contmotor = shp_contmotor_box.multiFuse(shp_contfuselist) else: shp_contmotor = shp_motor # we put the same shape doc.recompute() #fco_motor = doc.addObject("Part::Cut", name) #fco_motor.Base = fmotor #fco_motor.Tool = b2holes fco_motor = doc.addObject("Part::Feature", name) fco_motor.Shape = shp_motor self.fco = fco_motor self.shp_cont = shp_contmotor #Part.show(shp_contmotor) doc.recompute()
def makeStraightStairs(self, obj, edge, numberofsteps=None): "builds a simple, straight staircase from a straight edge" # Upgrade obj if it is from an older version of FreeCAD if not (hasattr(obj, "StringerOverlap")): obj.addProperty( "App::PropertyLength", "StringerOverlap", "Structure", QT_TRANSLATE_NOOP( "App::Property", "The overlap of the stringers above the bottom of the treads" )) # general data import Part, DraftGeomUtils if not numberofsteps: numberofsteps = obj.NumberOfSteps v = DraftGeomUtils.vec(edge) vLength = DraftVecUtils.scaleTo( v, float(edge.Length) / (numberofsteps - 1)) vLength = Vector(vLength.x, vLength.y, 0) if round(v.z, Draft.precision()) != 0: h = v.z else: h = obj.Height.Value vHeight = Vector(0, 0, float(h) / numberofsteps) vWidth = DraftVecUtils.scaleTo(vLength.cross(Vector(0, 0, 1)), obj.Width.Value) vBase = edge.Vertexes[0].Point vNose = DraftVecUtils.scaleTo(vLength, -abs(obj.Nosing.Value)) a = math.atan(vHeight.Length / vLength.Length) #print("stair data:",vLength.Length,":",vHeight.Length) # steps for i in range(numberofsteps - 1): p1 = vBase.add((Vector(vLength).multiply(i)).add( Vector(vHeight).multiply(i + 1))) p1 = self.align(p1, obj.Align, vWidth) p1 = p1.add(vNose).add(Vector(0, 0, -abs(obj.TreadThickness.Value))) p2 = p1.add(DraftVecUtils.neg(vNose)).add(vLength) p3 = p2.add(vWidth) p4 = p3.add(DraftVecUtils.neg(vLength)).add(vNose) step = Part.Face(Part.makePolygon([p1, p2, p3, p4, p1])) if obj.TreadThickness.Value: step = step.extrude(Vector(0, 0, abs(obj.TreadThickness.Value))) self.steps.append(step) else: self.pseudosteps.append(step) # structure lProfile = [] struct = None if obj.Structure == "Massive": if obj.StructureThickness.Value: for i in range(numberofsteps - 1): if not lProfile: lProfile.append(vBase) last = lProfile[-1] if len(lProfile) == 1: last = last.add( Vector(0, 0, -abs(obj.TreadThickness.Value))) lProfile.append(last.add(vHeight)) lProfile.append(lProfile[-1].add(vLength)) resHeight1 = obj.StructureThickness.Value / math.cos(a) lProfile.append(lProfile[-1].add(Vector(0, 0, -resHeight1))) resHeight2 = ((numberofsteps - 1) * vHeight.Length) - ( resHeight1 + obj.TreadThickness.Value) resLength = (vLength.Length / vHeight.Length) * resHeight2 h = DraftVecUtils.scaleTo(vLength, -resLength) lProfile.append(lProfile[-1].add(Vector(h.x, h.y, -resHeight2))) lProfile.append(vBase) #print(lProfile) pol = Part.makePolygon(lProfile) struct = Part.Face(pol) evec = vWidth if obj.StructureOffset.Value: mvec = DraftVecUtils.scaleTo(vWidth, obj.StructureOffset.Value) struct.translate(mvec) evec = DraftVecUtils.scaleTo( evec, evec.Length - (2 * mvec.Length)) struct = struct.extrude(evec) elif obj.Structure in ["One stringer", "Two stringers"]: if obj.StringerWidth.Value and obj.StructureThickness.Value: hyp = math.sqrt(vHeight.Length**2 + vLength.Length**2) l1 = Vector(vLength).multiply(numberofsteps - 1) h1 = Vector(vHeight).multiply(numberofsteps - 1).add( Vector( 0, 0, -abs(obj.TreadThickness.Value) + obj.StringerOverlap.Value)) p1 = vBase.add(l1).add(h1) p1 = self.align(p1, obj.Align, vWidth) if obj.StringerOverlap.Value <= float(h) / numberofsteps: lProfile.append(p1) else: p1b = vBase.add(l1).add(Vector(0, 0, float(h))) p1a = p1b.add( Vector(vLength).multiply( (p1b.z - p1.z) / vHeight.Length)) lProfile.append(p1a) lProfile.append(p1b) h2 = (obj.StructureThickness.Value / vLength.Length) * hyp lProfile.append(p1.add(Vector(0, 0, -abs(h2)))) h3 = lProfile[-1].z - vBase.z l3 = (h3 / vHeight.Length) * vLength.Length v3 = DraftVecUtils.scaleTo(vLength, -l3) lProfile.append(lProfile[-1].add(Vector(0, 0, -abs(h3))).add(v3)) l4 = (obj.StructureThickness.Value / vHeight.Length) * hyp v4 = DraftVecUtils.scaleTo(vLength, -l4) lProfile.append(lProfile[-1].add(v4)) lProfile.append(lProfile[0]) #print(lProfile) pol = Part.makePolygon(lProfile) pol = Part.Face(pol) evec = DraftVecUtils.scaleTo(vWidth, obj.StringerWidth.Value) if obj.Structure == "One stringer": if obj.StructureOffset.Value: mvec = DraftVecUtils.scaleTo(vWidth, obj.StructureOffset.Value) else: mvec = DraftVecUtils.scaleTo( vWidth, (vWidth.Length / 2) - obj.StringerWidth.Value / 2) pol.translate(mvec) struct = pol.extrude(evec) elif obj.Structure == "Two stringers": pol2 = pol.copy() if obj.StructureOffset.Value: mvec = DraftVecUtils.scaleTo(vWidth, obj.StructureOffset.Value) pol.translate(mvec) mvec = vWidth.add(mvec.negative()) pol2.translate(mvec) else: pol2.translate(vWidth) s1 = pol.extrude(evec) s2 = pol2.extrude(evec.negative()) struct = Part.makeCompound([s1, s2]) if struct: self.structures.append(struct)
def makeStraightLanding(self, obj, edge, numberofsteps=None): "builds a landing from a straight edge" # general data if not numberofsteps: numberofsteps = obj.NumberOfSteps import Part, DraftGeomUtils v = DraftGeomUtils.vec(edge) vLength = Vector(v.x, v.y, 0) vWidth = vWidth = DraftVecUtils.scaleTo(vLength.cross(Vector(0, 0, 1)), obj.Width.Value) vBase = edge.Vertexes[0].Point vNose = DraftVecUtils.scaleTo(vLength, -abs(obj.Nosing.Value)) h = obj.Height.Value l = obj.Length.Value if obj.Base: if obj.Base.isDerivedFrom("Part::Feature"): l = obj.Base.Shape.Length if obj.Base.Shape.BoundBox.ZLength: h = obj.Base.Shape.BoundBox.ZLength fLength = float(l - obj.Width.Value) / (numberofsteps - 2) fHeight = float(h) / numberofsteps a = math.atan(fHeight / fLength) print("landing data:", fLength, ":", fHeight) # step p1 = self.align(vBase, obj.Align, vWidth) p1 = p1.add(vNose).add(Vector(0, 0, -abs(obj.TreadThickness.Value))) p2 = p1.add(DraftVecUtils.neg(vNose)).add(vLength) p3 = p2.add(vWidth) p4 = p3.add(DraftVecUtils.neg(vLength)).add(vNose) step = Part.Face(Part.makePolygon([p1, p2, p3, p4, p1])) if obj.TreadThickness.Value: step = step.extrude(Vector(0, 0, abs(obj.TreadThickness.Value))) self.steps.append(step) else: self.pseudosteps.append(step) # structure lProfile = [] struct = None p7 = None p1 = p1.add(DraftVecUtils.neg(vNose)) p2 = p1.add(Vector(0, 0, -fHeight)).add( Vector(0, 0, -obj.StructureThickness.Value / math.cos(a))) resheight = p1.sub(p2).Length - obj.StructureThickness.Value reslength = resheight / math.tan(a) p3 = p2.add(DraftVecUtils.scaleTo(vLength, reslength)).add( Vector(0, 0, resheight)) p6 = p1.add(vLength) if obj.TreadThickness.Value: p7 = p6.add(Vector(0, 0, obj.TreadThickness.Value)) reslength = fLength + ( obj.StructureThickness.Value / math.sin(a) - (fHeight - obj.TreadThickness.Value) / math.tan(a)) if p7: p5 = p7.add(DraftVecUtils.scaleTo(vLength, reslength)) else: p5 = p6.add(DraftVecUtils.scaleTo(vLength, reslength)) resheight = obj.StructureThickness.Value + obj.TreadThickness.Value reslength = resheight / math.tan(a) p4 = p5.add(DraftVecUtils.scaleTo(vLength, -reslength)).add( Vector(0, 0, -resheight)) if obj.Structure == "Massive": if obj.StructureThickness.Value: if p7: struct = Part.Face( Part.makePolygon([p1, p2, p3, p4, p5, p7, p6, p1])) else: struct = Part.Face( Part.makePolygon([p1, p2, p3, p4, p5, p6, p1])) evec = vWidth if obj.StructureOffset.Value: mvec = DraftVecUtils.scaleTo(vWidth, obj.StructureOffset.Value) struct.translate(mvec) evec = DraftVecUtils.scaleTo( evec, evec.Length - (2 * mvec.Length)) struct = struct.extrude(evec) elif obj.Structure in ["One stringer", "Two stringers"]: if obj.StringerWidth.Value and obj.StructureThickness.Value: p1b = p1.add(Vector(0, 0, -fHeight)) reslength = fHeight / math.tan(a) p1c = p1.add(DraftVecUtils.scaleTo(vLength, reslength)) p5b = None p5c = None if obj.TreadThickness.Value: reslength = obj.StructureThickness.Value / math.sin(a) p5b = p5.add(DraftVecUtils.scaleTo(vLength, -reslength)) reslength = obj.TreadThickness.Value / math.tan(a) p5c = p5b.add(DraftVecUtils.scaleTo( vLength, -reslength)).add( Vector(0, 0, -obj.TreadThickness.Value)) pol = Part.Face( Part.makePolygon( [p1c, p1b, p2, p3, p4, p5, p5b, p5c, p1c])) else: pol = Part.Face( Part.makePolygon([p1c, p1b, p2, p3, p4, p5, p1c])) evec = DraftVecUtils.scaleTo(vWidth, obj.StringerWidth.Value) if obj.Structure == "One stringer": if obj.StructureOffset.Value: mvec = DraftVecUtils.scaleTo(vWidth, obj.StructureOffset.Value) else: mvec = DraftVecUtils.scaleTo( vWidth, (vWidth.Length / 2) - obj.StringerWidth.Value / 2) pol.translate(mvec) struct = pol.extrude(evec) elif obj.Structure == "Two stringers": pol2 = pol.copy() if obj.StructureOffset.Value: mvec = DraftVecUtils.scaleTo(vWidth, obj.StructureOffset.Value) pol.translate(mvec) mvec = vWidth.add(mvec.negative()) pol2.translate(mvec) else: pol2.translate(vWidth) s1 = pol.extrude(evec) s2 = pol2.extrude(evec.negative()) struct = Part.makeCompound([s1, s2]) if struct: self.structures.append(struct)
def makeStraightLanding(self,obj,edge,numberofsteps=None, callByMakeStraightStairsWithLanding=False): # what is use of numberofsteps ? "builds a landing from a straight edge" # general data if not numberofsteps: numberofsteps = obj.NumberOfSteps import Part,DraftGeomUtils v = DraftGeomUtils.vec(edge) vLength = Vector(v.x,v.y,0) vWidth = vWidth = DraftVecUtils.scaleTo(vLength.cross(Vector(0,0,1)),obj.Width.Value) vBase = edge.Vertexes[0].Point # if not call by makeStraightStairsWithLanding() - not 're-base' in function there, then 're-base' here if not callByMakeStraightStairsWithLanding: vBase = self.vbaseFollowLastSement(obj, vBase) obj.AbsTop = vBase vNose = DraftVecUtils.scaleTo(vLength,-abs(obj.Nosing.Value)) h = 0 if obj.RiserHeightEnforce != 0: h = obj.RiserHeightEnforce * numberofsteps elif obj.Base: # TODO - should this happen? - though in original code if obj.Base.isDerivedFrom("Part::Feature"): #l = obj.Base.Shape.Length #if obj.Base.Shape.BoundBox.ZLength: if round(obj.Base.Shape.BoundBox.ZLength,Draft.precision()) != 0: # ? - need precision h = obj.Base.Shape.BoundBox.ZLength #.Value? else: print ("obj.Base has 0 z-value") print (h) if h==0 and obj.Height.Value != 0: h = obj.Height.Value else: print (h) if obj.TreadDepthEnforce != 0: l = obj.TreadDepthEnforce.Value * (numberofsteps-2) if obj.LandingDepth: l += obj.LandingDepth.Value else: l += obj.Width.Value elif obj.Base: if obj.Base.isDerivedFrom("Part::Feature"): l = obj.Base.Shape.Length #.Value? elif obj.Length.Value != 0: l = obj.Length.Value if obj.LandingDepth: fLength = float(l-obj.LandingDepth.Value)/(numberofsteps-2) else: fLength = float(l-obj.Width.Value)/(numberofsteps-2) fHeight = float(h)/numberofsteps a = math.atan(fHeight/fLength) print("landing data:",fLength,":",fHeight) # step p1 = self.align(vBase,obj.Align,vWidth) p1o = p1.add(Vector(0,0,-abs(obj.TreadThickness.Value))) p1 = p1.add(vNose).add(Vector(0,0,-abs(obj.TreadThickness.Value))) p2 = p1.add(DraftVecUtils.neg(vNose)).add(vLength) p3 = p2.add(vWidth) p4 = p3.add(DraftVecUtils.neg(vLength)).add(vNose) p4o = p3.add(DraftVecUtils.neg(vLength)) if not callByMakeStraightStairsWithLanding: p2o = p2 p3o = p3 if callByMakeStraightStairsWithLanding: if obj.Flight == "HalfTurnLeft": p1 = p1.add(-vWidth) p2 = p2.add(-vWidth) elif obj.Flight == "HalfTurnRight": p3 = p3.add(vWidth) p4 = p4.add(vWidth) step = Part.Face(Part.makePolygon([p1,p2,p3,p4,p1])) if obj.TreadThickness.Value: step = step.extrude(Vector(0,0,abs(obj.TreadThickness.Value))) self.steps.append(step) else: self.pseudosteps.append(step) # structure lProfile = [] struct = None p7 = None p1 = p1.add(DraftVecUtils.neg(vNose)) p2 = p1.add(Vector(0,0,-fHeight)).add(Vector(0,0,-obj.StructureThickness.Value/math.cos(a))) resheight = p1.sub(p2).Length - obj.StructureThickness.Value reslength = resheight / math.tan(a) p3 = p2.add(DraftVecUtils.scaleTo(vLength,reslength)).add(Vector(0,0,resheight)) p6 = p1.add(vLength) if obj.TreadThickness.Value: if obj.Flight == "Straight": p7 = p6.add(Vector(0,0,obj.TreadThickness.Value)) reslength = fLength + (obj.StructureThickness.Value/math.sin(a)-(fHeight-obj.TreadThickness.Value)/math.tan(a)) if p7: p5 = p7.add(DraftVecUtils.scaleTo(vLength,reslength)) else: if obj.Flight == "Straight": p5 = p6.add(DraftVecUtils.scaleTo(vLength,reslength)) else: p5 = None resheight = obj.StructureThickness.Value + obj.TreadThickness.Value reslength = resheight/math.tan(a) if obj.Flight == "Straight": p4 = p5.add(DraftVecUtils.scaleTo(vLength,-reslength)).add(Vector(0,0,-resheight)) else: p4 = p6.add(Vector(0,0,-obj.StructureThickness.Value)) if obj.Structure == "Massive": if obj.StructureThickness.Value: if p7: struct = Part.Face(Part.makePolygon([p1,p2,p3,p4,p5,p7,p6,p1])) elif p5: struct = Part.Face(Part.makePolygon([p1,p2,p3,p4,p5,p6,p1])) else: struct = Part.Face(Part.makePolygon([p1,p2,p3,p4,p6,p1])) evec = vWidth mvec = FreeCAD.Vector(0.0,0) if obj.StructureOffset.Value: mvec = DraftVecUtils.scaleTo(vWidth,obj.StructureOffset.Value) struct.translate(mvec) if obj.Flight in ["HalfTurnLeft","HalfTurnRight"]: evec = DraftVecUtils.scaleTo(evec,2*evec.Length-2*mvec.Length) else: evec = DraftVecUtils.scaleTo(evec,evec.Length-(2*mvec.Length)) struct = struct.extrude(evec) elif obj.Structure in ["One stringer","Two stringers"]: if obj.StringerWidth.Value and obj.StructureThickness.Value: p1b = p1.add(Vector(0,0,-fHeight)) reslength = fHeight/math.tan(a) p1c = p1.add(DraftVecUtils.scaleTo(vLength,reslength)) p5b = None p5c = None if obj.TreadThickness.Value: reslength = obj.StructureThickness.Value/math.sin(a) p5b = p5.add(DraftVecUtils.scaleTo(vLength,-reslength)) reslength = obj.TreadThickness.Value/math.tan(a) p5c = p5b.add(DraftVecUtils.scaleTo(vLength,-reslength)).add(Vector(0,0,-obj.TreadThickness.Value)) pol = Part.Face(Part.makePolygon([p1c,p1b,p2,p3,p4,p5,p5b,p5c,p1c])) else: pol = Part.Face(Part.makePolygon([p1c,p1b,p2,p3,p4,p5,p1c])) evec = DraftVecUtils.scaleTo(vWidth,obj.StringerWidth.Value) if obj.Structure == "One stringer": if obj.StructureOffset.Value: mvec = DraftVecUtils.scaleTo(vWidth,obj.StructureOffset.Value) else: mvec = DraftVecUtils.scaleTo(vWidth,(vWidth.Length/2)-obj.StringerWidth.Value/2) pol.translate(mvec) struct = pol.extrude(evec) elif obj.Structure == "Two stringers": pol2 = pol.copy() if obj.StructureOffset.Value: mvec = DraftVecUtils.scaleTo(vWidth,obj.StructureOffset.Value) pol.translate(mvec) mvec = vWidth.add(mvec.negative()) pol2.translate(mvec) else: pol2.translate(vWidth) s1 = pol.extrude(evec) s2 = pol2.extrude(evec.negative()) struct = Part.makeCompound([s1,s2]) # Overwriting result of above functions if case fit - should better avoid running the above in first place (better rewrite later) if not callByMakeStraightStairsWithLanding: if obj.StructureThickness.Value: struct = None landingFace = Part.Face(Part.makePolygon([p1o,p2o,p3o,p4o,p1o])) struct = landingFace.extrude(Vector(0,0,-abs(obj.StructureThickness.Value))) if struct: self.structures.append(struct)
def returnOutlines(self, obj, edges, align="left", offsetH=0, offsetV=0): # better omit 'obj' latter - 'currently' only for vbaseFollowLastSement()? import DraftGeomUtils v, vLength, vWidth, vBase = [], [], [], [] p1o, p2o, p1, p2, p3, p4 = [], [], [], [], [], [] outline, outlineP1P2, outlineP3P4 = [], [], [] enum_edges = enumerate(edges) for i, edge in enum_edges: v.append(DraftGeomUtils.vec(edge)) vLength.append(Vector(v[i].x,v[i].y,0)) # TODO obj.Width[i].Value for different 'edges' / 'sections' of the landing netWidth = obj.Width.Value - 2*offsetH vWidth.append(DraftVecUtils.scaleTo(vLength[i].cross(Vector(0,0,1)),netWidth)) vBase.append(edges[i].Vertexes[0].Point) vBase[i] = self.vbaseFollowLastSement(obj, vBase[i]) if offsetV != 0: # redundant? vBase[i] = vBase[i].add(Vector(0,0,offsetV)) if offsetH != 0: # redundant? vOffsetH = DraftVecUtils.scaleTo(vLength[i].cross(Vector(0,0,1)),offsetH) vBase[i] = self.align(vBase[i], "Right", -vOffsetH) # step + structure # assume all left-align first # no nosing p1o.append(vBase[i].add(Vector(0,0,-abs(obj.TreadThickness.Value)))) p2o.append(p1o[i].add(vLength[i])) p1.append(self.align(vBase[i],obj.Align,vWidth[i]).add(Vector(0,0,-abs(obj.TreadThickness.Value)))) p2.append(p1[i].add(vLength[i])) p3.append(p2[i].add(vWidth[i])) p4.append(p3[i].add(DraftVecUtils.neg(vLength[i]))) #if obj.Align == 'Left': if False: outlineP1P2.append(p1[i]) outlineP1P2.append(p2[i]) # can better skip 1 'supposedly' overlapping point every pair? if i > 0: print ("Debug - intersection calculation") print (p3[i-1]) print (p4[i-1]) print (p3[i]) print (p4[i]) intersection = DraftGeomUtils.findIntersection(p3[i-1],p4[i-1],p3[i],p4[i],True,True) print (intersection) outlineP3P4.insert(0, intersection[0]) else: outlineP3P4.insert(0, p4[i]) #elif obj.Align == 'Right': if False: if i > 0: intersection = DraftGeomUtils.findIntersection(p1[i-1],p2[i-1],p1[i],p2[i],True,True) outlineP1P2.append(intersection[0]) else: outlineP1P2.append(p1[i]) outlineP3P4.insert(0, p4[i]) outlineP3P4.insert(0, p3[i]) #elif obj.Align == 'Center': if True: if i > 0: intersection = DraftGeomUtils.findIntersection(p1[i-1],p2[i-1],p1[i],p2[i],True,True) outlineP1P2.append(intersection[0]) intersection = DraftGeomUtils.findIntersection(p3[i-1],p4[i-1],p3[i],p4[i],True,True) outlineP3P4.insert(0, intersection[0]) else: outlineP1P2.append(p1[i]) outlineP3P4.insert(0, p4[i]) else: outlineP1P2.append(p1[i]) outlineP1P2.append(p2[i]) outlineP3P4.insert(0, p4[i]) outlineP3P4.insert(0, p3[i]) # add back last/first 'missing' point(s) outlineP3P4.insert(0, p3[i]) outlineP1P2.append(p2[i]) outline = outlineP1P2 + outlineP3P4 outline.append(p1[0]) print (outlineP1P2) print (outlineP3P4) print (outline) return outline, outlineP1P2, outlineP3P4, vBase