1 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5 Date started: 8/25/2004
6 Purpose: Stores various parameter types for functions
8 ------------- Copyright (C) 2004 Jon S. Berndt (jon@jsbsim.org) -------------
10 This program is free software; you can redistribute it and/or modify it under
11 the terms of the GNU Lesser General Public License as published by the Free Software
12 Foundation; either version 2 of the License, or (at your option) any later
15 This program is distributed in the hope that it will be useful, but WITHOUT
16 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
20 You should have received a copy of the GNU Lesser General Public License along with
21 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
22 Place - Suite 330, Boston, MA 02111-1307, USA.
24 Further information about the GNU Lesser General Public License can also be found on
25 the world wide web at http://www.gnu.org.
27 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
29 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
35 #include "FGFunction.h"
37 #include "FGPropertyValue.h"
38 #include "FGRealValue.h"
39 #include "input_output/FGXMLElement.h"
40 #include "input_output/FGPropertyManager.h"
46 static const char *IdSrc = "$Id: FGFunction.cpp,v 1.42 2011/09/07 02:36:04 jberndt Exp $";
47 static const char *IdHdr = ID_FUNCTION;
49 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
51 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
53 const std::string FGFunction::property_string = "property";
54 const std::string FGFunction::value_string = "value";
55 const std::string FGFunction::table_string = "table";
56 const std::string FGFunction::p_string = "p";
57 const std::string FGFunction::v_string = "v";
58 const std::string FGFunction::t_string = "t";
60 const std::string FGFunction::function_string = "function";
61 const std::string FGFunction::description_string = "description";
62 const std::string FGFunction::sum_string = "sum";
63 const std::string FGFunction::difference_string = "difference";
64 const std::string FGFunction::product_string = "product";
65 const std::string FGFunction::quotient_string = "quotient";
66 const std::string FGFunction::pow_string = "pow";
67 const std::string FGFunction::exp_string = "exp";
68 const std::string FGFunction::log2_string = "log2";
69 const std::string FGFunction::ln_string = "ln";
70 const std::string FGFunction::log10_string = "log10";
71 const std::string FGFunction::abs_string = "abs";
72 const std::string FGFunction::sign_string = "sign";
73 const std::string FGFunction::sin_string = "sin";
74 const std::string FGFunction::cos_string = "cos";
75 const std::string FGFunction::tan_string = "tan";
76 const std::string FGFunction::asin_string = "asin";
77 const std::string FGFunction::acos_string = "acos";
78 const std::string FGFunction::atan_string = "atan";
79 const std::string FGFunction::atan2_string = "atan2";
80 const std::string FGFunction::min_string = "min";
81 const std::string FGFunction::max_string = "max";
82 const std::string FGFunction::avg_string = "avg";
83 const std::string FGFunction::fraction_string = "fraction";
84 const std::string FGFunction::mod_string = "mod";
85 const std::string FGFunction::random_string = "random";
86 const std::string FGFunction::integer_string = "integer";
87 const std::string FGFunction::rotation_alpha_local_string = "rotation_alpha_local";
88 const std::string FGFunction::rotation_beta_local_string = "rotation_beta_local";
89 const std::string FGFunction::rotation_gamma_local_string = "rotation_gamma_local";
90 const std::string FGFunction::rotation_bf_to_wf_string = "rotation_bf_to_wf";
91 const std::string FGFunction::rotation_wf_to_bf_string = "rotation_wf_to_bf";
93 const std::string FGFunction::lessthan_string = "lt";
94 const std::string FGFunction::lessequal_string = "le";
95 const std::string FGFunction::greatthan_string = "gt";
96 const std::string FGFunction::greatequal_string = "ge";
97 const std::string FGFunction::equal_string = "eq";
98 const std::string FGFunction::notequal_string = "nq";
99 const std::string FGFunction::and_string = "and";
100 const std::string FGFunction::or_string = "or";
101 const std::string FGFunction::not_string = "not";
102 const std::string FGFunction::ifthen_string = "ifthen";
103 const std::string FGFunction::switch_string = "switch";
105 FGFunction::FGFunction(FGPropertyManager* propMan, Element* el, const string& prefix)
106 : PropertyManager(propMan), Prefix(prefix)
109 string operation, property_name;
111 cachedValue = -HUGE_VAL;
112 invlog2val = 1.0/log10(2.0);
114 Name = el->GetAttributeValue("name");
115 operation = el->GetName();
117 if (operation == function_string) {
119 } else if (operation == product_string) {
121 } else if (operation == difference_string) {
123 } else if (operation == sum_string) {
125 } else if (operation == quotient_string) {
127 } else if (operation == pow_string) {
129 } else if (operation == log2_string) {
131 } else if (operation == ln_string) {
133 } else if (operation == log10_string) {
135 } else if (operation == abs_string) {
137 } else if (operation == sign_string) {
139 } else if (operation == sin_string) {
141 } else if (operation == exp_string) {
143 } else if (operation == cos_string) {
145 } else if (operation == tan_string) {
147 } else if (operation == asin_string) {
149 } else if (operation == acos_string) {
151 } else if (operation == atan_string) {
153 } else if (operation == atan2_string) {
155 } else if (operation == min_string) {
157 } else if (operation == max_string) {
159 } else if (operation == avg_string) {
161 } else if (operation == fraction_string) {
163 } else if (operation == integer_string) {
165 } else if (operation == mod_string) {
167 } else if (operation == random_string) {
169 } else if (operation == rotation_alpha_local_string) {
170 Type = eRotation_alpha_local;
171 } else if (operation == rotation_beta_local_string) {
172 Type = eRotation_beta_local;
173 } else if (operation == rotation_gamma_local_string) {
174 Type = eRotation_gamma_local;
175 } else if (operation == rotation_bf_to_wf_string) {
176 Type = eRotation_bf_to_wf;
177 } else if (operation == rotation_wf_to_bf_string) {
178 Type = eRotation_wf_to_bf;
179 } else if (operation == lessthan_string) {
181 } else if (operation == lessequal_string) {
183 } else if (operation == greatthan_string) {
185 } else if (operation == greatequal_string) {
187 } else if (operation == equal_string) {
189 } else if (operation == notequal_string) {
191 } else if (operation == and_string) {
193 } else if (operation == or_string) {
195 } else if (operation == not_string) {
197 } else if (operation == ifthen_string) {
199 } else if (operation == switch_string) {
201 } else if (operation != description_string) {
202 cerr << "Bad operation " << operation << " detected in configuration file" << endl;
205 element = el->GetElement();
207 cerr << fgred << highint << endl;
208 cerr << " No element was specified as an argument to the \"" << operation << "\" operation" << endl;
209 cerr << " This can happen when, for instance, a cos operation is specified and a " << endl;
210 cerr << " property name is given explicitly, but is not placed within a" << endl;
211 cerr << " <property></property> element tag pair." << endl;
217 operation = element->GetName();
220 if (operation == property_string || operation == p_string) {
221 property_name = element->GetDataLine();
222 if (property_name.find("#") != string::npos) {
223 if (is_number(Prefix)) {
224 property_name = replace(property_name,"#",Prefix);
227 FGPropertyManager* newNode = 0L;
228 if (PropertyManager->HasNode(property_name)) {
229 newNode = PropertyManager->GetNode(property_name);
230 Parameters.push_back(new FGPropertyValue( newNode ));
232 cerr << fgcyan << "Warning: The property " + property_name + " is initially undefined."
234 Parameters.push_back(new FGPropertyValue( property_name,
237 } else if (operation == value_string || operation == v_string) {
238 Parameters.push_back(new FGRealValue(element->GetDataAsNumber()));
239 } else if (operation == table_string || operation == t_string) {
240 Parameters.push_back(new FGTable(PropertyManager, element));
242 } else if (operation == product_string ||
243 operation == difference_string ||
244 operation == sum_string ||
245 operation == quotient_string ||
246 operation == pow_string ||
247 operation == exp_string ||
248 operation == log2_string ||
249 operation == ln_string ||
250 operation == log10_string ||
251 operation == abs_string ||
252 operation == sign_string ||
253 operation == sin_string ||
254 operation == cos_string ||
255 operation == tan_string ||
256 operation == asin_string ||
257 operation == acos_string ||
258 operation == atan_string ||
259 operation == atan2_string ||
260 operation == min_string ||
261 operation == max_string ||
262 operation == fraction_string ||
263 operation == integer_string ||
264 operation == mod_string ||
265 operation == random_string ||
266 operation == avg_string ||
267 operation == rotation_alpha_local_string||
268 operation == rotation_beta_local_string||
269 operation == rotation_gamma_local_string||
270 operation == rotation_bf_to_wf_string||
271 operation == rotation_wf_to_bf_string ||
272 operation == lessthan_string ||
273 operation == lessequal_string ||
274 operation == greatthan_string ||
275 operation == greatequal_string ||
276 operation == equal_string ||
277 operation == notequal_string ||
278 operation == and_string ||
279 operation == or_string ||
280 operation == not_string ||
281 operation == ifthen_string ||
282 operation == switch_string)
284 Parameters.push_back(new FGFunction(PropertyManager, element, Prefix));
285 } else if (operation != description_string) {
286 cerr << "Bad operation " << operation << " detected in configuration file" << endl;
288 element = el->GetNextElement();
291 bind(); // Allow any function to save its value
296 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
298 FGFunction::~FGFunction(void)
300 for (unsigned int i=0; i<Parameters.size(); i++) delete Parameters[i];
303 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
305 void FGFunction::cacheValue(bool cache)
307 cached = false; // Must set cached to false prior to calling GetValue(), else
308 // it will _never_ calculate the value;
310 cachedValue = GetValue();
315 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
317 unsigned int FGFunction::GetBinary(double val) const
320 if (val < 1E-9) return 0;
321 else if (val-1 < 1E-9) return 1;
323 throw("Malformed conditional check in function definition.");
327 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
329 double FGFunction::GetValue(void) const
335 if (cached) return cachedValue;
337 temp = Parameters[0]->GetValue();
343 for (i=1;i<Parameters.size();i++) {
344 temp *= Parameters[i]->GetValue();
348 for (i=1;i<Parameters.size();i++) {
349 temp -= Parameters[i]->GetValue();
353 for (i=1;i<Parameters.size();i++) {
354 temp += Parameters[i]->GetValue();
358 if (Parameters[1]->GetValue() != 0.0)
359 temp /= Parameters[1]->GetValue();
364 temp = pow(temp,Parameters[1]->GetValue());
370 if (temp > 0.00) temp = log10(temp)*invlog2val;
371 else temp = -HUGE_VAL;
374 if (temp > 0.00) temp = log(temp);
375 else temp = -HUGE_VAL;
378 if (temp > 0.00) temp = log10(temp);
379 else temp = -HUGE_VAL;
385 temp = temp < 0 ? -1:1; // 0.0 counts as positive.
406 temp = atan2(temp, Parameters[1]->GetValue());
409 temp = ((int)temp) % ((int) Parameters[1]->GetValue());
412 for (i=1;i<Parameters.size();i++) {
413 if (Parameters[i]->GetValue() < temp) temp = Parameters[i]->GetValue();
417 for (i=1;i<Parameters.size();i++) {
418 if (Parameters[i]->GetValue() > temp) temp = Parameters[i]->GetValue();
422 for (i=1;i<Parameters.size();i++) {
423 temp += Parameters[i]->GetValue();
425 temp /= Parameters.size();
428 temp = modf(temp, &scratch);
431 modf(temp, &scratch);
435 temp = GaussianRandomNumber();
438 temp = (temp < Parameters[1]->GetValue())?1:0;
441 temp = (temp <= Parameters[1]->GetValue())?1:0;
444 temp = (temp > Parameters[1]->GetValue())?1:0;
447 temp = (temp >= Parameters[1]->GetValue())?1:0;
450 temp = (temp == Parameters[1]->GetValue())?1:0;
453 temp = (temp != Parameters[1]->GetValue())?1:0;
457 bool flag = (GetBinary(temp) != 0u);
458 for (i=1; i<Parameters.size() && flag; i++) {
459 flag = (GetBinary(Parameters[i]->GetValue()) != 0);
466 bool flag = (GetBinary(temp) != 0);
467 for (i=1; i<Parameters.size() && !flag; i++) {
468 flag = (GetBinary(Parameters[i]->GetValue()) != 0);
474 temp = (GetBinary(temp) != 0) ? 0 : 1;
478 i = Parameters.size();
480 if (GetBinary(temp) == 1) {
481 temp = Parameters[1]->GetValue();
483 temp = Parameters[2]->GetValue();
486 throw("Malformed if/then function statement");
492 unsigned int n = Parameters.size()-1;
494 if (i >= 0u && i < n) {
495 temp = Parameters[i+1]->GetValue();
497 throw(string("The switch function index selected a value above the range of supplied values"
498 " - not enough values were supplied."));
502 case eRotation_alpha_local:
503 if (Parameters.size()==6) // calculates local angle of attack for skydiver body component
504 //Euler angles from the intermediate body frame to the local body frame must be from a z-y-x axis rotation order
506 double alpha = Parameters[0]->GetValue()*degtorad;
507 double beta = Parameters[1]->GetValue()*degtorad;
508 double gamma = Parameters[2]->GetValue()*degtorad;
509 double phi = Parameters[3]->GetValue()*degtorad;
510 double theta = Parameters[4]->GetValue()*degtorad;
511 double psi = Parameters[5]->GetValue()*degtorad;
512 double cphi2 = cos(-phi/2), ctht2 = cos(-theta/2), cpsi2 = cos(-psi/2);
513 double sphi2 = sin(-phi/2), stht2 = sin(-theta/2), spsi2 = sin(-psi/2);
514 double calpha2 = cos(-alpha/2), salpha2 = sin(-alpha/2);
515 double cbeta2 = cos(beta/2), sbeta2 = sin(beta/2);
516 double cgamma2 = cos(-gamma/2), sgamma2 = sin(-gamma/2);
517 //calculate local body frame to the intermediate body frame rotation quaternion
518 double At = cphi2*ctht2*cpsi2 - sphi2*stht2*spsi2;
519 double Ax = cphi2*stht2*spsi2 + sphi2*ctht2*cpsi2;
520 double Ay = cphi2*stht2*cpsi2 - sphi2*ctht2*spsi2;
521 double Az = cphi2*ctht2*spsi2 + sphi2*stht2*cpsi2;
522 //calculate the intermediate body frame to global wind frame rotation quaternion
523 double Bt = calpha2*cbeta2*cgamma2 - salpha2*sbeta2*sgamma2;
524 double Bx = calpha2*cbeta2*sgamma2 + salpha2*sbeta2*cgamma2;
525 double By = calpha2*sbeta2*sgamma2 + salpha2*cbeta2*cgamma2;
526 double Bz = calpha2*sbeta2*cgamma2 - salpha2*cbeta2*sgamma2;
527 //multiply quaternions
528 double Ct = At*Bt - Ax*Bx - Ay*By - Az*Bz;
529 double Cx = At*Bx + Ax*Bt + Ay*Bz - Az*By;
530 double Cy = At*By - Ax*Bz + Ay*Bt + Az*Bx;
531 double Cz = At*Bz + Ax*By - Ay*Bx + Az*Bt;
532 //calculate alpha_local
533 temp = -atan2(2*(Cy*Ct-Cx*Cz),(Ct*Ct+Cx*Cx-Cy*Cy-Cz*Cz));
539 case eRotation_beta_local:
540 if (Parameters.size()==6) // calculates local angle of sideslip for skydiver body component
541 //Euler angles from the intermediate body frame to the local body frame must be from a z-y-x axis rotation order
543 double alpha = Parameters[0]->GetValue()*degtorad; //angle of attack of intermediate body frame
544 double beta = Parameters[1]->GetValue()*degtorad; //sideslip angle of intermediate body frame
545 double gamma = Parameters[2]->GetValue()*degtorad; //roll angle of intermediate body frame
546 double phi = Parameters[3]->GetValue()*degtorad; //x-axis Euler angle from the intermediate body frame to the local body frame
547 double theta = Parameters[4]->GetValue()*degtorad; //y-axis Euler angle from the intermediate body frame to the local body frame
548 double psi = Parameters[5]->GetValue()*degtorad; //z-axis Euler angle from the intermediate body frame to the local body frame
549 double cphi2 = cos(-phi/2), ctht2 = cos(-theta/2), cpsi2 = cos(-psi/2);
550 double sphi2 = sin(-phi/2), stht2 = sin(-theta/2), spsi2 = sin(-psi/2);
551 double calpha2 = cos(-alpha/2), salpha2 = sin(-alpha/2);
552 double cbeta2 = cos(beta/2), sbeta2 = sin(beta/2);
553 double cgamma2 = cos(-gamma/2), sgamma2 = sin(-gamma/2);
554 //calculate local body frame to the intermediate body frame rotation quaternion
555 double At = cphi2*ctht2*cpsi2 - sphi2*stht2*spsi2;
556 double Ax = cphi2*stht2*spsi2 + sphi2*ctht2*cpsi2;
557 double Ay = cphi2*stht2*cpsi2 - sphi2*ctht2*spsi2;
558 double Az = cphi2*ctht2*spsi2 + sphi2*stht2*cpsi2;
559 //calculate the intermediate body frame to global wind frame rotation quaternion
560 double Bt = calpha2*cbeta2*cgamma2 - salpha2*sbeta2*sgamma2;
561 double Bx = calpha2*cbeta2*sgamma2 + salpha2*sbeta2*cgamma2;
562 double By = calpha2*sbeta2*sgamma2 + salpha2*cbeta2*cgamma2;
563 double Bz = calpha2*sbeta2*cgamma2 - salpha2*cbeta2*sgamma2;
564 //multiply quaternions
565 double Ct = At*Bt - Ax*Bx - Ay*By - Az*Bz;
566 double Cx = At*Bx + Ax*Bt + Ay*Bz - Az*By;
567 double Cy = At*By - Ax*Bz + Ay*Bt + Az*Bx;
568 double Cz = At*Bz + Ax*By - Ay*Bx + Az*Bt;
569 //calculate beta_local
570 temp = asin(2*(Cx*Cy+Cz*Ct));
576 case eRotation_gamma_local:
577 if (Parameters.size()==6) // calculates local angle of attack for skydiver body component
578 //Euler angles from the intermediate body frame to the local body frame must be from a z-y-x axis rotation order
580 double alpha = Parameters[0]->GetValue()*degtorad; //angle of attack of intermediate body frame
581 double beta = Parameters[1]->GetValue()*degtorad; //sideslip angle of intermediate body frame
582 double gamma = Parameters[2]->GetValue()*degtorad; //roll angle of intermediate body frame
583 double phi = Parameters[3]->GetValue()*degtorad; //x-axis Euler angle from the intermediate body frame to the local body frame
584 double theta = Parameters[4]->GetValue()*degtorad; //y-axis Euler angle from the intermediate body frame to the local body frame
585 double psi = Parameters[5]->GetValue()*degtorad; //z-axis Euler angle from the intermediate body frame to the local body frame
586 double cphi2 = cos(-phi/2), ctht2 = cos(-theta/2), cpsi2 = cos(-psi/2);
587 double sphi2 = sin(-phi/2), stht2 = sin(-theta/2), spsi2 = sin(-psi/2);
588 double calpha2 = cos(-alpha/2), salpha2 = sin(-alpha/2);
589 double cbeta2 = cos(beta/2), sbeta2 = sin(beta/2);
590 double cgamma2 = cos(-gamma/2), sgamma2 = sin(-gamma/2);
591 //calculate local body frame to the intermediate body frame rotation quaternion
592 double At = cphi2*ctht2*cpsi2 - sphi2*stht2*spsi2;
593 double Ax = cphi2*stht2*spsi2 + sphi2*ctht2*cpsi2;
594 double Ay = cphi2*stht2*cpsi2 - sphi2*ctht2*spsi2;
595 double Az = cphi2*ctht2*spsi2 + sphi2*stht2*cpsi2;
596 //calculate the intermediate body frame to global wind frame rotation quaternion
597 double Bt = calpha2*cbeta2*cgamma2 - salpha2*sbeta2*sgamma2;
598 double Bx = calpha2*cbeta2*sgamma2 + salpha2*sbeta2*cgamma2;
599 double By = calpha2*sbeta2*sgamma2 + salpha2*cbeta2*cgamma2;
600 double Bz = calpha2*sbeta2*cgamma2 - salpha2*cbeta2*sgamma2;
601 //multiply quaternions
602 double Ct = At*Bt - Ax*Bx - Ay*By - Az*Bz;
603 double Cx = At*Bx + Ax*Bt + Ay*Bz - Az*By;
604 double Cy = At*By - Ax*Bz + Ay*Bt + Az*Bx;
605 double Cz = At*Bz + Ax*By - Ay*Bx + Az*Bt;
606 //calculate local roll anlge
607 temp = -atan2(2*(Cx*Ct-Cz*Cy),(Ct*Ct-Cx*Cx+Cy*Cy-Cz*Cz));
613 case eRotation_bf_to_wf:
614 if (Parameters.size()==7) // transforms the input vector from a body frame to a wind frame. The origin of the vector remains the same.
616 double rx = Parameters[0]->GetValue(); //x component of input vector
617 double ry = Parameters[1]->GetValue(); //y component of input vector
618 double rz = Parameters[2]->GetValue(); //z component of input vector
619 double alpha = Parameters[3]->GetValue()*degtorad; //angle of attack of the body frame
620 double beta = Parameters[4]->GetValue()*degtorad; //sideslip angle of the body frame
621 double gamma = Parameters[5]->GetValue()*degtorad; //roll angle of the body frame
622 double index = Parameters[6]->GetValue();
623 double calpha2 = cos(-alpha/2), salpha2 = sin(-alpha/2);
624 double cbeta2 = cos(beta/2), sbeta2 = sin(beta/2);
625 double cgamma2 = cos(-gamma/2), sgamma2 = sin(-gamma/2);
626 //calculate the body frame to wind frame quaternion
627 double qt = calpha2*cbeta2*cgamma2 - salpha2*sbeta2*sgamma2;
628 double qx = calpha2*cbeta2*sgamma2 + salpha2*sbeta2*cgamma2;
629 double qy = calpha2*sbeta2*sgamma2 + salpha2*cbeta2*cgamma2;
630 double qz = calpha2*sbeta2*cgamma2 - salpha2*cbeta2*sgamma2;
631 //calculate the quaternion conjugate
636 //multiply quaternions v*q
637 double vqt = -rx*qx - ry*qy - rz*qz;
638 double vqx = rx*qt + ry*qz - rz*qy;
639 double vqy = -rx*qz + ry*qt + rz*qx;
640 double vqz = rx*qy - ry*qx + rz*qt;
641 //multiply quaternions qstar*vq
642 double Cx = qstart*vqx + qstarx*vqt + qstary*vqz - qstarz*vqy;
643 double Cy = qstart*vqy - qstarx*vqz + qstary*vqt + qstarz*vqx;
644 double Cz = qstart*vqz + qstarx*vqy - qstary*vqx + qstarz*vqt;
646 if (index == 1) temp = Cx;
647 else if (index ==2) temp = Cy;
653 case eRotation_wf_to_bf:
654 if (Parameters.size()==7) // transforms the input vector from q wind frame to a body frame. The origin of the vector remains the same.
656 double rx = Parameters[0]->GetValue(); //x component of input vector
657 double ry = Parameters[1]->GetValue(); //y component of input vector
658 double rz = Parameters[2]->GetValue(); //z component of input vector
659 double alpha = Parameters[3]->GetValue()*degtorad; //angle of attack of the body frame
660 double beta = Parameters[4]->GetValue()*degtorad; //sideslip angle of the body frame
661 double gamma = Parameters[5]->GetValue()*degtorad; //roll angle of the body frame
662 double index = Parameters[6]->GetValue();
663 double calpha2 = cos(alpha/2), salpha2 = sin(alpha/2);
664 double cbeta2 = cos(-beta/2), sbeta2 = sin(-beta/2);
665 double cgamma2 = cos(gamma/2), sgamma2 = sin(gamma/2);
666 //calculate the wind frame to body frame quaternion
667 double qt = cgamma2*cbeta2*calpha2 + sgamma2*sbeta2*salpha2;
668 double qx = -cgamma2*sbeta2*salpha2 + sgamma2*cbeta2*calpha2;
669 double qy = cgamma2*cbeta2*salpha2 - sgamma2*sbeta2*calpha2;
670 double qz = cgamma2*sbeta2*calpha2 + sgamma2*cbeta2*salpha2;
671 //calculate the quaternion conjugate
676 //multiply quaternions v*q
677 double vqt = -rx*qx - ry*qy - rz*qz;
678 double vqx = rx*qt + ry*qz - rz*qy;
679 double vqy = -rx*qz + ry*qt + rz*qx;
680 double vqz = rx*qy - ry*qx + rz*qt;
681 //multiply quaternions qstar*vq
682 double Cx = qstart*vqx + qstarx*vqt + qstary*vqz - qstarz*vqy;
683 double Cy = qstart*vqy - qstarx*vqz + qstary*vqt + qstarz*vqx;
684 double Cz = qstart*vqz + qstarx*vqy - qstary*vqx + qstarz*vqt;
686 if (index == 1) temp = Cx;
687 else if (index ==2) temp = Cy;
694 cerr << "Unknown function operation type" << endl;
701 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
703 string FGFunction::GetValueAsString(void) const
705 ostringstream buffer;
707 buffer << setw(9) << setprecision(6) << GetValue();
711 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
713 void FGFunction::bind(void)
715 if ( !Name.empty() ) {
718 tmp = PropertyManager->mkPropertyName(Name, false);
720 if (is_number(Prefix)) {
721 if (Name.find("#") != string::npos) { // if "#" is found
722 Name = replace(Name,"#",Prefix);
723 tmp = PropertyManager->mkPropertyName(Name, false);
725 cerr << "Malformed function name with number: " << Prefix
726 << " and property name: " << Name
727 << " but no \"#\" sign for substitution." << endl;
730 tmp = PropertyManager->mkPropertyName(Prefix + "/" + Name, false);
734 PropertyManager->Tie( tmp, this, &FGFunction::GetValue);
738 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
739 // The bitmasked value choices are as follows:
740 // unset: In this case (the default) JSBSim would only print
741 // out the normally expected messages, essentially echoing
742 // the config files as they are read. If the environment
743 // variable is not set, debug_lvl is set to 1 internally
744 // 0: This requests JSBSim not to output any messages
746 // 1: This value explicity requests the normal JSBSim
748 // 2: This value asks for a message to be printed out when
749 // a class is instantiated
750 // 4: When this value is set, a message is displayed when a
751 // FGModel object executes its Run() method
752 // 8: When this value is set, various runtime state variables
753 // are printed out periodically
754 // 16: When set various parameters are sanity checked and
755 // a message is printed out when they go out of bounds
757 void FGFunction::Debug(int from)
759 if (debug_lvl <= 0) return;
761 if (debug_lvl & 1) { // Standard console startup message output
762 if (from == 0) { // Constructor
763 if (Type == eTopLevel)
764 cout << " Function: " << Name << endl;
767 if (debug_lvl & 2 ) { // Instantiation/Destruction notification
768 if (from == 0) cout << "Instantiated: FGFunction" << endl;
769 if (from == 1) cout << "Destroyed: FGFunction" << endl;
771 if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
773 if (debug_lvl & 8 ) { // Runtime state variables
775 if (debug_lvl & 16) { // Sanity checking
777 if (debug_lvl & 64) {
778 if (from == 0) { // Constructor
779 cout << IdSrc << endl;
780 cout << IdHdr << endl;