JSBSim Flight Dynamics Model 1.3.0 (09 Apr 2026)
An Open Source Flight Dynamics and Control Software Library in C++
Loading...
Searching...
No Matches
FGScript Class Reference

Detailed Description

Encapsulates the JSBSim scripting capability.

Scripting support provided via FGScript.

There is support for scripting provided in the FGScript class. Commands are specified using the Scripting Directives for JSBSim. The script file is in XML format. A test condition (or conditions) can be set up in an event in a script and when the condition evaluates to true, the specified action[s] is/are taken. An event can be persistent, meaning that at every time the test condition first evaluates to true (toggling from false to true) then the specified set actions take place. An event can also be defined to execute or evaluate continuously while the condition is true. When the set of tests evaluates to true for a given condition, an item may be set to another value. This value may be a value, or a delta value, and the change from the current value to the new value can be either via a step action, a ramp, or an exponential approach. The speed of a ramp or exponential approach is specified via the time constant. Here is an example illustrating the format of the script file:

<?xml version="1.0"?>
<runscript name="C172-01A takeoff run">
<!--
This run is for testing the C172 altitude hold autopilot
-->
<use aircraft="c172x"/>
<use initialize="reset00"/>
<run start="0.0" end="3000" dt="0.0083333">
<event name="engine start">
<notify/>
<condition>
sim-time-sec >= 0.25
</condition>
<set name="fcs/throttle-cmd-norm" value="1.0" action="FG_RAMP" tc ="0.5"/>
<set name="fcs/mixture-cmd-norm" value="0.87" action="FG_RAMP" tc ="0.5"/>
<set name="propulsion/magneto_cmd" value="3"/>
<set name="propulsion/starter_cmd" value="1"/>
</event>
<event name="set heading hold">
<!-- Set Heading when reach 5 ft -->
<notify/>
<condition>
position/h-agl-ft >= 5
</condition>
<set name="ap/heading_setpoint" value="200"/>
<set name="ap/attitude_hold" value="0"/>
<set name="ap/heading_hold" value="1"/>
</event>
<event name="set autopilot">
<!-- Set Autopilot for 20 ft -->
<notify/>
<condition>
aero/qbar-psf >= 4
</condition>
<set name="ap/altitude_setpoint" value="100.0" action="FG_EXP" tc ="2.0"/>
<set name="ap/altitude_hold" value="1"/>
<set name="fcs/flap-cmd-norm" value=".33"/>
</event>
<event name="set autopilot 2" persistent="true">
<!-- Set Autopilot for 6000 ft -->
<notify/>
<condition>
aero/qbar-psf > 5
</condition>
<set name="ap/altitude_setpoint" value="6000.0"/>
</event>
<event name="Time Notify">
<notify/>
<condition> sim-time-sec >= 500 </condition>
</event>
<event name="Time Notify">
<notify/>
<condition> sim-time-sec >= 1000 </condition>
</event>
</run>
</runscript>

The first line must always be present - it identifies the file as an XML format file. The second line identifies this file as a script file, and gives a descriptive name to the script file. Comments are next, delineated by the <!– and –> symbols. The aircraft and initialization files to be used are specified in the "use" lines. Next, comes the "run" section, where the conditions are described in "event" clauses.

Author
Jon S. Berndt

Definition at line 167 of file FGScript.h.

#include <FGScript.h>

+ Inheritance diagram for FGScript:
+ Collaboration diagram for FGScript:

Public Member Functions

 FGScript (FGFDMExec *exec)
 Default constructor.
 
 ~FGScript ()
 Default destructor.
 
bool LoadScript (const SGPath &script, double default_dT, const SGPath &initfile)
 Loads a script to drive JSBSim (usually in standalone mode).
 
void ResetEvents (void)
 
bool RunScript (void)
 This function is called each pass through the executive Run() method IF scripting is enabled.
 
