1 #include "PositionedBinding.hxx"
5 #include <simgear/props/props.hxx>
6 #include <simgear/debug/logstream.hxx>
7 #include <simgear/structure/exception.hxx>
9 #include <Main/fg_props.hxx>
10 #include <Navaids/navrecord.hxx>
11 #include <Airports/simple.hxx>
12 #include <Airports/runways.hxx>
13 #include <ATC/CommStation.hxx>
15 typedef std::map<SGPropertyNode*, flightgear::PositionedBinding*> BindingMap;
16 static BindingMap static_bindings;
20 class PropertyDeleteObserver : public SGPropertyChangeListener
23 virtual void childRemoved(SGPropertyNode*, SGPropertyNode* node)
25 BindingMap::iterator it = static_bindings.find(node);
26 if (it != static_bindings.end()) {
27 SG_LOG(SG_GENERAL, SG_INFO, "saw remove of:" << node->getPath() << ", deleting binding");
29 static_bindings.erase(it);
34 static PropertyDeleteObserver* static_deleteObserver = NULL;
36 } // of anonymous namespace
41 PositionedBinding::PositionedBinding(const FGPositioned* pos, SGPropertyNode* nd) :
42 p(const_cast<FGPositioned*>(pos)),
45 if (!static_deleteObserver) {
46 static_deleteObserver = new PropertyDeleteObserver;
47 globals->get_props()->addChangeListener(static_deleteObserver, false);
50 nd->setDoubleValue("latitude-deg", p->latitude());
51 nd->setDoubleValue("longitude-deg", p->longitude());
53 if (p->elevation() > -1000) {
54 nd->setDoubleValue("elevation-ft", p->elevation());
57 nd->setStringValue("ident", p->ident());
58 if (!p->name().empty()) {
59 nd->setStringValue("name", p->name());
62 nd->setStringValue("type", FGPositioned::nameForType(p->type()));
65 PositionedBinding::~PositionedBinding()
70 void PositionedBinding::bind(FGPositioned* pos, SGPropertyNode* node)
72 BindingMap::iterator it = static_bindings.find(node);
73 if (it != static_bindings.end()) {
74 throw sg_exception("duplicate positioned binding", node->getPath());
77 PositionedBinding* binding = pos->createBinding(node);
78 static_bindings.insert(it, std::make_pair(node, binding));
81 NavaidBinding::NavaidBinding(const FGNavRecord* nav, SGPropertyNode* nd) :
82 PositionedBinding(nav, nd)
84 FGPositioned::Type ty = nav->type();
85 if (ty == FGPositioned::NDB) {
86 nd->setDoubleValue("frequency-khz", nav->get_freq() / 100.0);
88 nd->setDoubleValue("frequency-mhz", nav->get_freq() / 100.0);
91 if ((ty == FGPositioned::LOC) || (ty == FGPositioned::ILS)) {
92 nd->setDoubleValue("loc-course-deg", nav->get_multiuse());
95 if (ty == FGPositioned::GS) {
96 nd->setDoubleValue("gs-angle-deg", nav->get_multiuse());
99 nd->setDoubleValue("range-nm", nav->get_range());
102 // don't want to create a cycle in the graph, so we don't re-bind
103 // the airport/runway node here - just expose the IDs
104 nd->setStringValue("airport", nav->runway()->airport()->ident());
105 nd->setStringValue("runway", nav->runway()->ident());
109 RunwayBinding::RunwayBinding(const FGRunway* rwy, SGPropertyNode* nd) :
110 PositionedBinding(rwy, nd)
112 nd->setDoubleValue("length-ft", rwy->lengthFt());
113 nd->setDoubleValue("length-m", rwy->lengthM());
114 nd->setDoubleValue("width-ft", rwy->widthFt());
115 nd->setDoubleValue("width-m", rwy->widthM());
116 nd->setDoubleValue("heading-deg", rwy->headingDeg());
117 nd->setBoolValue("hard-surface", rwy->isHardSurface());
119 nd->setDoubleValue("threshold-displacement-m", rwy->displacedThresholdM());
120 nd->setDoubleValue("stopway-m", rwy->stopwayM());
123 SGPropertyNode* ilsNode = nd->getChild("ils", 0, true);
124 PositionedBinding::bind(rwy->ILS(), ilsNode);
128 AirportBinding::AirportBinding(const FGAirport* apt, SGPropertyNode* nd) :
129 PositionedBinding(apt, nd)
131 nd->setIntValue("num-runways", apt->numRunways());
133 SGGeod tower = apt->getTowerLocation();
134 nd->setDoubleValue("tower/latitude-deg", tower.getLatitudeDeg());
135 nd->setDoubleValue("tower/longitude-deg", tower.getLongitudeDeg());
136 nd->setDoubleValue("tower/elevation-ft", tower.getElevationFt());
138 for (unsigned int r=0; r<apt->numRunways(); ++r) {
139 SGPropertyNode* rn = nd->getChild("runway", r, true);
140 FGRunway* rwy = apt->getRunwayByIndex(r);
141 PositionedBinding::bind(rwy, rn);
144 for (unsigned int c=0; c<apt->commStations().size(); ++c) {
145 flightgear::CommStation* comm = apt->commStations()[c];
146 std::string tynm = FGPositioned::nameForType(comm->type());
147 int count = nd->getChildren(tynm).size();
149 SGPropertyNode* commNode = nd->getChild(tynm, count, true);
150 commNode->setStringValue("ident", comm->ident());
151 commNode->setDoubleValue("frequency-mhz", comm->freqMHz());
155 CommStationBinding::CommStationBinding(const CommStation* sta, SGPropertyNode* node) :
156 PositionedBinding(sta, node)
158 node->setIntValue("range-nm", sta->rangeNm());
159 node->setDoubleValue("frequency-mhz", sta->freqMHz());
161 if (sta->airport()) {
162 // don't want to create a cycle in the graph, so we don't re-bind
163 // the airport/runway node here - just expose the IDs
164 node->setStringValue("airport", sta->airport()->ident());
168 } // of namespace flightgear