]> git.mxchange.org Git - flightgear.git/blob - src/Autopilot/inputvalue.cxx
fix #416: reciprocal filter broken
[flightgear.git] / src / Autopilot / inputvalue.cxx
1 // inputvalue.hxx - provide input to autopilot components
2 //
3 // Written by Torsten Dreyer
4 // Copyright (C) 2010  Torsten Dreyer - Torsten (at) t3r (dot) de
5 //
6 // This program is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU General Public License as
8 // published by the Free Software Foundation; either version 2 of the
9 // License, or (at your option) any later version.
10 //
11 // This program is distributed in the hope that it will be useful, but
12 // WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // General Public License for more details.
15 //
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software
18 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19 //
20
21 #include "inputvalue.hxx"
22 #include <Main/fg_props.hxx>
23 using namespace FGXMLAutopilot;
24
25 PeriodicalValue::PeriodicalValue( SGPropertyNode_ptr root )
26 {
27   SGPropertyNode_ptr minNode = root->getChild( "min" );
28   SGPropertyNode_ptr maxNode = root->getChild( "max" );
29   if( minNode == NULL || maxNode == NULL ) {
30     SG_LOG(SG_AUTOPILOT, SG_ALERT, "periodical defined, but no <min> and/or <max> tag. Period ignored." );
31   } else {
32     minPeriod = new InputValue( minNode );
33     maxPeriod = new InputValue( maxNode );
34   }
35 }
36
37 double PeriodicalValue::normalize( double value )
38 {
39   return SGMiscd::normalizePeriodic( minPeriod->get_value(), maxPeriod->get_value(), value );
40 }
41
42 InputValue::InputValue( SGPropertyNode_ptr node, double value, double offset, double scale) :
43   _value(0.0),
44   _abs(false)
45 {
46   parse( node, value, offset, scale );
47 }
48
49
50 void InputValue::parse( SGPropertyNode_ptr node, double aValue, double aOffset, double aScale )
51 {
52     _value = aValue;
53     _property = NULL; 
54     _offset = NULL;
55     _scale = NULL;
56     _min = NULL;
57     _max = NULL;
58     _periodical = NULL;
59
60     if( node == NULL )
61         return;
62
63     SGPropertyNode * n;
64
65     if( (n = node->getChild("condition")) != NULL ) {
66         _condition = sgReadCondition(fgGetNode("/"), n);
67     }
68
69     if( (n = node->getChild( "scale" )) != NULL ) {
70         _scale = new InputValue( n, aScale );
71     }
72
73     if( (n = node->getChild( "offset" )) != NULL ) {
74         _offset = new InputValue( n, aOffset );
75     }
76
77     if( (n = node->getChild( "max" )) != NULL ) {
78         _max = new InputValue( n );
79     }
80
81     if( (n = node->getChild( "min" )) != NULL ) {
82         _min = new InputValue( n );
83     }
84
85     if( (n = node->getChild( "abs" )) != NULL ) {
86       _abs = n->getBoolValue();
87     }
88
89     if( (n = node->getChild( "period" )) != NULL ) {
90       _periodical = new PeriodicalValue( n );
91     }
92
93     SGPropertyNode *valueNode = node->getChild( "value" );
94     if ( valueNode != NULL ) {
95         _value = valueNode->getDoubleValue();
96     }
97
98     if ((n = node->getChild("expression")) != NULL) {
99       _expression = SGReadDoubleExpression(fgGetNode("/"), n->getChild(0));
100       return;
101     }
102     
103     n = node->getChild( "property" );
104     // if no <property> element, check for <prop> element for backwards
105     // compatibility
106     if(  n == NULL )
107         n = node->getChild( "prop" );
108
109     if (  n != NULL ) {
110         _property = fgGetNode(  n->getStringValue(), true );
111         if ( valueNode != NULL ) {
112             // initialize property with given value 
113             // if both <prop> and <value> exist
114             double s = get_scale();
115             if( s != 0 )
116               _property->setDoubleValue( (_value - get_offset())/s );
117             else
118               _property->setDoubleValue( 0 ); // if scale is zero, value*scale is zero
119         }
120         
121         return;
122     } // of have a <property> or <prop>
123
124     
125     if (valueNode == NULL) {
126         // no <value>, <prop> or <expression> element, use text node 
127         const char * textnode = node->getStringValue();
128         char * endp = NULL;
129         // try to convert to a double value. If the textnode does not start with a number
130         // endp will point to the beginning of the string. We assume this should be
131         // a property name
132         _value = strtod( textnode, &endp );
133         if( endp == textnode ) {
134           _property = fgGetNode( textnode, true );
135         }
136     }
137 }
138
139 void InputValue::set_value( double aValue ) 
140 {
141     if (!_property)
142       return;
143       
144     double s = get_scale();
145     if( s != 0 )
146         _property->setDoubleValue( (aValue - get_offset())/s );
147     else
148         _property->setDoubleValue( 0 ); // if scale is zero, value*scale is zero
149 }
150
151 double InputValue::get_value() const
152 {
153     double value = _value;
154
155     if (_expression) {
156         // compute the expression value
157         value = _expression->getValue(NULL);
158     } else if( _property != NULL ) {
159         value = _property->getDoubleValue();
160     }
161     
162     if( _scale ) 
163         value *= _scale->get_value();
164
165     if( _offset ) 
166         value += _offset->get_value();
167
168     if( _min ) {
169         double m = _min->get_value();
170         if( value < m )
171             value = m;
172     }
173
174     if( _max ) {
175         double m = _max->get_value();
176         if( value > m )
177             value = m;
178     }
179
180     if( _periodical ) {
181       value = _periodical->normalize( value );
182     }
183     
184     return _abs ? fabs(value) : value;
185 }
186