1 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2
3 Author: Jon Berndt
4 Date started: 09/28/2004
5 Purpose: XML element class
6 Called by: FGXMLParse
7
8 ------------- Copyright (C) 2001 Jon S. Berndt (jon@jsbsim.org) -------------
9
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
12 Software Foundation; either version 2 of the License, or (at your option) any
13 later version.
14
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
18 details.
19
20 You should have received a copy of the GNU Lesser General Public License along
21 with this program; if not, write to the Free Software Foundation, Inc., 59
22 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23
24 Further information about the GNU Lesser General Public License can also be
25 found on the world wide web at http://www.gnu.org.
26
27 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
28 INCLUDES
29 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
30
31 #include "FGXMLElement.h"
32 #include "FGJSBBase.h"
33
34 using namespace std;
35
36 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
37 FORWARD DECLARATIONS
38 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
39
40 namespace JSBSim {
41
42 bool Element::converterIsInitialized = false;
43 map <string, map <string, double> > Element::convert;
44
45 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
46 CLASS IMPLEMENTATION
47 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
48
Element(const string & nm)49 Element::Element(const string& nm)
50 {
51 name = nm;
52 parent = 0L;
53 element_index = 0;
54 line_number = -1;
55
56 if (!converterIsInitialized) {
57 converterIsInitialized = true;
58 // convert ["from"]["to"] = factor, so: from * factor = to
59 // Length
60 convert["M"]["FT"] = 3.2808399;
61 convert["FT"]["M"] = 1.0/convert["M"]["FT"];
62 convert["CM"]["FT"] = 0.032808399;
63 convert["FT"]["CM"] = 1.0/convert["CM"]["FT"];
64 convert["KM"]["FT"] = 3280.8399;
65 convert["FT"]["KM"] = 1.0/convert["KM"]["FT"];
66 convert["FT"]["IN"] = 12.0;
67 convert["IN"]["FT"] = 1.0/convert["FT"]["IN"];
68 convert["IN"]["M"] = convert["IN"]["FT"] * convert["FT"]["M"];
69 convert["M"]["IN"] = convert["M"]["FT"] * convert["FT"]["IN"];
70 // Area
71 convert["M2"]["FT2"] = convert["M"]["FT"]*convert["M"]["FT"];
72 convert["FT2"]["M2"] = 1.0/convert["M2"]["FT2"];
73 convert["CM2"]["FT2"] = convert["CM"]["FT"]*convert["CM"]["FT"];
74 convert["FT2"]["CM2"] = 1.0/convert["CM2"]["FT2"];
75 convert["M2"]["IN2"] = convert["M"]["IN"]*convert["M"]["IN"];
76 convert["IN2"]["M2"] = 1.0/convert["M2"]["IN2"];
77 convert["FT2"]["IN2"] = 144.0;
78 convert["IN2"]["FT2"] = 1.0/convert["FT2"]["IN2"];
79 // Volume
80 convert["IN3"]["CC"] = 16.387064;
81 convert["CC"]["IN3"] = 1.0/convert["IN3"]["CC"];
82 convert["FT3"]["IN3"] = 1728.0;
83 convert["IN3"]["FT3"] = 1.0/convert["FT3"]["IN3"];
84 convert["M3"]["FT3"] = 35.3146667;
85 convert["FT3"]["M3"] = 1.0/convert["M3"]["FT3"];
86 convert["LTR"]["IN3"] = 61.0237441;
87 convert["IN3"]["LTR"] = 1.0/convert["LTR"]["IN3"];
88 convert["GAL"]["FT3"] = 0.133681;
89 convert["FT3"]["GAL"] = 1.0/convert["GAL"]["FT3"];
90 convert["IN3"]["GAL"] = convert["IN3"]["FT3"]*convert["FT3"]["GAL"];
91 convert["LTR"]["GAL"] = convert["LTR"]["IN3"]*convert["IN3"]["GAL"];
92 convert["M3"]["GAL"] = 1000.*convert["LTR"]["GAL"];
93 convert["CC"]["GAL"] = convert["CC"]["IN3"]*convert["IN3"]["GAL"];
94 // Mass & Weight
95 convert["LBS"]["KG"] = 0.45359237;
96 convert["KG"]["LBS"] = 1.0/convert["LBS"]["KG"];
97 convert["SLUG"]["KG"] = 14.59390;
98 convert["KG"]["SLUG"] = 1.0/convert["SLUG"]["KG"];
99 // Moments of Inertia
100 convert["SLUG*FT2"]["KG*M2"] = 1.35594;
101 convert["KG*M2"]["SLUG*FT2"] = 1.0/convert["SLUG*FT2"]["KG*M2"];
102 // Angles
103 convert["RAD"]["DEG"] = 180.0/M_PI;
104 convert["DEG"]["RAD"] = 1.0/convert["RAD"]["DEG"];
105 // Angular rates
106 convert["RAD/SEC"]["DEG/SEC"] = convert["RAD"]["DEG"];
107 convert["DEG/SEC"]["RAD/SEC"] = 1.0/convert["RAD/SEC"]["DEG/SEC"];
108 // Spring force
109 convert["LBS/FT"]["N/M"] = 14.5939;
110 convert["N/M"]["LBS/FT"] = 1.0/convert["LBS/FT"]["N/M"];
111 // Damping force
112 convert["LBS/FT/SEC"]["N/M/SEC"] = 14.5939;
113 convert["N/M/SEC"]["LBS/FT/SEC"] = 1.0/convert["LBS/FT/SEC"]["N/M/SEC"];
114 // Damping force (Square Law)
115 convert["LBS/FT2/SEC2"]["N/M2/SEC2"] = 47.880259;
116 convert["N/M2/SEC2"]["LBS/FT2/SEC2"] = 1.0/convert["LBS/FT2/SEC2"]["N/M2/SEC2"];
117 // Power
118 convert["WATTS"]["HP"] = 0.001341022;
119 convert["HP"]["WATTS"] = 1.0/convert["WATTS"]["HP"];
120 // Force
121 convert["N"]["LBS"] = 0.22482;
122 convert["LBS"]["N"] = 1.0/convert["N"]["LBS"];
123 // Velocity
124 convert["KTS"]["FT/SEC"] = 1.68781;
125 convert["FT/SEC"]["KTS"] = 1.0/convert["KTS"]["FT/SEC"];
126 convert["M/S"]["FT/S"] = 3.2808399;
127 convert["M/S"]["KTS"] = convert["M/S"]["FT/S"]/convert["KTS"]["FT/SEC"];
128 convert["M/SEC"]["FT/SEC"] = 3.2808399;
129 convert["FT/S"]["M/S"] = 1.0/convert["M/S"]["FT/S"];
130 convert["M/SEC"]["FT/SEC"] = 3.2808399;
131 convert["FT/SEC"]["M/SEC"] = 1.0/convert["M/SEC"]["FT/SEC"];
132 convert["KM/SEC"]["FT/SEC"] = 3280.8399;
133 convert["FT/SEC"]["KM/SEC"] = 1.0/convert["KM/SEC"]["FT/SEC"];
134 // Torque
135 convert["FT*LBS"]["N*M"] = 1.35581795;
136 convert["N*M"]["FT*LBS"] = 1/convert["FT*LBS"]["N*M"];
137 // Valve
138 convert["M4*SEC/KG"]["FT4*SEC/SLUG"] = convert["M"]["FT"]*convert["M"]["FT"]*
139 convert["M"]["FT"]*convert["M"]["FT"]/convert["KG"]["SLUG"];
140 convert["FT4*SEC/SLUG"]["M4*SEC/KG"] =
141 1.0/convert["M4*SEC/KG"]["FT4*SEC/SLUG"];
142 // Pressure
143 convert["INHG"]["PSF"] = 70.7180803;
144 convert["PSF"]["INHG"] = 1.0/convert["INHG"]["PSF"];
145 convert["ATM"]["INHG"] = 29.9246899;
146 convert["INHG"]["ATM"] = 1.0/convert["ATM"]["INHG"];
147 convert["PSI"]["INHG"] = 2.03625437;
148 convert["INHG"]["PSI"] = 1.0/convert["PSI"]["INHG"];
149 convert["INHG"]["PA"] = 3386.0; // inches Mercury to pascals
150 convert["PA"]["INHG"] = 1.0/convert["INHG"]["PA"];
151 convert["LBS/FT2"]["N/M2"] = 14.5939/convert["FT"]["M"];
152 convert["N/M2"]["LBS/FT2"] = 1.0/convert["LBS/FT2"]["N/M2"];
153 convert["LBS/FT2"]["PA"] = convert["LBS/FT2"]["N/M2"];
154 convert["PA"]["LBS/FT2"] = 1.0/convert["LBS/FT2"]["PA"];
155 // Mass flow
156 convert["KG/MIN"]["LBS/MIN"] = convert["KG"]["LBS"];
157 convert ["N/SEC"]["LBS/SEC"] = 0.224808943;
158 convert ["LBS/SEC"]["N/SEC"] = 1.0/convert ["N/SEC"]["LBS/SEC"];
159 // Fuel Consumption
160 convert["LBS/HP*HR"]["KG/KW*HR"] = 0.6083;
161 convert["KG/KW*HR"]["LBS/HP*HR"] = 1.0/convert["LBS/HP*HR"]["KG/KW*HR"];
162 // Density
163 convert["KG/L"]["LBS/GAL"] = 8.3454045;
164 convert["LBS/GAL"]["KG/L"] = 1.0/convert["KG/L"]["LBS/GAL"];
165
166 // Length
167 convert["M"]["M"] = 1.00;
168 convert["KM"]["KM"] = 1.00;
169 convert["FT"]["FT"] = 1.00;
170 convert["IN"]["IN"] = 1.00;
171 // Area
172 convert["M2"]["M2"] = 1.00;
173 convert["FT2"]["FT2"] = 1.00;
174 // Volume
175 convert["IN3"]["IN3"] = 1.00;
176 convert["CC"]["CC"] = 1.0;
177 convert["M3"]["M3"] = 1.0;
178 convert["FT3"]["FT3"] = 1.0;
179 convert["LTR"]["LTR"] = 1.0;
180 convert["GAL"]["GAL"] = 1.0;
181 // Mass & Weight
182 convert["KG"]["KG"] = 1.00;
183 convert["LBS"]["LBS"] = 1.00;
184 // Moments of Inertia
185 convert["KG*M2"]["KG*M2"] = 1.00;
186 convert["SLUG*FT2"]["SLUG*FT2"] = 1.00;
187 // Angles
188 convert["DEG"]["DEG"] = 1.00;
189 convert["RAD"]["RAD"] = 1.00;
190 // Angular rates
191 convert["DEG/SEC"]["DEG/SEC"] = 1.00;
192 convert["RAD/SEC"]["RAD/SEC"] = 1.00;
193 // Spring force
194 convert["LBS/FT"]["LBS/FT"] = 1.00;
195 convert["N/M"]["N/M"] = 1.00;
196 // Damping force
197 convert["LBS/FT/SEC"]["LBS/FT/SEC"] = 1.00;
198 convert["N/M/SEC"]["N/M/SEC"] = 1.00;
199 // Damping force (Square law)
200 convert["LBS/FT2/SEC2"]["LBS/FT2/SEC2"] = 1.00;
201 convert["N/M2/SEC2"]["N/M2/SEC2"] = 1.00;
202 // Power
203 convert["HP"]["HP"] = 1.00;
204 convert["WATTS"]["WATTS"] = 1.00;
205 // Force
206 convert["N"]["N"] = 1.00;
207 // Velocity
208 convert["FT/SEC"]["FT/SEC"] = 1.00;
209 convert["KTS"]["KTS"] = 1.00;
210 convert["M/S"]["M/S"] = 1.0;
211 convert["M/SEC"]["M/SEC"] = 1.0;
212 convert["KM/SEC"]["KM/SEC"] = 1.0;
213 // Torque
214 convert["FT*LBS"]["FT*LBS"] = 1.00;
215 convert["N*M"]["N*M"] = 1.00;
216 // Valve
217 convert["M4*SEC/KG"]["M4*SEC/KG"] = 1.0;
218 convert["FT4*SEC/SLUG"]["FT4*SEC/SLUG"] = 1.0;
219 // Pressure
220 convert["PSI"]["PSI"] = 1.00;
221 convert["PSF"]["PSF"] = 1.00;
222 convert["INHG"]["INHG"] = 1.00;
223 convert["ATM"]["ATM"] = 1.0;
224 convert["PA"]["PA"] = 1.0;
225 convert["N/M2"]["N/M2"] = 1.00;
226 convert["LBS/FT2"]["LBS/FT2"] = 1.00;
227 // Mass flow
228 convert["LBS/SEC"]["LBS/SEC"] = 1.00;
229 convert["KG/MIN"]["KG/MIN"] = 1.0;
230 convert["LBS/MIN"]["LBS/MIN"] = 1.0;
231 convert["N/SEC"]["N/SEC"] = 1.0;
232 // Fuel Consumption
233 convert["LBS/HP*HR"]["LBS/HP*HR"] = 1.0;
234 convert["KG/KW*HR"]["KG/KW*HR"] = 1.0;
235 // Density
236 convert["KG/L"]["KG/L"] = 1.0;
237 convert["LBS/GAL"]["LBS/GAL"] = 1.0;
238 }
239 }
240
241 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
242
~Element(void)243 Element::~Element(void)
244 {
245 for (unsigned int i = 0; i < children.size(); ++i)
246 children[i]->SetParent(0);
247 }
248
249 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
250
GetAttributeValue(const string & attr)251 string Element::GetAttributeValue(const string& attr)
252 {
253 if (HasAttribute(attr)) return attributes[attr];
254 else return ("");
255 }
256
257 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
258
SetAttributeValue(const std::string & key,const std::string & value)259 bool Element::SetAttributeValue(const std::string& key, const std::string& value)
260 {
261 bool ret = HasAttribute(key);
262 if (ret)
263 attributes[key] = value;
264
265 return ret;
266 }
267
268 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
269
GetAttributeValueAsNumber(const string & attr)270 double Element::GetAttributeValueAsNumber(const string& attr)
271 {
272 string attribute = GetAttributeValue(attr);
273
274 if (attribute.empty()) {
275 cerr << ReadFrom() << "Expecting numeric attribute value, but got no data"
276 << endl;
277 exit(-1);
278 }
279 else {
280 double number=0;
281 if (is_number(trim(attribute)))
282 number = atof(attribute.c_str());
283 else {
284 cerr << ReadFrom() << "Expecting numeric attribute value, but got: "
285 << attribute << endl;
286 exit(-1);
287 }
288
289 return (number);
290 }
291 }
292
293 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
294
GetElement(unsigned int el)295 Element* Element::GetElement(unsigned int el)
296 {
297 if (children.size() > el) {
298 element_index = el;
299 return children[el];
300 }
301 else {
302 element_index = 0;
303 return 0L;
304 }
305 }
306
307 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
308
GetNextElement(void)309 Element* Element::GetNextElement(void)
310 {
311 if (children.size() > element_index+1) {
312 element_index++;
313 return children[element_index];
314 } else {
315 element_index = 0;
316 return 0L;
317 }
318 }
319
320 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
321
GetDataLine(unsigned int i)322 string Element::GetDataLine(unsigned int i)
323 {
324 if (data_lines.size() > 0) return data_lines[i];
325 else return string("");
326 }
327
328 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
329
GetDataAsNumber(void)330 double Element::GetDataAsNumber(void)
331 {
332 if (data_lines.size() == 1) {
333 double number=0;
334 if (is_number(trim(data_lines[0])))
335 number = atof(data_lines[0].c_str());
336 else {
337 cerr << ReadFrom() << "Expected numeric value, but got: " << data_lines[0]
338 << endl;
339 exit(-1);
340 }
341
342 return number;
343 } else if (data_lines.size() == 0) {
344 cerr << ReadFrom() << "Expected numeric value, but got no data" << endl;
345 exit(-1);
346 } else {
347 cerr << ReadFrom() << "Attempting to get single data value in element "
348 << "<" << name << ">" << endl
349 << " from multiple lines:" << endl;
350 for(unsigned int i=0; i<data_lines.size(); ++i)
351 cerr << data_lines[i] << endl;
352 exit(-1);
353 }
354 }
355
356 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
357
GetNumElements(const string & element_name)358 unsigned int Element::GetNumElements(const string& element_name)
359 {
360 unsigned int number_of_elements=0;
361 Element* el=FindElement(element_name);
362 while (el) {
363 number_of_elements++;
364 el=FindNextElement(element_name);
365 }
366 return number_of_elements;
367 }
368
369 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
370
FindElement(const string & el)371 Element* Element::FindElement(const string& el)
372 {
373 if (el.empty() && children.size() >= 1) {
374 element_index = 1;
375 return children[0];
376 }
377 for (unsigned int i=0; i<children.size(); i++) {
378 if (el == children[i]->GetName()) {
379 element_index = i+1;
380 return children[i];
381 }
382 }
383 element_index = 0;
384 return 0L;
385 }
386
387 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
388
FindNextElement(const string & el)389 Element* Element::FindNextElement(const string& el)
390 {
391 if (el.empty()) {
392 if (element_index < children.size()) {
393 return children[element_index++];
394 } else {
395 element_index = 0;
396 return 0L;
397 }
398 }
399 for (unsigned int i=element_index; i<children.size(); i++) {
400 if (el == children[i]->GetName()) {
401 element_index = i+1;
402 return children[i];
403 }
404 }
405 element_index = 0;
406 return 0L;
407 }
408
409 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
410
FindElementValueAsNumber(const string & el)411 double Element::FindElementValueAsNumber(const string& el)
412 {
413 Element* element = FindElement(el);
414 if (element) {
415 double value = element->GetDataAsNumber();
416 value = DisperseValue(element, value);
417 return value;
418 } else {
419 cerr << ReadFrom() << "Attempting to get non-existent element " << el
420 << endl;
421 exit(-1);
422 }
423 }
424
425 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
426
FindElementValueAsBoolean(const string & el)427 bool Element::FindElementValueAsBoolean(const string& el)
428 {
429 Element* element = FindElement(el);
430 if (element) {
431 // check value as an ordinary number
432 double value = element->GetDataAsNumber();
433
434 // now check how it should return data
435 if (value == 0) {
436 return false;
437 } else {
438 return true;
439 }
440 } else {
441 cerr << ReadFrom() << "Attempting to get non-existent element " << el << " ;returning false"
442 << endl;
443 return false;
444 }
445 }
446
447 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
448
FindElementValue(const string & el)449 string Element::FindElementValue(const string& el)
450 {
451 Element* element = FindElement(el);
452 if (element) {
453 return element->GetDataLine();
454 } else {
455 return "";
456 }
457 }
458
459 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
460
FindElementValueAsNumberConvertTo(const string & el,const string & target_units)461 double Element::FindElementValueAsNumberConvertTo(const string& el, const string& target_units)
462 {
463 Element* element = FindElement(el);
464
465 if (!element) {
466 cerr << ReadFrom() << "Attempting to get non-existent element " << el
467 << endl;
468 exit(-1);
469 }
470
471 string supplied_units = element->GetAttributeValue("unit");
472
473 if (!supplied_units.empty()) {
474 if (convert.find(supplied_units) == convert.end()) {
475 cerr << element->ReadFrom() << "Supplied unit: \""
476 << supplied_units << "\" does not exist (typo?)." << endl;
477 exit(-1);
478 }
479 if (convert[supplied_units].find(target_units) == convert[supplied_units].end()) {
480 cerr << element->ReadFrom() << "Supplied unit: \""
481 << supplied_units << "\" cannot be converted to " << target_units
482 << endl;
483 exit(-1);
484 }
485 }
486
487 double value = element->GetDataAsNumber();
488
489 // Sanity check for angular values
490 if ((supplied_units == "RAD") && (fabs(value) > 2 * M_PI)) {
491 cerr << element->ReadFrom() << element->GetName() << " value "
492 << value << " RAD is outside the range [ -2*M_PI RAD ; +2*M_PI RAD ]"
493 << endl;
494 }
495 if ((supplied_units == "DEG") && (fabs(value) > 360.0)) {
496 cerr << element->ReadFrom() << element->GetName() << " value "
497 << value << " DEG is outside the range [ -360 DEG ; +360 DEG ]"
498 << endl;
499 }
500
501
502 if (!supplied_units.empty()) {
503 value *= convert[supplied_units][target_units];
504 }
505
506 if ((target_units == "RAD") && (fabs(value) > 2 * M_PI)) {
507 cerr << element->ReadFrom() << element->GetName() << " value "
508 << value << " RAD is outside the range [ -2*M_PI RAD ; +2*M_PI RAD ]"
509 << endl;
510 }
511 if ((target_units == "DEG") && (fabs(value) > 360.0)) {
512 cerr << element->ReadFrom() << element->GetName() << " value "
513 << value << " DEG is outside the range [ -360 DEG ; +360 DEG ]"
514 << endl;
515 }
516
517 value = DisperseValue(element, value, supplied_units, target_units);
518
519 return value;
520 }
521
522 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
523
FindElementValueAsNumberConvertFromTo(const string & el,const string & supplied_units,const string & target_units)524 double Element::FindElementValueAsNumberConvertFromTo( const string& el,
525 const string& supplied_units,
526 const string& target_units)
527 {
528 Element* element = FindElement(el);
529
530 if (!element) {
531 cerr << "Attempting to get non-existent element " << el << endl;
532 exit(-1);
533 }
534
535 if (!supplied_units.empty()) {
536 if (convert.find(supplied_units) == convert.end()) {
537 cerr << element->ReadFrom() << "Supplied unit: \""
538 << supplied_units << "\" does not exist (typo?)." << endl;
539 exit(-1);
540 }
541 if (convert[supplied_units].find(target_units) == convert[supplied_units].end()) {
542 cerr << element->ReadFrom() << "Supplied unit: \""
543 << supplied_units << "\" cannot be converted to " << target_units
544 << endl;
545 exit(-1);
546 }
547 }
548
549 double value = element->GetDataAsNumber();
550 if (!supplied_units.empty()) {
551 value *= convert[supplied_units][target_units];
552 }
553
554 value = DisperseValue(element, value, supplied_units, target_units);
555
556 return value;
557 }
558
559 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
560
FindElementTripletConvertTo(const string & target_units)561 FGColumnVector3 Element::FindElementTripletConvertTo( const string& target_units)
562 {
563 FGColumnVector3 triplet;
564 Element* item;
565 double value=0.0;
566 string supplied_units = GetAttributeValue("unit");
567
568 if (!supplied_units.empty()) {
569 if (convert.find(supplied_units) == convert.end()) {
570 cerr << ReadFrom() << "Supplied unit: \""
571 << supplied_units << "\" does not exist (typo?)." << endl;
572 exit(-1);
573 }
574 if (convert[supplied_units].find(target_units) == convert[supplied_units].end()) {
575 cerr << ReadFrom() << "Supplied unit: \""
576 << supplied_units << "\" cannot be converted to " << target_units
577 << endl;
578 exit(-1);
579 }
580 }
581
582 item = FindElement("x");
583 if (!item) item = FindElement("roll");
584 if (item) {
585 value = item->GetDataAsNumber();
586 if (!supplied_units.empty()) value *= convert[supplied_units][target_units];
587 triplet(1) = DisperseValue(item, value, supplied_units, target_units);
588 } else {
589 triplet(1) = 0.0;
590 }
591
592
593 item = FindElement("y");
594 if (!item) item = FindElement("pitch");
595 if (item) {
596 value = item->GetDataAsNumber();
597 if (!supplied_units.empty()) value *= convert[supplied_units][target_units];
598 triplet(2) = DisperseValue(item, value, supplied_units, target_units);
599 } else {
600 triplet(2) = 0.0;
601 }
602
603 item = FindElement("z");
604 if (!item) item = FindElement("yaw");
605 if (item) {
606 value = item->GetDataAsNumber();
607 if (!supplied_units.empty()) value *= convert[supplied_units][target_units];
608 triplet(3) = DisperseValue(item, value, supplied_units, target_units);
609 } else {
610 triplet(3) = 0.0;
611 }
612
613 return triplet;
614 }
615
616 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
617
DisperseValue(Element * e,double val,const std::string & supplied_units,const std::string & target_units)618 double Element::DisperseValue(Element *e, double val, const std::string& supplied_units,
619 const std::string& target_units)
620 {
621 double value=val;
622
623 bool disperse = false;
624 try {
625 char* num = getenv("JSBSIM_DISPERSE");
626 if (num) {
627 disperse = (atoi(num) == 1); // set dispersions
628 }
629 } catch (...) { // if error set to false
630 disperse = false;
631 std::cerr << "Could not process JSBSIM_DISPERSE environment variable: Assumed NO dispersions." << endl;
632 }
633
634 if (e->HasAttribute("dispersion") && disperse) {
635 double disp = e->GetAttributeValueAsNumber("dispersion");
636 if (!supplied_units.empty()) disp *= convert[supplied_units][target_units];
637 string attType = e->GetAttributeValue("type");
638 if (attType == "gaussian" || attType == "gaussiansigned") {
639 double grn = FGJSBBase::GaussianRandomNumber();
640 if (attType == "gaussian") {
641 value = val + disp*grn;
642 } else { // Assume gaussiansigned
643 value = (val + disp*grn)*(fabs(grn)/grn);
644 }
645 } else if (attType == "uniform" || attType == "uniformsigned") {
646 double urn = ((((double)rand()/RAND_MAX)-0.5)*2.0);
647 if (attType == "uniform") {
648 value = val + disp * urn;
649 } else { // Assume uniformsigned
650 value = (val + disp * urn)*(fabs(urn)/urn);
651 }
652 } else {
653 cerr << ReadFrom() << "Unknown dispersion type" << attType << endl;
654 exit(-1);
655 }
656
657 }
658 return value;
659 }
660
661 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
662
Print(unsigned int level)663 void Element::Print(unsigned int level)
664 {
665 unsigned int i, spaces;
666
667 level+=2;
668 for (spaces=0; spaces<=level; spaces++) cout << " "; // format output
669 cout << "Element Name: " << name;
670
671 map<string, string>::iterator it;
672 for (it = attributes.begin(); it != attributes.end(); ++it)
673 cout << " " << it->first << " = " << it->second;
674
675 cout << endl;
676 for (i=0; i<data_lines.size(); i++) {
677 for (spaces=0; spaces<=level; spaces++) cout << " "; // format output
678 cout << data_lines[i] << endl;
679 }
680 for (i=0; i<children.size(); i++) {
681 children[i]->Print(level);
682 }
683 }
684
685 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
686
AddAttribute(const string & name,const string & value)687 void Element::AddAttribute(const string& name, const string& value)
688 {
689 attributes[name] = value;
690 }
691
692 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
693
AddData(string d)694 void Element::AddData(string d)
695 {
696 string::size_type string_start = d.find_first_not_of(" \t");
697 if (string_start != string::npos && string_start > 0) {
698 d.erase(0,string_start);
699 }
700 data_lines.push_back(d);
701 }
702
703 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
704
ReadFrom(void) const705 string Element::ReadFrom(void) const
706 {
707 ostringstream message;
708
709 message << endl
710 << "In file " << GetFileName() << ": line " << GetLineNumber()
711 << endl;
712
713 return message.str();
714 }
715
716 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
717
MergeAttributes(Element * el)718 void Element::MergeAttributes(Element* el)
719 {
720 map<string, string>::iterator it;
721
722 for (it=el->attributes.begin(); it != el->attributes.end(); ++it) {
723 if (attributes.find(it->first) == attributes.end())
724 attributes[it->first] = it->second;
725 else {
726 if (FGJSBBase::debug_lvl > 0 && (attributes[it->first] != it->second))
727 cout << el->ReadFrom() << " Attribute '" << it->first << "' is overridden in file "
728 << GetFileName() << ": line " << GetLineNumber() << endl
729 << " The value '" << attributes[it->first] << "' will be used instead of '"
730 << it->second << "'." << endl;
731 }
732 }
733 }
734
735 } // end namespace JSBSim
736