From 65e87bf2f80a5cd7d4b0f71084f3cbf9a4f7cb82 Mon Sep 17 00:00:00 2001 From: Durk Talsma Date: Sun, 17 Apr 2011 10:19:58 +0200 Subject: [PATCH] Added some code to visualize the ground networks. --- src/ATC/atc_mgr.cxx | 11 +++ src/ATC/atcdialog.cxx | 60 ++++++++++++-- src/ATC/atcdialog.hxx | 1 + src/ATC/trafficcontrol.cxx | 12 +++ src/Airports/dynamics.cxx | 3 +- src/Airports/dynamics.hxx | 3 + src/Airports/gnnode.cxx | 25 +++--- src/Airports/gnnode.hxx | 4 +- src/Airports/groundnetwork.cxx | 143 +++++++++++++++++++++++++++------ src/Airports/groundnetwork.hxx | 26 +++--- src/Scenery/tilemgr.cxx | 1 + 11 files changed, 235 insertions(+), 54 deletions(-) diff --git a/src/ATC/atc_mgr.cxx b/src/ATC/atc_mgr.cxx index 88f527f32..dace2d26c 100644 --- a/src/ATC/atc_mgr.cxx +++ b/src/ATC/atc_mgr.cxx @@ -29,6 +29,7 @@ #include #include #include +#include #include "atc_mgr.hxx" @@ -155,6 +156,10 @@ void FGATCManager::init() { aircraftRadius, leg, &ai_ac); //dialog.init(); + + osg::Node* node = apt->getDynamics()->getGroundNetwork()->getRenderNode(); + cerr << "Adding groundnetWork to the scenegraph" << endl; + globals->get_scenery()->get_scene_graph()->addChild(node); } } @@ -180,4 +185,10 @@ void FGATCManager::update ( double time ) { speed, altitude, time); } + /*string airport = fgGetString("/sim/presets/airport-id"); + FGAirport *apt = FGAirport::findByIdent(airport); + osg::Node* node = apt->getDynamics()->getGroundNetwork()->getRenderNode(); + cerr << "Adding groundnetWork to the scenegraph" << endl; + globals->get_scenery()->get_scene_graph()->addChild(node); +*/ } diff --git a/src/ATC/atcdialog.cxx b/src/ATC/atcdialog.cxx index a4c75a611..c59bf959b 100644 --- a/src/ATC/atcdialog.cxx +++ b/src/ATC/atcdialog.cxx @@ -91,9 +91,62 @@ void FGATCDialogNew::addEntry(int nr, string txt) { commands.push_back(txt); } +void FGATCDialogNew::removeEntry(int nr) { + commands.clear(); +} + + void FGATCDialogNew::PopupDialog() { - double onBoardRadioFreq0 = + /*double onBoardRadioFreq0 = + fgGetDouble("/instrumentation/comm[0]/frequencies/selected-mhz"); + double onBoardRadioFreq1 = + fgGetDouble("/instrumentation/comm[1]/frequencies/selected-mhz"); + + const char *dialog_name = "atc-dialog"; + _gui = (NewGUI *)globals->get_subsystem("gui"); + SGPropertyNode_ptr dlg = _gui->getDialogProperties(dialog_name); + if (!dlg) + return; + + _gui->closeDialog(dialog_name); + SGPropertyNode_ptr button_group = getNamedNode(dlg, "transmission-choice"); + button_group->removeChildren("button", false); + + const int bufsize = 32; + char buf[bufsize]; + int commandNr = 0; + // loop over all entries that should fill up the dialog; use 10 items for now... + for (StringVecIterator i = commands.begin(); i != commands.end(); i++) { + snprintf(buf, bufsize, "/sim/atc/opt[%d]", commandNr); + fgSetBool(buf, false); + SGPropertyNode *entry = button_group->getNode("button", commandNr, true); + copyProperties(button_group->getNode("button-template", true), entry); + entry->removeChildren("enabled", true); + entry->setStringValue("property", buf); + entry->setIntValue("keynum", '1' + commandNr); + if (commandNr == 0) + entry->setBoolValue("default", true); + + snprintf(buf, bufsize, "%d", 1 + commandNr); + string legend = string(buf) + (*i); //"; // + current->menuentry; + entry->setStringValue("legend", legend.c_str()); + entry->setIntValue("binding/value", commandNr); + commandNr++; + //current++; + } +*/ + //if (dialogVisible) { + // _gui->closeDialog(dialog_name); + //} else { + // _gui->showDialog(dialog_name); + //} + dialogVisible = !dialogVisible; + return; +} + +void FGATCDialogNew::update(double dt) { + double onBoardRadioFreq0 = fgGetDouble("/instrumentation/comm[0]/frequencies/selected-mhz"); double onBoardRadioFreq1 = fgGetDouble("/instrumentation/comm[1]/frequencies/selected-mhz"); @@ -136,11 +189,8 @@ void FGATCDialogNew::PopupDialog() { } else { _gui->showDialog(dialog_name); } - dialogVisible = !dialogVisible; + //dialogVisible = !dialogVisible; return; -} - -void FGATCDialogNew::update(double dt) { /* static SGPropertyNode_ptr trans_num = globals->get_props()->getNode("/sim/atc/transmission-num", true); int n = trans_num->getIntValue(); diff --git a/src/ATC/atcdialog.hxx b/src/ATC/atcdialog.hxx index f667b87dc..f52b5b4f1 100644 --- a/src/ATC/atcdialog.hxx +++ b/src/ATC/atcdialog.hxx @@ -60,6 +60,7 @@ public: void update(double dt); void PopupDialog(); void addEntry(int, string); + void removeEntry(int); }; extern FGATCDialogNew *currentATCDialog; diff --git a/src/ATC/trafficcontrol.cxx b/src/ATC/trafficcontrol.cxx index b0adba541..c6b14504c 100644 --- a/src/ATC/trafficcontrol.cxx +++ b/src/ATC/trafficcontrol.cxx @@ -399,6 +399,10 @@ void FGTrafficRecord::setHeadingAdjustment(double heading) bool FGTrafficRecord::pushBackAllowed() { + // With the user ATC / AI integration, checking whether the user's aircraft is near no longer works, because + // 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())); @@ -409,7 +413,12 @@ bool FGTrafficRecord::pushBackAllowed() 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 } @@ -1023,6 +1032,8 @@ bool FGStartupController::checkTransmissionState(int st, time_t now, time_t star trans_num->setIntValue(-1); // PopupCallback(n); cerr << "Selected transmission message" << n << endl; + FGATCManager *atc = (FGATCManager*) globals->get_subsystem("atc"); + atc->getATCDialog()->removeEntry(1); } else { cerr << "creading message for " << i->getAircraft()->getCallSign() << endl; transmit(&(*i), msgId, msgDir, false); @@ -1092,6 +1103,7 @@ void FGStartupController::updateAircraftInformation(int id, double lat, double l } checkTransmissionState(5, now, (startTime + 140), i, MSG_INITIATE_CONTACT, ATC_AIR_TO_GROUND); checkTransmissionState(6, now, (startTime + 150), i, MSG_ACKNOWLEDGE_INITIATE_CONTACT, ATC_GROUND_TO_AIR); + checkTransmissionState(7, now, (startTime + 180), i, MSG_REQUEST_PUSHBACK_CLEARANCE, ATC_AIR_TO_GROUND); diff --git a/src/Airports/dynamics.cxx b/src/Airports/dynamics.cxx index d608043b4..fd5025a38 100644 --- a/src/Airports/dynamics.cxx +++ b/src/Airports/dynamics.cxx @@ -96,10 +96,11 @@ void FGAirportDynamics::init() random_shuffle(parkings.begin(), parkings.end()); sort(parkings.begin(), parkings.end()); // add the gate positions to the ground network. + groundNetwork.setParent(_ap); groundNetwork.addNodes(&parkings); groundNetwork.init(); groundNetwork.setTowerController(&towerController); - groundNetwork.setParent(_ap); + } bool FGAirportDynamics::getAvailableParking(double *lat, double *lon, diff --git a/src/Airports/dynamics.hxx b/src/Airports/dynamics.hxx index ecadb9d62..1aa61fe6f 100644 --- a/src/Airports/dynamics.hxx +++ b/src/Airports/dynamics.hxx @@ -72,6 +72,9 @@ private: string chooseRunwayFallback(); bool innerGetActiveRunway(const string &trafficType, int action, string &runway, double heading); string chooseRwyByHeading(stringVec rwys, double heading); + + double elevation; + public: FGAirportDynamics(FGAirport* ap); FGAirportDynamics(const FGAirportDynamics &other); diff --git a/src/Airports/gnnode.cxx b/src/Airports/gnnode.cxx index c9883d812..ae37d5959 100644 --- a/src/Airports/gnnode.cxx +++ b/src/Airports/gnnode.cxx @@ -31,9 +31,9 @@ double processPosition(const string &pos) return value; } -bool sortByHeadingDiff(FGTaxiSegment *a, FGTaxiSegment *b) { - return a->hasSmallerHeadingDiff(*b); -} +//bool sortByHeadingDiff(FGTaxiSegment *a, FGTaxiSegment *b) { +// return a->hasSmallerHeadingDiff(*b); +//} bool sortByLength(FGTaxiSegment *a, FGTaxiSegment *b) { return a->getLength() > b->getLength(); @@ -42,7 +42,10 @@ bool sortByLength(FGTaxiSegment *a, FGTaxiSegment *b) { /************************************************************************** * FGTaxiNode *************************************************************************/ - +void FGTaxiNode::setElevation(double val) +{ + geod.setElevationM(val); +} void FGTaxiNode::setLatitude (double val) { @@ -64,10 +67,10 @@ void FGTaxiNode::setLongitude(const string& val) geod.setLongitudeDeg(processPosition(val)); } -void FGTaxiNode::sortEndSegments(bool byLength) -{ - if (byLength) - sort(next.begin(), next.end(), sortByLength); - else - sort(next.begin(), next.end(), sortByHeadingDiff); -} +//void FGTaxiNode::sortEndSegments(bool byLength) +//{ +// if (byLength) +// sort(next.begin(), next.end(), sortByLength); +// else +// sort(next.begin(), next.end(), sortByHeadingDiff); +//} diff --git a/src/Airports/gnnode.hxx b/src/Airports/gnnode.hxx index 3358ea51e..a7627715e 100644 --- a/src/Airports/gnnode.hxx +++ b/src/Airports/gnnode.hxx @@ -83,6 +83,7 @@ FGTaxiNode &operator =(const FGTaxiNode &other) void setIndex(int idx) { index = idx; }; void setLatitude (double val); void setLongitude(double val); + void setElevation(double val); void setLatitude (const std::string& val); void setLongitude(const std::string& val); void addSegment(FGTaxiSegment *segment) { next.push_back(segment); }; @@ -99,6 +100,7 @@ FGTaxiNode &operator =(const FGTaxiNode &other) double getPathScore() { return pathScore; }; double getLatitude() { return geod.getLatitudeDeg();}; double getLongitude(){ return geod.getLongitudeDeg();}; + double getElevation() { return geod.getElevationM();}; const SGGeod& getGeod() const { return geod; } @@ -111,7 +113,7 @@ FGTaxiNode &operator =(const FGTaxiNode &other) FGTaxiSegmentVectorIterator getEndRoute() { return next.end(); }; bool operator<(const FGTaxiNode &other) const { return index < other.index; }; - void sortEndSegments(bool); + //void sortEndSegments(bool); }; diff --git a/src/Airports/groundnetwork.cxx b/src/Airports/groundnetwork.cxx index 37e9946bf..a87861fab 100644 --- a/src/Airports/groundnetwork.cxx +++ b/src/Airports/groundnetwork.cxx @@ -27,8 +27,15 @@ #include #include + +#include +#include +#include +#include + #include #include +#include #include #include @@ -77,19 +84,26 @@ void FGTaxiSegment::setEnd(FGTaxiNodeVector * nodes) // There is probably a computationally cheaper way of // doing this. -void FGTaxiSegment::setTrackDistance() +void FGTaxiSegment::setDimensions(double elevation) { length = SGGeodesy::distanceM(start->getGeod(), end->getGeod()); + //heading = SGGeodesy::headingDeg(start->getGeod(), end->getGeod()); + + double az2; //, distanceM; + SGGeodesy::inverse(start->getGeod(), end->getGeod(), heading, az2, length); + double coveredDistance = length * 0.5; + SGGeodesy::direct(start->getGeod(), heading, coveredDistance, center, az2); + cerr << "Centerpoint = (" << center.getLatitudeDeg() << ", " << center.getLongitudeDeg() << "). Heading = " << heading << endl; } -void FGTaxiSegment::setCourseDiff(double crse) -{ - headingDiff = fabs(course - crse); +//void FGTaxiSegment::setCourseDiff(double crse) +//{ +// headingDiff = fabs(course - crse); - if (headingDiff > 180) - headingDiff = fabs(headingDiff - 360); -} +// if (headingDiff > 180) +// headingDiff = fabs(headingDiff - 360); +//} /*************************************************************************** @@ -227,6 +241,7 @@ void FGGroundNetwork::addNodes(FGParkingVec * parkings) n.setIndex(i->getIndex()); n.setLatitude(i->getLatitude()); n.setLongitude(i->getLongitude()); + n.setElevation(parent->getElevation()); nodes.push_back(new FGTaxiNode(n)); i++; @@ -245,7 +260,7 @@ void FGGroundNetwork::init() while (i != segments.end()) { (*i)->setStart(&nodes); (*i)->setEnd(&nodes); - (*i)->setTrackDistance(); + (*i)->setDimensions(parent->getElevation()); (*i)->setIndex(index); if ((*i)->isPushBack()) { pushBackNodes.push_back((*i)->getEnd()); @@ -511,6 +526,36 @@ void FGGroundNetwork::signOff(int id) } } +bool FGGroundNetwork::checkTransmissionState(int minState, int maxState, TrafficVectorIterator i, time_t now, AtcMsgId msgId, + AtcMsgDir msgDir) +{ + int state = i->getState(); + if ((state >= minState) && (state <= maxState) && available) { + if ((msgDir == ATC_AIR_TO_GROUND) && isUserAircraft(i->getAircraft())) { + + cerr << "Checking state " << state << " for " << i->getAircraft()->getCallSign() << endl; + static SGPropertyNode_ptr trans_num = globals->get_props()->getNode("/sim/atc/transmission-num", true); + int n = trans_num->getIntValue(); + if (n >= 0) { + trans_num->setIntValue(-1); + // PopupCallback(n); + cerr << "Selected transmission message" << n << endl; + } else { + cerr << "creading message for " << i->getAircraft()->getCallSign() << endl; + transmit(&(*i), msgId, msgDir, false); + return false; + } + } + //cerr << "Transmitting startup msg" << endl; + transmit(&(*i), msgId, msgDir, true); + i->updateState(); + lastTransmission = now; + available = false; + return true; + } + return false; +} + void FGGroundNetwork::updateAircraftInformation(int id, double lat, double lon, double heading, double speed, double alt, double dt) @@ -568,23 +613,14 @@ void FGGroundNetwork::updateAircraftInformation(int id, double lat, double lon, if ((now - lastTransmission) > 15) { available = true; } - if ((state < 3) && available) { - transmit(&(*current), MSG_REQUEST_TAXI_CLEARANCE, ATC_AIR_TO_GROUND, true); - current->setState(3); - lastTransmission = now; - available = false; + if (checkTransmissionState(0,2, current, now, MSG_REQUEST_TAXI_CLEARANCE, ATC_AIR_TO_GROUND)) { + current->setState(3); } - if ((state == 3) && available) { - transmit(&(*current), MSG_ISSUE_TAXI_CLEARANCE, ATC_GROUND_TO_AIR, true); + if (checkTransmissionState(3,3, current, now, MSG_ISSUE_TAXI_CLEARANCE, ATC_GROUND_TO_AIR)) { current->setState(4); - lastTransmission = now; - available = false; } - if ((state == 4) && available) { - transmit(&(*current), MSG_ACKNOWLEDGE_TAXI_CLEARANCE, ATC_AIR_TO_GROUND, true); + if (checkTransmissionState(4,4, current, now, MSG_ACKNOWLEDGE_TAXI_CLEARANCE, ATC_AIR_TO_GROUND)) { current->setState(5); - lastTransmission = now; - available = false; } if ((state == 5) && available) { current->setState(0); @@ -862,8 +898,17 @@ void FGGroundNetwork::checkHoldPosition(int id, double lat, //cerr << "Current state " << current->getState() << endl; } else { } - int state = current->getState(); - if ((state == 1) && (available)) { + //int state = current->getState(); + if (checkTransmissionState(1,1, current, now, MSG_ACKNOWLEDGE_HOLD_POSITION, ATC_AIR_TO_GROUND)) { + current->setState(0); + current->setHoldPosition(true); + } + if (checkTransmissionState(2,2, current, now, MSG_ACKNOWLEDGE_RESUME_TAXI, ATC_AIR_TO_GROUND)) { + current->setState(0); + current->setHoldPosition(false); + } + + /*if ((state == 1) && (available)) { //cerr << "ACKNOWLEDGE HOLD" << endl; transmit(&(*current), MSG_ACKNOWLEDGE_HOLD_POSITION, ATC_AIR_TO_GROUND, true); current->setState(0); @@ -879,8 +924,8 @@ void FGGroundNetwork::checkHoldPosition(int id, double lat, current->setHoldPosition(false); lastTransmission = now; available = false; - } -} + }*/ +} /** * Check whether situations occur where the current aircraft is waiting for itself @@ -1036,3 +1081,51 @@ FGATCInstruction FGGroundNetwork::getInstruction(int id) } return FGATCInstruction(); } + +// Note that this function is copied from simgear. for maintanance purposes, it's probabtl better to make a general function out of that. +static void WorldCoordinate(osg::Matrix& obj_pos, double lat, + double lon, double elev, double hdg) +{ + SGGeod geod = SGGeod::fromDegM(lon, lat, elev); + obj_pos = geod.makeZUpFrame(); + // hdg is not a compass heading, but a counter-clockwise rotation + // around the Z axis + obj_pos.preMult(osg::Matrix::rotate(hdg * SGD_DEGREES_TO_RADIANS, + 0.0, 0.0, 1.0)); +} + + + +osg::Node* FGGroundNetwork::getRenderNode() +{ + osg::Group* group = new osg::Group; + + for ( FGTaxiSegmentVectorIterator i = segments.begin(); i != segments.end(); i++) { + osg::Matrix obj_pos; + osg::MatrixTransform *obj_trans = new osg::MatrixTransform; + obj_trans->setDataVariance(osg::Object::STATIC); + WorldCoordinate( obj_pos, (*i)->getLatitude(), (*i)->getLongitude(), parent->elevation()+10, -((*i)->getHeading()) ); + + obj_trans->setMatrix( obj_pos ); + //osg::Vec3 center(0, 0, 0) + + float width = (*i)->getLength() /2.0; + osg::Vec3 corner(-width, 0, 0.25f); + osg::Vec3 widthVec(2*width + 1, 0, 0); + osg::Vec3 heightVec(0, 0, 1); + 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; + + obj_trans->addChild(geode); + // wire as much of the scene graph together as we can + //->addChild( obj_trans ); + group->addChild( obj_trans ); + } + + + return group; +} \ No newline at end of file diff --git a/src/Airports/groundnetwork.hxx b/src/Airports/groundnetwork.hxx index 06ed98b12..319d8b2dd 100644 --- a/src/Airports/groundnetwork.hxx +++ b/src/Airports/groundnetwork.hxx @@ -56,8 +56,8 @@ private: int startNode; int endNode; double length; - double course; - double headingDiff; + double heading; + SGGeod center; bool isActive; bool isPushBackRoute; FGTaxiNode *start; @@ -72,8 +72,7 @@ public: startNode(0), endNode(0), length(0), - course(0), - headingDiff(0), + heading(0), isActive(0), isPushBackRoute(0), start(0), @@ -87,8 +86,8 @@ public: startNode (other.startNode), endNode (other.endNode), length (other.length), - course (other.course), - headingDiff (other.headingDiff), + heading (other.heading), + center (other.center), isActive (other.isActive), isPushBackRoute (other.isPushBackRoute), start (other.start), @@ -103,8 +102,8 @@ public: startNode = other.startNode; endNode = other.endNode; length = other.length; - course = other.course; - headingDiff = other.headingDiff; + heading = other.heading; + center = other.center; isActive = other.isActive; isPushBackRoute = other.isPushBackRoute; start = other.start; @@ -123,13 +122,15 @@ public: void setStart(FGTaxiNodeVector *nodes); void setEnd (FGTaxiNodeVector *nodes); void setPushBackType(bool val) { isPushBackRoute = val; }; - void setTrackDistance(); + void setDimensions(double elevation); FGTaxiNode * getEnd() { return end;}; FGTaxiNode * getStart() { return start; }; double getLength() { 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); @@ -137,7 +138,7 @@ public: FGTaxiSegment *getAddress() { return this;}; bool operator<(const FGTaxiSegment &other) const { return index < other.index; }; - bool hasSmallerHeadingDiff (const FGTaxiSegment &other) const { return headingDiff < other.headingDiff; }; + //bool hasSmallerHeadingDiff (const FGTaxiSegment &other) const { return headingDiff < other.headingDiff; }; FGTaxiSegment *opposite() { return oppositeDirection; }; void setCourseDiff(double crse); @@ -273,7 +274,10 @@ public: virtual bool hasInstruction(int id); virtual FGATCInstruction getInstruction(int id); + bool checkTransmissionState(int minState, int MaxState, TrafficVectorIterator i, time_t now, AtcMsgId msgId, + AtcMsgDir msgDir); bool checkForCircularWaits(int id); + osg::Node* getRenderNode(); }; diff --git a/src/Scenery/tilemgr.cxx b/src/Scenery/tilemgr.cxx index 6c19ec5c0..53f1f346d 100644 --- a/src/Scenery/tilemgr.cxx +++ b/src/Scenery/tilemgr.cxx @@ -152,6 +152,7 @@ bool FGTileMgr::sched_tile( const SGBucket& b, double priority, bool current_vie if ( tile_cache.insert_tile( t ) ) { // Attach to scene graph + t->addToSceneGraph(globals->get_scenery()->get_terrain_branch()); } else {