1
0
Fork 0

Merge branch 'next' of gitorious.org:fg/flightgear into next

This commit is contained in:
Torsten Dreyer 2011-10-03 22:29:48 +02:00
commit 5f2fff4ec4
34 changed files with 2448 additions and 1350 deletions

View file

@ -393,6 +393,14 @@
RelativePath="..\..\..\src\Aircraft\replay.hxx" RelativePath="..\..\..\src\Aircraft\replay.hxx"
> >
</File> </File>
<File
RelativePath="..\..\..\src\Aircraft\flightrecorder.cxx"
>
</File>
<File
RelativePath="..\..\..\src\Aircraft\flightrecorder.hxx"
>
</File>
</Filter> </Filter>
<Filter <Filter
Name="Lib_Airports" Name="Lib_Airports"

View file

@ -773,10 +773,10 @@ bool FGAIAircraft::leadPointReached(FGAIWaypoint* curr) {
} }
if (trafficRef) { if (trafficRef) {
//cerr << "Tracking callsign : \"" << fgGetString("/ai/track-callsign") << "\"" << endl; //cerr << "Tracking callsign : \"" << fgGetString("/ai/track-callsign") << "\"" << endl;
/* if (trafficRef->getCallSign() == fgGetString("/ai/track-callsign")) { if (trafficRef->getCallSign() == fgGetString("/ai/track-callsign")) {
cerr << trafficRef->getCallSign() << " " << tgt_altitude_ft << " " << _getSpeed() << " " cerr << trafficRef->getCallSign() << " " << tgt_altitude_ft << " " << _getSpeed() << " "
<< _getAltitude() << " "<< _getLatitude() << " " << _getLongitude() << " " << dist_to_go << " " << lead_dist << " " << curr->name << " " << vs << " " << tgt_vs << " " << bearing << " " << minBearing << " " << speedFraction << endl; << _getAltitude() << " "<< _getLatitude() << " " << _getLongitude() << " " << dist_to_go << " " << lead_dist << " " << curr->getName() << " " << vs << " " << tgt_vs << " " << bearing << " " << minBearing << " " << speedFraction << " " << invisible << endl;
}*/ }
} }
if ((dist_to_go < lead_dist) || (bearing > (minBearing * 1.1))) { if ((dist_to_go < lead_dist) || (bearing > (minBearing * 1.1))) {
minBearing = 360; minBearing = 360;
@ -1223,20 +1223,20 @@ bool FGAIAircraft::reachedEndOfCruise(double &distance) {
double distanceCovered = descentSpeed * descentTimeNeeded; double distanceCovered = descentSpeed * descentTimeNeeded;
//cerr << "Tracking : " << fgGetString("/ai/track-callsign"); //cerr << "Tracking : " << fgGetString("/ai/track-callsign");
if (trafficRef->getCallSign() == fgGetString("/ai/track-callsign")) { // if (trafficRef->getCallSign() == fgGetString("/ai/track-callsign")) {
cerr << "Checking for end of cruise stage for :" << trafficRef->getCallSign() << endl; // cerr << "Checking for end of cruise stage for :" << trafficRef->getCallSign() << endl;
cerr << "Descent rate : " << descentRate << endl; // cerr << "Descent rate : " << descentRate << endl;
cerr << "Descent speed : " << descentSpeed << endl; // cerr << "Descent speed : " << descentSpeed << endl;
cerr << "VerticalDistance : " << verticalDistance << ". Altitude : " << altitude_ft << ". Elevation " << trafficRef->getArrivalAirport()->getElevation() << endl; // cerr << "VerticalDistance : " << verticalDistance << ". Altitude : " << altitude_ft << ". Elevation " << trafficRef->getArrivalAirport()->getElevation() << endl;
cerr << "DecentTimeNeeded : " << descentTimeNeeded << endl; // cerr << "DecentTimeNeeded : " << descentTimeNeeded << endl;
cerr << "DistanceCovered : " << distanceCovered << endl; // cerr << "DistanceCovered : " << distanceCovered << endl;
} // }
//cerr << "Distance = " << distance << endl; //cerr << "Distance = " << distance << endl;
distance = distanceCovered; distance = distanceCovered;
if (dist < distanceCovered) { if (dist < distanceCovered) {
if (trafficRef->getCallSign() == fgGetString("/ai/track-callsign")) { // if (trafficRef->getCallSign() == fgGetString("/ai/track-callsign")) {
//exit(1); // //exit(1);
} // }
return true; return true;
} else { } else {
return false; return false;
@ -1290,8 +1290,8 @@ time_t FGAIAircraft::checkForArrivalTime(string wptName) {
time_t ete = tracklength / ((speed * SG_NM_TO_METER) / 3600.0); time_t ete = tracklength / ((speed * SG_NM_TO_METER) / 3600.0);
time_t secondsToGo = arrivalTime - now; time_t secondsToGo = arrivalTime - now;
if (trafficRef->getCallSign() == fgGetString("/ai/track-callsign")) { // if (trafficRef->getCallSign() == fgGetString("/ai/track-callsign")) {
cerr << "Checking arrival time: ete " << ete << ". Time to go : " << secondsToGo << ". Track length = " << tracklength << endl; // cerr << "Checking arrival time: ete " << ete << ". Time to go : " << secondsToGo << ". Track length = " << tracklength << endl;
} // }
return (ete - secondsToGo); // Positive when we're too slow... return (ete - secondsToGo); // Positive when we're too slow...
} }

View file

@ -179,6 +179,27 @@ void FGAIBase::update(double dt) {
ft_per_deg_lon = 365228.16 * cos(pos.getLatitudeRad()); ft_per_deg_lon = 365228.16 * cos(pos.getLatitudeRad());
} }
/** update LOD properties of the model */
void FGAIBase::updateLOD()
{
double maxRangeDetail = fgGetDouble("/sim/rendering/static-lod/ai-detailed", 10000.0);
double maxRangeBare = fgGetDouble("/sim/rendering/static-lod/ai-bare", 20000.0);
if (_model.valid())
{
if( maxRangeDetail == 0.0 )
{
// disable LOD
_model->setRange(0, 0.0, FLT_MAX);
_model->setRange(1, FLT_MAX, FLT_MAX);
}
else
{
_model->setRange(0, 0.0, maxRangeDetail);
_model->setRange(1, maxRangeDetail,maxRangeBare);
}
}
}
void FGAIBase::Transform() { void FGAIBase::Transform() {
if (!invisible) { if (!invisible) {
@ -226,23 +247,22 @@ bool FGAIBase::init(bool search_in_AI_path) {
_installed = true; _installed = true;
osg::Node * mdl = SGModelLib::loadPagedModel(f, props, new FGNasalModelData(props)); osg::Node * mdl = SGModelLib::loadPagedModel(f, props, new FGNasalModelData(props));
model = mdl;
double aiModelMaxRange = fgGetDouble("/sim/rendering/static-lod/ai", 0.0); _model = new osg::LOD;
if( aiModelMaxRange > 0.0 ) { _model->setName("AI-model range animation node");
osg::LOD * lod = new osg::LOD;
lod->setName("AI-model range animation node");
lod->addChild( mdl, 0, aiModelMaxRange ); _model->addChild( mdl, 0, FLT_MAX );
lod->setCenterMode(osg::LOD::USE_BOUNDING_SPHERE_CENTER); _model->setCenterMode(osg::LOD::USE_BOUNDING_SPHERE_CENTER);
lod->setRangeMode(osg::LOD::DISTANCE_FROM_EYE_POINT); _model->setRangeMode(osg::LOD::DISTANCE_FROM_EYE_POINT);
// We really need low-resolution versions of AI/MP aircraft.
model = lod; // Or at least dummy "stubs" with some default silhouette.
} // _model->addChild( SGModelLib::loadPagedModel(fgGetString("/sim/multiplay/default-model", default_model),
// props, new FGNasalModelData(props)), FLT_MAX, FLT_MAX);
updateLOD();
initModel(mdl); initModel(mdl);
if (model.valid() && _initialized == false) { if (_model.valid() && _initialized == false) {
aip.init( model.get() ); aip.init( _model.get() );
aip.setVisible(true); aip.setVisible(true);
invisible = false; invisible = false;
globals->get_scenery()->get_scene_graph()->addChild(aip.getSceneGraph()); globals->get_scenery()->get_scene_graph()->addChild(aip.getSceneGraph());
@ -260,7 +280,7 @@ bool FGAIBase::init(bool search_in_AI_path) {
void FGAIBase::initModel(osg::Node *node) void FGAIBase::initModel(osg::Node *node)
{ {
if (model.valid()) { if (_model.valid()) {
if( _path != ""){ if( _path != ""){
props->setStringValue("submodels/path", _path.c_str()); props->setStringValue("submodels/path", _path.c_str());
@ -523,7 +543,7 @@ SGVec3d FGAIBase::getCartPos() const {
bool FGAIBase::getGroundElevationM(const SGGeod& pos, double& elev, bool FGAIBase::getGroundElevationM(const SGGeod& pos, double& elev,
const SGMaterial** material) const { const SGMaterial** material) const {
return globals->get_scenery()->get_elevation_m(pos, elev, material, return globals->get_scenery()->get_elevation_m(pos, elev, material,
model.get()); _model.get());
} }
double FGAIBase::_getCartPosX() const { double FGAIBase::_getCartPosX() const {

View file

@ -64,6 +64,7 @@ public:
virtual void unbind(); virtual void unbind();
virtual void reinit() {} virtual void reinit() {}
void updateLOD();
void setManager(FGAIManager* mgr, SGPropertyNode* p); void setManager(FGAIManager* mgr, SGPropertyNode* p);
void setPath( const char* model ); void setPath( const char* model );
void setSMPath( const string& p ); void setSMPath( const string& p );
@ -186,7 +187,6 @@ protected:
double ht_diff; // value used by radar display instrument double ht_diff; // value used by radar display instrument
string model_path; //Path to the 3D model string model_path; //Path to the 3D model
osg::ref_ptr<osg::Node> model; //The 3D model object
SGModelPlacement aip; SGModelPlacement aip;
bool delete_me; bool delete_me;
@ -222,6 +222,7 @@ private:
int _refID; int _refID;
object_type _otype; object_type _otype;
bool _initialized; bool _initialized;
osg::ref_ptr<osg::LOD> _model; //The 3D model LOD object
public: public:
object_type getType(); object_type getType();

View file

@ -62,6 +62,11 @@ bool FGAIFlightPlan::create(FGAIAircraft * ac, FGAirport * dep,
case 1: case 1:
retVal = createPushBack(ac, firstFlight, dep, latitude, longitude, retVal = createPushBack(ac, firstFlight, dep, latitude, longitude,
radius, fltType, aircraftType, airline); radius, fltType, aircraftType, airline);
// Pregenerate the
if (retVal) {
waypoints.back()->setName( waypoints.back()->getName() + string("legend"));
retVal = createTakeoffTaxi(ac, false, dep, radius, fltType, aircraftType, airline);
}
break; break;
case 2: case 2:
retVal = createTakeoffTaxi(ac, firstFlight, dep, radius, fltType, retVal = createTakeoffTaxi(ac, firstFlight, dep, radius, fltType,

View file

@ -43,7 +43,12 @@
#include "AIGroundVehicle.hxx" #include "AIGroundVehicle.hxx"
#include "AIEscort.hxx" #include "AIEscort.hxx"
FGAIManager::FGAIManager() { FGAIManager::FGAIManager() :
cb_ai_bare(SGPropertyChangeCallback<FGAIManager>(this,&FGAIManager::updateLOD,
fgGetNode("/sim/rendering/static-lod/ai-bare", true))),
cb_ai_detailed(SGPropertyChangeCallback<FGAIManager>(this,&FGAIManager::updateLOD,
fgGetNode("/sim/rendering/static-lod/ai-detailed", true)))
{
_dt = 0.0; _dt = 0.0;
mNumAiModels = 0; mNumAiModels = 0;
@ -181,6 +186,18 @@ FGAIManager::update(double dt) {
thermal_lift_node->setDoubleValue( strength ); // for thermals thermal_lift_node->setDoubleValue( strength ); // for thermals
} }
/** update LOD settings of all AI/MP models */
void
FGAIManager::updateLOD(SGPropertyNode* node)
{
ai_list_iterator ai_list_itr = ai_list.begin();
while(ai_list_itr != ai_list.end())
{
(*ai_list_itr)->updateLOD();
++ai_list_itr;
}
}
void void
FGAIManager::attach(FGAIBase *model) FGAIManager::attach(FGAIBase *model)
{ {

View file

@ -27,6 +27,7 @@
#include <simgear/structure/subsystem_mgr.hxx> #include <simgear/structure/subsystem_mgr.hxx>
#include <simgear/structure/SGSharedPtr.hxx> #include <simgear/structure/SGSharedPtr.hxx>
#include <simgear/props/props_io.hxx>
#include <Main/fg_props.hxx> #include <Main/fg_props.hxx>
@ -66,6 +67,7 @@ public:
void bind(); void bind();
void unbind(); void unbind();
void update(double dt); void update(double dt);
void updateLOD(SGPropertyNode* node);
void attach(FGAIBase *model); void attach(FGAIBase *model);
void destroyObject( int ID ); void destroyObject( int ID );
@ -135,6 +137,8 @@ private:
double strength; double strength;
void processThermal( FGAIThermal* thermal ); void processThermal( FGAIThermal* thermal );
SGPropertyChangeCallback<FGAIManager> cb_ai_bare;
SGPropertyChangeCallback<FGAIManager> cb_ai_detailed;
}; };
#endif // _FG_AIMANAGER_HXX #endif // _FG_AIMANAGER_HXX

View file

@ -109,7 +109,7 @@ void FGATCManager::init() {
if (park_index < 0) { if (park_index < 0) {
SG_LOG( SG_GENERAL, SG_ALERT, SG_LOG( SG_GENERAL, SG_ALERT,
"Failed to find parking position " << parking << "Failed to find parking position " << parking <<
" at airport " << airport << "at " << SG_ORIGIN); " at airport " << airport << " at " << SG_ORIGIN);
} }
if (parking.empty() || (park_index < 0)) { if (parking.empty() || (park_index < 0)) {
controller = apt->getDynamics()->getTowerController(); controller = apt->getDynamics()->getTowerController();
@ -247,5 +247,7 @@ void FGATCManager::update ( double time ) {
//cerr << "Adding groundnetWork to the scenegraph::update" << endl; //cerr << "Adding groundnetWork to the scenegraph::update" << endl;
prevController = controller; prevController = controller;
} }
//globals->get_scenery()->get_scene_graph()->addChild(node); for (AtcVecIterator atc = activeStations.begin(); atc != activeStations.end(); atc++) {
(*atc)->update(time);
}
} }

View file

@ -65,7 +65,7 @@ time_t ActiveRunway::requestTimeSlot(time_t eta)
TimeVectorIterator i = estimatedArrivalTimes.begin(); TimeVectorIterator i = estimatedArrivalTimes.begin();
//cerr << "Checking eta slots " << eta << ": " << endl; //cerr << "Checking eta slots " << eta << ": " << endl;
for (i = estimatedArrivalTimes.begin(); for (i = estimatedArrivalTimes.begin();
i != estimatedArrivalTimes.end(); i++) { i != estimatedArrivalTimes.end(); i++) {
//cerr << "Stored time : " << (*i) << endl; //cerr << "Stored time : " << (*i) << endl;
} }
i = estimatedArrivalTimes.begin(); i = estimatedArrivalTimes.begin();
@ -144,18 +144,20 @@ time_t ActiveRunway::requestTimeSlot(time_t eta)
* FGTrafficRecord * FGTrafficRecord
**************************************************************************/ **************************************************************************/
FGTrafficRecord::FGTrafficRecord(): FGTrafficRecord::FGTrafficRecord():
id(0), waitsForId(0), id(0), waitsForId(0),
currentPos(0), currentPos(0),
leg(0), leg(0),
frequencyId(0), frequencyId(0),
state(0), state(0),
allowTransmission(true), allowTransmission(true),
latitude(0), longitude(0), heading(0), speed(0), altitude(0), radius(0) allowPushback(true),
priority(0),
latitude(0), longitude(0), heading(0), speed(0), altitude(0), radius(0)
{ {
} }
void FGTrafficRecord::setPositionAndIntentions(int pos, void FGTrafficRecord::setPositionAndIntentions(int pos,
FGAIFlightPlan * route) FGAIFlightPlan * route)
{ {
currentPos = pos; currentPos = pos;
@ -166,7 +168,7 @@ void FGTrafficRecord::setPositionAndIntentions(int pos,
"Error in FGTrafficRecord::setPositionAndIntentions"); "Error in FGTrafficRecord::setPositionAndIntentions");
//cerr << "Pos : " << pos << " Curr " << *(intentions.begin()) << endl; //cerr << "Pos : " << pos << " Curr " << *(intentions.begin()) << endl;
for (intVecIterator i = intentions.begin(); for (intVecIterator i = intentions.begin();
i != intentions.end(); i++) { i != intentions.end(); i++) {
//cerr << (*i) << " "; //cerr << (*i) << " ";
} }
//cerr << endl; //cerr << endl;
@ -237,8 +239,8 @@ bool FGTrafficRecord::checkPositionAndIntentions(FGTrafficRecord & other)
} }
void FGTrafficRecord::setPositionAndHeading(double lat, double lon, void FGTrafficRecord::setPositionAndHeading(double lat, double lon,
double hdg, double spd, double hdg, double spd,
double alt) double alt)
{ {
latitude = lat; latitude = lat;
longitude = lon; longitude = lon;
@ -251,7 +253,7 @@ int FGTrafficRecord::crosses(FGGroundNetwork * net,
FGTrafficRecord & other) FGTrafficRecord & other)
{ {
if (checkPositionAndIntentions(other) if (checkPositionAndIntentions(other)
|| (other.checkPositionAndIntentions(*this))) || (other.checkPositionAndIntentions(*this)))
return -1; return -1;
intVecIterator i, j; intVecIterator i, j;
int currentTargetNode = 0, otherTargetNode = 0; int currentTargetNode = 0, otherTargetNode = 0;
@ -265,7 +267,7 @@ int FGTrafficRecord::crosses(FGGroundNetwork * net,
for (i = intentions.begin(); i != intentions.end(); i++) { for (i = intentions.begin(); i != intentions.end(); i++) {
if ((*i) > 0) { if ((*i) > 0) {
if ((currentTargetNode == if ((currentTargetNode ==
net->findSegment(*i)->getEnd()->getIndex())) { net->findSegment(*i)->getEnd()->getIndex())) {
//cerr << "Current crosses at " << currentTargetNode <<endl; //cerr << "Current crosses at " << currentTargetNode <<endl;
return currentTargetNode; return currentTargetNode;
} }
@ -274,10 +276,10 @@ int FGTrafficRecord::crosses(FGGroundNetwork * net,
} }
if (other.intentions.size()) { if (other.intentions.size()) {
for (i = other.intentions.begin(); i != other.intentions.end(); for (i = other.intentions.begin(); i != other.intentions.end();
i++) { i++) {
if ((*i) > 0) { if ((*i) > 0) {
if (otherTargetNode == if (otherTargetNode ==
net->findSegment(*i)->getEnd()->getIndex()) { net->findSegment(*i)->getEnd()->getIndex()) {
//cerr << "Other crosses at " << currentTargetNode <<endl; //cerr << "Other crosses at " << currentTargetNode <<endl;
return otherTargetNode; return otherTargetNode;
} }
@ -287,7 +289,7 @@ int FGTrafficRecord::crosses(FGGroundNetwork * net,
if (intentions.size() && other.intentions.size()) { if (intentions.size() && other.intentions.size()) {
for (i = intentions.begin(); i != intentions.end(); i++) { for (i = intentions.begin(); i != intentions.end(); i++) {
for (j = other.intentions.begin(); j != other.intentions.end(); for (j = other.intentions.begin(); j != other.intentions.end();
j++) { j++) {
//cerr << "finding segment " << *i << " and " << *j << endl; //cerr << "finding segment " << *i << " and " << *j << endl;
if (((*i) > 0) && ((*j) > 0)) { if (((*i) > 0) && ((*j) > 0)) {
currentTargetNode = currentTargetNode =
@ -318,7 +320,7 @@ bool FGTrafficRecord::onRoute(FGGroundNetwork * net,
return true; return true;
if (other.intentions.size()) { if (other.intentions.size()) {
for (intVecIterator i = other.intentions.begin(); for (intVecIterator i = other.intentions.begin();
i != other.intentions.end(); i++) { i != other.intentions.end(); i++) {
if (*i > 0) { if (*i > 0) {
othernode = net->findSegment(*i)->getEnd()->getIndex(); othernode = net->findSegment(*i)->getEnd()->getIndex();
if ((node == othernode) && (node > -1)) if ((node == othernode) && (node > -1))
@ -358,13 +360,13 @@ bool FGTrafficRecord::isOpposing(FGGroundNetwork * net,
} }
for (intVecIterator i = intentions.begin(); i != intentions.end(); for (intVecIterator i = intentions.begin(); i != intentions.end();
i++) { i++) {
if ((opp = net->findSegment(other.currentPos)->opposite())) { if ((opp = net->findSegment(other.currentPos)->opposite())) {
if ((*i) > 0) if ((*i) > 0)
if (opp->getIndex() == if (opp->getIndex() ==
net->findSegment(*i)->getIndex()) { net->findSegment(*i)->getIndex()) {
if (net->findSegment(*i)->getStart()->getIndex() == if (net->findSegment(*i)->getStart()->getIndex() ==
node) { node) {
{ {
//cerr << "Found the node " << node << endl; //cerr << "Found the node " << node << endl;
return true; return true;
@ -374,17 +376,17 @@ bool FGTrafficRecord::isOpposing(FGGroundNetwork * net,
} }
if (other.intentions.size()) { if (other.intentions.size()) {
for (intVecIterator j = other.intentions.begin(); for (intVecIterator j = other.intentions.begin();
j != other.intentions.end(); j++) { j != other.intentions.end(); j++) {
// cerr << "Current segment 1 " << (*i) << endl; // cerr << "Current segment 1 " << (*i) << endl;
if ((*i) > 0) { if ((*i) > 0) {
if ((opp = net->findSegment(*i)->opposite())) { if ((opp = net->findSegment(*i)->opposite())) {
if (opp->getIndex() == if (opp->getIndex() ==
net->findSegment(*j)->getIndex()) { net->findSegment(*j)->getIndex()) {
//cerr << "Nodes " << net->findSegment(*i)->getIndex() //cerr << "Nodes " << net->findSegment(*i)->getIndex()
// << " and " << net->findSegment(*j)->getIndex() // << " and " << net->findSegment(*j)->getIndex()
// << " are opposites " << endl; // << " are opposites " << endl;
if (net->findSegment(*i)->getStart()-> if (net->findSegment(*i)->getStart()->
getIndex() == node) { getIndex() == node) {
{ {
//cerr << "Found the node " << node << endl; //cerr << "Found the node " << node << endl;
return true; return true;
@ -400,6 +402,14 @@ bool FGTrafficRecord::isOpposing(FGGroundNetwork * net,
return false; return false;
} }
bool FGTrafficRecord::isActive(int margin)
{
time_t now = time(NULL) + fgGetLong("/sim/time/warp");
time_t deptime = aircraft->getTrafficRef()->getDepartureTime();
return ((now + margin) > deptime);
}
void FGTrafficRecord::setSpeedAdjustment(double spd) void FGTrafficRecord::setSpeedAdjustment(double spd)
{ {
instruction.setChangeSpeed(true); instruction.setChangeSpeed(true);
@ -414,31 +424,12 @@ void FGTrafficRecord::setHeadingAdjustment(double heading)
bool FGTrafficRecord::pushBackAllowed() bool FGTrafficRecord::pushBackAllowed()
{ {
// With the user ATC / AI integration, checking whether the user's aircraft is near no longer works, because return allowPushback;
// this will effectively block the user's aircraft itself from receiving pushback clearance.
// So, what can we do?
/*
double course, az2, dist;
SGGeod curr(SGGeod::fromDegM(getLongitude(),
getLatitude(), getAltitude()));
double userLatitude = fgGetDouble("/position/latitude-deg");
double userLongitude = fgGetDouble("/position/longitude-deg");
SGGeod user(SGGeod::fromDeg(userLongitude, userLatitude));
SGGeodesy::inverse(curr, user, course, az2, dist);
//cerr << "Distance to user : " << dist << endl;
return (dist > 250);
*/
// In essence, we should check whether the pusbback route itself, as well as the associcated
// taxiways near the pushback point are free of traffic.
// To do so, we need to
return true;
} }
/*************************************************************************** /***************************************************************************
* FGATCInstruction * FGATCInstruction
* *
@ -483,7 +474,7 @@ FGATCController::FGATCController()
FGATCController::~FGATCController() FGATCController::~FGATCController()
{ {
//cerr << "running FGATController destructor" << endl; //cerr << "running FGATController destructor" << endl;
} }
string FGATCController::getGateName(FGAIAircraft * ref) string FGATCController::getGateName(FGAIAircraft * ref)
@ -585,11 +576,11 @@ void FGATCController::transmit(FGTrafficRecord * rec, AtcMsgId msgId,
getRunwayClassFromTrafficType(fltType); getRunwayClassFromTrafficType(fltType);
rec->getAircraft()->getTrafficRef()->getDepartureAirport()-> rec->getAircraft()->getTrafficRef()->getDepartureAirport()->
getDynamics()->getActiveRunway(rwyClass, 1, activeRunway, getDynamics()->getActiveRunway(rwyClass, 1, activeRunway,
heading); heading);
rec->getAircraft()->GetFlightPlan()->setRunway(activeRunway); rec->getAircraft()->GetFlightPlan()->setRunway(activeRunway);
fp = rec->getAircraft()->getTrafficRef()->getDepartureAirport()-> fp = rec->getAircraft()->getTrafficRef()->getDepartureAirport()->
getDynamics()->getSID(activeRunway, heading); getDynamics()->getSID(activeRunway, heading);
rec->getAircraft()->GetFlightPlan()->setSID(fp); rec->getAircraft()->GetFlightPlan()->setSID(fp);
if (fp) { if (fp) {
SID = fp->getName() + " departure"; SID = fp->getName() + " departure";
@ -682,16 +673,16 @@ void FGATCController::transmit(FGTrafficRecord * rec, AtcMsgId msgId,
activeRunway = rec->getAircraft()->GetFlightPlan()->getRunway(); activeRunway = rec->getAircraft()->GetFlightPlan()->getRunway();
//activeRunway = "test"; //activeRunway = "test";
text = receiver + ". Holding short runway " text = receiver + ". Holding short runway "
+ activeRunway + activeRunway
+ ". " + sender; + ". " + sender;
//text = "test1"; //text = "test1";
//cerr << "1 Currently at leg " << rec->getLeg() << endl; //cerr << "1 Currently at leg " << rec->getLeg() << endl;
break; break;
case MSG_ACKNOWLEDGE_REPORT_RUNWAY_HOLD_SHORT: case MSG_ACKNOWLEDGE_REPORT_RUNWAY_HOLD_SHORT:
activeRunway = rec->getAircraft()->GetFlightPlan()->getRunway(); activeRunway = rec->getAircraft()->GetFlightPlan()->getRunway();
text = receiver + "Roger. Holding short runway " text = receiver + "Roger. Holding short runway "
// + activeRunway // + activeRunway
+ ". " + sender; + ". " + sender;
//text = "test2"; //text = "test2";
//cerr << "2 Currently at leg " << rec->getLeg() << endl; //cerr << "2 Currently at leg " << rec->getLeg() << endl;
break; break;
@ -725,7 +716,7 @@ void FGATCController::transmit(FGTrafficRecord * rec, AtcMsgId msgId,
// the relevant frequency. // the relevant frequency.
// Note that distance attenuation is currently not yet implemented // Note that distance attenuation is currently not yet implemented
if ((onBoardRadioFreqI0 == stationFreq) if ((onBoardRadioFreqI0 == stationFreq)
|| (onBoardRadioFreqI1 == stationFreq)) { || (onBoardRadioFreqI1 == stationFreq)) {
if (rec->allowTransmissions()) { if (rec->allowTransmissions()) {
fgSetString("/sim/messages/atc", text.c_str()); fgSetString("/sim/messages/atc", text.c_str());
} }
@ -758,10 +749,10 @@ string FGATCController::genTransponderCode(string fltRules)
void FGATCController::init() void FGATCController::init()
{ {
if (!initialized) { if (!initialized) {
FGATCManager *mgr = (FGATCManager*) globals->get_subsystem("ATC"); FGATCManager *mgr = (FGATCManager*) globals->get_subsystem("ATC");
mgr->addController(this); mgr->addController(this);
initialized = true; initialized = true;
} }
} }
@ -770,19 +761,19 @@ void FGATCController::init()
* *
**************************************************************************/ **************************************************************************/
FGTowerController::FGTowerController(FGAirportDynamics *par) : FGTowerController::FGTowerController(FGAirportDynamics *par) :
FGATCController() FGATCController()
{ {
parent = par; parent = par;
} }
// //
void FGTowerController::announcePosition(int id, void FGTowerController::announcePosition(int id,
FGAIFlightPlan * intendedRoute, FGAIFlightPlan * intendedRoute,
int currentPosition, double lat, int currentPosition, double lat,
double lon, double heading, double lon, double heading,
double speed, double alt, double speed, double alt,
double radius, int leg, double radius, int leg,
FGAIAircraft * ref) FGAIAircraft * ref)
{ {
init(); init();
TrafficVectorIterator i = activeTraffic.begin(); TrafficVectorIterator i = activeTraffic.begin();
@ -835,8 +826,8 @@ void FGTowerController::announcePosition(int id,
} }
void FGTowerController::updateAircraftInformation(int id, double lat, double lon, void FGTowerController::updateAircraftInformation(int id, double lat, double lon,
double heading, double speed, double alt, double heading, double speed, double alt,
double dt) double dt)
{ {
TrafficVectorIterator i = activeTraffic.begin(); TrafficVectorIterator i = activeTraffic.begin();
// Search whether the current id has an entry // Search whether the current id has an entry
@ -899,6 +890,8 @@ void FGTowerController::updateAircraftInformation(int id, double lat, double lon
rwy->setCleared(id); rwy->setCleared(id);
} }
} }
} else {
} }
} }
@ -1006,6 +999,11 @@ string FGTowerController::getName() {
return string(parent->getId() + "-tower"); return string(parent->getId() + "-tower");
} }
void FGTowerController::update(double dt)
{
}
/*************************************************************************** /***************************************************************************
@ -1013,18 +1011,18 @@ string FGTowerController::getName() {
* *
**************************************************************************/ **************************************************************************/
FGStartupController::FGStartupController(FGAirportDynamics *par): FGStartupController::FGStartupController(FGAirportDynamics *par):
FGATCController() FGATCController()
{ {
parent = par; parent = par;
} }
void FGStartupController::announcePosition(int id, void FGStartupController::announcePosition(int id,
FGAIFlightPlan * intendedRoute, FGAIFlightPlan * intendedRoute,
int currentPosition, double lat, int currentPosition, double lat,
double lon, double heading, double lon, double heading,
double speed, double alt, double speed, double alt,
double radius, int leg, double radius, int leg,
FGAIAircraft * ref) FGAIAircraft * ref)
{ {
init(); init();
TrafficVectorIterator i = activeTraffic.begin(); TrafficVectorIterator i = activeTraffic.begin();
@ -1136,7 +1134,7 @@ void FGStartupController::signOff(int id)
} }
bool FGStartupController::checkTransmissionState(int st, time_t now, time_t startTime, TrafficVectorIterator i, AtcMsgId msgId, bool FGStartupController::checkTransmissionState(int st, time_t now, time_t startTime, TrafficVectorIterator i, AtcMsgId msgId,
AtcMsgDir msgDir) AtcMsgDir msgDir)
{ {
int state = i->getState(); int state = i->getState();
if ((state == st) && available) { if ((state == st) && available) {
@ -1147,9 +1145,9 @@ bool FGStartupController::checkTransmissionState(int st, time_t now, time_t star
int n = trans_num->getIntValue(); int n = trans_num->getIntValue();
if (n == 0) { if (n == 0) {
trans_num->setIntValue(-1); trans_num->setIntValue(-1);
// PopupCallback(n); // PopupCallback(n);
//cerr << "Selected transmission message " << n << endl; //cerr << "Selected transmission message " << n << endl;
FGATCDialogNew::instance()->removeEntry(1); FGATCDialogNew::instance()->removeEntry(1);
} else { } else {
//cerr << "creading message for " << i->getAircraft()->getCallSign() << endl; //cerr << "creading message for " << i->getAircraft()->getCallSign() << endl;
transmit(&(*i), msgId, msgDir, false); transmit(&(*i), msgId, msgDir, false);
@ -1169,8 +1167,8 @@ bool FGStartupController::checkTransmissionState(int st, time_t now, time_t star
} }
void FGStartupController::updateAircraftInformation(int id, double lat, double lon, void FGStartupController::updateAircraftInformation(int id, double lat, double lon,
double heading, double speed, double alt, double heading, double speed, double alt,
double dt) double dt)
{ {
TrafficVectorIterator i = activeTraffic.begin(); TrafficVectorIterator i = activeTraffic.begin();
// Search search if the current id has an entry // Search search if the current id has an entry
@ -1269,10 +1267,10 @@ void FGStartupController::render(bool visible)
//while (group->getNumChildren()) { //while (group->getNumChildren()) {
// cerr << "Number of children: " << group->getNumChildren() << endl; // cerr << "Number of children: " << group->getNumChildren() << endl;
//simgear::EffectGeode* geode = (simgear::EffectGeode*) group->getChild(0); //simgear::EffectGeode* geode = (simgear::EffectGeode*) group->getChild(0);
//osg::MatrixTransform *obj_trans = (osg::MatrixTransform*) group->getChild(0); //osg::MatrixTransform *obj_trans = (osg::MatrixTransform*) group->getChild(0);
//geode->releaseGLObjects(); //geode->releaseGLObjects();
//group->removeChild(geode); //group->removeChild(geode);
//delete geode; //delete geode;
group = 0; group = 0;
} }
if (visible) { if (visible) {
@ -1285,108 +1283,39 @@ void FGStartupController::render(bool visible)
//for ( FGTaxiSegmentVectorIterator i = segments.begin(); i != segments.end(); i++) { //for ( FGTaxiSegmentVectorIterator i = segments.begin(); i != segments.end(); i++) {
double dx = 0; double dx = 0;
for (TrafficVectorIterator i = activeTraffic.begin(); i != activeTraffic.end(); i++) { for (TrafficVectorIterator i = activeTraffic.begin(); i != activeTraffic.end(); i++) {
// Handle start point if (i->isActive(300)) {
int pos = i->getCurrentPosition(); // Handle start point
//cerr << "rendering for " << i->getAircraft()->getCallSign() << "pos = " << pos << endl; int pos = i->getCurrentPosition();
if (pos > 0) { //cerr << "rendering for " << i->getAircraft()->getCallSign() << "pos = " << pos << endl;
FGTaxiSegment *segment = parent->getGroundNetwork()->findSegment(pos); if (pos > 0) {
SGGeod start(SGGeod::fromDeg((i->getLongitude()), (i->getLatitude()))); FGTaxiSegment *segment = parent->getGroundNetwork()->findSegment(pos);
SGGeod end (SGGeod::fromDeg(segment->getEnd()->getLongitude(), segment->getEnd()->getLatitude())); SGGeod start(SGGeod::fromDeg((i->getLongitude()), (i->getLatitude())));
SGGeod end (SGGeod::fromDeg(segment->getEnd()->getLongitude(), segment->getEnd()->getLatitude()));
double length = SGGeodesy::distanceM(start, end); double length = SGGeodesy::distanceM(start, end);
//heading = SGGeodesy::headingDeg(start->getGeod(), end->getGeod()); //heading = SGGeodesy::headingDeg(start->getGeod(), end->getGeod());
double az2, heading; //, distanceM; double az2, heading; //, distanceM;
SGGeodesy::inverse(start, end, heading, az2, length); SGGeodesy::inverse(start, end, heading, az2, length);
double coveredDistance = length * 0.5; double coveredDistance = length * 0.5;
SGGeod center; SGGeod center;
SGGeodesy::direct(start, heading, coveredDistance, center, az2); SGGeodesy::direct(start, heading, coveredDistance, center, az2);
//cerr << "Active Aircraft : Centerpoint = (" << center.getLatitudeDeg() << ", " << center.getLongitudeDeg() << "). Heading = " << heading << endl; //cerr << "Active Aircraft : Centerpoint = (" << center.getLatitudeDeg() << ", " << center.getLongitudeDeg() << "). Heading = " << heading << endl;
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// Make a helper function out of this // Make a helper function out of this
osg::Matrix obj_pos; osg::Matrix obj_pos;
osg::MatrixTransform *obj_trans = new osg::MatrixTransform;
obj_trans->setDataVariance(osg::Object::STATIC);
// Experimental: Calculate slope here, based on length, and the individual elevations
double elevationStart;
if (isUserAircraft((i)->getAircraft())) {
elevationStart = fgGetDouble("/position/ground-elev-m");
} else {
elevationStart = ((i)->getAircraft()->_getAltitude());
}
double elevationEnd = segment->getEnd()->getElevation();
if ((elevationEnd == 0) || (elevationEnd == parent->getElevation())) {
SGGeod center2 = end;
center2.setElevationM(SG_MAX_ELEVATION_M);
if (local_scenery->get_elevation_m( center2, elevationEnd, NULL )) {
elevation_feet = elevationEnd * SG_METER_TO_FEET + 0.5;
//elevation_meters += 0.5;
}
else {
elevationEnd = parent->getElevation();
}
segment->getEnd()->setElevation(elevationEnd);
}
double elevationMean = (elevationStart + elevationEnd) / 2.0;
double elevDiff = elevationEnd - elevationStart;
double slope = atan2(elevDiff, length) * SGD_RADIANS_TO_DEGREES;
//cerr << "1. Using mean elevation : " << elevationMean << " and " << slope << endl;
WorldCoordinate( obj_pos, center.getLatitudeDeg(), center.getLongitudeDeg(), elevationMean + 0.5, -(heading), slope );
;
obj_trans->setMatrix( obj_pos );
//osg::Vec3 center(0, 0, 0)
float width = length /2.0;
osg::Vec3 corner(-width, 0, 0.25f);
osg::Vec3 widthVec(2*width + 1, 0, 0);
osg::Vec3 heightVec(0, 1, 0);
osg::Geometry* geometry;
geometry = osg::createTexturedQuadGeometry(corner, widthVec, heightVec);
simgear::EffectGeode* geode = new simgear::EffectGeode;
geode->setName("test");
geode->addDrawable(geometry);
//osg::Node *custom_obj;
SGMaterial *mat = matlib->find("UnidirectionalTaper");
if (mat)
geode->setEffect(mat->get_effect());
obj_trans->addChild(geode);
// wire as much of the scene graph together as we can
//->addChild( obj_trans );
group->addChild( obj_trans );
/////////////////////////////////////////////////////////////////////
} else {
//cerr << "BIG FAT WARNING: current position is here : " << pos << endl;
}
for(intVecIterator j = (i)->getIntentions().begin(); j != (i)->getIntentions().end(); j++) {
osg::Matrix obj_pos;
int k = (*j);
if (k > 0) {
//cerr << "rendering for " << i->getAircraft()->getCallSign() << "intention = " << k << endl;
osg::MatrixTransform *obj_trans = new osg::MatrixTransform; osg::MatrixTransform *obj_trans = new osg::MatrixTransform;
obj_trans->setDataVariance(osg::Object::STATIC); obj_trans->setDataVariance(osg::Object::STATIC);
FGTaxiSegment *segment = parent->getGroundNetwork()->findSegment(k); // Experimental: Calculate slope here, based on length, and the individual elevations
double elevationStart;
double elevationStart = segment->getStart()->getElevation(); if (isUserAircraft((i)->getAircraft())) {
double elevationEnd = segment->getEnd ()->getElevation(); elevationStart = fgGetDouble("/position/ground-elev-m");
if ((elevationStart == 0) || (elevationStart == parent->getElevation())) { } else {
SGGeod center2 = segment->getStart()->getGeod(); elevationStart = ((i)->getAircraft()->_getAltitude() * SG_FEET_TO_METER);
center2.setElevationM(SG_MAX_ELEVATION_M);
if (local_scenery->get_elevation_m( center2, elevationStart, NULL )) {
elevation_feet = elevationStart * SG_METER_TO_FEET + 0.5;
//elevation_meters += 0.5;
}
else {
elevationStart = parent->getElevation();
}
segment->getStart()->setElevation(elevationStart);
} }
double elevationEnd = segment->getEnd()->getElevation();
if ((elevationEnd == 0) || (elevationEnd == parent->getElevation())) { if ((elevationEnd == 0) || (elevationEnd == parent->getElevation())) {
SGGeod center2 = segment->getEnd()->getGeod(); SGGeod center2 = end;
center2.setElevationM(SG_MAX_ELEVATION_M); center2.setElevationM(SG_MAX_ELEVATION_M);
if (local_scenery->get_elevation_m( center2, elevationEnd, NULL )) { if (local_scenery->get_elevation_m( center2, elevationEnd, NULL )) {
elevation_feet = elevationEnd * SG_METER_TO_FEET + 0.5; elevation_feet = elevationEnd * SG_METER_TO_FEET + 0.5;
@ -1400,20 +1329,18 @@ void FGStartupController::render(bool visible)
double elevationMean = (elevationStart + elevationEnd) / 2.0; double elevationMean = (elevationStart + elevationEnd) / 2.0;
double elevDiff = elevationEnd - elevationStart; double elevDiff = elevationEnd - elevationStart;
double length = segment->getLength();
double slope = atan2(elevDiff, length) * SGD_RADIANS_TO_DEGREES; double slope = atan2(elevDiff, length) * SGD_RADIANS_TO_DEGREES;
//cerr << "2. Using mean elevation : " << elevationMean << " and " << slope << endl; //cerr << "1. Using mean elevation : " << elevationMean << " and " << slope << endl;
WorldCoordinate( obj_pos, center.getLatitudeDeg(), center.getLongitudeDeg(), elevationMean + 0.5 + dx, -(heading), slope );
WorldCoordinate( obj_pos, segment->getLatitude(), segment->getLongitude(), elevationMean + 0.5, -(segment->getHeading()), slope ); ;
//WorldCoordinate( obj_pos, segment->getLatitude(), segment->getLongitude(), parent->getElevation()+8+dx, -(segment->getHeading()) );
obj_trans->setMatrix( obj_pos ); obj_trans->setMatrix( obj_pos );
//osg::Vec3 center(0, 0, 0) //osg::Vec3 center(0, 0, 0)
float width = segment->getLength() /2.0; float width = length /2.0;
osg::Vec3 corner(-width, 0, 0.25f); osg::Vec3 corner(-width, 0, 0.25f);
osg::Vec3 widthVec(2*width + 1, 0, 0); osg::Vec3 widthVec(2*width + 1, 0, 0);
osg::Vec3 heightVec(0, 1, 0); osg::Vec3 heightVec(0, 1, 0);
@ -1423,18 +1350,101 @@ void FGStartupController::render(bool visible)
geode->setName("test"); geode->setName("test");
geode->addDrawable(geometry); geode->addDrawable(geometry);
//osg::Node *custom_obj; //osg::Node *custom_obj;
SGMaterial *mat = matlib->find("UnidirectionalTaper"); SGMaterial *mat;
if (segment->hasBlock()) {
mat = matlib->find("UnidirectionalTaperRed");
} else {
mat = matlib->find("UnidirectionalTaperGreen");
}
if (mat) if (mat)
geode->setEffect(mat->get_effect()); geode->setEffect(mat->get_effect());
obj_trans->addChild(geode); obj_trans->addChild(geode);
// wire as much of the scene graph together as we can // wire as much of the scene graph together as we can
//->addChild( obj_trans ); //->addChild( obj_trans );
group->addChild( obj_trans ); group->addChild( obj_trans );
/////////////////////////////////////////////////////////////////////
} else { } else {
//cerr << "BIG FAT WARNING: k is here : " << pos << endl; //cerr << "BIG FAT WARNING: current position is here : " << pos << endl;
} }
for (intVecIterator j = (i)->getIntentions().begin(); j != (i)->getIntentions().end(); j++) {
osg::Matrix obj_pos;
int k = (*j);
if (k > 0) {
//cerr << "rendering for " << i->getAircraft()->getCallSign() << "intention = " << k << endl;
osg::MatrixTransform *obj_trans = new osg::MatrixTransform;
obj_trans->setDataVariance(osg::Object::STATIC);
FGTaxiSegment *segment = parent->getGroundNetwork()->findSegment(k);
double elevationStart = segment->getStart()->getElevation();
double elevationEnd = segment->getEnd ()->getElevation();
if ((elevationStart == 0) || (elevationStart == parent->getElevation())) {
SGGeod center2 = segment->getStart()->getGeod();
center2.setElevationM(SG_MAX_ELEVATION_M);
if (local_scenery->get_elevation_m( center2, elevationStart, NULL )) {
elevation_feet = elevationStart * SG_METER_TO_FEET + 0.5;
//elevation_meters += 0.5;
}
else {
elevationStart = parent->getElevation();
}
segment->getStart()->setElevation(elevationStart);
}
if ((elevationEnd == 0) || (elevationEnd == parent->getElevation())) {
SGGeod center2 = segment->getEnd()->getGeod();
center2.setElevationM(SG_MAX_ELEVATION_M);
if (local_scenery->get_elevation_m( center2, elevationEnd, NULL )) {
elevation_feet = elevationEnd * SG_METER_TO_FEET + 0.5;
//elevation_meters += 0.5;
}
else {
elevationEnd = parent->getElevation();
}
segment->getEnd()->setElevation(elevationEnd);
}
double elevationMean = (elevationStart + elevationEnd) / 2.0;
double elevDiff = elevationEnd - elevationStart;
double length = segment->getLength();
double slope = atan2(elevDiff, length) * SGD_RADIANS_TO_DEGREES;
//cerr << "2. Using mean elevation : " << elevationMean << " and " << slope << endl;
WorldCoordinate( obj_pos, segment->getLatitude(), segment->getLongitude(), elevationMean + 0.5 + dx, -(segment->getHeading()), slope );
//WorldCoordinate( obj_pos, segment->getLatitude(), segment->getLongitude(), parent->getElevation()+8+dx, -(segment->getHeading()) );
obj_trans->setMatrix( obj_pos );
//osg::Vec3 center(0, 0, 0)
float width = segment->getLength() /2.0;
osg::Vec3 corner(-width, 0, 0.25f);
osg::Vec3 widthVec(2*width + 1, 0, 0);
osg::Vec3 heightVec(0, 1, 0);
osg::Geometry* geometry;
geometry = osg::createTexturedQuadGeometry(corner, widthVec, heightVec);
simgear::EffectGeode* geode = new simgear::EffectGeode;
geode->setName("test");
geode->addDrawable(geometry);
//osg::Node *custom_obj;
SGMaterial *mat;
if (segment->hasBlock()) {
mat = matlib->find("UnidirectionalTaperRed");
} else {
mat = matlib->find("UnidirectionalTaperGreen");
}
if (mat)
geode->setEffect(mat->get_effect());
obj_trans->addChild(geode);
// wire as much of the scene graph together as we can
//->addChild( obj_trans );
group->addChild( obj_trans );
} else {
//cerr << "BIG FAT WARNING: k is here : " << pos << endl;
}
}
dx += 0.2;
} }
//dx += 0.1;
} }
globals->get_scenery()->get_scene_graph()->addChild(group); globals->get_scenery()->get_scene_graph()->addChild(group);
} }
@ -1444,25 +1454,31 @@ string FGStartupController::getName() {
return string(parent->getId() + "-startup"); return string(parent->getId() + "-startup");
} }
void FGStartupController::update(double dt)
{
}
/*************************************************************************** /***************************************************************************
* class FGApproachController * class FGApproachController
* *
**************************************************************************/ **************************************************************************/
FGApproachController::FGApproachController(FGAirportDynamics *par): FGApproachController::FGApproachController(FGAirportDynamics *par):
FGATCController() FGATCController()
{ {
parent = par; parent = par;
} }
// //
void FGApproachController::announcePosition(int id, void FGApproachController::announcePosition(int id,
FGAIFlightPlan * intendedRoute, FGAIFlightPlan * intendedRoute,
int currentPosition, int currentPosition,
double lat, double lon, double lat, double lon,
double heading, double speed, double heading, double speed,
double alt, double radius, double alt, double radius,
int leg, FGAIAircraft * ref) int leg, FGAIAircraft * ref)
{ {
init(); init();
TrafficVectorIterator i = activeTraffic.begin(); TrafficVectorIterator i = activeTraffic.begin();
@ -1494,8 +1510,8 @@ void FGApproachController::announcePosition(int id,
} }
void FGApproachController::updateAircraftInformation(int id, double lat, double lon, void FGApproachController::updateAircraftInformation(int id, double lat, double lon,
double heading, double speed, double alt, double heading, double speed, double alt,
double dt) double dt)
{ {
TrafficVectorIterator i = activeTraffic.begin(); TrafficVectorIterator i = activeTraffic.begin();
// Search search if the current id has an entry // Search search if the current id has an entry
@ -1567,6 +1583,10 @@ void FGApproachController::signOff(int id)
} }
} }
void FGApproachController::update(double dt)
{
}

View file

@ -38,11 +38,14 @@
#include <simgear/structure/SGReferenced.hxx> #include <simgear/structure/SGReferenced.hxx>
#include <simgear/structure/SGSharedPtr.hxx> #include <simgear/structure/SGSharedPtr.hxx>
#include <string> #include <string>
#include <vector> #include <vector>
#include <list>
using std::string; using std::string;
using std::vector; using std::vector;
using std::list;
typedef vector<int> intVec; typedef vector<int> intVec;
@ -62,43 +65,79 @@ class FGAirportDynamics;
class FGATCInstruction class FGATCInstruction
{ {
private: private:
bool holdPattern; bool holdPattern;
bool holdPosition; bool holdPosition;
bool changeSpeed; bool changeSpeed;
bool changeHeading; bool changeHeading;
bool changeAltitude; bool changeAltitude;
bool resolveCircularWait; bool resolveCircularWait;
double speed; double speed;
double heading; double heading;
double alt; double alt;
public: public:
FGATCInstruction(); FGATCInstruction();
bool hasInstruction (); bool hasInstruction ();
bool getHoldPattern () { return holdPattern; }; bool getHoldPattern () {
bool getHoldPosition () { return holdPosition; }; return holdPattern;
bool getChangeSpeed () { return changeSpeed; }; };
bool getChangeHeading () { return changeHeading; }; bool getHoldPosition () {
bool getChangeAltitude() { return changeAltitude; }; return holdPosition;
};
bool getChangeSpeed () {
return changeSpeed;
};
bool getChangeHeading () {
return changeHeading;
};
bool getChangeAltitude() {
return changeAltitude;
};
double getSpeed () { return speed; }; double getSpeed () {
double getHeading () { return heading; }; return speed;
double getAlt () { return alt; }; };
double getHeading () {
return heading;
};
double getAlt () {
return alt;
};
bool getCheckForCircularWait() { return resolveCircularWait; }; bool getCheckForCircularWait() {
return resolveCircularWait;
};
void setHoldPattern (bool val) { holdPattern = val; }; void setHoldPattern (bool val) {
void setHoldPosition (bool val) { holdPosition = val; }; holdPattern = val;
void setChangeSpeed (bool val) { changeSpeed = val; }; };
void setChangeHeading (bool val) { changeHeading = val; }; void setHoldPosition (bool val) {
void setChangeAltitude(bool val) { changeAltitude = val; }; holdPosition = val;
};
void setChangeSpeed (bool val) {
changeSpeed = val;
};
void setChangeHeading (bool val) {
changeHeading = val;
};
void setChangeAltitude(bool val) {
changeAltitude = val;
};
void setResolveCircularWait (bool val) { resolveCircularWait = val; }; void setResolveCircularWait (bool val) {
resolveCircularWait = val;
};
void setSpeed (double val) { speed = val; }; void setSpeed (double val) {
void setHeading (double val) { heading = val; }; speed = val;
void setAlt (double val) { alt = val; }; };
void setHeading (double val) {
heading = val;
};
void setAlt (double val) {
alt = val;
};
}; };
@ -111,88 +150,175 @@ public:
class FGTrafficRecord class FGTrafficRecord
{ {
private: private:
int id, waitsForId; int id, waitsForId;
int currentPos; int currentPos;
int leg; int leg;
int frequencyId; int frequencyId;
int state; int state;
bool allowTransmission; bool allowTransmission;
time_t timer; bool allowPushback;
intVec intentions; int priority;
FGATCInstruction instruction; time_t timer;
double latitude, longitude, heading, speed, altitude, radius; intVec intentions;
string runway; FGATCInstruction instruction;
//FGAISchedule *trafficRef; double latitude, longitude, heading, speed, altitude, radius;
FGAIAircraft *aircraft; string runway;
//FGAISchedule *trafficRef;
FGAIAircraft *aircraft;
public: public:
FGTrafficRecord(); FGTrafficRecord();
void setId(int val) { id = val; }; void setId(int val) {
void setRadius(double rad) { radius = rad;}; id = val;
void setPositionAndIntentions(int pos, FGAIFlightPlan *route); };
void setRunway(string rwy) { runway = rwy;}; void setRadius(double rad) {
void setLeg(int lg) { leg = lg;}; radius = rad;
int getId() { return id;}; };
int getState() { return state;}; void setPositionAndIntentions(int pos, FGAIFlightPlan *route);
void setState(int s) { state = s;} void setRunway(string rwy) {
FGATCInstruction getInstruction() { return instruction;}; runway = rwy;
bool hasInstruction() { return instruction.hasInstruction(); }; };
void setPositionAndHeading(double lat, double lon, double hdg, double spd, double alt); void setLeg(int lg) {
bool checkPositionAndIntentions(FGTrafficRecord &other); leg = lg;
int crosses (FGGroundNetwork *, FGTrafficRecord &other); };
bool isOpposing (FGGroundNetwork *, FGTrafficRecord &other, int node); int getId() {
return id;
};
int getState() {
return state;
};
void setState(int s) {
state = s;
}
FGATCInstruction getInstruction() {
return instruction;
};
bool hasInstruction() {
return instruction.hasInstruction();
};
void setPositionAndHeading(double lat, double lon, double hdg, double spd, double alt);
bool checkPositionAndIntentions(FGTrafficRecord &other);
int crosses (FGGroundNetwork *, FGTrafficRecord &other);
bool isOpposing (FGGroundNetwork *, FGTrafficRecord &other, int node);
bool onRoute(FGGroundNetwork *, FGTrafficRecord &other); bool isActive(int margin);
bool getSpeedAdjustment() { return instruction.getChangeSpeed(); }; bool onRoute(FGGroundNetwork *, FGTrafficRecord &other);
double getLatitude () { return latitude ; }; bool getSpeedAdjustment() {
double getLongitude() { return longitude; }; return instruction.getChangeSpeed();
double getHeading () { return heading ; }; };
double getSpeed () { return speed ; };
double getAltitude () { return altitude ; };
double getRadius () { return radius ; };
int getWaitsForId () { return waitsForId; }; double getLatitude () {
return latitude ;
};
double getLongitude() {
return longitude;
};
double getHeading () {
return heading ;
};
double getSpeed () {
return speed ;
};
double getAltitude () {
return altitude ;
};
double getRadius () {
return radius ;
};
void setSpeedAdjustment(double spd); int getWaitsForId () {
void setHeadingAdjustment(double heading); return waitsForId;
void clearSpeedAdjustment () { instruction.setChangeSpeed (false); }; };
void clearHeadingAdjustment() { instruction.setChangeHeading(false); };
bool hasHeadingAdjustment() { return instruction.getChangeHeading(); }; void setSpeedAdjustment(double spd);
bool hasHoldPosition() { return instruction.getHoldPosition(); }; void setHeadingAdjustment(double heading);
void setHoldPosition (bool inst) { instruction.setHoldPosition(inst); }; void clearSpeedAdjustment () {
instruction.setChangeSpeed (false);
};
void clearHeadingAdjustment() {
instruction.setChangeHeading(false);
};
void setWaitsForId(int id) { waitsForId = id; }; bool hasHeadingAdjustment() {
return instruction.getChangeHeading();
};
bool hasHoldPosition() {
return instruction.getHoldPosition();
};
void setHoldPosition (bool inst) {
instruction.setHoldPosition(inst);
};
void setResolveCircularWait() { instruction.setResolveCircularWait(true); }; void setWaitsForId(int id) {
void clearResolveCircularWait() { instruction.setResolveCircularWait(false); }; waitsForId = id;
};
string getRunway() { return runway; }; void setResolveCircularWait() {
//void setCallSign(string clsgn) { callsign = clsgn; }; instruction.setResolveCircularWait(true);
void setAircraft(FGAIAircraft *ref) { aircraft = ref;}; };
void updateState() { state++; allowTransmission=true; }; void clearResolveCircularWait() {
//string getCallSign() { return callsign; }; instruction.setResolveCircularWait(false);
FGAIAircraft *getAircraft() { return aircraft;}; };
int getTime() { return timer; };
int getLeg() { return leg; };
void setTime(time_t time) { timer = time; };
bool pushBackAllowed(); string getRunway() {
bool allowTransmissions() { return allowTransmission; }; return runway;
void suppressRepeatedTransmissions () { allowTransmission=false; }; };
void allowRepeatedTransmissions () { allowTransmission=true; }; //void setCallSign(string clsgn) { callsign = clsgn; };
void nextFrequency() { frequencyId++; }; void setAircraft(FGAIAircraft *ref) {
int getNextFrequency() { return frequencyId; }; aircraft = ref;
intVec& getIntentions() { return intentions; }; };
int getCurrentPosition() { return currentPos; }; void updateState() {
state++;
allowTransmission=true;
};
//string getCallSign() { return callsign; };
FGAIAircraft *getAircraft() {
return aircraft;
};
int getTime() {
return timer;
};
int getLeg() {
return leg;
};
void setTime(time_t time) {
timer = time;
};
bool pushBackAllowed();
bool allowTransmissions() {
return allowTransmission;
};
void allowPushBack() { allowPushback =true;};
void denyPushBack () { allowPushback = false;};
void suppressRepeatedTransmissions () {
allowTransmission=false;
};
void allowRepeatedTransmissions () {
allowTransmission=true;
};
void nextFrequency() {
frequencyId++;
};
int getNextFrequency() {
return frequencyId;
};
intVec& getIntentions() {
return intentions;
};
int getCurrentPosition() {
return currentPos;
};
void setPriority(int p) { priority = p; };
int getPriority() { return priority; };
}; };
typedef vector<FGTrafficRecord> TrafficVector; typedef list<FGTrafficRecord> TrafficVector;
typedef vector<FGTrafficRecord>::iterator TrafficVectorIterator; typedef list<FGTrafficRecord>::iterator TrafficVectorIterator;
typedef vector<time_t> TimeVector; typedef vector<time_t> TimeVector;
typedef vector<time_t>::iterator TimeVectorIterator; typedef vector<time_t>::iterator TimeVectorIterator;
@ -207,28 +333,48 @@ typedef vector<FGAIAircraft*>::iterator AircraftVecIterator;
class ActiveRunway class ActiveRunway
{ {
private: private:
string rwy; string rwy;
int currentlyCleared; int currentlyCleared;
double distanceToFinal; double distanceToFinal;
TimeVector estimatedArrivalTimes; TimeVector estimatedArrivalTimes;
AircraftVec departureCue; AircraftVec departureCue;
public: public:
ActiveRunway(string r, int cc) { rwy = r; currentlyCleared = cc; distanceToFinal = 6.0 * SG_NM_TO_METER; }; ActiveRunway(string r, int cc) {
rwy = r;
currentlyCleared = cc;
distanceToFinal = 6.0 * SG_NM_TO_METER;
};
string getRunwayName() { return rwy; }; string getRunwayName() {
int getCleared () { return currentlyCleared; }; return rwy;
double getApproachDistance() { return distanceToFinal; }; };
//time_t getEstApproachTime() { return estimatedArrival; }; int getCleared () {
return currentlyCleared;
};
double getApproachDistance() {
return distanceToFinal;
};
//time_t getEstApproachTime() { return estimatedArrival; };
//void setEstApproachTime(time_t time) { estimatedArrival = time; }; //void setEstApproachTime(time_t time) { estimatedArrival = time; };
void addToDepartureCue(FGAIAircraft *ac) { departureCue.push_back(ac); }; void addToDepartureCue(FGAIAircraft *ac) {
void setCleared(int number) { currentlyCleared = number; }; departureCue.push_back(ac);
time_t requestTimeSlot(time_t eta); };
void setCleared(int number) {
currentlyCleared = number;
};
time_t requestTimeSlot(time_t eta);
int getDepartureCueSize() { return departureCue.size(); }; int getDepartureCueSize() {
FGAIAircraft* getFirstAircraftInDepartureCue() { return departureCue.size() ? *(departureCue.begin()) : NULL; }; return departureCue.size();
void updateDepartureCue() { departureCue.erase(departureCue.begin()); } };
FGAIAircraft* getFirstAircraftInDepartureCue() {
return departureCue.size() ? *(departureCue.begin()) : NULL;
};
void updateDepartureCue() {
departureCue.erase(departureCue.begin());
}
}; };
typedef vector<ActiveRunway> ActiveRunwayVec; typedef vector<ActiveRunway> ActiveRunwayVec;
@ -244,71 +390,78 @@ private:
protected: protected:
bool initialized; bool initialized;
bool available; bool available;
time_t lastTransmission; time_t lastTransmission;
double dt_count; double dt_count;
osg::Group* group; osg::Group* group;
string formatATCFrequency3_2(int ); string formatATCFrequency3_2(int );
string genTransponderCode(string fltRules); string genTransponderCode(string fltRules);
bool isUserAircraft(FGAIAircraft*); bool isUserAircraft(FGAIAircraft*);
public: public:
typedef enum { typedef enum {
MSG_ANNOUNCE_ENGINE_START, MSG_ANNOUNCE_ENGINE_START,
MSG_REQUEST_ENGINE_START, MSG_REQUEST_ENGINE_START,
MSG_PERMIT_ENGINE_START, MSG_PERMIT_ENGINE_START,
MSG_DENY_ENGINE_START, MSG_DENY_ENGINE_START,
MSG_ACKNOWLEDGE_ENGINE_START, MSG_ACKNOWLEDGE_ENGINE_START,
MSG_REQUEST_PUSHBACK_CLEARANCE, MSG_REQUEST_PUSHBACK_CLEARANCE,
MSG_PERMIT_PUSHBACK_CLEARANCE, MSG_PERMIT_PUSHBACK_CLEARANCE,
MSG_HOLD_PUSHBACK_CLEARANCE, MSG_HOLD_PUSHBACK_CLEARANCE,
MSG_ACKNOWLEDGE_SWITCH_GROUND_FREQUENCY, MSG_ACKNOWLEDGE_SWITCH_GROUND_FREQUENCY,
MSG_INITIATE_CONTACT, MSG_INITIATE_CONTACT,
MSG_ACKNOWLEDGE_INITIATE_CONTACT, MSG_ACKNOWLEDGE_INITIATE_CONTACT,
MSG_REQUEST_TAXI_CLEARANCE, MSG_REQUEST_TAXI_CLEARANCE,
MSG_ISSUE_TAXI_CLEARANCE, MSG_ISSUE_TAXI_CLEARANCE,
MSG_ACKNOWLEDGE_TAXI_CLEARANCE, MSG_ACKNOWLEDGE_TAXI_CLEARANCE,
MSG_HOLD_POSITION, MSG_HOLD_POSITION,
MSG_ACKNOWLEDGE_HOLD_POSITION, MSG_ACKNOWLEDGE_HOLD_POSITION,
MSG_RESUME_TAXI, MSG_RESUME_TAXI,
MSG_ACKNOWLEDGE_RESUME_TAXI, MSG_ACKNOWLEDGE_RESUME_TAXI,
MSG_REPORT_RUNWAY_HOLD_SHORT, MSG_REPORT_RUNWAY_HOLD_SHORT,
MSG_ACKNOWLEDGE_REPORT_RUNWAY_HOLD_SHORT, MSG_ACKNOWLEDGE_REPORT_RUNWAY_HOLD_SHORT,
MSG_SWITCH_TOWER_FREQUENCY, MSG_SWITCH_TOWER_FREQUENCY,
MSG_ACKNOWLEDGE_SWITCH_TOWER_FREQUENCY MSG_ACKNOWLEDGE_SWITCH_TOWER_FREQUENCY
} AtcMsgId; } AtcMsgId;
typedef enum { typedef enum {
ATC_AIR_TO_GROUND, ATC_AIR_TO_GROUND,
ATC_GROUND_TO_AIR } AtcMsgDir; ATC_GROUND_TO_AIR
FGATCController(); } AtcMsgDir;
virtual ~FGATCController(); FGATCController();
void init(); virtual ~FGATCController();
void init();
virtual void announcePosition(int id, FGAIFlightPlan *intendedRoute, int currentRoute, virtual void announcePosition(int id, FGAIFlightPlan *intendedRoute, int currentRoute,
double lat, double lon, double lat, double lon,
double hdg, double spd, double alt, double radius, int leg, double hdg, double spd, double alt, double radius, int leg,
FGAIAircraft *aircraft) = 0; FGAIAircraft *aircraft) = 0;
virtual void signOff(int id) = 0; virtual void signOff(int id) = 0;
virtual void updateAircraftInformation(int id, double lat, double lon, virtual void updateAircraftInformation(int id, double lat, double lon,
double heading, double speed, double alt, double dt) = 0; double heading, double speed, double alt, double dt) = 0;
virtual bool hasInstruction(int id) = 0; virtual bool hasInstruction(int id) = 0;
virtual FGATCInstruction getInstruction(int id) = 0; virtual FGATCInstruction getInstruction(int id) = 0;
double getDt() { return dt_count; }; double getDt() {
void setDt(double dt) { dt_count = dt;}; return dt_count;
void transmit(FGTrafficRecord *rec, AtcMsgId msgId, AtcMsgDir msgDir, bool audible); };
string getGateName(FGAIAircraft *aircraft); void setDt(double dt) {
virtual void render(bool) = 0; dt_count = dt;
virtual string getName() = 0; };
void transmit(FGTrafficRecord *rec, AtcMsgId msgId, AtcMsgDir msgDir, bool audible);
string getGateName(FGAIAircraft *aircraft);
virtual void render(bool) = 0;
virtual string getName() = 0;
virtual void update(double) = 0;
private: private:
AtcMsgDir lastTransmissionDirection; AtcMsgDir lastTransmissionDirection;
}; };
/****************************************************************************** /******************************************************************************
@ -317,27 +470,32 @@ private:
class FGTowerController : public FGATCController class FGTowerController : public FGATCController
{ {
private: private:
TrafficVector activeTraffic; TrafficVector activeTraffic;
ActiveRunwayVec activeRunways; ActiveRunwayVec activeRunways;
FGAirportDynamics *parent; FGAirportDynamics *parent;
public: public:
FGTowerController(FGAirportDynamics *parent); FGTowerController(FGAirportDynamics *parent);
virtual ~FGTowerController() {}; virtual ~FGTowerController() {};
virtual void announcePosition(int id, FGAIFlightPlan *intendedRoute, int currentRoute, virtual void announcePosition(int id, FGAIFlightPlan *intendedRoute, int currentRoute,
double lat, double lon, double lat, double lon,
double hdg, double spd, double alt, double radius, int leg, double hdg, double spd, double alt, double radius, int leg,
FGAIAircraft *aircraft); FGAIAircraft *aircraft);
virtual void signOff(int id); virtual void signOff(int id);
virtual void updateAircraftInformation(int id, double lat, double lon, virtual void updateAircraftInformation(int id, double lat, double lon,
double heading, double speed, double alt, double dt); double heading, double speed, double alt, double dt);
virtual bool hasInstruction(int id); virtual bool hasInstruction(int id);
virtual FGATCInstruction getInstruction(int id); virtual FGATCInstruction getInstruction(int id);
virtual void render(bool); virtual void render(bool);
virtual string getName(); virtual string getName();
bool hasActiveTraffic() { return activeTraffic.size() != 0; }; virtual void update(double dt);
TrafficVector &getActiveTraffic() { return activeTraffic; }; bool hasActiveTraffic() {
return activeTraffic.size() != 0;
};
TrafficVector &getActiveTraffic() {
return activeTraffic;
};
}; };
/****************************************************************************** /******************************************************************************
@ -348,32 +506,37 @@ public:
class FGStartupController : public FGATCController class FGStartupController : public FGATCController
{ {
private: private:
TrafficVector activeTraffic; TrafficVector activeTraffic;
//ActiveRunwayVec activeRunways; //ActiveRunwayVec activeRunways;
FGAirportDynamics *parent; FGAirportDynamics *parent;
public: public:
FGStartupController(FGAirportDynamics *parent); FGStartupController(FGAirportDynamics *parent);
virtual ~FGStartupController() {}; virtual ~FGStartupController() {};
virtual void announcePosition(int id, FGAIFlightPlan *intendedRoute, int currentRoute, virtual void announcePosition(int id, FGAIFlightPlan *intendedRoute, int currentRoute,
double lat, double lon, double lat, double lon,
double hdg, double spd, double alt, double radius, int leg, double hdg, double spd, double alt, double radius, int leg,
FGAIAircraft *aircraft); FGAIAircraft *aircraft);
virtual void signOff(int id); virtual void signOff(int id);
virtual void updateAircraftInformation(int id, double lat, double lon, virtual void updateAircraftInformation(int id, double lat, double lon,
double heading, double speed, double alt, double dt); double heading, double speed, double alt, double dt);
virtual bool hasInstruction(int id); virtual bool hasInstruction(int id);
virtual FGATCInstruction getInstruction(int id); virtual FGATCInstruction getInstruction(int id);
virtual void render(bool); virtual void render(bool);
virtual string getName(); virtual string getName();
virtual void update(double dt);
bool hasActiveTraffic() { return activeTraffic.size() != 0; }; bool hasActiveTraffic() {
TrafficVector &getActiveTraffic() { return activeTraffic; }; return activeTraffic.size() != 0;
};
TrafficVector &getActiveTraffic() {
return activeTraffic;
};
// Hpoefully, we can move this function to the base class, but I need to verify what is needed for the other controllers before doing so. // Hpoefully, we can move this function to the base class, but I need to verify what is needed for the other controllers before doing so.
bool checkTransmissionState(int st, time_t now, time_t startTime, TrafficVectorIterator i, AtcMsgId msgId, bool checkTransmissionState(int st, time_t now, time_t startTime, TrafficVectorIterator i, AtcMsgId msgId,
AtcMsgDir msgDir); AtcMsgDir msgDir);
}; };
@ -383,30 +546,35 @@ public:
class FGApproachController : public FGATCController class FGApproachController : public FGATCController
{ {
private: private:
TrafficVector activeTraffic; TrafficVector activeTraffic;
ActiveRunwayVec activeRunways; ActiveRunwayVec activeRunways;
FGAirportDynamics *parent; FGAirportDynamics *parent;
public: public:
FGApproachController(FGAirportDynamics * parent); FGApproachController(FGAirportDynamics * parent);
virtual ~FGApproachController() { }; virtual ~FGApproachController() { };
virtual void announcePosition(int id, FGAIFlightPlan *intendedRoute, int currentRoute, virtual void announcePosition(int id, FGAIFlightPlan *intendedRoute, int currentRoute,
double lat, double lon, double lat, double lon,
double hdg, double spd, double alt, double radius, int leg, double hdg, double spd, double alt, double radius, int leg,
FGAIAircraft *aircraft); FGAIAircraft *aircraft);
virtual void signOff(int id); virtual void signOff(int id);
virtual void updateAircraftInformation(int id, double lat, double lon, virtual void updateAircraftInformation(int id, double lat, double lon,
double heading, double speed, double alt, double dt); double heading, double speed, double alt, double dt);
virtual bool hasInstruction(int id); virtual bool hasInstruction(int id);
virtual FGATCInstruction getInstruction(int id); virtual FGATCInstruction getInstruction(int id);
virtual void render(bool); virtual void render(bool);
virtual string getName(); virtual string getName();
virtual void update(double dt);
ActiveRunway* getRunway(string name); ActiveRunway* getRunway(string name);
bool hasActiveTraffic() { return activeTraffic.size() != 0; }; bool hasActiveTraffic() {
TrafficVector &getActiveTraffic() { return activeTraffic; }; return activeTraffic.size() != 0;
};
TrafficVector &getActiveTraffic() {
return activeTraffic;
};
}; };

View file

@ -3,11 +3,13 @@ include(FlightGearComponent)
set(SOURCES set(SOURCES
controls.cxx controls.cxx
replay.cxx replay.cxx
flightrecorder.cxx
) )
set(HEADERS set(HEADERS
controls.hxx controls.hxx
replay.hxx replay.hxx
flightrecorder.hxx
) )

View file

@ -2,6 +2,7 @@ noinst_LIBRARIES = libAircraft.a
libAircraft_a_SOURCES = \ libAircraft_a_SOURCES = \
controls.cxx controls.hxx \ controls.cxx controls.hxx \
replay.cxx replay.hxx replay.cxx replay.hxx \
flightrecorder.cxx flightrecorder.hxx
INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/src INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/src

View file

@ -0,0 +1,544 @@
// flightrecorder.cxx
//
// Written by Thorsten Brehm, started August 2011.
//
// Copyright (C) 2011 Thorsten Brehm - brehmt (at) gmail com
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
///////////////////////////////////////////////////////////////////////////////
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <simgear/debug/logstream.hxx>
#include <simgear/props/props_io.hxx>
#include <simgear/misc/ResourceManager.hxx>
#include <simgear/misc/strutils.hxx>
#include <simgear/structure/exception.hxx>
#include <Main/fg_props.hxx>
#include "flightrecorder.hxx"
using namespace FlightRecorder;
FGFlightRecorder::FGFlightRecorder(const char* pConfigName) :
m_RecorderNode(fgGetNode("/sim/flight-recorder", true)),
m_TotalRecordSize(0),
m_ConfigName(pConfigName)
{
}
FGFlightRecorder::~FGFlightRecorder()
{
}
void
FGFlightRecorder::reinit(void)
{
m_ConfigNode = 0;
m_TotalRecordSize = 0;
m_CaptureDouble.clear();
m_CaptureFloat.clear();
m_CaptureInteger.clear();
m_CaptureInt16.clear();
m_CaptureInt8.clear();
m_CaptureBool.clear();
int Selected = m_RecorderNode->getIntValue(m_ConfigName, 0);
SG_LOG(SG_SYSTEMS, SG_INFO, "FlightRecorder: Recorder configuration #" << Selected);
if (Selected >= 0)
m_ConfigNode = m_RecorderNode->getChild("config", Selected);
if (!m_ConfigNode.valid())
initDefault();
if (!m_ConfigNode.valid())
{
SG_LOG(SG_SYSTEMS, SG_ALERT, "FlightRecorder: Configuration is invalid. Flight recorder disabled.");
}
else
{
// set name of active flight recorder type
const char* pRecorderName =
m_ConfigNode->getStringValue("name",
"aircraft-specific flight recorder");
SG_LOG(SG_SYSTEMS, SG_INFO, "FlightRecorder: Using custom recorder configuration: " << pRecorderName);
m_RecorderNode->setStringValue("active-config-name", pRecorderName);
// get signals
initSignalList("double", m_CaptureDouble, m_ConfigNode );
initSignalList("float", m_CaptureFloat , m_ConfigNode );
initSignalList("int", m_CaptureInteger, m_ConfigNode );
initSignalList("int16", m_CaptureInt16 , m_ConfigNode );
initSignalList("int8", m_CaptureInt8 , m_ConfigNode );
initSignalList("bool", m_CaptureBool , m_ConfigNode );
}
// calculate size of a single record
m_TotalRecordSize = sizeof(double) * 1 /* sim time */ +
sizeof(double) * m_CaptureDouble.size() +
sizeof(float) * m_CaptureFloat.size() +
sizeof(int) * m_CaptureInteger.size() +
sizeof(short int) * m_CaptureInt16.size() +
sizeof(signed char) * m_CaptureInt8.size() +
sizeof(unsigned char) * ((m_CaptureBool.size()+7)/8); // 8 bools per byte
// expose size of actual flight recorder record
m_RecorderNode->setIntValue("record-size", m_TotalRecordSize);
SG_LOG(SG_SYSTEMS, SG_INFO, "FlightRecorder: record size is " << m_TotalRecordSize << " bytes");
}
/** Check if SignalList already contains the given property */
bool
FGFlightRecorder::haveProperty(FlightRecorder::TSignalList& SignalList,SGPropertyNode* pProperty)
{
unsigned int Count = SignalList.size();
for (unsigned int i=0; i<Count; i++)
{
if (SignalList[i].Signal.get() == pProperty)
{
return true;
}
}
return false;
}
/** Check if any signal list already contains the given property */
bool
FGFlightRecorder::haveProperty(SGPropertyNode* pProperty)
{
if (haveProperty(m_CaptureDouble, pProperty))
return true;
if (haveProperty(m_CaptureFloat, pProperty))
return true;
if (haveProperty(m_CaptureInteger, pProperty))
return true;
if (haveProperty(m_CaptureInt16, pProperty))
return true;
if (haveProperty(m_CaptureInt8, pProperty))
return true;
if (haveProperty(m_CaptureBool, pProperty))
return true;
return false;
}
/** Read default flight-recorder configuration.
* Default should match properties as hard coded for versions up to FG2.4.0. */
void
FGFlightRecorder::initDefault(void)
{
// set name of active flight recorder type
SG_LOG(SG_SYSTEMS, SG_INFO, "FlightRecorder: No custom configuration. Loading generic default recorder.");
const char* Path = m_RecorderNode->getStringValue("default-config",NULL);
if (!Path)
{
SG_LOG(SG_SYSTEMS, SG_ALERT, "FlightRecorder: No default flight recorder specified! Check preferences.xml!");
}
else
{
SGPath path = globals->resolve_aircraft_path(Path);
if (path.isNull())
{
SG_LOG(SG_SYSTEMS, SG_ALERT, "FlightRecorder: Cannot find file '" << Path << "'.");
}
else
{
try
{
readProperties(path.str(), m_RecorderNode->getChild("config", 0 ,true), 0);
m_ConfigNode = m_RecorderNode->getChild("config", 0 ,false);
} catch (sg_io_exception &e)
{
SG_LOG(SG_SYSTEMS, SG_ALERT, "FlightRecorder: Error reading file '" <<
Path << ": " << e.getFormattedMessage());
}
}
}
}
/** Read signal list below given base node.
* Only process properties of given signal type and add all signals to the given list.
* This method is called for all supported signal types - properties of each type are
* kept in separate lists for efficiency reasons. */
void
FGFlightRecorder::initSignalList(const char* pSignalType, TSignalList& SignalList, SGPropertyNode_ptr BaseNode)
{
// clear old signals
SignalList.clear();
processSignalList(pSignalType, SignalList, BaseNode);
SG_LOG(SG_SYSTEMS, SG_DEBUG, "FlightRecorder: " << SignalList.size() << " signals of type " << pSignalType );
}
/** Process signal list below given base node.
* Only process properties of given signal type and add all signals to the given list.
* This method is called for all supported signal types - properties of each type are
* kept in separate lists for efficiency reasons. */
void
FGFlightRecorder::processSignalList(const char* pSignalType, TSignalList& SignalList, SGPropertyNode_ptr SignalListNode,
string PropPrefix, int Count)
{
// get the list of signal sources (property paths) for this signal type
SGPropertyNode_ptr SignalNode;
int Index=0;
Count = SignalListNode->getIntValue("count",Count);
PropPrefix = simgear::strutils::strip(SignalListNode->getStringValue("prefix",PropPrefix.c_str()));
if ((!PropPrefix.empty())&&(PropPrefix[PropPrefix.size()-1] != '/'))
PropPrefix += "/";
do
{
SignalNode = SignalListNode->getChild("signal",Index,false);
if (SignalNode.valid()&&
(0==strcmp(pSignalType, SignalNode->getStringValue("type","float"))))
{
string PropertyPath = SignalNode->getStringValue("property","");
if (!PropertyPath.empty())
{
PropertyPath = PropPrefix + PropertyPath;
const char* pInterpolation = SignalNode->getStringValue("interpolation","linear");
// Check if current signal has a "%i" place holder. Otherwise count is 1.
string::size_type IndexPos = PropertyPath.find("%i");
int SignalCount = Count;
if (IndexPos == string::npos)
SignalCount = 1;
for (int IndexValue=0;IndexValue<SignalCount;IndexValue++)
{
string PPath = PropertyPath;
if (IndexPos != string::npos)
{
char strbuf[20];
snprintf(strbuf, 20, "%d", IndexValue);
PPath = PPath.replace(IndexPos,2,strbuf);
}
TCapture Capture;
Capture.Signal = fgGetNode(PPath.c_str(),false);
if (!Capture.Signal.valid())
{
// warn user: we're maybe going to record useless data
// Or maybe the data is only initialized later. Warn anyway, so we can catch useless data.
SG_LOG(SG_SYSTEMS, SG_INFO, "FlightRecorder: Recording non-existent property '" << PPath << "'.");
Capture.Signal = fgGetNode(PPath.c_str(),true);
}
if (0==strcmp(pInterpolation,"discrete"))
Capture.Interpolation = discrete;
else
if ((0==strcmp(pInterpolation,"angular"))||
(0==strcmp(pInterpolation,"angular-rad")))
Capture.Interpolation = angular_rad;
else
if (0==strcmp(pInterpolation,"angular-deg"))
Capture.Interpolation = angular_deg;
else
if (0==strcmp(pInterpolation,"linear"))
Capture.Interpolation = linear;
else
{
SG_LOG(SG_SYSTEMS, SG_ALERT, "FlightRecorder: Unsupported interpolation type '"
<< pInterpolation<< "' of signal '" << PPath << "'");
Capture.Interpolation = linear;
}
if (haveProperty(Capture.Signal))
{
SG_LOG(SG_SYSTEMS, SG_ALERT, "FlightRecorder: Property '"
<< PPath << "' specified multiple times. Check flight recorder configuration.");
}
else
SignalList.push_back(Capture);
}
}
}
Index++;
} while (SignalNode.valid());
// allow recursive definition of signal lists
simgear::PropertyList Nodes = SignalListNode->getChildren("signals");
for (unsigned int i=0;i<Nodes.size();i++)
{
processSignalList(pSignalType, SignalList, Nodes[i], PropPrefix, Count);
}
}
/** Get an empty container for a single capture. */
FGReplayData*
FGFlightRecorder::createEmptyRecord(void)
{
if (!m_TotalRecordSize)
return NULL;
FGReplayData* p = (FGReplayData*) new unsigned char[m_TotalRecordSize];
return p;
}
/** Free given container with capture data. */
void
FGFlightRecorder::deleteRecord(FGReplayData* pRecord)
{
delete[] pRecord;
}
/** Capture data.
* When pBuffer==NULL new memory is allocated.
* If pBuffer!=NULL memory of given buffer is reused.
*/
FGReplayData*
FGFlightRecorder::capture(double SimTime, FGReplayData* pRecycledBuffer)
{
if (!pRecycledBuffer)
{
pRecycledBuffer = createEmptyRecord();
if (!pRecycledBuffer)
return NULL;
}
unsigned char* pBuffer = (unsigned char*) pRecycledBuffer;
int Offset = 0;
pRecycledBuffer->sim_time = SimTime;
Offset += sizeof(double);
// 64bit aligned data first!
{
// capture doubles
double* pDoubles = (double*) &pBuffer[Offset];
unsigned int SignalCount = m_CaptureDouble.size();
for (unsigned int i=0; i<SignalCount; i++)
{
pDoubles[i] = m_CaptureDouble[i].Signal->getDoubleValue();
}
Offset += SignalCount * sizeof(double);
}
// 32bit aligned data comes second...
{
// capture floats
float* pFloats = (float*) &pBuffer[Offset];
unsigned int SignalCount = m_CaptureFloat.size();
for (unsigned int i=0; i<SignalCount; i++)
{
pFloats[i] = m_CaptureFloat[i].Signal->getFloatValue();
}
Offset += SignalCount * sizeof(float);
}
{
// capture integers (32bit aligned)
int* pInt = (int*) &pBuffer[Offset];
unsigned int SignalCount = m_CaptureInteger.size();
for (unsigned int i=0; i<SignalCount; i++)
{
pInt[i] = m_CaptureInteger[i].Signal->getIntValue();
}
Offset += SignalCount * sizeof(int);
}
// 16bit aligned data is next...
{
// capture 16bit short integers
short int* pShortInt = (short int*) &pBuffer[Offset];
unsigned int SignalCount = m_CaptureInt16.size();
for (unsigned int i=0; i<SignalCount; i++)
{
pShortInt[i] = (short int) m_CaptureInt16[i].Signal->getIntValue();
}
Offset += SignalCount * sizeof(short int);
}
// finally: byte aligned data is last...
{
// capture 8bit chars
signed char* pChar = (signed char*) &pBuffer[Offset];
unsigned int SignalCount = m_CaptureInt8.size();
for (unsigned int i=0; i<SignalCount; i++)
{
pChar[i] = (signed char) m_CaptureInt8[i].Signal->getIntValue();
}
Offset += SignalCount * sizeof(signed char);
}
{
// capture 1bit booleans (8bit aligned)
unsigned char* pFlags = (unsigned char*) &pBuffer[Offset];
unsigned int SignalCount = m_CaptureBool.size();
int Size = (SignalCount+7)/8;
Offset += Size;
memset(pFlags,0,Size);
for (unsigned int i=0; i<SignalCount; i++)
{
if (m_CaptureBool[i].Signal->getBoolValue())
pFlags[i>>3] |= 1 << (i&7);
}
}
assert(Offset == m_TotalRecordSize);
return (FGReplayData*) pBuffer;
}
/** Do interpolation as defined by given interpolation type and weighting ratio. */
static double
weighting(TInterpolation interpolation, double ratio, double v1,double v2)
{
switch (interpolation)
{
case linear:
return v1 + ratio*(v2-v1);
case angular_deg:
{
// special handling of angular data
double tmp = v2 - v1;
if ( tmp > 180 )
tmp -= 360;
else if ( tmp < -180 )
tmp += 360;
return v1 + tmp * ratio;
}
case angular_rad:
{
// special handling of angular data
double tmp = v2 - v1;
if ( tmp > SGD_PI )
tmp -= SGD_2PI;
else if ( tmp < -SGD_PI )
tmp += SGD_2PI;
return v1 + tmp * ratio;
}
case discrete:
// fall through
default:
return v2;
}
}
/** Replay.
* Restore all properties with data from given buffer. */
void
FGFlightRecorder::replay(double SimTime, const FGReplayData* _pNextBuffer, const FGReplayData* _pLastBuffer)
{
const char* pLastBuffer = (const char*) _pLastBuffer;
const char* pBuffer = (const char*) _pNextBuffer;
if (!pBuffer)
return;
int Offset = 0;
double ratio;
if (pLastBuffer)
{
double NextSimTime = _pNextBuffer->sim_time;
double LastSimTime = _pLastBuffer->sim_time;
ratio = (SimTime - LastSimTime) / (NextSimTime - LastSimTime);
}
else
{
ratio = 1.0;
}
Offset += sizeof(double);
// 64bit aligned data first!
{
// restore doubles
const double* pDoubles = (const double*) &pBuffer[Offset];
const double* pLastDoubles = (const double*) &pLastBuffer[Offset];
unsigned int SignalCount = m_CaptureDouble.size();
for (unsigned int i=0; i<SignalCount; i++)
{
double v = pDoubles[i];
if (pLastBuffer)
{
v = weighting(m_CaptureDouble[i].Interpolation, ratio,
pLastDoubles[i], v);
}
m_CaptureDouble[i].Signal->setDoubleValue(v);
}
Offset += SignalCount * sizeof(double);
}
// 32bit aligned data comes second...
{
// restore floats
const float* pFloats = (const float*) &pBuffer[Offset];
const float* pLastFloats = (const float*) &pLastBuffer[Offset];
unsigned int SignalCount = m_CaptureFloat.size();
for (unsigned int i=0; i<SignalCount; i++)
{
float v = pFloats[i];
if (pLastBuffer)
{
v = weighting(m_CaptureFloat[i].Interpolation, ratio,
pLastFloats[i], v);
}
m_CaptureFloat[i].Signal->setDoubleValue(v);//setFloatValue
}
Offset += SignalCount * sizeof(float);
}
{
// restore integers (32bit aligned)
const int* pInt = (const int*) &pBuffer[Offset];
unsigned int SignalCount = m_CaptureInteger.size();
for (unsigned int i=0; i<SignalCount; i++)
{
m_CaptureInteger[i].Signal->setIntValue(pInt[i]);
}
Offset += SignalCount * sizeof(int);
}
// 16bit aligned data is next...
{
// restore 16bit short integers
const short int* pShortInt = (const short int*) &pBuffer[Offset];
unsigned int SignalCount = m_CaptureInt16.size();
for (unsigned int i=0; i<SignalCount; i++)
{
m_CaptureInt16[i].Signal->setIntValue(pShortInt[i]);
}
Offset += SignalCount * sizeof(short int);
}
// finally: byte aligned data is last...
{
// restore 8bit chars
const signed char* pChar = (const signed char*) &pBuffer[Offset];
unsigned int SignalCount = m_CaptureInt8.size();
for (unsigned int i=0; i<SignalCount; i++)
{
m_CaptureInt8[i].Signal->setIntValue(pChar[i]);
}
Offset += SignalCount * sizeof(signed char);
}
{
// restore 1bit booleans (8bit aligned)
const unsigned char* pFlags = (const unsigned char*) &pBuffer[Offset];
unsigned int SignalCount = m_CaptureBool.size();
int Size = (SignalCount+7)/8;
Offset += Size;
for (unsigned int i=0; i<SignalCount; i++)
{
m_CaptureBool[i].Signal->setBoolValue(0 != (pFlags[i>>3] & (1 << (i&7))));
}
}
}

View file

@ -0,0 +1,89 @@
// flightrecorder.hxx
//
// Written by Thorsten Brehm, started August 2011.
//
// Copyright (C) 2011 Thorsten Brehm - brehmt (at) gmail com
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
///////////////////////////////////////////////////////////////////////////////
#ifndef FLIGHTRECORDER_HXX_
#define FLIGHTRECORDER_HXX_
#include <simgear/props/props.hxx>
#include "replay.hxx"
namespace FlightRecorder
{
typedef enum
{
discrete = 0, // no interpolation
linear = 1, // linear interpolation
angular_rad = 2, // angular interpolation, value in radians
angular_deg = 3 // angular interpolation, value in degrees
} TInterpolation;
typedef struct
{
SGPropertyNode_ptr Signal;
TInterpolation Interpolation;
} TCapture;
typedef std::vector<TCapture> TSignalList;
}
class FGFlightRecorder
{
public:
FGFlightRecorder(const char* pConfigName);
virtual ~FGFlightRecorder();
void reinit (void);
FGReplayData* createEmptyRecord (void);
FGReplayData* capture (double SimTime, FGReplayData* pRecycledBuffer);
void replay (double SimTime, const FGReplayData* pNextBuffer,
const FGReplayData* pLastBuffer = NULL);
void deleteRecord (FGReplayData* pRecord);
int getRecordSize (void) { return m_TotalRecordSize;}
private:
void initDefault(void);
void initSignalList(const char* pSignalType, FlightRecorder::TSignalList& SignalList,
SGPropertyNode_ptr BaseNode);
void processSignalList(const char* pSignalType, FlightRecorder::TSignalList& SignalList,
SGPropertyNode_ptr SignalListNode,
string PropPrefix="", int Count = 1);
bool haveProperty(FlightRecorder::TSignalList& Capture,SGPropertyNode* pProperty);
bool haveProperty(SGPropertyNode* pProperty);
SGPropertyNode_ptr m_RecorderNode;
SGPropertyNode_ptr m_ConfigNode;
FlightRecorder::TSignalList m_CaptureDouble;
FlightRecorder::TSignalList m_CaptureFloat;
FlightRecorder::TSignalList m_CaptureInteger;
FlightRecorder::TSignalList m_CaptureInt16;
FlightRecorder::TSignalList m_CaptureInt8;
FlightRecorder::TSignalList m_CaptureBool;
int m_TotalRecordSize;
string m_ConfigName;
};
#endif /* FLIGHTRECORDER_HXX_ */

View file

@ -1,6 +1,7 @@
// replay.cxx - a system to record and replay FlightGear flights // replay.cxx - a system to record and replay FlightGear flights
// //
// Written by Curtis Olson, started Juley 2003. // Written by Curtis Olson, started July 2003.
// Updated by Thorsten Brehm, September 2011.
// //
// Copyright (C) 2003 Curtis L. Olson - http://www.flightgear.org/~curt // Copyright (C) 2003 Curtis L. Olson - http://www.flightgear.org/~curt
// //
@ -25,36 +26,31 @@
#endif #endif
#include <float.h> #include <float.h>
#include <simgear/constants.h> #include <simgear/constants.h>
#include <simgear/structure/exception.hxx> #include <simgear/structure/exception.hxx>
#include <Main/fg_props.hxx> #include <Main/fg_props.hxx>
#include <Network/native_ctrls.hxx>
#include <Network/native_fdm.hxx>
#include <Network/net_ctrls.hxx>
#include <Network/net_fdm.hxx>
#include <FDM/fdm_shell.hxx> #include <FDM/fdm_shell.hxx>
#include "replay.hxx" #include "replay.hxx"
#include "flightrecorder.hxx"
const double FGReplay::st_list_time = 60.0; // 60 secs of high res data
const double FGReplay::mt_list_time = 600.0; // 10 mins of 1 fps data
const double FGReplay::lt_list_time = 3600.0; // 1 hr of 10 spf data
// short term sample rate is as every frame
const double FGReplay::mt_dt = 0.5; // medium term sample rate (sec)
const double FGReplay::lt_dt = 5.0; // long term sample rate (sec)
/** /**
* Constructor * Constructor
*/ */
FGReplay::FGReplay() : FGReplay::FGReplay() :
last_replay_state(0) last_replay_state(0),
m_high_res_time(60.0),
m_medium_res_time(600.0),
m_low_res_time(3600.0),
m_medium_sample_rate(0.5), // medium term sample rate (sec)
m_long_sample_rate(5.0), // long term sample rate (sec)
m_pRecorder(new FGFlightRecorder("replay-config"))
{ {
} }
/** /**
* Destructor * Destructor
*/ */
@ -62,31 +58,35 @@ FGReplay::FGReplay() :
FGReplay::~FGReplay() FGReplay::~FGReplay()
{ {
clear(); clear();
delete m_pRecorder;
m_pRecorder = NULL;
} }
/** /**
* Clear all internal buffers. * Clear all internal buffers.
*/ */
void FGReplay::clear() void
FGReplay::clear()
{ {
while ( !short_term.empty() ) while ( !short_term.empty() )
{ {
delete short_term.front(); m_pRecorder->deleteRecord(short_term.front());
short_term.pop_front(); short_term.pop_front();
} }
while ( !medium_term.empty() ) while ( !medium_term.empty() )
{ {
delete medium_term.front(); m_pRecorder->deleteRecord(medium_term.front());
medium_term.pop_front(); medium_term.pop_front();
} }
while ( !long_term.empty() ) while ( !long_term.empty() )
{ {
delete long_term.front(); m_pRecorder->deleteRecord(long_term.front());
long_term.pop_front(); long_term.pop_front();
} }
while ( !recycler.empty() ) while ( !recycler.empty() )
{ {
delete recycler.front(); m_pRecorder->deleteRecord(recycler.front());
recycler.pop_front(); recycler.pop_front();
} }
} }
@ -95,12 +95,15 @@ void FGReplay::clear()
* Initialize the data structures * Initialize the data structures
*/ */
void FGReplay::init() void
FGReplay::init()
{ {
disable_replay = fgGetNode( "/sim/replay/disable", true ); disable_replay = fgGetNode("/sim/replay/disable", true);
replay_master = fgGetNode( "/sim/freeze/replay-state", true ); replay_master = fgGetNode("/sim/freeze/replay-state", true);
replay_time = fgGetNode( "/sim/replay/time", true); replay_time = fgGetNode("/sim/replay/time", true);
replay_looped = fgGetNode( "/sim/replay/looped", true); replay_time_str = fgGetNode("/sim/replay/time-str", true);
replay_looped = fgGetNode("/sim/replay/looped", true);
speed_up = fgGetNode("/sim/speed-up", true);
reinit(); reinit();
} }
@ -108,33 +111,50 @@ void FGReplay::init()
* Reset replay queues. * Reset replay queues.
*/ */
void FGReplay::reinit() void
FGReplay::reinit()
{ {
sim_time = 0.0; sim_time = 0.0;
last_mt_time = 0.0; last_mt_time = 0.0;
last_lt_time = 0.0; last_lt_time = 0.0;
// Make sure all queues are flushed // Flush queues
clear(); clear();
m_pRecorder->reinit();
m_high_res_time = fgGetDouble("/sim/replay/buffer/high-res-time", 60.0);
m_medium_res_time = fgGetDouble("/sim/replay/buffer/medium-res-time", 600.0); // 10 mins
m_low_res_time = fgGetDouble("/sim/replay/buffer/low-res-time", 3600.0); // 1 h
// short term sample rate is as every frame
m_medium_sample_rate = fgGetDouble("/sim/replay/buffer/medium-res-sample-dt", 0.5); // medium term sample rate (sec)
m_long_sample_rate = fgGetDouble("/sim/replay/buffer/low-res-sample-dt", 5.0); // long term sample rate (sec)
// Create an estimated nr of required ReplayData objects // Create an estimated nr of required ReplayData objects
// 120 is an estimated maximum frame rate. // 120 is an estimated maximum frame rate.
int estNrObjects = (int) ((st_list_time*120) + (mt_list_time*mt_dt) + int estNrObjects = (int) ((m_high_res_time*120) + (m_medium_res_time*m_medium_sample_rate) +
(lt_list_time*lt_dt)); (m_low_res_time*m_long_sample_rate));
for (int i = 0; i < estNrObjects; i++) for (int i = 0; i < estNrObjects; i++)
{ {
recycler.push_back(new FGReplayData); FGReplayData* r = m_pRecorder->createEmptyRecord();
if (r)
recycler.push_back(r);
else
{
SG_LOG(SG_SYSTEMS, SG_ALERT, "ReplaySystem: Out of memory!");
}
} }
replay_master->setIntValue(0); replay_master->setIntValue(0);
disable_replay->setBoolValue(0); disable_replay->setBoolValue(0);
replay_time->setDoubleValue(0); replay_time->setDoubleValue(0);
replay_time_str->setStringValue("");
} }
/** /**
* Bind to the property tree * Bind to the property tree
*/ */
void FGReplay::bind() void
FGReplay::bind()
{ {
} }
@ -143,26 +163,85 @@ void FGReplay::bind()
* Unbind from the property tree * Unbind from the property tree
*/ */
void FGReplay::unbind() void
FGReplay::unbind()
{ {
// nothing to unbind // nothing to unbind
} }
static void
printTimeStr(char* pStrBuffer,double _Time, bool ShowDecimal=true)
{
if (_Time<0)
_Time = 0;
unsigned int Time = (unsigned int) (_Time*10);
int h = Time/36000;
int m = (Time % 36000)/600;
int s = (Time % 600)/10;
int d = Time % 10;
if (h>0)
sprintf(pStrBuffer,"%u:%02u",h,m);
else
sprintf(pStrBuffer,"%u",m);
if (ShowDecimal)
sprintf(pStrBuffer,"%s:%02u.%u",pStrBuffer,s,d);
else
sprintf(pStrBuffer,"%s:%02u",pStrBuffer,s);
}
/** Start replay session
*/
bool
FGReplay::start()
{
// freeze the fdm, resume from sim pause
double StartTime = get_start_time();
double EndTime = get_end_time();
fgSetDouble("/sim/replay/start-time", StartTime);
fgSetDouble("/sim/replay/end-time", EndTime);
char StrBuffer[30];
printTimeStr(StrBuffer,StartTime,false);
fgSetString("/sim/replay/start-time-str", StrBuffer);
printTimeStr(StrBuffer,EndTime,false);
fgSetString("/sim/replay/end-time-str", StrBuffer);
unsigned long buffer_elements = short_term.size()+medium_term.size()+long_term.size();
fgSetDouble("/sim/replay/buffer-size-mbyte",
buffer_elements*m_pRecorder->getRecordSize() / (1024*1024.0));
if ((fgGetBool("/sim/freeze/master"))||
(0 == replay_master->getIntValue()))
fgSetString("/sim/messages/copilot", "Replay active. 'Esc' to stop.");
fgSetBool ("/sim/freeze/master", 0);
fgSetBool ("/sim/freeze/clock", 0);
if (0 == replay_master->getIntValue())
{
replay_master->setIntValue(1);
replay_time->setDoubleValue(-1);
replay_time_str->setStringValue("");
}
return true;
}
/** /**
* Update the saved data * Update the saved data
*/ */
void FGReplay::update( double dt ) void
FGReplay::update( double dt )
{ {
int current_replay_state = last_replay_state;
timingInfo.clear(); timingInfo.clear();
stamp("begin"); stamp("begin");
if ( disable_replay->getBoolValue() ) if ( disable_replay->getBoolValue() )
{ {
current_replay_state = replay_master->getIntValue();
replay_master->setIntValue(0); replay_master->setIntValue(0);
replay_time->setDoubleValue(0); replay_time->setDoubleValue(0);
replay_time_str->setStringValue("");
disable_replay->setBoolValue(0); disable_replay->setBoolValue(0);
speed_up->setDoubleValue(1.0);
fgSetString("/sim/messages/copilot", "Replay stopped");
} }
int replay_state = replay_master->getIntValue(); int replay_state = replay_master->getIntValue();
@ -180,8 +259,17 @@ void FGReplay::update( double dt )
if ((replay_state == 0)&& if ((replay_state == 0)&&
(last_replay_state > 0)) (last_replay_state > 0))
{ {
// replay was active, restore most recent frame if (current_replay_state == 3)
replay(DBL_MAX); {
// "my controls!" requested: pilot takes control at current replay position...
// May need to uncrash the aircraft here :)
fgSetBool("/sim/crashed", false);
}
else
{
// replay was active, restore most recent frame
replay(DBL_MAX);
}
// replay is finished, resume FDM // replay is finished, resume FDM
((FDMShell*) globals->get_subsystem("flight"))->getFDM()->resume(); ((FDMShell*) globals->get_subsystem("flight"))->getFDM()->resume();
} }
@ -195,30 +283,36 @@ void FGReplay::update( double dt )
// replay inactive, keep recording // replay inactive, keep recording
break; break;
case 1: case 1:
{
// replay active
double current_time = replay_time->getDoubleValue();
if (current_time<=0.0)
{ {
// replay active // initialize start time
double current_time = replay_time->getDoubleValue(); double startTime = get_start_time();
if (current_time<0.0) double endTime = get_end_time();
{ fgSetDouble( "/sim/replay/start-time", startTime );
// initialize start time fgSetDouble( "/sim/replay/end-time", endTime );
fgSetDouble( "/sim/replay/start-time", get_start_time() ); double duration = fgGetDouble( "/sim/replay/duration" );
fgSetDouble( "/sim/replay/end-time", get_end_time() ); if( duration && (duration < (endTime - startTime)) ) {
double duration = fgGetDouble( "/sim/replay/duration" ); current_time = endTime - duration;
if( duration && duration < (get_end_time() - get_start_time()) ) { } else {
current_time = get_end_time() - duration; current_time = startTime;
} else {
current_time = get_start_time();
}
} }
bool IsFinished = replay( replay_time->getDoubleValue() );
if ((IsFinished)&&(replay_looped->getBoolValue()))
current_time = -1;
else
current_time += dt * fgGetInt("/sim/speed-up");
replay_time->setDoubleValue(current_time);
} }
bool IsFinished = replay( replay_time->getDoubleValue() );
if (IsFinished)
current_time = (replay_looped->getBoolValue()) ? -1 : get_end_time()+0.01;
else
current_time += dt * speed_up->getDoubleValue();
replay_time->setDoubleValue(current_time);
char StrBuffer[30];
printTimeStr(StrBuffer,current_time);
replay_time_str->setStringValue((const char*)StrBuffer);
return; // don't record the replay session return; // don't record the replay session
case 2: }
case 2: // normal replay operation
case 3: // replay operation, prepare to resume normal flight at current replay position
// replay paused, no-op // replay paused, no-op
return; // don't record the replay session return; // don't record the replay session
default: default:
@ -228,78 +322,64 @@ void FGReplay::update( double dt )
// flight recording // flight recording
//cerr << "Recording replay" << endl; //cerr << "Recording replay" << endl;
sim_time += dt; sim_time += dt * speed_up->getDoubleValue();
// build the replay record
//FGNetFDM f;
//FGProps2NetFDM( &f, false );
// sanity check, don't collect data if FDM data isn't good // sanity check, don't collect data if FDM data isn't good
if (!fgGetBool("/sim/fdm-initialized", false)) { if (!fgGetBool("/sim/fdm-initialized", false)) {
return; return;
} }
//FGNetCtrls c; FGReplayData* r = record(sim_time);
//FGProps2NetCtrls( &c, false, false ); if (!r)
//stamp("point_04ba"); {
FGReplayData *r; SG_LOG(SG_SYSTEMS, SG_ALERT, "ReplaySystem: Out of memory!");
//stamp("point_04bb"); return;
if (!recycler.size()) {
stamp("Replay_01");
r = new FGReplayData;
stamp("Replay_02");
} else {
r = recycler.front();
recycler.pop_front();
//stamp("point_04be");
} }
r->sim_time = sim_time;
//r->ctrls = c;
//stamp("point_04e");
FGProps2NetFDM( &(r->fdm), false );
FGProps2NetCtrls( &(r->ctrls), false, false );
//r->fdm = f;
//stamp("point_05");
// update the short term list // update the short term list
//stamp("point_06"); //stamp("point_06");
short_term.push_back( r ); short_term.push_back( r );
//stamp("point_07"); //stamp("point_07");
FGReplayData *st_front = short_term.front(); FGReplayData *st_front = short_term.front();
if ( sim_time - st_front->sim_time > st_list_time ) {
while ( sim_time - st_front->sim_time > st_list_time ) { if (!st_front)
{
SG_LOG(SG_SYSTEMS, SG_ALERT, "ReplaySystem: Inconsistent data!");
}
if ( sim_time - st_front->sim_time > m_high_res_time ) {
while ( sim_time - st_front->sim_time > m_high_res_time ) {
st_front = short_term.front(); st_front = short_term.front();
recycler.push_back(st_front); recycler.push_back(st_front);
short_term.pop_front(); short_term.pop_front();
} }
//stamp("point_08"); //stamp("point_08");
// update the medium term list // update the medium term list
if ( sim_time - last_mt_time > mt_dt ) { if ( sim_time - last_mt_time > m_medium_sample_rate ) {
last_mt_time = sim_time; last_mt_time = sim_time;
st_front = short_term.front(); st_front = short_term.front();
medium_term.push_back( st_front ); medium_term.push_back( st_front );
short_term.pop_front(); short_term.pop_front();
FGReplayData *mt_front = medium_term.front(); FGReplayData *mt_front = medium_term.front();
if ( sim_time - mt_front->sim_time > mt_list_time ) { if ( sim_time - mt_front->sim_time > m_medium_res_time ) {
//stamp("point_09"); //stamp("point_09");
while ( sim_time - mt_front->sim_time > mt_list_time ) { while ( sim_time - mt_front->sim_time > m_medium_res_time ) {
mt_front = medium_term.front(); mt_front = medium_term.front();
recycler.push_back(mt_front); recycler.push_back(mt_front);
medium_term.pop_front(); medium_term.pop_front();
} }
// update the long term list // update the long term list
if ( sim_time - last_lt_time > lt_dt ) { if ( sim_time - last_lt_time > m_long_sample_rate ) {
last_lt_time = sim_time; last_lt_time = sim_time;
mt_front = medium_term.front(); mt_front = medium_term.front();
long_term.push_back( mt_front ); long_term.push_back( mt_front );
medium_term.pop_front(); medium_term.pop_front();
FGReplayData *lt_front = long_term.front(); FGReplayData *lt_front = long_term.front();
if ( sim_time - lt_front->sim_time > lt_list_time ) { if ( sim_time - lt_front->sim_time > m_low_res_time ) {
//stamp("point_10"); //stamp("point_10");
while ( sim_time - lt_front->sim_time > lt_list_time ) { while ( sim_time - lt_front->sim_time > m_low_res_time ) {
lt_front = long_term.front(); lt_front = long_term.front();
recycler.push_back(lt_front); recycler.push_back(lt_front);
long_term.pop_front(); long_term.pop_front();
@ -324,224 +404,37 @@ void FGReplay::update( double dt )
//stamp("point_finished"); //stamp("point_finished");
} }
FGReplayData*
static double weight( double data1, double data2, double ratio, FGReplay::record(double time)
bool rotational = false ) {
if ( rotational ) {
// special handling of rotational data
double tmp = data2 - data1;
if ( tmp > SGD_PI ) {
tmp -= SGD_2PI;
} else if ( tmp < -SGD_PI ) {
tmp += SGD_2PI;
}
return data1 + tmp * ratio;
} else {
// normal "linear" data
return data1 + ( data2 - data1 ) * ratio;
}
}
/**
* given two FGReplayData elements and a time, interpolate between them
*/
static void update_fdm( FGReplayData frame ) {
FGNetFDM2Props( &frame.fdm, false );
FGNetCtrls2Props( &frame.ctrls, false, false );
}
/**
* given two FGReplayData elements and a time, interpolate between them
*/
static FGReplayData interpolate( double time, FGReplayData f1, FGReplayData f2 )
{ {
FGReplayData result = f1; FGReplayData* r = NULL;
FGNetFDM fdm1 = f1.fdm; if (recycler.size())
FGNetFDM fdm2 = f2.fdm; {
r = recycler.front();
FGNetCtrls ctrls1 = f1.ctrls; recycler.pop_front();
FGNetCtrls ctrls2 = f2.ctrls;
double ratio = (time - f1.sim_time) / (f2.sim_time - f1.sim_time);
// Interpolate FDM data
// Positions
result.fdm.longitude = weight( fdm1.longitude, fdm2.longitude, ratio );
result.fdm.latitude = weight( fdm1.latitude, fdm2.latitude, ratio );
result.fdm.altitude = weight( fdm1.altitude, fdm2.altitude, ratio );
result.fdm.agl = weight( fdm1.agl, fdm2.agl, ratio );
result.fdm.phi = weight( fdm1.phi, fdm2.phi, ratio, true );
result.fdm.theta = weight( fdm1.theta, fdm2.theta, ratio, true );
result.fdm.psi = weight( fdm1.psi, fdm2.psi, ratio, true );
// Velocities
result.fdm.phidot = weight( fdm1.phidot, fdm2.phidot, ratio, true );
result.fdm.thetadot = weight( fdm1.thetadot, fdm2.thetadot, ratio, true );
result.fdm.psidot = weight( fdm1.psidot, fdm2.psidot, ratio, true );
result.fdm.vcas = weight( fdm1.vcas, fdm2.vcas, ratio );
result.fdm.climb_rate = weight( fdm1.climb_rate, fdm2.climb_rate, ratio );
result.fdm.v_north = weight( fdm1.v_north, fdm2.v_north, ratio );
result.fdm.v_east = weight( fdm1.v_east, fdm2.v_east, ratio );
result.fdm.v_down = weight( fdm1.v_down, fdm2.v_down, ratio );
result.fdm.v_wind_body_north
= weight( fdm1.v_wind_body_north, fdm2.v_wind_body_north, ratio );
result.fdm.v_wind_body_east
= weight( fdm1.v_wind_body_east, fdm2.v_wind_body_east, ratio );
result.fdm.v_wind_body_down
= weight( fdm1.v_wind_body_down, fdm2.v_wind_body_down, ratio );
// Stall
result.fdm.stall_warning
= weight( fdm1.stall_warning, fdm2.stall_warning, ratio );
// Accelerations
result.fdm.A_X_pilot = weight( fdm1.A_X_pilot, fdm2.A_X_pilot, ratio );
result.fdm.A_Y_pilot = weight( fdm1.A_Y_pilot, fdm2.A_Y_pilot, ratio );
result.fdm.A_Z_pilot = weight( fdm1.A_Z_pilot, fdm2.A_Z_pilot, ratio );
unsigned int i;
// Engine status
for ( i = 0; i < fdm1.num_engines; ++i ) {
result.fdm.eng_state[i] = fdm1.eng_state[i];
result.fdm.rpm[i] = weight( fdm1.rpm[i], fdm2.rpm[i], ratio );
result.fdm.fuel_flow[i]
= weight( fdm1.fuel_flow[i], fdm2.fuel_flow[i], ratio );
result.fdm.fuel_px[i]
= weight( fdm1.fuel_px[i], fdm2.fuel_px[i], ratio );
result.fdm.egt[i] = weight( fdm1.egt[i], fdm2.egt[i], ratio );
result.fdm.cht[i] = weight( fdm1.cht[i], fdm2.cht[i], ratio );
result.fdm.mp_osi[i] = weight( fdm1.mp_osi[i], fdm2.mp_osi[i], ratio );
result.fdm.tit[i] = weight( fdm1.tit[i], fdm2.tit[i], ratio );
result.fdm.oil_temp[i]
= weight( fdm1.oil_temp[i], fdm2.oil_temp[i], ratio );
result.fdm.oil_px[i] = weight( fdm1.oil_px[i], fdm2.oil_px[i], ratio );
} }
// Consumables r = m_pRecorder->capture(time, r);
for ( i = 0; i < fdm1.num_tanks; ++i ) {
result.fdm.fuel_quantity[i]
= weight( fdm1.fuel_quantity[i], fdm2.fuel_quantity[i], ratio );
}
// Gear status return r;
for ( i = 0; i < fdm1.num_wheels; ++i ) {
result.fdm.wow[i] = (int)(weight( fdm1.wow[i], fdm2.wow[i], ratio ));
result.fdm.gear_pos[i]
= weight( fdm1.gear_pos[i], fdm2.gear_pos[i], ratio );
result.fdm.gear_steer[i]
= weight( fdm1.gear_steer[i], fdm2.gear_steer[i], ratio );
result.fdm.gear_compression[i]
= weight( fdm1.gear_compression[i], fdm2.gear_compression[i],
ratio );
}
// Environment
result.fdm.cur_time = fdm1.cur_time;
result.fdm.warp = fdm1.warp;
result.fdm.visibility = weight( fdm1.visibility, fdm2.visibility, ratio );
// Control surface positions (normalized values)
result.fdm.elevator = weight( fdm1.elevator, fdm2.elevator, ratio );
result.fdm.left_flap = weight( fdm1.left_flap, fdm2.left_flap, ratio );
result.fdm.right_flap = weight( fdm1.right_flap, fdm2.right_flap, ratio );
result.fdm.left_aileron
= weight( fdm1.left_aileron, fdm2.left_aileron, ratio );
result.fdm.right_aileron
= weight( fdm1.right_aileron, fdm2.right_aileron, ratio );
result.fdm.rudder = weight( fdm1.rudder, fdm2.rudder, ratio );
result.fdm.speedbrake = weight( fdm1.speedbrake, fdm2.speedbrake, ratio );
result.fdm.spoilers = weight( fdm1.spoilers, fdm2.spoilers, ratio );
// Interpolate Control input data
// Aero controls
result.ctrls.aileron = weight( ctrls1.aileron, ctrls2.aileron, ratio );
result.ctrls.elevator = weight( ctrls1.elevator, ctrls2.elevator, ratio );
result.ctrls.rudder = weight( ctrls1.rudder, ctrls2.rudder, ratio );
result.ctrls.aileron_trim
= weight( ctrls1.aileron_trim, ctrls2.aileron_trim, ratio );
result.ctrls.elevator_trim
= weight( ctrls1.elevator_trim, ctrls2.elevator_trim, ratio );
result.ctrls.rudder_trim
= weight( ctrls1.rudder_trim, ctrls2.rudder_trim, ratio );
result.ctrls.flaps = weight( ctrls1.flaps, ctrls2.flaps, ratio );
result.ctrls.flaps_power = ctrls1.flaps_power;
result.ctrls.flap_motor_ok = ctrls1.flap_motor_ok;
// Engine controls
for ( i = 0; i < ctrls1.num_engines; ++i ) {
result.ctrls.master_bat[i] = ctrls1.master_bat[i];
result.ctrls.master_alt[i] = ctrls1.master_alt[i];
result.ctrls.magnetos[i] = ctrls1.magnetos[i];
result.ctrls.starter_power[i] = ctrls1.starter_power[i];
result.ctrls.throttle[i]
= weight( ctrls1.throttle[i], ctrls2.throttle[i], ratio );
result.ctrls.mixture[i]
= weight( ctrls1.mixture[i], ctrls2.mixture[i], ratio );
result.ctrls.fuel_pump_power[i] = ctrls1.fuel_pump_power[i];
result.ctrls.prop_advance[i]
= weight( ctrls1.prop_advance[i], ctrls2.prop_advance[i], ratio );
result.ctrls.engine_ok[i] = ctrls1.engine_ok[i];
result.ctrls.mag_left_ok[i] = ctrls1.mag_left_ok[i];
result.ctrls.mag_right_ok[i] = ctrls1.mag_right_ok[i];
result.ctrls.spark_plugs_ok[i] = ctrls1.spark_plugs_ok[i];
result.ctrls.oil_press_status[i] = ctrls1.oil_press_status[i];
result.ctrls.fuel_pump_ok[i] = ctrls1.fuel_pump_ok[i];
}
// Fuel management
for ( i = 0; i < ctrls1.num_tanks; ++i ) {
result.ctrls.fuel_selector[i] = ctrls1.fuel_selector[i];
}
// Brake controls
result.ctrls.brake_left
= weight( ctrls1.brake_left, ctrls2.brake_left, ratio );
result.ctrls.brake_right
= weight( ctrls1.brake_right, ctrls2.brake_right, ratio );
result.ctrls.brake_parking
= weight( ctrls1.brake_parking, ctrls2.brake_parking, ratio );
// Landing Gear
result.ctrls.gear_handle = ctrls1.gear_handle;
// Switches
result.ctrls.turbulence_norm = ctrls1.turbulence_norm;
// wind and turbulance
result.ctrls.wind_speed_kt
= weight( ctrls1.wind_speed_kt, ctrls2.wind_speed_kt, ratio );
result.ctrls.wind_dir_deg
= weight( ctrls1.wind_dir_deg, ctrls2.wind_dir_deg, ratio );
result.ctrls.turbulence_norm
= weight( ctrls1.turbulence_norm, ctrls2.turbulence_norm, ratio );
// other information about environment
result.ctrls.hground = weight( ctrls1.hground, ctrls2.hground, ratio );
result.ctrls.magvar = weight( ctrls1.magvar, ctrls2.magvar, ratio );
// simulation control
result.ctrls.speedup = ctrls1.speedup;
result.ctrls.freeze = ctrls1.freeze;
return result;
} }
/** /**
* interpolate a specific time from a specific list * interpolate a specific time from a specific list
*/ */
static void interpolate( double time, const replay_list_type &list ) { void
FGReplay::interpolate( double time, const replay_list_type &list)
{
// sanity checking // sanity checking
if ( list.size() == 0 ) { if ( list.size() == 0 )
{
// handle empty list // handle empty list
return; return;
} else if ( list.size() == 1 ) { } else if ( list.size() == 1 )
{
// handle list size == 1 // handle list size == 1
update_fdm( (*list[0]) ); replay(time, list[0]);
return; return;
} }
@ -549,9 +442,9 @@ static void interpolate( double time, const replay_list_type &list ) {
unsigned int first = 0; unsigned int first = 0;
unsigned int mid = ( last + first ) / 2; unsigned int mid = ( last + first ) / 2;
bool done = false; bool done = false;
while ( !done ) { while ( !done )
{
// cout << " " << first << " <=> " << last << endl; // cout << " " << first << " <=> " << last << endl;
if ( last == first ) { if ( last == first ) {
done = true; done = true;
@ -568,19 +461,17 @@ static void interpolate( double time, const replay_list_type &list ) {
} }
} }
FGReplayData result = interpolate( time, (*list[mid]), (*list[mid+1]) ); replay(time, list[mid+1], list[mid]);
update_fdm( result );
} }
/** /**
* Replay a saved frame based on time, interpolate from the two * Replay a saved frame based on time, interpolate from the two
* nearest saved frames. * nearest saved frames.
* Returns true when replay sequence has finished, false otherwise. * Returns true when replay sequence has finished, false otherwise.
*/ */
bool FGReplay::replay( double time ) { bool
FGReplay::replay( double time ) {
// cout << "replay: " << time << " "; // cout << "replay: " << time << " ";
// find the two frames to interpolate between // find the two frames to interpolate between
double t1, t2; double t1, t2;
@ -590,7 +481,7 @@ bool FGReplay::replay( double time ) {
t2 = short_term.front()->sim_time; t2 = short_term.front()->sim_time;
if ( time > t1 ) { if ( time > t1 ) {
// replay the most recent frame // replay the most recent frame
update_fdm( (*short_term.back()) ); replay( time, short_term.back() );
// replay is finished now // replay is finished now
return true; return true;
// cout << "first frame" << endl; // cout << "first frame" << endl;
@ -600,11 +491,9 @@ bool FGReplay::replay( double time ) {
} else if ( medium_term.size() > 0 ) { } else if ( medium_term.size() > 0 ) {
t1 = short_term.front()->sim_time; t1 = short_term.front()->sim_time;
t2 = medium_term.back()->sim_time; t2 = medium_term.back()->sim_time;
if ( time <= t1 && time >= t2 ) { if ( time <= t1 && time >= t2 )
FGReplayData result = interpolate( time, {
(*medium_term.back()), replay(time, medium_term.back(), short_term.front());
(*short_term.front()) );
update_fdm( result );
// cout << "from short/medium term" << endl; // cout << "from short/medium term" << endl;
} else { } else {
t1 = medium_term.back()->sim_time; t1 = medium_term.back()->sim_time;
@ -615,11 +504,9 @@ bool FGReplay::replay( double time ) {
} else if ( long_term.size() > 0 ) { } else if ( long_term.size() > 0 ) {
t1 = medium_term.front()->sim_time; t1 = medium_term.front()->sim_time;
t2 = long_term.back()->sim_time; t2 = long_term.back()->sim_time;
if ( time <= t1 && time >= t2 ) { if ( time <= t1 && time >= t2 )
FGReplayData result = interpolate( time, {
(*long_term.back()), replay(time, long_term.back(), medium_term.front());
(*medium_term.front()));
update_fdm( result );
// cout << "from medium/long term" << endl; // cout << "from medium/long term" << endl;
} else { } else {
t1 = long_term.back()->sim_time; t1 = long_term.back()->sim_time;
@ -629,19 +516,19 @@ bool FGReplay::replay( double time ) {
// cout << "from long term" << endl; // cout << "from long term" << endl;
} else { } else {
// replay the oldest long term frame // replay the oldest long term frame
update_fdm( (*long_term.front()) ); replay(time, long_term.front());
// cout << "oldest long term frame" << endl; // cout << "oldest long term frame" << endl;
} }
} }
} else { } else {
// replay the oldest medium term frame // replay the oldest medium term frame
update_fdm( (*medium_term.front()) ); replay(time, medium_term.front());
// cout << "oldest medium term frame" << endl; // cout << "oldest medium term frame" << endl;
} }
} }
} else { } else {
// replay the oldest short term frame // replay the oldest short term frame
update_fdm( (*short_term.front()) ); replay(time, short_term.front());
// cout << "oldest short term frame" << endl; // cout << "oldest short term frame" << endl;
} }
} else { } else {
@ -651,23 +538,41 @@ bool FGReplay::replay( double time ) {
return false; return false;
} }
/**
* given two FGReplayData elements and a time, interpolate between them
*/
void
FGReplay::replay(double time, FGReplayData* pCurrentFrame, FGReplayData* pOldFrame)
{
m_pRecorder->replay(time,pCurrentFrame,pOldFrame);
}
double FGReplay::get_start_time() { double
if ( long_term.size() > 0 ) { FGReplay::get_start_time()
return (*long_term.front()).sim_time; {
} else if ( medium_term.size() > 0 ) { if ( long_term.size() > 0 )
return (*medium_term.front()).sim_time; {
} else if ( short_term.size() ) { return long_term.front()->sim_time;
return (*short_term.front()).sim_time; } else if ( medium_term.size() > 0 )
} else { {
return medium_term.front()->sim_time;
} else if ( short_term.size() )
{
return short_term.front()->sim_time;
} else
{
return 0.0; return 0.0;
} }
} }
double FGReplay::get_end_time() { double
if ( short_term.size() ) { FGReplay::get_end_time()
return (*short_term.back()).sim_time; {
} else { if ( short_term.size() )
{
return short_term.back()->sim_time;
} else
{
return 0.0; return 0.0;
} }
} }

View file

@ -1,6 +1,6 @@
// replay.hxx - a system to record and replay FlightGear flights // replay.hxx - a system to record and replay FlightGear flights
// //
// Written by Curtis Olson, started Juley 2003. // Written by Curtis Olson, started July 2003.
// //
// Copyright (C) 2003 Curtis L. Olson - http://www.flightgear.org/~curt // Copyright (C) 2003 Curtis L. Olson - http://www.flightgear.org/~curt
// //
@ -36,20 +36,15 @@
#include <simgear/props/props.hxx> #include <simgear/props/props.hxx>
#include <simgear/structure/subsystem_mgr.hxx> #include <simgear/structure/subsystem_mgr.hxx>
#include <Network/net_ctrls.hxx>
#include <Network/net_fdm.hxx>
using std::deque; using std::deque;
class FGFlightRecorder;
class FGReplayData { typedef struct {
public:
double sim_time; double sim_time;
FGNetFDM fdm; char raw_data;
FGNetCtrls ctrls; /* more data here, hidden to the outside world */
}; } FGReplayData;
typedef deque < FGReplayData *> replay_list_type; typedef deque < FGReplayData *> replay_list_type;
@ -73,22 +68,18 @@ public:
virtual void bind(); virtual void bind();
virtual void unbind(); virtual void unbind();
virtual void update( double dt ); virtual void update( double dt );
bool start();
private:
void clear();
FGReplayData* record(double time);
void interpolate(double time, const replay_list_type &list);
void replay(double time, FGReplayData* pCurrentFrame, FGReplayData* pOldFrame=NULL);
bool replay( double time ); bool replay( double time );
double get_start_time(); double get_start_time();
double get_end_time(); double get_end_time();
private:
void clear();
static const double st_list_time; // 60 secs of high res data
static const double mt_list_time; // 10 mins of 1 fps data
static const double lt_list_time; // 1 hr of 10 spf data
// short term sample rate is as every frame
static const double mt_dt; // medium term sample rate (sec)
static const double lt_dt; // long term sample rate (sec)
double sim_time; double sim_time;
double last_mt_time; double last_mt_time;
double last_lt_time; double last_lt_time;
@ -101,7 +92,18 @@ private:
SGPropertyNode_ptr disable_replay; SGPropertyNode_ptr disable_replay;
SGPropertyNode_ptr replay_master; SGPropertyNode_ptr replay_master;
SGPropertyNode_ptr replay_time; SGPropertyNode_ptr replay_time;
SGPropertyNode_ptr replay_time_str;
SGPropertyNode_ptr replay_looped; SGPropertyNode_ptr replay_looped;
SGPropertyNode_ptr speed_up;
double m_high_res_time; // default: 60 secs of high res data
double m_medium_res_time; // default: 10 mins of 1 fps data
double m_low_res_time; // default: 1 hr of 10 spf data
// short term sample rate is as every frame
double m_medium_sample_rate; // medium term sample rate (sec)
double m_long_sample_rate; // long term sample rate (sec)
FGFlightRecorder* m_pRecorder;
}; };

View file

@ -478,25 +478,30 @@ private:
int freqKhz = atoi(token[1].c_str()); int freqKhz = atoi(token[1].c_str());
int rangeNm = 50; int rangeNm = 50;
FGPositioned::Type ty; FGPositioned::Type ty;
switch (lineId) { // Make sure we only pass on stations with at least a name
case 50: if (token.size() >2){
ty = FGPositioned::FREQ_AWOS;
if (token[2] == "ATIS") { switch (lineId) {
ty = FGPositioned::FREQ_ATIS; case 50:
ty = FGPositioned::FREQ_AWOS;
if (token[2] == "ATIS") {
ty = FGPositioned::FREQ_ATIS;
}
break;
case 51: ty = FGPositioned::FREQ_UNICOM; break;
case 52: ty = FGPositioned::FREQ_CLEARANCE; break;
case 53: ty = FGPositioned::FREQ_GROUND; break;
case 54: ty = FGPositioned::FREQ_TOWER; break;
case 55:
case 56: ty = FGPositioned::FREQ_APP_DEP; break;
default:
throw sg_range_exception("unupported apt.dat comm station type");
} }
break;
case 51: ty = FGPositioned::FREQ_UNICOM; break; commStations.push_back(new flightgear::CommStation(token[2], ty, pos, rangeNm, freqKhz));
case 52: ty = FGPositioned::FREQ_CLEARANCE; break;
case 53: ty = FGPositioned::FREQ_GROUND; break;
case 54: ty = FGPositioned::FREQ_TOWER; break;
case 55:
case 56: ty = FGPositioned::FREQ_APP_DEP; break;
default:
throw sg_range_exception("unupported apt.dat comm station type");
} }
else SG_LOG( SG_GENERAL, SG_DEBUG, "Found unnamed comm. Skipping: " << lineId);
commStations.push_back(new flightgear::CommStation(token[2], ty, pos, rangeNm, freqKhz));
} }
}; };

View file

@ -35,93 +35,117 @@ class FGEnvironment;
class FGAirportDynamics { class FGAirportDynamics {
private: private:
FGAirport* _ap; FGAirport* _ap;
FGParkingVec parkings; FGParkingVec parkings;
FGRunwayPreference rwyPrefs; FGRunwayPreference rwyPrefs;
FGSidStar SIDs; FGSidStar SIDs;
FGStartupController startupController; FGStartupController startupController;
FGGroundNetwork groundNetwork; FGGroundNetwork groundNetwork;
FGTowerController towerController; FGTowerController towerController;
FGApproachController approachController; FGApproachController approachController;
time_t lastUpdate; time_t lastUpdate;
std::string prevTrafficType; std::string prevTrafficType;
stringVec landing; stringVec landing;
stringVec takeoff; stringVec takeoff;
stringVec milActive, comActive, genActive, ulActive; stringVec milActive, comActive, genActive, ulActive;
stringVec *currentlyActive; stringVec *currentlyActive;
intVec freqAwos; // </AWOS> intVec freqAwos; // </AWOS>
intVec freqUnicom; // </UNICOM> intVec freqUnicom; // </UNICOM>
intVec freqClearance;// </CLEARANCE> intVec freqClearance;// </CLEARANCE>
intVec freqGround; // </GROUND> intVec freqGround; // </GROUND>
intVec freqTower; // </TOWER> intVec freqTower; // </TOWER>
intVec freqApproach; // </APPROACH> intVec freqApproach; // </APPROACH>
int atisSequenceIndex; int atisSequenceIndex;
double atisSequenceTimeStamp; double atisSequenceTimeStamp;
std::string chooseRunwayFallback(); std::string chooseRunwayFallback();
bool innerGetActiveRunway(const std::string &trafficType, int action, std::string &runway, double heading); bool innerGetActiveRunway(const std::string &trafficType, int action, std::string &runway, double heading);
std::string chooseRwyByHeading(stringVec rwys, double heading); std::string chooseRwyByHeading(stringVec rwys, double heading);
double elevation; double elevation;
public: public:
FGAirportDynamics(FGAirport* ap); FGAirportDynamics(FGAirport* ap);
~FGAirportDynamics(); ~FGAirportDynamics();
void addAwosFreq (int val) { freqAwos.push_back(val); }; void addAwosFreq (int val) {
void addUnicomFreq (int val) { freqUnicom.push_back(val); }; freqAwos.push_back(val);
void addClearanceFreq(int val) { freqClearance.push_back(val); }; };
void addGroundFreq (int val) { freqGround.push_back(val); }; void addUnicomFreq (int val) {
void addTowerFreq (int val) { freqTower.push_back(val); }; freqUnicom.push_back(val);
void addApproachFreq (int val) { freqApproach.push_back(val); }; };
void addClearanceFreq(int val) {
freqClearance.push_back(val);
};
void addGroundFreq (int val) {
freqGround.push_back(val);
};
void addTowerFreq (int val) {
freqTower.push_back(val);
};
void addApproachFreq (int val) {
freqApproach.push_back(val);
};
void init(); void init();
double getLongitude() const; double getLongitude() const;
// Returns degrees // Returns degrees
double getLatitude() const; double getLatitude() const;
// Returns ft // Returns ft
double getElevation() const; double getElevation() const;
const string& getId() const; const string& getId() const;
void getActiveRunway(const string& trafficType, int action, string& runway, double heading); void getActiveRunway(const string& trafficType, int action, string& runway, double heading);
void addParking(FGParking& park); void addParking(FGParking& park);
bool getAvailableParking(double *lat, double *lon, bool getAvailableParking(double *lat, double *lon,
double *heading, int *gate, double rad, const string& fltype, double *heading, int *gate, double rad, const string& fltype,
const string& acType, const string& airline); const string& acType, const string& airline);
void getParking (int id, double *lat, double* lon, double *heading); void getParking (int id, double *lat, double* lon, double *heading);
FGParking *getParking(int i); FGParking *getParking(int i);
void releaseParking(int id); void releaseParking(int id);
string getParkingName(int i); string getParkingName(int i);
int getNrOfParkings() { return parkings.size(); }; int getNrOfParkings() {
//FGAirport *getAddress() { return this; }; return parkings.size();
//const string &getName() const { return _name;}; };
// Returns degrees //FGAirport *getAddress() { return this; };
//const string &getName() const { return _name;};
// Returns degrees
// Departure / Arrival procedures // Departure / Arrival procedures
FGSidStar * getSIDs() { return &SIDs; }; FGSidStar * getSIDs() {
FGAIFlightPlan * getSID(string activeRunway, double heading); return &SIDs;
};
FGAIFlightPlan * getSID(string activeRunway, double heading);
// ATC related functions. // ATC related functions.
FGStartupController *getStartupController() { return &startupController; }; FGStartupController *getStartupController() {
FGGroundNetwork *getGroundNetwork() { return &groundNetwork; }; return &startupController;
FGTowerController *getTowerController() { return &towerController; }; };
FGApproachController *getApproachController() { return &approachController; }; FGGroundNetwork *getGroundNetwork() {
return &groundNetwork;
};
FGTowerController *getTowerController() {
return &towerController;
};
FGApproachController *getApproachController() {
return &approachController;
};
int getGroundFrequency(unsigned leg); int getGroundFrequency(unsigned leg);
int getTowerFrequency (unsigned nr); int getTowerFrequency (unsigned nr);
/// get current ATIS sequence letter /// get current ATIS sequence letter
const std::string getAtisSequence(); const std::string getAtisSequence();
/// get the current ATIS sequence number, updating it if necessary /// get the current ATIS sequence number, updating it if necessary
int updateAtisSequence(int interval, bool forceUpdate); int updateAtisSequence(int interval, bool forceUpdate);
void setRwyUse(const FGRunwayPreference& ref); void setRwyUse(const FGRunwayPreference& ref);
}; };

View file

@ -205,6 +205,11 @@ bool compare_segments(FGTaxiSegment * a, FGTaxiSegment * b)
return (*a) < (*b); return (*a) < (*b);
} }
bool compare_trafficrecords(FGTrafficRecord a, FGTrafficRecord b)
{
return (a.getIntentions().size() < b.getIntentions().size());
}
FGGroundNetwork::FGGroundNetwork() FGGroundNetwork::FGGroundNetwork()
{ {
hasNetwork = false; hasNetwork = false;
@ -244,18 +249,18 @@ FGGroundNetwork::~FGGroundNetwork()
} }
cachefile << "[GroundNetcachedata:ref:2011:09:04]" << endl; cachefile << "[GroundNetcachedata:ref:2011:09:04]" << endl;
for (FGTaxiNodeVectorIterator node = nodes.begin(); for (FGTaxiNodeVectorIterator node = nodes.begin();
node != nodes.end(); node++) { node != nodes.end(); node++) {
if (saveData) { if (saveData) {
cachefile << (*node)->getIndex () << " " cachefile << (*node)->getIndex () << " "
<< (*node)->getElevation () << " " << (*node)->getElevation () << " "
<< endl; << endl;
} }
delete(*node); delete(*node);
} }
nodes.clear(); nodes.clear();
pushBackNodes.clear(); pushBackNodes.clear();
for (FGTaxiSegmentVectorIterator seg = segments.begin(); for (FGTaxiSegmentVectorIterator seg = segments.begin();
seg != segments.end(); seg++) { seg != segments.end(); seg++) {
delete(*seg); delete(*seg);
} }
segments.clear(); segments.clear();
@ -288,12 +293,12 @@ void FGGroundNetwork::saveElevationCache() {
} }
cachefile << "[GroundNetcachedata:ref:2011:09:04]" << endl; cachefile << "[GroundNetcachedata:ref:2011:09:04]" << endl;
for (FGTaxiNodeVectorIterator node = nodes.begin(); for (FGTaxiNodeVectorIterator node = nodes.begin();
node != nodes.end(); node++) { node != nodes.end(); node++) {
if (saveData) { if (saveData) {
cachefile << (*node)->getIndex () << " " cachefile << (*node)->getIndex () << " "
<< (*node)->getElevation () << " " << (*node)->getElevation () << " "
<< endl; << endl;
} }
} }
if (saveData) { if (saveData) {
cachefile.close(); cachefile.close();
@ -406,11 +411,11 @@ void FGGroundNetwork::init()
data >> revisionStr; data >> revisionStr;
if (revisionStr != "[GroundNetcachedata:ref:2011:09:04]") { if (revisionStr != "[GroundNetcachedata:ref:2011:09:04]") {
SG_LOG(SG_GENERAL, SG_ALERT,"GroundNetwork Warning: discarding outdated cachefile " << SG_LOG(SG_GENERAL, SG_ALERT,"GroundNetwork Warning: discarding outdated cachefile " <<
cacheData.c_str() << " for Airport " << airport); cacheData.c_str() << " for Airport " << airport);
} else { } else {
for (FGTaxiNodeVectorIterator i = nodes.begin(); for (FGTaxiNodeVectorIterator i = nodes.begin();
i != nodes.end(); i != nodes.end();
i++) { i++) {
(*i)->setElevation(parent->getElevation() * SG_FEET_TO_METER); (*i)->setElevation(parent->getElevation() * SG_FEET_TO_METER);
data >> index >> elev; data >> index >> elev;
if (data.eof()) if (data.eof())
@ -435,7 +440,7 @@ int FGGroundNetwork::findNearestNode(const SGGeod & aGeod)
int index = -1; int index = -1;
for (FGTaxiNodeVectorIterator itr = nodes.begin(); itr != nodes.end(); for (FGTaxiNodeVectorIterator itr = nodes.begin(); itr != nodes.end();
itr++) { itr++) {
double d = SGGeodesy::distanceM(aGeod, (*itr)->getGeod()); double d = SGGeodesy::distanceM(aGeod, (*itr)->getGeod());
if (d < minDist) { if (d < minDist) {
minDist = d; minDist = d;
@ -488,7 +493,7 @@ FGTaxiSegment *FGGroundNetwork::findSegment(unsigned idx)
FGTaxiRoute FGGroundNetwork::findShortestRoute(int start, int end, FGTaxiRoute FGGroundNetwork::findShortestRoute(int start, int end,
bool fullSearch) bool fullSearch)
{ {
//implements Dijkstra's algorithm to find shortest distance route from start to end //implements Dijkstra's algorithm to find shortest distance route from start to end
//taken from http://en.wikipedia.org/wiki/Dijkstra's_algorithm //taken from http://en.wikipedia.org/wiki/Dijkstra's_algorithm
@ -504,7 +509,7 @@ FGTaxiRoute FGGroundNetwork::findShortestRoute(int start, int end,
} }
for (FGTaxiNodeVectorIterator for (FGTaxiNodeVectorIterator
itr = currNodesSet->begin(); itr != currNodesSet->end(); itr++) { itr = currNodesSet->begin(); itr != currNodesSet->end(); itr++) {
(*itr)->setPathScore(HUGE_VAL); //infinity by all practical means (*itr)->setPathScore(HUGE_VAL); //infinity by all practical means
(*itr)->setPreviousNode(0); // (*itr)->setPreviousNode(0); //
(*itr)->setPreviousSeg(0); // (*itr)->setPreviousSeg(0); //
@ -520,7 +525,7 @@ FGTaxiRoute FGGroundNetwork::findShortestRoute(int start, int end,
while (!unvisited.empty()) { while (!unvisited.empty()) {
FGTaxiNode *best = *(unvisited.begin()); FGTaxiNode *best = *(unvisited.begin());
for (FGTaxiNodeVectorIterator for (FGTaxiNodeVectorIterator
itr = unvisited.begin(); itr != unvisited.end(); itr++) { itr = unvisited.begin(); itr != unvisited.end(); itr++) {
if ((*itr)->getPathScore() < best->getPathScore()) if ((*itr)->getPathScore() < best->getPathScore())
best = (*itr); best = (*itr);
} }
@ -533,8 +538,8 @@ FGTaxiRoute FGGroundNetwork::findShortestRoute(int start, int end,
break; break;
} else { } else {
for (FGTaxiSegmentVectorIterator for (FGTaxiSegmentVectorIterator
seg = best->getBeginRoute(); seg = best->getBeginRoute();
seg != best->getEndRoute(); seg++) { seg != best->getEndRoute(); seg++) {
if (fullSearch || (*seg)->isPushBack()) { if (fullSearch || (*seg)->isPushBack()) {
FGTaxiNode *tgt = (*seg)->getEnd(); FGTaxiNode *tgt = (*seg)->getEnd();
double alt = double alt =
@ -623,7 +628,8 @@ void FGGroundNetwork::announcePosition(int id,
rec.setPositionAndHeading(lat, lon, heading, speed, alt); rec.setPositionAndHeading(lat, lon, heading, speed, alt);
rec.setRadius(radius); // only need to do this when creating the record. rec.setRadius(radius); // only need to do this when creating the record.
rec.setAircraft(aircraft); rec.setAircraft(aircraft);
activeTraffic.push_back(rec); activeTraffic.push_front(rec);
} else { } else {
i->setPositionAndIntentions(currentPosition, intendedRoute); i->setPositionAndIntentions(currentPosition, intendedRoute);
i->setPositionAndHeading(lat, lon, heading, speed, alt); i->setPositionAndHeading(lat, lon, heading, speed, alt);
@ -666,7 +672,7 @@ void FGGroundNetwork::signOff(int id)
* 9 = Acknowledge switch tower frequency * 9 = Acknowledge switch tower frequency
*************************************************************************************************************************/ *************************************************************************************************************************/
bool FGGroundNetwork::checkTransmissionState(int minState, int maxState, TrafficVectorIterator i, time_t now, AtcMsgId msgId, bool FGGroundNetwork::checkTransmissionState(int minState, int maxState, TrafficVectorIterator i, time_t now, AtcMsgId msgId,
AtcMsgDir msgDir) AtcMsgDir msgDir)
{ {
int state = i->getState(); int state = i->getState();
if ((state >= minState) && (state <= maxState) && available) { if ((state >= minState) && (state <= maxState) && available) {
@ -676,10 +682,10 @@ bool FGGroundNetwork::checkTransmissionState(int minState, int maxState, Traffic
int n = trans_num->getIntValue(); int n = trans_num->getIntValue();
if (n == 0) { if (n == 0) {
trans_num->setIntValue(-1); trans_num->setIntValue(-1);
// PopupCallback(n); // PopupCallback(n);
//cerr << "Selected transmission message " << n << endl; //cerr << "Selected transmission message " << n << endl;
FGATCManager *atc = (FGATCManager*) globals->get_subsystem("atc"); FGATCManager *atc = (FGATCManager*) globals->get_subsystem("atc");
FGATCDialogNew::instance()->removeEntry(1); FGATCDialogNew::instance()->removeEntry(1);
} else { } else {
//cerr << "creating message for " << i->getAircraft()->getCallSign() << endl; //cerr << "creating message for " << i->getAircraft()->getCallSign() << endl;
transmit(&(*i), msgId, msgDir, false); transmit(&(*i), msgId, msgDir, false);
@ -696,8 +702,8 @@ bool FGGroundNetwork::checkTransmissionState(int minState, int maxState, Traffic
} }
void FGGroundNetwork::updateAircraftInformation(int id, double lat, double lon, void FGGroundNetwork::updateAircraftInformation(int id, double lat, double lon,
double heading, double speed, double alt, double heading, double speed, double alt,
double dt) double dt)
{ {
time_t currentTime = time(NULL); time_t currentTime = time(NULL);
if (nextSave < currentTime) { if (nextSave < currentTime) {
@ -747,9 +753,9 @@ void FGGroundNetwork::updateAircraftInformation(int id, double lat, double lon,
bool needsTaxiClearance = current->getAircraft()->getTaxiClearanceRequest(); bool needsTaxiClearance = current->getAircraft()->getTaxiClearanceRequest();
if (!needsTaxiClearance) { if (!needsTaxiClearance) {
checkHoldPosition(id, lat, lon, heading, speed, alt); checkHoldPosition(id, lat, lon, heading, speed, alt);
if (checkForCircularWaits(id)) { //if (checkForCircularWaits(id)) {
i->setResolveCircularWait(); // i->setResolveCircularWait();
} //}
} else { } else {
current->setHoldPosition(true); current->setHoldPosition(true);
int state = current->getState(); int state = current->getState();
@ -791,11 +797,11 @@ void FGGroundNetwork::updateAircraftInformation(int id, double lat, double lon,
*/ */
void FGGroundNetwork::checkSpeedAdjustment(int id, double lat, void FGGroundNetwork::checkSpeedAdjustment(int id, double lat,
double lon, double heading, double lon, double heading,
double speed, double alt) double speed, double alt)
{ {
TrafficVectorIterator current, closest; TrafficVectorIterator current, closest, closestOnNetwork;
TrafficVectorIterator i = activeTraffic.begin(); TrafficVectorIterator i = activeTraffic.begin();
bool otherReasonToSlowDown = false; bool otherReasonToSlowDown = false;
bool previousInstruction; bool previousInstruction;
@ -825,7 +831,7 @@ void FGGroundNetwork::checkSpeedAdjustment(int id, double lat,
//TrafficVector iterator closest; //TrafficVector iterator closest;
closest = current; closest = current;
for (TrafficVectorIterator i = activeTraffic.begin(); for (TrafficVectorIterator i = activeTraffic.begin();
i != activeTraffic.end(); i++) { i != activeTraffic.end(); i++) {
if (i == current) { if (i == current) {
continue; continue;
} }
@ -840,14 +846,16 @@ void FGGroundNetwork::checkSpeedAdjustment(int id, double lat,
if ((dist < mindist) && (bearing < 60.0)) { if ((dist < mindist) && (bearing < 60.0)) {
mindist = dist; mindist = dist;
closest = i; closest = i;
closestOnNetwork = i;
minbearing = bearing; minbearing = bearing;
} }
} }
//Check traffic at the tower controller //Check traffic at the tower controller
if (towerController->hasActiveTraffic()) { if (towerController->hasActiveTraffic()) {
for (TrafficVectorIterator i = for (TrafficVectorIterator i =
towerController->getActiveTraffic().begin(); towerController->getActiveTraffic().begin();
i != towerController->getActiveTraffic().end(); i++) { i != towerController->getActiveTraffic().end(); i++) {
//cerr << "Comparing " << current->getId() << " and " << i->getId() << endl; //cerr << "Comparing " << current->getId() << " and " << i->getId() << endl;
SGGeod other(SGGeod::fromDegM(i->getLongitude(), SGGeod other(SGGeod::fromDegM(i->getLongitude(),
i->getLatitude(), i->getLatitude(),
@ -887,9 +895,9 @@ void FGGroundNetwork::checkSpeedAdjustment(int id, double lat,
} }
*/ */
current->clearSpeedAdjustment(); current->clearSpeedAdjustment();
bool needBraking = false;
if (current->checkPositionAndIntentions(*closest) if (current->checkPositionAndIntentions(*closest)
|| otherReasonToSlowDown) { || otherReasonToSlowDown) {
double maxAllowableDistance = double maxAllowableDistance =
(1.1 * current->getRadius()) + (1.1 * current->getRadius()) +
(1.1 * closest->getRadius()); (1.1 * closest->getRadius());
@ -901,12 +909,13 @@ void FGGroundNetwork::checkSpeedAdjustment(int id, double lat,
if (closest->getId() != current->getId()) { if (closest->getId() != current->getId()) {
current->setSpeedAdjustment(closest->getSpeed() * current->setSpeedAdjustment(closest->getSpeed() *
(mindist / 100)); (mindist / 100));
needBraking = true;
if ( if (
closest->getAircraft()->getTakeOffStatus() && closest->getAircraft()->getTakeOffStatus() &&
(current->getAircraft()->getTrafficRef()->getDepartureAirport() == closest->getAircraft()->getTrafficRef()->getDepartureAirport()) && (current->getAircraft()->getTrafficRef()->getDepartureAirport() == closest->getAircraft()->getTrafficRef()->getDepartureAirport()) &&
(current->getAircraft()->GetFlightPlan()->getRunway() == closest->getAircraft()->GetFlightPlan()->getRunway()) (current->getAircraft()->GetFlightPlan()->getRunway() == closest->getAircraft()->GetFlightPlan()->getRunway())
) )
current->getAircraft()->scheduleForATCTowerDepartureControl(1); current->getAircraft()->scheduleForATCTowerDepartureControl(1);
} else { } else {
current->setSpeedAdjustment(0); // This can only happen when the user aircraft is the one closest current->setSpeedAdjustment(0); // This can only happen when the user aircraft is the one closest
} }
@ -920,6 +929,9 @@ void FGGroundNetwork::checkSpeedAdjustment(int id, double lat,
} }
} }
} }
if ((closest == closestOnNetwork) && (current->getPriority() < closest->getPriority()) && needBraking) {
swap(current, closest);
}
} }
} }
@ -956,80 +968,100 @@ void FGGroundNetwork::checkHoldPosition(int id, double lat,
bool origStatus = current->hasHoldPosition(); bool origStatus = current->hasHoldPosition();
current->setHoldPosition(false); current->setHoldPosition(false);
SGGeod curr(SGGeod::fromDegM(lon, lat, alt)); SGGeod curr(SGGeod::fromDegM(lon, lat, alt));
int currentRoute = i->getCurrentPosition();
int nextRoute;
if (i->getIntentions().size()) {
nextRoute = (*(i->getIntentions().begin()));
} else {
nextRoute = 0;
}
if (currentRoute > 0) {
FGTaxiSegment *tx = findSegment(currentRoute);
FGTaxiSegment *nx;
if (nextRoute) {
nx = findSegment(nextRoute);
} else {
nx = tx;
}
if (tx->hasBlock() || nx->hasBlock() ) {
current->setHoldPosition(true);
}
}
for (i = activeTraffic.begin(); i != activeTraffic.end(); i++) {
if (i->getId() != current->getId()) {
int node = current->crosses(this, *i);
if (node != -1) {
FGTaxiNode *taxiNode = findNode(node);
// Determine whether it's save to continue or not. /* for (i = activeTraffic.begin(); i != activeTraffic.end(); i++) {
// If we have a crossing route, there are two possibilities: if (i->getId() != current->getId()) {
// 1) This is an interestion int node = current->crosses(this, *i);
// 2) This is oncoming two-way traffic, using the same taxiway. if (node != -1) {
//cerr << "Hold check 1 : " << id << " has common node " << node << endl; FGTaxiNode *taxiNode = findNode(node);
SGGeod other(SGGeod:: // Determine whether it's save to continue or not.
fromDegM(i->getLongitude(), i->getLatitude(), // If we have a crossing route, there are two possibilities:
i->getAltitude())); // 1) This is an interestion
bool needsToWait; // 2) This is oncoming two-way traffic, using the same taxiway.
bool opposing; //cerr << "Hold check 1 : " << id << " has common node " << node << endl;
if (current->isOpposing(this, *i, node)) {
needsToWait = true; SGGeod other(SGGeod::
opposing = true; fromDegM(i->getLongitude(), i->getLatitude(),
//cerr << "Hold check 2 : " << node << " has opposing segment " << endl; i->getAltitude()));
// issue a "Hold Position" as soon as we're close to the offending node bool needsToWait;
// For now, I'm doing this as long as the other aircraft doesn't bool opposing;
// have a hold instruction as soon as we're within a reasonable if (current->isOpposing(this, *i, node)) {
// distance from the offending node.
// This may be a bit of a conservative estimate though, as it may
// be well possible that both aircraft can both continue to taxi
// without crashing into each other.
} else {
opposing = false;
if (SGGeodesy::distanceM(other, taxiNode->getGeod()) > 200) // 2.0*i->getRadius())
{
needsToWait = false;
//cerr << "Hold check 3 : " << id <<" Other aircraft approaching node is still far away. (" << dist << " nm). Can safely continue "
// << endl;
} else {
needsToWait = true; needsToWait = true;
//cerr << "Hold check 4: " << id << " Would need to wait for other aircraft : distance = " << dist << " meters" << endl; opposing = true;
} //cerr << "Hold check 2 : " << node << " has opposing segment " << endl;
} // issue a "Hold Position" as soon as we're close to the offending node
// For now, I'm doing this as long as the other aircraft doesn't
double dist = // have a hold instruction as soon as we're within a reasonable
SGGeodesy::distanceM(curr, taxiNode->getGeod()); // distance from the offending node.
if (!(i->hasHoldPosition())) { // This may be a bit of a conservative estimate though, as it may
// be well possible that both aircraft can both continue to taxi
if ((dist < 200) && //2.5*current->getRadius()) && // without crashing into each other.
(needsToWait) && (i->onRoute(this, *current)) &&
//((i->onRoute(this, *current)) || ((!(i->getSpeedAdjustment())))) &&
(!(current->getId() == i->getWaitsForId())))
//(!(i->getSpeedAdjustment()))) // &&
//(!(current->getSpeedAdjustment())))
{
if (!(isUserAircraft(i->getAircraft()))) { // test code. Don't wait for the user, let the user wait for you.
current->setHoldPosition(true);
current->setWaitsForId(i->getId());
}
//cerr << "Hold check 5: " << current->getCallSign() <<" Setting Hold Position: distance to node (" << node << ") "
// << dist << " meters. Waiting for " << i->getCallSign();
//if (opposing)
//cerr <<" [opposing] " << endl;
//else
// cerr << "[non-opposing] " << endl;
//if (i->hasSpeefAdjustment())
// {
// cerr << " (which in turn waits for ) " << i->
} else { } else {
//cerr << "Hold check 6: " << id << " No need to hold yet: Distance to node : " << dist << " nm"<< endl; opposing = false;
if (SGGeodesy::distanceM(other, taxiNode->getGeod()) > 200) // 2.0*i->getRadius())
{
needsToWait = false;
//cerr << "Hold check 3 : " << id <<" Other aircraft approaching node is still far away. (" << dist << " nm). Can safely continue "
// << endl;
} else {
needsToWait = true;
//cerr << "Hold check 4: " << id << " Would need to wait for other aircraft : distance = " << dist << " meters" << endl;
}
}
double dist =
SGGeodesy::distanceM(curr, taxiNode->getGeod());
if (!(i->hasHoldPosition())) {
if ((dist < 200) && //2.5*current->getRadius()) &&
(needsToWait) && (i->onRoute(this, *current)) &&
//((i->onRoute(this, *current)) || ((!(i->getSpeedAdjustment())))) &&
(!(current->getId() == i->getWaitsForId())))
//(!(i->getSpeedAdjustment()))) // &&
//(!(current->getSpeedAdjustment())))
{
if (!(isUserAircraft(i->getAircraft()))) { // test code. Don't wait for the user, let the user wait for you.
current->setHoldPosition(true);
current->setWaitsForId(i->getId());
}
//cerr << "Hold check 5: " << current->getCallSign() <<" Setting Hold Position: distance to node (" << node << ") "
// << dist << " meters. Waiting for " << i->getCallSign();
//if (opposing)
//cerr <<" [opposing] " << endl;
//else
// cerr << "[non-opposing] " << endl;
//if (i->hasSpeefAdjustment())
// {
// cerr << " (which in turn waits for ) " << i->
} else {
//cerr << "Hold check 6: " << id << " No need to hold yet: Distance to node : " << dist << " nm"<< endl;
}
} }
} }
} }
} } */
}
bool currStatus = current->hasHoldPosition(); bool currStatus = current->hasHoldPosition();
current->setHoldPosition(origStatus); current->setHoldPosition(origStatus);
// Either a Hold Position or a resume taxi transmission has been issued // Either a Hold Position or a resume taxi transmission has been issued
@ -1064,17 +1096,17 @@ void FGGroundNetwork::checkHoldPosition(int id, double lat,
//int state = current->getState(); //int state = current->getState();
if (checkTransmissionState(1,1, current, now, MSG_ACKNOWLEDGE_HOLD_POSITION, ATC_AIR_TO_GROUND)) { if (checkTransmissionState(1,1, current, now, MSG_ACKNOWLEDGE_HOLD_POSITION, ATC_AIR_TO_GROUND)) {
current->setState(0); current->setState(0);
current->setHoldPosition(true); current->setHoldPosition(true);
} }
if (checkTransmissionState(2,2, current, now, MSG_ACKNOWLEDGE_RESUME_TAXI, ATC_AIR_TO_GROUND)) { if (checkTransmissionState(2,2, current, now, MSG_ACKNOWLEDGE_RESUME_TAXI, ATC_AIR_TO_GROUND)) {
current->setState(0); current->setState(0);
current->setHoldPosition(false); current->setHoldPosition(false);
} }
if (current->getAircraft()->getTakeOffStatus() && (current->getState() == 0)) { if (current->getAircraft()->getTakeOffStatus() && (current->getState() == 0)) {
//cerr << "Scheduling " << current->getAircraft()->getCallSign() << " for hold short" << endl; //cerr << "Scheduling " << current->getAircraft()->getCallSign() << " for hold short" << endl;
current->setState(6); current->setState(6);
} }
if (checkTransmissionState(6,6, current, now, MSG_REPORT_RUNWAY_HOLD_SHORT, ATC_AIR_TO_GROUND)) { if (checkTransmissionState(6,6, current, now, MSG_REPORT_RUNWAY_HOLD_SHORT, ATC_AIR_TO_GROUND)) {
} }
if (checkTransmissionState(7,7, current, now, MSG_ACKNOWLEDGE_REPORT_RUNWAY_HOLD_SHORT, ATC_GROUND_TO_AIR)) { if (checkTransmissionState(7,7, current, now, MSG_ACKNOWLEDGE_REPORT_RUNWAY_HOLD_SHORT, ATC_GROUND_TO_AIR)) {
@ -1086,7 +1118,7 @@ void FGGroundNetwork::checkHoldPosition(int id, double lat,
//current->setState(0); //current->setState(0);
} }
/** /**
@ -1271,10 +1303,10 @@ void FGGroundNetwork::render(bool visible)
//while (group->getNumChildren()) { //while (group->getNumChildren()) {
// cerr << "Number of children: " << group->getNumChildren() << endl; // cerr << "Number of children: " << group->getNumChildren() << endl;
//simgear::EffectGeode* geode = (simgear::EffectGeode*) group->getChild(0); //simgear::EffectGeode* geode = (simgear::EffectGeode*) group->getChild(0);
//osg::MatrixTransform *obj_trans = (osg::MatrixTransform*) group->getChild(0); //osg::MatrixTransform *obj_trans = (osg::MatrixTransform*) group->getChild(0);
//geode->releaseGLObjects(); //geode->releaseGLObjects();
//group->removeChild(geode); //group->removeChild(geode);
//delete geode; //delete geode;
group = 0; group = 0;
} }
if (visible) { if (visible) {
@ -1301,7 +1333,7 @@ void FGGroundNetwork::render(bool visible)
SGGeod center; SGGeod center;
SGGeodesy::direct(start, heading, coveredDistance, center, az2); SGGeodesy::direct(start, heading, coveredDistance, center, az2);
//cerr << "Active Aircraft : Centerpoint = (" << center.getLatitudeDeg() << ", " << center.getLongitudeDeg() << "). Heading = " << heading << endl; //cerr << "Active Aircraft : Centerpoint = (" << center.getLatitudeDeg() << ", " << center.getLongitudeDeg() << "). Heading = " << heading << endl;
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// Make a helper function out of this // Make a helper function out of this
osg::Matrix obj_pos; osg::Matrix obj_pos;
osg::MatrixTransform *obj_trans = new osg::MatrixTransform; osg::MatrixTransform *obj_trans = new osg::MatrixTransform;
@ -1321,7 +1353,7 @@ void FGGroundNetwork::render(bool visible)
center2.setElevationM(SG_MAX_ELEVATION_M); center2.setElevationM(SG_MAX_ELEVATION_M);
if (local_scenery->get_elevation_m( center2, elevationEnd, NULL )) { if (local_scenery->get_elevation_m( center2, elevationEnd, NULL )) {
elevation_feet = elevationEnd * SG_METER_TO_FEET + 0.5; elevation_feet = elevationEnd * SG_METER_TO_FEET + 0.5;
//elevation_meters += 0.5; //elevation_meters += 0.5;
} }
else { else {
elevationEnd = parent->getElevation(); elevationEnd = parent->getElevation();
@ -1331,9 +1363,9 @@ void FGGroundNetwork::render(bool visible)
double elevationMean = (elevationStart + elevationEnd) / 2.0; double elevationMean = (elevationStart + elevationEnd) / 2.0;
double elevDiff = elevationEnd - elevationStart; double elevDiff = elevationEnd - elevationStart;
double slope = atan2(elevDiff, length) * SGD_RADIANS_TO_DEGREES; double slope = atan2(elevDiff, length) * SGD_RADIANS_TO_DEGREES;
//cerr << "1. Using mean elevation : " << elevationMean << " and " << slope << endl; //cerr << "1. Using mean elevation : " << elevationMean << " and " << slope << endl;
WorldCoordinate( obj_pos, center.getLatitudeDeg(), center.getLongitudeDeg(), elevationMean+ 0.5, -(heading), slope ); WorldCoordinate( obj_pos, center.getLatitudeDeg(), center.getLongitudeDeg(), elevationMean+ 0.5, -(heading), slope );
@ -1350,18 +1382,23 @@ void FGGroundNetwork::render(bool visible)
geode->setName("test"); geode->setName("test");
geode->addDrawable(geometry); geode->addDrawable(geometry);
//osg::Node *custom_obj; //osg::Node *custom_obj;
SGMaterial *mat = matlib->find("UnidirectionalTaper"); SGMaterial *mat;
if (segments[pos]->hasBlock()) {
mat = matlib->find("UnidirectionalTaperRed");
} else {
mat = matlib->find("UnidirectionalTaperGreen");
}
if (mat) if (mat)
geode->setEffect(mat->get_effect()); geode->setEffect(mat->get_effect());
obj_trans->addChild(geode); obj_trans->addChild(geode);
// wire as much of the scene graph together as we can // wire as much of the scene graph together as we can
//->addChild( obj_trans ); //->addChild( obj_trans );
group->addChild( obj_trans ); group->addChild( obj_trans );
///////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////
} else { } else {
//cerr << "BIG FAT WARNING: current position is here : " << pos << endl; //cerr << "BIG FAT WARNING: current position is here : " << pos << endl;
} }
for(intVecIterator j = (i)->getIntentions().begin(); j != (i)->getIntentions().end(); j++) { for (intVecIterator j = (i)->getIntentions().begin(); j != (i)->getIntentions().end(); j++) {
osg::Matrix obj_pos; osg::Matrix obj_pos;
int k = (*j)-1; int k = (*j)-1;
if (k >= 0) { if (k >= 0) {
@ -1401,7 +1438,7 @@ void FGGroundNetwork::render(bool visible)
double length = segments[k]->getLength(); double length = segments[k]->getLength();
double slope = atan2(elevDiff, length) * SGD_RADIANS_TO_DEGREES; double slope = atan2(elevDiff, length) * SGD_RADIANS_TO_DEGREES;
// cerr << "2. Using mean elevation : " << elevationMean << " and " << slope << endl; // cerr << "2. Using mean elevation : " << elevationMean << " and " << slope << endl;
WorldCoordinate( obj_pos, segments[k]->getLatitude(), segments[k]->getLongitude(), elevationMean+ 0.5, -(segments[k]->getHeading()), slope ); WorldCoordinate( obj_pos, segments[k]->getLatitude(), segments[k]->getLongitude(), elevationMean+ 0.5, -(segments[k]->getHeading()), slope );
@ -1419,7 +1456,12 @@ void FGGroundNetwork::render(bool visible)
geode->setName("test"); geode->setName("test");
geode->addDrawable(geometry); geode->addDrawable(geometry);
//osg::Node *custom_obj; //osg::Node *custom_obj;
SGMaterial *mat = matlib->find("UnidirectionalTaper"); SGMaterial *mat;
if (segments[k]->hasBlock()) {
mat = matlib->find("UnidirectionalTaperRed");
} else {
mat = matlib->find("UnidirectionalTaperGreen");
}
if (mat) if (mat)
geode->setEffect(mat->get_effect()); geode->setEffect(mat->get_effect());
obj_trans->addChild(geode); obj_trans->addChild(geode);
@ -1437,3 +1479,96 @@ void FGGroundNetwork::render(bool visible)
string FGGroundNetwork::getName() { string FGGroundNetwork::getName() {
return string(parent->getId() + "-ground"); return string(parent->getId() + "-ground");
} }
void FGGroundNetwork::update(double dt)
{
for (FGTaxiSegmentVectorIterator tsi = segments.begin(); tsi != segments.end(); tsi++) {
(*tsi)->unblock();
}
int priority = 1;
//sort(activeTraffic.begin(), activeTraffic.end(), compare_trafficrecords);
// Handle traffic that is under ground control first; this way we'll prevent clutter at the gate areas.
// Don't allow an aircraft to pushback when a taxiing aircraft is currently using part of the intended route.
for (TrafficVectorIterator i = parent->getDynamics()->getStartupController()->getActiveTraffic().begin();
i != parent->getDynamics()->getStartupController()->getActiveTraffic().end(); i++) {
i->allowPushBack();
i->setPriority(priority++);
if (i->isActive(60)) {
// Check for all active aircraft whether it's current pos segment is
// an opposite of one of the departing aircraft's intentions
for (TrafficVectorIterator j = activeTraffic.begin(); j != activeTraffic.end(); j++) {
int pos = j->getCurrentPosition();
if (pos > 0) {
FGTaxiSegment *seg = segments[pos-1]->opposite();
if (seg) {
int posReverse = seg->getIndex();
for (intVecIterator k = i->getIntentions().begin(); k != i->getIntentions().end(); k++) {
if ((*k) == posReverse) {
i->denyPushBack();
segments[posReverse-1]->block();
}
}
}
}
}
// if the current aircraft is still allowed to pushback, we can start reserving a route for if by blocking all the entry taxiways.
if (i->pushBackAllowed()) {
int pos = i->getCurrentPosition();
if (pos > 0) {
FGTaxiSegment *seg = segments[pos-1];
FGTaxiNode *node = seg->getEnd();
for (FGTaxiSegmentVectorIterator tsi = segments.begin(); tsi != segments.end(); tsi++) {
if (((*tsi)->getEnd() == node) && ((*tsi) != seg)) {
(*tsi)->block();
}
}
}
for (intVecIterator j = i->getIntentions().begin(); j != i->getIntentions().end(); j++) {
int pos = (*j);
if (pos > 0) {
FGTaxiSegment *seg = segments[pos-1];
FGTaxiNode *node = seg->getEnd();
for (FGTaxiSegmentVectorIterator tsi = segments.begin(); tsi != segments.end(); tsi++) {
if (((*tsi)->getEnd() == node) && ((*tsi) != seg)) {
(*tsi)->block();
}
}
}
}
}
}
}
for (TrafficVectorIterator i = activeTraffic.begin(); i != activeTraffic.end(); i++) {
i->setPriority(priority++);
int pos = i->getCurrentPosition();
if (pos > 0) {
if (segments[pos-1]->hasBlock()) {
SG_LOG(SG_GENERAL, SG_ALERT, "Taxiway incursion for AI aircraft" << i->getAircraft()->getCallSign());
}
}
intVecIterator ivi;
for (ivi = i->getIntentions().begin(); ivi != i->getIntentions().end(); ivi++) {
int segIndex = (*ivi);
if (segIndex > 0) {
if (segments[segIndex-1]->hasBlock())
break;
}
}
//after this, ivi points just behind the last valid unblocked taxi segment.
for (intVecIterator j = i->getIntentions().begin(); j != ivi; j++) {
int pos = (*j);
if (pos > 0) {
FGTaxiSegment *seg = segments[pos-1];
FGTaxiNode *node = seg->getEnd();
for (FGTaxiSegmentVectorIterator tsi = segments.begin(); tsi != segments.end(); tsi++) {
if (((*tsi)->getEnd() == node) && ((*tsi) != seg)) {
(*tsi)->block();
}
}
}
}
}
}

View file

@ -60,94 +60,139 @@ typedef vector<FGTaxiSegment*>::iterator FGTaxiSegmentVectorIterator;
class FGTaxiSegment class FGTaxiSegment
{ {
private: private:
int startNode; int startNode;
int endNode; int endNode;
double length; double length;
double heading; double heading;
SGGeod center; SGGeod center;
bool isActive; bool isActive;
bool isPushBackRoute; bool isPushBackRoute;
FGTaxiNode *start; bool isBlocked;
FGTaxiNode *end; FGTaxiNode *start;
int index; FGTaxiNode *end;
FGTaxiSegment *oppositeDirection; int index;
FGTaxiSegment *oppositeDirection;
public: public:
FGTaxiSegment() : FGTaxiSegment() :
startNode(0), startNode(0),
endNode(0), endNode(0),
length(0), length(0),
heading(0), heading(0),
isActive(0), isActive(0),
isPushBackRoute(0), isPushBackRoute(0),
start(0), isBlocked(0),
end(0), start(0),
index(0), end(0),
oppositeDirection(0) index(0),
{ oppositeDirection(0)
}; {
};
FGTaxiSegment (const FGTaxiSegment &other) : FGTaxiSegment (const FGTaxiSegment &other) :
startNode (other.startNode), startNode (other.startNode),
endNode (other.endNode), endNode (other.endNode),
length (other.length), length (other.length),
heading (other.heading), heading (other.heading),
center (other.center), center (other.center),
isActive (other.isActive), isActive (other.isActive),
isPushBackRoute (other.isPushBackRoute), isPushBackRoute (other.isPushBackRoute),
start (other.start), isBlocked (other.isBlocked),
end (other.end), start (other.start),
index (other.index), end (other.end),
oppositeDirection (other.oppositeDirection) index (other.index),
{ oppositeDirection (other.oppositeDirection)
}; {
};
FGTaxiSegment& operator=(const FGTaxiSegment &other) FGTaxiSegment& operator=(const FGTaxiSegment &other)
{ {
startNode = other.startNode; startNode = other.startNode;
endNode = other.endNode; endNode = other.endNode;
length = other.length; length = other.length;
heading = other.heading; heading = other.heading;
center = other.center; center = other.center;
isActive = other.isActive; isActive = other.isActive;
isPushBackRoute = other.isPushBackRoute; isPushBackRoute = other.isPushBackRoute;
start = other.start; isBlocked = other.isBlocked;
end = other.end; start = other.start;
index = other.index; end = other.end;
oppositeDirection = other.oppositeDirection; index = other.index;
return *this; oppositeDirection = other.oppositeDirection;
}; return *this;
};
void setIndex (int val) { index = val; }; void setIndex (int val) {
void setStartNodeRef (int val) { startNode = val; }; index = val;
void setEndNodeRef (int val) { endNode = val; }; };
void setStartNodeRef (int val) {
startNode = val;
};
void setEndNodeRef (int val) {
endNode = val;
};
void setOpposite(FGTaxiSegment *opp) { oppositeDirection = opp; }; void setOpposite(FGTaxiSegment *opp) {
oppositeDirection = opp;
};
void setStart(FGTaxiNodeVector *nodes); void setStart(FGTaxiNodeVector *nodes);
void setEnd (FGTaxiNodeVector *nodes); void setEnd (FGTaxiNodeVector *nodes);
void setPushBackType(bool val) { isPushBackRoute = val; }; void setPushBackType(bool val) {
void setDimensions(double elevation); isPushBackRoute = val;
};
void setDimensions(double elevation);
void block() {
isBlocked = true;
}
void unblock() {
isBlocked = false;
};
bool hasBlock() {
return isBlocked;
};
FGTaxiNode * getEnd() { return end;}; FGTaxiNode * getEnd() {
FGTaxiNode * getStart() { return start; }; return end;
double getLength() { return length; }; };
int getIndex() { return index; }; FGTaxiNode * getStart() {
double getLatitude() { return center.getLatitudeDeg(); }; return start;
double getLongitude() { return center.getLongitudeDeg(); }; };
double getHeading() { return heading; }; double getLength() {
bool isPushBack() { return isPushBackRoute; }; return length;
};
int getIndex() {
return index;
};
double getLatitude() {
return center.getLatitudeDeg();
};
double getLongitude() {
return center.getLongitudeDeg();
};
double getHeading() {
return heading;
};
bool isPushBack() {
return isPushBackRoute;
};
int getPenalty(int nGates); int getPenalty(int nGates);
FGTaxiSegment *getAddress() { return this;}; FGTaxiSegment *getAddress() {
return this;
};
bool operator<(const FGTaxiSegment &other) const { return index < other.index; }; bool operator<(const FGTaxiSegment &other) const {
//bool hasSmallerHeadingDiff (const FGTaxiSegment &other) const { return headingDiff < other.headingDiff; }; return index < other.index;
FGTaxiSegment *opposite() { return oppositeDirection; }; };
void setCourseDiff(double crse); //bool hasSmallerHeadingDiff (const FGTaxiSegment &other) const { return headingDiff < other.headingDiff; };
FGTaxiSegment *opposite() {
return oppositeDirection;
};
void setCourseDiff(double crse);
@ -168,52 +213,67 @@ typedef vector<int>::iterator intVecIterator;
class FGTaxiRoute class FGTaxiRoute
{ {
private: private:
intVec nodes; intVec nodes;
intVec routes; intVec routes;
double distance; double distance;
// int depth; // int depth;
intVecIterator currNode; intVecIterator currNode;
intVecIterator currRoute; intVecIterator currRoute;
public: public:
FGTaxiRoute() { distance = 0; currNode = nodes.begin(); currRoute = routes.begin();}; FGTaxiRoute() {
FGTaxiRoute(intVec nds, intVec rts, double dist, int dpth) { distance = 0;
nodes = nds; currNode = nodes.begin();
routes = rts; currRoute = routes.begin();
distance = dist; };
currNode = nodes.begin(); FGTaxiRoute(intVec nds, intVec rts, double dist, int dpth) {
currRoute = routes.begin(); nodes = nds;
routes = rts;
distance = dist;
currNode = nodes.begin();
currRoute = routes.begin();
// depth = dpth; // depth = dpth;
}; };
FGTaxiRoute& operator= (const FGTaxiRoute &other) { FGTaxiRoute& operator= (const FGTaxiRoute &other) {
nodes = other.nodes; nodes = other.nodes;
routes = other.routes; routes = other.routes;
distance = other.distance; distance = other.distance;
// depth = other.depth; // depth = other.depth;
currNode = nodes.begin(); currNode = nodes.begin();
currRoute = routes.begin(); currRoute = routes.begin();
return *this; return *this;
}; };
FGTaxiRoute(const FGTaxiRoute& copy) : FGTaxiRoute(const FGTaxiRoute& copy) :
nodes(copy.nodes), nodes(copy.nodes),
routes(copy.routes), routes(copy.routes),
distance(copy.distance), distance(copy.distance),
// depth(copy.depth), // depth(copy.depth),
currNode(nodes.begin()), currNode(nodes.begin()),
currRoute(routes.begin()) currRoute(routes.begin())
{}; {};
bool operator< (const FGTaxiRoute &other) const {return distance < other.distance; }; bool operator< (const FGTaxiRoute &other) const {
bool empty () { return nodes.begin() == nodes.end(); }; return distance < other.distance;
bool next(int *nde); };
bool next(int *nde, int *rte); bool empty () {
void rewind(int legNr); return nodes.begin() == nodes.end();
};
bool next(int *nde);
bool next(int *nde, int *rte);
void rewind(int legNr);
void first() { currNode = nodes.begin(); currRoute = routes.begin(); }; void first() {
int size() { return nodes.size(); }; currNode = nodes.begin();
int nodesLeft() { return nodes.end() - currNode; }; currRoute = routes.begin();
};
int size() {
return nodes.size();
};
int nodesLeft() {
return nodes.end() - currNode;
};
// int getDepth() { return depth; }; // int getDepth() { return depth; };
}; };
@ -227,75 +287,84 @@ typedef vector<FGTaxiRoute>::iterator TaxiRouteVectorIterator;
class FGGroundNetwork : public FGATCController class FGGroundNetwork : public FGATCController
{ {
private: private:
bool hasNetwork; bool hasNetwork;
bool networkInitialized; bool networkInitialized;
time_t nextSave; time_t nextSave;
//int maxDepth; //int maxDepth;
int count; int count;
FGTaxiNodeVector nodes; FGTaxiNodeVector nodes;
FGTaxiNodeVector pushBackNodes; FGTaxiNodeVector pushBackNodes;
FGTaxiSegmentVector segments; FGTaxiSegmentVector segments;
//intVec route; //intVec route;
//intVec nodesStack; //intVec nodesStack;
//intVec routesStack; //intVec routesStack;
TaxiRouteVector routes; TaxiRouteVector routes;
TrafficVector activeTraffic; TrafficVector activeTraffic;
TrafficVectorIterator currTraffic; TrafficVectorIterator currTraffic;
bool foundRoute; bool foundRoute;
double totalDistance, maxDistance; double totalDistance, maxDistance;
FGTowerController *towerController; FGTowerController *towerController;
FGAirport *parent; FGAirport *parent;
//void printRoutingError(string); //void printRoutingError(string);
void checkSpeedAdjustment(int id, double lat, double lon, void checkSpeedAdjustment(int id, double lat, double lon,
double heading, double speed, double alt); double heading, double speed, double alt);
void checkHoldPosition(int id, double lat, double lon, void checkHoldPosition(int id, double lat, double lon,
double heading, double speed, double alt); double heading, double speed, double alt);
public: public:
FGGroundNetwork(); FGGroundNetwork();
~FGGroundNetwork(); ~FGGroundNetwork();
void addNode (const FGTaxiNode& node); void addNode (const FGTaxiNode& node);
void addNodes (FGParkingVec *parkings); void addNodes (FGParkingVec *parkings);
void addSegment(const FGTaxiSegment& seg); void addSegment(const FGTaxiSegment& seg);
void init(); void init();
bool exists() { return hasNetwork; }; bool exists() {
void setTowerController(FGTowerController *twrCtrlr) { towerController = twrCtrlr; }; return hasNetwork;
};
void setTowerController(FGTowerController *twrCtrlr) {
towerController = twrCtrlr;
};
int findNearestNode(double lat, double lon); int findNearestNode(double lat, double lon);
int findNearestNode(const SGGeod& aGeod); int findNearestNode(const SGGeod& aGeod);
FGTaxiNode *findNode(unsigned idx); FGTaxiNode *findNode(unsigned idx);
FGTaxiSegment *findSegment(unsigned idx); FGTaxiSegment *findSegment(unsigned idx);
FGTaxiRoute findShortestRoute(int start, int end, bool fullSearch=true); FGTaxiRoute findShortestRoute(int start, int end, bool fullSearch=true);
//void trace(FGTaxiNode *, int, int, double dist); //void trace(FGTaxiNode *, int, int, double dist);
int getNrOfNodes() { return nodes.size(); }; int getNrOfNodes() {
return nodes.size();
};
void setParent(FGAirport *par) { parent = par; }; void setParent(FGAirport *par) {
parent = par;
};
virtual void announcePosition(int id, FGAIFlightPlan *intendedRoute, int currentRoute, virtual void announcePosition(int id, FGAIFlightPlan *intendedRoute, int currentRoute,
double lat, double lon, double hdg, double spd, double alt, double lat, double lon, double hdg, double spd, double alt,
double radius, int leg, FGAIAircraft *aircraft); double radius, int leg, FGAIAircraft *aircraft);
virtual void signOff(int id); virtual void signOff(int id);
virtual void updateAircraftInformation(int id, double lat, double lon, double heading, double speed, double alt, double dt); virtual void updateAircraftInformation(int id, double lat, double lon, double heading, double speed, double alt, double dt);
virtual bool hasInstruction(int id); virtual bool hasInstruction(int id);
virtual FGATCInstruction getInstruction(int id); virtual FGATCInstruction getInstruction(int id);
bool checkTransmissionState(int minState, int MaxState, TrafficVectorIterator i, time_t now, AtcMsgId msgId, bool checkTransmissionState(int minState, int MaxState, TrafficVectorIterator i, time_t now, AtcMsgId msgId,
AtcMsgDir msgDir); AtcMsgDir msgDir);
bool checkForCircularWaits(int id); bool checkForCircularWaits(int id);
virtual void render(bool); virtual void render(bool);
virtual string getName(); virtual string getName();
virtual void update(double dt);
void saveElevationCache(); void saveElevationCache();
}; };

View file

@ -305,7 +305,8 @@ FGInterface::bind ()
// Ground speed knots // Ground speed knots
fgTie("/velocities/groundspeed-kt", this, fgTie("/velocities/groundspeed-kt", this,
&FGInterface::get_V_ground_speed_kt); // read-only &FGInterface::get_V_ground_speed_kt,
&FGInterface::set_V_ground_speed_kt); // read-only
// Calibrated airspeed // Calibrated airspeed
fgTie("/velocities/airspeed-kt", this, fgTie("/velocities/airspeed-kt", this,

View file

@ -552,6 +552,7 @@ public:
inline double get_V_ground_speed() const { return v_ground_speed; } inline double get_V_ground_speed() const { return v_ground_speed; }
inline double get_V_ground_speed_kt() const { return v_ground_speed * SG_FEET_TO_METER * 3600 * SG_METER_TO_NM; } inline double get_V_ground_speed_kt() const { return v_ground_speed * SG_FEET_TO_METER * 3600 * SG_METER_TO_NM; }
inline void set_V_ground_speed_kt(double ground_speed) { v_ground_speed = ground_speed / ( SG_FEET_TO_METER * 3600 * SG_METER_TO_NM); }
inline double get_V_equiv_kts() const { return v_equiv_kts; } inline double get_V_equiv_kts() const { return v_equiv_kts; }

View file

@ -397,6 +397,7 @@ MapWidget::MapWidget(int x, int y, int maxX, int maxY) :
MapWidget::~MapWidget() MapWidget::~MapWidget()
{ {
delete _magVar; delete _magVar;
clearData();
} }
void MapWidget::setProperty(SGPropertyNode_ptr prop) void MapWidget::setProperty(SGPropertyNode_ptr prop)
@ -535,10 +536,14 @@ void MapWidget::draw(int dx, int dy)
{ {
_aircraft = SGGeod::fromDeg(fgGetDouble("/position/longitude-deg"), _aircraft = SGGeod::fromDeg(fgGetDouble("/position/longitude-deg"),
fgGetDouble("/position/latitude-deg")); fgGetDouble("/position/latitude-deg"));
_magneticHeadings = _root->getBoolValue("magnetic-headings");
if (_hasPanned) bool mag = _root->getBoolValue("magnetic-headings");
{ if (mag != _magneticHeadings) {
clearData(); // flush cached data text, since it often includes heading
_magneticHeadings = mag;
}
if (_hasPanned) {
_root->setBoolValue("centre-on-aircraft", false); _root->setBoolValue("centre-on-aircraft", false);
_hasPanned = false; _hasPanned = false;
} }
@ -630,14 +635,9 @@ void MapWidget::paintRuler()
double dist, az, az2; double dist, az, az2;
SGGeodesy::inverse(_aircraft, _clickGeod, az, az2, dist); SGGeodesy::inverse(_aircraft, _clickGeod, az, az2, dist);
if (_magneticHeadings) {
az -= _magVar->get_magvar();
SG_NORMALIZE_RANGE(az, 0.0, 360.0);
}
char buffer[1024]; char buffer[1024];
::snprintf(buffer, 1024, "%03d/%.1fnm", ::snprintf(buffer, 1024, "%03d/%.1fnm",
SGMiscd::roundToInt(az), dist * SG_METER_TO_NM); displayHeading(az), dist * SG_METER_TO_NM);
MapData* d = getOrCreateDataForKey((void*) RULER_LEGEND_KEY); MapData* d = getOrCreateDataForKey((void*) RULER_LEGEND_KEY);
d->setLabel(buffer); d->setLabel(buffer);
@ -1245,11 +1245,11 @@ void MapWidget::drawRunway(FGRunway* rwy)
} }
char buffer[1024]; char buffer[1024];
::snprintf(buffer, 1024, "%s/%s\n%3.0f/%3.0f\n%.0f'", ::snprintf(buffer, 1024, "%s/%s\n%03d/%03d\n%.0f'",
rwy->ident().c_str(), rwy->ident().c_str(),
rwy->reciprocalRunway()->ident().c_str(), rwy->reciprocalRunway()->ident().c_str(),
rwy->headingDeg(), displayHeading(rwy->headingDeg()),
rwy->reciprocalRunway()->headingDeg(), displayHeading(rwy->reciprocalRunway()->headingDeg()),
rwy->lengthFt()); rwy->lengthFt());
MapData* d = createDataForKey(rwy); MapData* d = createDataForKey(rwy);
@ -1311,8 +1311,10 @@ void MapWidget::drawILS(bool tuned, FGRunway* rwy)
} }
char buffer[1024]; char buffer[1024];
::snprintf(buffer, 1024, "%s\n%s\n%3.2fMHz", ::snprintf(buffer, 1024, "%s\n%s\n%03d - %3.2fMHz",
loc->name().c_str(), loc->ident().c_str(),loc->get_freq()/100.0); loc->ident().c_str(), loc->name().c_str(),
displayHeading(radial),
loc->get_freq()/100.0);
MapData* d = createDataForKey(loc); MapData* d = createDataForKey(loc);
d->setPriority(40); d->setPriority(40);
@ -1680,3 +1682,23 @@ MapData* MapWidget::createDataForKey(void* key)
d->resetAge(); d->resetAge();
return d; return d;
} }
void MapWidget::clearData()
{
KeyDataMap::iterator it = _mapData.begin();
for (; it != _mapData.end(); ++it) {
delete it->second;
}
_mapData.clear();
}
int MapWidget::displayHeading(double h) const
{
if (_magneticHeadings) {
h -= _magVar->get_magvar() * SG_RADIANS_TO_DEGREES;
}
SG_NORMALIZE_RANGE(h, 0.0, 360.0);
return SGMiscd::roundToInt(h);
}

View file

@ -73,11 +73,14 @@ private:
MapData* getOrCreateDataForKey(void* key); MapData* getOrCreateDataForKey(void* key);
MapData* createDataForKey(void* key); MapData* createDataForKey(void* key);
void setAnchorForKey(void* key, const SGVec2d& anchor); void setAnchorForKey(void* key, const SGVec2d& anchor);
void clearData();
SGVec2d project(const SGGeod& geod) const; SGVec2d project(const SGGeod& geod) const;
SGGeod unproject(const SGVec2d& p) const; SGGeod unproject(const SGVec2d& p) const;
double currentScale() const; double currentScale() const;
int displayHeading(double trueHeading) const;
void circleAt(const SGVec2d& center, int nSides, double r); void circleAt(const SGVec2d& center, int nSides, double r);
void circleAtAlt(const SGVec2d& center, int nSides, double r, double r2); void circleAtAlt(const SGVec2d& center, int nSides, double r, double r2);
void drawLine(const SGVec2d& p1, const SGVec2d& p2); void drawLine(const SGVec2d& p1, const SGVec2d& p2);

View file

@ -22,6 +22,10 @@
#include <Main/fg_props.hxx> #include <Main/fg_props.hxx>
#if defined(SG_UNIX) && !defined(SG_MAC)
#include "GL/glx.h"
#endif
#include "menubar.hxx" #include "menubar.hxx"
#include "dialog.hxx" #include "dialog.hxx"
@ -417,6 +421,11 @@ FGFontCache::FGFontCache() :
FGFontCache::~FGFontCache() FGFontCache::~FGFontCache()
{ {
#if defined(SG_UNIX) && !defined(SG_MAC)
// Ugly workaround for a crash on exit with multiple screens configured
if (!glXGetCurrentContext())
return;
#endif
PuFontMap::iterator it, end = _puFonts.end(); PuFontMap::iterator it, end = _puFonts.end();
for (it = _puFonts.begin(); it != end; ++it) for (it = _puFonts.begin(); it != end; ++it)
delete it->second; delete it->second;

View file

@ -124,6 +124,7 @@ ADF::update (double delta_time_sec)
if (_electrical_node->getDoubleValue() < 8.0 if (_electrical_node->getDoubleValue() < 8.0
|| !_serviceable_node->getBoolValue() || !_serviceable_node->getBoolValue()
|| !_power_btn_node->getBoolValue() ) { || !_power_btn_node->getBoolValue() ) {
_in_range_node->setBoolValue(false);
_ident_node->setStringValue(""); _ident_node->setStringValue("");
return; return;
} }
@ -131,6 +132,7 @@ ADF::update (double delta_time_sec)
string mode = _mode_node->getStringValue(); string mode = _mode_node->getStringValue();
if (mode == "ant" || mode == "test") set_bearing(delta_time_sec, 90); if (mode == "ant" || mode == "test") set_bearing(delta_time_sec, 90);
if (mode != "bfo" && mode != "adf") { if (mode != "bfo" && mode != "adf") {
_in_range_node->setBoolValue(false);
_ident_node->setStringValue(""); _ident_node->setStringValue("");
return; return;
} }
@ -155,6 +157,7 @@ ADF::update (double delta_time_sec)
search(frequency_khz, longitude_rad, latitude_rad, altitude_m); search(frequency_khz, longitude_rad, latitude_rad, altitude_m);
if (!_transmitter_valid) { if (!_transmitter_valid) {
_in_range_node->setBoolValue(false);
_ident_node->setStringValue(""); _ident_node->setStringValue("");
return; return;
} }

View file

@ -318,14 +318,32 @@ do_resume (const SGPropertyNode * arg)
#endif #endif
/**
* Built-in command: replay the FDR buffer
*/
static bool
do_replay (const SGPropertyNode * arg)
{
FGReplay *r = (FGReplay *)(globals->get_subsystem( "replay" ));
return r->start();
}
/**
* Built-in command: pause/unpause the sim
*/
static bool static bool
do_pause (const SGPropertyNode * arg) do_pause (const SGPropertyNode * arg)
{ {
bool paused = fgGetBool("/sim/freeze/master",true) || fgGetBool("/sim/freeze/clock",true); bool paused = fgGetBool("/sim/freeze/master",true) || fgGetBool("/sim/freeze/clock",true);
fgSetBool("/sim/freeze/master",!paused); if (paused && (fgGetInt("/sim/freeze/replay-state",0)>0))
fgSetBool("/sim/freeze/clock",!paused); {
if (fgGetBool("/sim/freeze/replay-state",false)) do_replay(NULL);
fgSetBool("/sim/replay/disable",true); }
else
{
fgSetBool("/sim/freeze/master",!paused);
fgSetBool("/sim/freeze/clock",!paused);
}
return true; return true;
} }
@ -1170,24 +1188,6 @@ do_log_level (const SGPropertyNode * arg)
return true; return true;
} }
/**
* Built-in command: replay the FDR buffer
*/
static bool
do_replay (const SGPropertyNode * arg)
{
// freeze the fdm, resume from sim pause
fgSetInt( "/sim/freeze/replay-state", 1 );
fgSetBool("/sim/freeze/master", 0 );
fgSetBool("/sim/freeze/clock", 0 );
fgSetDouble( "/sim/replay/time", -1 );
// cout << "start = " << r->get_start_time()
// << " end = " << r->get_end_time() << endl;
return true;
}
/* /*
static bool static bool
do_decrease_visibility (const SGPropertyNode * arg) do_decrease_visibility (const SGPropertyNode * arg)

View file

@ -132,7 +132,6 @@ static void fgMainLoop( void ) {
= fgGetNode("/sim/timing-statistics/min-time-ms", true); = fgGetNode("/sim/timing-statistics/min-time-ms", true);
frame_signal->fireValueChanged(); frame_signal->fireValueChanged();
SGCloudLayer::enable_bump_mapping = fgGetBool("/sim/rendering/bump-mapping");
SG_LOG( SG_GENERAL, SG_DEBUG, "Running Main Loop"); SG_LOG( SG_GENERAL, SG_DEBUG, "Running Main Loop");
SG_LOG( SG_GENERAL, SG_DEBUG, "======= ==== ===="); SG_LOG( SG_GENERAL, SG_DEBUG, "======= ==== ====");

View file

@ -172,6 +172,8 @@ static const IdPropertyList sIdPropertyList[] = {
{1300, "tanker", simgear::props::INT}, {1300, "tanker", simgear::props::INT},
{1400, "scenery/events", simgear::props::STRING},
{10001, "sim/multiplay/transmission-freq-hz", simgear::props::STRING}, {10001, "sim/multiplay/transmission-freq-hz", simgear::props::STRING},
{10002, "sim/multiplay/chat", simgear::props::STRING}, {10002, "sim/multiplay/chat", simgear::props::STRING},
@ -636,7 +638,8 @@ FGMultiplayMgr::SendMyPosition(const FGExternalMotionData& motionInfo)
strncpy(PosMsg->Model, fgGetString("/sim/model/path"), MAX_MODEL_NAME_LEN); strncpy(PosMsg->Model, fgGetString("/sim/model/path"), MAX_MODEL_NAME_LEN);
PosMsg->Model[MAX_MODEL_NAME_LEN - 1] = '\0'; PosMsg->Model[MAX_MODEL_NAME_LEN - 1] = '\0';
if (fgGetBool("/sim/freeze/replay-state", true)) if (fgGetBool("/sim/freeze/replay-state", true)&&
fgGetBool("/sim/multiplay/freeze-on-replay",true))
{ {
// do not send position updates during replay // do not send position updates during replay
for (unsigned i = 0 ; i < 3; ++i) for (unsigned i = 0 ; i < 3; ++i)

View file

@ -323,6 +323,34 @@ private:
ObjectClassConfigList _objectClassConfigList; ObjectClassConfigList _objectClassConfigList;
}; };
class PropertyReferenceSet : public SGReferenced {
public:
void insert(const std::string& relativePath, const SGSharedPtr<sg::HLAPropertyDataElement>& dataElement)
{
if (_rootNode.valid())
dataElement->setPropertyNode(_rootNode->getNode(relativePath, true));
_pathDataElementPairList.push_back(PathDataElementPair(relativePath, dataElement));
}
void setRootNode(SGPropertyNode* rootNode)
{
_rootNode = rootNode;
for (PathDataElementPairList::iterator i = _pathDataElementPairList.begin();
i != _pathDataElementPairList.end(); ++i) {
i->second->setPropertyNode(_rootNode->getNode(i->first, true));
}
}
SGPropertyNode* getRootNode()
{ return _rootNode.get(); }
private:
SGSharedPtr<SGPropertyNode> _rootNode;
typedef std::pair<std::string, SGSharedPtr<sg::HLAPropertyDataElement> > PathDataElementPair;
typedef std::list<PathDataElementPair> PathDataElementPairList;
PathDataElementPairList _pathDataElementPairList;
};
class AbstractSimTime : public SGReferenced { class AbstractSimTime : public SGReferenced {
public: public:
virtual ~AbstractSimTime() {} virtual ~AbstractSimTime() {}
@ -533,7 +561,7 @@ private:
// Factory class that is used to create an apternative data element for the multiplayer property attribute // Factory class that is used to create an apternative data element for the multiplayer property attribute
class MPPropertyVariantDataElementFactory : public sg::HLAVariantArrayDataElement::AlternativeDataElementFactory { class MPPropertyVariantDataElementFactory : public sg::HLAVariantArrayDataElement::AlternativeDataElementFactory {
public: public:
MPPropertyVariantDataElementFactory(sg::HLAPropertyReferenceSet* propertyReferenceSet) : MPPropertyVariantDataElementFactory(PropertyReferenceSet* propertyReferenceSet) :
_propertyReferenceSet(propertyReferenceSet) _propertyReferenceSet(propertyReferenceSet)
{ } { }
@ -551,19 +579,19 @@ public:
// The relative property path should be in the semantics field name // The relative property path should be in the semantics field name
std::string relativePath = dataType->getAlternativeSemantics(index); std::string relativePath = dataType->getAlternativeSemantics(index);
sg::HLAPropertyReference* propertyReference = new sg::HLAPropertyReference(relativePath); sg::HLAPropertyDataElement* dataElement = new sg::HLAPropertyDataElement(alternativeDataType, (SGPropertyNode*)0);
_propertyReferenceSet->insert(propertyReference); _propertyReferenceSet->insert(relativePath, dataElement);
return new sg::HLAPropertyDataElement(alternativeDataType, propertyReference); return dataElement;
} }
private: private:
SGSharedPtr<sg::HLAPropertyReferenceSet> _propertyReferenceSet; SGSharedPtr<PropertyReferenceSet> _propertyReferenceSet;
}; };
class MPAttributeCallback : public sg::HLAObjectInstance::AttributeCallback { class MPAttributeCallback : public sg::HLAObjectInstance::AttributeCallback {
public: public:
MPAttributeCallback() : MPAttributeCallback() :
_propertyReferenceSet(new sg::HLAPropertyReferenceSet), _propertyReferenceSet(new PropertyReferenceSet),
_mpProperties(new sg::HLAVariantArrayDataElement) _mpProperties(new sg::HLAVariantArrayDataElement)
{ {
_mpProperties->setAlternativeDataElementFactory(new MPPropertyVariantDataElementFactory(_propertyReferenceSet.get())); _mpProperties->setAlternativeDataElementFactory(new MPPropertyVariantDataElementFactory(_propertyReferenceSet.get()));
@ -595,7 +623,7 @@ public:
sg::HLAVariantArrayDataElement* getMPProperties() const sg::HLAVariantArrayDataElement* getMPProperties() const
{ return _mpProperties.get(); } { return _mpProperties.get(); }
SGSharedPtr<sg::HLAPropertyReferenceSet> _propertyReferenceSet; SGSharedPtr<PropertyReferenceSet> _propertyReferenceSet;
protected: protected:
SGSharedPtr<sg::HLAAbstractLocation> _location; SGSharedPtr<sg::HLAAbstractLocation> _location;
@ -792,7 +820,7 @@ private:
objectInstance.setAttributes(attributePathElementMap); objectInstance.setAttributes(attributePathElementMap);
} }
void attachPropertyDataElements(sg::HLAPropertyReferenceSet& propertyReferenceSet, void attachPropertyDataElements(PropertyReferenceSet& propertyReferenceSet,
sg::HLAAttributePathElementMap& attributePathElementMap, sg::HLAAttributePathElementMap& attributePathElementMap,
const AttributePathPropertyMap& attributePathPropertyMap) const AttributePathPropertyMap& attributePathPropertyMap)
{ {
@ -800,10 +828,9 @@ private:
i != attributePathPropertyMap.end(); ++i) { i != attributePathPropertyMap.end(); ++i) {
for (PathPropertyMap::const_iterator j = i->second.begin(); for (PathPropertyMap::const_iterator j = i->second.begin();
j != i->second.end(); ++j) { j != i->second.end(); ++j) {
SGSharedPtr<sg::HLAPropertyReference> propertyReference; sg::HLAPropertyDataElement* dataElement = new sg::HLAPropertyDataElement;
propertyReference = new sg::HLAPropertyReference(j->second); propertyReferenceSet.insert(j->second, dataElement);
propertyReferenceSet.insert(propertyReference); attributePathElementMap[i->first][j->first] = dataElement;
attributePathElementMap[i->first][j->first] = new sg::HLAPropertyDataElement(propertyReference);
} }
} }
} }
@ -920,30 +947,28 @@ FGHLA::open()
// We need that to communicate to the rti // We need that to communicate to the rti
switch (configReader.getRTIVersion()) { switch (configReader.getRTIVersion()) {
case RTI13: case RTI13:
if (!_hlaFederate->connect(simgear::HLAFederate::RTI13, configReader.getRTIArguments())) { _hlaFederate->setVersion(simgear::HLAFederate::RTI13);
SG_LOG(SG_IO, SG_ALERT, "Could not connect to RTI13 federation.");
return false;
}
break; break;
case RTI1516: case RTI1516:
if (!_hlaFederate->connect(simgear::HLAFederate::RTI1516, configReader.getRTIArguments())) { _hlaFederate->setVersion(simgear::HLAFederate::RTI1516);
SG_LOG(SG_IO, SG_ALERT, "Could not connect to RTI1516 federation.");
return false;
}
break; break;
case RTI1516E: case RTI1516E:
if (!_hlaFederate->connect(simgear::HLAFederate::RTI1516E, configReader.getRTIArguments())) { _hlaFederate->setVersion(simgear::HLAFederate::RTI1516E);
SG_LOG(SG_IO, SG_ALERT, "Could not connect to RTI1516E federation.");
return false;
}
break; break;
} }
_hlaFederate->setConnectArguments(configReader.getRTIArguments());
_hlaFederate->setFederationExecutionName(_federation);
_hlaFederate->setFederationObjectModel(objectModel);
_hlaFederate->setFederateType(_federate);
// Try to create a new federation execution // Now that it is paramtrized, connect
_hlaFederate->createFederationExecution(_federation, objectModel); if (!_hlaFederate->connect()) {
SG_LOG(SG_IO, SG_ALERT, "Could not connect to rti.");
return false;
}
// Try to join // Try to create and join the new federation execution
if (!_hlaFederate->join(_federate, _federation)) { if (!_hlaFederate->createJoinFederationExecution()) {
SG_LOG(SG_IO, SG_ALERT, "Could not join federation"); SG_LOG(SG_IO, SG_ALERT, "Could not join federation");
return false; return false;
} }
@ -1240,16 +1265,9 @@ FGHLA::process()
} }
} }
// Then get news from others ... // Then get news from others and process possible update requests
if (get_direction() & SG_IO_IN) { if (get_direction() & (SG_IO_IN|SG_IO_OUT)) {
_hlaFederate->processMessages();
// I hoped that the tick call itself would do that job with the timestamps, but this way it works
SGTimeStamp timestamp = SGTimeStamp::now();
timestamp += SGTimeStamp::fromSec(0.01);
do {
if (!_hlaFederate->tick(0.0, 0.0))
break;
} while (SGTimeStamp::now() <= timestamp);
} }
return true; return true;
@ -1267,11 +1285,9 @@ FGHLA::close()
_localAircraftInstance = 0; _localAircraftInstance = 0;
} }
// Leave the federation // Leave the federation and try to destroy the federation execution.
_hlaFederate->resign(); // Only works if no federate is joined
_hlaFederate->resignDestroyFederationExecution();
// Try to destroy the federation execution. Only works if no federate is joined
_hlaFederate->destroyFederationExecution(_federation);
// throw away the HLAFederate // throw away the HLAFederate
_hlaFederate->disconnect(); _hlaFederate->disconnect();

View file

@ -380,7 +380,7 @@ void FGAISchedule::scheduleFlights(time_t now)
FGScheduledFlight *flight = NULL; FGScheduledFlight *flight = NULL;
do { do {
if (currentDestination.empty()) { if (currentDestination.empty()) {
flight = findAvailableFlight(userPort, flightIdentifier, now, (now+6400)); //flight = findAvailableFlight(userPort, flightIdentifier, now, (now+1800));
if (!flight) if (!flight)
flight = findAvailableFlight(currentDestination, flightIdentifier); flight = findAvailableFlight(currentDestination, flightIdentifier);
} else { } else {
@ -423,7 +423,7 @@ void FGAISchedule::scheduleFlights(time_t now)
<< " " << arrT << ":"); << " " << arrT << ":");
flights.push_back(flight); flights.push_back(flight);
} while (currentDestination != startingPort); } while (1); //(currentDestination != startingPort);
SG_LOG(SG_GENERAL, SG_BULK, " Done "); SG_LOG(SG_GENERAL, SG_BULK, " Done ");
} }

View file

@ -56,6 +56,8 @@ FGGLApplication::FGGLApplication( const char * aName, int argc, char ** argv ) :
FGGLApplication::~FGGLApplication() FGGLApplication::~FGGLApplication()
{ {
if (gameMode)
glutLeaveGameMode();
} }
void FGGLApplication::DisplayCallback() void FGGLApplication::DisplayCallback()

View file

@ -90,6 +90,15 @@ FGPanelApplication::FGPanelApplication( int argc, char ** argv ) :
throw exception(); throw exception();
} }
// see if we got a valid fgdata path
SGPath BaseCheck(ApplicationProperties::root);
BaseCheck.append("version");
if (!BaseCheck.exists())
{
cerr << "Missing base package. Use --fg-root=path_to_fgdata" << endl;
throw exception();
}
try { try {
SGPath tpath = ApplicationProperties::GetRootPath( panelFilename.c_str() ); SGPath tpath = ApplicationProperties::GetRootPath( panelFilename.c_str() );
readProperties( tpath.str(), ApplicationProperties::Properties ); readProperties( tpath.str(), ApplicationProperties::Properties );
@ -284,8 +293,12 @@ double ApplicationProperties::getDouble( const char * name, double def )
if( n == NULL ) return def; if( n == NULL ) return def;
return n->getDoubleValue(); return n->getDoubleValue();
} }
SGPath ApplicationProperties::GetRootPath( const char * sub ) SGPath ApplicationProperties::GetRootPath( const char * sub )
{ {
SGPath subpath( sub );
if ( subpath.isAbsolute() )
return subpath;
SGPath path( ApplicationProperties::root ); SGPath path( ApplicationProperties::root );
if( sub != NULL ) if( sub != NULL )
path.append( sub ); path.append( sub );

View file

@ -804,6 +804,11 @@ FGTextLayer::draw ()
transform(); transform();
text_renderer.setFont(ApplicationProperties::fontCache.getTexFont(_font_name.c_str())); text_renderer.setFont(ApplicationProperties::fontCache.getTexFont(_font_name.c_str()));
if (!text_renderer.getFont())
{
SG_LOG( SG_COCKPIT, SG_ALERT, "Missing font file: " << _font_name );
return;
}
text_renderer.setPointSize(_pointSize); text_renderer.setPointSize(_pointSize);
text_renderer.begin(); text_renderer.begin();