Analysis of plane frames

This is more a technical question, since I am completely unaware of the use of the FEM module, I would like to know if it is the most convenient to perform the analysis and calculation of a metal structure (portico), more specifically an industrial warehouse. Until now I was using the FTool soft, its similar? Regards
P/D: Sorry for my english.

OS: Windows 10 64-bit
Version: 0.17.13522 (Git)
Build type: Release
Branch: releases/FreeCAD-0-17
Hash: 3bb5ff4e70c0c526f2d9dd69b1004155b2f527f2
Python version: 2.7.14
Qt version: 4.8.7
Coin version: 4.0.0a
OCC version: 7.2.0

First welcome to the forum
Than what i see when i did a search. Ftool is for stuctures. Probably they make use of some sort FEM module.
In FreeCAD it is posssible to calculate with beams etc. But don’t know if it like the figures is saw on internet.

Last point Please can you remove you’re FreeCAD propeties out of you’re signature!!
FreeCAD properties are time related and when changing the signature it changes everywhere!!

concretely what I want to get are the reactions in the supports and the moments in the sections, something like this:

I think this problem should be plane truss problem.
It can find only axial force in an element and can apply the only joint load at a node.

The link below has a python code for analyzing 2D Truss by matrix analysis method for truss, that can run on FreeCAD 0.17.xxxx

I will try to assign a portico problem with that code.

the working link … https://sukhbinder.wordpress.com/2015/02/10/analysing-trusses-a-python-program/

just give it a try … https://forum.freecadweb.org/viewtopic.php?f=18&t=22383#p175602

beam analysis is supported for some cross sections. If you manually edit the input file of ccx you can use real truss elements and any cross section. Post processing for beam element could be better, but you may use para view for this. Would be cool if someone does some development in the regard of beams and trusses in FreeCAD FEM, because everything is there …

bernd

Thank you very much for the answers. @bernd, I do not understand what the thread was for.

I also search on other posts that I found interesting, and they look like what I’m looking for:

(my proyect its like this, the drawing that i post are belts that connect porticos supported in Ra)
https://forum.freecadweb.org/viewtopic.php?p=119490#p119490

(my idea its like this, clarify below)
https://forum.freecadweb.org/viewtopic.php?p=92940#p92940

I think, it would be great to be able to draw the free body diagram, and that from defining a section you can “develop” the volume of structural element. This would allow two things:

  • Simplify the modeling process


  • Perform simple calculations (such as a plane truss)

I understand that the problem would lie in the fact that the parts of a complex structure, such as a truss, dont link at one point, but at their sides/edges … so we would have to clarify which element “passes over another” .. but I think also when creating a mesh, is it from the object “as a whole” right?

Hi Hessed.
I use Ftool nearly every day, but when running your example I found out, that Ftool automatically generates
a mid-point at the diagonals. How to get rid of this behaviour? The diagonals should overlap, not
intersect. An idea to modell a plane truss problem in FC without any new programming is using a 2D-mesh
with facebinder-tool. As you can see in the Ftool-plots, the main force is the normal force in the truss-members.
Shear-force/bending moment is nearly zero (as expected).
In FC you can assign an arbitrary shell-thickness to each truss member for simulating the strain-stiffness along each truss.
I will have a closer look at this.
Thomas
Ftool.JPG
freecad_truss.JPG

Hi thomas
Im not a magician, just forgetful haha .. I dont clarify that part, constructively there are two crossed tensioners, but in reality only one works (or the other depending on the direction of the wind), in fact the “functional” scheme should look like this:

and the complete structural scheme of what I want to do is:

some measurements may be wrong in the last images, because I take them from the teacher’s model

I have no idea how to do something similar to FTool in FC, besides that I would like to do it in 3D, with the corresponding sections, with the option to modify it in a general way in all the elements (no idea if this is even possible).

Line model of the factory, made by python scripting.

Factory01.png

"""
   make Frame for factory.
   line model.
   6 june 2018 ,by c.tiya
"""


import Draft
import Part
import BOPTools.SplitFeatures
from FreeCAD import Vector



