import FreeCAD as App, Part, FreeCADGui #import PartDesign from FreeCAD import Base def toMM(value): # Convert gawdawful imperial to mm return (value * 25.4) ROBUSTNESS = 1.25 #Scaling factor for pipes and struts. Distorts true scale # but makes the part stronger for the model PIPE_3_5_DIAMETER = ROBUSTNESS * toMM(0.159) PIPE_3_5_RADIUS = PIPE_3_5_DIAMETER / 2.0 PIPE_2_5_DIAMETER = ROBUSTNESS * toMM(0.114) PIPE_2_5_RADIUS = PIPE_2_5_DIAMETER / 2.0 TOWER_HEIGHT = toMM(5.455) #TOWER_BASE_SEMI_SPAN = toMM(1.099) TOWER_BASE_SEMI_SPAN = toMM(1.228) TOWER_TOP_SEMI_SPAN = toMM(0.733) LOWER_STRUT_HEIGHT = toMM(1.393) UPPER_STRUT_HEIGHT = toMM(2.618) BASE_STRUT_HEIGHT = toMM(0.993) BASE_STRUT_ATTACH = toMM(0.310) TORUS_RADIUS = toMM(0.539) # Center of the torus TORUS_HEIGHT = toMM(3.991) POST_DIAMETER = toMM(0.125) POST_RADIUS = POST_DIAMETER / 2.0 POST_HEIGHT = toMM(0.20) STEP_RADIUS = toMM(0.084) STEP_PIPE_OUTER_RADIUS = toMM(0.082) STEP_PIPE_HEIGHT = toMM(0.290) STEP_WIDTH = 2 * STEP_RADIUS STEP_HEIGHT = toMM(0.023) STEP_LENGTH = toMM(0.283) STEP_BRACE_EDGE = (3 * STEP_LENGTH) / 4 class TowerLeg(object): _lastObject = None def __init__(self, body, x1, y1, x2, y2, z): self._doc = FreeCAD.activeDocument() self._body = body self._base = Base.Vector(x1,y1,0.0) self._top = Base.Vector(x2,y2,z) self._height = z self._tan_x = z / float(x1-x2) self._tan_y = z / float(y1-y2) self._x1 = x1 self._y1 = y1 self._x2 = x2 self._y2 = y2 self._z = z self._components = [] @classmethod def getLast(cls): return cls._lastObject @classmethod def setLast(cls, last): cls._lastObject = last def addFeature(self, name): obj = self._doc.addObject("Part::Feature",name) #self._body.addObject(obj) #if self.getLast() is not None: # FreeCADGui.activeDocument().hide(self.getLast().Name) # pass #self.setLast(obj) self._components.append(obj) return obj def drawLeg(self): # Draw separately here, as the pipe ends are level with the main plane circle = Part.makeCircle(PIPE_3_5_RADIUS, self._base) wire=Part.Wire(circle) face=Part.Face(wire) self._tube = face.extrude(Base.Vector(self._x2-self._x1,self._y2-self._y1,self._z)) self._obj = self.addFeature("TowerLeg") self._obj.Shape = self._tube self._doc.recompute() def intersection(self, height): x = self._base.x - (height / self._tan_x) y = self._base.y - (height / self._tan_y) v = Base.Vector(x, y, height) return v def strut(self, name, tower2, radius, height, height2): v1 = self.intersection(height) v2 = tower2.intersection(height2) return self.drawNamedStrut(name, radius, v1, v2) def drawNamedStrut(self, name, radius, p1, p2): strutVector=p2.sub(p1) circle = Part.makeCircle(radius, p1, strutVector) wire=Part.Wire(circle) face=Part.Face(wire) tube = face.extrude(strutVector) towerLegObject = self.addFeature(name) towerLegObject.Shape = tube self._doc.recompute() return tube def drawStrut(self, radius, p1, p2): return self.drawNamedStrut("Strut", radius, p1, p2) def lowerStruts(self, tower2): v1 = self.intersection(LOWER_STRUT_HEIGHT) v2 = tower2.intersection(LOWER_STRUT_HEIGHT) v3 = self.intersection(LOWER_STRUT_HEIGHT - BASE_STRUT_HEIGHT) v4 = tower2.intersection(LOWER_STRUT_HEIGHT - BASE_STRUT_HEIGHT) # Determine if we are x constant or y constant if v1.x == v2.x: # x constant if v3.y > 0: self.drawNamedStrut("BaseStrut", PIPE_2_5_RADIUS, v3, Base.Vector(v1.x, BASE_STRUT_ATTACH, LOWER_STRUT_HEIGHT)) self.drawNamedStrut("BaseStrut", PIPE_2_5_RADIUS, v4, Base.Vector(v1.x, -BASE_STRUT_ATTACH, LOWER_STRUT_HEIGHT)) else: self.drawNamedStrut("BaseStrut", PIPE_2_5_RADIUS, v3, Base.Vector(v1.x, -BASE_STRUT_ATTACH, LOWER_STRUT_HEIGHT)) self.drawNamedStrut("BaseStrut", PIPE_2_5_RADIUS, v4, Base.Vector(v1.x, BASE_STRUT_ATTACH, LOWER_STRUT_HEIGHT)) else: # y constant if v3.x > 0: self.drawNamedStrut("BaseStrut", PIPE_2_5_RADIUS, v3, Base.Vector( BASE_STRUT_ATTACH, v1.y, LOWER_STRUT_HEIGHT)) self.drawNamedStrut("BaseStrut", PIPE_2_5_RADIUS, v4, Base.Vector(-BASE_STRUT_ATTACH, v1.y, LOWER_STRUT_HEIGHT)) else: self.drawNamedStrut("BaseStrut", PIPE_2_5_RADIUS, v3, Base.Vector(-BASE_STRUT_ATTACH, v1.y, LOWER_STRUT_HEIGHT)) self.drawNamedStrut("BaseStrut", PIPE_2_5_RADIUS, v4, Base.Vector( BASE_STRUT_ATTACH, v1.y, LOWER_STRUT_HEIGHT)) def tripleStrut(self, tower2, reverse): self.strut("CrossStrut", tower2, PIPE_3_5_RADIUS, LOWER_STRUT_HEIGHT, LOWER_STRUT_HEIGHT) self.strut("CrossStrut", tower2, PIPE_2_5_RADIUS, UPPER_STRUT_HEIGHT, UPPER_STRUT_HEIGHT) if reverse: self.strut("CrossStrut", tower2, PIPE_2_5_RADIUS, UPPER_STRUT_HEIGHT, LOWER_STRUT_HEIGHT) else: self.strut("CrossStrut", tower2, PIPE_2_5_RADIUS, LOWER_STRUT_HEIGHT, UPPER_STRUT_HEIGHT) self.lowerStruts(tower2) def ringStrut(self): if self._base.x < 0: x = -TORUS_RADIUS else: x = TORUS_RADIUS if self._base.y < 0: y = -TORUS_RADIUS else: y = TORUS_RADIUS v1 = self.intersection(UPPER_STRUT_HEIGHT) v2 = Base.Vector(x, 0, TORUS_HEIGHT) v3 = Base.Vector(0, y, TORUS_HEIGHT) self.drawNamedStrut("LowerRingStrut" ,PIPE_2_5_RADIUS, v1, v2) self.drawNamedStrut("LowerRingStrut" ,PIPE_2_5_RADIUS, v1, v3) self.drawNamedStrut("UpperRingStrut" ,PIPE_2_5_RADIUS, self._top, v2) self.drawNamedStrut("UpperRingStrut" ,PIPE_2_5_RADIUS, self._top, v3) def topPost(self): postTop = self._top.add(Base.Vector(0, 0, POST_HEIGHT)) self.drawNamedStrut("Post", POST_RADIUS, self._top, postTop) def ring(self): tor=Part.makeTorus(TORUS_RADIUS, PIPE_2_5_RADIUS, Base.Vector(0,0,TORUS_HEIGHT)) towerLegObject = self.addFeature("Ring") towerLegObject.Shape = tor self._doc.recompute() def fuse(self, *parts): for part in parts: self._components.extend(part._components) fuse=self._doc.addObject("Part::MultiFuse","Fusion") fuse.Shapes = [x for x in self._components] for x in self._components: Gui.activeDocument().getObject(x.Name).Visibility=False self._components = [] #self._body.addObject(self._obj) self._doc.recompute() return fuse def fuseWith(self, part): self._components.append(part) fuse=self._doc.addObject("Part::MultiFuse","Fusion") fuse.Shapes = [x for x in self._components] for x in self._components: Gui.activeDocument().getObject(x.Name).Visibility=False self._components = [] #self._body.addObject(self._obj) self._doc.recompute() return fuse def leg(x1, y1, x2, y2, z): #edge = Part.makeLine(Base.Vector(x1,y1,0), Base.Vector(x2,y2,z)) #circle = Part.makeCircle(PIPE_3_5_RADIUS, Base.Vector(x1,y1,0)) #tube = circle.extrude( Base.Vector(x2-x1,y2-y1,z)) ##Part.show(edge) #Part.show(tube) #return tube return TowerLeg(x1, y1, x2, y2, z) def tower(): App.activeDocument().Tip = App.activeDocument().addObject('App::Part','Part') App.activeDocument().Part.Label = 'Part' App.activeDocument().addObject('PartDesign::Body','Body') App.activeDocument().Part.addObject(App.ActiveDocument.Body) FreeCADGui.activeView().setActiveObject('pdbody', App.ActiveDocument.Body) App.activeDocument().recompute() body = FreeCADGui.activeView().getActiveObject("pdbody") if body == None: print("No body selected") leg1 = TowerLeg(body, TOWER_BASE_SEMI_SPAN, TOWER_BASE_SEMI_SPAN, TOWER_TOP_SEMI_SPAN, TOWER_TOP_SEMI_SPAN, TOWER_HEIGHT) leg2 = TowerLeg(body, TOWER_BASE_SEMI_SPAN, -TOWER_BASE_SEMI_SPAN, TOWER_TOP_SEMI_SPAN, -TOWER_TOP_SEMI_SPAN, TOWER_HEIGHT) leg3 = TowerLeg(body, -TOWER_BASE_SEMI_SPAN, TOWER_BASE_SEMI_SPAN, -TOWER_TOP_SEMI_SPAN, TOWER_TOP_SEMI_SPAN, TOWER_HEIGHT) leg4 = TowerLeg(body, -TOWER_BASE_SEMI_SPAN, -TOWER_BASE_SEMI_SPAN, -TOWER_TOP_SEMI_SPAN, -TOWER_TOP_SEMI_SPAN, TOWER_HEIGHT) leg1.drawLeg() leg1.tripleStrut(leg2, True) leg1.ringStrut() leg1.topPost() leg1.ring() fuse1 = leg1.fuse() #body.addObject(fuse1) App.activeDocument().recompute() leg2.drawLeg() leg2.tripleStrut(leg4, False) leg2.ringStrut() leg2.topPost() fuse2 = leg2.fuseWith(fuse1) #body.addObject(fuse2) App.activeDocument().recompute() leg4.drawLeg() leg4.tripleStrut(leg3, True) leg4.ringStrut() leg4.topPost() fuse3 = leg4.fuseWith(fuse2) #body.addObject(fuse3) App.activeDocument().recompute() leg3.drawLeg() leg3.tripleStrut(leg1, False) leg3.ringStrut() leg3.topPost() fuse4 = leg3.fuseWith(fuse3) #body.addObject(fuse4) App.activeDocument().recompute() #STEP_RADIUS = toMM(0.084) #STEP_PIPE_OUTER_RADIUS = toMM(0.082) #STEP_PIPE_HEIGHT = toMM(0.345) #STEP_WIDTH = 2 * STEP_RADIUS #STEP_HEIGHT = toMM(0.023) class TowerStep(object): def __init__(self, top, normal, angle): self._doc = FreeCAD.activeDocument() # Assumes a step in the XY plane? self._top = top self._normal = normal self._angle = angle def drawStepPlate(self): center = Base.Vector(0, -STEP_RADIUS, 0) v1 = Base.Vector( STEP_RADIUS, 0, 0) v2 = Base.Vector( STEP_RADIUS, STEP_LENGTH, 0) v3 = Base.Vector(-STEP_RADIUS, 0, 0) v4 = Base.Vector(-STEP_RADIUS, STEP_LENGTH, 0) arc1 = Part.Arc(v1,center,v3) line1 = Part.Line(v1,v2) line2 = Part.Line(v2,v4) line3 = Part.Line(v4,v3) shape = Part.Shape([arc1, line1, line2, line3]) wire = Part.Wire(shape.Edges) face=Part.Face(wire) stepPlate = face.extrude(Base.Vector(0, 0, STEP_HEIGHT)) obj = self._doc.addObject("Part::Feature","stepPlate") obj.Shape = stepPlate self._doc.recompute() self._stepPlate = stepPlate def drawPipe(self): circle = Part.makeCircle(STEP_PIPE_OUTER_RADIUS, Base.Vector(0,0,0)) wire=Part.Wire(circle) face=Part.Face(wire) pipe = face.extrude(Base.Vector(0, 0, -STEP_PIPE_HEIGHT)) obj = self._doc.addObject("Part::Feature","Pipe") obj.Shape = pipe self._doc.recompute() self._stepPipe = pipe def drawBrace(self): offset = -(STEP_HEIGHT / 2) v1 = Base.Vector( offset, STEP_PIPE_OUTER_RADIUS, 0) v2 = Base.Vector( offset, STEP_BRACE_EDGE, 0) v3 = Base.Vector( offset, STEP_PIPE_OUTER_RADIUS, -STEP_PIPE_HEIGHT) line1 = Part.Line(v1,v2) line2 = Part.Line(v2,v3) line3 = Part.Line(v3,v1) shape = Part.Shape([line1, line2, line3]) wire = Part.Wire(shape.Edges) face=Part.Face(wire) brace = face.extrude(Base.Vector(STEP_HEIGHT, 0, 0)) obj = self._doc.addObject("Part::Feature","Brace") obj.Shape = brace self._doc.recompute() self._stepBrace = brace def drawStep(self): self.drawStepPlate() self.drawPipe() self.drawBrace() fusion1 = self._stepPipe.fuse(self._stepPlate) fusion2 = fusion1.fuse(self._stepBrace) # Rotate by an angle fusion2.rotate(Base.Vector(0,0,0),Base.Vector(0,0,1),self._angle) # Move to the correct location fusion2.translate(self._top) # Realign with the noraml vector #... stepObject = self._doc.addObject("Part::Feature", "Step") stepObject.Shape = fusion2 self._doc.recompute() def step(): footing = TowerStep(Base.Vector(0,10,0), Base.Vector(0,0,1), 90) footing.drawStep() footing = TowerStep(Base.Vector(10,10,0), Base.Vector(0,0,1), 0) footing.drawStep() footing = TowerStep(Base.Vector(0,0,0), Base.Vector(0,0,1), -90) footing.drawStep() footing = TowerStep(Base.Vector(10,0,0), Base.Vector(0,0,1), 180) footing.drawStep() tower() #step() Gui.activeDocument().activeView().viewAxonometric() Gui.SendMsgToActiveView("ViewFit")