docs: public void buildInteractiveObject(String fromNode, String fromField, String toNode, String toField) {
          Sensor routeFromSensor = null;
          TimeSensor routeToTimeSensor = null;
          TimeSensor routeFromTimeSensor = null;
          Interpolator routeToInterpolator = null;
          Interpolator routeFromInterpolator = null;
          EventUtility routeToEventUtility = null;
          EventUtility routeFromEventUtility = null;
          DefinedItem routeToDefinedItem = null;
          DefinedItem routeFromDefinedItem = null; // used passing items into a Script
          ScriptObject routeFromScriptObject = null;
          ScriptObject routeToScriptObject = null;
  
          // Get pointers to the Sensor, TimeSensor, Interpolator,
          // EventUtility (such as BooleanToggle), ScriptObject
          // and/or Defined Items based the nodes of this object
          for (Sensor sensor : sensors) {
              if (sensor.getName().equalsIgnoreCase(fromNode)) {
                  routeFromSensor = sensor;
              }
          }
  
          for (TimeSensor timeSensor : timeSensors) {
              if (timeSensor.name.equalsIgnoreCase(toNode)) {
                  routeToTimeSensor = timeSensor;
              } else if (timeSensor.name.equalsIgnoreCase(fromNode)) {
                  routeFromTimeSensor = timeSensor;
              }
          }
  
          for (Interpolator interpolator : interpolators) {
              if (interpolator.name.equalsIgnoreCase(toNode)) {
                  routeToInterpolator = interpolator;
              } else if (interpolator.name.equalsIgnoreCase(fromNode)) {
                  routeFromInterpolator = interpolator;
              }
          }
  
          for (EventUtility eventUtility : eventUtilities) {
              if (eventUtility.getName().equalsIgnoreCase(toNode)) {
                  routeToEventUtility = eventUtility;
              } else if (eventUtility.getName().equalsIgnoreCase(fromNode)) {
                  routeFromEventUtility = eventUtility;
              }
          }
  
          for (ScriptObject scriptObject : scriptObjects) {
              if (scriptObject.getName().equalsIgnoreCase(toNode)) {
                  routeToScriptObject = scriptObject;
              } else if (scriptObject.getName().equalsIgnoreCase(fromNode)) {
                  routeFromScriptObject = scriptObject;
              }
          }
  
          for (DefinedItem definedItem : definedItems) {
              if (definedItem.getName().equalsIgnoreCase(toNode)) {
                  routeToDefinedItem = definedItem;
              } else if (definedItem.getName().equalsIgnoreCase(fromNode)) {
                  routeFromDefinedItem = definedItem;
              }
          }
  
          // Now build the InteractiveObject by assigning pointers
          // to an existing InteractiveObject matches non-null links
          // or create a new InteractiveObject.
          // The flow is to test where the ROUTE TO goes (instead of FROM)
  
          // ROUTE TO a TimeSensor
          if (routeToTimeSensor != null) {
              boolean routeToTimeSensorFound = false;
              for (InteractiveObject interactiveObject : interactiveObjects) {
                  if (routeToTimeSensor == interactiveObject.getTimeSensor()) {
                      if (interactiveObject.getSensor() == null) {
                          //This sensor already exists inside an Interactive Object
                          interactiveObject.setSensor(routeFromSensor, fromField);
                          routeToTimeSensorFound = true;
                      }
                  }
                  else if (routeFromScriptObject != null) {
                      // a rare case where a Script node sends data to a TimeSensor
                      if (routeFromScriptObject == interactiveObject.getScriptObject()) {
                          //TODO: complete adding field to this Script Node when sent to TimeSensor
                          for (ScriptObject.Field field : routeFromScriptObject.getFieldsArrayList()) {
                              if (toField.equalsIgnoreCase(routeFromScriptObject.getFieldName(field))) {
                                  interactiveObject.getScriptObject().setToTimeSensor(field, routeToTimeSensor, toField);
                                  routeToTimeSensorFound = true;
                              }
                          }
                      }
                  }
              }
              if (!routeToTimeSensorFound) {
                  // construct a new interactiveObject for this sensor and timeSensor
                  InteractiveObject interactiveObject = new InteractiveObject();
                  interactiveObject.setSensor(routeFromSensor, fromField);
                  interactiveObject.setTimeSensor(routeToTimeSensor);
                  interactiveObjects.add(interactiveObject);
              }
          }  //  end route To TimeSensor
  
          // ROUTE TO an Interpolator (Position, Rotation, etc)
          if (routeToInterpolator != null) {
              boolean routeToInterpolatorFound = false;
              for (InteractiveObject interactiveObject : interactiveObjects) {
                  if (routeToInterpolator == interactiveObject.getInterpolator()) {
                      if (interactiveObject.getTimeSensor() == null) {
                          //This sensor already exists as part of an interactive Object
                          interactiveObject.setTimeSensor(routeFromTimeSensor);
                          routeToInterpolatorFound = true;
                      }
                  }
              }
              if (!routeToInterpolatorFound) {
                  // construct a new interactiveObject for this sensor and timeSensor
                  for (InteractiveObject interactiveObject : interactiveObjects) {
                      if (routeFromTimeSensor == interactiveObject.getTimeSensor()) {
                          if ((interactiveObject.getInterpolator() == null)
                                  && (interactiveObject.getScriptObject() == null)) {
                              //This timer already exists as part of an interactive Object
                              interactiveObject.setInterpolator(routeToInterpolator);
                              routeToInterpolatorFound = true;
                          }
                      }
                  }
              }
              if (!routeToInterpolatorFound) {
                  // construct a new interactiveObject for this sensor and timeSensor
                  InteractiveObject interactiveObject = new InteractiveObject();
                  interactiveObject.setTimeSensor(routeFromTimeSensor);
                  interactiveObject.setInterpolator(routeToInterpolator);
                  interactiveObjects.add(interactiveObject);
              }
          }  //  end route To Interpolator
  
          // ROUTE TO an Event Utility (such as a BooleanToggle
          if (routeToEventUtility != null) {
              boolean routeToEventUtilityFound = false;
              for (InteractiveObject interactiveObject : interactiveObjects) {
                  if (routeToEventUtility == interactiveObject.getEventUtility()) {
                      if ( (interactiveObject.getSensor() == null) && (routeFromSensor != null) ) {
                          interactiveObject.setSensor(routeFromSensor, fromField);
                          routeToEventUtilityFound = true;
                      }
                      else if ( (interactiveObject.getScriptObject() == null) && (routeFromScriptObject != null) ) {
                          for (ScriptObject.Field field : routeFromScriptObject.getFieldsArrayList()) {
                              if (fromField.equalsIgnoreCase(routeFromScriptObject.getFieldName(field))) {
                                  routeFromScriptObject.setToEventUtility(field, routeToEventUtility, toField);
                                  routeToEventUtilityFound = true;
                              }
                          }
                      }
                  }
              }
              if (!routeToEventUtilityFound) {
                  // construct a new interactiveObject for this sensor and timeSensor
                  InteractiveObject interactiveObject = new InteractiveObject();
                  interactiveObject.setSensor(routeFromSensor, fromField);
                  interactiveObject.setEventUtility(routeToEventUtility);
                  interactiveObject.setScriptObject(routeFromScriptObject);
                  interactiveObjects.add(interactiveObject);
              }
          }  //  end routeToEventUtility
  
          // ROUTE TO a Script Object
          if (routeToScriptObject != null) {
              boolean routeToScriptObjectFound = false;
              for (InteractiveObject interactiveObject : interactiveObjects) {
                  if (routeToScriptObject == interactiveObject.getScriptObject()) {
                      if ((interactiveObject.getSensor() == null) && (routeFromSensor != null)) {
                          //This sensor already exists as part of an interactive Object
                          interactiveObject.setSensor(routeFromSensor, fromField);
                          routeToScriptObjectFound = true;
                      }  //  end Sensor
                      else if ((interactiveObject.getDefinedItem() == null) && (routeFromDefinedItem != null)) {
                          //This defined Item already exists as part of an interactive Object
                          for (ScriptObject.Field field : routeToScriptObject.getFieldsArrayList()) {
                              if (toField.equalsIgnoreCase(routeToScriptObject.getFieldName(field))) {
                                  routeToScriptObject.setFromDefinedItem(field, routeFromDefinedItem, fromField);
                              }
                          }
                          routeToScriptObjectFound = true;
                      }  // end definedItem
                      else if ((interactiveObject.getEventUtility() == null) && (routeFromEventUtility != null)) {
                          //This event utility already exists as part of an interactive Object
                          for (ScriptObject.Field field : routeToScriptObject.getFieldsArrayList()) {
                              if (toField.equalsIgnoreCase(routeToScriptObject.getFieldName(field))) {
                                  routeToScriptObject.setFromEventUtility(field, routeFromEventUtility, fromField);
                              }
                          }
                          routeToScriptObjectFound = true;
                      } // end eventUtility
  
                      else if ((interactiveObject.getTimeSensor() == null) && (routeFromTimeSensor != null)) {
                          //This sensor already exists as part of an interactive Object
                          for (ScriptObject.Field field : routeToScriptObject.getFieldsArrayList()) {
                              if (toField.equalsIgnoreCase(routeToScriptObject.getFieldName(field))) {
                                  routeToScriptObject.setFromTimeSensor(field, routeFromTimeSensor, fromField);
                              }
                          }
                          routeToScriptObjectFound = true;
                      } // end timeSensor
  
                  }
              }
              if (!routeToScriptObjectFound) {
                  // construct a new interactiveObject for this sensor and timeSensor
                  InteractiveObject interactiveObject = new InteractiveObject();
                  interactiveObject.setScriptObject(routeToScriptObject);
                  if (routeFromSensor != null) {
                      interactiveObject.setSensor(routeFromSensor, fromField);
                  }
                  else if (routeFromDefinedItem != null) {
                      // happens when scripting and sending values from item to the script
                      interactiveObject.setDefinedItemFromField(routeFromDefinedItem, fromField);
                      for (ScriptObject.Field field : routeToScriptObject.getFieldsArrayList()) {
                          if (toField.equalsIgnoreCase(routeToScriptObject.getFieldName(field))) {
                              routeToScriptObject.setFromDefinedItem(field, routeFromDefinedItem, fromField);
                          }
                      }
                  }
                  else if (routeFromEventUtility != null) {
                      String fieldName = routeToScriptObject.getFieldName(routeToScriptObject.getField(0));
                      if ( !fieldName.equalsIgnoreCase(toField) ) {
                          // the first field, which is the name of the function
                          for (ScriptObject.Field field : routeToScriptObject.getFieldsArrayList()) {
                              if (toField.equalsIgnoreCase(routeToScriptObject.getFieldName(field))) {
                                  routeToScriptObject.setFromEventUtility(field, routeFromEventUtility, fromField);
                              }
                          }
                      }
                      else interactiveObject.setEventUtility(routeFromEventUtility);
                  }
                  else if (routeFromTimeSensor != null) {
                      String fieldName = routeToScriptObject.getFieldName(routeToScriptObject.getField(0));
                      if ( !fieldName.equalsIgnoreCase(toField) ) {
                          // the first field, which is the name of the function
                          for (ScriptObject.Field field : routeToScriptObject.getFieldsArrayList()) {
                              if (toField.equalsIgnoreCase(routeToScriptObject.getFieldName(field))) {
                                  routeToScriptObject.setFromTimeSensor(field, routeFromTimeSensor, fromField);
                              }
                          }
                      }
                      else interactiveObject.setTimeSensor(routeFromTimeSensor);
                  }
                  interactiveObjects.add(interactiveObject);
              }
          }  //  end routeToScriptObject
  
          // ROUTE TO a DEFind Object
          if (routeToDefinedItem != null) {
              boolean routeToDEFinedItemFound = false;
              for (InteractiveObject interactiveObject : interactiveObjects) {
                  if ((routeFromInterpolator == interactiveObject.getInterpolator()) &&
                          (routeFromInterpolator != null)) {
                      if (interactiveObject.getDefinedItemToField() == null) {
                          interactiveObject.setDefinedItemToField(routeToDefinedItem, toField);
                          routeToDEFinedItemFound = true;
                      }
                  } else if ((routeFromEventUtility == interactiveObject.getEventUtility()) &&
                          (routeFromEventUtility != null)) {
                      if (interactiveObject.getDefinedItemToField() == null) {
                          interactiveObject.setDefinedItemToField(routeToDefinedItem, toField);
                          routeToDEFinedItemFound = true;
                      }
                  } else if ((routeFromScriptObject == interactiveObject.getScriptObject()) &&
                          (routeFromScriptObject != null)) {
                      if (interactiveObject.getDefinedItemToField() == null) {
                          for (ScriptObject.Field field : routeFromScriptObject.getFieldsArrayList()) {
                              if (fromField.equalsIgnoreCase(routeFromScriptObject.getFieldName(field))) {
                                  routeFromScriptObject.setToDefinedItem(field, routeToDefinedItem, toField);
                              }
                          }
                          routeToDEFinedItemFound = true;
                      }
                  }
              }
              if (!routeToDEFinedItemFound) {
                  // construct a new interactiveObject for this sensor and timeSensor
                  InteractiveObject interactiveObject = new InteractiveObject();
                  interactiveObject.setInterpolator(routeFromInterpolator);
                  interactiveObject.setDefinedItemToField(routeToDefinedItem, toField);
                  if (routeFromSensor != null)
                      interactiveObject.setSensor(routeFromSensor, fromField);
                  if (routeFromScriptObject != null) {
                      for (ScriptObject.Field field : routeFromScriptObject.getFieldsArrayList()) {
                          if (fromField.equalsIgnoreCase(routeFromScriptObject.getFieldName(field))) {
                              routeFromScriptObject.setToDefinedItem(field, routeToDefinedItem, toField);
                          }
                      }
  
                  }
                  if (routeFromEventUtility != null) {
                      interactiveObject.setEventUtility(routeFromEventUtility);
                  }
                  interactiveObjects.add(interactiveObject);
              }
          }  //  end if routeToDefinedItem != null
      }