]> git.mxchange.org Git - flightgear.git/blob - src/Autopilot/inputvalue.cxx
Some xml-autopilot tuning
[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 ) const
38 {
39   return SGMiscd::normalizePeriodic( minPeriod->get_value(), maxPeriod->get_value(), value );
40 }
41
42 double PeriodicalValue::normalizeSymmetric( double value ) const
43 {
44   double minValue = minPeriod->get_value();
45   double maxValue = maxPeriod->get_value();
46   
47   value = SGMiscd::normalizePeriodic( minValue, maxValue, value );
48   double width_2 = (maxValue - minValue)/2;
49   return value > width_2 ? width_2 - value : value;
50 }
51
52 InputValue::InputValue( SGPropertyNode_ptr node, double value, double offset, double scale) :
53   _value(0.0),
54   _abs(false)
55 {
56   parse( node, value, offset, scale );
57 }
58
59
60 void InputValue::parse( SGPropertyNode_ptr node, double aValue, double aOffset, double aScale )
61 {
62     _value = aValue;
63     _property = NULL; 
64     _offset = NULL;
65     _scale = NULL;
66     _min = NULL;
67     _max = NULL;
68     _periodical = NULL;
69
70     if( node == NULL )
71         return;
72
73     SGPropertyNode * n;
74
75     if( (n = node->getChild("condition")) != NULL ) {
76         _condition = sgReadCondition(fgGetNode("/"), n);
77     }
78
79     if( (n = node->getChild( "scale" )) != NULL ) {
80         _scale = new InputValue( n, aScale );
81     }
82
83     if( (n = node->getChild( "offset" )) != NULL ) {
84         _offset = new InputValue( n, aOffset );
85     }
86
87     if( (n = node->getChild( "max" )) != NULL ) {
88         _max = new InputValue( n );
89     }
90
91     if( (n = node->getChild( "min" )) != NULL ) {
92         _min = new InputValue( n );
93     }
94
95     if( (n = node->getChild( "abs" )) != NULL ) {
96       _abs = n->getBoolValue();
97     }
98
99     if( (n = node->getChild( "period" )) != NULL ) {
100       _periodical = new PeriodicalValue( n );
101     }
102
103     SGPropertyNode *valueNode = node->getChild( "value" );
104     if ( valueNode != NULL ) {
105         _value = valueNode->getDoubleValue();
106     }
107
108     if ((n = node->getChild("expression")) != NULL) {
109       _expression = SGReadDoubleExpression(fgGetNode("/"), n->getChild(0));
110       return;
111     }
112     
113     n = node->getChild( "property" );
114     // if no <property> element, check for <prop> element for backwards
115     // compatibility
116     if(  n == NULL )
117         n = node->getChild( "prop" );
118
119     if (  n != NULL ) {
120         _property = fgGetNode(  n->getStringValue(), true );
121         if ( valueNode != NULL ) {
122             // initialize property with given value 
123             // if both <prop> and <value> exist
124             double s = get_scale();
125             if( s != 0 )
126               _property->setDoubleValue( (_value - get_offset())/s );
127             else
128               _property->setDoubleValue( 0 ); // if scale is zero, value*scale is zero
129         }
130         
131         return;
132     } // of have a <property> or <prop>
133
134     
135     if (valueNode == NULL) {
136         // no <value>, <prop> or <expression> element, use text node 
137         const char * textnode = node->getStringValue();
138         char * endp = NULL;
139         // try to convert to a double value. If the textnode does not start with a number
140         // endp will point to the beginning of the string. We assume this should be
141         // a property name
142         _value = strtod( textnode, &endp );
143         if( endp == textnode ) {
144           _property = fgGetNode( textnode, true );
145         }
146     }
147 }
148
149 void InputValue::set_value( double aValue ) 
150 {
151     if (!_property)
152       return;
153       
154     double s = get_scale();
155     if( s != 0 )
156         _property->setDoubleValue( (aValue - get_offset())/s );
157     else
158         _property->setDoubleValue( 0 ); // if scale is zero, value*scale is zero
159 }
160
161 double InputValue::get_value() const
162 {
163     double value = _value;
164
165     if (_expression) {
166         // compute the expression value
167         value = _expression->getValue(NULL);
168     } else if( _property != NULL ) {
169         value = _property->getDoubleValue();
170     }
171     
172     if( _scale ) 
173         value *= _scale->get_value();
174
175     if( _offset ) 
176         value += _offset->get_value();
177
178     if( _min ) {
179         double m = _min->get_value();
180         if( value < m )
181             value = m;
182     }
183
184     if( _max ) {
185         double m = _max->get_value();
186         if( value > m )
187             value = m;
188     }
189
190     if( _periodical ) {
191       value = _periodical->normalize( value );
192     }
193     
194     return _abs ? fabs(value) : value;
195 }
196