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