- Public Member Functions inherited from FGJSBBase
 FGJSBBase ()
 Constructor for FGJSBBase.
 
virtual ~FGJSBBase ()
 Destructor for FGJSBBase.
 
void disableHighLighting (void)
 Disables highlighting in the console output.
 

Additional Inherited Members

- Public Types inherited from FGJSBBase
enum  { eL = 1 , eM , eN }
 Moments L, M, N. More...
 
enum  { eP = 1 , eQ , eR }
 Rates P, Q, R. More...
 
enum  { eU = 1 , eV , eW }
 Velocities U, V, W. More...
 
enum  { eX = 1 , eY , eZ }
 Positions X, Y, Z. More...
 
enum  { ePhi = 1 , eTht , ePsi }
 Euler angles Phi, Theta, Psi. More...
 
enum  { eDrag = 1 , eSide , eLift }
 Stability axis forces, Drag, Side force, Lift. More...
 
enum  { eRoll = 1 , ePitch , eYaw }
 Local frame orientation Roll, Pitch, Yaw. More...
 
enum  { eNorth = 1 , eEast , eDown }
 Local frame position North, East, Down. More...
 
enum  { eLat = 1 , eLong , eRad }
 Locations Radius, Latitude, Longitude. More...
 
enum  {
  inNone = 0 , inDegrees , inRadians , inMeters ,
  inFeet
}
 Conversion specifiers. More...
 
- Static Public Member Functions inherited from FGJSBBase
static const std::string & GetVersion (void)
 Returns the version number of JSBSim.
 
static constexpr double KelvinToFahrenheit (double kelvin)
 Converts from degrees Kelvin to degrees Fahrenheit.
 
static constexpr double CelsiusToRankine (double celsius)
 Converts from degrees Celsius to degrees Rankine.
 
static constexpr double RankineToCelsius (double rankine)
 Converts from degrees Rankine to degrees Celsius.
 
static constexpr double KelvinToRankine (double kelvin)
 Converts from degrees Kelvin to degrees Rankine.
 
static constexpr double RankineToKelvin (double rankine)
 Converts from degrees Rankine to degrees Kelvin.
 
static constexpr double FahrenheitToCelsius (double fahrenheit)
 Converts from degrees Fahrenheit to degrees Celsius.
 
static constexpr double CelsiusToFahrenheit (double celsius)
 Converts from degrees Celsius to degrees Fahrenheit.
 
static constexpr double CelsiusToKelvin (double celsius)
 Converts from degrees Celsius to degrees Kelvin.
 
static constexpr double KelvinToCelsius (double kelvin)
 Converts from degrees Kelvin to degrees Celsius.
 
static constexpr double FeetToMeters (double measure)
 Converts from feet to meters.
 
static bool EqualToRoundoff (double a, double b)
 Finite precision comparison.
 
static bool EqualToRoundoff (float a, float b)
 Finite precision comparison.
 
static bool EqualToRoundoff (float a, double b)
 Finite precision comparison.
 
static bool EqualToRoundoff (double a, float b)
 Finite precision comparison.
 
static constexpr double Constrain (double min, double value, double max)
 Constrain a value between a minimum and a maximum value.
 
static constexpr double sign (double num)
 
- Static Public Attributes inherited from FGJSBBase
static char highint [5] = {27, '[', '1', 'm', '\0' }
 highlights text
 
static char halfint [5] = {27, '[', '2', 'm', '\0' }
 low intensity text
 
static char normint [6] = {27, '[', '2', '2', 'm', '\0' }
 normal intensity text
 
static char reset [5] = {27, '[', '0', 'm', '\0' }
 resets text properties
 
static char underon [5] = {27, '[', '4', 'm', '\0' }
 underlines text
 
static char underoff [6] = {27, '[', '2', '4', 'm', '\0' }
 underline off
 
static char fgblue [6] = {27, '[', '3', '4', 'm', '\0' }
 blue text
 
