def execute(self, fp): if fp.OD>fp.OD2: if fp.calcH or fp.Height==0: fp.Height=3*(fp.OD-fp.OD2) fp.Profile=str(fp.OD)+"x"+str(fp.OD2) if fp.conc: sol = Part.makeCone(fp.OD/2,fp.OD2/2,fp.Height) if fp.thk<fp.OD/2 and fp.thk2<fp.OD2/2: fp.Shape=sol.cut(Part.makeCone(fp.OD/2-fp.thk,fp.OD2/2-fp.thk2,fp.Height)) else: fp.Shape=sol fp.Ports=[FreeCAD.Vector(),FreeCAD.Vector(0,0,float(fp.Height))] else: C=Part.makeCircle(fp.OD/2,FreeCAD.Vector(0,0,0),FreeCAD.Vector(0,0,1)) c=Part.makeCircle(fp.OD2/2,FreeCAD.Vector(0,0,0),FreeCAD.Vector(0,0,1)) c.translate(FreeCAD.Vector((fp.OD-fp.OD2)/2,0,fp.Height)) sol=Part.makeLoft([c,C],True) if fp.thk<fp.OD/2 and fp.thk2<fp.OD2/2: C=Part.makeCircle(fp.OD/2-fp.thk,FreeCAD.Vector(0,0,0),FreeCAD.Vector(0,0,1)) c=Part.makeCircle(fp.OD2/2-fp.thk2,FreeCAD.Vector(0,0,0),FreeCAD.Vector(0,0,1)) c.translate(FreeCAD.Vector((fp.OD-fp.OD2)/2,0,fp.Height)) fp.Shape=sol.cut(Part.makeLoft([c,C],True)) else: fp.Shape=sol fp.Ports=[FreeCAD.Vector(),FreeCAD.Vector((fp.OD-fp.OD2)/2,0,float(fp.Height))] super(Reduct,self).execute(fp) # perform common operations
def execute(self, fp): if fp.BendAngle<180: if fp.thk>fp.OD/2: fp.thk=fp.OD/2 fp.ID=fp.OD-2*fp.thk fp.Profile=str(fp.OD)+"x"+str(fp.thk) CenterOfBend=FreeCAD.Vector(fp.BendRadius,fp.BendRadius,0) ## make center-line ## R=Part.makeCircle(fp.BendRadius,CenterOfBend,FreeCAD.Vector(0,0,1),225-float(fp.BendAngle)/2,225+float(fp.BendAngle)/2) ## move the cl so that Placement.Base is the center of elbow ## from math import pi, cos, sqrt d=(fp.BendRadius*sqrt(2)-fp.BendRadius/cos(fp.BendAngle/180*pi/2)) P=FreeCAD.Vector(-d*cos(pi/4),-d*cos(pi/4),0) R.translate(P) ## calculate Ports position ## fp.Ports=[R.valueAt(R.FirstParameter),R.valueAt(R.LastParameter)] ## make the shape of the elbow ## c=Part.makeCircle(fp.OD/2,fp.Ports[0],R.tangentAt(R.FirstParameter)*-1) b=Part.makeSweepSurface(R,c) p1=Part.Face(Part.Wire(c)) p2=Part.Face(Part.Wire(Part.makeCircle(fp.OD/2,fp.Ports[1],R.tangentAt(R.LastParameter)))) sol=Part.Solid(Part.Shell([b,p1,p2])) planeFaces=[f for f in sol.Faces if type(f.Surface)==Part.Plane] #elbow=sol.makeThickness(planeFaces,-fp.thk,1.e-3) #fp.Shape = elbow if fp.thk<fp.OD/2: fp.Shape=sol.makeThickness(planeFaces,-fp.thk,1.e-3) else: fp.Shape=sol super(Elbow,self).execute(fp) # perform common operations
def update(self, names, pos): """ Update the 3D view printing annotations. @param names Weight names. @param pos Weight positions (FreeCAD::Base::Vector). """ # Destroy all previous entities self.clean() for i in range(0, len(names)): # Draw gravity line line = Part.makeLine((pos[i].x,pos[i].y,pos[i].z),(pos[i].x,pos[i].y,pos[i].z - 9.81)) Part.show(line) objs = FreeCAD.ActiveDocument.Objects self.objects.append(objs[-1]) objs[-1].Label = names[i] + 'Line' # Draw circles circle = Part.makeCircle(0.5, pos[i], Base.Vector(1.0,0.0,0.0)) Part.show(circle) objs = FreeCAD.ActiveDocument.Objects self.objects.append(objs[-1]) objs[-1].Label = names[i] + 'CircleX' circle = Part.makeCircle(0.5, pos[i], Base.Vector(0.0,1.0,0.0)) Part.show(circle) objs = FreeCAD.ActiveDocument.Objects self.objects.append(objs[-1]) objs[-1].Label = names[i] + 'CircleY' circle = Part.makeCircle(0.5, pos[i], Base.Vector(0.0,0.0,1.0)) Part.show(circle) objs = FreeCAD.ActiveDocument.Objects self.objects.append(objs[-1]) objs[-1].Label = names[i] + 'CircleZ' # Draw annotation self.objects.append(DrawText(names[i] + 'Text', names[i], Base.Vector(pos[i].x+1.0,pos[i].y,pos[i].z)))
def test72(self): '''Flip a circle''' edge = Part.makeCircle(3, Vector(1, 3, 2), Vector(0, 0, 1)) self.assertEdgeShapesMatch(edge, PathGeom.flipEdge(edge)) edge = Part.makeCircle(3, Vector(1, 3, 2), Vector(0, 0, -1)) self.assertEdgeShapesMatch(edge, PathGeom.flipEdge(edge))
def circle_hollow(params,document): od = params['D'] t = params['t'] l = params['l'] name = params['name'] id = od - t outer = Part.Wire(Part.makeCircle(0.5*od)) inner = Part.Wire(Part.makeCircle(0.5*id)) face = Part.makeFace([outer, inner], "Part::FaceMakerBullseye") if params['arch']: part = Arch.makeStructure(name=name) prof = document.addObject("Part::Feature","Profile") prof.Shape = face part.Base = prof part.Height = l else: part = document.addObject("Part::Feature","BOLTS_part") part.Label = name beam = face.extrude(Vector(0,0,l)) part.Shape = beam
def execute(self, fp): fp.thread="M"+str(float(fp.d)) c=Part.makeCircle(fp.C/2,FreeCAD.Vector(0,0,0),FreeCAD.Vector(0,0,1),0,180) l1=Part.makeLine((fp.C/2,0,0),(fp.C/2,fp.C/2-fp.H,0)) l2=Part.makeLine((-fp.C/2,0,0),(-fp.C/2,fp.C/2-fp.H,0)) p=Part.Face(Part.Wire(Part.makeCircle(fp.d/2,c.valueAt(c.FirstParameter),c.tangentAt(c.FirstParameter)))) path=Part.Wire([c,l1,l2]) fp.Shape=path.makePipe(p) fp.Ports=[FreeCAD.Vector(0,0,1)]
def test04(self): '''Verify isWireClockwise for unoriented wires.''' e0 = Part.makeCircle(5, Vector(1, 2, 3), Vector(0, 0, -1), 0, 180) e3 = Part.makeLine(e0.valueAt(e0.FirstParameter), e0.valueAt(e0.LastParameter)) self.assertTrue(PathOpTools.isWireClockwise(Part.Wire([e0, e3]))) e0 = Part.makeCircle(5, Vector(1, 2, 3), Vector(0, 0, +1), 0, 180) e3 = Part.makeLine(e0.valueAt(e0.FirstParameter), e0.valueAt(e0.LastParameter)) self.assertFalse(PathOpTools.isWireClockwise(Part.Wire([e0, e3])))
def test03(self): '''Verify isWireClockwise for two edge wires with an arc.''' e0 = Part.makeCircle(5, Vector(1, 2, 3), Vector(0, 0, -1), 0, 180) e2 = Part.makeLine(e0.valueAt(e0.LastParameter), e0.valueAt(e0.FirstParameter)) self.assertTrue(PathOpTools.isWireClockwise(Part.Wire([e0, e2]))) e0 = Part.makeCircle(5, Vector(1, 2, 3), Vector(0, 0, +1), 0, 180) e2 = Part.makeLine(e0.valueAt(e0.LastParameter), e0.valueAt(e0.FirstParameter)) self.assertFalse(PathOpTools.isWireClockwise(Part.Wire([e0, e2])))
def test02(self): '''Verify isWireClockwise for two half circle wires.''' e0 = Part.makeCircle(5, Vector(1, 2, 3), Vector(0, 0, -1), 0, 180) e1 = Part.makeCircle(5, Vector(1, 2, 3), Vector(0, 0, -1), 180, 360) self.assertTrue(PathOpTools.isWireClockwise(Part.Wire([e0, e1]))) e0 = Part.makeCircle(5, Vector(1, 2, 3), Vector(0, 0, +1), 0, 180) e1 = Part.makeCircle(5, Vector(1, 2, 3), Vector(0, 0, +1), 180, 360) self.assertFalse(PathOpTools.isWireClockwise(Part.Wire([e0, e1])))
def execute(self, fp): "Create all of the assosiated goemetry" radius = fp.CenterPoint.sub(fp.StartPoint).Length #length between start point and center point centerBase = fp.CenterPoint centerDir = fp.StartPoint.sub(fp.CenterPoint).normalize() angle1 = 0.0 angle2 = degrees(centerDir.getAngle(fp.EndPoint.sub(fp.CenterPoint).normalize())) ###############PROBLEM HERE, ONLY 180deg MAX############# fp.Shape = Part.makeCircle(radius,centerBase,centerDir,angle1,angle2) #this is just the basic arc shape #create snap points (start and end points of line) sps = [] sps.append(fp.StartPoint) sps.append(fp.EndPoint) fp.SnapPoints = sps #create all the snap line direction vectors startVec = fp.StartPoint.sub(fp.CenterPoint).normalize() endVec = fp.EndPoint.sub(fp.CenterPoint).normalize() startVecPerp = FreeCAD.Vector(startVec.y,-startVec.x,startVec.z) endVecPerp = FreeCAD.Vector(endVec.y,-endVec.x,endVec.z) vert = FreeCAD.Vector(0,1,0)#vertical horiz = FreeCAD.Vector(1,0,0)#horizontal #fill out index list. index and vector list must be same length fp.SnapLinesIndex = [0,0,0,0,1,1,1,1] #create assosiated (with index list) vector list spvs = [startVec,startVecPerp,vert,horiz,endVec,endVecPerp,vert,horiz] fp.SnapDirections = spvs # I don't know why I have to do it like this and not just add directly
def execute(self, fp): "Do something when doing a recomputation, this method is mandatory" circle = Part.makeCircle(fp.Radius) cylinder = circle.extrude(Base.Vector(0, 0, fp.Length)) fp.Shape = cylinder FreeCAD.Console.PrintMessage("Recompute Python Missile_body feature\n")
def makeCylinder(p1,p2,p3,p4): s=Part.makePolygon([p1,p2,p3,p1]) f=Part.makeFilledFace(s.Edges) n=f.Faces[0].normalAt(0,0) # Drehung n2=FreeCAD.Vector(0,0,1) r=FreeCAD.Rotation(n,n2) k1=r.multVec(p1) sp1=sympy.point.Point2D(k1.x,k1.y) z=k1.z sp1 k2=r.multVec(p2) sp2=sympy.point.Point2D(k2.x,k2.y) sp2 k3=r.multVec(p3) sp3=sympy.point.Point2D(k3.x,k3.y) sp3 k4=r.multVec(p4) sp4=sympy.point.Point2D(k4.x,k4.y) sp4 t=sympy.Triangle(sp1,sp2,sp3) rad=t.circumradius.evalf() center=t.circumcenter print rad print center x=center.x.evalf() y=center.y.evalf() circ=Part.makeCircle(rad,FreeCAD.Vector(x,y,z)) Part.show(circ) cb=App.ActiveDocument.ActiveObject h=k4.z-k3.z # und wieder zurueck r2=FreeCAD.Rotation(n2,n) ex=App.ActiveDocument.addObject("Part::Extrusion","Extrude") ex.Base = cb ex.Dir = (0,0,h) ex.Solid = (True) ex.Placement.Rotation=r2 ex.ViewObject.Transparency=80 cb.ViewObject.hide() s2=Part.makePolygon([p1,p2,p3,p4]) Part.show(s2) for p in [p1,p2,p3,p4]: k1=App.ActiveDocument.addObject("Part::Sphere","Sphere") k1.Placement.Base=p k1.Radius=0.5 k1.ViewObject.ShapeColor=(1.0,0.0,0.0) App.activeDocument().recompute()
def makeSquareTool(s, m): # makes a cylinder with an inner square hole, used as cutting tool # create square face msq = Base.Matrix() msq.rotateZ(math.radians(90.0)) polygon = [] vsq = Base.Vector(s / 2.0, s / 2.0, -m * 0.1) for i in range(4): polygon.append(vsq) vsq = msq.multiply(vsq) polygon.append(vsq) square = Part.makePolygon(polygon) square = Part.Face(square) # create circle face circ = Part.makeCircle(s * 3.0, Base.Vector(0.0, 0.0, -m * 0.1)) circ = Part.Face(Part.Wire(circ)) # Create the face with the circle as outline and the square as hole face=circ.cut(square) # Extrude in z to create the final cutting tool exSquare = face.extrude(Base.Vector(0.0, 0.0, m * 1.2)) # Part.show(exHex) return exSquare
def arcoCoronaCircular(rInt,rExt,vectorCentro,angIni,angFin): # Devuelve el arco de la corona circular (en el plano XY) definido por: # rInt: radio interior # rExt: radio exterior # vectorCentro: centro del cÃrculo (coordenadas x,y) # angIni: ángulo inicial (0 a 360º) # angFin: ángulo final (0 a 360º) # Los ángulos crecen en sentido contrario a las agujas del reloj arcoExt=Part.makeCircle(rExt,vectorCentro,Base.Vector(0,0,1),angIni,angFin) arcoInt=Part.makeCircle(rInt,vectorCentro,Base.Vector(0,0,1),angIni,angFin) angIni=angIni*math.pi/180.0 angFin=angFin*math.pi/180.0 r1=Part.makeLine(vectorCentro.add(Base.Vector(rInt*math.cos(angIni),rInt*math.sin(angIni))),vectorCentro.add(Base.Vector(rExt*math.cos(angIni),rExt*math.sin(angIni)))) r2=Part.makeLine(vectorCentro.add(Base.Vector(rInt*math.cos(angFin),rInt*math.sin(angFin))),vectorCentro.add(Base.Vector(rExt*math.cos(angFin),rExt*math.sin(angFin)))) arcCoron=Part.Face(Part.Wire([arcoExt,r1,arcoInt,r2])) return arcCoron
def execute(self, fp): edges = fp.Edges if edges < 3: edges = 3 length = fp.Length radius = fp.Radius height = fp.Height m=Base.Matrix() m.rotateZ(math.radians(360.0/edges)) # create polygon polygon = [] v=Base.Vector(length,0,0) for i in range(edges): polygon.append(v) v = m.multiply(v) polygon.append(v) wire = Part.makePolygon(polygon) # create circle circ=Part.makeCircle(radius) # Create the face with the polygon as outline and the circle as hole face=Part.Face([wire,Part.Wire(circ)]) # Extrude in z to create the final solid extrude=face.extrude(Base.Vector(0,0,height)) fp.Shape = extrude
def makeBase(l,z,lpol,zpol,lone,zone,zero): lines=[] f=np.sqrt(len2(lpol,zero)) e=np.sqrt(len2(lone,zero)) dist=e*f*l/((l-1)*e+f) pa=pointat(zero,lpol,dist) print (l,z,dist,pa) # lines.append(Part.makeLine(vec(zpol),vec(pa))) # lines.append(Part.makeCircle(10000,vec(pa))) f=np.sqrt(len2(zpol,zero)) e=np.sqrt(len2(zone,zero)) dist=e*f*z/((z-1)*e+f) pb=pointat(zero,zpol,dist) print (l,z,dist,pb) # lines.append(Part.makeLine(vec(lpol),vec(pb))) # lines.append(Part.makeCircle(10000,vec(pb))) pc=schnittpunkt(lpol,pb,zpol,pa) print (pa,pb,pc) lines.append(Part.makeCircle(15000,vec(pc))) comp=Part.makeCompound(lines) # Part.show(comp) return pc
def Process_board_outline(doc, board_outline, drills, board_thickness): """Process_board_outline(doc,board_outline,drills,board_thickness)-> number proccesed loops adds emn geometry from emn file""" vertex_index = -1 # presume no vertex lines = -1 # presume no lines out_shape = [] out_face = [] for point in board_outline: vertex = Base.Vector(point[1], point[2], 0) vertex_index += 1 if vertex_index == 0: lines = point[0] elif lines == point[0]: if point[3] != 0 and point[3] != 360: out_shape.append(Part.Arc(prev_vertex, mid_point(prev_vertex, vertex, point[3]), vertex)) FreeCAD.Console.PrintMessage("mid point " + str(mid_point) + "\n") elif point[3] == 360: per_point = Per_point(prev_vertex, vertex) out_shape.append(Part.Arc(per_point, mid_point(per_point, vertex, point[3] / 2), vertex)) out_shape.append(Part.Arc(per_point, mid_point(per_point, vertex, -point[3] / 2), vertex)) else: out_shape.append(Part.LineSegment(prev_vertex, vertex)) else: out_shape = Part.Shape(out_shape) out_shape = Part.Wire(out_shape.Edges) out_face.append(Part.Face(out_shape)) out_shape = [] vertex_index = 0 lines = point[0] prev_vertex = vertex if lines != -1: out_shape = Part.Shape(out_shape) out_shape = Part.Wire(out_shape.Edges) out_face.append(Part.Face(out_shape)) outline = out_face[0] FreeCAD.Console.PrintMessage("Added outline\n") if len(out_face) > 1: for otl_cut in out_face[1:]: outline = outline.cut(otl_cut) FreeCAD.Console.PrintMessage("Cutting shape inside outline\n") for drill in drills: FreeCAD.Console.PrintMessage("Cutting hole inside outline\n") out_shape = Part.makeCircle(drill[0] / 2, Base.Vector(drill[1], drill[2], 0)) out_shape = Part.Wire(out_shape.Edges) outline = outline.cut(Part.Face(out_shape)) doc_outline = doc.addObject("Part::Feature", "Board_outline") doc_outline.Shape = outline # FreeCADGui.Selection.addSelection(doc_outline) # FreeCADGui.runCommand("Draft_Upgrade") # outline=FreeCAD.ActiveDocument.getObject("Union").Shape # FreeCAD.ActiveDocument.removeObject("Union") # doc_outline=doc.addObject("Part::Feature","Board_outline") doc_outline.Shape = outline.extrude(Base.Vector(0, 0, -board_thickness)) grp = doc.addObject("App::DocumentObjectGroup", "Board_Geoms") grp.addObject(doc_outline) doc.Board_outline.ViewObject.ShapeColor = (0.0, 0.5, 0.0, 0.0) return lines + 1
def testScale(self): """ Tests scaling a shape and whether the dimensions are correct afterwards """ e = Shape.cast(Part.makeCircle(2.0, FreeCAD.Base.Vector(1, 2, 3))) e2 = e.scale(0.5) self.assertAlmostEquals(2.0, e2.BoundingBox(tolerance=0.0001).xlen, 3) self.assertAlmostEquals(2.0, e2.BoundingBox(tolerance=0.0001).ylen, 3)
def testCopy(self): """ Tests making a copy of a shape object and whether the new one has the same properties as the original. """ e = Shape.cast(Part.makeCircle(2.0, FreeCAD.Base.Vector(1, 2, 3))) e2 = e.copy() self.assertEquals(e.BoundingBox().xlen, e2.BoundingBox().xlen) self.assertEquals(e.BoundingBox().ylen, e2.BoundingBox().ylen)
def makeWorkplane(shape): """ Creates a workplane circle at the ZMin level. """ PathLog.track() loc = FreeCAD.Vector(shape.BoundBox.Center.x, shape.BoundBox.Center.y, shape.BoundBox.ZMin) c = Part.makeCircle(10, loc) return c
def recompute(self): if self.circle: self.sep.removeChild(self.circle) self.circle = None if self.endangle < self.startangle: c = Part.makeCircle(1,Vector(0,0,0),FreeCAD.DraftWorkingPlane.axis,self.endangle,self.startangle) else: c = Part.makeCircle(1,Vector(0,0,0),FreeCAD.DraftWorkingPlane.axis,self.startangle,self.endangle) buf=c.writeInventor(2,0.01) ivin = coin.SoInput() ivin.setBuffer(buf) ivob = coin.SoDB.readAll(ivin) # In case reading from buffer failed if ivob and ivob.getNumChildren() > 1: self.circle = ivob.getChild(1).getChild(0) self.circle.removeChild(self.circle.getChild(0)) self.circle.removeChild(self.circle.getChild(0)) self.sep.addChild(self.circle) else: FreeCAD.Console.PrintWarning("arcTracker.recompute() failed to read-in Inventor string\n")
def makeCircle(cls, radius, center, normal): """ Makes a Circle centered at the provided point, having normal in the provided direction :param radius: floating point radius of the circle, must be > 0 :param center: vector representing the center of the circle :param normal: vector representing the direction of the plane the circle should lie in :return: """ w = Wire(FreeCADPart.Wire([FreeCADPart.makeCircle(radius, center.wrapped, normal.wrapped)])) return w
def makeBubbles(self): import Part def getNode(): # make sure we already have the complete node built r = self.ViewObject.RootNode if r.getChildren().getLength() > 2: if r.getChild(2).getChildren().getLength() > 0: if r.getChild(2).getChild(0).getChildren().getLength() > 0: return self.ViewObject.RootNode.getChild(2).getChild(0).getChild(0) return None rn = getNode() if rn: if self.bubbles: rn.removeChild(self.bubbles) self.bubbles = None self.bubbles = coin.SoSeparator() isep = coin.SoSeparator() self.bubblestyle = coin.SoDrawStyle() self.bubblestyle.linePattern = 0xffff self.bubbles.addChild(self.bubblestyle) for i in range(len(self.ViewObject.Object.Distances)): invpl = self.ViewObject.Object.Placement.inverse() verts = self.ViewObject.Object.Shape.Edges[i].Vertexes p1 = invpl.multVec(verts[0].Point) p2 = invpl.multVec(verts[1].Point) dv = p2.sub(p1) dv.normalize() rad = self.ViewObject.BubbleSize center = p2.add(dv.scale(rad,rad,rad)) ts = Part.makeCircle(rad,center).writeInventor() cin = coin.SoInput() cin.setBuffer(ts) cob = coin.SoDB.readAll(cin) co = cob.getChild(1).getChild(0).getChild(2) li = cob.getChild(1).getChild(0).getChild(3) self.bubbles.addChild(co) self.bubbles.addChild(li) st = coin.SoSeparator() tr = coin.SoTransform() tr.translation.setValue((center.x,center.y-rad/4,center.z)) fo = coin.SoFont() fo.name = "Arial,Sans" fo.size = rad*100 tx = coin.SoText2() tx.justification = coin.SoText2.CENTER tx.string = self.getNumber(i) st.addChild(tr) st.addChild(fo) st.addChild(tx) isep.addChild(st) self.bubbles.addChild(isep) rn.addChild(self.bubbles)
def execute(self, fp): inner_diameter = fp.module.Value * fp.teeth outer_diameter = inner_diameter + fp.height.Value * 2 inner_circle = Part.Wire(Part.makeCircle(inner_diameter / 2.)) outer_circle = Part.Wire(Part.makeCircle(outer_diameter / 2.)) inner_circle.reverse() face = Part.Face([outer_circle, inner_circle]) solid = face.extrude(App.Vector([0., 0., -fp.thickness.Value])) ### cutting obj alpha_w = np.deg2rad(fp.pressure_angle.Value) m = fp.module.Value t = fp.teeth t_c = t t_i = fp.other_teeth rm = inner_diameter / 2 y0 = m * 0.5 y1 = m + y0 y2 = m r0 = inner_diameter / 2 - fp.height.Value * 0.1 r1 = outer_diameter / 2 + fp.height.Value * 0.3 polies = [] for r_i in np.linspace(r0, r1, fp.num_profiles): pts = self.profile(m, r_i, rm, t_c, t_i, alpha_w, y0, y1, y2) poly = Wire(makePolygon(list(map(fcvec, pts)))) polies.append(poly) loft = makeLoft(polies, True) rot = App.Matrix() rot.rotateZ(2 * np.pi / t) if fp.construct: cut_shapes = [solid] for _ in range(t): loft = loft.transformGeometry(rot) cut_shapes.append(loft) fp.Shape = Part.Compound(cut_shapes) else: for i in range(t): loft = loft.transformGeometry(rot) solid = solid.cut(loft) fp.Shape = solid
def recompute(self): import Part, re if self.circle: self.sep.removeChild(self.circle) self.circle = None if self.endangle < self.startangle: c = Part.makeCircle(1, Vector(0, 0, 0), self.normal, self.endangle, self.startangle) else: c = Part.makeCircle(1, Vector(0, 0, 0), self.normal, self.startangle, self.endangle) buf = c.writeInventor(2, 0.01) try: ivin = coin.SoInput() ivin.setBuffer(buf) ivob = coin.SoDB.readAll(ivin) except: # workaround for pivy SoInput.setBuffer() bug buf = buf.replace("\n", "") pts = re.findall("point \[(.*?)\]", buf)[0] pts = pts.split(",") pc = [] for p in pts: v = p.strip().split() pc.append([float(v[0]), float(v[1]), float(v[2])]) coords = coin.SoCoordinate3() coords.point.setValues(0, len(pc), pc) line = coin.SoLineSet() line.numVertices.setValue(-1) self.circle = coin.SoSeparator() self.circle.addChild(coords) self.circle.addChild(line) self.sep.addChild(self.circle) else: if ivob and ivob.getNumChildren() > 1: self.circle = ivob.getChild(1).getChild(0) self.circle.removeChild(self.circle.getChild(0)) self.circle.removeChild(self.circle.getChild(0)) self.sep.addChild(self.circle) else: FreeCAD.Console.PrintWarning("arcTracker.recompute() failed to read-in Inventor string\n")
def secTirante(tipo,tam): if 'Fi' in tipo: d=eval(tipo)[tam]['d'] secPerfil=Part.makeCircle(d/2.0,Base.Vector(0,0,0),Base.Vector(0,1,0)) secPerfil=Part.Face(Part.Wire([secPerfil])) elif 'Cuad' in tipo: d=eval(tipo)[tam]['d'] secPerfil=Part.makePlane(d,d,Base.Vector(0,0,0),Base.Vector(0,1,0)) elif 'Rect' in tipo: b=eval(tipo)[tam]['b'] d=eval(tipo)[tam]['d'] secPerfil=Part.makePlane(b,d,Base.Vector(0,0,0),Base.Vector(0,1,0)) return secPerfil
def fillet2D(Pini,P2recta1,P1recta2,Pfin,radioConSigno): # Devuelve dos segmentos de las rectas definidas por los ptos Pini-P2recta1 y P1recta2-Pfin y el arco de circunferencia de radio igual al valor absoluto de radioConSigno que es tangente a ellas. # Pini: pto. 1 de la recta 1, será el 1er pto. de la lÃnea que devuelve la función # P2recta1: pto. 2 de la recta 1 # P1recta2: pto. 1 de la recta 2 # Pfin: pto. 2 de la recta 2, será el último pto. de la lÃnea que devuelve la función # radioConSigno: radio del arco de circunferencia tangente signo + si de Pini a Pfin gira en el sentido contrario a las agujas del reloj, - en caso contrario. signo=radioConSigno/abs(radioConSigno) v1=P2recta1.sub(Pini) v1.normalize() #vector de dirección de la recta 1 v2=Pfin.sub(P1recta2) v2.normalize() #vector de dirección de la recta 2 vP1=Base.Vector(-1*signo*v1.y,signo*v1.x) vP1.normalize() #vector de dirección perpendicular a la recta 1 vP1.multiply(abs(radioConSigno)) vP2=Base.Vector(-1*signo*v2.y,signo*v2.x) vP2.normalize() #vector de dirección perpendicular a la recta 2 vP2.multiply(abs(radioConSigno)) Paux1=Pini.add(vP1) Paux2=Paux1.add(v1) Paux3=Pfin.add(vP2) Paux4=Paux3.add(v2) centro=int2rectas(Paux1,Paux2,Paux3,Paux4) vP1.multiply(-1) vP2.multiply(-1) Pfin1=centro.add(vP1) Pini2=centro.add(vP2) segm1=Part.makeLine(Pini,Pfin1) ang1=angVector2DEjeX(vP1) ang2=angVector2DEjeX(vP2) if signo==1: arco=Part.makeCircle(abs(radioConSigno),centro,Base.Vector(0,0,1),ang1,ang2) else: arco=Part.makeCircle(abs(radioConSigno),centro,Base.Vector(0,0,1),ang2,ang1) segm2=Part.makeLine(Pini2,Pfin) linea=Part.Wire([segm1,arco,segm2]) return linea
def arcTo(self, alpha, x, y): """ a is the start angle of the arc from the current point (x, y) is the end point draw an arc from the current point to (x, y) update the current point """ a = radians(alpha) x0, y0 = self.x, self.y # start point self.x, self.y = x, y # update current start point p = x*x + y*y - x0*x0 - y0*y0 q = x0*cos(a) + y0*sin(a) d = (x - x0)*sin(a) - (y - y0)*cos(a) X = (.5*sin(a)*p - (y-y0)*q) / d # center of arc Y = ((x-x0)*q -.5*cos(a)*p) / d r = hypot(X - x, Y - y) g = (y - y0)*cos(a) - (x - x0)*sin(a) a = degrees(copysign(acos((x0 - X)/r), y0 - Y)) b = degrees(copysign(acos((x - X)/r), y - Y)) if g > 0: e = Part.makeCircle(r, fv(X, Y, 0), fv(0, 0, 1), a, b) else: e = Part.makeCircle(r, fv(X, Y, 0), fv(0, 0, 1), b, a) self.addEdge(e)
def execute(self, fp): base=Part.Face(Part.Wire(Part.makeCircle(fp.D/2))) if fp.d>0: base=base.cut(Part.Face(Part.Wire(Part.makeCircle(fp.d/2)))) if fp.n>0: hole=Part.Face(Part.Wire(Part.makeCircle(fp.f/2,FreeCAD.Vector(fp.df/2,0,0),FreeCAD.Vector(0,0,1)))) hole.rotate(FreeCAD.Vector(0,0,0),FreeCAD.Vector(0,0,1),360.0/fp.n/2) for i in list(range(fp.n)): base=base.cut(hole) hole.rotate(FreeCAD.Vector(0,0,0),FreeCAD.Vector(0,0,1),360.0/fp.n) flange = base.extrude(FreeCAD.Vector(0,0,fp.t)) try: # Flange2: raised-face and welding-neck if fp.trf>0 and fp.drf>0: rf=Part.makeCylinder(fp.drf/2,fp.trf,vO,vZ*-1).cut(Part.makeCylinder(fp.d/2,fp.trf,vO,vZ*-1)) flange=flange.fuse(rf) if fp.dwn>0 and fp.twn>0 and fp.ODp>0: wn=Part.makeCone(fp.dwn/2,fp.ODp/2,fp.twn,vZ*float(fp.t)).cut(Part.makeCylinder(fp.d/2,fp.twn,vZ*float(fp.t))) flange=flange.fuse(wn) except: pass fp.Shape = flange fp.Ports=[FreeCAD.Vector(),FreeCAD.Vector(0,0,float(fp.t))] super(Flange,self).execute(fp) # perform common operations
def edge_fillet(edges,radius): """ when given a list of two lines connected lines, returns a list of three curves (line, arc, line) corresponding to a filleted edge """ l1 = edges[0] l2 = edges[1] assert(l1.Curve.EndPoint == l2.Curve.StartPoint) dir1 =l1.Curve.EndPoint - l1.Curve.StartPoint dir2 =l2.Curve.EndPoint - l2.Curve.StartPoint normal = dir1.cross(dir2) raw_angle = math.asin(normal[2]/dir1.Length/dir2.Length) #This is the smaller angle enclosed by the two lines in radians angle = math.pi - abs(raw_angle) #to find the transition points of the fillet, we consider a rectangular #triangle with one kathete equal to the radius and the other one lying on #one of the input lines with length a a = radius/math.tan(0.5*angle) #parameter per length ppl1 = (l1.Curve.LastParameter-l1.Curve.FirstParameter)/l1.Curve.length() ppl2 = (l2.Curve.LastParameter-l2.Curve.FirstParameter)/l2.Curve.length() t1 = l1.Curve.value(l1.Curve.LastParameter - a*ppl1) t2 = l2.Curve.value(l1.Curve.FirstParameter + a*ppl2) #to fine the center of the fillet radius, we construct the angle bisector #between the two input lines, and get the distance of the center from the #common point by a trigonometric consideration bis = Part.makeLine(l1.Curve.EndPoint,(t1+t2).scale(0.5,0.5,0.5)) pplb = (bis.Curve.LastParameter-bis.Curve.FirstParameter)/bis.Curve.length() d = radius/math.sin(0.5*angle) center = bis.Curve.value(bis.Curve.FirstParameter + d*pplb) #to construct the circle we need start and end angles r1 = t1 - center r2 = t2 - center if raw_angle > 0: alpha1 = math.atan2(r1[1],r1[0])*180/math.pi alpha2 = math.atan2(r2[1],r2[0])*180/math.pi else: alpha2 = math.atan2(r1[1],r1[0])*180/math.pi alpha1 = math.atan2(r2[1],r2[0])*180/math.pi normal *= -1 return [Part.makeLine(l1.Curve.StartPoint,t1), Part.makeCircle(radius,center,normal,alpha1,alpha2), Part.makeLine(t2,l2.Curve.EndPoint)]
def vslot(symmetry, vertices, fillets, corner_offset, circle_offsets): outline = assemble(symmetry, vertices) outline = fillet(outline, fillets, 1.5) outline = Part.Wire(outline) holes = [] # corners # x offset, y offset, reverse, switch, mir_x, mir_y corner_symmetry = [ (0, 0, False, False, False, False), (corner_offset, 0, False, False, True, False), (corner_offset, 0, False, False, True, True), (0, 0, False, False, False, True), ] for sym in corner_symmetry: holes.append(Part.Wire(assemble([sym], [vslot_cornerhole]))) if sym[4] == sym[5]: holes[-1].reverse() # circular holes for offset in circle_offsets: holes.append(Part.Wire(Part.makeCircle(2.1, Vector(offset, 0, 0)))) holes[-1].reverse() # big spaces print("Space") for offset in circle_offsets[:-1]: print(space_symmetry, vslot_space) holes.append( Part.Wire(assemble(space_symmetry, 4 * [vslot_space], (offset, 0)))) holes[-1].reverse() print("Space") # put everything together return Part.Face([outline] + holes)
def execute(self, obj): """This method is run when the object is created or recomputed.""" import Part plm = obj.Placement shape = Part.makeCircle(obj.Radius.Value, App.Vector(0, 0, 0), App.Vector(0, 0, 1), obj.FirstAngle.Value, obj.LastAngle.Value) if obj.FirstAngle.Value == obj.LastAngle.Value: shape = Part.Wire(shape) if getattr(obj, "MakeFace", True): shape = Part.Face(shape) obj.Shape = shape if hasattr(obj, "Area") and hasattr(shape, "Area"): obj.Area = shape.Area obj.Placement = plm obj.positionBySupport()
def execute(self, fp): xtotal = fp.xsize.Value * fp.xoccurrences ytotal = fp.ysize.Value * fp.yoccurrences #App.Console.PrintMessage("xtotal,ytotal:" + str(xtotal) + "," + str(ytotal) + "\n") e1 = LineSegment(App.Vector(0, 0, 0), App.Vector(xtotal, 0, 0)).toShape().Edges[0] e2 = LineSegment(App.Vector(xtotal, 0, 0), App.Vector(xtotal, ytotal, 0)).toShape().Edges[0] e3 = LineSegment(App.Vector(xtotal, ytotal, 0), App.Vector(0, ytotal, 0)).toShape().Edges[0] e4 = LineSegment(App.Vector(0, ytotal, 0), App.Vector(0, 0, 0)).toShape().Edges[0] w = Wire([e1, e2, e3, e4]) #hole holes = [] for i in range(fp.xoccurrences): for j in range(fp.yoccurrences): holes.append( Part.Wire( Part.makeCircle( fp.holesize.Value / 2, App.Vector(fp.xsize.Value / 2 + i * fp.xsize.Value, fp.ysize.Value / 2 + j * fp.ysize.Value, 0), App.Vector(0, 0, -1)))) face = Part.Face([w] + holes) baseshape = face.extrude(App.Vector(0, 0, fp.height.Value)) if fp.fillet.Value > 0: borders = [] for i in range(12): borders.append(baseshape.Edges[i]) fp.Shape = baseshape.makeFillet(fp.fillet.Value, borders) else: fp.Shape = face.extrude(App.Vector(0, 0, fp.height.Value))
def testFuse(self): """ Tests fusing one face to another. """ # Face 1 edge1 = Part.makeLine((0, 0, 0), (0, 10, 0)) edge2 = Part.makeLine((0, 10, 0), (10, 10, 0)) edge3 = Part.makeLine((10, 10, 0), (10, 0, 0)) edge4 = Part.makeLine((10, 0, 0), (0, 0, 0)) wire1 = Part.Wire([edge1, edge2, edge3, edge4]) face1 = Part.Face(wire1) cqFace1 = Face(face1) # Face 2 (face to cut out of face 1) edge1 = Part.makeCircle(4.0) wire1 = Part.Wire([edge1]) face2 = Part.Face(wire1) cqFace2 = Face(face2) # Face resulting from fuse cqFace3 = cqFace1.fuse(cqFace2) self.assertEquals(len(cqFace3.Faces()), 3) self.assertEquals(len(cqFace3.Edges()), 8)
def testIntersect(self): """ Tests finding the intersection of two faces. """ # Face 1 edge1 = Part.makeLine((0, 0, 0), (0, 10, 0)) edge2 = Part.makeLine((0, 10, 0), (10, 10, 0)) edge3 = Part.makeLine((10, 10, 0), (10, 0, 0)) edge4 = Part.makeLine((10, 0, 0), (0, 0, 0)) wire1 = Part.Wire([edge1, edge2, edge3, edge4]) face1 = Part.Face(wire1) cqFace1 = Face(face1) # Face 2 (face to cut out of face 1) edge1 = Part.makeCircle(4.0) wire1 = Part.Wire([edge1]) face2 = Part.Face(wire1) cqFace2 = Face(face2) # Face resulting from the intersection cqFace3 = cqFace1.intersect(cqFace2) self.assertEquals(len(cqFace3.Faces()), 1) self.assertEquals(len(cqFace3.Edges()), 3)
def MountingHole(self,yBase,yHeight): mhorig = Base.Vector(self.holeorig.x,yBase,self.holeorig.z) vthick = Base.Vector(0,yHeight,0) YNorm = Base.Vector(0,1,0) hole = Part.Face(Part.Wire(Part.makeCircle(self.bracketholedia()/2,mhorig,YNorm))).extrude(vthick) return hole
def setup(doc=None, solvertype="ccxtools"): # setup model if doc is None: doc = init_doc() # parts # TODO turn circle of upper tube to have the line on the other side # make a boolean fragment of them to be sure there is a mesh point on remesh # but as long as we do not remesh it works without the boolean fragment too # tubes tube_radius = 25 tube_length = 500 sh_lower_circle = Part.Wire(Part.makeCircle(tube_radius)) sh_lower_tube = sh_lower_circle.extrude(FreeCAD.Vector(0, 0, tube_length)) sh_lower_tube.reverse() lower_tube = doc.addObject("Part::Feature", "Lower_tube") lower_tube.Shape = sh_lower_tube sh_upper_circle = Part.Wire(Part.makeCircle(tube_radius)) sh_upper_tube = sh_upper_circle.extrude(FreeCAD.Vector(0, 0, tube_length)) sh_upper_tube.reverse() upper_tube = doc.addObject("Part::Feature", "Upper_tube") upper_tube.Shape = sh_upper_tube upper_tube.Placement = FreeCAD.Placement( FreeCAD.Vector(-25, 51, 475), FreeCAD.Rotation(90, 0, 90), FreeCAD.Vector(0, 0, 0), ) # point for load v_force_pt = FreeCAD.Vector(0, 76, 475) sh_force_point = Part.Vertex(v_force_pt) force_point = doc.addObject("Part::Feature", "Load_place_point") force_point.Shape = sh_force_point if FreeCAD.GuiUp: force_point.ViewObject.PointSize = 10.0 force_point.ViewObject.PointColor = (1.0, 0.0, 0.0) BooleanFrag = BOPTools.SplitFeatures.makeBooleanFragments( name='BooleanFragments') BooleanFrag.Objects = [upper_tube, force_point] if FreeCAD.GuiUp: upper_tube.ViewObject.hide() compound = doc.addObject("Part::Compound", "Compound") compound.Links = [BooleanFrag, lower_tube] # line for load direction sh_load_line = Part.makeLine(v_force_pt, FreeCAD.Vector(0, 150, 475)) load_line = doc.addObject("Part::Feature", "Load_direction_line") load_line.Shape = sh_load_line if FreeCAD.GuiUp: load_line.ViewObject.LineWidth = 5.0 load_line.ViewObject.LineColor = (1.0, 0.0, 0.0) doc.recompute() if FreeCAD.GuiUp: import FreeCADGui FreeCADGui.ActiveDocument.activeView().viewAxonometric() FreeCADGui.SendMsgToActiveView("ViewFit") # analysis analysis = ObjectsFem.makeAnalysis(doc, "Analysis") # solver if solvertype == "calculix": solver_object = analysis.addObject( ObjectsFem.makeSolverCalculix(doc, "SolverCalculiX"))[0] elif solvertype == "ccxtools": solver_object = analysis.addObject( ObjectsFem.makeSolverCalculixCcxTools(doc, "CalculiXccxTools"))[0] solver_object.WorkingDir = u"" if solvertype == "calculix" or solvertype == "ccxtools": solver_object.AnalysisType = "static" solver_object.BeamShellResultOutput3D = True solver_object.GeometricalNonlinearity = "linear" # really? # TODO iterations parameter !!! solver_object.ThermoMechSteadyState = False solver_object.MatrixSolverType = "default" solver_object.IterationsControlParameterTimeUse = False solver_object.SplitInputWriter = False # shell thickness analysis.addObject( ObjectsFem.makeElementGeometry2D(doc, 0.5, 'ShellThickness')) # material material_obj = analysis.addObject( ObjectsFem.makeMaterialSolid(doc, "MechanicalMaterial"))[0] mat = material_obj.Material mat["Name"] = "AlCuMgPb" mat["YoungsModulus"] = "72000 MPa" mat["PoissonRatio"] = "0.30" material_obj.Material = mat analysis.addObject(material_obj) # fixed_constraint fixed_constraint = analysis.addObject( ObjectsFem.makeConstraintFixed(doc, "ConstraintFixed"))[0] fixed_constraint.References = [ (lower_tube, "Edge2"), (upper_tube, "Edge3"), ] # force_constraint force_constraint = doc.Analysis.addObject( ObjectsFem.makeConstraintForce(doc, name="ConstraintForce"))[0] # TODO use point of tube boolean fragment force_constraint.References = [(force_point, "Vertex1")] force_constraint.Force = 5000.0 force_constraint.Direction = (load_line, ["Edge1"]) force_constraint.Reversed = True # contact constraint contact_constraint = doc.Analysis.addObject( ObjectsFem.makeConstraintContact(doc, name="ConstraintContact"))[0] contact_constraint.References = [ (lower_tube, "Face1"), (upper_tube, "Face1"), ] contact_constraint.Friction = 0.0 # contact_constrsh_aint.Slope = "1000000.0 kg/(mm*s^2)" # contact stiffness contact_constraint.Slope = 1000000.0 # should be 1000000.0 kg/(mm*s^2) # mesh from .meshes.mesh_contact_tube_tube_tria3 import create_nodes, create_elements fem_mesh = Fem.FemMesh() control = create_nodes(fem_mesh) if not control: FreeCAD.Console.PrintError("Error on creating nodes.\n") control = create_elements(fem_mesh) if not control: FreeCAD.Console.PrintError("Error on creating elements.\n") femmesh_obj = analysis.addObject( doc.addObject("Fem::FemMeshObject", mesh_name))[0] femmesh_obj.FemMesh = fem_mesh doc.recompute() return doc
def getDeviation(self): "returns a deviation vector that represents the base of the circle" import Part c = Part.makeCircle(1,Vector(0,0,0),self.normal) return c.Vertexes[0].Point
def __init__(self, name, origin): self.name = name if not isinstance(origin, Base.Vector): raise RuntimeError("origin is not a Vector") self.origin = origin ox = origin.x oy = origin.y oz = origin.z boardsurf = Part.makePlane(PCBwithStrips._psPCBwidth, PCBwithStrips._psPCBlength, origin) xh = (ox + PCBwithStrips._stripIncr) while xh <= ox + PCBwithStrips._psPCBwidth: yh = oy + PCBwithStrips._stripIncr while yh <= oy + PCBwithStrips._psPCBlength: boardsurf = self._drill_leadhole(boardsurf, xh, yh, oz) yh += PCBwithStrips._stripIncr xh += PCBwithStrips._stripIncr self.mhvector = { 1: Base.Vector(ox + PCBwithStrips._stripIncr, oy + (PCBwithStrips._stripIncr + 5 * 2.54), oz), 2: Base.Vector( ox + (PCBwithStrips._psPCBwidth - PCBwithStrips._stripIncr), oy + (PCBwithStrips._stripIncr + 5 * 2.54), oz), 3: Base.Vector( ox + PCBwithStrips._stripIncr, oy + (PCBwithStrips._psPCBlength - (PCBwithStrips._stripIncr + 5 * 2.54)), oz), 4: Base.Vector( ox + (PCBwithStrips._psPCBwidth - PCBwithStrips._stripIncr), oy + (PCBwithStrips._psPCBlength - (PCBwithStrips._stripIncr + 5 * 2.54)), oz) } mh1circ = Part.makeCircle(PCBwithStrips._mhdia / 2.0, self.mhvector[1]) mh1wire = Part.Wire(mh1circ) mh1 = Part.Face(mh1wire) boardsurf = boardsurf.cut(mh1) mh2circ = Part.makeCircle(PCBwithStrips._mhdia / 2.0, self.mhvector[2]) mh2wire = Part.Wire(mh2circ) mh2 = Part.Face(mh2wire) boardsurf = boardsurf.cut(mh2) mh3circ = Part.makeCircle(PCBwithStrips._mhdia / 2.0, self.mhvector[3]) mh3wire = Part.Wire(mh3circ) mh3 = Part.Face(mh3wire) boardsurf = boardsurf.cut(mh3) mh4circ = Part.makeCircle(PCBwithStrips._mhdia / 2.0, self.mhvector[4]) mh4wire = Part.Wire(mh4circ) mh4 = Part.Face(mh4wire) boardsurf = boardsurf.cut(mh4) self.board = boardsurf.extrude( Base.Vector(0, 0, PCBwithStrips._psPCBThickness)) mh = { 1: Part.Face( Part.Wire( Part.makeCircle( PCBwithStrips._mhdia / 2.0, Base.Vector(self.mhvector[1].x, self.mhvector[1].y, oz - PCBwithStrips._stripThickness)))), 2: Part.Face( Part.Wire( Part.makeCircle( PCBwithStrips._mhdia / 2.0, Base.Vector(self.mhvector[2].x, self.mhvector[2].y, oz - PCBwithStrips._stripThickness)))), 3: Part.Face( Part.Wire( Part.makeCircle( PCBwithStrips._mhdia / 2.0, Base.Vector(self.mhvector[3].x, self.mhvector[3].y, oz - PCBwithStrips._stripThickness)))), 4: Part.Face( Part.Wire( Part.makeCircle( PCBwithStrips._mhdia / 2.0, Base.Vector(self.mhvector[4].x, self.mhvector[4].y, oz - PCBwithStrips._stripThickness)))) } yoff = (PCBwithStrips._psPCBlength - PSK_S15C._pslength) / 2.0 xoff = (PCBwithStrips._psPCBwidth - PSK_S15C._pswidth) / 2.0 pin1X = PSK_S15C._pspin1Yoff + xoff pin2X = PSK_S15C._pspin2Yoff + xoff sx = PCBwithStrips._stripIncr self.strips = list() while (sx + PCBwithStrips._stripIncr) <= PCBwithStrips._psPCBwidth: if sx <= pin1X and sx >= pin2X: stripCP1 = Base.Vector( ox + (sx - (PCBwithStrips._stripWidth / 2.0)), oy + PCBwithStrips._stripOffset, oz - PCBwithStrips._stripThickness) stripCP2 = Base.Vector( ox + (sx - (PCBwithStrips._stripWidth / 2.0)), oy + (PCBwithStrips._stripOffset + yoff + PSK_S15C._pspin1Xoff - PCBwithStrips._stripExtra - 2.54), oz - PCBwithStrips._stripThickness) striplen = yoff + PSK_S15C._pspin4Xoff + PCBwithStrips._stripExtra stripsurf = Part.makePlane(PCBwithStrips._stripWidth, striplen, stripCP1) xh = stripCP1.x + (PCBwithStrips._stripWidth / 2.0) yh = stripCP1.y + PCBwithStrips._stripOffset while yh < stripCP1.y + striplen: stripsurf = self._drill_leadhole(stripsurf, xh, yh, stripCP1.z) yh += PCBwithStrips._stripIncr strip = stripsurf.extrude( Base.Vector(0, 0, PCBwithStrips._stripThickness)) self.strips.append(strip) stripsurf = Part.makePlane(PCBwithStrips._stripWidth, striplen, stripCP2) xh = stripCP2.x + (PCBwithStrips._stripWidth / 2.0) yh = stripCP2.y + PCBwithStrips._stripOffset while yh < stripCP2.y + striplen: stripsurf = self._drill_leadhole(stripsurf, xh, yh, stripCP2.z) yh += PCBwithStrips._stripIncr strip = stripsurf.extrude( Base.Vector(0, 0, PCBwithStrips._stripThickness)) self.strips.append(strip) else: stripCP = Base.Vector( ox + (sx - (PCBwithStrips._stripWidth / 2.0)), oy + PCBwithStrips._stripOffset, oz - PCBwithStrips._stripThickness) stripsurf = Part.makePlane( PCBwithStrips._stripWidth, PCBwithStrips._psPCBlength - (PCBwithStrips._stripOffset * 2), stripCP) xh = stripCP.x + (PCBwithStrips._stripWidth / 2.0) yh = stripCP.y + PCBwithStrips._stripOffset while yh < stripCP.y + PCBwithStrips._psPCBlength - ( PCBwithStrips._stripOffset * 2): stripsurf = self._drill_leadhole(stripsurf, xh, yh, stripCP.z) yh += PCBwithStrips._stripIncr i = 1 while i <= 4: h = self.mhvector[i] stripsurf = stripsurf.cut(mh[i]) i += 1 strip = stripsurf.extrude( Base.Vector(0, 0, PCBwithStrips._stripThickness)) self.strips.append(strip) sx += PCBwithStrips._stripIncr
def MountingHole(self, i, zBase): mhv = self.mhvector[i] mhz = Base.Vector(mhv.x, mhv.y, zBase) mhcirc = Part.makeCircle(self._mhdia / 2.0, mhz) mhwire = Part.Wire(mhcirc) return Part.Face(mhwire)
def _drill_leadhole(self, surf, x, y, z): return (surf.cut( Part.Face( Part.Wire( Part.makeCircle(self._leadhole_r, Base.Vector(x, y, z))))))
def runmode2(self, fp, prop): f=fp.source.Shape.Faces[fp.faceNumber-1] nf=f.toNurbs() ff=nf.Face1 ff.ParameterRange sf=ff.Surface u=0.01*fp.u v=0.01*fp.v p=sf.value(u,v) [t1,t2]=sf.tangent(u,v) sf.parameter(t1) sf.parameter(t2) c1,c2=sf.curvatureDirections(u,v) cmax=sf.curvature(u,v,"Max") cmin=sf.curvature(u,v,"Min") if cmax <>0: rmax=1.0/cmax else: rmax=0 if cmin <>0: rmin=1.0/cmin else: rmin=0 n=sf.normal(u,v) if rmax>fp.maxRadius: rmax=fp.maxRadius cmax=0 if rmax<-fp.maxRadius: rmax=-fp.maxRadius cmax=0 if rmin>fp.maxRadius: rmin=fp.maxRadius cmin=0 if rmin<-fp.maxRadius: rmin=-fp.maxRadius cmin=0 m2=p+n*rmin m1=p+n*rmax pts=[p,m2,p,m1] print (rmin,rmax) comp=[] try: comp +=[Part.makePolygon([p,m2])] except: pass try: comp += [Part.makePolygon([p,m1])] except: pass k=fp.maxRadius if cmax==0: c=Part.makePolygon([p-c1*k,p+c1*k]) else: c=Part.makeCircle(abs(rmax),m1,c2) comp += [c] if cmin==0: c=Part.makePolygon([p-c2*k,p+c2*k]) else: c=Part.makeCircle(abs(rmin),m2,c1) comp += [c] print "done" fp.Shape=Part.Compound(comp)
def __init__(self, name, origin): PCBwithStrips.__init__(self, name, origin) ox = origin.x oy = origin.y oz = origin.z yoff = (PCBwithStrips._psPCBlength - PSK_S15C._pslength) / 2.0 xoff = (PCBwithStrips._psPCBwidth - PSK_S15C._pswidth) / 2.0 psorigin = Base.Vector(ox + xoff, oy + yoff, oz + PCBwithStrips._psPCBThickness) self.powersupply = PSK_S15C(name + "_powersupply", psorigin) actermorigin = Base.Vector( ox + (PCBwithStrips._psPCBwidth - PCBwithStrips._psactermyoff - TB007_508_03BE.Length()), oy + (PCBwithStrips._psPCBlength - PCBwithStrips._pstermxoff - TB007_508_xxBE._termwidth), oz + PCBwithStrips._psPCBThickness) self.acterm = TB007_508_03BE(name + "_acterm", actermorigin) dctermorigin = Base.Vector( ox + (PCBwithStrips._psPCBwidth - PCBwithStrips._psdctermyoff - TB007_508_02BE.Length()), oy + (PCBwithStrips._pstermxoff), oz + PCBwithStrips._psPCBThickness) self.dcterm = TB007_508_02BE(name + "_dcterm", dctermorigin) self.bypasscap = C333( name + "_bypasscap", Base.Vector(ox + PSOnPCB._bypassY, oy + PSOnPCB._bypassX, oz)) self.filtercap = AL_CAP_Radial_5mm10x12_5( name + "_filtercap", Base.Vector(ox + PSOnPCB._filterY, oy + PSOnPCB._filterX, oz + PCBwithStrips._psPCBThickness)) self.esd = DO_15_bendedLeads_400_under( name + "_esd", Base.Vector(ox + PSOnPCB._esdY, oy + PSOnPCB._esdX, oz)) self.fuseholder = Littlefuse_FuseHolder_02810007H_02810010H( name + "_fuseholder", Base.Vector(ox + PSOnPCB._fuseholderY, oy + PSOnPCB._fuseholderX, oz + PCBwithStrips._psPCBThickness)) self.mov = B72220S2301K101( name + "_mov", Base.Vector( ox + (PCBwithStrips._psPCBwidth / 2.0), oy + ((PCBwithStrips._psPCBlength - (yoff + PSK_S15C._pspin3Xoff + 3) + 3.81)), oz)) groundj1X = oy + ((PCBwithStrips._psPCBlength / 2.0)) groundj1Y = ox + ((PSK_S15C._pspin1Yoff) + yoff) groundj1L = 20.32 + 5.08 wireradius = PSOnPCB._wiredia / 2.0 XNorm = Base.Vector(1, 0, 0) YNorm = Base.Vector(0, 1, 0) self.groundwires = list() g1 = Part.Face( Part.Wire( Part.makeCircle( wireradius, Base.Vector(groundj1Y, groundj1X, oz - wireradius), XNorm))).extrude(Base.Vector(-groundj1L, 0, 0)) self.groundwires.append(g1) for i in [1, 2, 3]: yy = i * 2.54 xx = (i & 1) * 2.54 y1 = groundj1Y + yy y2 = groundj1Y - groundj1L - yy x = groundj1X - xx gA = Part.Face( Part.Wire( Part.makeCircle(wireradius, Base.Vector(y1, x, oz - wireradius), XNorm))).extrude(Base.Vector(-2.54, 0, 0)) gB = Part.Face( Part.Wire( Part.makeCircle(wireradius, Base.Vector(y2, x, oz - wireradius), XNorm))).extrude(Base.Vector(2.54, 0, 0)) self.groundwires.append(gA) self.groundwires.append(gB) self.linewires = list() l1Y = ox + PCBwithStrips._psactermyoff + (7 * 2.54) l1X = oy + PCBwithStrips._psPCBlength - (5.08 + 2.54) l1L = 5.08 l1 = Part.Face( Part.Wire( Part.makeCircle(wireradius, Base.Vector(l1Y, l1X, oz - wireradius), XNorm))).extrude(Base.Vector(l1L, 0, 0)) self.linewires.append(l1) l2Y = l1Y - 5.08 - 5.08 l2X = oy + PCBwithStrips._psPCBlength - 5.08 l2L = 5.08 l2 = Part.Face( Part.Wire( Part.makeCircle(wireradius, Base.Vector(l2Y, l2X, oz - wireradius), XNorm))).extrude(Base.Vector(l2L, 0, 0)) self.linewires.append(l2) self.minuswires = list() M1Y = ox + PCBwithStrips._psdctermyoff + (5 * 2.54) M1X = oy + PCBwithStrips._pstermxoff + (TB007_508_xxBE._termwidth / 2.0) + 2.54 M1L = 5.08 m1 = Part.Face( Part.Wire( Part.makeCircle(wireradius, Base.Vector(M1Y, M1X, oz - wireradius), XNorm))).extrude(Base.Vector(M1L, 0, 0)) self.minuswires.append(m1) M2Y = M1Y - M1L - 2.54 M2X = M1X + 2.54 M2L = 7.62 m2 = Part.Face( Part.Wire( Part.makeCircle(wireradius, Base.Vector(M2Y, M2X, oz - wireradius), XNorm))).extrude(Base.Vector(M2L, 0, 0)) self.minuswires.append(m2) self.pluswires = list() P1Y = ox + PCBwithStrips._psdctermyoff + 5.08 + 5.08 P1X = M2X + 2.54 P1L = 2.54 * 5 p1 = Part.Face( Part.Wire( Part.makeCircle(wireradius, Base.Vector(P1Y, P1X, oz - wireradius), XNorm))).extrude(Base.Vector(P1L, 0, 0)) self.pluswires.append(p1)
def onChanged(self, vobj, prop): if prop == "LineColor": l = vobj.LineColor self.mat.diffuseColor.setValue([l[0], l[1], l[2]]) elif prop == "DrawStyle": if vobj.DrawStyle == "Solid": self.linestyle.linePattern = 0xffff elif vobj.DrawStyle == "Dashed": self.linestyle.linePattern = 0xf00f elif vobj.DrawStyle == "Dotted": self.linestyle.linePattern = 0x0f0f else: self.linestyle.linePattern = 0xff88 elif prop == "LineWidth": self.linestyle.lineWidth = vobj.LineWidth elif prop in ["BubbleSize", "BubblePosition", "FontName", "FontSize"]: if hasattr(self, "bubbleset"): if self.bubbles: self.bubbleset.removeChild(self.bubbles) self.bubbles = None if vobj.Object.Shape: if vobj.Object.Shape.Edges: self.bubbles = coin.SoSeparator() self.bubblestyle = coin.SoDrawStyle() self.bubblestyle.linePattern = 0xffff self.bubbles.addChild(self.bubblestyle) import Part, Draft self.bubbletexts = [] pos = ["Start"] if hasattr(vobj, "BubblePosition"): if vobj.BubblePosition == "Both": pos = ["Start", "End"] elif vobj.BubblePosition == "None": pos = [] else: pos = [vobj.BubblePosition] for i in range(len(vobj.Object.Shape.Edges)): for p in pos: verts = vobj.Object.Shape.Edges[i].Vertexes if p == "Start": p1 = verts[0].Point p2 = verts[1].Point else: p1 = verts[1].Point p2 = verts[0].Point dv = p2.sub(p1) dv.normalize() if hasattr(vobj.BubbleSize, "Value"): rad = vobj.BubbleSize.Value / 2 else: rad = vobj.BubbleSize / 2 center = p2.add(dv.scale(rad, rad, rad)) buf = Part.makeCircle(rad, center).writeInventor() try: cin = coin.SoInput() cin.setBuffer(buf) cob = coin.SoDB.readAll(cin) except: import re # workaround for pivy SoInput.setBuffer() bug buf = buf.replace("\n", "") pts = re.findall("point \[(.*?)\]", buf)[0] pts = pts.split(",") pc = [] for p in pts: v = p.strip().split() pc.append([ float(v[0]), float(v[1]), float(v[2]) ]) coords = coin.SoCoordinate3() coords.point.setValues(0, len(pc), pc) line = coin.SoLineSet() line.numVertices.setValue(-1) else: coords = cob.getChild(1).getChild( 0).getChild(2) line = cob.getChild(1).getChild( 0).getChild(3) self.bubbles.addChild(coords) self.bubbles.addChild(line) st = coin.SoSeparator() tr = coin.SoTransform() fs = rad * 1.5 if hasattr(vobj, "FontSize"): fs = vobj.FontSize.Value tr.translation.setValue( (center.x, center.y - fs / 2.5, center.z)) fo = coin.SoFont() fn = Draft.getParam("textfont", "Arial,Sans") if hasattr(vobj, "FontName"): if vobj.FontName: try: fn = str(vobj.FontName) except: pass fo.name = fn fo.size = fs tx = coin.SoAsciiText() tx.justification = coin.SoText2.CENTER self.bubbletexts.append(tx) st.addChild(tr) st.addChild(fo) st.addChild(tx) self.bubbles.addChild(st) self.bubbleset.addChild(self.bubbles) self.onChanged(vobj, "NumberingStyle") if prop in ["FontName", "FontSize"]: self.onChanged(vobj, "ShowLabel") elif prop in ["NumberingStyle", "StartNumber"]: if hasattr(self, "bubbletexts"): chars = "abcdefghijklmnopqrstuvwxyz" roman = (('M', 1000), ('CM', 900), ('D', 500), ('CD', 400), ('C', 100), ('XC', 90), ('L', 50), ('XL', 40), ('X', 10), ('IX', 9), ('V', 5), ('IV', 4), ('I', 1)) num = 0 if hasattr(vobj, "StartNumber"): if vobj.StartNumber > 1: num = vobj.StartNumber - 1 alt = False for t in self.bubbletexts: if hasattr(vobj, "NumberingStyle"): if vobj.NumberingStyle == "1,2,3": t.string = str(num + 1) elif vobj.NumberingStyle == "01,02,03": t.string = str(num + 1).zfill(2) elif vobj.NumberingStyle == "001,002,003": t.string = str(num + 1).zfill(3) elif vobj.NumberingStyle == "A,B,C": result = "" base = num / 26 if base: result += chars[base].upper() remainder = num % 26 result += chars[remainder].upper() t.string = result elif vobj.NumberingStyle == "a,b,c": result = "" base = num / 26 if base: result += chars[base] remainder = num % 26 result += chars[remainder] t.string = result elif vobj.NumberingStyle == "I,II,III": result = "" n = num n += 1 for numeral, integer in roman: while n >= integer: result += numeral n -= integer t.string = result elif vobj.NumberingStyle == "L0,L1,L2": t.string = "L" + str(num) else: t.string = str(num + 1) num += 1 if hasattr(vobj, "BubblePosition"): if vobj.BubblePosition == "Both": if not alt: num -= 1 alt = not alt elif prop in ["ShowLabel", "LabelOffset"]: if hasattr(self, "labels"): if self.labels: self.labelset.removeChild(self.labels) self.labels = None if hasattr(vobj, "ShowLabel") and hasattr(vobj.Object, "Labels"): if vobj.ShowLabel: self.labels = coin.SoSeparator() for i in range(len(vobj.Object.Shape.Edges)): if len(vobj.Object.Labels) > i: if vobj.Object.Labels[i]: import Draft vert = vobj.Object.Shape.Edges[i].Vertexes[ 0].Point if hasattr(vobj, "LabelOffset"): pl = FreeCAD.Placement(vobj.LabelOffset) pl.Base = vert.add(pl.Base) st = coin.SoSeparator() tr = coin.SoTransform() fo = coin.SoFont() tx = coin.SoAsciiText() tx.justification = coin.SoText2.LEFT t = vobj.Object.Labels[i] if isinstance(t, unicode): t = t.encode("utf8") tx.string.setValue(t) if hasattr(vobj, "FontSize"): fs = vobj.FontSize.Value elif hasattr(vobj.BubbleSize, "Value"): fs = vobj.BubbleSize.Value * 0.75 else: fs = vobj.BubbleSize * 0.75 tr.translation.setValue(tuple(pl.Base)) tr.rotation.setValue(pl.Rotation.Q) fn = Draft.getParam("textfont", "Arial,Sans") if hasattr(vobj, "FontName"): if vobj.FontName: try: fn = str(vobj.FontName) except: pass fo.name = fn fo.size = fs st.addChild(tr) st.addChild(fo) st.addChild(tx) self.labels.addChild(st) self.labelset.addChild(self.labels)
def updateData(self, obj, prop): if hasattr(self, "arc"): from pivy import coin import Part, DraftGeomUtils import DraftGui arcsegs = 24 # calculate the arc data if DraftVecUtils.isNull(obj.Normal): norm = App.Vector(0, 0, 1) else: norm = obj.Normal radius = (obj.Dimline.sub(obj.Center)).Length self.circle = Part.makeCircle(radius, obj.Center, norm, obj.FirstAngle.Value, obj.LastAngle.Value) self.p2 = self.circle.Vertexes[0].Point self.p3 = self.circle.Vertexes[-1].Point mp = DraftGeomUtils.findMidpoint(self.circle.Edges[0]) ray = mp.sub(obj.Center) # set text value if obj.LastAngle.Value > obj.FirstAngle.Value: a = obj.LastAngle.Value - obj.FirstAngle.Value else: a = (360 - obj.FirstAngle.Value) + obj.LastAngle.Value su = True if hasattr(obj.ViewObject, "ShowUnit"): su = obj.ViewObject.ShowUnit if hasattr(obj.ViewObject, "Decimals"): self.string = DraftGui.displayExternal(a, obj.ViewObject.Decimals, 'Angle', su) else: self.string = DraftGui.displayExternal(a, None, 'Angle', su) if obj.ViewObject.Override: self.string = obj.ViewObject.Override.replace("$dim",\ self.string) self.text.string = self.text3d.string = utils.string_encode_coin( self.string) # check display mode try: m = obj.ViewObject.DisplayMode except: # swallow all exceptions here since it always fails on first run (Displaymode enum no set yet) m = ["2D", "3D"][utils.get_param("dimstyle", 0)] # set the arc if m == "3D": # calculate the spacing of the text spacing = (len(self.string) * obj.ViewObject.FontSize.Value) / 8.0 pts1 = [] cut = None pts2 = [] for i in range(arcsegs + 1): p = self.circle.valueAt(self.circle.FirstParameter + ( (self.circle.LastParameter - self.circle.FirstParameter) / arcsegs) * i) if (p.sub(mp)).Length <= spacing: if cut is None: cut = i else: if cut is None: pts1.append([p.x, p.y, p.z]) else: pts2.append([p.x, p.y, p.z]) self.coords.point.setValues(pts1 + pts2) i1 = len(pts1) i2 = i1 + len(pts2) self.arc.coordIndex.setValues( 0, len(pts1) + len(pts2) + 1, list(range(len(pts1))) + [-1] + list(range(i1, i2))) if (len(pts1) >= 3) and (len(pts2) >= 3): self.circle1 = Part.Arc( App.Vector(pts1[0][0], pts1[0][1], pts1[0][2]), App.Vector(pts1[1][0], pts1[1][1], pts1[1][2]), App.Vector(pts1[-1][0], pts1[-1][1], pts1[-1][2])).toShape() self.circle2 = Part.Arc( App.Vector(pts2[0][0], pts2[0][1], pts2[0][2]), App.Vector(pts2[1][0], pts2[1][1], pts2[1][2]), App.Vector(pts2[-1][0], pts2[-1][1], pts2[-1][2])).toShape() else: pts = [] for i in range(arcsegs + 1): p = self.circle.valueAt(self.circle.FirstParameter + ( (self.circle.LastParameter - self.circle.FirstParameter) / arcsegs) * i) pts.append([p.x, p.y, p.z]) self.coords.point.setValues(pts) self.arc.coordIndex.setValues(0, arcsegs + 1, list(range(arcsegs + 1))) # set the arrow coords and rotation self.trans1.translation.setValue((self.p2.x, self.p2.y, self.p2.z)) self.coord1.point.setValue((self.p2.x, self.p2.y, self.p2.z)) self.trans2.translation.setValue((self.p3.x, self.p3.y, self.p3.z)) self.coord2.point.setValue((self.p3.x, self.p3.y, self.p3.z)) # calculate small chords to make arrows look better arrowlength = 4 * obj.ViewObject.ArrowSize.Value u1 = (self.circle.valueAt(self.circle.FirstParameter + arrowlength) ).sub(self.circle.valueAt( self.circle.FirstParameter)).normalize() u2 = (self.circle.valueAt(self.circle.LastParameter)).sub( self.circle.valueAt(self.circle.LastParameter - arrowlength)).normalize() if hasattr(obj.ViewObject, "FlipArrows"): if obj.ViewObject.FlipArrows: u1 = u1.negative() u2 = u2.negative() w2 = self.circle.Curve.Axis w1 = w2.negative() v1 = w1.cross(u1) v2 = w2.cross(u2) q1 = App.Placement(DraftVecUtils.getPlaneRotation(u1, v1, w1)).Rotation.Q q2 = App.Placement(DraftVecUtils.getPlaneRotation(u2, v2, w2)).Rotation.Q self.trans1.rotation.setValue((q1[0], q1[1], q1[2], q1[3])) self.trans2.rotation.setValue((q2[0], q2[1], q2[2], q2[3])) # setting text pos & rot self.tbase = mp if hasattr(obj.ViewObject, "TextPosition"): if not DraftVecUtils.isNull(obj.ViewObject.TextPosition): self.tbase = obj.ViewObject.TextPosition u3 = ray.cross(norm).normalize() v3 = norm.cross(u3) r = App.Placement(DraftVecUtils.getPlaneRotation(u3, v3, norm)).Rotation offset = r.multVec(App.Vector(0, 1, 0)) if hasattr(obj.ViewObject, "TextSpacing"): offset = DraftVecUtils.scaleTo( offset, obj.ViewObject.TextSpacing.Value) else: offset = DraftVecUtils.scaleTo(offset, 0.05) if m == "3D": offset = offset.negative() self.tbase = self.tbase.add(offset) q = r.Q self.textpos.translation.setValue( [self.tbase.x, self.tbase.y, self.tbase.z]) self.textpos.rotation = coin.SbRotation(q[0], q[1], q[2], q[3]) # set the angle property if round(obj.Angle, utils.precision()) != round( a, utils.precision()): obj.Angle = a
def USBJackCutoutHole(self,xPanel): cutoutOrig = self.origin.add(Base.Vector(-40,\ self._FeatherYUSB_Offset+self._FeatherYBoardOffset,\ 62.5 + 196.5 + 100 + 62.5)) cutoutOrig = Base.Vector(xPanel,cutoutOrig.y+110,cutoutOrig.z+55) return Part.Face(Part.Wire(Part.makeCircle(175,cutoutOrig,Base.Vector(1,0,0))))
def execute(self, obj): if self.clone(obj): return if len(obj.InList) != 1: return if Draft.getType(obj.InList[0]) != "Structure": return if not obj.InList[0].Shape: return if not obj.Base: return if not obj.Base.Shape: return if not obj.Base.Shape.Wires: return if not obj.Diameter.Value: return if not obj.Amount: return father = obj.InList[0] wire = obj.Base.Shape.Wires[0] if hasattr(obj, "Rounding"): #print obj.Rounding if obj.Rounding: radius = obj.Rounding * obj.Diameter.Value import DraftGeomUtils wire = DraftGeomUtils.filletWire(wire, radius) bpoint, bvec = self.getBaseAndAxis(wire) if not bpoint: return axis = obj.Base.Placement.Rotation.multVec(FreeCAD.Vector(0, 0, -1)) size = (ArchCommands.projectToVector(father.Shape.copy(), axis)).Length if hasattr(obj, "Direction"): if not DraftVecUtils.isNull(obj.Direction): axis = FreeCAD.Vector(obj.Direction) #.normalize() # don't normalize so the vector can also be used to determine the distance size = axis.Length #print axis #print size if (obj.OffsetStart.Value + obj.OffsetEnd.Value) > size: return # all tests ok! pl = obj.Placement import Part circle = Part.makeCircle(obj.Diameter.Value / 2, bpoint, bvec) circle = Part.Wire(circle) try: bar = wire.makePipeShell([circle], True, False, 2) except Part.OCCError: print "Arch: error sweeping rebar profile along the base sketch" return # building final shape shapes = [] if obj.Amount == 1: offset = DraftVecUtils.scaleTo(axis, size / 2) bar.translate(offset) shapes.append(bar) if hasattr(obj, "Spacing"): obj.Spacing = 0 else: if obj.OffsetStart.Value: baseoffset = DraftVecUtils.scaleTo(axis, obj.OffsetStart.Value) else: baseoffset = None interval = size - (obj.OffsetStart.Value + obj.OffsetEnd.Value) interval = interval / (obj.Amount - 1) vinterval = DraftVecUtils.scaleTo(axis, interval) for i in range(obj.Amount): if i == 0: if baseoffset: bar.translate(baseoffset) shapes.append(bar) else: bar = bar.copy() bar.translate(vinterval) shapes.append(bar) if hasattr(obj, "Spacing"): obj.Spacing = interval if shapes: obj.Shape = Part.makeCompound(shapes) obj.Placement = pl
def execute(self, obj): if self.clone(obj): return if not obj.Base and ((not obj.Shape) or (not obj.Shape.isNull())): # let pass without error if we already have a shape return if not obj.Base: FreeCAD.Console.PrintError( "No Base, return without a rebar shape for {}.\n".format( obj.Name)) return if not hasattr(obj.Base, "Shape") or ( not obj.Base.Shape) or obj.Base.Shape.isNull(): FreeCAD.Console.PrintError( "No Shape in Base, return without a rebar shape for {}.\n". format(obj.Name)) return if obj.Base.Shape.Faces: FreeCAD.Console.PrintError( "Faces in Shape of Base, return without a rebar shape for {}.\n" .format(obj.Name)) return if not obj.Base.Shape.Edges: FreeCAD.Console.PrintError( "No Edges in Shape of Base, return without a rebar shape for {}.\n" .format(obj.Name)) return if not obj.Diameter.Value: FreeCAD.Console.PrintError( "No Diameter Value, return without a rebar shape for {}.\n". format(obj.Name)) return if not obj.Amount: FreeCAD.Console.PrintError( "No Amount, return without a rebar shape for {}.\n".format( obj.Name)) return father = obj.Host fathershape = None if not father: # support for old-style rebars if obj.InList: if hasattr(obj.InList[0], "Armatures"): if obj in obj.InList[0].Armatures: father = obj.InList[0] if father: if hasattr(father, 'Shape'): fathershape = father.Shape import Part # corner cases: # compound from more Wires # compound without Wires but with multiple Edges # Does they make sense? If yes handle them. # Does it makes sense to handle Shapes with Faces or even Solids? if not obj.Base.Shape.Wires and len(obj.Base.Shape.Edges) == 1: wire = Part.Wire(obj.Base.Shape.Edges[0]) else: wire = obj.Base.Shape.Wires[0] if hasattr(obj, "Rounding"): #print(obj.Rounding) if obj.Rounding: radius = obj.Rounding * obj.Diameter.Value from DraftGeomUtils import filletWire wire = filletWire(wire, radius) bpoint, bvec = self.getBaseAndAxis(wire) if not bpoint: return axis = obj.Base.Placement.Rotation.multVec(FreeCAD.Vector(0, 0, -1)) if fathershape: size = (ArchCommands.projectToVector(fathershape.copy(), axis)).Length else: size = 1 if hasattr(obj, "Direction"): if not DraftVecUtils.isNull(obj.Direction): axis = FreeCAD.Vector(obj.Direction) axis.normalize() if fathershape: size = (ArchCommands.projectToVector( fathershape.copy(), axis)).Length else: size = 1 if hasattr(obj, "Distance"): if obj.Distance.Value: size = obj.Distance.Value spacinglist = None if hasattr(obj, "CustomSpacing"): if obj.CustomSpacing: spacinglist = strprocessOfCustomSpacing(obj.CustomSpacing) influenceArea = sum( spacinglist) - spacinglist[0] / 2 - spacinglist[-1] / 2 # Drop this check to solve issue as discussed here: https://github.com/FreeCAD/FreeCAD/pull/2550 # if (obj.OffsetStart.Value + obj.OffsetEnd.Value) > size: # return # all tests ok! if hasattr(obj, "Length"): length = getLengthOfRebar(obj) if length: obj.Length = length pl = obj.Placement circle = Part.makeCircle(obj.Diameter.Value / 2, bpoint, bvec) circle = Part.Wire(circle) try: bar = wire.makePipeShell([circle], True, False, 2) basewire = wire.copy() except Part.OCCError: print("Arch: error sweeping rebar profile along the base sketch") return # building final shape shapes = [] placementlist = [] self.wires = [] rot = FreeCAD.Rotation() if obj.Amount == 1: if hasattr(obj, "RebarShape"): barplacement = CalculatePlacement( obj.Amount, 1, obj.Diameter.Value, size, axis, rot, obj.OffsetStart.Value, obj.OffsetEnd.Value, obj.RebarShape) else: barplacement = CalculatePlacement(obj.Amount, 1, obj.Diameter.Value, size, axis, rot, obj.OffsetStart.Value, obj.OffsetEnd.Value) placementlist.append(barplacement) if hasattr(obj, "Spacing"): obj.Spacing = 0 else: if obj.OffsetStart.Value: baseoffset = DraftVecUtils.scaleTo(axis, obj.OffsetStart.Value) else: baseoffset = None if hasattr(obj, "RebarShape") and obj.RebarShape == "Stirrup": interval = size - (obj.OffsetStart.Value + obj.OffsetEnd.Value + obj.Diameter.Value) else: interval = size - (obj.OffsetStart.Value + obj.OffsetEnd.Value) interval = interval / (obj.Amount - 1) for i in range(obj.Amount): if hasattr(obj, "RebarShape"): barplacement = CalculatePlacement(obj.Amount, i + 1, obj.Diameter.Value, size, axis, rot, obj.OffsetStart.Value, obj.OffsetEnd.Value, obj.RebarShape) else: barplacement = CalculatePlacement(obj.Amount, i + 1, obj.Diameter.Value, size, axis, rot, obj.OffsetStart.Value, obj.OffsetEnd.Value) placementlist.append(barplacement) if hasattr(obj, "Spacing"): obj.Spacing = interval # Calculate placement of bars from custom spacing. if spacinglist: placementlist[:] = [] if hasattr(obj, "RebarShape") and obj.RebarShape == "Stirrup": reqInfluenceArea = size - (obj.OffsetStart.Value + obj.OffsetEnd.Value + obj.Diameter.Value) else: reqInfluenceArea = size - (obj.OffsetStart.Value + obj.OffsetEnd.Value) # Avoid unnecessary checks to pass like. For eg.: when we have values # like influenceArea is 100.00001 and reqInflueneArea is 100 if round(influenceArea) > round(reqInfluenceArea): FreeCAD.Console.PrintWarning( "Influence area of rebars is greater than " + str(reqInfluenceArea) + ".\n") elif round(influenceArea) < round(reqInfluenceArea): FreeCAD.Console.PrintWarning( "Last span is greater that end offset.\n") for i in range(len(spacinglist)): if i == 0: barplacement = CustomSpacingPlacement( spacinglist, 1, axis, father.Placement.Rotation, obj.OffsetStart.Value, obj.OffsetEnd.Value) placementlist.append(barplacement) else: barplacement = CustomSpacingPlacement( spacinglist, i + 1, axis, father.Placement.Rotation, obj.OffsetStart.Value, obj.OffsetEnd.Value) placementlist.append(barplacement) obj.Amount = len(spacinglist) obj.Spacing = 0 obj.PlacementList = placementlist for i in range(len(obj.PlacementList)): if i == 0: bar.Placement = obj.PlacementList[i] shapes.append(bar) basewire.Placement = obj.PlacementList[i] self.wires.append(basewire) else: bar = bar.copy() bar.Placement = obj.PlacementList[i] shapes.append(bar) w = basewire.copy() w.Placement = obj.PlacementList[i] self.wires.append(w) if shapes: obj.Shape = Part.makeCompound(shapes) obj.Placement = pl obj.TotalLength = obj.Length * len(obj.PlacementList)
def MountingHole(self,i,zBase,panelThick): mh = self.mh[i] mh = Base.Vector(mh.x,mh.y,zBase) thick = Base.Vector(0,0,panelThick) mrad = self.hvpowerboardMHDia()/2.0 return Part.Face(Part.Wire(Part.makeCircle(mrad,mh))).extrude(thick)
def __init__(self, name, origin): self.name = name if not isinstance(origin, Base.Vector): raise RuntimeError("origin is not a Vector") self.origin = origin ox = origin.x oy = origin.y oz = origin.z boardsurf = Part.makePlane(self._psPCBwidth, self._psPCBlength, origin) xh = (ox + self._stripIncr) while xh <= ox + self._psPCBwidth: yh = oy + self._stripIncr while yh <= oy + self._psPCBlength: boardsurf = self._drill_leadhole(boardsurf, xh, yh, oz) yh += self._stripIncr xh += self._stripIncr self.mhvector = { 1: Base.Vector(ox + self._psPCBMhOff + self._stripIncr, oy + (self._stripIncr + 5 * 2.54), oz), 2: Base.Vector( ox + self._psPCBMhOff + self._psPCBpsw + self._stripIncr, oy + (self._stripIncr + 5 * 2.54), oz), 3: Base.Vector( ox + self._psPCBMhOff + self._stripIncr, oy + (self._psPCBlength - (self._stripIncr + 5 * 2.54)), oz), 4: Base.Vector( ox + (self._psPCBMhOff + self._psPCBpsw + self._stripIncr), oy + (self._psPCBlength - (self._stripIncr + 5 * 2.54)), oz) } mh1circ = Part.makeCircle(self._mhdia / 2.0, self.mhvector[1]) mh1wire = Part.Wire(mh1circ) mh1 = Part.Face(mh1wire) boardsurf = boardsurf.cut(mh1) mh2circ = Part.makeCircle(self._mhdia / 2.0, self.mhvector[2]) mh2wire = Part.Wire(mh2circ) mh2 = Part.Face(mh2wire) boardsurf = boardsurf.cut(mh2) mh3circ = Part.makeCircle(self._mhdia / 2.0, self.mhvector[3]) mh3wire = Part.Wire(mh3circ) mh3 = Part.Face(mh3wire) boardsurf = boardsurf.cut(mh3) mh4circ = Part.makeCircle(self._mhdia / 2.0, self.mhvector[4]) mh4wire = Part.Wire(mh4circ) mh4 = Part.Face(mh4wire) boardsurf = boardsurf.cut(mh4) self.board = boardsurf.extrude(Base.Vector(0, 0, self._psPCBThickness)) mh = { 1: Part.Face( Part.Wire( Part.makeCircle( self._mhdia / 2.0, Base.Vector(self.mhvector[1].x, self.mhvector[1].y, oz - self._stripThickness)))), 2: Part.Face( Part.Wire( Part.makeCircle( self._mhdia / 2.0, Base.Vector(self.mhvector[2].x, self.mhvector[2].y, oz - self._stripThickness)))), 3: Part.Face( Part.Wire( Part.makeCircle( self._mhdia / 2.0, Base.Vector(self.mhvector[3].x, self.mhvector[3].y, oz - self._stripThickness)))), 4: Part.Face( Part.Wire( Part.makeCircle( self._mhdia / 2.0, Base.Vector(self.mhvector[4].x, self.mhvector[4].y, oz - self._stripThickness)))) } yoff = (self._psPCBlength - PSK_S15C._pslength) / 2.0 xoff = self._psPCBMhOff + ( (self._psPCBpsw - PSK_S15C._pswidth) / 2.0) + self._stripIncr pin1X = (PSK_S15C._pspin1Yoff + xoff) pin2X = (PSK_S15C._pspin2Yoff + xoff) sx = self._stripIncr vinX = sx + self._stripIncr gndX1 = vinX + self._stripIncr gndX2 = gndX1 + (3 * self._stripIncr) voutX = gndX2 + self._stripIncr self.strips = list() while (sx + self._stripIncr) <= self._psPCBwidth: #sys.__stderr__.write("*** sx = %f, pin1X is %f, pin2X is %f\n"%(sx,pin1X,pin2X)) #sys.__stderr__.write("*** sx = %f, vinX is %f, voutX is %f\n"%(sx,vinX,voutX)) if closeto(sx, vinX) or closeto(sx, voutX): #sys.__stderr__.write("*** sx hit\n") stripCP1 = Base.Vector(ox + (sx - (self._stripWidth / 2.0)), oy + self._stripOffset, oz - self._stripThickness) striplen1 = 6 * self._stripIncr stripsurf = Part.makePlane(self._stripWidth, striplen1, stripCP1) xh = stripCP1.x + (self._stripWidth / 2.0) yh = stripCP1.y + self._stripOffset while yh < stripCP1.y + striplen1: stripsurf = self._drill_leadhole(stripsurf, xh, yh, stripCP1.z) yh += self._stripIncr strip = stripsurf.extrude( Base.Vector(0, 0, self._stripThickness)) self.strips.append(strip) stripCP2 = Base.Vector(ox + (sx - (self._stripWidth / 2.0)), oy + (11.5 * self._stripIncr), oz - self._stripThickness) striplen2 = self._psPCBlength - (12 * self._stripIncr) stripsurf = Part.makePlane(self._stripWidth, striplen2, stripCP2) xh = stripCP2.x + (self._stripWidth / 2.0) yh = stripCP2.y + self._stripOffset while yh < stripCP2.y + striplen2: stripsurf = self._drill_leadhole(stripsurf, xh, yh, stripCP2.z) yh += self._stripIncr strip = stripsurf.extrude( Base.Vector(0, 0, self._stripThickness)) self.strips.append(strip) elif closeto(sx, gndX1) or closeto(sx, gndX2): #sys.__stderr__.write("*** sx hit\n") stripCP1 = Base.Vector(ox + (sx - (self._stripWidth / 2.0)), oy + self._stripOffset, oz - self._stripThickness) striplen1 = 6 * self._stripIncr stripsurf = Part.makePlane(self._stripWidth, striplen1, stripCP1) xh = stripCP1.x + (self._stripWidth / 2.0) yh = stripCP1.y + self._stripOffset while yh < stripCP1.y + striplen1: stripsurf = self._drill_leadhole(stripsurf, xh, yh, stripCP1.z) yh += self._stripIncr strip = stripsurf.extrude( Base.Vector(0, 0, self._stripThickness)) self.strips.append(strip) stripCP2 = Base.Vector(ox + (sx - (self._stripWidth / 2.0)), oy + (11.5 * self._stripIncr), oz - self._stripThickness) striplen2 = 5 * self._stripIncr stripsurf = Part.makePlane(self._stripWidth, striplen2, stripCP2) xh = stripCP2.x + (self._stripWidth / 2.0) yh = stripCP2.y + self._stripOffset while yh < stripCP2.y + striplen2: stripsurf = self._drill_leadhole(stripsurf, xh, yh, stripCP2.z) yh += self._stripIncr strip = stripsurf.extrude( Base.Vector(0, 0, self._stripThickness)) self.strips.append(strip) stripCP3 = Base.Vector(ox + (sx - (self._stripWidth / 2.0)), oy + (25.5 * self._stripIncr), oz - self._stripThickness) striplen3 = 4 * self._stripIncr stripsurf = Part.makePlane(self._stripWidth, striplen3, stripCP3) xh = stripCP3.x + (self._stripWidth / 2.0) yh = stripCP3.y + self._stripOffset while yh < stripCP3.y + striplen3: stripsurf = self._drill_leadhole(stripsurf, xh, yh, stripCP3.z) yh += self._stripIncr strip = stripsurf.extrude( Base.Vector(0, 0, self._stripThickness)) self.strips.append(strip) elif (sx < pin1X or closeto(sx,pin1X)) and \ (sx > pin2X or closeto(sx,pin2X)): #sys.__stderr__.write("*** sx hit\n") stripCP1 = Base.Vector(ox + (sx - (self._stripWidth / 2.0)), oy + self._stripOffset, oz - self._stripThickness) stripCP2 = Base.Vector( ox + (sx - (self._stripWidth / 2.0)), oy + (self._stripOffset + yoff + PSK_S15C._pspin1Xoff - self._stripExtra - 2.54), oz - self._stripThickness) striplen = yoff + PSK_S15C._pspin4Xoff + self._stripExtra stripsurf = Part.makePlane(self._stripWidth, striplen, stripCP1) xh = stripCP1.x + (self._stripWidth / 2.0) yh = stripCP1.y + self._stripOffset while yh < stripCP1.y + striplen: stripsurf = self._drill_leadhole(stripsurf, xh, yh, stripCP1.z) yh += self._stripIncr strip = stripsurf.extrude( Base.Vector(0, 0, self._stripThickness)) self.strips.append(strip) stripsurf = Part.makePlane(self._stripWidth, striplen, stripCP2) xh = stripCP2.x + (self._stripWidth / 2.0) yh = stripCP2.y + self._stripOffset while yh < stripCP2.y + striplen: stripsurf = self._drill_leadhole(stripsurf, xh, yh, stripCP2.z) yh += self._stripIncr strip = stripsurf.extrude( Base.Vector(0, 0, self._stripThickness)) self.strips.append(strip) else: stripCP = Base.Vector(ox + (sx - (self._stripWidth / 2.0)), oy + self._stripOffset, oz - self._stripThickness) stripsurf = Part.makePlane( self._stripWidth, self._psPCBlength - (self._stripOffset * 2), stripCP) xh = stripCP.x + (self._stripWidth / 2.0) yh = stripCP.y + self._stripOffset while yh < stripCP.y + self._psPCBlength - (self._stripOffset * 2): stripsurf = self._drill_leadhole(stripsurf, xh, yh, stripCP.z) yh += self._stripIncr i = 1 while i <= 4: h = self.mhvector[i] stripsurf = stripsurf.cut(mh[i]) i += 1 strip = stripsurf.extrude( Base.Vector(0, 0, self._stripThickness)) self.strips.append(strip) sx += self._stripIncr
def Standoff(self,i,zBase,height,diameter): soff = self.mh[i] soff = Base.Vector(soff.x,soff.y,zBase) stall = Base.Vector(0,0,height) srad = diameter/2.0 return Part.Face(Part.Wire(Part.makeCircle(srad,soff))).extrude(stall)
def create_circle(self): position = Base.Vector(self.position) direction = Base.Vector(self.direction) self.shape = Part.makeCircle(self.radius, position, direction, 0, 360)
def makeSolarDiagram(longitude, latitude, scale=1, complete=False): """makeSolarDiagram(longitude,latitude,[scale,complete]): returns a solar diagram as a pivy node. If complete is True, the 12 months are drawn""" from subprocess import call py3_failed = call(["python3", "-c", "import Pysolar"]) if py3_failed: try: import Pysolar except: print( "Pysolar is not installed. Unable to generate solar diagrams") return None else: from subprocess import check_output from pivy import coin if not scale: return None def toNode(shape): "builds a pivy node from a simple linear shape" from pivy import coin buf = shape.writeInventor(2, 0.01) buf = buf.replace("\n", "") pts = re.findall("point \[(.*?)\]", buf)[0] pts = pts.split(",") pc = [] for p in pts: v = p.strip().split() pc.append([float(v[0]), float(v[1]), float(v[2])]) coords = coin.SoCoordinate3() coords.point.setValues(0, len(pc), pc) line = coin.SoLineSet() line.numVertices.setValue(-1) item = coin.SoSeparator() item.addChild(coords) item.addChild(line) return item circles = [] sunpaths = [] hourpaths = [] circlepos = [] hourpos = [] # build the base circle + number positions import Part for i in range(1, 9): circles.append(Part.makeCircle(scale * (i / 8.0))) for ad in range(0, 360, 15): a = math.radians(ad) p1 = FreeCAD.Vector(math.cos(a) * scale, math.sin(a) * scale, 0) p2 = FreeCAD.Vector( math.cos(a) * scale * 0.125, math.sin(a) * scale * 0.125, 0) p3 = FreeCAD.Vector( math.cos(a) * scale * 1.08, math.sin(a) * scale * 1.08, 0) circles.append(Part.LineSegment(p1, p2).toShape()) circlepos.append((ad, p3)) # build the sun curves at solstices and equinoxe year = datetime.datetime.now().year hpts = [[] for i in range(24)] m = [(6, 21), (7, 21), (8, 21), (9, 21), (10, 21), (11, 21), (12, 21)] if complete: m.extend([(1, 21), (2, 21), (3, 21), (4, 21), (5, 21)]) for i, d in enumerate(m): pts = [] for h in range(24): if not py3_failed: dt = "datetime.datetime(%s, %s, %s, %s)" % (year, d[0], d[1], h) alt_call = "python3 -c 'import datetime,Pysolar; print (Pysolar.solar.get_altitude_fast(%s, %s, %s))'" % ( latitude, longitude, dt) alt = math.radians( float(check_output(alt_call, shell=True).strip())) az_call = "python3 -c 'import datetime,Pysolar; print (Pysolar.solar.get_azimuth(%s, %s, %s))'" % ( latitude, longitude, dt) az = float( re.search('.+$', check_output(az_call, shell=True)).group(0)) else: dt = datetime.datetime(year, d[0], d[1], h) alt = math.radians( Pysolar.solar.GetAltitudeFast(latitude, longitude, dt)) az = Pysolar.solar.GetAzimuth(latitude, longitude, dt) az = -90 + az # pysolar's zero is south if az < 0: az = 360 + az az = math.radians(az) zc = math.sin(alt) * scale ic = math.cos(alt) * scale xc = math.cos(az) * ic yc = math.sin(az) * ic p = FreeCAD.Vector(xc, yc, zc) pts.append(p) hpts[h].append(p) if i in [0, 6]: ep = FreeCAD.Vector(p) ep.multiply(1.08) if ep.z >= 0: if h == 12: if i == 0: h = "SUMMER" else: h = "WINTER" if latitude < 0: if h == "SUMMER": h = "WINTER" else: h = "SUMMER" hourpos.append((h, ep)) if i < 7: sunpaths.append(Part.makePolygon(pts)) for h in hpts: if complete: h.append(h[0]) hourpaths.append(Part.makePolygon(h)) # cut underground lines sz = 2.1 * scale cube = Part.makeBox(sz, sz, sz) cube.translate(FreeCAD.Vector(-sz / 2, -sz / 2, -sz)) sunpaths = [sp.cut(cube) for sp in sunpaths] hourpaths = [hp.cut(cube) for hp in hourpaths] # build nodes ts = 0.005 * scale # text scale mastersep = coin.SoSeparator() circlesep = coin.SoSeparator() numsep = coin.SoSeparator() pathsep = coin.SoSeparator() hoursep = coin.SoSeparator() hournumsep = coin.SoSeparator() mastersep.addChild(circlesep) mastersep.addChild(numsep) mastersep.addChild(pathsep) mastersep.addChild(hoursep) for item in circles: circlesep.addChild(toNode(item)) for item in sunpaths: for w in item.Edges: pathsep.addChild(toNode(w)) for item in hourpaths: for w in item.Edges: hoursep.addChild(toNode(w)) for p in circlepos: text = coin.SoText2() s = p[0] - 90 s = -s if s > 360: s = s - 360 if s < 0: s = 360 + s if s == 0: s = "N" elif s == 90: s = "E" elif s == 180: s = "S" elif s == 270: s = "W" else: s = str(s) text.string = s text.justification = coin.SoText2.CENTER coords = coin.SoTransform() coords.translation.setValue([p[1].x, p[1].y, p[1].z]) coords.scaleFactor.setValue([ts, ts, ts]) item = coin.SoSeparator() item.addChild(coords) item.addChild(text) numsep.addChild(item) for p in hourpos: text = coin.SoText2() s = str(p[0]) text.string = s text.justification = coin.SoText2.CENTER coords = coin.SoTransform() coords.translation.setValue([p[1].x, p[1].y, p[1].z]) coords.scaleFactor.setValue([ts, ts, ts]) item = coin.SoSeparator() item.addChild(coords) item.addChild(text) numsep.addChild(item) return mastersep
def execute(self,fp): b = fp.pin_circle_radius d = fp.roller_diameter e = fp.eccentricity n = fp.teeth_number p = b/n s = fp.segment_count ang = fp.pressure_angle_lim c = fp.pressure_angle_offset q = 2*math.pi/float(s) # Find the pressure angle limit circles minAngle = -1.0 maxAngle = -1.0 for i in range(0, 180): x = self.calc_pressure_angle(p, d, n, i * math.pi / 180.) if ( x < ang) and (minAngle < 0): minAngle = float(i) if (x < -ang) and (maxAngle < 0): maxAngle = float(i-1) minRadius = self.calc_pressure_limit(p, d, e, n, minAngle * math.pi / 180.) maxRadius = self.calc_pressure_limit(p, d, e, n, maxAngle * math.pi / 180.) # unused # Wire(Part.makeCircle(minRadius,App.Vector(-e, 0, 0))) # Wire(Part.makeCircle(maxRadius,App.Vector(-e, 0, 0))) App.Console.PrintMessage("Generating cam disk\r\n") #generate the cam profile - note: shifted in -x by eccentricicy amount i=0 x = self.calc_x(p, d, e, n, q*i / float(n)) y = self.calc_y(p, d, e, n, q*i / n) x, y = self.check_limit(x,y,maxRadius,minRadius,c) points = [App.Vector(x-e, y, 0)] for i in range(0,s): x = self.calc_x(p, d, e, n, q*(i+1) / n) y = self.calc_y(p, d, e, n, q*(i+1) / n) x, y = self.check_limit(x, y, maxRadius, minRadius, c) points.append([x-e, y, 0]) wi = make_bspline_wire([points]) wires = [] mat= App.Matrix() mat.move(App.Vector(e, 0., 0.)) mat.rotateZ(2 * np.pi / n) mat.move(App.Vector(-e, 0., 0.)) for _ in range(n): wi = wi.transformGeometry(mat) wires.append(wi) cam = Face(Wire(wires)) #add a circle in the center of the cam if fp.hole_radius.Value: centerCircle = Face(Wire(Part.makeCircle(fp.hole_radius.Value, App.Vector(-e, 0, 0)))) cam = cam.cut(centerCircle) to_be_fused = [] if fp.show_disk0==True: if fp.disk_height.Value==0: to_be_fused.append(cam) else: to_be_fused.append(cam.extrude(App.Vector(0, 0, fp.disk_height.Value))) #secondary cam disk if fp.show_disk1==True: App.Console.PrintMessage("Generating secondary cam disk\r\n") second_cam = cam.copy() mat= App.Matrix() mat.rotateZ(np.pi) mat.move(App.Vector(-e, 0, 0)) if n%2 == 0: mat.rotateZ(np.pi/n) mat.move(App.Vector(e, 0, 0)) second_cam = second_cam.transformGeometry(mat) if fp.disk_height.Value==0: to_be_fused.append(second_cam) else: to_be_fused.append(second_cam.extrude(App.Vector(0, 0, -fp.disk_height.Value))) #pins if fp.show_pins==True: App.Console.PrintMessage("Generating pins\r\n") pins = [] for i in range(0, n + 1): x = p * n * math.cos(2 * math.pi / (n + 1) * i) y = p * n * math.sin(2 * math.pi / (n + 1) * i) pins.append(Wire(Part.makeCircle(d / 2, App.Vector(x, y, 0)))) pins = Face(pins) z_offset = -fp.pin_height.Value / 2; if fp.center_pins==True: if fp.show_disk0==True and fp.show_disk1==False: z_offset += fp.disk_height.Value / 2; elif fp.show_disk0==False and fp.show_disk1==True: z_offset += -fp.disk_height.Value / 2; #extrude if z_offset!=0: pins.translate(App.Vector(0, 0, z_offset)) if fp.pin_height!=0: pins = pins.extrude(App.Vector(0, 0, fp.pin_height.Value)) to_be_fused.append(pins); if to_be_fused: fp.Shape = Part.makeCompound(to_be_fused)
def execute(self, obj): if self.clone(obj): return if not obj.Base: return if not obj.Base.Shape: return if not obj.Base.Shape.Wires: return if not obj.Diameter.Value: return if not obj.Amount: return father = obj.Host fathershape = None if not father: # support for old-style rebars if obj.InList: if hasattr(obj.InList[0], "Armatures"): if obj in obj.InList[0].Armatures: father = obj.InList[0] if father: if father.isDerivedFrom("Part::Feature"): fathershape = father.Shape wire = obj.Base.Shape.Wires[0] if hasattr(obj, "Rounding"): #print(obj.Rounding) if obj.Rounding: radius = obj.Rounding * obj.Diameter.Value import DraftGeomUtils wire = DraftGeomUtils.filletWire(wire, radius) bpoint, bvec = self.getBaseAndAxis(wire) if not bpoint: return axis = obj.Base.Placement.Rotation.multVec(FreeCAD.Vector(0, 0, -1)) if fathershape: size = (ArchCommands.projectToVector(fathershape.copy(), axis)).Length else: size = 1 if hasattr(obj, "Direction"): if not DraftVecUtils.isNull(obj.Direction): axis = FreeCAD.Vector(obj.Direction) axis.normalize() if fathershape: size = (ArchCommands.projectToVector( fathershape.copy(), axis)).Length else: size = 1 if hasattr(obj, "Distance"): if obj.Distance.Value: size = obj.Distance.Value #print(axis) #print(size) spacinglist = None if hasattr(obj, "CustomSpacing"): if obj.CustomSpacing: spacinglist = strprocessOfCustomSpacing(obj.CustomSpacing) influenceArea = sum( spacinglist) - spacinglist[0] / 2 - spacinglist[-1] / 2 if (obj.OffsetStart.Value + obj.OffsetEnd.Value) > size: return # all tests ok! if hasattr(obj, "Length"): length = getLengthOfRebar(obj) if length: obj.Length = length pl = obj.Placement import Part circle = Part.makeCircle(obj.Diameter.Value / 2, bpoint, bvec) circle = Part.Wire(circle) try: bar = wire.makePipeShell([circle], True, False, 2) basewire = wire.copy() except Part.OCCError: print("Arch: error sweeping rebar profile along the base sketch") return # building final shape shapes = [] placementlist = [] self.wires = [] if father: rot = father.Placement.Rotation else: rot = FreeCAD.Rotation() if obj.Amount == 1: barplacement = CalculatePlacement(obj.Amount, 1, size, axis, rot, obj.OffsetStart.Value, obj.OffsetEnd.Value) placementlist.append(barplacement) if hasattr(obj, "Spacing"): obj.Spacing = 0 else: if obj.OffsetStart.Value: baseoffset = DraftVecUtils.scaleTo(axis, obj.OffsetStart.Value) else: baseoffset = None interval = size - (obj.OffsetStart.Value + obj.OffsetEnd.Value) interval = interval / (obj.Amount - 1) for i in range(obj.Amount): barplacement = CalculatePlacement(obj.Amount, i + 1, size, axis, rot, obj.OffsetStart.Value, obj.OffsetEnd.Value) placementlist.append(barplacement) if hasattr(obj, "Spacing"): obj.Spacing = interval # Calculate placement of bars from custom spacing. if spacinglist: placementlist[:] = [] reqInfluenceArea = size - (obj.OffsetStart.Value + obj.OffsetEnd.Value) # Avoid unnecessary checks to pass like. For eg.: when we have values # like influenceArea is 100.00001 and reqInflueneArea is 100 if round(influenceArea) > round(reqInfluenceArea): return FreeCAD.Console.PrintError( "Influence area of rebars is greater than " + str(reqInfluenceArea) + ".\n") elif round(influenceArea) < round(reqInfluenceArea): FreeCAD.Console.PrintWarning( "Last span is greater that end offset.\n") for i in range(len(spacinglist)): if i == 0: barplacement = CustomSpacingPlacement( spacinglist, 1, axis, father.Placement.Rotation, obj.OffsetStart.Value, obj.OffsetEnd.Value) placementlist.append(barplacement) else: barplacement = CustomSpacingPlacement( spacinglist, i + 1, axis, father.Placement.Rotation, obj.OffsetStart.Value, obj.OffsetEnd.Value) placementlist.append(barplacement) obj.Amount = len(spacinglist) obj.Spacing = 0 obj.PlacementList = placementlist for i in range(len(obj.PlacementList)): if i == 0: bar.Placement = obj.PlacementList[i] shapes.append(bar) basewire.Placement = obj.PlacementList[i] self.wires.append(basewire) else: bar = bar.copy() bar.Placement = obj.PlacementList[i] shapes.append(bar) w = basewire.copy() w.Placement = obj.PlacementList[i] self.wires.append(w) if shapes: obj.Shape = Part.makeCompound(shapes) obj.Placement = pl obj.TotalLength = obj.Length * len(obj.PlacementList)
def execute(self, fp): m = fp.module.Value d = fp.diameter.Value t = fp.teeth h = fp.height clearance = fp.clearance head = fp.head alpha = fp.pressure_angle.Value beta = np.arctan(m * t / d) fp.beta = np.rad2deg(beta) beta = -(fp.reverse_pitch * 2 - 1) * (np.pi / 2 - beta) r_1 = (d - (2 + 2 * clearance) * m) / 2 r_2 = (d + (2 + 2 * head) * m) / 2 z_a = (2 + head + clearance) * m * np.tan(np.deg2rad(alpha)) z_b = (m * np.pi - 4 * m * np.tan(np.deg2rad(alpha))) / 2 z_0 = clearance * m * np.tan(np.deg2rad(alpha)) z_1 = z_b - z_0 z_2 = z_1 + z_a z_3 = z_2 + z_b - 2 * head * m * np.tan(np.deg2rad(alpha)) z_4 = z_3 + z_a def helical_projection(r, z): phi = 2 * z / m / t x = r * np.cos(phi) y = r * np.sin(phi) z = 0 * y return np.array([x, y, z]). T # create a circle from phi=0 to phi_1 with r_1 phi_0 = 2 * z_0 / m / t phi_1 = 2 * z_1 / m / t c1 = Part.makeCircle(r_1, App.Vector(0, 0, 0), App.Vector(0, 0, 1), np.rad2deg(phi_0), np.rad2deg(phi_1)) # create first bspline z_values = np.linspace(z_1, z_2, 10) r_values = np.linspace(r_1, r_2, 10) points = helical_projection(r_values, z_values) bsp1 = Part.BSplineCurve() bsp1.interpolate(list(map(fcvec, points))) bsp1 = bsp1.toShape() # create circle from phi_2 to phi_3 phi_2 = 2 * z_2 / m / t phi_3 = 2 * z_3 / m / t c2 = Part.makeCircle(r_2, App.Vector(0, 0, 0), App.Vector( 0, 0, 1), np.rad2deg(phi_2), np.rad2deg(phi_3)) # create second bspline z_values = np.linspace(z_3, z_4, 10) r_values = np.linspace(r_2, r_1, 10) points = helical_projection(r_values, z_values) bsp2 = Part.BSplineCurve() bsp2.interpolate(list(map(fcvec, points))) bsp2 = bsp2.toShape() wire = Part.Wire([c1, bsp1, c2, bsp2]) w_all = [wire] rot = App.Matrix() rot.rotateZ(2 * np.pi / t) for i in range(1, t): w_all.append(w_all[-1].transformGeometry(rot)) full_wire = Part.Wire(Part.Wire(w_all)) if h == 0: fp.Shape = full_wire else: shape = helicalextrusion(full_wire, h, h * np.tan(beta) * 2 / d) fp.Shape = shape
def areaOpShapes(self, obj): '''areaOpShapes(obj) ... return shapes representing the solids to be removed.''' PathLog.track() if obj.Base: PathLog.debug("base items exist. Processing...") self.removalshapes = [] self.horiz = [] vertical = [] for o in obj.Base: PathLog.debug("Base item: {}".format(o)) base = o[0] for sub in o[1]: if "Face" in sub: face = base.Shape.getElement(sub) if type(face.Surface) == Part.Plane and PathGeom.isVertical(face.Surface.Axis): # it's a flat horizontal face self.horiz.append(face) elif type(face.Surface) == Part.Cylinder and PathGeom.isVertical(face.Surface.Axis): # vertical cylinder wall if any(e.isClosed() for e in face.Edges): # complete cylinder circle = Part.makeCircle(face.Surface.Radius, face.Surface.Center) disk = Part.Face(Part.Wire(circle)) self.horiz.append(disk) else: # partial cylinder wall vertical.append(face) elif type(face.Surface) == Part.Plane and PathGeom.isHorizontal(face.Surface.Axis): vertical.append(face) else: PathLog.error(translate('PathPocket', "Pocket does not support shape %s.%s") % (base.Label, sub)) self.vertical = PathGeom.combineConnectedShapes(vertical) self.vWires = [TechDraw.findShapeOutline(shape, 1, FreeCAD.Vector(0, 0, 1)) for shape in self.vertical] for wire in self.vWires: w = PathGeom.removeDuplicateEdges(wire) face = Part.Face(w) face.tessellate(0.1) if PathGeom.isRoughly(face.Area, 0): PathLog.error(translate('PathPocket', 'Vertical faces do not form a loop - ignoring')) else: self.horiz.append(face) # move all horizontal faces to FinalDepth for f in self.horiz: f.translate(FreeCAD.Vector(0, 0, obj.FinalDepth.Value - f.BoundBox.ZMin)) # check all faces and see if they are touching/overlapping and combine those into a compound self.horizontal = [] for shape in PathGeom.combineConnectedShapes(self.horiz): shape.sewShape() shape.tessellate(0.1) if obj.UseOutline: wire = TechDraw.findShapeOutline(shape, 1, FreeCAD.Vector(0, 0, 1)) wire.translate(FreeCAD.Vector(0, 0, obj.FinalDepth.Value - wire.BoundBox.ZMin)) self.horizontal.append(Part.Face(wire)) else: self.horizontal.append(shape) # extrude all faces up to StartDepth and those are the removal shapes extent = FreeCAD.Vector(0, 0, obj.StartDepth.Value - obj.FinalDepth.Value) self.removalshapes = [(face.extrude(extent), False) for face in self.horizontal] else: # process the job base object as a whole PathLog.debug("processing the whole job base object") self.outline = Part.Face(TechDraw.findShapeOutline(self.baseobject.Shape, 1, FreeCAD.Vector(0, 0, 1))) stockBB = self.stock.Shape.BoundBox self.outline.translate(FreeCAD.Vector(0, 0, stockBB.ZMin - 1)) self.body = self.outline.extrude(FreeCAD.Vector(0, 0, stockBB.ZLength + 2)) self.removalshapes = [(self.stock.Shape.cut(self.body), False)] for (shape,hole) in self.removalshapes: shape.tessellate(0.1) if self.removalshapes: obj.removalshape = self.removalshapes[0][0] return self.removalshapes
def makeTruss(self, obj, v0, v1): import Part # get normal direction normal = obj.Normal if not normal.Length: normal = FreeCAD.Vector(0, 0, 1) # create base profile maindir = v1.sub(v0) sidedir = normal.cross(maindir) if not sidedir.Length: FreeCAD.Console.PrintLog(obj.Label + ": normal and base are parallel\n") return sidedir.normalize() p0 = v0.add( FreeCAD.Vector(sidedir).negative().multiply(obj.StrutWidth.Value / 2)) p1 = p0.add( FreeCAD.Vector(sidedir).multiply(obj.StrutWidth.Value / 2).multiply(2)) p2 = p1.add(FreeCAD.Vector(normal).multiply(obj.StrutHeight)) p3 = p0.add(FreeCAD.Vector(normal).multiply(obj.StrutHeight)) trussprofile = Part.Face(Part.makePolygon([p0, p1, p2, p3, p0])) # create bottom strut bottomstrut = trussprofile.extrude(maindir) # create top strut v2 = v0.add(FreeCAD.Vector(normal).multiply(obj.HeightStart.Value)) v3 = v1.add(FreeCAD.Vector(normal).multiply(obj.HeightEnd.Value)) topdir = v3.sub(v2) if obj.StrutStartOffset.Value: v2f = v2.add( (v2.sub(v3)).normalize().multiply(obj.StrutStartOffset.Value)) else: v2f = v2 if obj.StrutEndOffset.Value: v3f = v3.add( (v3.sub(v2)).normalize().multiply(obj.StrutEndOffset.Value)) else: v3f = v3 offtopdir = v3f.sub(v2f) topstrut = trussprofile.extrude(offtopdir) topstrut.translate(v2f.sub(v0)) topstrut.translate( FreeCAD.Vector(normal).multiply(-obj.StrutHeight.Value)) angle = math.degrees(topdir.getAngle(maindir)) # create rod profile on the XY plane if obj.RodType == "Round": rodprofile = Part.Face( Part.Wire([Part.makeCircle(obj.RodSize / 2)])) else: rodprofile = Part.Face( Part.makePlane( obj.RodSize, obj.RodSize, FreeCAD.Vector(-obj.RodSize / 2, -obj.RodSize / 2, 0))) # create rods rods = [] bottomrodstart = v0.add( FreeCAD.Vector(normal).multiply(obj.StrutHeight.Value / 2)) toprodstart = v2.add( FreeCAD.Vector(normal).multiply(obj.StrutHeight.Value / 2).negative()) bottomrodvec = FreeCAD.Vector(maindir).multiply(1 / obj.RodSections) toprodvec = FreeCAD.Vector(topdir).multiply(1 / obj.RodSections) bottomrodpos = [bottomrodstart] toprodpos = [toprodstart] if obj.RodMode == rodmodes[0]: # /|/|/| for i in range(1, obj.RodSections + 1): if (i > 1) or (obj.StrutStartOffset.Value >= 0): # do not add first vert rod if negative offset rods.append( self.makeRod(rodprofile, bottomrodpos[-1], toprodpos[-1])) bottomrodpos.append(bottomrodpos[-1].add(bottomrodvec)) toprodpos.append(toprodpos[-1].add(toprodvec)) if obj.RodDirection == "Forward": rods.append( self.makeRod(rodprofile, bottomrodpos[-2], toprodpos[-1])) else: rods.append( self.makeRod(rodprofile, bottomrodpos[-1], toprodpos[-2])) elif obj.RodMode == rodmodes[1]: # /\/\/\ fw = True for i in range(1, obj.RodSections + 1): bottomrodpos.append(bottomrodpos[-1].add(bottomrodvec)) toprodpos.append(toprodpos[-1].add(toprodvec)) if obj.RodDirection == "Forward": if fw: rods.append( self.makeRod(rodprofile, bottomrodpos[-2], toprodpos[-1])) else: rods.append( self.makeRod(rodprofile, bottomrodpos[-1], toprodpos[-2])) else: if fw: rods.append( self.makeRod(rodprofile, bottomrodpos[-1], toprodpos[-2])) else: rods.append( self.makeRod(rodprofile, bottomrodpos[-2], toprodpos[-1])) fw = not fw elif obj.RodMode == rodmodes[2]: # /|\|/|\ fw = True for i in range(1, obj.RodSections + 1): if (i > 1) or (obj.StrutStartOffset.Value >= 0): # do not add first vert rod if negative offset rods.append( self.makeRod(rodprofile, bottomrodpos[-1], toprodpos[-1])) bottomrodpos.append(bottomrodpos[-1].add(bottomrodvec)) toprodpos.append(toprodpos[-1].add(toprodvec)) if obj.RodDirection == "Forward": if fw: rods.append( self.makeRod(rodprofile, bottomrodpos[-2], toprodpos[-1])) else: rods.append( self.makeRod(rodprofile, bottomrodpos[-1], toprodpos[-2])) else: if fw: rods.append( self.makeRod(rodprofile, bottomrodpos[-1], toprodpos[-2])) else: rods.append( self.makeRod(rodprofile, bottomrodpos[-2], toprodpos[-1])) fw = not fw # add end rod if obj.RodEnd: rods.append( self.makeRod(rodprofile, bottomrodpos[-1], toprodpos[-1])) # trim rods rods = [rod.cut(topstrut).cut(bottomstrut) for rod in rods] return topstrut, bottomstrut, rods, angle
def areaOpShapes(self, obj): '''areaOpShapes(obj) ... return shapes representing the solids to be removed.''' PathLog.track() PathLog.debug("areaOpShapes() in PathPocketShape.py") def judgeFinalDepth(obj, fD): if obj.FinalDepth.Value >= fD: return obj.FinalDepth.Value else: return fD def judgeStartDepth(obj, sD): if obj.StartDepth.Value >= sD: return obj.StartDepth.Value else: return sD def analyzeVerticalFaces(self, obj, vertTuples): hT = [] # base = FreeCAD.ActiveDocument.getObject(self.modelName) # Separate elements, regroup by orientation (axis_angle combination) vTags = ['X34.2'] vGrps = [[(2.3, 3.4, 'X')]] for tup in vertTuples: (face, sub, angle, axis, tag, strDep, finDep, trans) = tup if tag in vTags: # Determine index of found string i = 0 for orn in vTags: if orn == tag: break i += 1 vGrps[i].append(tup) else: vTags.append(tag) # add orientation entry vGrps.append([tup]) # add orientation entry # Remove temp elements vTags.pop(0) vGrps.pop(0) # check all faces in each axis_angle group shpList = [] zmaxH = 0.0 for o in range(0, len(vTags)): shpList = [] zmaxH = vGrps[o][0].BoundBox.ZMax for (face, sub, angle, axis, tag, strDep, finDep, trans) in vGrps[o]: shpList.append(face) # Identify tallest face to use as zMax if face.BoundBox.ZMax > zmaxH: zmaxH = face.BoundBox.ZMax # check all faces and see if they are touching/overlapping and combine those into a compound # Original Code in For loop self.vertical = PathGeom.combineConnectedShapes(shpList) self.vWires = [ TechDraw.findShapeOutline(shape, 1, FreeCAD.Vector(0, 0, 1)) for shape in self.vertical ] for wire in self.vWires: w = PathGeom.removeDuplicateEdges(wire) face = Part.Face(w) face.tessellate(0.05) if PathGeom.isRoughly(face.Area, 0): PathLog.error( translate( 'PathPocket', 'Vertical faces do not form a loop - ignoring') ) else: strDep = zmaxH + self.leadIn # base.Shape.BoundBox.ZMax finDep = judgeFinalDepth(obj, face.BoundBox.ZMin) tup = face, sub, angle, axis, tag, strDep, finDep, trans hT.append(tup) # Eol return hT if obj.Base: PathLog.debug('base items exist. Processing...') self.removalshapes = [] self.horiz = [] vertical = [] horizTuples = [] vertTuples = [] axis = 'X' angle = 0.0 reset = False resetPlacement = None trans = FreeCAD.Vector(0.0, 0.0, 0.0) for o in obj.Base: PathLog.debug('Base item: {}'.format(o)) base = o[0] # Limit sub faces to children of single Model object. if self.modelName is None: self.modelName = base.Name else: if base.Name != self.modelName: for sub in o[1]: PathLog.error(sub + " is not a part of Model object: " + self.modelName) o[1] = [] PathLog.error( "Only processing faces on a single Model object per operation." ) PathLog.error( "You will need to separate faces per Model object within the Job." ) startBase = FreeCAD.Vector(base.Placement.Base.x, base.Placement.Base.y, base.Placement.Base.z) startAngle = base.Placement.Rotation.Angle startAxis = base.Placement.Rotation.Axis startRotation = FreeCAD.Rotation(startAxis, startAngle) resetPlacement = FreeCAD.Placement(startBase, startRotation) for sub in o[1]: if 'Face' in sub: PathLog.debug('sub: {}'.format(sub)) # Determine angle of rotation needed to make normal vector = (0,0,1) strDep = obj.StartDepth.Value finDep = obj.FinalDepth.Value trans = FreeCAD.Vector(0.0, 0.0, 0.0) rtn = False if obj.UseRotation != 'Off': (rtn, angle, axis) = self.pocketRotationAnalysis(obj, base, sub, prnt=True) if rtn is True: reset = True PathLog.debug( str(sub) + ": rotating model to make face normal at (0,0,1) ..." ) if axis == 'X': bX = 0.0 bY = 0.0 bZ = math.sin(math.radians( angle)) * base.Placement.Base.y vect = FreeCAD.Vector(1, 0, 0) elif axis == 'Y': bX = 0.0 bY = 0.0 bZ = math.sin(math.radians( angle)) * base.Placement.Base.x if obj.B_AxisErrorOverride is True: bZ = -1 * bZ vect = FreeCAD.Vector(0, 1, 0) # Rotate base to such that Surface.Axis of pocket bottom is Z=1 base.Placement.Rotation = FreeCAD.Rotation( vect, angle) base.recompute() trans = FreeCAD.Vector(bX, bY, bZ) else: axis = 'X' angle = 0.0 tag = axis + str(round(angle, 7)) face = base.Shape.getElement(sub) if type(face.Surface ) == Part.Plane and PathGeom.isVertical( face.Surface.Axis): # it's a flat horizontal face PathLog.debug(" == Part.Plane: isVertical") # Adjust start and finish depths for pocket strDep = base.Shape.BoundBox.ZMax + self.leadIn finDep = judgeFinalDepth(obj, face.BoundBox.ZMin) # Over-write default final depth value, leaves manual override by user obj.StartDepth.Value = trans.z + strDep obj.FinalDepth.Value = trans.z + finDep tup = face, sub, angle, axis, tag, strDep, finDep, trans horizTuples.append(tup) elif type(face.Surface ) == Part.Cylinder and PathGeom.isVertical( face.Surface.Axis): PathLog.debug("== Part.Cylinder") # vertical cylinder wall if any(e.isClosed() for e in face.Edges): PathLog.debug("e.isClosed()") # complete cylinder circle = Part.makeCircle( face.Surface.Radius, face.Surface.Center) disk = Part.Face(Part.Wire(circle)) # Adjust start and finish depths for pocket strDep = face.BoundBox.ZMax + self.leadIn # base.Shape.BoundBox.ZMax + self.leadIn finDep = judgeFinalDepth( obj, face.BoundBox.ZMin) # Over-write default final depth value, leaves manual override by user obj.StartDepth.Value = trans.z + strDep obj.FinalDepth.Value = trans.z + finDep tup = disk, sub, angle, axis, tag, strDep, finDep, trans horizTuples.append(tup) else: # partial cylinder wall vertical.append(face) # Adjust start and finish depths for pocket strDep = face.BoundBox.ZMax + self.leadIn # base.Shape.BoundBox.ZMax + self.leadIn finDep = judgeFinalDepth( obj, face.BoundBox.ZMin) # Over-write default final depth value, leaves manual override by user obj.StartDepth.Value = trans.z + strDep obj.FinalDepth.Value = trans.z + finDep tup = face, sub, angle, axis, tag, strDep, finDep, trans vertTuples.append(tup) PathLog.debug(sub + "is vertical after rotation.") elif type(face.Surface ) == Part.Plane and PathGeom.isHorizontal( face.Surface.Axis): vertical.append(face) # Adjust start and finish depths for pocket strDep = face.BoundBox.ZMax + self.leadIn # base.Shape.BoundBox.ZMax + self.leadIn finDep = judgeFinalDepth(obj, face.BoundBox.ZMin) # Over-write default final depth value, leaves manual override by user obj.StartDepth.Value = trans.z + strDep obj.FinalDepth.Value = trans.z + finDep tup = face, sub, angle, axis, tag, strDep, finDep, trans vertTuples.append(tup) PathLog.debug(sub + "is vertical after rotation.") else: PathLog.error( translate( 'PathPocket', 'Pocket does not support shape %s.%s') % (base.Label, sub)) if reset is True: base.Placement.Rotation = startRotation base.recompute() reset = False # End IF # End FOR base.Placement = resetPlacement base.recompute() # End FOR # Analyze vertical faces via PathGeom.combineConnectedShapes() # hT = analyzeVerticalFaces(self, obj, vertTuples) # horizTuples.extend(hT) # This section will be replaced analyzeVerticalFaces(self, obj, vertTuples) above self.vertical = PathGeom.combineConnectedShapes(vertical) self.vWires = [ TechDraw.findShapeOutline(shape, 1, FreeCAD.Vector(0.0, 0.0, 1.0)) for shape in self.vertical ] for wire in self.vWires: w = PathGeom.removeDuplicateEdges(wire) face = Part.Face(w) face.tessellate(0.05) if PathGeom.isRoughly(face.Area, 0): PathLog.error( translate( 'PathPocket', 'Vertical faces do not form a loop - ignoring')) else: # self.horiz.append(face) strDep = base.Shape.BoundBox.ZMax + self.leadIn finDep = judgeFinalDepth(obj, face.BoundBox.ZMin) tup = face, 'vertFace', 0.0, 'X', 'X0.0', strDep, finDep, FreeCAD.Vector( 0.0, 0.0, 0.0) horizTuples.append(tup) # add faces for extensions self.exts = [] for ext in self.getExtensions(obj): wire = Part.Face(ext.getWire()) if wire: face = Part.Face(wire) # self.horiz.append(face) strDep = base.Shape.BoundBox.ZMax + self.leadIn finDep = judgeFinalDepth(obj, face.BoundBox.ZMin) tup = face, 'vertFace', 0.0, 'X', 'X0.0', strDep, finDep, FreeCAD.Vector( 0.0, 0.0, 0.0) horizTuples.append(tup) self.exts.append(face) # move all horizontal faces to FinalDepth for (face, sub, angle, axis, tag, strDep, finDep, trans) in horizTuples: # face.translate(FreeCAD.Vector(0, 0, obj.FinalDepth.Value - face.BoundBox.ZMin)) if angle <= 0.0: if axis == 'X': face.translate( FreeCAD.Vector( 0, trans.z, trans.z + finDep - face.BoundBox.ZMin)) elif axis == 'Y': face.translate( FreeCAD.Vector( -1 * trans.z, 0, trans.z + finDep - face.BoundBox.ZMin)) else: if axis == 'X': face.translate( FreeCAD.Vector( 0, -1 * trans.z, trans.z + finDep - face.BoundBox.ZMin)) elif axis == 'Y': face.translate( FreeCAD.Vector( trans.z, 0, trans.z + finDep - face.BoundBox.ZMin)) # Separate elements, regroup by orientation (axis_angle combination) hTags = ['X34.2'] hGrps = [[(2.3, 3.4, 'X')]] for tup in horizTuples: (face, sub, angle, axis, tag, strDep, finDep, trans) = tup if tag in hTags: # Determine index of found string i = 0 for orn in hTags: if orn == tag: break i += 1 hGrps[i].append(tup) else: hTags.append(tag) # add orientation entry hGrps.append([tup]) # add orientation entry # Remove temp elements hTags.pop(0) hGrps.pop(0) # check all faces in each axis_angle group self.horizontal = [] shpList = [] for o in range(0, len(hTags)): PathLog.debug('hTag: {}'.format(hTags[o])) shpList = [] for (face, sub, angle, axis, tag, strDep, finDep, trans) in hGrps[o]: shpList.append(face) # check all faces and see if they are touching/overlapping and combine those into a compound # Original Code in For loop for shape in PathGeom.combineConnectedShapes(shpList): shape.sewShape() # shape.tessellate(0.05) # Russ4262 0.1 original if obj.UseOutline: wire = TechDraw.findShapeOutline( shape, 1, FreeCAD.Vector(0, 0, 1)) wire.translate( FreeCAD.Vector( 0, 0, obj.FinalDepth.Value - wire.BoundBox.ZMin)) PathLog.debug( " -obj.UseOutline: obj.FinalDepth.Value" + str(obj.FinalDepth.Value)) PathLog.debug(" -obj.UseOutline: wire.BoundBox.ZMin" + str(wire.BoundBox.ZMin)) # shape.tessellate(0.05) # Russ4262 0.1 original face = Part.Face(wire) tup = face, sub, angle, axis, tag, strDep, finDep, trans self.horizontal.append(tup) else: # Re-pair shape to tuple set for (face, sub, angle, axis, tag, strDep, finDep, trans) in hGrps[o]: if shape is face: tup = face, sub, angle, axis, tag, strDep, finDep, trans self.horizontal.append(tup) break # Eol # extrude all faces up to StartDepth and those are the removal shapes for (face, sub, angle, axis, tag, strDep, finDep, trans) in self.horizontal: # extent = FreeCAD.Vector(0, 0, obj.StartDepth.Value - obj.FinalDepth.Value) extent = FreeCAD.Vector(0, 0, strDep - finDep) shp = face.removeSplitter().extrude(extent) # tup = shp, False, sub, angle, axis, tag, strDep, finDep, trans tup = shp, False, sub, angle, axis # shape, isHole, sub, angle, axis self.removalshapes.append(tup) else: # process the job base object as a whole PathLog.debug("processing the whole job base object") self.outlines = [ Part.Face( TechDraw.findShapeOutline(base.Shape, 1, FreeCAD.Vector(0, 0, 1))) for base in self.model ] stockBB = self.stock.Shape.BoundBox PathLog.debug(" -Using outlines; no obj.Base") self.removalshapes = [] self.bodies = [] for outline in self.outlines: outline.translate(FreeCAD.Vector(0, 0, stockBB.ZMin - 1)) body = outline.extrude( FreeCAD.Vector(0, 0, stockBB.ZLength + 2)) self.bodies.append(body) self.removalshapes.append( (self.stock.Shape.cut(body), False, 'outline', 0.0, 'X')) for (shape, isHole, sub, angle, axis) in self.removalshapes: shape.tessellate(0.05) if self.removalshapes: obj.removalshape = self.removalshapes[0][0] return self.removalshapes
def getSVG(obj, scale=1, linewidth=0.35, fontsize=12, fillstyle="shape color", direction=None, linestyle=None, color=None, linespacing=None, techdraw=False, rotation=0, fillSpaces=False, override=True): '''getSVG(object,[scale], [linewidth],[fontsize],[fillstyle],[direction],[linestyle],[color],[linespacing]): returns a string containing a SVG representation of the given object, with the given linewidth and fontsize (used if the given object contains any text). You can also supply an arbitrary projection vector. the scale parameter allows to scale linewidths down, so they are resolution-independant.''' import Part, DraftGeomUtils # if this is a group, gather all the svg views of its children if hasattr(obj, "isDerivedFrom"): if obj.isDerivedFrom("App::DocumentObjectGroup") or getType( obj) == "Layer": svg = "" for child in obj.Group: svg += getSVG(child, scale, linewidth, fontsize, fillstyle, direction, linestyle, color, linespacing, techdraw, rotation, fillSpaces, override) return svg pathdata = [] svg = "" linewidth = float(linewidth) / scale if not override: if hasattr(obj, "ViewObject"): if hasattr(obj.ViewObject, "LineWidth"): if hasattr(obj.ViewObject.LineWidth, "Value"): lw = obj.ViewObject.LineWidth.Value else: lw = obj.ViewObject.LineWidth linewidth = lw * linewidth fontsize = (float(fontsize) / scale) / 2 if linespacing: linespacing = float(linespacing) / scale else: linespacing = 0.5 #print obj.Label," line spacing ",linespacing,"scale ",scale pointratio = .75 # the number of times the dots are smaller than the arrow size plane = None if direction: if isinstance(direction, FreeCAD.Vector): if direction != Vector(0, 0, 0): plane = WorkingPlane.plane() plane.alignToPointAndAxis_SVG(Vector(0, 0, 0), direction.negative().negative(), 0) elif isinstance(direction, WorkingPlane.plane): plane = direction stroke = "#000000" if color and override: if "#" in color: stroke = color else: stroke = getrgb(color) elif gui: if hasattr(obj, "ViewObject"): if hasattr(obj.ViewObject, "LineColor"): stroke = getrgb(obj.ViewObject.LineColor) elif hasattr(obj.ViewObject, "TextColor"): stroke = getrgb(obj.ViewObject.TextColor) lstyle = "none" if override: lstyle = getLineStyle(linestyle, scale) else: if hasattr(obj, "ViewObject"): if hasattr(obj.ViewObject, "DrawStyle"): lstyle = getLineStyle(obj.ViewObject.DrawStyle, scale) def getPath(edges=[], wires=[], pathname=None): svg = "<path " if pathname is None: svg += 'id="%s" ' % obj.Name elif pathname != "": svg += 'id="%s" ' % pathname svg += ' d="' if not wires: egroups = Part.sortEdges(edges) else: egroups = [] first = True for w in wires: w1 = w.copy() if first: first = False else: # invert further wires to create holes w1 = DraftGeomUtils.invert(w1) w1.fixWire() egroups.append(Part.__sortEdges__(w1.Edges)) for egroupindex, edges in enumerate(egroups): edata = "" vs = () #skipped for the first edge for edgeindex, e in enumerate(edges): previousvs = vs # vertexes of an edge (reversed if needed) vs = e.Vertexes if previousvs: if (vs[0].Point - previousvs[-1].Point).Length > 1e-6: vs.reverse() if edgeindex == 0: v = getProj(vs[0].Point, plane) edata += 'M ' + str(v.x) + ' ' + str(v.y) + ' ' else: if (vs[0].Point - previousvs[-1].Point).Length > 1e-6: raise ValueError('edges not ordered') iscircle = DraftGeomUtils.geomType(e) == "Circle" isellipse = DraftGeomUtils.geomType(e) == "Ellipse" if iscircle or isellipse: import math if hasattr(FreeCAD, "DraftWorkingPlane"): drawing_plane_normal = FreeCAD.DraftWorkingPlane.axis else: drawing_plane_normal = FreeCAD.Vector(0, 0, 1) if plane: drawing_plane_normal = plane.axis c = e.Curve if round(c.Axis.getAngle(drawing_plane_normal), 2) in [0, 3.14]: occversion = Part.OCC_VERSION.split(".") done = False if (int(occversion[0]) >= 7) and (int(occversion[1]) >= 1): # if using occ >= 7.1, use HLR algorithm import Drawing snip = Drawing.projectToSVG( e, drawing_plane_normal) if snip: try: a = "A " + snip.split("path d=\"")[ 1].split("\"")[0].split("A")[1] except: pass else: edata += a done = True if not done: if len(e.Vertexes ) == 1 and iscircle: #complete curve svg = getCircle(e) return svg elif len(e.Vertexes) == 1 and isellipse: #svg = getEllipse(e) #return svg endpoints = [ getProj( c.value((c.LastParameter - c.FirstParameter) / 2.0), plane), getProj(vs[-1].Point, plane) ] else: endpoints = [getProj(vs[-1].Point, plane)] # arc if iscircle: rx = ry = c.Radius rot = 0 else: #ellipse rx = c.MajorRadius ry = c.MinorRadius rot = math.degrees(c.AngleXU * (c.Axis * \ FreeCAD.Vector(0,0,1))) if rot > 90: rot -= 180 if rot < -90: rot += 180 #be careful with the sweep flag flag_large_arc = (((e.ParameterRange[1] - \ e.ParameterRange[0]) / math.pi) % 2) > 1 #flag_sweep = (c.Axis * drawing_plane_normal >= 0) \ # == (e.LastParameter > e.FirstParameter) # == (e.Orientation == "Forward") # other method: check the direction of the angle between tangents t1 = e.tangentAt(e.FirstParameter) t2 = e.tangentAt( e.FirstParameter + (e.LastParameter - e.FirstParameter) / 10) flag_sweep = (DraftVecUtils.angle( t1, t2, drawing_plane_normal) < 0) for v in endpoints: edata += 'A %s %s %s %s %s %s %s ' % \ (str(rx),str(ry),str(rot),\ str(int(flag_large_arc)),\ str(int(flag_sweep)),str(v.x),str(v.y)) else: edata += getDiscretized(e, plane) elif DraftGeomUtils.geomType(e) == "Line": v = getProj(vs[-1].Point, plane) edata += 'L ' + str(v.x) + ' ' + str(v.y) + ' ' else: bspline = e.Curve.toBSpline(e.FirstParameter, e.LastParameter) if bspline.Degree > 3 or bspline.isRational(): try: bspline = bspline.approximateBSpline( 0.05, 50, 3, 'C0') except RuntimeError: print("Debug: unable to approximate bspline") if bspline.Degree <= 3 and not bspline.isRational(): for bezierseg in bspline.toBezier(): if bezierseg.Degree > 3: #should not happen raise AssertionError elif bezierseg.Degree == 1: edata += 'L ' elif bezierseg.Degree == 2: edata += 'Q ' elif bezierseg.Degree == 3: edata += 'C ' for pole in bezierseg.getPoles()[1:]: v = getProj(pole, plane) edata += str(v.x) + ' ' + str(v.y) + ' ' else: print("Debug: one edge (hash ",e.hashCode(),\ ") has been discretized with parameter 0.1") for linepoint in bspline.discretize(0.1)[1:]: v = getProj(linepoint, plane) edata += 'L ' + str(v.x) + ' ' + str(v.y) + ' ' if fill != 'none': edata += 'Z ' if edata in pathdata: # do not draw a path on another identical path return "" else: svg += edata pathdata.append(edata) svg += '" ' svg += 'stroke="' + stroke + '" ' svg += 'stroke-width="' + str(linewidth) + ' px" ' svg += 'style="stroke-width:' + str(linewidth) svg += ';stroke-miterlimit:4' svg += ';stroke-dasharray:' + lstyle svg += ';fill:' + fill try: svg += ';fill-opacity:' + str(fill_opacity) except NameError: pass svg += ';fill-rule: evenodd "' svg += '/>\n' return svg def getCircle(edge): cen = getProj(edge.Curve.Center, plane) rad = edge.Curve.Radius if hasattr(FreeCAD, "DraftWorkingPlane"): drawing_plane_normal = FreeCAD.DraftWorkingPlane.axis else: drawing_plane_normal = FreeCAD.Vector(0, 0, 1) if plane: drawing_plane_normal = plane.axis if round(edge.Curve.Axis.getAngle(drawing_plane_normal), 2) in [0, 3.14]: # perpendicular projection: circle svg = '<circle cx="' + str(cen.x) svg += '" cy="' + str(cen.y) svg += '" r="' + str(rad) + '" ' else: # any other projection: ellipse svg = '<path d="' svg += getDiscretized(edge, plane) svg += '" ' svg += 'stroke="' + stroke + '" ' svg += 'stroke-width="' + str(linewidth) + ' px" ' svg += 'style="stroke-width:' + str(linewidth) svg += ';stroke-miterlimit:4' svg += ';stroke-dasharray:' + lstyle svg += ';fill:' + fill + '"' svg += '/>\n' return svg def getEllipse(edge): cen = getProj(edge.Curve.Center, plane) mir = edge.Curve.MinorRadius mar = edge.Curve.MajorRadius svg = '<ellipse cx="' + str(cen.x) svg += '" cy="' + str(cen.y) svg += '" rx="' + str(mar) svg += '" ry="' + str(mir) + '" ' svg += 'stroke="' + stroke + '" ' svg += 'stroke-width="' + str(linewidth) + ' px" ' svg += 'style="stroke-width:' + str(linewidth) svg += ';stroke-miterlimit:4' svg += ';stroke-dasharray:' + lstyle svg += ';fill:' + fill + '"' svg += '/>\n' return svg def getArrow(arrowtype, point, arrowsize, color, linewidth, angle=0): svg = "" if gui: if not obj.ViewObject: return svg if obj.ViewObject.ArrowType == "Circle": svg += '<circle cx="' + str(point.x) + '" cy="' + str(point.y) svg += '" r="' + str(arrowsize) + '" ' svg += 'fill="none" stroke="' + color + '" ' svg += 'style="stroke-width:' + str( linewidth) + ';stroke-miterlimit:4;stroke-dasharray:none" ' svg += 'freecad:skip="1"' svg += '/>\n' elif obj.ViewObject.ArrowType == "Dot": svg += '<circle cx="' + str(point.x) + '" cy="' + str(point.y) svg += '" r="' + str(arrowsize) + '" ' svg += 'fill="' + color + '" stroke="none" ' svg += 'style="stroke-miterlimit:4;stroke-dasharray:none" ' svg += 'freecad:skip="1"' svg += '/>\n' elif obj.ViewObject.ArrowType == "Arrow": svg += '<path transform="rotate(' + str(math.degrees(angle)) svg += ',' + str(point.x) + ',' + str(point.y) + ') ' svg += 'translate(' + str(point.x) + ',' + str(point.y) + ') ' svg += 'scale(' + str(arrowsize) + ',' + str( arrowsize) + ')" freecad:skip="1" ' svg += 'fill="' + color + '" stroke="none" ' svg += 'style="stroke-miterlimit:4;stroke-dasharray:none" ' svg += 'd="M 0 0 L 4 1 L 4 -1 Z"/>\n' elif obj.ViewObject.ArrowType == "Tick": svg += '<path transform="rotate(' + str(math.degrees(angle)) svg += ',' + str(point.x) + ',' + str(point.y) + ') ' svg += 'translate(' + str(point.x) + ',' + str(point.y) + ') ' svg += 'scale(' + str(arrowsize) + ',' + str( arrowsize) + ')" freecad:skip="1" ' svg += 'fill="' + color + '" stroke="none" ' svg += 'style="stroke-miterlimit:4;stroke-dasharray:none" ' svg += 'd="M -1 -2 L 0 2 L 1 2 L 0 -2 Z"/>\n' elif obj.ViewObject.ArrowType == "Tick-2": svg += '<line transform="rotate(' + str( math.degrees(angle) + 45) svg += ',' + str(point.x) + ',' + str(point.y) + ') ' svg += 'translate(' + str(point.x) + ',' + str(point.y) + ') ' svg += '" freecad:skip="1" ' svg += 'fill="none" stroke="' + color + '" ' svg += 'style="stroke-dasharray:none;stroke-linecap:square;' svg += 'stroke-width:' + str(linewidth) + '" ' svg += 'x1="-' + str(arrowsize * 2) + '" y1="0" ' svg += 'x2="' + str(arrowsize * 2) + '" y2="0" />\n' else: print("getSVG: arrow type not implemented") return svg def getOvershoot(point, shootsize, color, linewidth, angle=0): svg = '<line transform="rotate(' + str(math.degrees(angle)) svg += ',' + str(point.x) + ',' + str(point.y) + ') ' svg += 'translate(' + str(point.x) + ',' + str(point.y) + ') ' svg += '" freecad:skip="1" ' svg += 'fill="none" stroke="' + color + '" ' svg += 'style="stroke-dasharray:none;stroke-linecap:square;' svg += 'stroke-width:' + str(linewidth) + '" ' svg += 'x1="0" y1="0" ' svg += 'x2="' + str(shootsize * -1) + '" y2="0" />\n' return svg def getText(tcolor, fontsize, fontname, angle, base, text, linespacing=0.5, align="center", flip=True): if isinstance(angle, FreeCAD.Rotation): if not plane: angle = angle.Angle else: if plane.axis.getAngle(angle.Axis) < 0.001: angle = angle.Angle elif abs(plane.axis.getAngle(angle.Axis) - math.pi) < 0.001: if abs(angle.Angle) > 0.1: angle = -angle.Angle else: angle = angle.Angle elif abs(plane.axis.getAngle(angle.Axis) - math.pi / 2) < 0.001: return "" # text is perpendicular to view, so it shouldn't appear else: angle = 0 #TODO maybe there is something better to do here? if not isinstance(text, list): text = text.split("\n") if align.lower() == "center": anchor = "middle" elif align.lower() == "left": anchor = "start" else: anchor = "end" if techdraw: svg = "" for i in range(len(text)): t = text[i].replace("&", "&").replace("<", "<").replace( ">", ">") if six.PY2 and not isinstance(t, six.text_type): t = t.decode("utf8") # possible workaround if UTF8 is unsupported # import unicodedata # t = u"".join([c for c in unicodedata.normalize("NFKD",t) if not unicodedata.combining(c)]).encode("utf8") svg += '<text stroke-width="0" stroke="' + tcolor + '" fill="' + tcolor + '" font-size="' + str( fontsize) + '" ' svg += 'style="text-anchor:' + anchor + ';text-align:' + align.lower( ) + ';' svg += 'font-family:' + fontname + '" ' svg += 'transform="rotate(' + str(math.degrees(angle)) svg += ',' + str( base.x) + ',' + str(base.y - linespacing * i) + ') ' svg += 'translate(' + str( base.x) + ',' + str(base.y - linespacing * i) + ') ' svg += 'scale(1,-1)" ' #svg += '" freecad:skip="1"' svg += '>\n' + t + '</text>\n' else: svg = '<text stroke-width="0" stroke="' + tcolor + '" fill="' svg += tcolor + '" font-size="' svg += str(fontsize) + '" ' svg += 'style="text-anchor:' + anchor + ';text-align:' + align.lower( ) + ';' svg += 'font-family:' + fontname + '" ' svg += 'transform="rotate(' + str(math.degrees(angle)) svg += ',' + str(base.x) + ',' + str(base.y) + ') ' if flip: svg += 'translate(' + str(base.x) + ',' + str(base.y) + ')' else: svg += 'translate(' + str(base.x) + ',' + str(-base.y) + ')' #svg += 'scale('+str(tmod/2000)+',-'+str(tmod/2000)+') ' if flip: svg += ' scale(1,-1) ' else: svg += ' scale(1,1) ' svg += '" freecad:skip="1"' svg += '>\n' if len(text) == 1: try: svg += text[0].replace("&", "&").replace( "<", "<").replace(">", ">") except: svg += text[0].decode("utf8").replace( "&", "&").replace("<", "<").replace(">", ">") else: for i in range(len(text)): if i == 0: svg += '<tspan>' else: svg += '<tspan x="0" dy="' + str(linespacing) + '">' try: svg += text[i].replace("&", "&").replace( "<", "<").replace(">", ">") except: svg += text[i].decode("utf8").replace( "&", "&").replace("<", "<").replace(">", ">") svg += '</tspan>\n' svg += '</text>\n' return svg if not obj: pass elif isinstance(obj, Part.Shape): if "#" in fillstyle: fill = fillstyle elif fillstyle == "shape color": fill = "#888888" else: fill = 'url(#' + fillstyle + ')' svg += getPath(obj.Edges, pathname="") elif getType(obj) in ["Dimension", "LinearDimension"]: if gui: if not obj.ViewObject: print( "export of dimensions to SVG is only available in GUI mode" ) elif obj.ViewObject.Proxy: if hasattr(obj.ViewObject.Proxy, "p1"): prx = obj.ViewObject.Proxy ts = (len(prx.string) * obj.ViewObject.FontSize.Value) / 4.0 rm = ((prx.p3.sub(prx.p2)).Length / 2.0) - ts p2a = getProj( prx.p2.add( DraftVecUtils.scaleTo(prx.p3.sub(prx.p2), rm)), plane) p2b = getProj( prx.p3.add( DraftVecUtils.scaleTo(prx.p2.sub(prx.p3), rm)), plane) p1 = getProj(prx.p1, plane) p2 = getProj(prx.p2, plane) p3 = getProj(prx.p3, plane) p4 = getProj(prx.p4, plane) tbase = getProj(prx.tbase, plane) r = prx.textpos.rotation.getValue().getValue() rv = FreeCAD.Rotation(r[0], r[1], r[2], r[3]).multVec( FreeCAD.Vector(1, 0, 0)) angle = -DraftVecUtils.angle(getProj(rv, plane)) #angle = -DraftVecUtils.angle(p3.sub(p2)) svg = '' nolines = False if hasattr(obj.ViewObject, "ShowLine"): if not obj.ViewObject.ShowLine: nolines = True # drawing lines if not nolines: svg += '<path ' if obj.ViewObject.DisplayMode == "2D": tangle = angle if tangle > math.pi / 2: tangle = tangle - math.pi #elif (tangle <= -math.pi/2) or (tangle > math.pi/2): # tangle = tangle+math.pi #tbase = tbase.add(DraftVecUtils.rotate(Vector(0,2/scale,0),tangle)) if rotation != 0: #print "dim: tangle:",tangle," rot: ",rotation," text: ",prx.string if abs(tangle + math.radians(rotation)) < 0.0001: tangle += math.pi tbase = tbase.add( DraftVecUtils.rotate( Vector(0, 2 / scale, 0), tangle)) if not nolines: svg += 'd="M ' + str(p1.x) + ' ' + str(p1.y) + ' ' svg += 'L ' + str(p2.x) + ' ' + str(p2.y) + ' ' svg += 'L ' + str(p3.x) + ' ' + str(p3.y) + ' ' svg += 'L ' + str(p4.x) + ' ' + str(p4.y) + '" ' else: tangle = 0 if rotation != 0: tangle = -math.radians(rotation) tbase = tbase.add(Vector(0, -2.0 / scale, 0)) if not nolines: svg += 'd="M ' + str(p1.x) + ' ' + str(p1.y) + ' ' svg += 'L ' + str(p2.x) + ' ' + str(p2.y) + ' ' svg += 'L ' + str(p2a.x) + ' ' + str(p2a.y) + ' ' svg += 'M ' + str(p2b.x) + ' ' + str(p2b.y) + ' ' svg += 'L ' + str(p3.x) + ' ' + str(p3.y) + ' ' svg += 'L ' + str(p4.x) + ' ' + str(p4.y) + '" ' if not nolines: svg += 'fill="none" stroke="' svg += stroke + '" ' svg += 'stroke-width="' + str(linewidth) + ' px" ' svg += 'style="stroke-width:' + str(linewidth) svg += ';stroke-miterlimit:4;stroke-dasharray:none" ' svg += 'freecad:basepoint1="' + str(p1.x) + ' ' + str( p1.y) + '" ' svg += 'freecad:basepoint2="' + str(p4.x) + ' ' + str( p4.y) + '" ' svg += 'freecad:dimpoint="' + str(p2.x) + ' ' + str( p2.y) + '"' svg += '/>\n' # drawing dimension and extension lines overshoots if hasattr(obj.ViewObject, "DimOvershoot" ) and obj.ViewObject.DimOvershoot.Value: shootsize = obj.ViewObject.DimOvershoot.Value / pointratio svg += getOvershoot(p2, shootsize, stroke, linewidth, angle) svg += getOvershoot(p3, shootsize, stroke, linewidth, angle + math.pi) if hasattr(obj.ViewObject, "ExtOvershoot" ) and obj.ViewObject.ExtOvershoot.Value: shootsize = obj.ViewObject.ExtOvershoot.Value / pointratio shootangle = -DraftVecUtils.angle(p1.sub(p2)) svg += getOvershoot(p2, shootsize, stroke, linewidth, shootangle) svg += getOvershoot(p3, shootsize, stroke, linewidth, shootangle) # drawing arrows if hasattr(obj.ViewObject, "ArrowType"): arrowsize = obj.ViewObject.ArrowSize.Value / pointratio if hasattr(obj.ViewObject, "FlipArrows"): if obj.ViewObject.FlipArrows: angle = angle + math.pi svg += getArrow(obj.ViewObject.ArrowType, p2, arrowsize, stroke, linewidth, angle) svg += getArrow(obj.ViewObject.ArrowType, p3, arrowsize, stroke, linewidth, angle + math.pi) # drawing text svg += getText(stroke, fontsize, obj.ViewObject.FontName, tangle, tbase, prx.string) elif getType(obj) == "AngularDimension": if gui: if not obj.ViewObject: print( "export of dimensions to SVG is only available in GUI mode" ) elif obj.ViewObject.Proxy: if hasattr(obj.ViewObject.Proxy, "circle"): prx = obj.ViewObject.Proxy # drawing arc fill = "none" if obj.ViewObject.DisplayMode == "2D": svg += getPath([prx.circle]) else: if hasattr(prx, "circle1"): svg += getPath([prx.circle1]) svg += getPath([prx.circle2]) else: svg += getPath([prx.circle]) # drawing arrows if hasattr(obj.ViewObject, "ArrowType"): p2 = getProj(prx.p2, plane) p3 = getProj(prx.p3, plane) arrowsize = obj.ViewObject.ArrowSize.Value / pointratio arrowlength = 4 * obj.ViewObject.ArrowSize.Value u1 = getProj( (prx.circle.valueAt(prx.circle.FirstParameter + arrowlength) ).sub( prx.circle.valueAt( prx.circle.FirstParameter)), plane) u2 = getProj( (prx.circle.valueAt(prx.circle.LastParameter - arrowlength) ).sub(prx.circle.valueAt( prx.circle.LastParameter)), plane) angle1 = -DraftVecUtils.angle(u1) angle2 = -DraftVecUtils.angle(u2) if hasattr(obj.ViewObject, "FlipArrows"): if obj.ViewObject.FlipArrows: angle1 = angle1 + math.pi angle2 = angle2 + math.pi svg += getArrow(obj.ViewObject.ArrowType, p2, arrowsize, stroke, linewidth, angle1) svg += getArrow(obj.ViewObject.ArrowType, p3, arrowsize, stroke, linewidth, angle2) # drawing text if obj.ViewObject.DisplayMode == "2D": t = prx.circle.tangentAt(prx.circle.FirstParameter + (prx.circle.LastParameter - prx.circle.FirstParameter) / 2.0) t = getProj(t, plane) tangle = DraftVecUtils.angle(t) if (tangle <= -math.pi / 2) or (tangle > math.pi / 2): tangle = tangle + math.pi tbase = getProj( prx.circle.valueAt(prx.circle.FirstParameter + (prx.circle.LastParameter - prx.circle.FirstParameter) / 2.0), plane) tbase = tbase.add( DraftVecUtils.rotate(Vector(0, 2.0 / scale, 0), tangle)) #print(tbase) else: tangle = 0 tbase = getProj(prx.tbase, plane) svg += getText(stroke, fontsize, obj.ViewObject.FontName, tangle, tbase, prx.string) elif getType(obj) == "Label": if getattr(obj.ViewObject, "Line", True): # some Labels may have no Line property def format_point(coords, action='L'): return "{action}{x},{y}".format(x=coords.x, y=coords.y, action=action) # Draw multisegment line proj_points = list(map(lambda x: getProj(x, plane), obj.Points)) path_dir_list = [format_point(proj_points[0], action='M')] path_dir_list += map(format_point, proj_points[1:]) path_dir_str = " ".join(path_dir_list) svg_path = '<path fill="none" stroke="{stroke}" stroke-width="{linewidth}" d="{directions}"/>'.format( stroke=stroke, linewidth=linewidth, directions=path_dir_str) svg += svg_path # Draw arrow. # We are different here from 3D view # if Line is set to 'off', no arrow is drawn if hasattr(obj.ViewObject, "ArrowType") and len(obj.Points) >= 2: last_segment = FreeCAD.Vector(obj.Points[-1] - obj.Points[-2]) angle = -DraftVecUtils.angle(getProj(last_segment, plane)) + math.pi svg += getArrow(arrowtype=obj.ViewObject.ArrowType, point=proj_points[-1], arrowsize=obj.ViewObject.ArrowSize.Value / pointratio, color=stroke, linewidth=linewidth, angle=angle) # print text if gui: if not obj.ViewObject: print("export of texts to SVG is only available in GUI mode") else: fontname = obj.ViewObject.TextFont position = getProj(obj.Placement.Base, plane) rotation = obj.Placement.Rotation justification = obj.ViewObject.TextAlignment text = obj.Text svg += getText(stroke, fontsize, fontname, rotation, position, text, linespacing, justification) elif getType(obj) in ["Annotation", "DraftText"]: "returns an svg representation of a document annotation" if gui: if not obj.ViewObject: print("export of texts to SVG is only available in GUI mode") else: n = obj.ViewObject.FontName if getType(obj) == "Annotation": p = getProj(obj.Position, plane) r = obj.ViewObject.Rotation.getValueAs("rad") t = obj.LabelText else: # DraftText p = getProj(obj.Placement.Base, plane) r = obj.Placement.Rotation t = obj.Text j = obj.ViewObject.Justification svg += getText(stroke, fontsize, n, r, p, t, linespacing, j) elif getType(obj) == "Axis": "returns the SVG representation of an Arch Axis system" if gui: if not obj.ViewObject: print("export of axes to SVG is only available in GUI mode") else: vobj = obj.ViewObject lorig = lstyle fill = 'none' rad = vobj.BubbleSize.Value / 2 n = 0 for e in obj.Shape.Edges: lstyle = lorig svg += getPath([e]) lstyle = "none" pos = ["Start"] if hasattr(vobj, "BubblePosition"): if vobj.BubblePosition == "Both": pos = ["Start", "End"] else: pos = [vobj.BubblePosition] for p in pos: if p == "Start": p1 = e.Vertexes[0].Point p2 = e.Vertexes[1].Point else: p1 = e.Vertexes[1].Point p2 = e.Vertexes[0].Point dv = p2.sub(p1) dv.normalize() center = p2.add(dv.scale(rad, rad, rad)) svg += getCircle(Part.makeCircle(rad, center)) if hasattr(vobj.Proxy, "bubbletexts"): if len(vobj.Proxy.bubbletexts) >= n: svg += '<text fill="' + stroke + '" ' svg += 'font-size="' + str(rad) + '" ' svg += 'style="text-anchor:middle;' svg += 'text-align:center;' svg += 'font-family: sans;" ' svg += 'transform="translate(' + str( center.x + rad / 4.0) + ',' + str(center.y - rad / 3.0) + ') ' svg += 'scale(1,-1)"> ' svg += '<tspan>' + obj.ViewObject.Proxy.bubbletexts[ n].string.getValues()[0] + '</tspan>\n' svg += '</text>\n' n += 1 lstyle = lorig elif getType(obj) == "Pipe": fill = stroke if obj.Base and obj.Diameter: svg += getPath(obj.Base.Shape.Edges) for f in obj.Shape.Faces: if len(f.Edges) == 1: if isinstance(f.Edges[0].Curve, Part.Circle): svg += getCircle(f.Edges[0]) elif getType(obj) == "Rebar": fill = "none" if obj.Proxy: if not hasattr(obj.Proxy, "wires"): obj.Proxy.execute(obj) if hasattr(obj.Proxy, "wires"): svg += getPath(wires=obj.Proxy.wires) elif getType(obj) == "PipeConnector": pass elif getType(obj) == "Space": "returns an SVG fragment for the text of a space" if gui: if not obj.ViewObject: print("export of spaces to SVG is only available in GUI mode") else: if fillSpaces: if hasattr(obj, "Proxy"): if not hasattr(obj.Proxy, "face"): obj.Proxy.getArea(obj, notouch=True) if hasattr(obj.Proxy, "face"): # setting fill if gui: fill = getrgb(obj.ViewObject.ShapeColor, testbw=False) fill_opacity = 1 - ( obj.ViewObject.Transparency / 100.0) else: fill = "#888888" svg += getPath(wires=[obj.Proxy.face.OuterWire]) c = getrgb(obj.ViewObject.TextColor) n = obj.ViewObject.FontName a = 0 if rotation != 0: a = math.radians(rotation) t1 = obj.ViewObject.Proxy.text1.string.getValues() t2 = obj.ViewObject.Proxy.text2.string.getValues() scale = obj.ViewObject.FirstLine.Value / obj.ViewObject.FontSize.Value f1 = fontsize * scale p2 = obj.Placement.multVec( FreeCAD.Vector(obj.ViewObject.Proxy.coords.translation. getValue().getValue())) lspc = FreeCAD.Vector(obj.ViewObject.Proxy.header.translation. getValue().getValue()) p1 = p2.add(lspc) j = obj.ViewObject.TextAlign t3 = getText(c, f1, n, a, getProj(p1, plane), t1, linespacing, j, flip=True) svg += t3 if t2: ofs = FreeCAD.Vector(0, -lspc.Length, 0) if a: ofs = FreeCAD.Rotation(FreeCAD.Vector(0, 0, 1), -rotation).multVec(ofs) t4 = getText(c, fontsize, n, a, getProj(p1, plane).add(ofs), t2, linespacing, j, flip=True) svg += t4 elif obj.isDerivedFrom('Part::Feature'): if obj.Shape.isNull(): return '' # setting fill if obj.Shape.Faces: if gui: try: m = obj.ViewObject.DisplayMode except AttributeError: m = None if (m != "Wireframe"): if fillstyle == "shape color": fill = getrgb(obj.ViewObject.ShapeColor, testbw=False) fill_opacity = 1 - (obj.ViewObject.Transparency / 100.0) else: fill = 'url(#' + fillstyle + ')' svg += getPattern(fillstyle) else: fill = "none" else: fill = "#888888" else: fill = 'none' if len(obj.Shape.Vertexes) > 1: wiredEdges = [] if obj.Shape.Faces: for i, f in enumerate(obj.Shape.Faces): # place outer wire first wires = [f.OuterWire] wires.extend([ w for w in f.Wires if w.hashCode() != f.OuterWire.hashCode() ]) svg += getPath(wires=f.Wires,pathname='%s_f%04d' % \ (obj.Name,i)) wiredEdges.extend(f.Edges) else: for i, w in enumerate(obj.Shape.Wires): svg += getPath(w.Edges,pathname='%s_w%04d' % \ (obj.Name,i)) wiredEdges.extend(w.Edges) if len(wiredEdges) != len(obj.Shape.Edges): for i, e in enumerate(obj.Shape.Edges): if (DraftGeomUtils.findEdge(e, wiredEdges) is None): svg += getPath([e],pathname='%s_nwe%04d' % \ (obj.Name,i)) else: # closed circle or spline if obj.Shape.Edges: if isinstance(obj.Shape.Edges[0].Curve, Part.Circle): svg = getCircle(obj.Shape.Edges[0]) else: svg = getPath(obj.Shape.Edges) if FreeCAD.GuiUp: if hasattr(obj.ViewObject, "EndArrow") and hasattr( obj.ViewObject, "ArrowType") and (len(obj.Shape.Vertexes) > 1): if obj.ViewObject.EndArrow: p1 = getProj(obj.Shape.Vertexes[-1].Point, plane) p2 = getProj(obj.Shape.Vertexes[-2].Point, plane) angle = -DraftVecUtils.angle(p2.sub(p1)) arrowsize = obj.ViewObject.ArrowSize.Value / pointratio svg += getArrow(obj.ViewObject.ArrowType, p1, arrowsize, stroke, linewidth, angle) # techdraw expects bottom-to-top coordinates if techdraw: svg = '<g transform ="scale(1,-1)">\n ' + svg + '</g>\n' return svg