92 const SGPath& initfile)
95 string aircraft=
"", prop_name=
"";
96 string notifyPropertyName=
"";
97 Element *element=0, *run_element=0, *event_element=0;
99 Element *notify_element = 0L, *notify_property_element = 0L;
100 double dt = 0.0, value = 0.0;
107 cerr <<
"File: " << script <<
" could not be loaded." << endl;
111 if (document->
GetName() !=
string(
"runscript")) {
112 cerr <<
"File: " << script <<
" is not a script file" << endl;
123 cerr <<
"No \"run\" element found in script." << endl;
129 if (run_element->HasAttribute(
"start"))
133 FDMExec->Setsim_time(StartTime);
134 if (run_element->HasAttribute(
"end")) {
135 EndTime = run_element->GetAttributeValueAsNumber(
"end");
137 cerr <<
"An end time (duration) for the script must be specified in the script <run> element." << endl;
141 if (default_dT == 0.0)
142 dt = run_element->GetAttributeValueAsNumber(
"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;
152 EndTime += 0.99*FDMExec->GetDeltaT();
159 if (!aircraft.empty()) {
160 if (!FDMExec->LoadModel(aircraft))
163 cerr <<
"Aircraft must be specified in use element." << endl;
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;
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;
181 cerr <<
"No \"use\" directives in the script file." << endl;
186 if ( ! IC->
Load( initialize )) {
187 cerr <<
"Initialization unsuccessful" << endl;
194 if (!FDMExec->GetInput()->Load(element))
202 SGPath scriptDir = SGPath(script.dir());
203 if (scriptDir.isNull())
204 scriptDir = SGPath(
".");
207 if (!FDMExec->GetOutput()->Load(element, scriptDir))
216 LocalProperties.Load(run_element, PropertyManager,
true);
221 event_element = run_element->FindElement(
"event");
222 while (event_element) {
225 struct event *newEvent =
new struct event();
228 newEvent->Name = event_element->GetAttributeValue(
"name");
232 if (event_element->GetAttributeValue(
"persistent") ==
string(
"true")) {
233 newEvent->Persistent = true;
237 if (event_element->GetAttributeValue(
"continuous") ==
string(
"true")) {
238 newEvent->Continuous = true;
243 if (condition_element != 0) {
245 newCondition =
new FGCondition(condition_element, PropertyManager);
246 }
catch(
string& str) {
247 cout << endl <<
fgred << str <<
reset << endl << endl;
251 newEvent->Condition = newCondition;
253 cerr <<
"No condition specified in script event " << newEvent->Name
264 newEvent->Delay = event_element->FindElementValueAsNumber(
"delay");
266 newEvent->Delay = 0.0;
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;
273 newEvent->Notify =
true;
275 string notify_description = notify_element->
FindElementValue(
"description");
276 if (!notify_description.empty()) {
277 newEvent->Description = notify_description;
279 notify_property_element = notify_element->
FindElement(
"property");
280 while (notify_property_element) {
281 notifyPropertyName = notify_property_element->GetDataLine();
283 if (notify_property_element->HasAttribute(
"apply")) {
284 string function_str = notify_property_element->GetAttributeValue(
"apply");
287 newEvent->NotifyProperties.push_back(
new FGFunctionValue(notifyPropertyName, PropertyManager, f));
289 cerr << notify_property_element->ReadFrom()
291 << function_str <<
" has been defined. This property will "
292 <<
"not be logged. You should check your configuration file."
297 newEvent->NotifyProperties.push_back(
new FGPropertyValue(notifyPropertyName, PropertyManager));
299 string caption_attribute = notify_property_element->GetAttributeValue(
"caption");
300 if (caption_attribute.empty()) {
301 newEvent->DisplayString.push_back(notifyPropertyName);
303 newEvent->DisplayString.push_back(caption_attribute);
313 while (set_element) {
315 if (PropertyManager->HasNode(prop_name)) {
316 newEvent->SetParam.push_back( PropertyManager->GetNode(prop_name) );
318 newEvent->SetParam.push_back( 0L );
320 newEvent->SetParamName.push_back( prop_name );
326 newEvent->Functions.push_back(
nullptr);
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);
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);
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);
349 newEvent->TC.push_back(1.0);
351 newEvent->Transiting.push_back(
false);
355 Events.push_back(*newEvent);
382 unsigned event_ctr = 0;
384 double currentTime = FDMExec->GetSimTime();
385 double newSetValue = 0;
387 if (currentTime > EndTime)
return false;
390 for (
unsigned int ev_ctr=0; ev_ctr < Events.size(); ev_ctr++) {
392 struct event &thisEvent = Events[ev_ctr];
399 if (thisEvent.Condition->
Evaluate()) {
400 if (!thisEvent.Triggered) {
404 for (
i=0;
i<thisEvent.SetValue.size();
i++) {
405 if (thisEvent.SetParam[
i] == 0L) {
406 if (PropertyManager->HasNode(thisEvent.SetParamName[
i])) {
407 thisEvent.SetParam[
i] = PropertyManager->GetNode(thisEvent.SetParamName[
i]);
409 throw(
"No property, \""+thisEvent.SetParamName[
i]+
"\" is defined.");
412 thisEvent.OriginalValue[
i] = thisEvent.SetParam[
i]->getDoubleValue();
413 if (thisEvent.Functions[
i] != 0) {
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;
421 switch (thisEvent.Type[
i]) {
424 thisEvent.newValue[
i] = thisEvent.SetValue[
i];
427 thisEvent.newValue[
i] = thisEvent.OriginalValue[
i] + thisEvent.SetValue[
i];
430 cerr <<
"Invalid Type specified" << endl;
433 thisEvent.StartTime = currentTime + thisEvent.Delay;
434 thisEvent.ValueSpan[
i] = thisEvent.newValue[
i] - thisEvent.OriginalValue[
i];
435 thisEvent.Transiting[
i] =
true;
438 thisEvent.Triggered =
true;
440 }
else if (thisEvent.Persistent) {
441 thisEvent.Triggered =
false;
442 thisEvent.Notified =
false;
443 }
else if (thisEvent.Continuous) {
444 thisEvent.Triggered =
false;
445 thisEvent.Notified =
false;
448 if ((currentTime >= thisEvent.StartTime) && thisEvent.Triggered) {
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]) {
455 if (thisEvent.TimeSpan <= thisEvent.TC[
i]) {
456 newSetValue = thisEvent.TimeSpan/thisEvent.TC[
i] * thisEvent.ValueSpan[
i] + thisEvent.OriginalValue[
i];
458 newSetValue = thisEvent.newValue[
i];
459 if (thisEvent.Continuous !=
true) thisEvent.Transiting[
i] =
false;
463 newSetValue = thisEvent.newValue[
i];
469 if (thisEvent.Continuous !=
true)
470 thisEvent.Transiting[
i] =
false;
471 else if (thisEvent.Functions[
i] != 0)
472 newSetValue = thisEvent.Functions[
i]->GetValue();
476 newSetValue = (1 - exp( -thisEvent.TimeSpan/thisEvent.TC[
i] )) * thisEvent.ValueSpan[
i] + thisEvent.OriginalValue[
i];
479 cerr <<
"Invalid Action specified" << endl;
482 thisEvent.SetParam[
i]->setDoubleValue(newSetValue);
487 if (thisEvent.Notify && !thisEvent.Notified) {
488 if (thisEvent.NotifyKML) {
489 cout << endl <<
"<Placemark>" << endl;
490 cout <<
" <name> " << currentTime <<
" seconds" <<
" </name>"
492 cout <<
" <description>" << endl;
493 cout <<
" <![CDATA[" << endl;
494 cout <<
" <b>" << thisEvent.Name <<
" (Event " << event_ctr <<
")"
495 <<
" executed at time: " << currentTime <<
"</b><br/>" << endl;
499 <<
" (Event " << event_ctr <<
")"
503 if (!thisEvent.Description.empty()) {
504 cout <<
" " << thisEvent.Description << endl;
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/>";
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;
527 thisEvent.Notified =
true;