def makeFrame(ftype=1 ):
    #Group= FreeCAD.ActiveDocument.addObject("App::DocumentObjectGroup","Group")
    #BooleanFragments = BOPTools.SplitFeatures.makeBooleanFragments(name= 'Frame%d'%ftype)
    objects = []
    # C1
    H1 = 8000.0
    H2 = 4500.0
    L1 = 16800.0
    points=[FreeCAD.Vector(0,0,0),FreeCAD.Vector(0,0,H1)]
    col1 = Part.makeLine(points[0],points[1])
    objects.append(col1)
    
    points=[FreeCAD.Vector(L1,0,0),FreeCAD.Vector(L1,0,H1)]
    col3 = Part.makeLine(points[0],points[1])
    objects.append(col3)
    
    if ftype==1:
        points=[FreeCAD.Vector(L1/2.,0,0),FreeCAD.Vector(L1/2.,0,H2)]
        col2 = Part.makeLine(points[0],points[1])
        objects.append(col2)

        points=[FreeCAD.Vector(0,0,H2),FreeCAD.Vector(L1,0,H2)]
        beam1 = Part.makeLine(points[0],points[1])
        objects.append(beam1)
    
    # Truss
    hTruss = 1500.0
    # Top Chord Left
    points=[Vector(0,0,H1+hTruss),Vector(L1/2,0,H1+2300)]
    TopCL = Part.makeLine(points[0],points[1])
    objects.append(TopCL)
    # Top Chord Right
    points=[Vector(L1/2,0,H1+2300) , Vector(L1,0,H1+hTruss)]
    TopCR = Part.makeLine(points[0],points[1])
    objects.append(TopCR)
    # Bottom Chord Left
    points=[Vector(0,0,H1),Vector(L1/2,0,H1+(2300-hTruss))]
    BottomCL = Part.makeLine(points[0],points[1])
    objects.append(BottomCL)
    # Bottom Chord Right
    points=[Vector(L1/2,0,H1+(2300-hTruss)) , Vector(L1,0,H1)]
    BottomCR = Part.makeLine(points[0],points[1])
    objects.append(BottomCR)
    
    # Struct
    n = 6
    stepX = L1/2./n
    stepY = (2300.0-hTruss)/n
    #Msg('stepX=%g , stepY = %g\n'%(stepX,stepY))
    for i in range(n+1):
        x = stepX*i
        y = stepY*i
        #Msg('x=%g , y = %g\n'%(x,y))
        points=[Vector(x,0,H1+y) , Vector(x,0,H1+y+hTruss)]
        iStruct = Part.makeLine(points[0],points[1])
        objects.append(iStruct)
    for i in range(n):
        x = L1-stepX*i
        y = stepY*i
        #Msg('x=%g , y = %g\n'%(x,y))
        points=[Vector(x,0,H1+y) , Vector(x,0,H1+y+hTruss)]
        iStruct = Part.makeLine(points[0],points[1])
        objects.append(iStruct)
    # Web Left
    for i in range(n):
        x = stepX*i
        y = stepY*i
        #Msg('x=%g , y = %g\n'%(x,y))
        points=[Vector(x,0,H1+y+hTruss) , Vector(x+stepX,0,H1+y+stepY)]
        iStruct = Part.makeLine(points[0],points[1])
        objects.append(iStruct)
    # Web Right
    for i in range(n):
        x = L1-stepX*i
        y = stepY*i
        #Msg('x=%g , y = %g\n'%(x,y))
        points=[Vector(x,0,H1+y+hTruss) , Vector(x-stepX,0,H1+y+stepY)]
        iStruct = Part.makeLine(points[0],points[1])
        objects.append(iStruct)
    
    obj = FreeCAD.ActiveDocument.addObject("Part::Feature","Frame%d"%ftype)
    obj.Shape = Part.makeCompound(objects)
    return  obj


if __name__=='__main__':
    GroupFrame = makeFrame()
    FreeCAD.ActiveDocument.recompute()
    
    Frame1_2 = Draft.clone(GroupFrame)
    Frame1_2.Placement.Base.y += 5000
    
    Frame1_3 = Draft.clone(GroupFrame)
    Frame1_3.Placement.Base.y += 5000*2
    
    Frame1_4 = Draft.clone(GroupFrame)
    Frame1_4.Placement.Base.y += 5000*2+10000*2
    
    Frame1_5 = Draft.clone(GroupFrame)
    Frame1_5.Placement.Base.y += 5000*2+10000*2+5000
    
    Frame1_6 = Draft.clone(GroupFrame)
    Frame1_6.Placement.Base.y += 5000*2+10000*2+5000*2
    
    GroupFrame2 = makeFrame(ftype=2)
    GroupFrame2.Placement.Base.y += 5000*3
    FreeCAD.ActiveDocument.recompute()
    
    Frame2_2 = Draft.clone(GroupFrame2)
    Frame2_2.Placement.Base.y += 5000*1
    
    Frame2_3 = Draft.clone(GroupFrame2)
    Frame2_3.Placement.Base.y += 5000*2
    
    
    FreeCAD.ActiveDocument.recompute()
    Msg('Done!\n')
    
