]> git.mxchange.org Git - flightgear.git/blob - src/Navaids/PositionedBinding.cxx
758491cc5743aba101509de3c32977245c91a32f
[flightgear.git] / src / Navaids / PositionedBinding.cxx
1 #include "PositionedBinding.hxx"
2
3 #include <map>
4
5 #include <simgear/props/props.hxx>
6 #include <simgear/debug/logstream.hxx>
7 #include <simgear/structure/exception.hxx>
8
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>
14
15 typedef std::map<SGPropertyNode*, flightgear::PositionedBinding*> BindingMap;
16 static BindingMap static_bindings;
17     
18 namespace {
19     
20 class PropertyDeleteObserver : public SGPropertyChangeListener
21 {
22 public:
23     virtual void childRemoved(SGPropertyNode*, SGPropertyNode* node)
24     {
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");
28             delete it->second;
29             static_bindings.erase(it);
30         }
31     }
32 };
33     
34 static PropertyDeleteObserver* static_deleteObserver = NULL;
35     
36 } // of anonymous namespace
37     
38 namespace flightgear
39 {
40
41 PositionedBinding::PositionedBinding(const FGPositioned* pos, SGPropertyNode* nd) :
42     p(const_cast<FGPositioned*>(pos)),
43     tied(nd)
44 {
45     if (!static_deleteObserver) {
46         static_deleteObserver = new PropertyDeleteObserver;
47         globals->get_props()->addChangeListener(static_deleteObserver, false);
48     }
49     
50     nd->setDoubleValue("latitude-deg", p->latitude());
51     nd->setDoubleValue("longitude-deg", p->longitude());
52     
53     if (p->elevation() > -1000) {
54         nd->setDoubleValue("elevation-ft", p->elevation());
55     }
56     
57     nd->setStringValue("ident", p->ident());
58     if (!p->name().empty()) {
59         nd->setStringValue("name", p->name());
60     }
61     
62     nd->setStringValue("type", FGPositioned::nameForType(p->type()));
63 }
64
65 PositionedBinding::~PositionedBinding()
66 {
67     tied.Untie();
68 }
69
70 void PositionedBinding::bind(FGPositioned* pos, SGPropertyNode* node)
71 {
72     BindingMap::iterator it = static_bindings.find(node);
73     if (it != static_bindings.end()) {
74         throw sg_exception("duplicate positioned binding", node->getPath());
75     }
76     
77     PositionedBinding* binding = pos->createBinding(node);
78     static_bindings.insert(it, std::make_pair(node, binding));
79 }
80
81 NavaidBinding::NavaidBinding(const FGNavRecord* nav, SGPropertyNode* nd) :
82     PositionedBinding(nav, nd)
83 {
84     FGPositioned::Type ty = nav->type();
85     if (ty == FGPositioned::NDB) {
86         nd->setDoubleValue("frequency-khz", nav->get_freq() / 100.0);
87     } else {
88         nd->setDoubleValue("frequency-mhz", nav->get_freq() / 100.0);
89     }
90     
91     if ((ty == FGPositioned::LOC) || (ty == FGPositioned::ILS)) {
92       nd->setDoubleValue("loc-course-deg", nav->get_multiuse());
93     }
94     
95     if (ty == FGPositioned::GS) {
96         nd->setDoubleValue("gs-angle-deg", nav->get_multiuse());
97     }
98     
99     nd->setDoubleValue("range-nm", nav->get_range());
100     
101     if (nav->runway()) {
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());
106     }
107 };
108
109 RunwayBinding::RunwayBinding(const FGRunway* rwy, SGPropertyNode* nd) :
110     PositionedBinding(rwy, nd)
111 {
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());
118     
119     nd->setDoubleValue("threshold-displacement-m", rwy->displacedThresholdM());
120     nd->setDoubleValue("stopway-m", rwy->stopwayM());
121     
122     if (rwy->ILS()) {
123         SGPropertyNode* ilsNode = nd->getChild("ils", 0, true);
124         PositionedBinding::bind(rwy->ILS(), ilsNode);
125     }
126 }
127
128 AirportBinding::AirportBinding(const FGAirport* apt, SGPropertyNode* nd) :
129     PositionedBinding(apt, nd)
130 {
131     nd->setIntValue("num-runways", apt->numRunways());
132     
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());
137     
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);
142     }
143     
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();
148         
149         SGPropertyNode* commNode = nd->getChild(tynm, count, true);
150         commNode->setStringValue("ident", comm->ident());
151         commNode->setDoubleValue("frequency-mhz", comm->freqMHz());
152     }
153 }
154
155 CommStationBinding::CommStationBinding(const CommStation* sta, SGPropertyNode* node) :
156     PositionedBinding(sta, node)
157 {
158     node->setIntValue("range-nm", sta->rangeNm());
159     node->setDoubleValue("frequency-mhz", sta->freqMHz());
160     
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());
165     }
166 }
167
168 } // of namespace flightgear
169