static char fgcyan [6] = {27, '[', '3', '6', 'm', '\0' }
 cyan text
 
static char fgred [6] = {27, '[', '3', '1', 'm', '\0' }
 red text
 
static char fggreen [6] = {27, '[', '3', '2', 'm', '\0' }
 green text
 
static char fgdef [6] = {27, '[', '3', '9', 'm', '\0' }
 default text
 
static short debug_lvl = 1
 
- Static Protected Member Functions inherited from FGJSBBase
static std::string CreateIndexedPropertyName (const std::string &Property, int index)
 
- Static Protected Attributes inherited from FGJSBBase
static constexpr double radtodeg = 180. / M_PI
 
static constexpr double degtorad = M_PI / 180.
 
static constexpr double hptoftlbssec = 550.0
 
static constexpr double psftoinhg = 0.014138
 
static constexpr double psftopa = 47.88
 
static constexpr double fttom = 0.3048
 
static constexpr double ktstofps = 1852./(3600*fttom)
 
static constexpr double fpstokts = 1.0 / ktstofps
 
static constexpr double inchtoft = 1.0/12.0
 
static constexpr double m3toft3 = 1.0/(fttom*fttom*fttom)
 
static constexpr double in3tom3 = inchtoft*inchtoft*inchtoft/m3toft3
 
static constexpr double inhgtopa = 3386.38
 
static constexpr double slugtolb = 32.174049
 Note that definition of lbtoslug by the inverse of slugtolb and not to a different constant you can also get from some tables will make lbtoslug*slugtolb == 1 up to the magnitude of roundoff.
 
static constexpr double lbtoslug = 1.0/slugtolb
 
static constexpr double kgtolb = 2.20462
 
static constexpr double kgtoslug = 0.06852168
 
static const std::string needed_cfg_version = "2.0"
 
static const std::string JSBSim_version = JSBSIM_VERSION " " __DATE__ " " __TIME__
 

Constructor & Destructor Documentation

◆ FGScript()

FGScript ( FGFDMExec exec)

Default constructor.

Definition at line 65 of file FGScript.cpp.

65 : FDMExec(fgex)
66{
67 PropertyManager=FDMExec->GetPropertyManager();
68
69 Debug(0);
70}
std::shared_ptr< FGPropertyManager > GetPropertyManager(void) const
Returns a pointer to the property manager object.
Definition FGFDMExec.h:422
+ Here is the call graph for this function:

◆ ~FGScript()

~FGScript ( )

Default destructor.

Definition at line 74 of file FGScript.cpp.

75{
76 unsigned int i, j;
77
78 for (i=0; i<Events.size(); i++) {
79 delete Events[i].Condition;
80 for (j=0; j<Events[i].Functions.size(); j++)
81 delete Events[i].Functions[j];
82 for (j=0; j<Events[i].NotifyProperties.size(); j++)
83 delete Events[i].NotifyProperties[j];
84 }
85 Events.clear();
86
87 Debug(1);
88}

Member Function Documentation

◆ LoadScript()

bool LoadScript ( const SGPath &  script,
double  default_dT,
const SGPath &  initfile 
)

Loads a script to drive JSBSim (usually in standalone mode).

The language is the Script Directives for JSBSim. If a simulation step size has been supplied on the command line, it will override the script specified simulation step size.

Parameters
scriptthe filename (including path name, if any) for the script.
default_dTthe default simulation step size if no value is specified in the script
initfileAn optional initialization file name passed in, empty by default. If a file name is passed in, it will override the one present in the script.
Returns
true if successful

Definition at line 92 of file FGScript.cpp.

