New TCAS display mode for wxradar.
- new mode to display traffic in TCAS-style - select symbols according to TCAS-threat level
This commit is contained in:
parent
bdd931aed9
commit
b6eba5ce65
2 changed files with 125 additions and 19 deletions
|
@ -69,18 +69,29 @@ using std::endl;
|
||||||
static const float UNIT = 1.0f / 8.0f; // 8 symbols in a row/column in the texture
|
static const float UNIT = 1.0f / 8.0f; // 8 symbols in a row/column in the texture
|
||||||
static const char *DEFAULT_FONT = "typewriter.txf";
|
static const char *DEFAULT_FONT = "typewriter.txf";
|
||||||
|
|
||||||
|
|
||||||
wxRadarBg::wxRadarBg(SGPropertyNode *node) :
|
wxRadarBg::wxRadarBg(SGPropertyNode *node) :
|
||||||
_name(node->getStringValue("name", "radar")),
|
_name(node->getStringValue("name", "radar")),
|
||||||
_num(node->getIntValue("number", 0)),
|
_num(node->getIntValue("number", 0)),
|
||||||
_time(0.0),
|
_time(0.0),
|
||||||
_interval(node->getDoubleValue("update-interval-sec", 1.0)),
|
_interval(node->getDoubleValue("update-interval-sec", 1.0)),
|
||||||
|
_elapsed_time(0),
|
||||||
|
_persistance(0),
|
||||||
_sim_init_done(false),
|
_sim_init_done(false),
|
||||||
_odg(0),
|
_odg(0),
|
||||||
_last_switchKnob("off"),
|
_range_nm(0),
|
||||||
|
_scale(0),
|
||||||
|
_angle_offset(0),
|
||||||
|
_view_heading(0),
|
||||||
|
_x_offset(0),
|
||||||
|
_y_offset(0),
|
||||||
|
_radar_ref_rng(0),
|
||||||
|
_lat(0),
|
||||||
|
_lon(0),
|
||||||
_antenna_ht(node->getDoubleValue("antenna-ht-ft", 0.0)),
|
_antenna_ht(node->getDoubleValue("antenna-ht-ft", 0.0)),
|
||||||
_resultTexture(0),
|
_resultTexture(0),
|
||||||
_wxEcho(0)
|
_wxEcho(0),
|
||||||
|
_font_size(0),
|
||||||
|
_font_spacing(0)
|
||||||
{
|
{
|
||||||
string branch;
|
string branch;
|
||||||
branch = "/instrumentation/" + _name;
|
branch = "/instrumentation/" + _name;
|
||||||
|
@ -174,6 +185,7 @@ wxRadarBg::init ()
|
||||||
_radar_symbol_node = n->getNode("symbol", true);
|
_radar_symbol_node = n->getNode("symbol", true);
|
||||||
_radar_centre_node = n->getNode("centre", true);
|
_radar_centre_node = n->getNode("centre", true);
|
||||||
_radar_rotate_node = n->getNode("rotate", true);
|
_radar_rotate_node = n->getNode("rotate", true);
|
||||||
|
_radar_tcas_node = n->getNode("tcas", true);
|
||||||
|
|
||||||
_radar_centre_node->setBoolValue(false);
|
_radar_centre_node->setBoolValue(false);
|
||||||
if (!_radar_coverage_node->hasValue())
|
if (!_radar_coverage_node->hasValue())
|
||||||
|
@ -231,6 +243,8 @@ wxRadarBg::init ()
|
||||||
osg::Camera *camera = _odg->getCamera();
|
osg::Camera *camera = _odg->getCamera();
|
||||||
camera->addChild(_radarGeode.get());
|
camera->addChild(_radarGeode.get());
|
||||||
camera->addChild(_textGeode.get());
|
camera->addChild(_textGeode.get());
|
||||||
|
|
||||||
|
updateFont();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -305,16 +319,6 @@ wxRadarBg::update (double delta_time_sec)
|
||||||
}
|
}
|
||||||
|
|
||||||
string switchKnob = _Instrument->getStringValue("switch", "on");
|
string switchKnob = _Instrument->getStringValue("switch", "on");
|
||||||
if (_last_switchKnob != switchKnob) {
|
|
||||||
// since 3D models don't share textures with the rest of the world
|
|
||||||
// we must locate them and replace their handle by hand
|
|
||||||
// only do that when the instrument is turned on
|
|
||||||
//if (_last_switchKnob == "off")
|
|
||||||
//_odg->set_texture(_texture_path.c_str(), _resultTexture->getHandle());
|
|
||||||
|
|
||||||
_last_switchKnob = switchKnob;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (switchKnob == "off") {
|
if (switchKnob == "off") {
|
||||||
_Instrument->setStringValue("status", "");
|
_Instrument->setStringValue("status", "");
|
||||||
} else if (switchKnob == "stby") {
|
} else if (switchKnob == "stby") {
|
||||||
|
@ -666,6 +670,7 @@ wxRadarBg::update_aircraft()
|
||||||
if (!_ai_enabled_node->getBoolValue())
|
if (!_ai_enabled_node->getBoolValue())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
bool draw_tcas = _radar_tcas_node->getBoolValue();
|
||||||
bool draw_echoes = _radar_position_node->getBoolValue();
|
bool draw_echoes = _radar_position_node->getBoolValue();
|
||||||
bool draw_symbols = _radar_symbol_node->getBoolValue();
|
bool draw_symbols = _radar_symbol_node->getBoolValue();
|
||||||
bool draw_data = _radar_data_node->getBoolValue();
|
bool draw_data = _radar_data_node->getBoolValue();
|
||||||
|
@ -697,7 +702,8 @@ wxRadarBg::update_aircraft()
|
||||||
model = ai->getChild(i);
|
model = ai->getChild(i);
|
||||||
if (!model->nChildren())
|
if (!model->nChildren())
|
||||||
continue;
|
continue;
|
||||||
if (model->getIntValue("id") == selected_id) {
|
if ((model->getIntValue("id") == selected_id)&&
|
||||||
|
(!draw_tcas)) {
|
||||||
selected_ac = model; // save selected model for last iteration
|
selected_ac = model; // save selected model for last iteration
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -752,8 +758,14 @@ wxRadarBg::update_aircraft()
|
||||||
bearing += _angle_offset;
|
bearing += _angle_offset;
|
||||||
heading += _angle_offset;
|
heading += _angle_offset;
|
||||||
|
|
||||||
|
bool is_tcas_contact = false;
|
||||||
|
if (draw_tcas)
|
||||||
|
{
|
||||||
|
is_tcas_contact = update_tcas(model,range,user_alt,alt,bearing,radius);
|
||||||
|
}
|
||||||
|
|
||||||
// pos mode
|
// pos mode
|
||||||
if (draw_echoes) {
|
if (draw_echoes && (!is_tcas_contact)) {
|
||||||
float size = echo_radius * 120 * UNIT;
|
float size = echo_radius * 120 * UNIT;
|
||||||
|
|
||||||
const osg::Vec2f texBase(3 * UNIT, 3 * UNIT);
|
const osg::Vec2f texBase(3 * UNIT, 3 * UNIT);
|
||||||
|
@ -764,7 +776,7 @@ wxRadarBg::update_aircraft()
|
||||||
}
|
}
|
||||||
|
|
||||||
// data mode
|
// data mode
|
||||||
if (draw_symbols) {
|
if (draw_symbols && (!draw_tcas)) {
|
||||||
const osg::Vec2f texBase(0, 3 * UNIT);
|
const osg::Vec2f texBase(0, 3 * UNIT);
|
||||||
float size = 600 * UNIT;
|
float size = 600 * UNIT;
|
||||||
osg::Matrixf m(osg::Matrixf::scale(size, size, 1.0f)
|
osg::Matrixf m(osg::Matrixf::scale(size, size, 1.0f)
|
||||||
|
@ -774,11 +786,91 @@ wxRadarBg::update_aircraft()
|
||||||
addQuad(_vertices, _texCoords, m, texBase);
|
addQuad(_vertices, _texCoords, m, texBase);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (draw_data || i < 0) // selected one (i == -1) is always drawn
|
if ((draw_data || i < 0)&& // selected one (i == -1) is always drawn
|
||||||
|
((!draw_tcas)||(is_tcas_contact)||(draw_echoes)))
|
||||||
update_data(model, alt, heading, radius, bearing, i < 0);
|
update_data(model, alt, heading, radius, bearing, i < 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Update TCAS display.
|
||||||
|
* Return true when processed as TCAS contact, false otherwise. */
|
||||||
|
bool
|
||||||
|
wxRadarBg::update_tcas(const SGPropertyNode *model,double range,double user_alt,double alt,
|
||||||
|
double bearing,double radius)
|
||||||
|
{
|
||||||
|
int threatLevel=0;
|
||||||
|
{
|
||||||
|
// update TCAS symbol
|
||||||
|
osg::Vec2f texBase;
|
||||||
|
threatLevel = model->getIntValue("tcas/threat-level",-1);
|
||||||
|
if (threatLevel == -1)
|
||||||
|
{
|
||||||
|
// no TCAS information (i.e. no transponder) => not visible to TCAS
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
int row = 7 - threatLevel;
|
||||||
|
int col = 4;
|
||||||
|
double vspeed = model->getDoubleValue("velocities/vertical-speed-fps");
|
||||||
|
if (vspeed < -3.0) // descending
|
||||||
|
col+=1;
|
||||||
|
else
|
||||||
|
if (vspeed > 3.0) // climbing
|
||||||
|
col+=2;
|
||||||
|
texBase = osg::Vec2f(col*UNIT,row * UNIT);
|
||||||
|
float size = 200 * UNIT;
|
||||||
|
osg::Matrixf m(osg::Matrixf::scale(size, size, 1.0f)
|
||||||
|
* wxRotate(-bearing)
|
||||||
|
* osg::Matrixf::translate(0.0f, radius, 0.0f)
|
||||||
|
* wxRotate(bearing) * _centerTrans);
|
||||||
|
addQuad(_vertices, _texCoords, m, texBase);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// update TCAS data
|
||||||
|
osgText::Text *altStr = new osgText::Text;
|
||||||
|
altStr->setFont(_font.get());
|
||||||
|
altStr->setFontResolution(12, 12);
|
||||||
|
altStr->setCharacterSize(_font_size);
|
||||||
|
altStr->setColor(_tcas_colors[threatLevel]);
|
||||||
|
osg::Matrixf m(wxRotate(-bearing)
|
||||||
|
* osg::Matrixf::translate(0.0f, radius, 0.0f)
|
||||||
|
* wxRotate(bearing) * _centerTrans);
|
||||||
|
|
||||||
|
osg::Vec3 pos = m.preMult(osg::Vec3(16, 16, 0));
|
||||||
|
// cast to int's, otherwise text comes out ugly
|
||||||
|
altStr->setLineSpacing(_font_spacing);
|
||||||
|
|
||||||
|
stringstream text;
|
||||||
|
altStr->setAlignment(osgText::Text::LEFT_CENTER);
|
||||||
|
int altDif = (alt-user_alt+50)/100;
|
||||||
|
char sign = 0;
|
||||||
|
int dy=0;
|
||||||
|
if (altDif>=0)
|
||||||
|
{
|
||||||
|
sign='+';
|
||||||
|
dy=2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if (altDif<0)
|
||||||
|
{
|
||||||
|
sign='-';
|
||||||
|
altDif = -altDif;
|
||||||
|
dy=-30;
|
||||||
|
}
|
||||||
|
altStr->setPosition(osg::Vec3((int)pos.x()-30, (int)pos.y()+dy, 0));
|
||||||
|
if (sign)
|
||||||
|
{
|
||||||
|
text << sign
|
||||||
|
<< setprecision(0) << fixed
|
||||||
|
<< setw(2) << setfill('0') << altDif << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
altStr->setText(text.str());
|
||||||
|
_textGeode->addDrawable(altStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
wxRadarBg::update_tacan()
|
wxRadarBg::update_tacan()
|
||||||
|
@ -983,11 +1075,23 @@ wxRadarBg::updateFont()
|
||||||
_font->setGlyphImageMargin(0);
|
_font->setGlyphImageMargin(0);
|
||||||
_font->setGlyphImageMarginRatio(0);
|
_font->setGlyphImageMarginRatio(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (int i=0;i<4;i++)
|
||||||
|
{
|
||||||
|
const float defaultColors[4][3] = {{0,1,1},{0,1,1},{1,0.5,0},{1,0,0}};
|
||||||
|
SGPropertyNode_ptr color_node = _font_node->getNode("tcas/color",i,true);
|
||||||
|
float red = color_node->getFloatValue("red",defaultColors[i][0]);
|
||||||
|
float green = color_node->getFloatValue("green",defaultColors[i][1]);
|
||||||
|
float blue = color_node->getFloatValue("blue",defaultColors[i][2]);
|
||||||
|
float alpha = color_node->getFloatValue("alpha",1);
|
||||||
|
_tcas_colors[i]=osg::Vec4(red, green, blue, alpha);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
wxRadarBg::valueChanged(SGPropertyNode*)
|
wxRadarBg::valueChanged(SGPropertyNode*)
|
||||||
{
|
{
|
||||||
updateFont();
|
updateFont();
|
||||||
|
_time = _interval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -96,8 +96,6 @@ private:
|
||||||
typedef enum { ARC, MAP, PLAN, ROSE, BSCAN} DisplayMode;
|
typedef enum { ARC, MAP, PLAN, ROSE, BSCAN} DisplayMode;
|
||||||
DisplayMode _display_mode;
|
DisplayMode _display_mode;
|
||||||
|
|
||||||
string _last_switchKnob;
|
|
||||||
|
|
||||||
float _range_nm;
|
float _range_nm;
|
||||||
float _scale; // factor to convert nm to display units
|
float _scale; // factor to convert nm to display units
|
||||||
float _angle_offset;
|
float _angle_offset;
|
||||||
|
@ -130,6 +128,7 @@ private:
|
||||||
SGPropertyNode_ptr _radar_ref_rng_node;
|
SGPropertyNode_ptr _radar_ref_rng_node;
|
||||||
SGPropertyNode_ptr _radar_hdg_marker_node;
|
SGPropertyNode_ptr _radar_hdg_marker_node;
|
||||||
SGPropertyNode_ptr _radar_rotate_node;
|
SGPropertyNode_ptr _radar_rotate_node;
|
||||||
|
SGPropertyNode_ptr _radar_tcas_node;
|
||||||
|
|
||||||
SGPropertyNode_ptr _font_node;
|
SGPropertyNode_ptr _font_node;
|
||||||
SGPropertyNode_ptr _ai_enabled_node;
|
SGPropertyNode_ptr _ai_enabled_node;
|
||||||
|
@ -144,6 +143,7 @@ private:
|
||||||
osg::Matrixf _centerTrans;
|
osg::Matrixf _centerTrans;
|
||||||
osg::ref_ptr<osgText::Font> _font;
|
osg::ref_ptr<osgText::Font> _font;
|
||||||
osg::Vec4 _font_color;
|
osg::Vec4 _font_color;
|
||||||
|
osg::Vec4 _tcas_colors[4];
|
||||||
float _font_size;
|
float _font_size;
|
||||||
float _font_spacing;
|
float _font_spacing;
|
||||||
|
|
||||||
|
@ -155,6 +155,8 @@ private:
|
||||||
void update_heading_marker();
|
void update_heading_marker();
|
||||||
void update_data(const SGPropertyNode *ac, double alt, double heading,
|
void update_data(const SGPropertyNode *ac, double alt, double heading,
|
||||||
double radius, double bearing, bool selected);
|
double radius, double bearing, bool selected);
|
||||||
|
bool update_tcas(const SGPropertyNode *model,double range,double user_alt,double alt,
|
||||||
|
double bearing,double radius);
|
||||||
void center_map();
|
void center_map();
|
||||||
void apply_map_offset();
|
void apply_map_offset();
|
||||||
void updateFont();
|
void updateFont();
|
||||||
|
|
Loading…
Reference in a new issue