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