94{
95 SGPath initialize;
96 string aircraft="", prop_name="";
97 string notifyPropertyName="";
98 Element *element=0, *run_element=0, *event_element=0;
99 Element *set_element=0;
100 Element *notify_element = 0L, *notify_property_element = 0L;
101 double dt = 0.0, value = 0.0;
102 FGCondition *newCondition;
103
104 FGXMLFileRead XMLFileRead;
105 Element* document = XMLFileRead.LoadXMLDocument(script);
106
107 if (!document) {
108 FGLogging log(LogLevel::ERROR);
109 log << "File: " << script << " could not be loaded.\n";
110 return false;
111 }
112
113 if (document->GetName() != string("runscript")) {
114 FGXMLLogging log(document, LogLevel::ERROR);
115 log << "File: " << script << " is not a script file\n";
116 return false;
117 }
118
119 ScriptName = document->GetAttributeValue("name");
120
121 // First, find "run" element and set delta T
122
123 run_element = document->FindElement("run");
124
125 if (!run_element) {
126 FGXMLLogging log(document, LogLevel::ERROR);
127 log << "No \"run\" element found in script.\n";
128 return false;
129 }
130
131 // Set sim timing
132
133 if (run_element->HasAttribute("start"))
134 StartTime = run_element->GetAttributeValueAsNumber("start");
135 else
136 StartTime = 0.0;
137 FDMExec->Setsim_time(StartTime);
138 if (run_element->HasAttribute("end")) {
139 EndTime = run_element->GetAttributeValueAsNumber("end");
140 } else {
141 FGXMLLogging log(run_element, LogLevel::ERROR);
142 log << "An end time (duration) for the script must be specified in the script <run> element.\n";
143 return false;
144 }
145
146 if (default_dT == 0.0)
147 dt = run_element->GetAttributeValueAsNumber("dt");
148 else {
149 dt = default_dT;
150 FGLogging log(LogLevel::INFO);
151 log << "\nOverriding simulation step size from the command line. New step size is: "
152 << default_dT << " seconds (" << 1/default_dT << " Hz)\n\n";
153 }
154
155 FDMExec->Setdt(dt);
156
157 // Make sure that the desired time is reached and executed.
158 EndTime += 0.99*FDMExec->GetDeltaT();
159
160 // read aircraft and initialization files
161
162 element = document->FindElement("use");
163 if (element) {
164 aircraft = element->GetAttributeValue("aircraft");
165 if (!aircraft.empty()) {
166 if (!FDMExec->LoadModel(aircraft))
167 return false;
168 } else {
169 FGXMLLogging log(element, LogLevel::ERROR);
170 log << "Aircraft must be specified in use element.\n";
171 return false;
172 }
173
174 initialize = SGPath::fromLocal8Bit(element->GetAttributeValue("initialize").c_str());
175 if (initfile.isNull()) {
176 if (initialize.isNull()) {
177 FGXMLLogging log(element, LogLevel::ERROR);
178 log << "Initialization file must be specified in use element.\n";
179 return false;
180 }
181 } else {
182 FGLogging log(LogLevel::INFO);
183 log << "\nThe initialization file specified in the script file ("
184 << initialize << ") has been overridden with a specified file ("
185 << initfile << ").\n";
186 initialize = initfile;
187 }
188
189 } else {
190 FGXMLLogging log(document, LogLevel::ERROR);
191 log << "No \"use\" directives in the script file.\n";
192 return false;
193 }
194
195 auto IC = FDMExec->GetIC();
196 if ( ! IC->Load( initialize )) {
197 FGLogging log(LogLevel::ERROR);
198 log << "Initialization unsuccessful\n";
199 return false;
200 }
201
202 // Now, read input spec if given.
203 element = document->FindElement("input");
204 while (element) {
205 if (!FDMExec->GetInput()->Load(element))
206 return false;
207
208 element = document->FindNextElement("input");
209 }
210
211 // Now, read output spec if given.
212 element = document->FindElement("output");
213 SGPath scriptDir = SGPath(script.dir());
214 if (scriptDir.isNull())
215 scriptDir = SGPath(".");
216
217 while (element) {
218 if (!FDMExec->GetOutput()->Load(element, scriptDir))
219 return false;
220
221 element = document->FindNextElement("output");
222 }
223
224 // Read local property/value declarations
225 int saved_debug_lvl = debug_lvl;
226 debug_lvl = 0; // Disable messages
227 LocalProperties.Load(run_element, PropertyManager.get(), true);
228 debug_lvl = saved_debug_lvl;
229
230 // Read "events" from script
231
232 event_element = run_element->FindElement("event");
233 while (event_element) { // event processing
234
235 // Create the event structure
236 struct event *newEvent = new struct event();
237
238 // Retrieve the event name if given
239 newEvent->Name = event_element->GetAttributeValue("name");
240
241 // Is this event persistent? That is, does it execute every time the
242 // condition triggers to true, or does it execute as a one-shot event, only?
243 if (event_element->GetAttributeValue("persistent") == string("true")) {
244 newEvent->Persistent = true;
245 }
246
247 // Does this event execute continuously when triggered to true?
248 if (event_element->GetAttributeValue("continuous") == string("true")) {
249 newEvent->Continuous = true;
250 }
251
252 // Process the conditions
253 Element* condition_element = event_element->FindElement("condition");
254 if (condition_element) {
255 try {
256 newCondition = new FGCondition(condition_element, PropertyManager);
257 } catch(BaseException& e) {
258 FGXMLLogging log(condition_element, LogLevel::ERROR);
259 log << LogFormat::RED << e.what() << LogFormat::RESET << "\n\n";
260 delete newEvent;
261 return false;
262 }
263 newEvent->Condition = newCondition;
264 } else {
265 FGXMLLogging log(event_element, LogLevel::ERROR);
266 log << "No condition specified in script event " << newEvent->Name << "\n";
267 delete newEvent;
268 return false;
269 }
270
271 // Is there a delay between the time this event is triggered, and when the
272 // event actions are executed?
273
274 Element* delay_element = event_element->FindElement("delay");
275 if (delay_element)
276 newEvent->Delay = event_element->FindElementValueAsNumber("delay");
277 else
278 newEvent->Delay = 0.0;
279
280 // Notify about when this event is triggered?
281 if ((notify_element = event_element->FindElement("notify")) != 0) {
282 if (notify_element->HasAttribute("format")) {
283 if (notify_element->GetAttributeValue("format") == "kml") newEvent->NotifyKML = true;
284 }
285 newEvent->Notify = true;
286 // Check here for new <description> tag that gets echoed
287 string notify_description = notify_element->FindElementValue("description");
288 if (!notify_description.empty()) {
289 newEvent->Description = notify_description;
290 }
291 notify_property_element = notify_element->FindElement("property");
292 while (notify_property_element) {
293 notifyPropertyName = notify_property_element->GetDataLine();
294
295 if (notify_property_element->HasAttribute("apply")) {
296 string function_str = notify_property_element->GetAttributeValue("apply");
297 auto f = FDMExec->GetTemplateFunc(function_str);
298 if (f)
299 newEvent->NotifyProperties.push_back(new FGFunctionValue(notifyPropertyName, PropertyManager, f,
300 notify_property_element));
301 else {
302 FGXMLLogging log(notify_property_element, LogLevel::WARN);
303 log << LogFormat::RED << LogFormat::BOLD << " No function by the name "
304 << function_str << " has been defined. This property will "
305 << "not be logged. You should check your configuration file.\n"
306 << LogFormat::RESET;
307 }
308 }
309 else
310 newEvent->NotifyProperties.push_back(new FGPropertyValue(notifyPropertyName, PropertyManager,
311 notify_property_element));
312
313 string caption_attribute = notify_property_element->GetAttributeValue("caption");
314 if (caption_attribute.empty()) {
315 newEvent->DisplayString.push_back(notifyPropertyName);
316 } else {
317 newEvent->DisplayString.push_back(caption_attribute);
318 }
319
320 notify_property_element = notify_element->FindNextElement("property");
321 }
322 }
323
324 // Read set definitions (these define the actions to be taken when the event
325 // is triggered).
326 set_element = event_element->FindElement("set");
327 while (set_element) {
328 prop_name = set_element->GetAttributeValue("name");
329 if (PropertyManager->HasNode(prop_name)) {
330 newEvent->SetParam.push_back( PropertyManager->GetNode(prop_name) );
331 } else {
332 newEvent->SetParam.push_back( 0L );
333 }
334 newEvent->SetParamName.push_back( prop_name );
335
336 // Todo - should probably do some safety checking here to make sure one or
337 // the other of value or function is specified.
338 if (!set_element->GetAttributeValue("value").empty()) {
339 value = set_element->GetAttributeValueAsNumber("value");
340 newEvent->Functions.push_back(nullptr);
341 } else if (set_element->FindElement("function")) {
342 value = 0.0;
343 newEvent->Functions.push_back(new FGFunction(FDMExec, set_element->FindElement("function")));
344 }
345 newEvent->SetValue.push_back(value);
346 newEvent->OriginalValue.push_back(0.0);
347 newEvent->newValue.push_back(0.0);
348 newEvent->ValueSpan.push_back(0.0);
349 string tempCompare = set_element->GetAttributeValue("type");
350 if (to_lower(tempCompare).find("delta") != string::npos) newEvent->Type.push_back(FG_DELTA);
351 else if (to_lower(tempCompare).find("bool") != string::npos) newEvent->Type.push_back(FG_BOOL);
352 else if (to_lower(tempCompare).find("value") != string::npos) newEvent->Type.push_back(FG_VALUE);
353 else newEvent->Type.push_back(FG_VALUE); // DEFAULT
354 tempCompare = set_element->GetAttributeValue("action");
355 if (to_lower(tempCompare).find("ramp") != string::npos) newEvent->Action.push_back(FG_RAMP);
356 else if (to_lower(tempCompare).find("step") != string::npos) newEvent->Action.push_back(FG_STEP);
357 else if (to_lower(tempCompare).find("exp") != string::npos) newEvent->Action.push_back(FG_EXP);
358 else newEvent->Action.push_back(FG_STEP); // DEFAULT
359
360 if (!set_element->GetAttributeValue("tc").empty())
361 newEvent->TC.push_back(set_element->GetAttributeValueAsNumber("tc"));
362 else
363 newEvent->TC.push_back(1.0); // DEFAULT
364
365 newEvent->Transiting.push_back(false);
366
367 set_element = event_element->FindNextElement("set");
368 }
369 Events.push_back(*newEvent);
370 delete newEvent;
371
372 event_element = run_element->FindNextElement("event");
373 }
374
375 Debug(4);
376
377 return true;
378}
std::shared_ptr< FGInitialCondition > GetIC(void) const
Returns a pointer to the FGInitialCondition object.
Definition FGFDMExec.h:390
std::shared_ptr< FGOutput > GetOutput(void) const
Returns the FGOutput pointer.
double GetDeltaT(void) const
Returns the simulation delta T.
Definition FGFDMExec.h:553
double Setsim_time(double cur_time)
Sets the current sim time.
bool LoadModel(const SGPath &AircraftPath, const SGPath &EnginePath, const SGPath &SystemsPath, const std::string &model, bool addModelToPath=true)
Loads an aircraft model.
void Setdt(double delta_t)
Sets the integration time step for the simulation executive.
Definition FGFDMExec.h:572
std::shared_ptr< FGInput > GetInput(void) const
Returns the FGInput pointer.
+ Here is the call graph for this function:

