93                          const SGPath& initfile)
 
   96  string aircraft=
"", prop_name=
"";
 
   97  string notifyPropertyName=
"";
 
   98  Element *element=0, *run_element=0, *event_element=0;
 
  100  Element *notify_element = 0L, *notify_property_element = 0L;
 
  101  double dt = 0.0, value = 0.0;
 
  105  Element* document = XMLFileRead.LoadXMLDocument(script);
 
  108    cerr << 
"File: " << script << 
" could not be loaded." << endl;
 
  112  if (document->
GetName() != 
string(
"runscript")) {
 
  113    cerr << 
"File: " << script << 
" is not a script file" << endl;
 
  124    cerr << 
"No \"run\" element found in script." << endl;
 
  130  if (run_element->HasAttribute(
"start"))
 
  131    StartTime = run_element->GetAttributeValueAsNumber(
"start");
 
  135  if (run_element->HasAttribute(
"end")) {
 
  136    EndTime   = run_element->GetAttributeValueAsNumber(
"end");
 
  138    cerr << 
"An end time (duration) for the script must be specified in the script <run> element." << endl;
 
  142  if (default_dT == 0.0)
 
  143    dt = run_element->GetAttributeValueAsNumber(
"dt");
 
  146    cout << endl << 
"Overriding simulation step size from the command line. New step size is: " 
  147         << default_dT << 
" seconds (" << 1/default_dT << 
" Hz)" << endl << endl;
 
  160    if (!aircraft.empty()) {
 
  164      cerr << 
"Aircraft must be specified in use element." << endl;
 
  168    initialize = SGPath::fromLocal8Bit(element->
GetAttributeValue(
"initialize").c_str());
 
  169    if (initfile.isNull()) {
 
  170      if (initialize.isNull()) {
 
  171        cerr << 
"Initialization file must be specified in use element." << endl;
 
  175      cout << endl << 
"The initialization file specified in the script file (" 
  176           << initialize << 
") has been overridden with a specified file (" 
  177           << initfile << 
")." << endl;
 
  178      initialize = initfile;
 
  182    cerr << 
"No \"use\" directives in the script file." << endl;
 
  186  auto IC = FDMExec->
GetIC();
 
  187  if ( ! IC->Load( initialize )) {
 
  188    cerr << 
"Initialization unsuccessful" << endl;
 
  195    if (!FDMExec->
GetInput()->Load(element))
 
  203  SGPath scriptDir = SGPath(script.dir());
 
  204  if (scriptDir.isNull())
 
  205    scriptDir = SGPath(
".");
 
  208    if (!FDMExec->
GetOutput()->Load(element, scriptDir))
 
  215  int saved_debug_lvl = debug_lvl;
 
  217  LocalProperties.Load(run_element, PropertyManager.get(), 
true);
 
  218  debug_lvl = saved_debug_lvl;
 
  222  event_element = run_element->FindElement(
"event");
 
  223  while (event_element) { 
 
  226    struct event *newEvent = 
new struct event();
 
  229    newEvent->Name = event_element->GetAttributeValue(
"name");
 
  233    if (event_element->GetAttributeValue(
"persistent") == 
string(
"true")) {
 
  234      newEvent->Persistent = 
true;
 
  238    if (event_element->GetAttributeValue(
"continuous") == 
string(
"true")) {
 
  239      newEvent->Continuous = 
true;
 
  244    if (condition_element) {
 
  246        newCondition = 
new FGCondition(condition_element, PropertyManager);
 
  248        cerr << condition_element->
ReadFrom()
 
  249             << 
fgred << e.what() << 
reset << endl << endl;
 
  253      newEvent->Condition = newCondition;
 
  255      cerr << 
"No condition specified in script event " << newEvent->Name
 
  268      newEvent->Delay = 0.0;
 
  271    if ((notify_element = event_element->
FindElement(
"notify")) != 0) {
 
  273        if (notify_element->
GetAttributeValue(
"format") == 
"kml") newEvent->NotifyKML = 
true;
 
  275      newEvent->Notify = 
true;
 
  277      string notify_description = notify_element->
FindElementValue(
"description");
 
  278      if (!notify_description.empty()) {
 
  279        newEvent->Description = notify_description;
 
  281      notify_property_element = notify_element->
FindElement(
"property");
 
  282      while (notify_property_element) {
 
  283        notifyPropertyName = notify_property_element->
GetDataLine();
 
  285        if (notify_property_element->HasAttribute(
"apply")) {
 
  286          string function_str = notify_property_element->GetAttributeValue(
"apply");
 
  287          auto f = FDMExec->GetTemplateFunc(function_str);
 
  289            newEvent->NotifyProperties.push_back(
new FGFunctionValue(notifyPropertyName, PropertyManager, f,
 
  290                                                                     notify_property_element));
 
  292            cerr << notify_property_element->ReadFrom()
 
  294              << function_str << 
" has been defined. This property will " 
  295              << 
"not be logged. You should check your configuration file." 
  300          newEvent->NotifyProperties.push_back(
new FGPropertyValue(notifyPropertyName, PropertyManager,
 
  301                                                                   notify_property_element));
 
  303        string caption_attribute = notify_property_element->GetAttributeValue(
"caption");
 
  304        if (caption_attribute.empty()) {
 
  305          newEvent->DisplayString.push_back(notifyPropertyName);
 
  307          newEvent->DisplayString.push_back(caption_attribute);
 
  317    while (set_element) {
 
  319      if (PropertyManager->HasNode(prop_name)) {
 
  320        newEvent->SetParam.push_back( PropertyManager->GetNode(prop_name) );
 
  322        newEvent->SetParam.push_back( 0L );
 
  324      newEvent->SetParamName.push_back( prop_name );
 
  330        newEvent->Functions.push_back(
nullptr);
 
  335      newEvent->SetValue.push_back(value);
 
  336      newEvent->OriginalValue.push_back(0.0);
 
  337      newEvent->newValue.push_back(0.0);
 
  338      newEvent->ValueSpan.push_back(0.0);
 
  340      if      (to_lower(tempCompare).find(
"delta") != string::npos) newEvent->Type.push_back(FG_DELTA);
 
  341      else if (to_lower(tempCompare).find(
"bool") != string::npos)  newEvent->Type.push_back(FG_BOOL);
 
  342      else if (to_lower(tempCompare).find(
"value") != string::npos) newEvent->Type.push_back(FG_VALUE);
 
  343      else                                newEvent->Type.push_back(FG_VALUE); 
 
  345      if      (to_lower(tempCompare).find(
"ramp") != string::npos) newEvent->Action.push_back(FG_RAMP);
 
  346      else if (to_lower(tempCompare).find(
"step") != string::npos) newEvent->Action.push_back(FG_STEP);
 
  347      else if (to_lower(tempCompare).find(
"exp") != string::npos) newEvent->Action.push_back(FG_EXP);
 
  348      else                               newEvent->Action.push_back(FG_STEP); 
 
  353        newEvent->TC.push_back(1.0); 
 
  355      newEvent->Transiting.push_back(
false);
 
  359    Events.push_back(*newEvent);
 
  362    event_element = run_element->FindNextElement(
"event");
 
 
  386  unsigned event_ctr = 0;
 
  389  double newSetValue = 0;
 
  391  if (currentTime > EndTime) 
return false;
 
  394  for (
unsigned int ev_ctr=0; ev_ctr < Events.size(); ev_ctr++) {
 
  396    struct event &thisEvent = Events[ev_ctr];
 
  403    if (thisEvent.Condition->Evaluate()) {
 
  404      if (!thisEvent.Triggered) {
 
  408        for (i=0; i<thisEvent.SetValue.size(); i++) {
 
  409          if (thisEvent.SetParam[i] == 0L) { 
 
  410            if (PropertyManager->HasNode(thisEvent.SetParamName[i])) {
 
  411              thisEvent.SetParam[i] = PropertyManager->GetNode(thisEvent.SetParamName[i]);
 
  413              throw(
"No property, \""+thisEvent.SetParamName[i]+
"\" is defined.");
 
  416          thisEvent.OriginalValue[i] = thisEvent.SetParam[i]->getDoubleValue();
 
  417          if (thisEvent.Functions[i] != 0) { 
 
  419              thisEvent.SetValue[i] = thisEvent.Functions[i]->GetValue();
 
  420            } 
catch (
string& msg) {
 
  421              std::cerr << std::endl << 
"A problem occurred in the execution of the script. " << msg << endl;
 
  425          switch (thisEvent.Type[i]) {
 
  428            thisEvent.newValue[i] = thisEvent.SetValue[i];
 
  431            thisEvent.newValue[i] = thisEvent.OriginalValue[i] + thisEvent.SetValue[i];
 
  434            cerr << 
"Invalid Type specified" << endl;
 
  437          thisEvent.StartTime = currentTime + thisEvent.Delay;
 
  438          thisEvent.ValueSpan[i] = thisEvent.newValue[i] - thisEvent.OriginalValue[i];
 
  439          thisEvent.Transiting[i] = 
true;
 
  442      thisEvent.Triggered = 
true;
 
  444    } 
else if (thisEvent.Persistent) { 
 
  445      thisEvent.Triggered = 
false; 
 
  446      thisEvent.Notified = 
false;  
 
  447    } 
else if (thisEvent.Continuous) { 
 
  448      thisEvent.Triggered = 
false; 
 
  449      thisEvent.Notified = 
false;  
 
  452    if ((currentTime >= thisEvent.StartTime) && thisEvent.Triggered) {
 
  454      for (i=0; i<thisEvent.SetValue.size(); i++) {
 
  455        if (thisEvent.Transiting[i]) {
 
  456          thisEvent.TimeSpan = currentTime - thisEvent.StartTime;
 
  457          switch (thisEvent.Action[i]) {
 
  459            if (thisEvent.TimeSpan <= thisEvent.TC[i]) {
 
  460              newSetValue = thisEvent.TimeSpan/thisEvent.TC[i] * thisEvent.ValueSpan[i] + thisEvent.OriginalValue[i];
 
  462              newSetValue = thisEvent.newValue[i];
 
  463              if (thisEvent.Continuous != 
true) thisEvent.Transiting[i] = 
false;
 
  467            newSetValue = thisEvent.newValue[i];
 
  473            if (thisEvent.Continuous != 
true)
 
  474              thisEvent.Transiting[i] = 
false;
 
  475            else if (thisEvent.Functions[i] != 0)
 
  476              newSetValue = thisEvent.Functions[i]->GetValue();
 
  480            newSetValue = (1 - exp( -thisEvent.TimeSpan/thisEvent.TC[i] )) * thisEvent.ValueSpan[i] + thisEvent.OriginalValue[i];
 
  483            cerr << 
"Invalid Action specified" << endl;
 
  486          thisEvent.SetParam[i]->setDoubleValue(newSetValue);
 
  491      if (thisEvent.Notify && !thisEvent.Notified) {
 
  492        if (thisEvent.NotifyKML) {
 
  493          cout << endl << 
"<Placemark>" << endl;
 
  494          cout << 
"  <name> " << currentTime << 
" seconds" << 
" </name>" 
  496          cout << 
"  <description>" << endl;
 
  497          cout << 
"  <![CDATA[" << endl;
 
  498          cout << 
"  <b>" << thisEvent.Name << 
" (Event " << event_ctr << 
")" 
  499               << 
" executed at time: " << currentTime << 
"</b><br/>" << endl;
 
  503               << 
" (Event " << event_ctr << 
")" 
  507        if (!thisEvent.Description.empty()) {
 
  508          cout << 
"    " << thisEvent.Description << endl;
 
  510        for (j=0; j<thisEvent.NotifyProperties.size();j++) {
 
  511          cout << 
"    " << thisEvent.DisplayString[j] << 
" = " 
  512               << thisEvent.NotifyProperties[j]->getDoubleValue();
 
  513          if (thisEvent.NotifyKML) cout << 
" <br/>";
 
  516        if (thisEvent.NotifyKML) {
 
  517          cout << 
"  ]]>" << endl;
 
  518          cout << 
"  </description>" << endl;
 
  519          cout << 
"  <Point>" << endl;
 
  520          cout << 
"    <altitudeMode> absolute </altitudeMode>" << endl;
 
  521          cout << 
"    <extrude> 1 </extrude>" << endl;
 
  522          cout << 
"    <coordinates>" 
  526               << 
"</coordinates>" << endl;
 
  527          cout << 
"  </Point>" << endl;
 
  528          cout << 
"</Placemark>" << endl;
 
  531        thisEvent.Notified = 
true;