JSBSim Flight Dynamics Model  1.0 (02 March 2017)
An Open Source Flight Dynamics and Control Software Library in C++
FGScript.cpp
1 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2 
3  Module: FGScript.cpp
4  Author: Jon S. Berndt
5  Date started: 12/21/01
6  Purpose: Loads and runs JSBSim scripts.
7 
8  ------------- Copyright (C) 1999 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 Software
12  Foundation; either version 2 of the License, or (at your option) any later
13  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 with
21  this program; if not, write to the Free Software Foundation, Inc., 59 Temple
22  Place - Suite 330, Boston, MA 02111-1307, USA.
23 
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.
26 
27 FUNCTIONAL DESCRIPTION
28 --------------------------------------------------------------------------------
29 
30 This class wraps up the simulation scripting routines.
31 
32 HISTORY
33 --------------------------------------------------------------------------------
34 12/21/01 JSB Created
35 
36 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
37 COMMENTS, REFERENCES, and NOTES
38 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
39 
40 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
41 INCLUDES
42 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
43 
44 #include <iostream>
45 #include <cstdlib>
46 #include <iomanip>
47 
48 #include "FGScript.h"
49 #include "FGFDMExec.h"
50 #include "input_output/FGXMLElement.h"
51 #include "input_output/FGXMLFileRead.h"
52 #include "initialization/FGInitialCondition.h"
53 #include "models/FGInput.h"
54 #include "math/FGCondition.h"
55 #include "math/FGFunction.h"
56 
57 using namespace std;
58 
59 namespace JSBSim {
60 
61 IDENT(IdSrc,"$Id: FGScript.cpp,v 1.65 2017/02/25 14:23:18 bcoconni Exp $");
62 IDENT(IdHdr,ID_FGSCRIPT);
63 
64 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
65 GLOBAL DECLARATIONS
66 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
67 
68 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
69 CLASS IMPLEMENTATION
70 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
71 
72 // Constructor
73 
74 FGScript::FGScript(FGFDMExec* fgex) : FDMExec(fgex)
75 {
76  PropertyManager=FDMExec->GetPropertyManager();
77 
78  Debug(0);
79 }
80 
81 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
82 
84 {
85  unsigned int i, j;
86 
87  for (i=0; i<Events.size(); i++) {
88  delete Events[i].Condition;
89  for (j=0; j<Events[i].Functions.size(); j++)
90  delete Events[i].Functions[j];
91  }
92  Events.clear();
93 
94  Debug(1);
95 }
96 
97 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
98 
99 bool FGScript::LoadScript(const SGPath& script, double default_dT,
100  const SGPath& initfile)
101 {
102  SGPath initialize;
103  string aircraft="", prop_name="";
104  string notifyPropertyName="";
105  Element *element=0, *run_element=0, *event_element=0;
106  Element *set_element=0;
107  Element *notify_element = 0L, *notify_property_element = 0L;
108  double dt = 0.0, value = 0.0;
109  FGCondition *newCondition;
110 
111  FGXMLFileRead XMLFileRead;
112  Element* document = XMLFileRead.LoadXMLDocument(script);
113 
114  if (!document) {
115  cerr << "File: " << script << " could not be loaded." << endl;
116  return false;
117  }
118 
119  if (document->GetName() != string("runscript")) {
120  cerr << "File: " << script << " is not a script file" << endl;
121  return false;
122  }
123 
124  ScriptName = document->GetAttributeValue("name");
125 
126  // First, find "run" element and set delta T
127 
128  run_element = document->FindElement("run");
129 
130  if (!run_element) {
131  cerr << "No \"run\" element found in script." << endl;
132  return false;
133  }
134 
135  // Set sim timing
136 
137  if (run_element->HasAttribute("start"))
138  StartTime = run_element->GetAttributeValueAsNumber("start");
139  else
140  StartTime = 0.0;
141  FDMExec->Setsim_time(StartTime);
142  if (run_element->HasAttribute("end")) {
143  EndTime = run_element->GetAttributeValueAsNumber("end");
144  } else {
145  cerr << "An end time (duration) for the script must be specified in the script <run> element." << endl;
146  return false;
147  }
148 
149  // Make sure that the desired time is reached and executed.
150  EndTime += 0.99*FDMExec->GetDeltaT();
151 
152  if (default_dT == 0.0)
153  dt = run_element->GetAttributeValueAsNumber("dt");
154  else {
155  dt = default_dT;
156  cout << endl << "Overriding simulation step size from the command line. New step size is: "
157  << default_dT << " seconds (" << 1/default_dT << " Hz)" << endl << endl;
158  }
159 
160  FDMExec->Setdt(dt);
161 
162  // read aircraft and initialization files
163 
164  element = document->FindElement("use");
165  if (element) {
166  aircraft = element->GetAttributeValue("aircraft");
167  if (!aircraft.empty()) {
168  if (!FDMExec->LoadModel(aircraft))
169  return false;
170  } else {
171  cerr << "Aircraft must be specified in use element." << endl;
172  return false;
173  }
174 
175  initialize = SGPath::fromLocal8Bit(element->GetAttributeValue("initialize").c_str());
176  if (initfile.isNull()) {
177  if (initialize.isNull()) {
178  cerr << "Initialization file must be specified in use element." << endl;
179  return false;
180  }
181  } else {
182  cout << endl << "The initialization file specified in the script file (" << initialize
183  << ") has been overridden with a specified file (" << initfile << ")." << endl;
184  initialize = initfile;
185  }
186 
187  } else {
188  cerr << "No \"use\" directives in the script file." << endl;
189  return false;
190  }
191 
192  FGInitialCondition *IC=FDMExec->GetIC();
193  if ( ! IC->Load( initialize )) {
194  cerr << "Initialization unsuccessful" << endl;
195  return false;
196  }
197 
198  // Now, read input spec if given.
199  element = document->FindElement("input");
200  while (element) {
201  if (!FDMExec->GetInput()->Load(element))
202  return false;
203 
204  element = document->FindNextElement("input");
205  }
206 
207  // Now, read output spec if given.
208  element = document->FindElement("output");
209  while (element) {
210  if (!FDMExec->GetOutput()->Load(element))
211  return false;
212 
213  element = document->FindNextElement("output");
214  }
215 
216  // Read local property/value declarations
217  int saved_debug_lvl = debug_lvl;
218  debug_lvl = 0; // Disable messages
219  LocalProperties.Load(run_element, PropertyManager, true);
220  debug_lvl = saved_debug_lvl;
221 
222  // Read "events" from script
223 
224  event_element = run_element->FindElement("event");
225  while (event_element) { // event processing
226 
227  // Create the event structure
228  struct event *newEvent = new struct event();
229 
230  // Retrieve the event name if given
231  newEvent->Name = event_element->GetAttributeValue("name");
232 
233  // Is this event persistent? That is, does it execute every time the
234  // condition triggers to true, or does it execute as a one-shot event, only?
235  if (event_element->GetAttributeValue("persistent") == string("true")) {
236  newEvent->Persistent = true;
237  }
238 
239  // Does this event execute continuously when triggered to true?
240  if (event_element->GetAttributeValue("continuous") == string("true")) {
241  newEvent->Continuous = true;
242  }
243 
244  // Process the conditions
245  Element* condition_element = event_element->FindElement("condition");
246  if (condition_element != 0) {
247  try {
248  newCondition = new FGCondition(condition_element, PropertyManager);
249  } catch(string& str) {
250  cout << endl << fgred << str << reset << endl << endl;
251  delete newEvent;
252  return false;
253  }
254  newEvent->Condition = newCondition;
255  } else {
256  cerr << "No condition specified in script event " << newEvent->Name << endl;
257  delete newEvent;
258  return false;
259  }
260 
261  // Is there a delay between the time this event is triggered, and when the event
262  // actions are executed?
263 
264  Element* delay_element = event_element->FindElement("delay");
265  if (delay_element)
266  newEvent->Delay = event_element->FindElementValueAsNumber("delay");
267  else
268  newEvent->Delay = 0.0;
269 
270  // Notify about when this event is triggered?
271  if ((notify_element = event_element->FindElement("notify")) != 0) {
272  if (notify_element->HasAttribute("format")) {
273  if (notify_element->GetAttributeValue("format") == "kml") newEvent->NotifyKML = true;
274  }
275  newEvent->Notify = true;
276  // Check here for new <description> tag that gets echoed
277  string notify_description = notify_element->FindElementValue("description");
278  if (!notify_description.empty()) {
279  newEvent->Description = notify_description;
280  }
281  notify_property_element = notify_element->FindElement("property");
282  while (notify_property_element) {
283  notifyPropertyName = notify_property_element->GetDataLine();
284 
285  newEvent->NotifyPropertyNames.push_back(notifyPropertyName);
286  newEvent->NotifyProperties.push_back(0);
287  string caption_attribute = notify_property_element->GetAttributeValue("caption");
288  if (caption_attribute.empty()) {
289  newEvent->DisplayString.push_back(notifyPropertyName);
290  } else {
291  newEvent->DisplayString.push_back(caption_attribute);
292  }
293 
294  notify_property_element = notify_element->FindNextElement("property");
295  }
296  }
297 
298  // Read set definitions (these define the actions to be taken when the event is triggered).
299  set_element = event_element->FindElement("set");
300  while (set_element) {
301  prop_name = set_element->GetAttributeValue("name");
302  if (PropertyManager->HasNode(prop_name)) {
303  newEvent->SetParam.push_back( PropertyManager->GetNode(prop_name) );
304  } else {
305  newEvent->SetParam.push_back( 0L );
306  }
307  newEvent->SetParamName.push_back( prop_name );
308 
309  //Todo - should probably do some safety checking here to make sure one or the other
310  //of value or function is specified.
311  if (!set_element->GetAttributeValue("value").empty()) {
312  value = set_element->GetAttributeValueAsNumber("value");
313  newEvent->Functions.push_back((FGFunction*)0L);
314  } else if (set_element->FindElement("function")) {
315  value = 0.0;
316  newEvent->Functions.push_back(new FGFunction(PropertyManager, set_element->FindElement("function")));
317  }
318  newEvent->SetValue.push_back(value);
319  newEvent->OriginalValue.push_back(0.0);
320  newEvent->newValue.push_back(0.0);
321  newEvent->ValueSpan.push_back(0.0);
322  string tempCompare = set_element->GetAttributeValue("type");
323  if (to_lower(tempCompare).find("delta") != string::npos) newEvent->Type.push_back(FG_DELTA);
324  else if (to_lower(tempCompare).find("bool") != string::npos) newEvent->Type.push_back(FG_BOOL);
325  else if (to_lower(tempCompare).find("value") != string::npos) newEvent->Type.push_back(FG_VALUE);
326  else newEvent->Type.push_back(FG_VALUE); // DEFAULT
327  tempCompare = set_element->GetAttributeValue("action");
328  if (to_lower(tempCompare).find("ramp") != string::npos) newEvent->Action.push_back(FG_RAMP);
329  else if (to_lower(tempCompare).find("step") != string::npos) newEvent->Action.push_back(FG_STEP);
330  else if (to_lower(tempCompare).find("exp") != string::npos) newEvent->Action.push_back(FG_EXP);
331  else newEvent->Action.push_back(FG_STEP); // DEFAULT
332 
333  if (!set_element->GetAttributeValue("tc").empty())
334  newEvent->TC.push_back(set_element->GetAttributeValueAsNumber("tc"));
335  else
336  newEvent->TC.push_back(1.0); // DEFAULT
337 
338  newEvent->Transiting.push_back(false);
339 
340  set_element = event_element->FindNextElement("set");
341  }
342  Events.push_back(*newEvent);
343  delete newEvent;
344 
345  event_element = run_element->FindNextElement("event");
346  }
347 
348  Debug(4);
349 
350  return true;
351 }
352 
353 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
354 
355 void FGScript::ResetEvents(void)
356 {
357  LocalProperties.ResetToIC();
358  FDMExec->Setsim_time(StartTime);
359 
360  for (unsigned int i=0; i<Events.size(); i++)
361  Events[i].reset();
362 }
363 
364 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
365 
367 {
368  unsigned i, j;
369  unsigned event_ctr = 0;
370 
371  double currentTime = FDMExec->GetSimTime();
372  double newSetValue = 0;
373 
374  if (currentTime > EndTime) return false;
375 
376  // Iterate over all events.
377  for (unsigned int ev_ctr=0; ev_ctr < Events.size(); ev_ctr++) {
378 
379  struct event &thisEvent = Events[ev_ctr];
380 
381  // Determine whether the set of conditional tests for this condition equate
382  // to true and should cause the event to execute. If the conditions evaluate
383  // to true, then the event is triggered. If the event is not persistent,
384  // then this trigger will remain set true. If the event is persistent,
385  // the trigger will reset to false when the condition evaluates to false.
386  if (thisEvent.Condition->Evaluate()) {
387  if (!thisEvent.Triggered) {
388 
389  // The conditions are true, do the setting of the desired Event parameters
390  for (i=0; i<thisEvent.SetValue.size(); i++) {
391  if (thisEvent.SetParam[i] == 0L) { // Late bind property if necessary
392  if (PropertyManager->HasNode(thisEvent.SetParamName[i])) {
393  thisEvent.SetParam[i] = PropertyManager->GetNode(thisEvent.SetParamName[i]);
394  } else {
395  throw("No property, \""+thisEvent.SetParamName[i]+"\" is defined.");
396  }
397  }
398  thisEvent.OriginalValue[i] = thisEvent.SetParam[i]->getDoubleValue();
399  if (thisEvent.Functions[i] != 0) { // Parameter should be set to a function value
400  try {
401  thisEvent.SetValue[i] = thisEvent.Functions[i]->GetValue();
402  } catch (string& msg) {
403  std::cerr << std::endl << "A problem occurred in the execution of the script. " << msg << endl;
404  throw;
405  }
406  }
407  switch (thisEvent.Type[i]) {
408  case FG_VALUE:
409  case FG_BOOL:
410  thisEvent.newValue[i] = thisEvent.SetValue[i];
411  break;
412  case FG_DELTA:
413  thisEvent.newValue[i] = thisEvent.OriginalValue[i] + thisEvent.SetValue[i];
414  break;
415  default:
416  cerr << "Invalid Type specified" << endl;
417  break;
418  }
419  thisEvent.StartTime = currentTime + thisEvent.Delay;
420  thisEvent.ValueSpan[i] = thisEvent.newValue[i] - thisEvent.OriginalValue[i];
421  thisEvent.Transiting[i] = true;
422  }
423  }
424  thisEvent.Triggered = true;
425 
426  } else if (thisEvent.Persistent) { // If the event is persistent, reset the trigger.
427  thisEvent.Triggered = false; // Reset the trigger for persistent events
428  thisEvent.Notified = false; // Also reset the notification flag
429  } else if (thisEvent.Continuous) { // If the event is continuous, reset the trigger.
430  thisEvent.Triggered = false; // Reset the trigger for persistent events
431  thisEvent.Notified = false; // Also reset the notification flag
432  }
433 
434  if ((currentTime >= thisEvent.StartTime) && thisEvent.Triggered) {
435 
436  for (i=0; i<thisEvent.SetValue.size(); i++) {
437  if (thisEvent.Transiting[i]) {
438  thisEvent.TimeSpan = currentTime - thisEvent.StartTime;
439  switch (thisEvent.Action[i]) {
440  case FG_RAMP:
441  if (thisEvent.TimeSpan <= thisEvent.TC[i]) {
442  newSetValue = thisEvent.TimeSpan/thisEvent.TC[i] * thisEvent.ValueSpan[i] + thisEvent.OriginalValue[i];
443  } else {
444  newSetValue = thisEvent.newValue[i];
445  if (thisEvent.Continuous != true) thisEvent.Transiting[i] = false;
446  }
447  break;
448  case FG_STEP:
449  newSetValue = thisEvent.newValue[i];
450 
451  // If this is not a continuous event, reset the transiting flag.
452  // Otherwise, it is known that the event is a continuous event.
453  // Furthermore, if the event is to be determined by a function,
454  // then the function will be continuously calculated.
455  if (thisEvent.Continuous != true)
456  thisEvent.Transiting[i] = false;
457  else if (thisEvent.Functions[i] != 0)
458  newSetValue = thisEvent.Functions[i]->GetValue();
459 
460  break;
461  case FG_EXP:
462  newSetValue = (1 - exp( -thisEvent.TimeSpan/thisEvent.TC[i] )) * thisEvent.ValueSpan[i] + thisEvent.OriginalValue[i];
463  break;
464  default:
465  cerr << "Invalid Action specified" << endl;
466  break;
467  }
468  thisEvent.SetParam[i]->setDoubleValue(newSetValue);
469  }
470  }
471 
472  // Print notification values after setting them
473  if (thisEvent.Notify && !thisEvent.Notified) {
474  if (thisEvent.NotifyKML) {
475  cout << endl << "<Placemark>" << endl;
476  cout << " <name> " << currentTime << " seconds" << " </name>" << endl;
477  cout << " <description>" << endl;
478  cout << " <![CDATA[" << endl;
479  cout << " <b>" << thisEvent.Name << " (Event " << event_ctr << ")" << " executed at time: " << currentTime << "</b><br/>" << endl;
480  } else {
481  cout << endl << underon
482  << highint << thisEvent.Name << normint << underoff
483  << " (Event " << event_ctr << ")"
484  << " executed at time: " << highint << currentTime << normint << endl;
485  }
486  if (!thisEvent.Description.empty()) {
487  cout << " " << thisEvent.Description << endl;
488  }
489  for (j=0; j<thisEvent.NotifyProperties.size();j++) {
490  if (thisEvent.NotifyProperties[j] == 0) {
491  if (PropertyManager->HasNode(thisEvent.NotifyPropertyNames[j])) {
492  thisEvent.NotifyProperties[j] = PropertyManager->GetNode(thisEvent.NotifyPropertyNames[j]);
493  } else {
494  throw("Could not find property named "+thisEvent.NotifyPropertyNames[j]+" in script.");
495  }
496  }
497  cout << " " << thisEvent.DisplayString[j] << " = " << thisEvent.NotifyProperties[j]->getDoubleValue();
498  if (thisEvent.NotifyKML) cout << " <br/>";
499  cout << endl;
500  }
501  if (thisEvent.NotifyKML) {
502  cout << " ]]>" << endl;
503  cout << " </description>" << endl;
504  cout << " <Point>" << endl;
505  cout << " <altitudeMode> absolute </altitudeMode>" << endl;
506  cout << " <extrude> 1 </extrude>" << endl;
507  cout << " <coordinates>" << FDMExec->GetPropagate()->GetLongitudeDeg()
508  << "," << FDMExec->GetPropagate()->GetGeodLatitudeDeg()
509  << "," << FDMExec->GetPropagate()->GetAltitudeASLmeters() << "</coordinates>" << endl;
510  cout << " </Point>" << endl;
511  cout << "</Placemark>" << endl;
512  }
513  cout << endl;
514  thisEvent.Notified = true;
515  }
516 
517  }
518 
519  event_ctr++;
520  }
521  return true;
522 }
523 
524 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
525 // The bitmasked value choices are as follows:
526 // unset: In this case (the default) JSBSim would only print
527 // out the normally expected messages, essentially echoing
528 // the config files as they are read. If the environment
529 // variable is not set, debug_lvl is set to 1 internally
530 // 0: This requests JSBSim not to output any messages
531 // whatsoever.
532 // 1: This value explicity requests the normal JSBSim
533 // startup messages
534 // 2: This value asks for a message to be printed out when
535 // a class is instantiated
536 // 4: When this value is set, a message is displayed when a
537 // FGModel object executes its Run() method
538 // 8: When this value is set, various runtime state variables
539 // are printed out periodically
540 // 16: When set various parameters are sanity checked and
541 // a message is printed out when they go out of bounds
542 
543 void FGScript::Debug(int from)
544 {
545  if (debug_lvl <= 0) return;
546 
547  if (debug_lvl & 1) { // Standard console startup message output
548  if (from == 0) { // Constructor
549  } else if (from == 3) {
550  } else if (from == 4) { // print out script data
551  cout << endl;
552  cout << "Script: \"" << ScriptName << "\"" << endl;
553  cout << " begins at " << StartTime << " seconds and runs to " << EndTime
554  << " seconds with dt = " << setprecision(6) << FDMExec->GetDeltaT() << " (" <<
555  ceil(1.0/FDMExec->GetDeltaT()) << " Hz)" << endl;
556  cout << endl;
557 
559  for (it = LocalProperties.begin(); it != LocalProperties.end(); ++it) {
560  FGPropertyNode* node = *it;
561  cout << "Local property: " << node->GetName()
562  << " = " << node->getDoubleValue()
563  << endl;
564  }
565 
566  if (LocalProperties.empty()) cout << endl;
567 
568  for (unsigned i=0; i<Events.size(); i++) {
569  cout << "Event " << i;
570  if (!Events[i].Name.empty()) cout << " (" << Events[i].Name << ")";
571  cout << ":" << endl;
572 
573  if (Events[i].Persistent)
574  cout << " " << "Whenever triggered, executes once";
575  else if (Events[i].Continuous)
576  cout << " " << "While true, always executes";
577  else
578  cout << " " << "When first triggered, executes once";
579 
580  Events[i].Condition->PrintCondition();
581 
582  cout << endl << " Actions taken";
583  if (Events[i].Delay > 0.0)
584  cout << " (after a delay of " << Events[i].Delay << " secs)";
585  cout << ":" << endl << " {";
586  for (unsigned j=0; j<Events[i].SetValue.size(); j++) {
587  if (Events[i].SetValue[j] == 0.0 && Events[i].Functions[j] != 0L) {
588  if (Events[i].SetParam[j] == 0) {
589  if (Events[i].SetParamName[j].size() == 0) {
590  cerr << fgred << highint << endl
591  << " An attempt has been made to access a non-existent property" << endl
592  << " in this event. Please check the property names used, spelling, etc."
593  << reset << endl;
594  exit(-1);
595  } else {
596  cout << endl << " set " << Events[i].SetParamName[j]
597  << " to function value (Late Bound)";
598  }
599  } else {
600  cout << endl << " set " << Events[i].SetParam[j]->GetRelativeName("/fdm/jsbsim/")
601  << " to function value";
602  }
603  } else {
604  if (Events[i].SetParam[j] == 0) {
605  if (Events[i].SetParamName[j].size() == 0) {
606  cerr << fgred << highint << endl
607  << " An attempt has been made to access a non-existent property" << endl
608  << " in this event. Please check the property names used, spelling, etc."
609  << reset << endl;
610  exit(-1);
611  } else {
612  cout << endl << " set " << Events[i].SetParamName[j]
613  << " to function value (Late Bound)";
614  }
615  } else {
616  cout << endl << " set " << Events[i].SetParam[j]->GetRelativeName("/fdm/jsbsim/")
617  << " to " << Events[i].SetValue[j];
618  }
619  }
620 
621  switch (Events[i].Type[j]) {
622  case FG_VALUE:
623  case FG_BOOL:
624  cout << " (constant";
625  break;
626  case FG_DELTA:
627  cout << " (delta";
628  break;
629  default:
630  cout << " (unspecified type";
631  }
632 
633  switch (Events[i].Action[j]) {
634  case FG_RAMP:
635  cout << " via ramp";
636  break;
637  case FG_STEP:
638  cout << " via step)";
639  break;
640  case FG_EXP:
641  cout << " via exponential approach";
642  break;
643  default:
644  cout << " via unspecified action)";
645  }
646 
647  if (Events[i].Action[j] == FG_RAMP || Events[i].Action[j] == FG_EXP)
648  cout << " with time constant " << Events[i].TC[j] << ")";
649  }
650  cout << endl << " }" << endl;
651 
652  // Print notifications
653  if (Events[i].Notify) {
654  if (Events[i].NotifyProperties.size() > 0) {
655  if (Events[i].NotifyKML) {
656  cout << " Notifications (KML Format):" << endl << " {" << endl;
657  } else {
658  cout << " Notifications:" << endl << " {" << endl;
659  }
660  for (unsigned j=0; j<Events[i].NotifyPropertyNames.size();j++) {
661  cout << " "
662  << Events[i].NotifyPropertyNames[j]
663  << endl;
664  }
665  cout << " }" << endl;
666  }
667  }
668  cout << endl;
669  }
670  }
671  }
672  if (debug_lvl & 2 ) { // Instantiation/Destruction notification
673  if (from == 0) cout << "Instantiated: FGScript" << endl;
674  if (from == 1) cout << "Destroyed: FGScript" << endl;
675  }
676  if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
677  }
678  if (debug_lvl & 8 ) { // Runtime state variables
679  }
680  if (debug_lvl & 16) { // Sanity checking
681  }
682  if (debug_lvl & 64) {
683  if (from == 0) { // Constructor
684  cout << IdSrc << endl;
685  cout << IdHdr << endl;
686  }
687  }
688 }
689 }
FGInitialCondition * GetIC(void)
Returns a pointer to the FGInitialCondition object.
Definition: FGFDMExec.h:385
std::string GetAttributeValue(const std::string &key)
Retrieves an attribute.
FGOutput * GetOutput(void)
Returns the FGOutput pointer.
Definition: FGFDMExec.h:375
bool HasAttribute(const std::string &key)
Determines if an element has the supplied attribute.
Definition: FGXMLElement.h:162
std::string GetName(void) const
Get the name of a node.
Class wrapper for property handling.
static char reset[5]
resets text properties
Definition: FGJSBBase.h:131
double GetAltitudeASLmeters(void) const
Returns the current altitude above sea level.
Definition: FGPropagate.h:344
FGInput * GetInput(void)
Returns the FGInput pointer.
Definition: FGFDMExec.h:373
STL namespace.
bool LoadScript(const SGPath &script, double default_dT, const SGPath &initfile)
Loads a script to drive JSBSim (usually in standalone mode).
Definition: FGScript.cpp:99
Element * FindElement(const std::string &el="")
Searches for a specified element.
double FindElementValueAsNumber(const std::string &el="")
Searches for the named element and returns the data belonging to it as a number.
static char normint[6]
normal intensity text
Definition: FGJSBBase.h:129
FGPropertyManager * GetPropertyManager(void)
Returns a pointer to the property manager object.
Definition: FGFDMExec.cpp:1099
static char fgred[6]
red text
Definition: FGJSBBase.h:141
double Setsim_time(double cur_time)
Sets the current sim time.
Definition: FGFDMExec.h:551
void Setdt(double delta_t)
Sets the integration time step for the simulation executive.
Definition: FGFDMExec.h:559
bool RunScript(void)
This function is called each pass through the executive Run() method IF scripting is enabled...
Definition: FGScript.cpp:366
double GetAttributeValueAsNumber(const std::string &key)
Retrieves an attribute value as a double precision real number.
const std::string & GetName(void) const
Retrieves the element name.
Definition: FGXMLElement.h:186
std::string FindElementValue(const std::string &el="")
Searches for the named element and returns the string data belonging to it.
~FGScript()
Default destructor.
Definition: FGScript.cpp:83
Represents a mathematical function.
Definition: FGFunction.h:699
std::string GetDataLine(unsigned int i=0)
Gets a line of data belonging to an element.
bool Load(const SGPath &rstname, bool useStoredPath=true)
Loads the initial conditions.
static char underoff[6]
underline off
Definition: FGJSBBase.h:135
bool Load(Element *el)
Load the output directives and adds a new output instance to the Output Manager list.
Definition: FGOutput.cpp:249
bool Load(Element *el)
Load the input directives and adds a new input instance to the Input Manager list.
Definition: FGInput.cpp:81
Initializes the simulation run.
double GetSimTime(void) const
Returns the cumulative simulation time in seconds.
Definition: FGFDMExec.h:533
Element * FindNextElement(const std::string &el="")
Searches for the next element as specified.
static char highint[5]
highlights text
Definition: FGJSBBase.h:125
double GetDeltaT(void) const
Returns the simulation delta T.
Definition: FGFDMExec.h:536
Encapsulates a condition, which is used in parts of JSBSim including switches.
Definition: FGCondition.h:70
Encapsulates the JSBSim simulation executive.
Definition: FGFDMExec.h:189
bool LoadModel(const SGPath &AircraftPath, const SGPath &EnginePath, const SGPath &SystemsPath, const std::string &model, bool addModelToPath=true)
Loads an aircraft model.
Definition: FGFDMExec.cpp:666
static char underon[5]
underlines text
Definition: FGJSBBase.h:133
FGPropagate * GetPropagate(void)
Returns the FGPropagate pointer.
Definition: FGFDMExec.h:369