private static String toAnglesString(Quaternion q) {
   float[] angles = q.toAngles(null);
   return "(X: "
       + (FastMath.RAD_TO_DEG * angles[0])
       + ", "
       + "Y: "
       + (FastMath.RAD_TO_DEG * angles[1])
       + ", "
       + "Z: "
       + (FastMath.RAD_TO_DEG * angles[2])
       + ")";
 }
  public void animateNode() {
    Vector3f v3f;

    int startFrame = 0;
    int endFrame = 0;
    float zRotationInc = 0.0f;
    float xRotationInc = 0.0f;

    System.out.println("animateNode");

    v3f = node1theSpatial.getLocalTranslation();
    System.out.println("Before animation - " + v3f + " - After last run = " + v3fFinal);

    node1result = new TimelineScenario.Sequence();
    // Add each key frame info as an animation and then play the whole
    if (animationStartKeyframe == 0 && animationEndKeyframe == 0) {
      startFrame = 0;
      endFrame = Tkft.length - 1;
    } else {
      startFrame = animationStartKeyframe;
      endFrame = animationEndKeyframe - 1;
    }

    for (int j = startFrame; j < endFrame; j++) {
      t = new Timeline(this);
      // *******************************************  Node 1
      float[] fromAngles = node1keyFrames[j].toAngles(null);
      float[] fromAnglesNext = node1keyFrames[j + 1].toAngles(null);

      float[] rotFinalAngles = rotFinal.toAngles(null);

      Quaternion quat = new Quaternion();
      quat.fromAngles(
          //                    fromAngles[0] + rotFinalAngles[0] + animationStartRotation[0],
          //                    fromAngles[1] + rotFinalAngles[1] + animationStartRotation[1],
          //                    fromAngles[2] + rotFinalAngles[2] + animationStartRotation[2]);
          fromAngles[0] + animationStartRotation[0],
          fromAngles[1] + rotFinalAngles[1] + animationStartRotation[1],
          fromAngles[2] + animationStartRotation[2]);
      Quaternion quatNext = new Quaternion();
      quatNext.fromAngles(
          //                    fromAnglesNext[0] + rotFinalAngles[0] + animationStartRotation[0],
          //                    fromAnglesNext[1] + rotFinalAngles[1] + animationStartRotation[1],
          //                    fromAnglesNext[2] + rotFinalAngles[2] + animationStartRotation[2]);
          fromAnglesNext[0] + animationStartRotation[0],
          fromAnglesNext[1] + rotFinalAngles[1] + animationStartRotation[1],
          fromAnglesNext[2] + animationStartRotation[2]);
      //            System.out.println("rots - x = " +
      //                    (fromAngles[0] + rotFinalAngles[0] + animationStartRotation[0]) + " - y
      // = " +
      //                    (fromAngles[1] + rotFinalAngles[1] + animationStartRotation[1]) + " - z
      // = " +
      //                    (fromAngles[2] + rotFinalAngles[2] + animationStartRotation[2]));

      t.addPropertyToInterpolate(
          "Node1Quat", quat, quatNext, new ModulatorQuaternionInterpolator());

      ////            t.addPropertyToInterpolate("Node1Quat", node1keyFrames[j], node1keyFrames[j +
      // 1], new ModulatorQuaternionInterpolator());

      zRotationInc = (float) Math.sin(animationStartRotation[1]);
      xRotationInc = (float) Math.cos(animationStartRotation[1]);

      if (v3fFinal.x == 0.0f && v3fFinal.y == 0.0 && v3fFinal.z == 0.0) {
        Vector3f tempVec =
            new Vector3f(
                (node1keyTrans[j].x + animationStartTranslate.x),
                (node1keyTrans[j].y + animationStartTranslate.y),
                (node1keyTrans[j].z + animationStartTranslate.z));
        Vector3f tempVecPlus =
            new Vector3f(
                (node1keyTrans[j + 1].x + animationStartTranslate.x),
                (node1keyTrans[j + 1].y + animationStartTranslate.y),
                (node1keyTrans[j + 1].z + animationStartTranslate.z));
        //                System.out.println("x = " +
        //                        (node1keyTrans[j].x + animationStartTranslate.x) + " - y = " +
        //                        (node1keyTrans[j].y + animationStartTranslate.y) + " - z = " +
        //                        (node1keyTrans[j].z + animationStartTranslate.z));
        t.addPropertyToInterpolate(
            "Node1Trans", tempVec, tempVecPlus, new ModulatorVectorInterpolator());
      } else {
        Vector3f tempVec =
            new Vector3f(
                node1keyTrans[j].x
                    + v3fFinal.x
                    + (node1keyTrans[j].x * (float) Math.sin(rotFinalAngles[1])),
                node1keyTrans[j].y + v3fFinal.y,
                node1keyTrans[j].z
                    + v3fFinal.z
                    + (node1keyTrans[j].z * (float) Math.cos(rotFinalAngles[1])));
        Vector3f tempVecPlus =
            new Vector3f(
                node1keyTrans[j + 1].x
                    + v3fFinal.x
                    + (node1keyTrans[j + 1].x * (float) Math.sin(rotFinalAngles[1])),
                node1keyTrans[j + 1].y + v3fFinal.y,
                node1keyTrans[j + 1].z
                    + v3fFinal.z
                    + (node1keyTrans[j + 1].z * (float) Math.cos(rotFinalAngles[1])));
        //                System.out.println("final - x = " +
        //                        (node1keyTrans[j].x + v3fFinal.x + (node1keyTrans[j].x *
        // (float)Math.sin(rotFinalAngles[1]))) + " - y = " +
        //                        (node1keyTrans[j].y + v3fFinal.y) + " - z = " +
        //                        (node1keyTrans[j].z + v3fFinal.z + (node1keyTrans[j].z *
        // (float)Math.cos(rotFinalAngles[1]))));
        t.addPropertyToInterpolate(
            "Node1Trans", tempVec, tempVecPlus, new ModulatorVectorInterpolator());
      }
      if (j == endFrame - 1) {
        t.addCallback(
            new TimelineCallback() {

              public void onTimelineDone() {
                Vector3f v3f = node1theSpatial.getLocalTranslation();
                System.out.println("After animation from timeline done - " + v3f);
              }

              public void onTimelineStateChanged(
                  TimelineState oldState, TimelineState newState, float arg2, float arg3) {
                if (newState == TimelineState.DONE) {
                  if (animationSaveTransform) {
                    v3fFinal = node1theSpatial.getLocalTranslation();
                    rotFinal = node1theSpatial.getLocalRotation();
                  }
                  System.out.println("After animation - " + v3fFinal);
                  ClientContext.getInputManager()
                      .postEvent(new IntercellEvent("F", animationIceCode));
                }
              }

              public void onTimelinePulse(float arg0, float arg1) {}
            });
      }

      ////            t.addPropertyToInterpolate("Node1Trans", node1keyTrans[j], node1keyTrans[j +
      // 1], new ModulatorVectorInterpolator());
      //        t.setEase(new Spline(0.4f));
      t.setDuration((long) ((Tkft[j + 1] - Tkft[j]) * 1000) * animationTimeMultiplier);
      node1result.addScenarioActor(t);
    }

    node2result = new TimelineScenario.Sequence();
    // ***************************************** Node 2
    // Add each key frame info as an animation and then play the whole
    for (int j = startFrame; j < endFrame; j++) {
      t = new Timeline(this);
      t.addPropertyToInterpolate(
          "Node2Quat",
          node2keyFrames[j],
          node2keyFrames[j + 1],
          new ModulatorQuaternionInterpolator());

      ///            Vector3f tempVec = new Vector3f(node2keyTrans[j].x + animationStartTranslate.x,
      // node2keyTrans[j].y + animationStartTranslate.y, node2keyTrans[j].z +
      // animationStartTranslate.z);
      ///            Vector3f tempVecPlus = new Vector3f(node2keyTrans[j + 1].x +
      // animationStartTranslate.x, node2keyTrans[j + 1].y + animationStartTranslate.y,
      // node2keyTrans[j + 1].z + animationStartTranslate.z);
      ///            t.addPropertyToInterpolate("Node2Trans", tempVec, tempVecPlus, new
      // ModulatorVectorInterpolator());
      /// System.out.println("node2 - orig y = " + node2keyTrans[j].y + " - shift - " + tempVec.y);
      t.addPropertyToInterpolate(
          "Node2Trans", node2keyTrans[j], node2keyTrans[j + 1], new ModulatorVectorInterpolator());
      //        t.setEase(new Spline(0.4f));
      t.setDuration((long) ((Tkft[j + 1] - Tkft[j]) * 1000) * animationTimeMultiplier);
      node2result.addScenarioActor(t);
    }

    node3result = new TimelineScenario.Sequence();
    // *******************************************************  Node 3
    // Add each key frame info as an animation and then play the whole
    for (int j = startFrame; j < endFrame; j++) {
      t = new Timeline(this);
      t.addPropertyToInterpolate(
          "Node3Quat",
          node3keyFrames[j],
          node3keyFrames[j + 1],
          new ModulatorQuaternionInterpolator());

      ///            Vector3f tempVec = new Vector3f(node3keyTrans[j].x + animationStartTranslate.x,
      // node3keyTrans[j].y + animationStartTranslate.y, node3keyTrans[j].z +
      // animationStartTranslate.z);
      ///            Vector3f tempVecPlus = new Vector3f(node3keyTrans[j + 1].x +
      // animationStartTranslate.x, node3keyTrans[j + 1].y + animationStartTranslate.y,
      // node3keyTrans[j + 1].z + animationStartTranslate.z);
      ///            t.addPropertyToInterpolate("Node3Trans", tempVec, tempVecPlus, new
      // ModulatorVectorInterpolator());
      /// System.out.println("node3 - orig y = " + node3keyTrans[j].y + " - shift - " + tempVec.y);
      t.addPropertyToInterpolate(
          "Node3Trans", node3keyTrans[j], node3keyTrans[j + 1], new ModulatorVectorInterpolator());
      //        t.setEase(new Spline(0.4f));
      t.setDuration((long) ((Tkft[j + 1] - Tkft[j]) * 1000) * animationTimeMultiplier);
      node3result.addScenarioActor(t);
    }

    node1result.play();
    node2result.play();
    node3result.play();
  }