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