◆ ResetEvents()

void ResetEvents ( void  )

Definition at line 382 of file FGScript.cpp.

383{
384 LocalProperties.ResetToIC();
385 FDMExec->Setsim_time(StartTime);
386
387 for (unsigned int i=0; i<Events.size(); i++)
388 Events[i].reset();
389}
static char reset[5]
resets text properties
Definition FGJSBBase.h:157

◆ RunScript()

bool RunScript ( void  )

This function is called each pass through the executive Run() method IF scripting is enabled.

Returns
false if script should exit (i.e. if time limits are violated

Definition at line 393 of file FGScript.cpp.

394{
395 unsigned i, j;
396 unsigned event_ctr = 0;
397
398 double currentTime = FDMExec->GetSimTime();
399 double newSetValue = 0;
400
401 if (currentTime > EndTime) return false;
402
403 // Iterate over all events.
404 for (unsigned int ev_ctr=0; ev_ctr < Events.size(); ev_ctr++) {
405
406 struct event &thisEvent = Events[ev_ctr];
407
408 // Determine whether the set of conditional tests for this condition equate
409 // to true and should cause the event to execute. If the conditions evaluate
410 // to true, then the event is triggered. If the event is not persistent,
411 // then this trigger will remain set true. If the event is persistent, the
412 // trigger will reset to false when the condition evaluates to false.
413 if (thisEvent.Condition->Evaluate()) {
414 if (!thisEvent.Triggered) {
415
416 // The conditions are true, do the setting of the desired Event
417 // parameters
418 for (i=0; i<thisEvent.SetValue.size(); i++) {
419 if (thisEvent.SetParam[i] == 0L) { // Late bind property if necessary
420 if (PropertyManager->HasNode(thisEvent.SetParamName[i])) {
421 thisEvent.SetParam[i] = PropertyManager->GetNode(thisEvent.SetParamName[i]);
422 } else {
423 LogException err;
424 err << "No property, \"" << thisEvent.SetParamName[i] << "\" is defined.\n";
425 throw err;
426 }
427 }
428 thisEvent.OriginalValue[i] = thisEvent.SetParam[i]->getDoubleValue();
429 if (thisEvent.Functions[i] != 0) { // Parameter should be set to a function value
430 try {
431 thisEvent.SetValue[i] = thisEvent.Functions[i]->GetValue();
432 } catch (BaseException& e) {
433 LogException err;
434 err << "\nA problem occurred in the execution of the script. "
435 << e.what() << "\n";
436 throw err;
437 }
438 }
439 switch (thisEvent.Type[i]) {
440 case FG_VALUE:
441 case FG_BOOL:
442 thisEvent.newValue[i] = thisEvent.SetValue[i];
443 break;
444 case FG_DELTA:
445 thisEvent.newValue[i] = thisEvent.OriginalValue[i] + thisEvent.SetValue[i];
446 break;
447 default:
448 FGLogging log(LogLevel::WARN);
449 log << "Invalid Type specified\n";
450 break;
451 }
452 thisEvent.StartTime = currentTime + thisEvent.Delay;
453 thisEvent.ValueSpan[i] = thisEvent.newValue[i] - thisEvent.OriginalValue[i];
454 thisEvent.Transiting[i] = true;
455 }
456 }
457 thisEvent.Triggered = true;
458
459 } else if (thisEvent.Persistent) { // If the event is persistent, reset the trigger.
460 thisEvent.Triggered = false; // Reset the trigger for persistent events
461 thisEvent.Notified = false; // Also reset the notification flag
462 } else if (thisEvent.Continuous) { // If the event is continuous, reset the trigger.
463 thisEvent.Triggered = false; // Reset the trigger for persistent events
464 thisEvent.Notified = false; // Also reset the notification flag
465 }
466
467 if ((currentTime >= thisEvent.StartTime) && thisEvent.Triggered) {
468
469 for (i=0; i<thisEvent.SetValue.size(); i++) {
470 if (thisEvent.Transiting[i]) {
471 thisEvent.TimeSpan = currentTime - thisEvent.StartTime;
472 switch (thisEvent.Action[i]) {
473 case FG_RAMP:
474 if (thisEvent.TimeSpan <= thisEvent.TC[i]) {
475 newSetValue = thisEvent.TimeSpan/thisEvent.TC[i] * thisEvent.ValueSpan[i] + thisEvent.OriginalValue[i];
476 } else {
477 newSetValue = thisEvent.newValue[i];
478 if (thisEvent.Continuous != true) thisEvent.Transiting[i] = false;
479 }
480 break;
481 case FG_STEP:
482 newSetValue = thisEvent.newValue[i];
483
484 // If this is not a continuous event, reset the transiting flag.
485 // Otherwise, it is known that the event is a continuous event.
486 // Furthermore, if the event is to be determined by a function,
487 // then the function will be continuously calculated.
488 if (thisEvent.Continuous != true)
489 thisEvent.Transiting[i] = false;
490 else if (thisEvent.Functions[i] != 0)
491 newSetValue = thisEvent.Functions[i]->GetValue();
492
493 break;
494 case FG_EXP:
495 newSetValue = (1 - exp( -thisEvent.TimeSpan/thisEvent.TC[i] )) * thisEvent.ValueSpan[i] + thisEvent.OriginalValue[i];
496 break;
497 default:
498 FGLogging log(LogLevel::WARN);
499 log << "Invalid Action specified\n";
500 break;
501 }
502 thisEvent.SetParam[i]->setDoubleValue(newSetValue);
503 }
504 }
505
506 // Print notification values after setting them
507 if (thisEvent.Notify && !thisEvent.Notified) {
508 LogLevel level = thisEvent.NotifyKML ? LogLevel::STDOUT : LogLevel::INFO;
509 FGLogging out(level);
510 if (thisEvent.NotifyKML) {
511 out << "\n<Placemark>\n";
512 out << " <name> " << currentTime << " seconds" << " </name>\n";
513 out << " <description>\n";
514 out << " <![CDATA[\n";
515 out << " <b>" << thisEvent.Name << " (Event " << event_ctr << ")"
516 << " executed at time: " << currentTime << "</b><br/>\n";
517 } else {
518 out << "\n" << LogFormat::UNDERLINE_ON << LogFormat::BOLD
519 << thisEvent.Name << LogFormat::NORMAL << LogFormat::UNDERLINE_OFF
520 << " (Event " << event_ctr << ")"
521 << " executed at time: " << LogFormat::BOLD << currentTime << LogFormat::NORMAL
522 << "\n";
523 }
524 if (!thisEvent.Description.empty()) {
525 out << " " << thisEvent.Description << "\n";
526 }
527 for (j=0; j<thisEvent.NotifyProperties.size();j++) {
528 out << " " << thisEvent.DisplayString[j] << " = "
529 << thisEvent.NotifyProperties[j]->getDoubleValue();
530 if (thisEvent.NotifyKML) out << " <br/>";
531 out << "\n";
532 }
533 if (thisEvent.NotifyKML) {
534 out << " ]]>\n";
535 out << " </description>\n";
536 out << " <Point>\n";
537 out << " <altitudeMode> absolute </altitudeMode>\n";
538 out << " <extrude> 1 </extrude>\n";
539 out << " <coordinates>"
540 << FDMExec->GetPropagate()->GetLongitudeDeg() << ","
541 << FDMExec->GetPropagate()->GetGeodLatitudeDeg() << ","
542 << FDMExec->GetPropagate()->GetAltitudeASLmeters()
543 << "</coordinates>\n";
544 out << " </Point>\n";
545 out << "</Placemark>\n";
546 }
547 out << "\n";
548 thisEvent.Notified = true;
549 }
550
551 }
552
553 event_ctr++;
554 }
555 return true;
556}
std::shared_ptr< FGPropagate > GetPropagate(void) const
Returns the FGPropagate pointer.
double GetSimTime(void) const
Returns the cumulative simulation time in seconds.
Definition FGFDMExec.h:550
+ Here is the call graph for this function:

The documentation for this class was generated from the following files: