forked from magwas/SurfaceMesh
-
Notifications
You must be signed in to change notification settings - Fork 0
/
truss.py
156 lines (135 loc) · 5.17 KB
/
truss.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
import FreeCAD
have_sympy=False
try:
from sympy import *
except ImportError:
FreeCAD.Console.PrintMessage("truss calculation needs python-sympy")
class Beam(object):
def toMatrix(self,v):
""" converts a freecad vector to a sympy matrix """
return Matrix([[v.x],[v.y],[v.z]])
def dirVector(self,p1,p2):
""" return the direction vector (p2-p1)/|p2-p1| as a sympy matrix """
v=p2-p1
l=v.Length
return self.toMatrix(v)/l
def __init__(self,edge,truss,addpoints=True):
l=symbols("%s"%str(edge.Label),real=True, each_char=False)
self.truss=truss
self.symbol=l
self.edge=edge
p1=edge.Start
p2=edge.End
self.eq=self.dirVector(p1.Coordinates,p2.Coordinates)*l
truss.addForce(p1.Proxy,self.eq,addpoints)
truss.addForce(p2.Proxy,-self.eq,addpoints)
def reportForce(self):
if not getattr(self.edge,"Force",None):
self.edge.addProperty("App::PropertyFloat","Force","Truss")
print self.edge.Label
force=float(self.symbol.subs(self.truss.solution))
print self.edge.Label,":\t",force
self.edge.Force=force
class Joint(object):
def __init__(self,point,truss,eq):
self.truss=truss
self.point=point
self.eq=eq
tp = getattr(point,"trusspart",None)
print point.Label,tp
if tp == "supported":
self.support = Matrix([[self.eqpart("x")],[self.eqpart("y")],[self.eqpart("z")]])
self.truss.supportsyms = self.truss.supportsyms.union(self.support)
self.eq += self.support
print "supported",point.Label,self.eq
if tp == "load":
F = self.point.F
self.eq += Matrix([[F.x],[F.y],[F.z]])
def eqpart(self,axis):
return symbols("%s_%s"%(str(self.point.Label),axis),real=True, each_char=False)
def matrixToVector(self,mx):
"""It also converts from stadard FreeCAD mm to SI m"""
return FreeCAD.Base.Vector(mx[0]/1000,mx[1]/1000,mx[2]/1000)
def reportForce(self):
print self.point.Label
if getattr(self,"support",None):
if not getattr(self.point,"ForceVector",None):
self.point.addProperty("App::PropertyVector","ForceVector","Truss")
if not getattr(self.point,"Force",None):
self.point.addProperty("App::PropertyFloat","Force","Truss")
self.point.ForceVector= self.matrixToVector(self.support.subs(self.truss.solution))
self.point.Force = self.point.ForceVector.Length
class Truss(object):
"""
A Truss is represented with:
A set of beams:
The beams are edges identified as having the property of trusspart=beam
The goal is to calculate the force along the beams
Note that we assume straight beams even if the edge is not straight.
A set of joints:
The joints are the endpoints of the beams.
The supported joints are marked as trusspart=supported.
On supported joints we calculate the force on the support.
A set of loads:
The loads are points identified by the property trusspart=load
The force is given in the vector property F
"""
def __init__(self,mesh):
"""
initialise our data structures from the given mesh
"""
self.beams={}
self.joints={}
self.supportsyms=set()
for e in mesh.getEdges():
tp=getattr(e,"trusspart",None)
if tp == "beam":
b = Beam(e,self)
self.beams[str(b.symbol)]=b
def addForce(self,point,eq,addpoints=True):
if not self.joints.has_key(point.Label):
if addpoints:
self.joints[point.Label]=Joint(point,self,eq)
else:
self.joints[point.Label].eq += eq
def solve(self):
self.eqs=[]
for (k,v) in self.joints.items():
for eq in v.eq:
if eq != 0:
self.eqs.append(eq)
solution = solve(self.eqs)
#if a support component makes the truss indeterminate, we fix that component to 0
missings = set()
for k,v in solution.items():
syms = v.atoms(Symbol)
if not syms:
continue
if syms - self.supportsyms:
print syms
print self.supportsyms
raise ValueError("This truss is unsolvable")
missings = missings.union(syms)
for s in missings:
self.eqs.append(s)
self.solution = solve(self.eqs)
self.report()
def report(self):
for b in self.beams.values():
b.reportForce()
for j in self.joints.values():
j.reportForce()
def listeqs(self):
for (k,v) in self.joints.items():
print k
print "\t%s\n\t%s\n\t%s\n"%tuple(v.eq.tolist())
for (k,v) in self.solution.items():
print k,":\t",v
"""
import truss
reload(truss)
mesh=Gui.getDocument("bridge").getObject("Mesh").Proxy
t=truss.Truss(mesh)
t.solve()
t.listeqs()
"""