"""
sel = FreeCADGui.Selection.getSelection()[0]
"""

makeFrameTruss.py (3.88 KB)
TestFactory01.FCStd (20.7 KB)

I do not understand much about how you did it, but this is great, exactly that is what I was aiming for.
Are these elements one-dimensional or three-dimensional? Can I apply charges and get the reactions and stresses in bars?
Above I shared a link from a post where you show this that I’m wanting to do:

Diverging a bit from the question, but building a complete 3D structure out of a wire model like chakkree’s above might be pretty easy with flamingo…

This means that those entities (of the factory) are one-dimensional, lines, no volumes … what you call cables right?

Sorry about the name of the topic, is that at that time I was not sure what it was called what I really wanted to ask, because although the structure is three-dimensional, the analysis of the forces is done in a plane, different for each part (as portico, truss, belts, etc) Should I change it?

As for what you say about Flamingo, that will serve for what I stated above:

I think, it would be great to be able to draw the free body diagram, and that from defining a section you can “develop” the volume of structural element.

I use python script to show node and node number.

Factory01_with_node_number.png

"""
   make Frame for factory.
   line model.
   7 june 2018 ,by c.tiya 
     - Draw Truss node and number
   6 june 2018 ,by c.tiya
"""


import Draft
import Part
from FreeCAD import Vector



def makeFrame(ftype=1 ):
    #Group= FreeCAD.ActiveDocument.addObject("App::DocumentObjectGroup","Group")
    #BooleanFragments = BOPTools.SplitFeatures.makeBooleanFragments(name= 'Frame%d'%ftype)
    objects = []
    # C1
    H1 = 8000.0
    H2 = 4500.0
    L1 = 16800.0
    points=[FreeCAD.Vector(0,0,0),FreeCAD.Vector(0,0,H1)]
    col1 = Part.makeLine(points[0],points[1])
    objects.append(col1)
    
    points=[FreeCAD.Vector(L1,0,0),FreeCAD.Vector(L1,0,H1)]
    col3 = Part.makeLine(points[0],points[1])
    objects.append(col3)
    
    if ftype==1:
        points=[FreeCAD.Vector(L1/2.,0,0),FreeCAD.Vector(L1/2.,0,H2)]
        col2 = Part.makeLine(points[0],points[1])
        objects.append(col2)

        points=[FreeCAD.Vector(0,0,H2),FreeCAD.Vector(L1,0,H2)]
        beam1 = Part.makeLine(points[0],points[1])
        objects.append(beam1)
    
    # Truss
    hTruss = 1500.0
    # Top Chord Left
    points=[Vector(0,0,H1+hTruss),Vector(L1/2,0,H1+2300)]
    TopCL = Part.makeLine(points[0],points[1])
    objects.append(TopCL)
    # Top Chord Right
    points=[Vector(L1/2,0,H1+2300) , Vector(L1,0,H1+hTruss)]
    TopCR = Part.makeLine(points[0],points[1])
    objects.append(TopCR)
    # Bottom Chord Left
    points=[Vector(0,0,H1),Vector(L1/2,0,H1+(2300-hTruss))]
    BottomCL = Part.makeLine(points[0],points[1])
    objects.append(BottomCL)
    # Bottom Chord Right
    points=[Vector(L1/2,0,H1+(2300-hTruss)) , Vector(L1,0,H1)]
    BottomCR = Part.makeLine(points[0],points[1])
    objects.append(BottomCR)
    
    # Struct
    n = 6
    stepX = L1/2./n
    stepY = (2300.0-hTruss)/n
    #Msg('stepX=%g , stepY = %g\n'%(stepX,stepY))
    for i in range(n+1):
        x = stepX*i
        y = stepY*i
        #Msg('x=%g , y = %g\n'%(x,y))
        points=[Vector(x,0,H1+y) , Vector(x,0,H1+y+hTruss)]
        iStruct = Part.makeLine(points[0],points[1])
        objects.append(iStruct)
    for i in range(n):
        x = L1-stepX*i
        y = stepY*i
        #Msg('x=%g , y = %g\n'%(x,y))
        points=[Vector(x,0,H1+y) , Vector(x,0,H1+y+hTruss)]
        iStruct = Part.makeLine(points[0],points[1])
        objects.append(iStruct)
    # Web Left
    for i in range(n):
        x = stepX*i
        y = stepY*i
        #Msg('x=%g , y = %g\n'%(x,y))
        points=[Vector(x,0,H1+y+hTruss) , Vector(x+stepX,0,H1+y+stepY)]
        iStruct = Part.makeLine(points[0],points[1])
        objects.append(iStruct)
    # Web Right
    for i in range(n):
        x = L1-stepX*i
        y = stepY*i
        #Msg('x=%g , y = %g\n'%(x,y))
        points=[Vector(x,0,H1+y+hTruss) , Vector(x-stepX,0,H1+y+stepY)]
        iStruct = Part.makeLine(points[0],points[1])
        objects.append(iStruct)
    
    obj = FreeCAD.ActiveDocument.addObject("Part::Feature","Frame%d"%ftype)
    obj.Shape = Part.makeCompound(objects)
    return  obj


def makeTrussData():
    H1 = 2300.
    Depth = 1500.
    L = 16800.
    n = 12
    dataNodes = []

    stepX = L/n
    stepY = (H1-Depth)/(n/2)
    for i in range(n/2+1):
        x = stepX*i
        y = stepY*i
        dataNodes.append([x,y])
    for i in range(n/2):
        x = L-stepX*i
        y = stepY*i
        dataNodes.append([x,y])
    for i in range(n/2+1):
        x = stepX*i
        y = stepY*i+Depth
        dataNodes.append([x,y])
    for i in range(n/2):
        x = L-stepX*i
        y = stepY*i+Depth
        dataNodes.append([x,y])

    
    Msg(dataNodes); Msg('\n')
    return dataNodes

def DrawTruss(nodes , showNodeNumber = True ):
    font_path = 'your_font_path'
    font_name = 'your_font_name.ttf'
    objects = []
    i = 0
    for iNode in nodes:
        x = iNode[0]; y = iNode[1]
        #point = Draft.makePoint(x,0,y)
        #point.ViewObject.PointColor = (0.000,0.667,0.000)
        #point =Part.Point( Vector(x,0,y) )
        point = Part.makeSphere(30,Vector(x,0,y) )
        objects.append(point)
        if showNodeNumber:
            text = Part.makeWireString('%d'%i , font_path, font_name , 100)
            for char in text:
                CharFaces = []
                for CWire in char:
                    CWire.translate(Vector(x,0,y))                
                    #objects.append(CWire)
                    f = Part.Face(CWire)
                    if f:
                        CharFaces.append(f)
                # whitespace (ex: ' ') has no faces. This breaks OpenSCAD2Dgeom...
                if CharFaces:
                    s = Part.makeFace(char,'Part::FaceMakerSimple')
                    s.rotate(Vector(x,0,y),Vector(1,0,0),90)
                    s.translate(Vector(20,0,20))
                    objects.append(s)
        i+=1
        
    
    obj = FreeCAD.ActiveDocument.addObject("Part::Feature","Nodes")
    obj.Shape = Part.makeCompound(objects)
    #obj.ViewObject.PointSize=5.0
    #obj.ViewObject.PointColor = (0.000,0.667,0.000)
    return  obj

if __name__=='__main__':

    GroupFrame = makeFrame()
    FreeCAD.ActiveDocument.recompute()
    
    Frame1_2 = Draft.clone(GroupFrame)
    Frame1_2.Placement.Base.y += 5000
    
    Frame1_3 = Draft.clone(GroupFrame)
    Frame1_3.Placement.Base.y += 5000*2
    
    Frame1_4 = Draft.clone(GroupFrame)
    Frame1_4.Placement.Base.y += 5000*2+10000*2
    
    Frame1_5 = Draft.clone(GroupFrame)
    Frame1_5.Placement.Base.y += 5000*2+10000*2+5000
    
    Frame1_6 = Draft.clone(GroupFrame)
    Frame1_6.Placement.Base.y += 5000*2+10000*2+5000*2
    
    GroupFrame2 = makeFrame(ftype=2)
    GroupFrame2.Placement.Base.y += 5000*3
    FreeCAD.ActiveDocument.recompute()
    
    Frame2_2 = Draft.clone(GroupFrame2)
    Frame2_2.Placement.Base.y += 5000*1
    
    Frame2_3 = Draft.clone(GroupFrame2)
    Frame2_3.Placement.Base.y += 5000*2

    
    nodes = makeTrussData()
    truss = DrawTruss(nodes )
    truss.Placement.Base.y += 5000
    truss.Placement.Base.z += 8000
    
    FreeCAD.ActiveDocument.recompute()
    Msg('Done!\n')
    
