]> git.mxchange.org Git - flightgear.git/blob - src/Navaids/PositionedBinding.cxx
fix trx and rx heights and improve calculations
[flightgear.git] / src / Navaids / PositionedBinding.cxx
1 #ifdef HAVE_CONFIG_H
2 #  include "config.h"
3 #endif
4
5 #include "PositionedBinding.hxx"
6
7 #include <map>
8
9 #include <simgear/props/props.hxx>
10 #include <simgear/debug/logstream.hxx>
11 #include <simgear/structure/exception.hxx>
12
13 #include <Main/fg_props.hxx>
14 #include <Navaids/navrecord.hxx>
15 #include <Airports/simple.hxx>
16 #include <Airports/runways.hxx>
17 #include <ATC/CommStation.hxx>
18
19 typedef std::map<SGPropertyNode*, flightgear::PositionedBinding*> BindingMap;
20 static BindingMap static_bindings;
21     
22 namespace {
23     
24 class PropertyDeleteObserver : public SGPropertyChangeListener
25 {
26 public:
27     virtual void childRemoved(SGPropertyNode*, SGPropertyNode* node)
28     {
29         BindingMap::iterator it = static_bindings.find(node);
30         if (it != static_bindings.end()) {
31             SG_LOG(SG_GENERAL, SG_INFO, "saw remove of:" << node->getPath() << ", deleting binding");
32             delete it->second;
33             static_bindings.erase(it);
34         }
35     }
36 };
37     
38 static PropertyDeleteObserver* static_deleteObserver = NULL;
39     
40 } // of anonymous namespace
41     
42 namespace flightgear
43 {
44
45 PositionedBinding::PositionedBinding(const FGPositioned* pos, SGPropertyNode* nd) :
46     p(const_cast<FGPositioned*>(pos)),
47     tied(nd)
48 {
49     if (!static_deleteObserver) {
50         static_deleteObserver = new PropertyDeleteObserver;
51         globals->get_props()->addChangeListener(static_deleteObserver, false);
52     }
53     
54     nd->setDoubleValue("latitude-deg", p->latitude());
55     nd->setDoubleValue("longitude-deg", p->longitude());
56     
57     if (p->elevation() > -1000) {
58         nd->setDoubleValue("elevation-ft", p->elevation());
59     }
60     
61     nd->setStringValue("ident", p->ident());
62     if (!p->name().empty()) {
63         nd->setStringValue("name", p->name());
64     }
65     
66     nd->setStringValue("type", FGPositioned::nameForType(p->type()));
67 }
68
69 PositionedBinding::~PositionedBinding()
70 {
71     tied.Untie();
72 }
73
74 void PositionedBinding::bind(FGPositioned* pos, SGPropertyNode* node)
75 {
76     BindingMap::iterator it = static_bindings.find(node);
77     if (it != static_bindings.end()) {
78         throw sg_exception("duplicate positioned binding", node->getPath());
79     }
80     
81     PositionedBinding* binding = pos->createBinding(node);
82     static_bindings.insert(it, std::make_pair(node, binding));
83 }
84
85 NavaidBinding::NavaidBinding(const FGNavRecord* nav, SGPropertyNode* nd) :
86     PositionedBinding(nav, nd)
87 {
88     FGPositioned::Type ty = nav->type();
89     if (ty == FGPositioned::NDB) {
90         nd->setDoubleValue("frequency-khz", nav->get_freq() / 100.0);
91     } else {
92         nd->setDoubleValue("frequency-mhz", nav->get_freq() / 100.0);
93     }
94     
95     if ((ty == FGPositioned::LOC) || (ty == FGPositioned::ILS)) {
96       nd->setDoubleValue("loc-course-deg", nav->get_multiuse());
97     }
98     
99     if (ty == FGPositioned::GS) {
100         nd->setDoubleValue("gs-angle-deg", nav->get_multiuse());
101     }
102     
103     nd->setDoubleValue("range-nm", nav->get_range());
104     
105     if (nav->runway()) {
106         // don't want to create a cycle in the graph, so we don't re-bind
107         // the airport/runway node here - just expose the IDs
108         nd->setStringValue("airport", nav->runway()->airport()->ident());
109         nd->setStringValue("runway", nav->runway()->ident());
110     }
111 };
112
113 RunwayBinding::RunwayBinding(const FGRunway* rwy, SGPropertyNode* nd) :
114     PositionedBinding(rwy, nd)
115 {
116     nd->setDoubleValue("length-ft", rwy->lengthFt());
117     nd->setDoubleValue("length-m", rwy->lengthM());
118     nd->setDoubleValue("width-ft", rwy->widthFt());
119     nd->setDoubleValue("width-m", rwy->widthM());
120     nd->setDoubleValue("heading-deg", rwy->headingDeg());
121     nd->setBoolValue("hard-surface", rwy->isHardSurface());
122     
123     nd->setDoubleValue("threshold-displacement-m", rwy->displacedThresholdM());
124     nd->setDoubleValue("stopway-m", rwy->stopwayM());
125     
126     if (rwy->ILS()) {
127         SGPropertyNode* ilsNode = nd->getChild("ils", 0, true);
128         PositionedBinding::bind(rwy->ILS(), ilsNode);
129     }
130 }
131
132 AirportBinding::AirportBinding(const FGAirport* apt, SGPropertyNode* nd) :
133     PositionedBinding(apt, nd)
134 {
135     nd->setIntValue("num-runways", apt->numRunways());
136     
137     SGGeod tower = apt->getTowerLocation();
138     nd->setDoubleValue("tower/latitude-deg", tower.getLatitudeDeg());
139     nd->setDoubleValue("tower/longitude-deg", tower.getLongitudeDeg());
140     nd->setDoubleValue("tower/elevation-ft", tower.getElevationFt());
141     
142     for (unsigned int r=0; r<apt->numRunways(); ++r) {
143         SGPropertyNode* rn = nd->getChild("runway", r, true);
144         FGRunway* rwy = apt->getRunwayByIndex(r);
145         PositionedBinding::bind(rwy, rn);
146     }
147     
148     for (unsigned int c=0; c<apt->commStations().size(); ++c) {
149         flightgear::CommStation* comm = apt->commStations()[c];
150         std::string tynm = FGPositioned::nameForType(comm->type());
151         
152       // for some standard frequence types, we don't care about the ident,
153       // so just list the frequencies under one group.
154         if ((comm->type() == FGPositioned::FREQ_ATIS) ||
155             (comm->type() == FGPositioned::FREQ_AWOS) ||
156             (comm->type() == FGPositioned::FREQ_TOWER) ||
157             (comm->type() == FGPositioned::FREQ_GROUND))
158         {
159           SGPropertyNode* commNode = nd->getChild(tynm, 0, true);
160           int count = nd->getChildren("frequency-mhz").size();
161           SGPropertyNode* freqNode = commNode->getChild("frequency-mhz", count, true);
162           freqNode->setDoubleValue(comm->freqMHz());
163         } else {
164       // for other kinds of frequency, there's more variation, so list the ID too
165           int count = nd->getChildren(tynm).size();
166           SGPropertyNode* commNode = nd->getChild(tynm, count, true);
167           commNode->setStringValue("ident", comm->ident());
168           commNode->setDoubleValue("frequency-mhz", comm->freqMHz());
169
170         }
171       } // of airprot comm stations iteration
172 }
173
174 CommStationBinding::CommStationBinding(const CommStation* sta, SGPropertyNode* node) :
175     PositionedBinding(sta, node)
176 {
177     node->setIntValue("range-nm", sta->rangeNm());
178     node->setDoubleValue("frequency-mhz", sta->freqMHz());
179     
180     if (sta->airport()) {
181         // don't want to create a cycle in the graph, so we don't re-bind
182         // the airport/runway node here - just expose the IDs
183         node->setStringValue("airport", sta->airport()->ident());
184     }
185 }
186
187 } // of namespace flightgear
188