JSBSim Flight Dynamics Model  1.0 (02 March 2017)
An Open Source Flight Dynamics and Control Software Library in C++
FGAngles.cpp
1 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2 
3  Module: FGAngles.cpp
4  Author: Jon S. Berndt
5  Date started: 6/2013
6 
7  ------------- Copyright (C) 2013 Jon S. Berndt (jon@jsbsim.org) -------------
8 
9  This program is free software; you can redistribute it and/or modify it under
10  the terms of the GNU Lesser General Public License as published by the Free Software
11  Foundation; either version 2 of the License, or (at your option) any later
12  version.
13 
14  This program is distributed in the hope that it will be useful, but WITHOUT
15  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16  FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
17  details.
18 
19  You should have received a copy of the GNU Lesser General Public License along with
20  this program; if not, write to the Free Software Foundation, Inc., 59 Temple
21  Place - Suite 330, Boston, MA 02111-1307, USA.
22 
23  Further information about the GNU Lesser General Public License can also be found on
24  the world wide web at http://www.gnu.org.
25 
26 FUNCTIONAL DESCRIPTION
27 --------------------------------------------------------------------------------
28 
29 HISTORY
30 --------------------------------------------------------------------------------
31 Created: 6/2013 Jon S. Berndt
32 
33 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
34 COMMENTS, REFERENCES, and NOTES
35 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
36 
37  The Included Angle to Heading algorithm is used to find the smallest included angle
38  (the angle less than or equal to 180 degrees) to a specified heading from
39  the current heading. The sense of the rotation to get to that angle is also
40  calculated (positive 1 for a clockwise rotation, negative 1 for counter-
41  clockwise).
42 
43  The angle to the heading is calculated as follows:
44 
45  Given an angle phi:
46 
47  V = cos(phi)i + sin(phi)j (this is a unit vector)
48 
49  The dot product for two, 2D vectors is written:
50 
51  V1*V2 = |V1||V2|cos(phi)
52 
53  Since the magnitude of a unit vector is 1, we can write the equation as follows:
54 
55  V1*V2 = cos(phi)
56 
57  or,
58 
59  phi = acos(V1*V2)
60 
61  or,
62 
63  phi = acos[ cos(phi1)cos(phi2) + sin(phi1)sin(phi2) ]
64 
65 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
66 INCLUDES
67 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
68 
69 #include "FGAngles.h"
70 #include "input_output/FGXMLElement.h"
71 #include "input_output/FGPropertyManager.h"
72 
73 using namespace std;
74 
75 namespace JSBSim {
76 
77 IDENT(IdSrc,"$Id: FGAngles.cpp,v 1.5 2016/07/27 22:42:47 andgi Exp $");
78 IDENT(IdHdr,ID_ANGLES);
79 
80 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
81 CLASS IMPLEMENTATION
82 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
83 
84 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
85 
86 FGAngles::FGAngles(FGFCS* fcs, Element* element) : FGFCSComponent(fcs, element)
87 {
88  source_angle = 0.0;
89  target_angle = 0.0;
90  source_angle_unit = 1.0;
91  target_angle_unit = 1.0;
92  output_unit = 1.0;
93 
94  if (element->FindElement("target_angle") ) {
95  target_angle_pNode = PropertyManager->GetNode(element->FindElementValue("target_angle"));
96  if (element->FindElement("target_angle")->HasAttribute("unit")) {
97  if (element->FindElement("target_angle")->GetAttributeValue("unit") == "DEG") {
98  target_angle_unit = 0.017453293;
99  }
100  }
101  } else {
102  throw("Target angle is required for component: "+Name);
103  }
104 
105  if (element->FindElement("source_angle") ) {
106  source_angle_pNode = PropertyManager->GetNode(element->FindElementValue("source_angle"));
107  if (element->FindElement("source_angle")->HasAttribute("unit")) {
108  if (element->FindElement("source_angle")->GetAttributeValue("unit") == "DEG") {
109  source_angle_unit = 0.017453293;
110  }
111  }
112  } else {
113  throw("Source latitude is required for Angles component: "+Name);
114  }
115 
116  unit = element->GetAttributeValue("unit");
117  if (!unit.empty()) {
118  if (unit == "DEG") output_unit = 180.0/M_PI;
119  else if (unit == "RAD") output_unit = 1.0;
120  else throw("Unknown unit "+unit+" in angle component, "+Name);
121  } else {
122  output_unit = 1.0; // Default is radians (1.0) if unspecified
123  }
124 
125  FGFCSComponent::bind();
126  Debug(0);
127 }
128 
129 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
130 
131 FGAngles::~FGAngles()
132 {
133  Debug(1);
134 }
135 
136 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
137 
138 bool FGAngles::Run(void )
139 {
140  source_angle = source_angle_pNode->getDoubleValue() * source_angle_unit;
141  target_angle = target_angle_pNode->getDoubleValue() * target_angle_unit;
142 
143  double x1 = cos(source_angle);
144  double y1 = sin(source_angle);
145  double x2 = cos(target_angle);
146  double y2 = sin(target_angle);
147 
148  double x1x2_y1y2 = max(-1.0, min(x1*x2 + y1*y2, 1.0));
149  double angle_to_heading_rad = acos(x1x2_y1y2);
150  double x1y2 = x1*y2;
151  double x2y1 = x2*y1;
152 
153  if (x1y2 >= x2y1) Output = angle_to_heading_rad * output_unit;
154  else Output = -angle_to_heading_rad * output_unit;
155 
156  Clip();
157  if (IsOutput) SetOutput();
158 
159  return true;
160 }
161 
162 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
163 // The bitmasked value choices are as follows:
164 // unset: In this case (the default) JSBSim would only print
165 // out the normally expected messages, essentially echoing
166 // the config files as they are read. If the environment
167 // variable is not set, debug_lvl is set to 1 internally
168 // 0: This requests JSBSim not to output any messages
169 // whatsoever.
170 // 1: This value explicity requests the normal JSBSim
171 // startup messages
172 // 2: This value asks for a message to be printed out when
173 // a class is instantiated
174 // 4: When this value is set, a message is displayed when a
175 // FGModel object executes its Run() method
176 // 8: When this value is set, various runtime state variables
177 // are printed out periodically
178 // 16: When set various parameters are sanity checked and
179 // a message is printed out when they go out of bounds
180 
181 void FGAngles::Debug(int from)
182 {
183  if (debug_lvl <= 0) return;
184 
185  if (debug_lvl & 1) { // Standard console startup message output
186  if (from == 0) { // Constructor
187  }
188  }
189  if (debug_lvl & 2 ) { // Instantiation/Destruction notification
190  if (from == 0) cout << "Instantiated: FGAngles" << endl;
191  if (from == 1) cout << "Destroyed: FGAngles" << endl;
192  }
193  if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
194  }
195  if (debug_lvl & 8 ) { // Runtime state variables
196  }
197  if (debug_lvl & 16) { // Sanity checking
198  }
199  if (debug_lvl & 64) {
200  if (from == 0) { // Constructor
201  cout << IdSrc << endl;
202  cout << IdHdr << endl;
203  }
204  }
205 }
206 }
STL namespace.