"""
sel = FreeCADGui.Selection.getSelection()[0]
"""

makeFrameTruss2.py (6.02 KB)

frame-fem.FCStd (54 KB)

OS: Windows 10
Word size of OS: 64-bit
Word size of FreeCAD: 64-bit
Version: 0.18.13617 (Git)
Build type: Release
Branch: master
Hash: 5941a32f715b5d0e47c2e38763e521d4307385a2
Python version: 2.7.14
Qt version: 4.8.7
Coin version: 4.0.0a
OCC version: 7.2.0
Locale: German/Switzerland (de_CH)


pic.jpg

Thank you very much for your contributions, I really love this more and more.
@chakkree : As for the scrip, I still do not find the way, im trying copying the text and it does not work, neither downloading the file that you attached and dragging it to the Py console. I get this error:

… Msg(dataNodes); Msg(‘\n’)
File “”, line 2
Msg(dataNodes); Msg(‘\n’)
^
IndentationError: unexpected indent

@bernd : Regarding this, I am studying your file to see if I can decipher how you did it, it does not seem complicated at all, but to me is requiring reverse engineering to understand it haha. with what tools did you draw it?

Last : (again, i dont know if this its the right place to this but since we are..) i try Flamingo as Yorik told me, and apparently it is not possible to insert PNC in adjacent lines that share direction, in the following image it is seen how I had to stretch the upper cord to be able to join it to the right side cord (and the same should be done with the columns, which only extend to the truss, and not even the support on the ground itself) you think that this can affect how the structure is considered during the calculation ? Excuse me for asking something that is surely silly, but I still dont understand very well how it works.

I used one of chakkree frames, extracted the edges and used Part → BooleanFragments to put them together. All the rest ist normal FEM in FreeCAD …

Bernd

@Bernd Wow! :astonished:
I’m very interest in this.
I will try to analyze like this with FEM WB.
Thank you very much.

2DTruss_in_Space.png

some interesting link in this regard 3126

Analyze truss and show internal force.
by sukhbinder procedure.

Factory01_with_internal_force.png

"""
   make Frame for factory.
   line model.

   9 june 2018 ,by c.tiya
     - Analysis truss , and draw member force + displacement shape.
   7 june 2018 ,by c.tiya 
     - Draw Truss node and number
   6 june 2018 ,by c.tiya
"""

import Arch
import Draft
import Part
from FreeCAD import Vector
from math import radians

import numpy as np


def makeGrids():
    gridX = [0,16800/2,16800/2]
    gridY = [0,5000,5000,5000,5000,5000,5000,5000,5000]
    GridX = Arch.makeAxis()
    GridX.Distances = gridX
    GridX.Angles = [0,0,0]
    GridX.Length = sum(gridY) +2000*2
    GridX.Placement.Base.y -= 2000
    GridX.ViewObject.NumberingStyle = "A,B,C"
    
    GridY = Arch.makeAxis()
    GridY.Distances = gridY
    GridY.Angles = [0,0,0,0,0,0,0,0,0]
    GridY.Placement.Rotation.Angle = radians(90)
    GridY.Length = sum(gridX) +2000*2
    GridY.Placement.Base.x += sum(gridX)+2000
    


