+
// groundnet.cxx - Implimentation of the FlightGear airport ground handling code
//
// Written by Durk Talsma, started June 2005.
#include <math.h>
#include <algorithm>
+
+#include <osg/Geode>
+#include <osg/Geometry>
+#include <osg/MatrixTransform>
+#include <osg/Shape>
+
#include <simgear/debug/logstream.hxx>
#include <simgear/route/waypoint.hxx>
+#include <simgear/scene/material/EffectGeode.hxx>
+#include <simgear/scene/material/matlib.hxx>
+#include <simgear/scene/material/mat.hxx>
+#include <Airports/simple.hxx>
#include <Airports/dynamics.hxx>
#include <AIModel/AIAircraft.hxx>
#include <AIModel/AIFlightPlan.hxx>
+#include <ATC/atc_mgr.hxx>
+
+#include <Scenery/scenery.hxx>
+
#include "groundnetwork.hxx"
/***************************************************************************
// 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);
+//}
/***************************************************************************
//maxDepth = 1000;
count = 0;
currTraffic = activeTraffic.begin();
+ group = 0;
}
n.setIndex(i->getIndex());
n.setLatitude(i->getLatitude());
n.setLongitude(i->getLongitude());
+ n.setElevation(parent->getElevation());
nodes.push_back(new FGTaxiNode(n));
i++;
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());
double radius, int leg,
FGAIAircraft * aircraft)
{
+ init();
TrafficVectorIterator i = activeTraffic.begin();
// Search search if the current id alread has an entry
// This might be faster using a map instead of a vector, but let's start by taking a safe route
}
}
+
void FGGroundNetwork::signOff(int id)
{
TrafficVectorIterator i = activeTraffic.begin();
}
}
-void FGGroundNetwork::update(int id, double lat, double lon,
- double heading, double speed, double alt,
- double dt)
+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;
+ FGATCManager *atc = (FGATCManager*) globals->get_subsystem("atc");
+ atc->getATCDialog()->removeEntry(1);
+ } else {
+ //cerr << "creating message for " << i->getAircraft()->getCallSign() << endl;
+ transmit(&(*i), msgId, msgDir, false);
+ return false;
+ }
+ }
+ 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)
{
// Check whether aircraft are on hold due to a preceding pushback. If so, make sure to
// Transmit air-to-ground "Ready to taxi request:
current->clearResolveCircularWait();
current->setWaitsForId(0);
checkSpeedAdjustment(id, lat, lon, heading, speed, alt);
- checkHoldPosition(id, lat, lon, heading, speed, alt);
- if (checkForCircularWaits(id)) {
- i->setResolveCircularWait();
- }
bool needsTaxiClearance = current->getAircraft()->getTaxiClearanceRequest();
- int state = current->getState();
- time_t now = time(NULL) + fgGetLong("/sim/time/warp");
- if ((now - lastTransmission) > 15) {
- available = true;
- }
- if (needsTaxiClearance && available) {
- transmit(&(*current), MSG_REQUEST_TAXI_CLEARANCE, ATC_AIR_TO_GROUND);
- current->getAircraft()->setTaxiClearanceRequest(false);
- current->setState(3);
- lastTransmission = now;
- available = false;
- }
- if ((state == 3) && available) {
- transmit(&(*current), 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);
- current->setState(0);
- lastTransmission = now;
- available = false;
+ if (!needsTaxiClearance) {
+ checkHoldPosition(id, lat, lon, heading, speed, alt);
+ if (checkForCircularWaits(id)) {
+ i->setResolveCircularWait();
+ }
+ } else {
+ current->setHoldPosition(true);
+ int state = current->getState();
+ time_t now = time(NULL) + fgGetLong("/sim/time/warp");
+ if ((now - lastTransmission) > 15) {
+ available = true;
+ }
+ if (checkTransmissionState(0,2, current, now, MSG_REQUEST_TAXI_CLEARANCE, ATC_AIR_TO_GROUND)) {
+ current->setState(3);
+ }
+ if (checkTransmissionState(3,3, current, now, MSG_ISSUE_TAXI_CLEARANCE, ATC_GROUND_TO_AIR)) {
+ current->setState(4);
+ }
+ if (checkTransmissionState(4,4, current, now, MSG_ACKNOWLEDGE_TAXI_CLEARANCE, ATC_AIR_TO_GROUND)) {
+ current->setState(5);
+ }
+ if ((state == 5) && available) {
+ current->setState(0);
+ current->getAircraft()->setTaxiClearanceRequest(false);
+ current->setHoldPosition(true);
+ available = false;
+ }
+
}
+
}
/**
}
}
//Check traffic at the tower controller
+ // Note, as of 2011-08-01, this should no longer be necessecary.
+ /*
if (towerController->hasActiveTraffic()) {
for (TrafficVectorIterator i =
towerController->getActiveTraffic().begin();
}
}
// Finally, check UserPosition
+ // Note, as of 2011-08-01, this should no longer be necessecary.
double userLatitude = fgGetDouble("/position/latitude-deg");
double userLongitude = fgGetDouble("/position/longitude-deg");
SGGeod user(SGGeod::fromDeg(userLongitude, userLatitude));
minbearing = bearing;
otherReasonToSlowDown = true;
}
-
+ */
current->clearSpeedAdjustment();
if (current->checkPositionAndIntentions(*closest)
if (closest->getId() != current->getId())
current->setSpeedAdjustment(closest->getSpeed() *
(mindist / 100));
+ if (closest->getAircraft()->isScheduledForTakeoff())
+ current->getAircraft()->scheduleForATCTowerDepartureControl();
else
current->setSpeedAdjustment(0); // This can only happen when the user aircraft is the one closest
if (mindist < maxAllowableDistance) {
if ((origStatus != currStatus) && available) {
//cerr << "Issueing hold short instrudtion " << currStatus << " " << available << endl;
if (currStatus == true) { // No has a hold short instruction
- transmit(&(*current), MSG_HOLD_POSITION, ATC_GROUND_TO_AIR);
+ transmit(&(*current), MSG_HOLD_POSITION, ATC_GROUND_TO_AIR, true);
//cerr << "Transmittin hold short instrudtion " << currStatus << " " << available << endl;
current->setState(1);
} else {
- transmit(&(*current), MSG_RESUME_TAXI, ATC_GROUND_TO_AIR);
+ transmit(&(*current), MSG_RESUME_TAXI, ATC_GROUND_TO_AIR, true);
//cerr << "Transmittig resume instrudtion " << currStatus << " " << available << endl;
current->setState(2);
}
//cerr << "Current state " << current->getState() << endl;
} else {
}
- int state = current->getState();
- if ((state == 1) && (available)) {
- //cerr << "ACKNOWLEDGE HOLD" << endl;
- transmit(&(*current), MSG_ACKNOWLEDGE_HOLD_POSITION, ATC_AIR_TO_GROUND);
- current->setState(0);
- current->setHoldPosition(true);
- lastTransmission = now;
- available = false;
-
+ //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 ((state == 2) && (available)) {
- //cerr << "ACKNOWLEDGE RESUME" << endl;
- transmit(&(*current), MSG_ACKNOWLEDGE_RESUME_TAXI, ATC_AIR_TO_GROUND);
- current->setState(0);
- current->setHoldPosition(false);
- lastTransmission = now;
- available = false;
+ if (checkTransmissionState(2,2, current, now, MSG_ACKNOWLEDGE_RESUME_TAXI, ATC_AIR_TO_GROUND)) {
+ current->setState(0);
+ current->setHoldPosition(false);
}
-}
+}
/**
* Check whether situations occur where the current aircraft is waiting for itself
}
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));
+}
+
+
+
+
+void FGGroundNetwork::render(bool visible)
+{
+
+ SGMaterialLib *matlib = globals->get_matlib();
+ if (group) {
+ //int nr = ;
+ globals->get_scenery()->get_scene_graph()->removeChild(group);
+ //while (group->getNumChildren()) {
+ // cerr << "Number of children: " << group->getNumChildren() << endl;
+ simgear::EffectGeode* geode = (simgear::EffectGeode*) group->getChild(0);
+ //osg::MatrixTransform *obj_trans = (osg::MatrixTransform*) group->getChild(0);
+ //geode->releaseGLObjects();
+ //group->removeChild(geode);
+ //delete geode;
+ group = 0;
+ }
+ if (visible) {
+ group = new osg::Group;
+
+ //for ( FGTaxiSegmentVectorIterator i = segments.begin(); i != segments.end(); i++) {
+ double dx = 0;
+ for (TrafficVectorIterator i = activeTraffic.begin(); i != activeTraffic.end(); i++) {
+ // Handle start point
+ int pos = i->getCurrentPosition() - 1;
+ if (pos >= 0) {
+
+ SGGeod start(SGGeod::fromDeg((i->getLongitude()), (i->getLatitude())));
+ SGGeod end (SGGeod::fromDeg(segments[pos]->getEnd()->getLongitude(), segments[pos]->getEnd()->getLatitude()));
+
+ double length = SGGeodesy::distanceM(start, end);
+ //heading = SGGeodesy::headingDeg(start->getGeod(), end->getGeod());
+
+ double az2, heading; //, distanceM;
+ SGGeodesy::inverse(start, end, heading, az2, length);
+ double coveredDistance = length * 0.5;
+ SGGeod center;
+ SGGeodesy::direct(start, heading, coveredDistance, center, az2);
+ //cerr << "Active Aircraft : Centerpoint = (" << center.getLatitudeDeg() << ", " << center.getLongitudeDeg() << "). Heading = " << heading << endl;
+ ///////////////////////////////////////////////////////////////////////////////
+ // Make a helper function out of this
+ osg::Matrix obj_pos;
+ osg::MatrixTransform *obj_trans = new osg::MatrixTransform;
+ obj_trans->setDataVariance(osg::Object::STATIC);
+
+ WorldCoordinate( obj_pos, center.getLatitudeDeg(), center.getLongitudeDeg(), parent->elevation()+8+dx, -(heading) );
+
+ 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)-1;
+ if (k >= 0) {
+ osg::MatrixTransform *obj_trans = new osg::MatrixTransform;
+ obj_trans->setDataVariance(osg::Object::STATIC);
+
+ WorldCoordinate( obj_pos, segments[k]->getLatitude(), segments[k]->getLongitude(), parent->elevation()+8+dx, -(segments[k]->getHeading()) );
+
+ obj_trans->setMatrix( obj_pos );
+ //osg::Vec3 center(0, 0, 0)
+
+ float width = segments[k]->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 = 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 );
+ }
+ }
+ //dx += 0.1;
+ }
+ globals->get_scenery()->get_scene_graph()->addChild(group);
+ }
+}
+
+string FGGroundNetwork::getName() {
+ return string(parent->getId() + "-ground");
+}