/// <summary>
    /// Called when a manipulation gesture is currently happening
    /// </summary>
    /// <param name="eventData">The data of the manipulation event</param>
    public void OnManipulationUpdated(ManipulationEventData eventData)
    {
        if (transformationManager.enabled)
        {
            // compute the difference of the drag gesture in comparison to the last frame
            // this way the rotation speed is not accumulating but only depends on the current drag speed
            Vector3 delta = lastCummulativeDelta - eventData.CumulativeDelta;

            delta *= -1;

            switch (handleType)
            {
            case HandleType.SCALE:
            {
                // it is also possible to scale without preserving the aspect ratio
                // this option is implemented in here but it is currently not used
                bool preserveAspectRatio = true;
                if (preserveAspectRatio)
                {
                    Vector2 centerProj = Camera.main.WorldToScreenPoint(toManipulate.position);
                    Vector2 handleProj = Camera.main.WorldToScreenPoint(transform.position);

                    Vector2 fromCenterToHandle = handleProj - centerProj;
                    fromCenterToHandle = fromCenterToHandle.normalized;

                    int drawDirection = Math.Sign(Vector2.Dot(delta, fromCenterToHandle));
                    // fromCenterToHandle points outwards from the center
                    // thus:
                    // if drawDirection < 0: inwards-drag => scale down
                    // if drawDirection > 0: outwards-drag => scale up

                    // just get the most dominant 2D-axis to determine the strength of the scale
                    // float max = Math.Max(Math.Abs(delta.x), Math.Abs(delta.y));

                    // get the length of the drag vector in order to determine the strength of the operation
                    float max = delta.magnitude;

                    // determine scaling factor
                    float scaleFac = 1.0f + (speed * max * drawDirection);

#if BOUNDING_BOX_DEBUG
                    // the following are debug lines which can be used to visualize the relevant vectors
                    // they are only visible in the game view
                    //Debug.DrawLine(toManipulate.position, toManipulate.position + new Vector3(fromCenterToHandle.x, fromCenterToHandle.y, 0), Color.red);
                    //Debug.DrawLine(Camera.main.transform.position, Camera.main.transform.position + (delta * 10000), Color.cyan);
#endif

                    // scale
                    transformationManager.Scale(scaleFac * Vector3.one);
                }
                else
                {
                    Vector3 scaleVec = speed * new Vector3(
                        delta.x * gestureOrientation.x,
                        delta.y * gestureOrientation.y,
                        delta.z * gestureOrientation.z);
                    transformationManager.Scale(scaleVec);
                }
                break;
            }

            case HandleType.ROTATE:
            {
                // it uses the projection of the axis and computes everything in the viewport plane
                Vector3 projectedDelta = Vector3.Project(delta, projectionCross);

                float rotationAngle = projectedDelta.magnitude * Vector3.Dot(projectedDelta.normalized, projectionCross.normalized) * 360;

#if BOUNDING_BOX_DEBUG
                // the following are debug lines which can be used to visualize the relevant vectors
                // they are only visible in the game view
                //Debug.DrawLine(toManipulate.position, toManipulate.position + currentAxis, Color.red);
                //Debug.DrawLine(Camera.main.transform.position, Camera.main.transform.position + currentAxisProjection, Color.magenta);
                //Debug.DrawLine(Camera.main.transform.position, Camera.main.transform.position + projectionCross, Color.green);
                //Debug.DrawLine(Camera.main.transform.position, Camera.main.transform.position + (projectedDelta * 10000), Color.blue);
                //Debug.DrawLine(Camera.main.transform.position, Camera.main.transform.position + (delta * 10000), Color.cyan);
#endif

#if ALTERNATIVE_SOLUTION
                // this solution determines the angle at the object between the camera and its offset by the drag vector
                // with the aid of the cross product the "sign of the angle" can be determined
                // i.e. if the drag direction is pointing to the left or the right of the axis as seen from the camera
                Vector3 objToCam      = Camera.main.transform.position - toManipulate.position;
                Vector3 objToTarget   = (Camera.main.transform.position + delta) - toManipulate.position;
                float   rotationAngle = Vector3.Angle(objToCam, objToTarget);

                Vector3 crossProduct = Vector3.Cross(objToCam, objToTarget);
                if (Vector3.Dot(crossProduct, currentAxis) < 0)
                {
                    rotationAngle *= -1;
                }
#endif

                Debug.Log("Rotation by: " + rotationAngle);

                // rotate around the given axis by the calculated angle
                transformationManager.Rotate(gestureOrientation, speed * rotationAngle);
                break;
            }

            case HandleType.TRANSLATE:
            {
                transformationManager.Translate(speed * delta);
                break;
            }
            }

            // remember the cumulativeDelta in order to calculate the difference to this in the next frame
            lastCummulativeDelta = eventData.CumulativeDelta;
        }
    }
 public void TestRotate_NegativeAngle()
 {
     go.transform.rotation = Quaternion.identity;
     transManager.Rotate(Vector3.up, -10);
     Assert.IsTrue(go.transform.rotation.eulerAngles.Equals(new Vector3(0, 350, 0)));
 }