def makeFrame(ftype=1 ):
    #Group= FreeCAD.ActiveDocument.addObject("App::DocumentObjectGroup","Group")
    #BooleanFragments = BOPTools.SplitFeatures.makeBooleanFragments(name= 'Frame%d'%ftype)
    objects = []
    # C1
    H1 = 8000.0
    H2 = 4500.0
    L1 = 16800.0
    points=[FreeCAD.Vector(0,0,0),FreeCAD.Vector(0,0,H1)]
    col1 = Part.makeLine(points[0],points[1])
    objects.append(col1)
    
    points=[FreeCAD.Vector(L1,0,0),FreeCAD.Vector(L1,0,H1)]
    col3 = Part.makeLine(points[0],points[1])
    objects.append(col3)
    
    if ftype==1:
        points=[FreeCAD.Vector(L1/2.,0,0),FreeCAD.Vector(L1/2.,0,H2)]
        col2 = Part.makeLine(points[0],points[1])
        objects.append(col2)

        points=[FreeCAD.Vector(0,0,H2),FreeCAD.Vector(L1,0,H2)]
        beam1 = Part.makeLine(points[0],points[1])
        objects.append(beam1)
    
    # Truss
    hTruss = 1500.0
    # Top Chord Left
    points=[Vector(0,0,H1+hTruss),Vector(L1/2,0,H1+2300)]
    TopCL = Part.makeLine(points[0],points[1])
    objects.append(TopCL)
    # Top Chord Right
    points=[Vector(L1/2,0,H1+2300) , Vector(L1,0,H1+hTruss)]
    TopCR = Part.makeLine(points[0],points[1])
    objects.append(TopCR)
    # Bottom Chord Left
    points=[Vector(0,0,H1),Vector(L1/2,0,H1+(2300-hTruss))]
    BottomCL = Part.makeLine(points[0],points[1])
    objects.append(BottomCL)
    # Bottom Chord Right
    points=[Vector(L1/2,0,H1+(2300-hTruss)) , Vector(L1,0,H1)]
    BottomCR = Part.makeLine(points[0],points[1])
    objects.append(BottomCR)
    
    # Struct
    n = 6
    stepX = L1/2./n
    stepY = (2300.0-hTruss)/n
    #Msg('stepX=%g , stepY = %g\n'%(stepX,stepY))
    for i in range(n+1):
        x = stepX*i
        y = stepY*i
        #Msg('x=%g , y = %g\n'%(x,y))
        points=[Vector(x,0,H1+y) , Vector(x,0,H1+y+hTruss)]
        iStruct = Part.makeLine(points[0],points[1])
        objects.append(iStruct)
    for i in range(n):
        x = L1-stepX*i
        y = stepY*i
        #Msg('x=%g , y = %g\n'%(x,y))
        points=[Vector(x,0,H1+y) , Vector(x,0,H1+y+hTruss)]
        iStruct = Part.makeLine(points[0],points[1])
        objects.append(iStruct)
    # Web Left
    for i in range(n):
        x = stepX*i
        y = stepY*i
        #Msg('x=%g , y = %g\n'%(x,y))
        points=[Vector(x,0,H1+y+hTruss) , Vector(x+stepX,0,H1+y+stepY)]
        iStruct = Part.makeLine(points[0],points[1])
        objects.append(iStruct)
    # Web Right
    for i in range(n):
        x = L1-stepX*i
        y = stepY*i
        #Msg('x=%g , y = %g\n'%(x,y))
        points=[Vector(x,0,H1+y+hTruss) , Vector(x-stepX,0,H1+y+stepY)]
        iStruct = Part.makeLine(points[0],points[1])
        objects.append(iStruct)
    
    obj = FreeCAD.ActiveDocument.addObject("Part::Feature","Frame%d"%ftype)
    obj.Shape = Part.makeCompound(objects)
    return  obj


def makeTrussData():
    H1 = 2300.
    Depth = 1500.
    L = 16800.
    n = 12

    # Gen. Nodes
    dataNodes = []
    stepX = L/n
    stepY = (H1-Depth)/(n/2)
    for i in range(n/2+1):
        x = stepX*i
        y = stepY*i
        dataNodes.append([x,y])
    for i in range(n/2):
        x = L-stepX*i
        y = stepY*i
        dataNodes.append([x,y])
    for i in range(n/2+1):
        x = stepX*i
        y = stepY*i+Depth
        dataNodes.append([x,y])
    for i in range(n/2):
        x = L-stepX*i
        y = stepY*i+Depth
        dataNodes.append([x,y])
    
    # Gen Elements
    dataElements = []
    # bottom chord    
    for i in range(n/2):
        dataElements.append([i,i+1])
    count = n/2
    for i in range(n/2-1):
        dataElements.append([count+i+1,count+i+2])
    dataElements.append([count+i+2,count])
    # top chord 
    count = n
    for i in range(n/2):
        dataElements.append([count+i+1,count+i+2])
    count = n + n/2+1
    for i in range(n/2-1):
        dataElements.append([count+i+1,count+i+2])
    dataElements.append([count+i+2,count])
    # Struct    
    for i in range(n/2+1):
        dataElements.append([i,n+i+1])
    for i in range(n/2):
        dataElements.append([n/2+i+1, n+n/2+i+2])
    # Web
    for i in range(n/2):
        dataElements.append([i+1,n+i+1])
    for i in range(n/2-1):
        dataElements.append([n/2+i+2,n+n/2+i+2])
    dataElements.append([n/2,n+n/2+i+3])
    
    Msg(dataNodes); Msg('\n\n')
    Msg(dataElements); Msg('\n')
    return dataNodes,dataElements


