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