1
0
Fork 0
flightgear/src/Autopilot/inputvalue.cxx

311 lines
9 KiB
C++
Raw Normal View History

// inputvalue.hxx - provide input to autopilot components
//
// Written by Torsten Dreyer
// Copyright (C) 2010 Torsten Dreyer - Torsten (at) t3r (dot) de
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
#include <cstdlib>
#include "inputvalue.hxx"
#include <simgear/misc/strutils.hxx>
using namespace FGXMLAutopilot;
//------------------------------------------------------------------------------
PeriodicalValue::PeriodicalValue( SGPropertyNode& prop_root,
SGPropertyNode& cfg )
{
SGPropertyNode_ptr minNode = cfg.getChild( "min" );
SGPropertyNode_ptr maxNode = cfg.getChild( "max" );
if( !minNode || !maxNode )
{
SG_LOG
(
SG_AUTOPILOT,
SG_ALERT,
"periodical defined, but no <min> and/or <max> tag. Period ignored."
);
}
else
{
minPeriod = new InputValue(prop_root, *minNode);
maxPeriod = new InputValue(prop_root, *maxNode);
}
}
//------------------------------------------------------------------------------
double PeriodicalValue::normalize( double value ) const
{
return SGMiscd::normalizePeriodic( minPeriod->get_value(),
maxPeriod->get_value(),
value );
}
//------------------------------------------------------------------------------
double PeriodicalValue::normalizeSymmetric( double value ) const
{
double minValue = minPeriod->get_value();
double maxValue = maxPeriod->get_value();
value = SGMiscd::normalizePeriodic( minValue, maxValue, value );
double width_2 = (maxValue - minValue)/2;
return value > width_2 ? width_2 - value : value;
}
//------------------------------------------------------------------------------
InputValue::InputValue( SGPropertyNode& prop_root,
SGPropertyNode& cfg,
double value,
double offset,
double scale ):
_value(0.0),
_abs(false)
{
parse(prop_root, cfg, value, offset, scale);
}
InputValue::~InputValue()
{
if (_pathNode) {
_pathNode->removeChangeListener(this);
}
}
void InputValue::initPropertyFromInitialValue()
{
double s = get_scale();
if( s != 0 )
_property->setDoubleValue( (_value - get_offset())/s );
else
_property->setDoubleValue(0); // if scale is zero, value*scale is zero
}
//------------------------------------------------------------------------------
void InputValue::parse( SGPropertyNode& prop_root,
SGPropertyNode& cfg,
double aValue,
double aOffset,
double aScale )
{
_value = aValue;
_property = NULL;
_offset = NULL;
_scale = NULL;
_min = NULL;
_max = NULL;
_periodical = NULL;
SGPropertyNode * n;
if( (n = cfg.getChild("condition")) != NULL )
_condition = sgReadCondition(&prop_root, n);
if( (n = cfg.getChild( "scale" )) != NULL )
_scale = new InputValue(prop_root, *n, aScale);
if( (n = cfg.getChild( "offset" )) != NULL )
_offset = new InputValue(prop_root, *n, aOffset);
if( (n = cfg.getChild( "max" )) != NULL )
_max = new InputValue(prop_root, *n);
if( (n = cfg.getChild( "min" )) != NULL )
_min = new InputValue(prop_root, *n);
if( (n = cfg.getChild( "abs" )) != NULL )
_abs = n->getBoolValue();
if( (n = cfg.getChild( "period" )) != NULL )
_periodical = new PeriodicalValue(prop_root, *n);
SGPropertyNode *valueNode = cfg.getChild("value");
if( valueNode != NULL )
_value = valueNode->getDoubleValue();
if( (n = cfg.getChild("expression")) != NULL )
{
_expression = SGReadDoubleExpression(&prop_root, n->getChild(0));
return;
}
if ((n = cfg.getChild("property-path"))) {
// cache the root node, in case of changes
_rootNode = &prop_root;
const auto trimmed = simgear::strutils::strip(n->getStringValue());
_pathNode = prop_root.getNode(trimmed, true);
_pathNode->addChangeListener(this);
// if <property> is defined, should we use it to initialise
// the path prop? not doing so for now.
const auto path = simgear::strutils::strip(_pathNode->getStringValue());
if (!path.empty()) {
_property = _rootNode->getNode(path);
}
return;
}
// if no <property> element, check for <prop> element for backwards
// compatibility
if( (n = cfg.getChild("property"))
|| (n = cfg.getChild("prop" )) )
{
// tolerate leading & trailing whitespace from XML, in the property name
const auto trimmed = simgear::strutils::strip(n->getStringValue());
_property = prop_root.getNode(trimmed, true);
if( valueNode )
{
initPropertyFromInitialValue();
}
return;
} // of have a <property> or <prop>
if( !valueNode )
{
// no <value>, <prop> or <expression> element, use text node
std::string textnode = cfg.getStringValue();
char * endp = NULL;
// try to convert to a double value. If the textnode does not start with a number
// endp will point to the beginning of the string. We assume this should be
// a property name
_value = strtod( textnode.c_str(), &endp );
if( endp == textnode.c_str() )
_property = prop_root.getNode(textnode, true);
}
}
void InputValue::set_value( double aValue )
{
if (!_property)
return;
double s = get_scale();
if( s != 0 )
_property->setDoubleValue( (aValue - get_offset())/s );
else
_property->setDoubleValue( 0 ); // if scale is zero, value*scale is zero
}
double InputValue::get_value() const
{
double value = _value;
if (_expression) {
// compute the expression value
value = _expression->getValue(NULL);
if (SGMiscd::isNaN(value)) {
SG_LOG(SG_AUTOPILOT, SG_DEV_ALERT, "AP input: read NaN from expression");
}
} else if( _property != NULL ) {
value = _property->getDoubleValue();
if (SGMiscd::isNaN(value)) {
SG_LOG(SG_AUTOPILOT, SG_DEV_ALERT, "AP input: read NaN from:" << _property->getPath() );
}
} else {
if (SGMiscd::isNaN(value)) {
SG_LOG(SG_AUTOPILOT, SG_DEV_ALERT, "AP input is NaN." );
}
}
if( _scale )
value *= _scale->get_value();
if( _offset )
value += _offset->get_value();
if( _min ) {
double m = _min->get_value();
if( value < m )
value = m;
}
if( _max ) {
double m = _max->get_value();
if( value > m )
value = m;
}
if( _periodical ) {
value = _periodical->normalize( value );
}
return _abs ? fabs(value) : value;
}
bool InputValue::is_enabled() const
{
if (_pathNode && !_property) {
// if we have a configurable path, and it's currently not valid,
// mark ourselves as disabled
return false;
}
if (_condition) {
return _condition->test();
}
return true; // default to enab;ed
}
Added highlighting system. If /sim/highlighting/enabled is true, we highlight animated objects under the pointer, and also highlight other objects that are animated by the same or related properties. The intent here is to be able to give a visual indication of what cockpit controls do or what cockpit controls affect particular aircraft objects - for example moving the pointer over the flaps will highlight the flaps and also highlight any controls or rotary indicators in the cockpit that are associated with the flaps. To make this work, we have to discover associations between properties. This is currently done for YASim (e.g. associations between /controls/flight/flaps and /surface-positions/flap-pos-norm) and autopilot filters (e.g. with the 777, digital filters associate /controls/flight/rudder-nul with /fcs/fbw/yaw/rudder-ratio-out). We don't currently gather associations between properties in JSBSim We also detect associations between dialogs, menus and keypresses and properties, which is used to populate /sim/highlighting/current with information about dialogs, menus and keypresses that are associated with the currently highlighted nodes' properties. Details: src/GUI/Highlight.cxx src/GUI/Highlight.hxx src/GUI/CMakeLists.txt src/Main/fg_init.cxx New subsystem called 'highlight', with support for registering and recovering links between menus, dialogs, keypresses and OSG node animations. Provides a function Highlight::highlight_nodes() which highlights related nodes using internal NodeHighlighting class, and populates /sim/highlighting/current with information about related dialogs, menus and keypresses. The NodeHighlighting class works by making nodes use an alternative StateSet which shows up as a distinct material on screen. We remember each highlighted node's original StateSet so that we can un-highlight. We update the material parameters using a listener for /sim/highlighting/material, which allows some control over the appearence of highlighted nodes. src/FDM/flight.cxx src/FDM/flight.hxx Added virtual method FGInterface::property_associations() which returns property associations from the FDM. Default implementation returns empty set. Implemented in YASim, but not (yet) in JSBSim. Uses a simple function pointer at the moment to avoid requring FDMs to use recent C++ features. src/FDM/YASim/FGFDM.cpp src/FDM/YASim/FGFDM.hpp src/FDM/YASim/YASim.cxx src/FDM/YASim/YASim.hxx Gathers information about property associations on startup such as /controls/flight/flaps => /surface-positions/flap-pos-norm, then YASim::property_associations() overrides default implementation to return these associations. src/Autopilot/analogcomponent.cxx src/Autopilot/analogcomponent.hxx src/Autopilot/digitalfilter.cxx src/Autopilot/inputvalue.cxx src/Autopilot/inputvalue.hxx Filters now gather information about their input/output properties and register with Highlight::add_property_property(). For example this makes highlighting work on the 777, where pilot controls affect control surfaces only via filters. src/GUI/new_gui.cxx Scan menus, keypresses and dialogs and register associations with Highlight::add_*(). src/GUI/property_list.cxx src/GUI/property_list.hxx src/GUI/FGPUIDialog.cxx Added <readonly> flag to property-list. If set, we don't show .. or . items and don't respond to mouse/keyboard. Used by fgdata's new Highlighting dialogue. src/Model/acmodel.cxx src/Model/acmodel.hxx Visit the user aircraft's scene graph when it is loaded, gathering information about osg::Node's that are animated by properties, and register these associations with Highlight::add_property_node(). src/Viewer/renderer.cxx When scanning for pick highlights, use Highlight::highlight_nodes() to highlight animated objects under the pointer and related objects.
2021-10-05 21:25:08 +00:00
void InputValue::collectDependentProperties(std::set<const SGPropertyNode*>& props) const
{
if (_property) props.insert(_property);
if (_offset) _offset->collectDependentProperties(props);
if (_scale) _scale->collectDependentProperties(props);
if (_min) _min->collectDependentProperties(props);
if (_max) _max->collectDependentProperties(props);
if (_expression) _expression->collectDependentProperties(props);
if (_pathNode) props.insert(_pathNode);
Added highlighting system. If /sim/highlighting/enabled is true, we highlight animated objects under the pointer, and also highlight other objects that are animated by the same or related properties. The intent here is to be able to give a visual indication of what cockpit controls do or what cockpit controls affect particular aircraft objects - for example moving the pointer over the flaps will highlight the flaps and also highlight any controls or rotary indicators in the cockpit that are associated with the flaps. To make this work, we have to discover associations between properties. This is currently done for YASim (e.g. associations between /controls/flight/flaps and /surface-positions/flap-pos-norm) and autopilot filters (e.g. with the 777, digital filters associate /controls/flight/rudder-nul with /fcs/fbw/yaw/rudder-ratio-out). We don't currently gather associations between properties in JSBSim We also detect associations between dialogs, menus and keypresses and properties, which is used to populate /sim/highlighting/current with information about dialogs, menus and keypresses that are associated with the currently highlighted nodes' properties. Details: src/GUI/Highlight.cxx src/GUI/Highlight.hxx src/GUI/CMakeLists.txt src/Main/fg_init.cxx New subsystem called 'highlight', with support for registering and recovering links between menus, dialogs, keypresses and OSG node animations. Provides a function Highlight::highlight_nodes() which highlights related nodes using internal NodeHighlighting class, and populates /sim/highlighting/current with information about related dialogs, menus and keypresses. The NodeHighlighting class works by making nodes use an alternative StateSet which shows up as a distinct material on screen. We remember each highlighted node's original StateSet so that we can un-highlight. We update the material parameters using a listener for /sim/highlighting/material, which allows some control over the appearence of highlighted nodes. src/FDM/flight.cxx src/FDM/flight.hxx Added virtual method FGInterface::property_associations() which returns property associations from the FDM. Default implementation returns empty set. Implemented in YASim, but not (yet) in JSBSim. Uses a simple function pointer at the moment to avoid requring FDMs to use recent C++ features. src/FDM/YASim/FGFDM.cpp src/FDM/YASim/FGFDM.hpp src/FDM/YASim/YASim.cxx src/FDM/YASim/YASim.hxx Gathers information about property associations on startup such as /controls/flight/flaps => /surface-positions/flap-pos-norm, then YASim::property_associations() overrides default implementation to return these associations. src/Autopilot/analogcomponent.cxx src/Autopilot/analogcomponent.hxx src/Autopilot/digitalfilter.cxx src/Autopilot/inputvalue.cxx src/Autopilot/inputvalue.hxx Filters now gather information about their input/output properties and register with Highlight::add_property_property(). For example this makes highlighting work on the 777, where pilot controls affect control surfaces only via filters. src/GUI/new_gui.cxx Scan menus, keypresses and dialogs and register associations with Highlight::add_*(). src/GUI/property_list.cxx src/GUI/property_list.hxx src/GUI/FGPUIDialog.cxx Added <readonly> flag to property-list. If set, we don't show .. or . items and don't respond to mouse/keyboard. Used by fgdata's new Highlighting dialogue. src/Model/acmodel.cxx src/Model/acmodel.hxx Visit the user aircraft's scene graph when it is loaded, gathering information about osg::Node's that are animated by properties, and register these associations with Highlight::add_property_node(). src/Viewer/renderer.cxx When scanning for pick highlights, use Highlight::highlight_nodes() to highlight animated objects under the pointer and related objects.
2021-10-05 21:25:08 +00:00
}
void InputValue::valueChanged(SGPropertyNode *node)
{
assert(node == _pathNode);
const auto path = simgear::strutils::strip(_pathNode->getStringValue());
if (path.empty()) {
// don't consider an empty string to mean the root node, that's not
// useful behaviour
_property.reset();
return;
}
// important we don't create here: this allows an invalid path
// to give us a null _property, which causes us to be marked as
// disabled, allowing another input to be used
auto propNode = _rootNode->getNode(path);
if (propNode) {
_property = propNode;
} else {
_property.reset();
}
}
Added highlighting system. If /sim/highlighting/enabled is true, we highlight animated objects under the pointer, and also highlight other objects that are animated by the same or related properties. The intent here is to be able to give a visual indication of what cockpit controls do or what cockpit controls affect particular aircraft objects - for example moving the pointer over the flaps will highlight the flaps and also highlight any controls or rotary indicators in the cockpit that are associated with the flaps. To make this work, we have to discover associations between properties. This is currently done for YASim (e.g. associations between /controls/flight/flaps and /surface-positions/flap-pos-norm) and autopilot filters (e.g. with the 777, digital filters associate /controls/flight/rudder-nul with /fcs/fbw/yaw/rudder-ratio-out). We don't currently gather associations between properties in JSBSim We also detect associations between dialogs, menus and keypresses and properties, which is used to populate /sim/highlighting/current with information about dialogs, menus and keypresses that are associated with the currently highlighted nodes' properties. Details: src/GUI/Highlight.cxx src/GUI/Highlight.hxx src/GUI/CMakeLists.txt src/Main/fg_init.cxx New subsystem called 'highlight', with support for registering and recovering links between menus, dialogs, keypresses and OSG node animations. Provides a function Highlight::highlight_nodes() which highlights related nodes using internal NodeHighlighting class, and populates /sim/highlighting/current with information about related dialogs, menus and keypresses. The NodeHighlighting class works by making nodes use an alternative StateSet which shows up as a distinct material on screen. We remember each highlighted node's original StateSet so that we can un-highlight. We update the material parameters using a listener for /sim/highlighting/material, which allows some control over the appearence of highlighted nodes. src/FDM/flight.cxx src/FDM/flight.hxx Added virtual method FGInterface::property_associations() which returns property associations from the FDM. Default implementation returns empty set. Implemented in YASim, but not (yet) in JSBSim. Uses a simple function pointer at the moment to avoid requring FDMs to use recent C++ features. src/FDM/YASim/FGFDM.cpp src/FDM/YASim/FGFDM.hpp src/FDM/YASim/YASim.cxx src/FDM/YASim/YASim.hxx Gathers information about property associations on startup such as /controls/flight/flaps => /surface-positions/flap-pos-norm, then YASim::property_associations() overrides default implementation to return these associations. src/Autopilot/analogcomponent.cxx src/Autopilot/analogcomponent.hxx src/Autopilot/digitalfilter.cxx src/Autopilot/inputvalue.cxx src/Autopilot/inputvalue.hxx Filters now gather information about their input/output properties and register with Highlight::add_property_property(). For example this makes highlighting work on the 777, where pilot controls affect control surfaces only via filters. src/GUI/new_gui.cxx Scan menus, keypresses and dialogs and register associations with Highlight::add_*(). src/GUI/property_list.cxx src/GUI/property_list.hxx src/GUI/FGPUIDialog.cxx Added <readonly> flag to property-list. If set, we don't show .. or . items and don't respond to mouse/keyboard. Used by fgdata's new Highlighting dialogue. src/Model/acmodel.cxx src/Model/acmodel.hxx Visit the user aircraft's scene graph when it is loaded, gathering information about osg::Node's that are animated by properties, and register these associations with Highlight::add_property_node(). src/Viewer/renderer.cxx When scanning for pick highlights, use Highlight::highlight_nodes() to highlight animated objects under the pointer and related objects.
2021-10-05 21:25:08 +00:00
void InputValueList::collectDependentProperties(std::set<const SGPropertyNode*>& props) const
{
for (auto& iv: *this) {
iv->collectDependentProperties(props);
}
}