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