1 #include <Main/fg_props.hxx>
2 #include "RigidBody.hpp"
3
4 namespace yasim {
5
RigidBody()6 RigidBody::RigidBody()
7 {
8 // Allocate space for 16 masses initially. More space will be
9 // allocated dynamically.
10 _nMasses = 0;
11 _massesAlloced = 16;
12 _masses = new Mass[_massesAlloced];
13 _gyro[0] = _gyro[1] = _gyro[2] = 0;
14 _spin[0] = _spin[1] = _spin[2] = 0;
15 _bodyN = fgGetNode("/fdm/yasim/model/masses", true);
16 }
17
~RigidBody()18 RigidBody::~RigidBody()
19 {
20 delete[] _masses;
21 }
22
23 /// add new point mass to body
24 /// isStatic: set to true for masses that do not change per iteration (everything but fuel?)
addMass(float mass,const float * pos,bool isStatic)25 int RigidBody::addMass(float mass, const float* pos, bool isStatic)
26 {
27 // If out of space, reallocate twice as much
28 if(_nMasses == _massesAlloced) {
29 _massesAlloced *= 2;
30 Mass *m2 = new Mass[_massesAlloced];
31 int i;
32 for(i=0; i<_nMasses; i++)
33 m2[i] = _masses[i];
34 delete[] _masses;
35 _masses = m2;
36 }
37 setMass(_nMasses, mass, pos, isStatic);
38 return _nMasses++;
39 }
40
41 /// change mass
42 /// handle: returned by addMass
setMass(int handle,float mass)43 void RigidBody::setMass(int handle, float mass)
44 {
45 if (_masses[handle].m == mass)
46 return;
47 _masses[handle].m = mass;
48 // if static mass is changed, reset pre-calculated mass
49 // may apply to weights like cargo, pax, that usually do not change with FDM rate
50 if (_masses[handle].isStatic)
51 _staticMass.m = 0;
52 if (_bodyN != 0)
53 _bodyN->getChild("mass", handle, true)->getNode("mass", true)->setFloatValue(mass);
54 }
55
setMass(int handle,float mass,const float * pos,bool isStatic)56 void RigidBody::setMass(int handle, float mass, const float* pos, bool isStatic)
57 {
58 _masses[handle].isStatic = isStatic;
59 Math::set3(pos, _masses[handle].p);
60 setMass(handle, mass);
61 if (_bodyN != 0) {
62 SGPropertyNode_ptr n = _bodyN->getChild("mass", handle, true);
63 n->getNode("isStatic", true)->setValue(isStatic);
64 n->getNode("pos-x", true)->setFloatValue(pos[0]);
65 n->getNode("pos-y", true)->setFloatValue(pos[1]);
66 n->getNode("pos-z", true)->setFloatValue(pos[2]);
67 }
68 }
69
getMassPosition(int handle,float * out) const70 void RigidBody::getMassPosition(int handle, float* out) const
71 {
72 Math::set3(_masses[handle].p, out);
73 }
74
75 // Calcualtes the rotational velocity of a particular point. All
76 // coordinates are local!
pointVelocity(const float * pos,const float * rot,float * out)77 void RigidBody::pointVelocity(const float* pos, const float* rot, float* out)
78 {
79 Math::sub3(pos, _cg, out); // out = pos-cg
80 Math::cross3(rot, out, out); // = rot cross (pos-cg)
81 }
82
_recalcStatic()83 void RigidBody::_recalcStatic()
84 {
85 // aggregate all masses that do not change (e.g. fuselage, wings) into one point mass
86 _staticMass.m = 0;
87 Math::zero3(_staticMass.p);
88 int i;
89 int s = 0;
90 for(i=0; i<_nMasses; i++) {
91 if (_masses[i].isStatic) {
92 s++;
93 float mass = _masses[i].m;
94 _staticMass.m += mass;
95 float momentum[3];
96 Math::mul3(mass, _masses[i].p, momentum);
97 Math::add3(momentum, _staticMass.p, _staticMass.p);
98 }
99 }
100 Math::mul3(1/_staticMass.m, _staticMass.p, _staticMass.p);
101 if (_bodyN != 0) {
102 _bodyN->getNode("aggregated-mass", true)->setFloatValue(_staticMass.m);
103 _bodyN->getNode("aggregated-count", true)->setIntValue(s);
104 _bodyN->getNode("aggregated-pos-x", true)->setFloatValue(_staticMass.p[0]);
105 _bodyN->getNode("aggregated-pos-y", true)->setFloatValue(_staticMass.p[1]);
106 _bodyN->getNode("aggregated-pos-z", true)->setFloatValue(_staticMass.p[2]);
107 }
108 // Now the inertia tensor:
109 for(i=0; i<9; i++)
110 _tI_static[i] = 0;
111
112 for(i=0; i<_nMasses; i++) {
113 if (_masses[i].isStatic) {
114 float m = _masses[i].m;
115
116 float x = _masses[i].p[0] - _staticMass.p[0];
117 float y = _masses[i].p[1] - _staticMass.p[1];
118 float z = _masses[i].p[2] - _staticMass.p[2];
119
120 float xy = m*x*y; float yz = m*y*z; float zx = m*z*x;
121 float x2 = m*x*x; float y2 = m*y*y; float z2 = m*z*z;
122
123 // tensor is symmetric, so we can save some calculations in the loop
124 _tI_static[0] += y2+z2; _tI_static[1] -= xy; _tI_static[2] -= zx;
125 _tI_static[4] += x2+z2; _tI_static[5] -= yz;
126 _tI_static[8] += x2+y2;
127 }
128 }
129 // copy symmetric elements
130 _tI_static[3] = _tI_static[1];
131 _tI_static[6] = _tI_static[2];
132 _tI_static[7] = _tI_static[5];
133 }
134
135 /// calculate the total mass, centre of gravity and inertia tensor
136 /**
137 recalc is used when compiling the model but more important it is called in
138 Model::iterate() e.g. at FDM rate (120 Hz)
139 We can save some CPU due to the symmetry of the tensor and by aggregating
140 masses that do not change during flight.
141 */
recalc()142 void RigidBody::recalc()
143 {
144 //aggregate static masses into one mass
145 if (_staticMass.m == 0) _recalcStatic();
146
147 // Calculate the c.g and total mass
148 // init with pre-calculated static mass
149 _totalMass = _staticMass.m;
150 Math::mul3(_staticMass.m, _staticMass.p, _cg);
151 int i;
152 for(i=0; i<_nMasses; i++) {
153 // only masses we did not aggregate
154 if (!_masses[i].isStatic) {
155 float mass = _masses[i].m;
156 _totalMass += mass;
157 float momentum[3];
158 Math::mul3(mass, _masses[i].p, momentum);
159 Math::add3(momentum, _cg, _cg);
160 }
161 }
162 Math::mul3(1/_totalMass, _cg, _cg);
163
164 // Now the inertia tensor:
165 for(i=0; i<9; i++)
166 _tI[i] = _tI_static[i];
167
168 for(i=0; i<_nMasses; i++) {
169 if (!_masses[i].isStatic) {
170 float m = _masses[i].m;
171
172 float x = _masses[i].p[0] - _cg[0];
173 float y = _masses[i].p[1] - _cg[1];
174 float z = _masses[i].p[2] - _cg[2];
175 float mx = m*x;
176 float my = m*y;
177 float mz = m*z;
178
179 float xy = mx*y; float yz = my*z; float zx = mz*x;
180 float x2 = mx*x; float y2 = my*y; float z2 = mz*z;
181
182 _tI[0] += y2+z2; _tI[1] -= xy; _tI[2] -= zx;
183 _tI[4] += x2+z2; _tI[5] -= yz;
184 _tI[8] += x2+y2;
185 }
186 }
187 // copy symmetric elements
188 _tI[3] = _tI[1];
189 _tI[6] = _tI[2];
190 _tI[7] = _tI[5];
191
192 //calculate inverse
193 Math::invert33_sym(_tI, _invI);
194 }
195
reset()196 void RigidBody::reset()
197 {
198 Math::zero3(_torque);
199 Math::zero3(_force);
200 }
201
addForce(const float * pos,const float * force)202 void RigidBody::addForce(const float* pos, const float* force)
203 {
204 addForce(force);
205
206 // For a force F at position X, the torque about the c.g C is:
207 // torque = F cross (C - X)
208 float v[3], t[3];
209 Math::sub3(_cg, pos, v);
210 Math::cross3(force, v, t);
211 addTorque(t);
212 }
213
getAccel(const float * pos,float * accelOut) const214 void RigidBody::getAccel(const float* pos, float* accelOut) const
215 {
216 getAccel(accelOut);
217
218 // Turn the "spin" vector into a normalized spin axis "a" and a
219 // radians/sec scalar "rate".
220 float a[3];
221 float rate = Math::mag3(_spin);
222 Math::set3(_spin, a);
223 if (rate !=0 )
224 Math::mul3(1/rate, a, a);
225 //an else branch is not neccesary. a, which is a=(0,0,0) in the else case, is only used in a dot product
226 float v[3];
227 Math::sub3(_cg, pos, v); // v = cg - pos
228 Math::mul3(Math::dot3(v, a), a, a); // a = a * (v dot a)
229 Math::add3(v, a, v); // v = v + a
230
231 // Now v contains the vector from pos to the rotation axis.
232 // Multiply by the square of the rotation rate to get the linear
233 // acceleration.
234 Math::mul3(rate*rate, v, v);
235 Math::add3(v, accelOut, accelOut);
236 }
237
getAngularAccel(float * accelOut) const238 void RigidBody::getAngularAccel(float* accelOut) const
239 {
240 // Compute "tau" as the externally applied torque, plus the
241 // counter-torque due to the internal gyro.
242 float tau[3]; // torque
243 Math::cross3(_gyro, _spin, tau);
244 Math::add3(_torque, tau, tau);
245
246 // Now work the equation of motion. Use "v" as a notational
247 // shorthand, as the value isn't an acceleration until the end.
248 float *v = accelOut;
249 Math::vmul33(_tI, _spin, v); // v = I*omega
250 Math::cross3(_spin, v, v); // v = omega X I*omega
251 Math::add3(tau, v, v); // v = tau + (omega X I*omega)
252 Math::vmul33(_invI, v, v); // v = invI*(tau + (omega X I*omega))
253 }
254
getInertiaMatrix(float * inertiaOut) const255 void RigidBody::getInertiaMatrix(float* inertiaOut) const
256 {
257 // valid only after a call to RigidBody::recalc()
258 // See comment at top of RigidBody.hpp on units.
259 for(int i=0;i<9;i++)
260 {
261 inertiaOut[i] = _tI[i];
262 }
263 }
264
265 }; // namespace yasim
266