3 // Written by Vivian MEAZZA, started Feb 2008.
6 // Copyright (C) 2008 Vivian Meazza
8 // This program is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU General Public License as
10 // published by the Free Software Foundation; either version 2 of the
11 // License, or (at your option) any later version.
13 // This program is distributed in the hope that it will be useful, but
14 // WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 // General Public License for more details.
18 // You should have received a copy of the GNU General Public License
19 // along with this program; if not, write to the Free Software
20 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
28 #include "agradar.hxx"
31 agRadar::agRadar(SGPropertyNode *node) : wxRadarBg(node)
34 _name = node->getStringValue("name", "air-ground-radar");
35 _num = node->getIntValue("number", 0);
46 _user_hdg_deg_node = fgGetNode("/orientation/heading-deg", true);
47 _user_pitch_deg_node = fgGetNode("/orientation/pitch-deg", true);
48 _user_roll_deg_node = fgGetNode("/orientation/roll-deg", true);
50 _terrain_warning_node = fgGetNode("/sim/alarms/terrain-warning", true);
51 _terrain_warning_node->setBoolValue(false);
55 // those properties are used by a radar instrument of a MFD
56 // input switch = OFF | TST | STBY | ON
57 // input mode = WX | WXA | MAP | TW
58 // output status = STBY | TEST | WX | WXA | MAP | blank
59 // input lightning = true | false
60 // input TRK = +/- n degrees
61 // input TILT = +/- n degree
62 // input autotilt = true | false
63 // input range = n nm (20/40/80)
64 // input display-mode = arc | rose | map | plan
66 _Instrument->setFloatValue("trk", 0.0);
67 _Instrument->setFloatValue("tilt",-2.5);
68 _Instrument->setStringValue("status","");
69 _Instrument->setIntValue("mode-control", 5);
71 _Instrument->setBoolValue("stabilisation/roll", false);
72 _Instrument->setBoolValue("stabilisation/pitch", false);
74 _Instrument->getNode("antenna/x-offset-m", true);
75 _Instrument->getNode("antenna/y-offset-m", true);
76 _Instrument->getNode("antenna/z-offset-m", true);
78 _Instrument->getNode("terrain-warning/elev-limit-deg", true);
79 _Instrument->getNode("terrain-warning/elev-step-deg", true);
80 _Instrument->getNode("terrain-warning/az-limit-deg", true);
81 _Instrument->getNode("terrain-warning/az-step-deg", true);
82 _Instrument->getNode("terrain-warning/max-range-m", true);
83 _Instrument->getNode("terrain-warning/min-range-m", true);
84 _Instrument->getNode("terrain-warning/tilt",true);
86 _Instrument->getNode("terrain-warning/hit/brg-deg", true);
87 _Instrument->getNode("terrain-warning/hit/range-m", true);
88 _Instrument->getNode("terrain-warning/hit/material", true);
89 _Instrument->getNode("terrain-warning/hit/bumpiness", true);
91 _Instrument->getNode("terrain-warning/stabilisation/roll", true);
92 _Instrument->getNode("terrain-warning/stabilisation/pitch", true);
93 // cout << "init done" << endl;
98 agRadar::update (double delta_time_sec)
100 if ( ! _sim_init_done ) {
102 if ( ! fgGetBool("sim/sceneryloaded", false) )
105 _sim_init_done = true;
108 if ( !_odg || ! _serviceable_node->getBoolValue() ) {
109 _Instrument->setStringValue("status","");
113 _time += delta_time_sec;
115 if (_time < _interval)
122 // wxRadarBg::update(delta_time_sec);
126 agRadar::setUserPos()
128 userpos.setLatitudeDeg(_user_lat_node->getDoubleValue());
129 userpos.setLongitudeDeg(_user_lon_node->getDoubleValue());
130 userpos.setElevationM(_user_alt_node->getDoubleValue() * SG_FEET_TO_METER);
134 agRadar::getCartUserPos() const {
135 SGVec3d cartUserPos = SGVec3d::fromGeod(userpos);
140 agRadar::getCartAntennaPos() const {
142 float yaw = _user_hdg_deg_node->getDoubleValue();
143 float pitch = _user_pitch_deg_node->getDoubleValue();
144 float roll = _user_roll_deg_node->getDoubleValue();
146 double x_offset_m =_Instrument->getDoubleValue("antenna/x-offset-m", 0);
147 double y_offset_m =_Instrument->getDoubleValue("antenna/y-offset-m", 0);
148 double z_offset_m =_Instrument->getDoubleValue("antenna/y-offset-m", 0);
150 // convert geodetic positions to geocentered
151 SGVec3d cartuserPos = getCartUserPos();
153 // Transform to the right coordinate frame, configuration is done in
154 // the x-forward, y-right, z-up coordinates (feet), computation
155 // in the simulation usual body x-forward, y-right, z-down coordinates
157 SGVec3d _off(x_offset_m, y_offset_m, -z_offset_m);
159 // Transform the user position to the horizontal local coordinate system.
160 SGQuatd hlTrans = SGQuatd::fromLonLat(userpos);
162 // and postrotate the orientation of the user model wrt the horizontal
164 hlTrans *= SGQuatd::fromYawPitchRollDeg(yaw,pitch,roll);
166 // The offset converted to the usual body fixed coordinate system
167 // rotated to the earth-fixed coordinates axis
168 SGVec3d off = hlTrans.backTransform(_off);
170 // Add the position offset of the user model to get the geocentered position
171 SGVec3d offsetPos = cartuserPos + off;
177 agRadar::setAntennaPos() {
178 SGGeodesy::SGCartToGeod(getCartAntennaPos(), antennapos);
182 agRadar::setUserVec(double az, double el)
184 float yaw = _user_hdg_deg_node->getDoubleValue();
185 float pitch = _user_pitch_deg_node->getDoubleValue();
186 float roll = _user_roll_deg_node->getDoubleValue();
187 int mode = _radar_mode_control_node->getIntValue();
188 double tilt = _Instrument->getDoubleValue("tilt");
189 double trk = _Instrument->getDoubleValue("trk");
190 bool roll_stab = _Instrument->getBoolValue("stabilisation/roll");
191 bool pitch_stab = _Instrument->getBoolValue("stabilisation/pitch");
193 SGQuatd offset = SGQuatd::fromYawPitchRollDeg(az + trk, el + tilt, 0);
195 // Transform the antenna position to the horizontal local coordinate system.
196 SGQuatd hlTrans = SGQuatd::fromLonLat(antennapos);
198 // and postrotate the orientation of the radar wrt the horizontal
200 hlTrans *= SGQuatd::fromYawPitchRollDeg(yaw,
201 pitch_stab ? 0 :pitch,
202 roll_stab ? 0 : roll);
205 // now rotate the rotation vector back into the
206 // earth centered frames coordinates
207 SGVec3d angleaxis(1,0,0);
208 uservec = hlTrans.backTransform(angleaxis);
213 agRadar::getMaterial(){
215 if (globals->get_scenery()->get_elevation_m(hitpos, _elevation_m, &_material)){
216 //_ht_agl_ft = pos.getElevationFt() - _elevation_m * SG_METER_TO_FEET;
218 const vector<string>& names = _material->get_names();
220 _solid = _material->get_solid();
221 _load_resistance = _material->get_load_resistance();
222 _frictionFactor =_material->get_friction_factor();
223 _bumpinessFactor = _material->get_bumpiness();
226 _mat_name = names[0].c_str();
231 /*cout << "material " << mat_name
232 << " solid " << _solid
233 << " load " << _load_resistance
234 << " frictionFactor " << frictionFactor
235 << " _bumpinessFactor " << _bumpinessFactor
245 agRadar::update_terrain()
247 int mode = _radar_mode_control_node->getIntValue();
251 double az_limit = 50;
253 double max_range = 40000;
254 double min_range = 250;
256 bool roll_stab = _Instrument->getBoolValue("stabilisation/roll");
257 bool pitch_stab = _Instrument->getBoolValue("stabilisation/pitch");
258 //string status = "";
265 roll_stab = _Instrument->getBoolValue("terrain-warning/stabilisation/roll", true);
266 pitch_stab = _Instrument->getBoolValue("terrain-warning/stabilisation/pitch", false);
267 tilt = _Instrument->getDoubleValue("terrain-warning/tilt", -2);
268 el_limit = _Instrument->getDoubleValue("terrain-warning/elev-limit-deg", 2);
269 el_step = _Instrument->getDoubleValue("terrain-warning/elev-step-deg", 1);
270 az_limit = _Instrument->getDoubleValue("terrain-warning/az-limit-deg", 1);
271 az_step = _Instrument->getDoubleValue("terrain-warning/az-step-deg", 1.5);
272 max_range = _Instrument->getDoubleValue("terrain-warning/max-range-m", 4000);
273 min_range = _Instrument->getDoubleValue("terrain-warning/min-range-m", 250);
276 _Instrument->setDoubleValue("tilt", tilt);
277 _Instrument->setBoolValue("stabilisation/roll", roll_stab);
278 _Instrument->setBoolValue("stabilisation/pitch", pitch_stab);
279 _Instrument->setStringValue("status", status);
280 _Instrument->setDoubleValue("limit-deg", az_limit);
281 _Instrument->setBoolValue("heading-marker", hdg_mkr);
284 SGVec3d cartantennapos = getCartAntennaPos();
286 for(double brg = -az_limit; brg <= az_limit; brg += az_step){
287 for(double elev = el_limit; elev >= - el_limit; elev -= el_step){
288 setUserVec(brg, elev);
290 globals->get_scenery()->get_cart_ground_intersection(cartantennapos, uservec, nearestHit);
291 SGGeodesy::SGCartToGeod(nearestHit, hitpos);
293 double course1, course2, distance;
295 SGGeodesy::inverse(hitpos, antennapos, course1, course2, distance);
297 if (distance >= min_range && distance <= max_range) {
298 _terrain_warning_node->setBoolValue(true);
300 _Instrument->setDoubleValue("terrain-warning/hit/brg-deg", course2);
301 _Instrument->setDoubleValue("terrain-warning/hit/range-m", distance);
302 _Instrument->setStringValue("terrain-warning/hit/material", _mat_name.c_str());
303 _Instrument->setDoubleValue("terrain-warning/hit/bumpiness", _bumpinessFactor);
304 _Instrument->setDoubleValue("terrain-warning/hit/elevation-m", _elevation_m);
306 _terrain_warning_node->setBoolValue(false);
307 _Instrument->setDoubleValue("terrain-warning/hit/brg-deg", 0);
308 _Instrument->setDoubleValue("terrain-warning/hit/range-m", 0);
309 _Instrument->setStringValue("terrain-warning/hit/material", "");
310 _Instrument->setDoubleValue("terrain-warning/hit/bumpiness", 0);
311 _Instrument->setDoubleValue("terrain-warning/hit/elevation-m",0);
314 //cout << "usr hdg " << _user_hdg_deg_node->getDoubleValue()
315 // << " ant brg " << course2
316 // << " elev " << _Instrument->getDoubleValue("tilt")
317 // << " gnd rng nm " << distance * SG_METER_TO_NM
318 // << " ht " << hitpos.getElevationFt()
319 // << " mat " << _mat_name
320 // << " solid " << _solid
321 // << " bumpiness " << _bumpinessFactor