#include "RigidBody.hpp"
#include "Surface.hpp"
#include "Rotorpart.hpp"
-#include "Rotorblade.hpp"
#include "Thruster.hpp"
+#include "Hitch.hpp"
#include "Airplane.hpp"
namespace yasim {
_cruiseT = 0;
_cruiseSpeed = 0;
_cruiseWeight = 0;
+ _cruiseGlideAngle = 0;
_approachP = 0;
_approachT = 0;
_approachSpeed = 0;
_approachAoA = 0;
_approachWeight = 0;
+ _approachGlideAngle = 0;
_dragFactor = 1;
_liftRatio = 1;
_cruiseAoA = 0;
_tailIncidence = 0;
+
+ _failureMsg = 0;
}
Airplane::~Airplane()
delete (Tank*)_tanks.get(i);
for(i=0; i<_thrusters.size(); i++)
delete (ThrustRec*)_thrusters.get(i);
- for(i=0; i<_gears.size(); i++)
- delete (GearRec*)_gears.get(i);
+ for(i=0; i<_gears.size(); i++) {
+ GearRec* g = (GearRec*)_gears.get(i);
+ delete g->gear;
+ delete g;
+ }
for(i=0; i<_surfs.size(); i++)
delete (Surface*)_surfs.get(i);
- for(i=0; i<_contacts.size(); i++)
- delete[] (float*)_contacts.get(i);
+ for(i=0; i<_contacts.size(); i++) {
+ ContactRec* c = (ContactRec*)_contacts.get(i);
+ delete c->gear;
+ delete c;
+ }
+ for(i=0; i<_solveWeights.size(); i++)
+ delete (SolveWeight*)_solveWeights.get(i);
+ for(i=0; i<_cruiseControls.size(); i++)
+ delete (Control*)_cruiseControls.get(i);
+ for(i=0; i<_approachControls.size(); i++) {
+ Control* c = (Control*)_approachControls.get(i);
+ if(c != &_approachElevator)
+ delete c;
+ }
+ delete _wing;
+ delete _tail;
+ for(i=0; i<_vstabs.size(); i++)
+ delete (Wing*)_vstabs.get(i);
+ for(i=0; i<_weights.size(); i++)
+ delete (WeightRec*)_weights.get(i);
}
void Airplane::iterate(float dt)
// The gear might have moved. Change their aerodynamics.
updateGearState();
- _model.iterate(dt);
+ _model.iterate();
}
-void Airplane::consumeFuel(float dt)
+void Airplane::calcFuelWeights()
{
- // This is a really simple implementation that assumes all engines
- // draw equally from all tanks in proportion to the amount of fuel
- // stored there. Needs to be fixed, but that has to wait for a
- // decision as to what the property interface will look like.
- int i, outOfFuel = 0;
- float fuelFlow = 0, totalFuel = 0.00001; // <-- overflow protection
- for(i=0; i<_thrusters.size(); i++)
- fuelFlow += ((ThrustRec*)_thrusters.get(i))->thruster->getFuelFlow();
- for(i=0; i<_tanks.size(); i++)
- totalFuel += ((Tank*)_tanks.get(i))->fill;
- for(i=0; i<_tanks.size(); i++) {
- Tank* t = (Tank*)_tanks.get(i);
- t->fill -= dt * fuelFlow * (t->fill/totalFuel);
- if(t->fill <= 0) {
- t->fill = 0;
- outOfFuel = 1;
- }
- }
- if(outOfFuel)
- for(int i=0; i<_thrusters.size(); i++)
- ((ThrustRec*)_thrusters.get(i))->thruster->setFuelState(false);
-
- // Set the tank masses on the RigidBody
- for(i=0; i<_tanks.size(); i++) {
+ for(int i=0; i<_tanks.size(); i++) {
Tank* t = (Tank*)_tanks.get(i);
_model.getBody()->setMass(t->handle, t->fill);
}
return ((GearRec*)_gears.get(g))->gear;
}
+Hook* Airplane::getHook()
+{
+ return _model.getHook();
+}
+
+Launchbar* Airplane::getLaunchbar()
+{
+ return _model.getLaunchbar();
+}
+
+Rotorgear* Airplane::getRotorgear()
+{
+ return _model.getRotorgear();
+}
+
void Airplane::updateGearState()
{
for(int i=0; i<_gears.size(); i++) {
}
}
-void Airplane::setApproach(float speed, float altitude)
-{
- // The zero AoA will become a calculated stall AoA in compile()
- setApproach(speed, altitude, 0);
-}
-
-void Airplane::setApproach(float speed, float altitude, float aoa)
+void Airplane::setApproach(float speed, float altitude, float aoa, float fuel, float gla)
{
_approachSpeed = speed;
_approachP = Atmosphere::getStdPressure(altitude);
_approachT = Atmosphere::getStdTemperature(altitude);
_approachAoA = aoa;
+ _approachFuel = fuel;
+ _approachGlideAngle = gla;
}
-void Airplane::setCruise(float speed, float altitude)
+void Airplane::setCruise(float speed, float altitude, float fuel, float gla)
{
_cruiseSpeed = speed;
_cruiseP = Atmosphere::getStdPressure(altitude);
_cruiseT = Atmosphere::getStdTemperature(altitude);
_cruiseAoA = 0;
_tailIncidence = 0;
+ _cruiseFuel = fuel;
+ _cruiseGlideAngle = gla;
}
void Airplane::setElevatorControl(int control)
_cruiseControls.add(c);
}
+void Airplane::addSolutionWeight(bool approach, int idx, float wgt)
+{
+ SolveWeight* w = new SolveWeight();
+ w->approach = approach;
+ w->idx = idx;
+ w->wgt = wgt;
+ _solveWeights.add(w);
+}
+
int Airplane::numTanks()
{
return _tanks.size();
return ((Tank*)_tanks.get(tank))->fill;
}
+float Airplane::setFuel(int tank, float fuel)
+{
+ return ((Tank*)_tanks.get(tank))->fill = fuel;
+}
+
float Airplane::getFuelDensity(int tank)
{
return ((Tank*)_tanks.get(tank))->density;
_vstabs.add(vstab);
}
-void Airplane::addRotor(Rotor* rotor)
-{
- _rotors.add(rotor);
-}
-
void Airplane::addFuselage(float* front, float* back, float width,
- float taper, float mid)
+ float taper, float mid,
+ float cx, float cy, float cz, float idrag)
{
Fuselage* f = new Fuselage();
int i;
f->width = width;
f->taper = taper;
f->mid = mid;
+ f->_cx=cx;
+ f->_cy=cy;
+ f->_cz=cz;
+ f->_idrag=idrag;
_fuselages.add(f);
}
_gears.add(g);
}
+void Airplane::addHook(Hook* hook)
+{
+ _model.addHook(hook);
+}
+
+void Airplane::addHitch(Hitch* hitch)
+{
+ _model.addHitch(hitch);
+}
+
+void Airplane::addLaunchbar(Launchbar* launchbar)
+{
+ _model.addLaunchbar(launchbar);
+}
+
void Airplane::addThruster(Thruster* thruster, float mass, float* cg)
{
ThrustRec* t = new ThrustRec();
return _tailIncidence;
}
-char* Airplane::getFailureMsg()
+const char* Airplane::getFailureMsg()
{
return _failureMsg;
}
return _solutionIterations;
}
-void Airplane::setupState(float aoa, float speed, State* s)
+void Airplane::setupState(float aoa, float speed, float gla, State* s)
{
float cosAoA = Math::cos(aoa);
float sinAoA = Math::sin(aoa);
s->orient[3] = 0; s->orient[4] = 1; s->orient[5] = 0;
s->orient[6] = -sinAoA; s->orient[7] = 0; s->orient[8] = cosAoA;
- s->v[0] = speed; s->v[1] = 0; s->v[2] = 0;
+ s->v[0] = speed*Math::cos(gla); s->v[1] = -speed*Math::sin(gla); s->v[2] = 0;
int i;
for(i=0; i<3; i++)
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);
+ ContactRec* c = new ContactRec;
+ c->gear = 0;
+ c->p[0] = pos[0];
+ c->p[1] = pos[1];
+ c->p[2] = pos[2];
+ _contacts.add(c);
}
float Airplane::compileWing(Wing* w)
return wgt;
}
-float Airplane::compileRotor(Rotor* w)
+void Airplane::compileRotorgear()
{
- /* todo contact points
- // 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.
- w->compile();
- _model.addRotor(w);
-
- float wgt = 0;
- int i;
- /* Todo: add rotor to model!!!
- Todo: calc and add mass!!!
- */
- for(i=0; i<w->numRotorparts(); i++) {
- Rotorpart* s = (Rotorpart*)w->getRotorpart(i);
-
- //float td = s->getTotalDrag();
- //s->setTotalDrag(td);
-
- _model.addRotorpart(s);
-
-
- float mass = s->getWeight();
- mass = mass * Math::sqrt(mass);
- float pos[3];
- s->getPosition(pos);
- _model.getBody()->addMass(mass, pos);
- wgt += mass;
-
- }
-
- for(i=0; i<w->numRotorblades(); i++) {
- Rotorblade* s = (Rotorblade*)w->getRotorblade(i);
-
- //float td = s->getTotalDrag();
- //s->setTotalDrag(td);
-
- _model.addRotorblade(s);
-
-
- float mass = s->getWeight();
- mass = mass * Math::sqrt(mass);
- float pos[3];
- s->getPosition(pos);
- _model.getBody()->addMass(mass, pos);
- wgt += mass;
-
- }
-
- return wgt;
+ getRotorgear()->compile();
}
float Airplane::compileFuselage(Fuselage* f)
float fwd[3];
Math::sub3(f->front, f->back, fwd);
float len = Math::mag3(fwd);
+ if (len == 0) {
+ _failureMsg = "Zero length fuselage";
+ return 0;
+ }
float wid = f->width;
int segs = (int)Math::ceil(len/wid);
float segWgt = len*wid/segs;
Surface* s = new Surface();
s->setPosition(pos);
float sideDrag = len/wid;
- s->setYDrag(sideDrag);
- s->setZDrag(sideDrag);
- s->setTotalDrag(scale*segWgt);
+ s->setYDrag(sideDrag*f->_cy);
+ s->setZDrag(sideDrag*f->_cz);
+ s->setTotalDrag(scale*segWgt*f->_cx);
+ s->setInducedDrag(f->_idrag);
// FIXME: fails for fuselages aligned along the Y axis
float o[9];
int i;
for(i=0; i<_contacts.size(); i++) {
- float *cp = (float*)_contacts.get(i);
+ ContactRec* c = (ContactRec*)_contacts.get(i);
Gear* g = new Gear();
- g->setPosition(cp);
+ c->gear = g;
+ g->setPosition(c->p);
g->setCompression(comp);
g->setSpring(spring);
// I made these up
g->setStaticFriction(0.6f);
g->setDynamicFriction(0.5f);
+ g->setContactPoint(1);
_model.addGear(g);
}
void Airplane::compile()
{
- double ground[3];
- ground[0] = 0; ground[1] = 0; ground[2] = 1;
- _model.setGroundPlane(ground, -100000);
-
RigidBody* body = _model.getBody();
int firstMass = body->numMasses();
if (_tail)
aeroWgt += compileWing(_tail);
int i;
- for(i=0; i<_vstabs.size(); i++) {
+ for(i=0; i<_vstabs.size(); i++)
aeroWgt += compileWing((Wing*)_vstabs.get(i));
- }
- for(i=0; i<_rotors.size(); i++) {
- aeroWgt += compileRotor((Rotor*)_rotors.get(i));
- }
-
+
+
// The fuselage(s)
- for(i=0; i<_fuselages.size(); i++) {
+ for(i=0; i<_fuselages.size(); i++)
aeroWgt += compileFuselage((Fuselage*)_fuselages.get(i));
- }
// Count up the absolute weight we have
float nonAeroWgt = _ballast;
t->handle = body->addMass(0, t->pos);
totalFuel += t->cap;
}
- _cruiseWeight = _emptyWeight + totalFuel*0.5f;
- _approachWeight = _emptyWeight + totalFuel*0.2f;
+ _cruiseWeight = _emptyWeight + totalFuel*_cruiseFuel;
+ _approachWeight = _emptyWeight + totalFuel*_approachFuel;
body->recalc();
}
// Ground effect
- float gepos[3];
- float gespan;
- if(_wing)
- gespan = _wing->getGroundEffect(gepos);
- else
- gespan=0;
- _model.setGroundEffect(gepos, gespan, 0.15f);
+ if(_wing) {
+ float gepos[3];
+ float gespan = 0;
+ gespan = _wing->getGroundEffect(gepos);
+ _model.setGroundEffect(gepos, gespan, 0.15f);
+ }
+
+ // solve function below resets failure message
+ // so check if we have any problems and abort here
+ if (_failureMsg) return;
solveGear();
-
- solve();
+ if(_wing && _tail) solve();
+ else
+ {
+ // The rotor(s) mass:
+ compileRotorgear();
+ solveHelicopter();
+ }
// Do this after solveGear, because it creates "gear" objects that
// we don't want to affect.
g->getPosition(pos);
Math::sub3(cg, pos, pos);
gr->wgt = 1.0f/(0.5f+Math::sqrt(pos[0]*pos[0] + pos[1]*pos[1]));
- total += gr->wgt;
+ if (!g->getIgnoreWhileSolving())
+ total += gr->wgt;
}
// Renormalize so they sum to 1
float e = energy * gr->wgt;
float comp[3];
gr->gear->getCompression(comp);
- float len = Math::mag3(comp);
+ float len = Math::mag3(comp)*(1+2*gr->gear->getInitialLoad());
// Energy in a spring: e = 0.5 * k * len^2
float k = 2 * e / (len*len);
// Critically damped (too damped, too!)
gr->gear->setDamping(2*Math::sqrt(k*_approachWeight*gr->wgt)
* gr->gear->getDamping());
-
- // These are pretty generic
- gr->gear->setStaticFriction(0.8f);
- gr->gear->setDynamicFriction(0.7f);
}
}
_model.getThruster(i)->stabilize();
}
+void Airplane::setupWeights(bool isApproach)
+{
+ int i;
+ for(i=0; i<_weights.size(); i++)
+ setWeight(i, 0);
+ for(i=0; i<_solveWeights.size(); i++) {
+ SolveWeight* w = (SolveWeight*)_solveWeights.get(i);
+ if(w->approach == isApproach)
+ setWeight(w->idx, w->wgt);
+ }
+}
+
void Airplane::runCruise()
{
- setupState(_cruiseAoA, _cruiseSpeed, &_cruiseState);
+ setupState(_cruiseAoA, _cruiseSpeed,_cruiseGlideAngle, &_cruiseState);
_model.setState(&_cruiseState);
_model.setAir(_cruiseP, _cruiseT,
Atmosphere::calcStdDensity(_cruiseP, _cruiseT));
Math::mul3(-1, _cruiseState.v, wind);
Math::vmul33(_cruiseState.orient, wind, wind);
- // Cruise is by convention at 50% tank capacity
- setFuelFraction(0.5);
+ setFuelFraction(_cruiseFuel);
+ setupWeights(false);
// Set up the thruster parameters and iterate until the thrust
// stabilizes.
// Precompute thrust in the model, and calculate aerodynamic forces
_model.getBody()->recalc();
_model.getBody()->reset();
- _model.initIteration(.01);//hier parameter egal
+ _model.initIteration();
_model.calcForces(&_cruiseState);
}
void Airplane::runApproach()
{
- setupState(_approachAoA, _approachSpeed, &_approachState);
+ setupState(_approachAoA, _approachSpeed,_approachGlideAngle, &_approachState);
_model.setState(&_approachState);
_model.setAir(_approachP, _approachT,
Atmosphere::calcStdDensity(_approachP, _approachT));
Math::mul3(-1, _approachState.v, wind);
Math::vmul33(_approachState.orient, wind, wind);
- // Approach is by convention at 20% tank capacity
- setFuelFraction(0.2f);
+ setFuelFraction(_approachFuel);
+
+ setupWeights(true);
// Run the thrusters until they get to a stable setting. FIXME:
// this is lots of wasted work.
// Precompute thrust in the model, and calculate aerodynamic forces
_model.getBody()->recalc();
_model.getBody()->reset();
- _model.initIteration(.01);//hier parameter egal
+ _model.initIteration();
_model.calcForces(&_approachState);
}
float tmp[3];
_solutionIterations = 0;
_failureMsg = 0;
- if((_wing)&&(_tail))
- {
- while(1) {
-#if 0
- printf("%d %f %f %f %f %f\n", //DEBUG
- _solutionIterations,
- 1000*_dragFactor,
- _liftRatio,
- _cruiseAoA,
- _tailIncidence,
- _approachElevator.val);
-#endif
+ while(1) {
if(_solutionIterations++ > 10000) {
_failureMsg = "Solution failed to converge after 10000 iterations";
return;
runCruise();
_model.getThrust(tmp);
- float thrust = tmp[0];
+ float thrust = tmp[0] + _cruiseWeight * Math::sin(_cruiseGlideAngle) * 9.81;
_model.getBody()->getAccel(tmp);
Math::tmul33(_cruiseState.orient, tmp, tmp);
_failureMsg = "Tail incidence > 10 degrees";
return;
}
+}
+
+void Airplane::solveHelicopter()
+{
+ _solutionIterations = 0;
+ _failureMsg = 0;
+ if (getRotorgear()!=0)
+ {
+ Rotorgear* rg = getRotorgear();
+ applyDragFactor(Math::pow(rg->getYasimDragFactor()/1000,
+ 1/SOLVE_TWEAK));
+ applyLiftRatio(Math::pow(rg->getYasimLiftFactor(),
+ 1/SOLVE_TWEAK));
}
else
+ //huh, no wing and no rotor? (_rotorgear is constructed,
+ //if a rotor is defined
{
applyDragFactor(Math::pow(15.7/1000, 1/SOLVE_TWEAK));
applyLiftRatio(Math::pow(104, 1/SOLVE_TWEAK));
- setupState(0,0, &_cruiseState);
- _model.setState(&_cruiseState);
- _controls.reset();
- _model.getBody()->reset();
-
-
}
-
- return;
+ setupState(0,0,0, &_cruiseState);
+ _model.setState(&_cruiseState);
+ setupWeights(true);
+ _controls.reset();
+ _model.getBody()->reset();
+ _model.setAir(_cruiseP, _cruiseT,
+ Atmosphere::calcStdDensity(_cruiseP, _cruiseT));
+
}
+
}; // namespace yasim