"""
modified from Sukhbinder Singh
https://sukhbinder.wordpress.com/2015/02/10/analysing-trusses-a-python-program/
"""
def AnalysisTruss(nodeCords , elemNodes , force , presDof):
    modE=2.1e6/10/10
    Area=500.0
    numElem=elemNodes.shape[0]
    numNodes=nodeCords.shape[0]
    
    xx=nodeCords[:,0]
    yy=nodeCords[:,1]
    
    EA=modE*Area
    tdof = 2*numNodes #total number of degrees of freedom
    disps=np.zeros((tdof,1))
    #force=np.zeros((tdof,1))
    sigma=np.zeros((numElem,1))
    stiffness=np.zeros((tdof,tdof))
    np.set_printoptions(precision=3)
    
    for e in xrange(numElem):
        indice= elemNodes[e,:]
        elemDof=np.array([indice[0]*2, indice[0]*2+1, indice[1]*2, indice[1]*2+1 ])
        xa=xx[indice[1]]-xx[indice[0]]
        ya=yy[indice[1]]-yy[indice[0]]
        len_elem=np.sqrt(xa*xa+ya*ya)
        c=xa/len_elem
        s=ya/len_elem
        k1=(EA/len_elem)* np.array([[c*c,c*s,-c*c, -c*s],
                                    [c*s,s*s,-c*s ,-s*s],
                                    [-c*c,-c*s,c*c,c*s],
                                    [-c*s,-s*s,c*s,s*s]])
        stiffness[np.ix_(elemDof,elemDof)] +=k1
    
    actDof=np.setdiff1d(np.arange(tdof),presDof)
    
    disp1=np.linalg.solve(stiffness[np.ix_(actDof,actDof)],force[np.ix_(actDof)]);
    disps[np.ix_(actDof)]=disp1
    
    # stresses at elements
    
    for e in xrange(numElem):
        indice= elemNodes[e,:]
        elemDof=np.array([indice[0]*2, indice[0]*2+1, indice[1]*2, indice[1]*2+1 ])
        xa=xx[indice[1]]-xx[indice[0]]
        ya=yy[indice[1]]-yy[indice[0]]
        len_elem=np.sqrt(xa*xa+ya*ya)
        c=xa/len_elem
        s=ya/len_elem
        sigma[e] = (modE/len_elem) * np.dot(np.array([-c,-s,c,s]),disps[np.ix_(elemDof)])
    
    react = np.dot(stiffness,disps)
    
    return disps , sigma , react

