#include "Airplane.hpp"
namespace yasim {
+// gadgets
+inline float norm(float f) { return f<1 ? 1/f : f; }
+inline float abs(float f) { return f<0 ? -f : f; }
+
Airplane::Airplane()
{
_emptyWeight = 0;
delete (GearRec*)_gears.get(i);
for(i=0; i<_surfs.size(); i++)
delete (Surface*)_surfs.get(i);
+ for(i=0; i<_contacts.size(); i++)
+ delete[] (float*)_contacts.get(i);
}
void Airplane::iterate(float dt)
{
+ // The gear might have moved. Change their aerodynamics.
+ updateGearState();
+
_model.iterate();
// FIXME: Consume fuel
// Gravity
Glue::geodUp(s->pos, out);
- Math::mul3(-9.8, out, out);
+ Math::mul3(-9.8f, out, out);
// The regular acceleration
float tmp[3];
return ((GearRec*)_gears.get(g))->gear;
}
-void Airplane::setGearState(bool down, float dt)
+void Airplane::updateGearState()
{
- int i;
- for(i=0; i<_gears.size(); i++) {
+ for(int i=0; i<_gears.size(); i++) {
GearRec* gr = (GearRec*)_gears.get(i);
- if(gr->time == 0) {
- // Non-extensible
- gr->gear->setExtension(1);
- gr->surf->setXDrag(1);
- gr->surf->setYDrag(1);
- gr->surf->setZDrag(1);
- continue;
- }
+ float ext = gr->gear->getExtension();
- float diff = dt / gr->time;
- if(!down) diff = -diff;
- float ext = gr->gear->getExtension() + diff;
- if(ext < 0) ext = 0;
- if(ext > 1) ext = 1;
-
- gr->gear->setExtension(ext);
gr->surf->setXDrag(ext);
gr->surf->setYDrag(ext);
gr->surf->setZDrag(ext);
_tailIncidence = 0;
}
+void Airplane::setElevatorControl(int control)
+{
+ _approachElevator.control = control;
+ _approachElevator.val = 0;
+ _approachControls.add(&_approachElevator);
+}
+
void Airplane::addApproachControl(int control, float val)
{
Control* c = new Control();
return _tanks.add(t);
}
-void Airplane::addGear(Gear* gear, float transitionTime)
+void Airplane::addGear(Gear* gear)
{
GearRec* g = new GearRec();
g->gear = gear;
g->surf = 0;
- g->time = transitionTime;
_gears.add(g);
}
s->pos[2] = 1;
}
+void Airplane::addContactPoint(float* pos)
+{
+ float* cp = new float[3];
+ cp[0] = pos[0];
+ cp[1] = pos[1];
+ cp[2] = pos[2];
+ _contacts.add(cp);
+}
+
float Airplane::compileWing(Wing* w)
{
+ // The tip of the wing is a contact point
+ float tip[3];
+ w->getTip(tip);
+ addContactPoint(tip);
+ if(w->isMirrored()) {
+ tip[1] *= -1;
+ addContactPoint(tip);
+ }
+
// Make sure it's initialized. The surfaces will pop out with
// total drag coefficients equal to their areas, which is what we
// want.
float Airplane::compileFuselage(Fuselage* f)
{
+ // The front and back are contact points
+ addContactPoint(f->front);
+ addContactPoint(f->back);
+
float wgt = 0;
float fwd[3];
Math::sub3(f->front, f->back, fwd);
float segWgt = len*wid/segs;
int j;
for(j=0; j<segs; j++) {
- float frac = (j+0.5) / segs;
+ float frac = (j+0.5f) / segs;
float scale = 1;
if(frac < f->mid)
Math::unit3(fwd, x);
y[0] = 0; y[1] = 1; y[2] = 0;
Math::cross3(x, y, z);
+ Math::unit3(z, z);
+ Math::cross3(z, x, y);
s->setOrientation(o);
_model.addSurface(s);
_surfs.add(s);
}
+void Airplane::compileContactPoints()
+{
+ // Figure it will compress by 20cm
+ float comp[3];
+ float DIST = 0.2f;
+ comp[0] = 0; comp[1] = 0; comp[2] = DIST;
+
+ // Give it a spring constant such that at full compression it will
+ // hold up 10 times the planes mass. That's about right. Yeah.
+ float mass = _model.getBody()->getTotalMass();
+ float spring = (1/DIST) * 9.8f * 10.0f * mass;
+ float damp = 2 * Math::sqrt(spring * mass);
+
+ int i;
+ for(i=0; i<_contacts.size(); i++) {
+ float *cp = (float*)_contacts.get(i);
+
+ Gear* g = new Gear();
+ g->setPosition(cp);
+
+ g->setCompression(comp);
+ g->setSpring(spring);
+ g->setDamping(damp);
+ g->setBrake(1);
+
+ // I made these up
+ g->setStaticFriction(0.6f);
+ g->setDynamicFriction(0.5f);
+
+ _model.addGear(g);
+ }
+}
+
void Airplane::compile()
{
double ground[3];
t->handle = body->addMass(0, t->pos);
totalFuel += t->cap;
}
- _cruiseWeight = _emptyWeight + totalFuel*0.5;
- _approachWeight = _emptyWeight + totalFuel*0.2;
+ _cruiseWeight = _emptyWeight + totalFuel*0.5f;
+ _approachWeight = _emptyWeight + totalFuel*0.2f;
body->recalc();
// Ground effect
float gepos[3];
float gespan = _wing->getGroundEffect(gepos);
- _model.setGroundEffect(gepos, gespan, .3);
+ _model.setGroundEffect(gepos, gespan, 0.3f);
solveGear();
solve();
- // Drop the gear (use a really big dt)
- setGearState(true, 1000000);
+ // Do this after solveGear, because it creates "gear" objects that
+ // we don't want to affect.
+ compileContactPoints();
}
void Airplane::solveGear()
Gear* g = gr->gear;
g->getPosition(pos);
Math::sub3(cg, pos, pos);
- gr->wgt = 1/(0.5+Math::sqrt(pos[0]*pos[0] + pos[1]*pos[1]));
+ gr->wgt = 1.0f/(0.5f+Math::sqrt(pos[0]*pos[0] + pos[1]*pos[1]));
total += gr->wgt;
}
// The force at max compression should be sufficient to stop a
// plane moving downwards at 3x the approach descent rate. Assume
// a 3 degree approach.
- float descentRate = 3*_approachSpeed/19.1;
+ float descentRate = 3.0f*_approachSpeed/19.1f;
// Spread the kinetic energy according to the gear weights. This
// will results in an equal compression fraction (not distance) of
// each gear.
- float energy = 0.5*_approachWeight*descentRate*descentRate;
+ float energy = 0.5f*_approachWeight*descentRate*descentRate;
for(i=0; i<_gears.size(); i++) {
GearRec* gr = (GearRec*)_gears.get(i);
gr->gear->setDamping(2*Math::sqrt(k*_approachWeight*gr->wgt));
// These are pretty generic
- gr->gear->setStaticFriction(0.8);
- gr->gear->setDynamicFriction(0.7);
+ gr->gear->setStaticFriction(0.8f);
+ gr->gear->setDynamicFriction(0.7f);
+ }
+}
+
+void Airplane::initEngines()
+{
+ for(int i=0; i<_thrusters.size(); i++) {
+ ThrustRec* tr = (ThrustRec*)_thrusters.get(i);
+ tr->thruster->init();
}
}
Control* c = (Control*)_cruiseControls.get(i);
_controls.setInput(c->control, c->val);
}
- _controls.applyControls();
+ _controls.applyControls(1000000); // Huge dt value
// The local wind
float wind[3];
Math::mul3(-1, _cruiseState.v, wind);
Math::vmul33(_cruiseState.orient, wind, wind);
- // Gear are up (if they're non-retractable, this is a noop)
- setGearState(false, 100000);
-
// Cruise is by convention at 50% tank capacity
setFuelFraction(0.5);
}
stabilizeThrust();
+ updateGearState();
+
// Precompute thrust in the model, and calculate aerodynamic forces
_model.getBody()->reset();
_model.initIteration();
Control* c = (Control*)_approachControls.get(i);
_controls.setInput(c->control, c->val);
}
- _controls.applyControls();
+ _controls.applyControls(1000000);
// The local wind
float wind[3];
Math::vmul33(_approachState.orient, wind, wind);
// Approach is by convention at 20% tank capacity
- setFuelFraction(0.2);
-
- // Gear are down
- setGearState(true, 100000);
+ setFuelFraction(0.2f);
// Run the thrusters until they get to a stable setting. FIXME:
// this is lots of wasted work.
}
stabilizeThrust();
+ updateGearState();
+
// Precompute thrust in the model, and calculate aerodynamic forces
_model.getBody()->reset();
_model.initIteration();
void Airplane::solve()
{
- static const float ARCMIN = 0.0002909;
+ static const float ARCMIN = 0.0002909f;
float tmp[3];
_solutionIterations = 0;
// Run an approach iteration, and do likewise
runApproach();
+ _model.getBody()->getAngularAccel(tmp);
+ float apitch0 = tmp[1];
+
_model.getBody()->getAccel(tmp);
float alift = _approachWeight * tmp[2];
float pitch1 = tmp[1];
// Now calculate:
- float awgt = 9.8 * _approachWeight;
+ float awgt = 9.8f * _approachWeight;
float dragFactor = thrust / (thrust-xforce);
float liftFactor = awgt / (awgt+alift);
return;
}
- // And apply:
+ // And the elevator control in the approach. This works just
+ // like the tail incidence computation (it's solving for the
+ // same thing -- pitching moment -- by diddling a different
+ // variable).
+ const float ELEVDIDDLE = 0.0001f;
+ _approachElevator.val += ELEVDIDDLE;
+ runApproach();
+ _approachElevator.val -= ELEVDIDDLE;
+
+ _model.getBody()->getAngularAccel(tmp);
+ float apitch1 = tmp[1];
+ float elevDelta = -apitch0 * (ELEVDIDDLE/(apitch1-apitch0));
+
+ // Now apply the values we just computed. Note that the
+ // "minor" variables are deferred until we get the lift/drag
+ // numbers in the right ballpark.
+
applyDragFactor(dragFactor);
applyLiftRatio(liftFactor);
continue;
}
- // OK, now we can adjust the minor variables
- _cruiseAoA += 0.5*aoaDelta;
- _tailIncidence += 0.5*tailDelta;
+ // OK, now we can adjust the minor variables:
+ _cruiseAoA += 0.5f*aoaDelta;
+ _tailIncidence += 0.5f*tailDelta;
+ _approachElevator.val += 0.5f*elevDelta;
- _cruiseAoA = clamp(_cruiseAoA, -.174, .174);
- _tailIncidence = clamp(_tailIncidence, -.174, .174);
-
- if(dragFactor < 1.00001 && liftFactor < 1.00001 &&
- aoaDelta < .000017 && tailDelta < .000017)
+ _cruiseAoA = clamp(_cruiseAoA, -0.174f, 0.174f);
+ _tailIncidence = clamp(_tailIncidence, -0.174f, 0.174f);
+ _approachElevator.val = clamp(_approachElevator.val, -1.f, 1.f);
+
+ if(norm(dragFactor) < 1.00001 &&
+ norm(liftFactor) < 1.00001 &&
+ abs(aoaDelta) < .000017 &&
+ abs(tailDelta) < .000017 &&
+ abs(elevDelta) < 0.00001)
{
break;
}