def DrawTruss(nodes , elements , disps , int_forces , 
         showNodeNumber=True , showDisplacement=False ):
    FactorDisp = 3.
    font_path = 'your_font_path'
    font_name = 'your_font_name.ttf'
    objects = []
    i = 0
    
    if showDisplacement:
        numNodes=nodeCords.shape[0]
        #for i in range(numNodes):
        #    nodes[i][0] += disps[i*2-1]*FactorDisp
        #    nodes[i][1] += disps[i*2]*FactorDisp
        
        nodes += disps.reshape((numNodes,2))*FactorDisp
    Msg('Displecment Coordinate:\n')
    Msg(nodes); Msg('\n');
    
    for iNode in nodes:
        x = iNode[0]; y = iNode[1]
        #point = Draft.makePoint(x,0,y)
        #point.ViewObject.PointColor = (0.000,0.667,0.000)
        #point =Part.Point( Vector(x,0,y) )
        point = Part.makeSphere(30,Vector(x,0,y) )
        objects.append(point)
        if showNodeNumber:
            text = Part.makeWireString('%d'%i , font_path, font_name , 100)
            for char in text:
                CharFaces = []
                for CWire in char:
                    CWire.translate(Vector(x,0,y))                
                    #objects.append(CWire)
                    f = Part.Face(CWire)
                    if f:
                        CharFaces.append(f)
                # whitespace (ex: ' ') has no faces. This breaks OpenSCAD2Dgeom...
                if CharFaces:
                    s = Part.makeFace(char,'Part::FaceMakerSimple')
                    s.rotate(Vector(x,0,y),Vector(1,0,0),90)
                    s.translate(Vector(20,0,20))
                    objects.append(s)
        i+=1
    # Draw Elements
    i = 0
    for iEle in elements:
        n1 = iEle[0]
        n2 = iEle[1]
        x1 = nodes[n1][0]
        y1 = nodes[n1][1]
        x2 = nodes[n2][0]
        y2 = nodes[n2][1]
        xMid = (x2+x1)/2.
        yMid = (y2+y1)/2.
        points=[Vector(x1,0,y1) , Vector(x2,0,y2)]
        lineElement = Part.makeLine(points[0],points[1])
        objects.append(lineElement)
        # internal Force
        text = Part.makeWireString('%.0f'%int_forces[i] , font_path, font_name , 70)
        for char in text:
            CharFaces = []
            for CWire in char:
                CWire.translate(Vector(xMid,0,yMid))                
                #objects.append(CWire)
                f = Part.Face(CWire)
                if f:
                    CharFaces.append(f)
            # whitespace (ex: ' ') has no faces. This breaks OpenSCAD2Dgeom...
            if CharFaces:
                s = Part.makeFace(char,'Part::FaceMakerSimple')
                s.rotate(Vector(xMid,0,yMid),Vector(1,0,0),90)
                #s.translate(Vector(20,0,20))
                objects.append(s)
        i+=1

    obj = FreeCAD.ActiveDocument.addObject("Part::Feature","Truss")
    obj.Shape = Part.makeCompound(objects)
    #obj.ViewObject.PointSize=5.0
    #obj.ViewObject.PointColor = (0.000,0.667,0.000)
    return  obj

if __name__=='__main__':
    #"""
    GroupFrame = makeFrame()
    FreeCAD.ActiveDocument.recompute()
    
    Frame1_2 = Draft.clone(GroupFrame)
    Frame1_2.Placement.Base.y += 5000
    
    Frame1_3 = Draft.clone(GroupFrame)
    Frame1_3.Placement.Base.y += 5000*2
    
    Frame1_4 = Draft.clone(GroupFrame)
    Frame1_4.Placement.Base.y += 5000*2+10000*2
    
    Frame1_5 = Draft.clone(GroupFrame)
    Frame1_5.Placement.Base.y += 5000*2+10000*2+5000
    
    Frame1_6 = Draft.clone(GroupFrame)
    Frame1_6.Placement.Base.y += 5000*2+10000*2+5000*2
    
    GroupFrame2 = makeFrame(ftype=2)
    GroupFrame2.Placement.Base.y += 5000*3
    FreeCAD.ActiveDocument.recompute()
    
    Frame2_2 = Draft.clone(GroupFrame2)
    Frame2_2.Placement.Base.y += 5000*1
    
    Frame2_3 = Draft.clone(GroupFrame2)
    Frame2_3.Placement.Base.y += 5000*2
    #"""
    
    nodes, elements = makeTrussData()
    nodeCords=np.array(nodes)
    elemNodes=np.array(elements)

    numNodes=nodeCords.shape[0]
    tdof = 2*numNodes #total number of degrees of freedom
    force=np.zeros((tdof,1))
    n = 12
    for i in range(n+1,(n+1)*2):
        force[2*i+1] = -1000
    Msg('Forces\n'); Msg(force); Msg('\n')
    
    presDof=np.array([0,1,(n/2+1)*2+1 ])
    Msg('presDof\n'); Msg(presDof); Msg('\n')
    
    disps, sigma, react = AnalysisTruss(nodeCords, elemNodes , force , presDof)
    Msg('disps\n'); Msg(disps); Msg('\n')
    Msg('sigma\n'); Msg(sigma); Msg('\n')
    Msg('react\n'); Msg(react); Msg('\n')
    
    
    truss = DrawTruss(nodes , elements , disps, sigma*500.0 , showDisplacement=True)
    truss.Placement.Base.y += 5000
    truss.Placement.Base.z += 8000
    truss.ViewObject.LineColor = (0.667,0.000,0.000)

    """
    truss = DrawTruss(nodes , elements , disps , showDisplacement=False)
    truss.Placement.Base.y += 5000
    truss.Placement.Base.z += 8000
    """
    
    makeGrids()
    FreeCAD.ActiveDocument.recompute()
    Msg('Done!\n')
    
"""
sel = FreeCADGui.Selection.getSelection()[0]
"""

makeFrameTruss3.py (11.8 KB)