// Takes in a Unity Vector3 and Unity Quaternion (for ease of use with GameObject.Transform to avoid multiple conversions, for now)
    // TODO Doesnt yet work propperly: Translation is 2x the corrrect vector; Rotation causes a translation as well as a rotation.
    // TODO Not sure how to combine this with interpolation (how would we use t?), does it require SLERP plus somthing else, where to apply this?
    // TODO Review equations here: http://www.xbdev.net/misc_demos/demos/dual_quaternions_beyond/paper.pdf
    void MoveWithDualQuat(UnityEngine.Vector3 t_position, UnityEngine.Quaternion t_rotation)
    {
        // Translate Unity Vector3 position and Unity Quaternion rotation into Mathd Dual Quaternion.
        Mathd.DualQuaternion point = new Mathd.DualQuaternion(new Mathd.Vector3(transform.position), new Mathd.Quaternion(transform.rotation));

        // Setup a transform within another Dual Quaternion. This will be the 'portal'.
        Mathd.Vector3        newPosition      = new Mathd.Vector3(t_position);
        Mathd.Quaternion     newRotation      = new Mathd.Quaternion(t_rotation);
        Mathd.DualQuaternion transformToApply = new Mathd.DualQuaternion(newPosition, newRotation);

        // Now perform the dual quaternion, awesome paralelle universe, movement!!
        // p' = qpq`
        // Where:
        // q  is the translation and rotation wrapped up in a dual quaternion
        // q` is the conjugate of q
        // p  is the transform of the point to transform by q
        // p' is the resulting transformation
        Mathd.DualQuaternion transformedPoint = (transformToApply * point) * transformToApply.conjugate;

        // Read back out from the transformed point and convert into Unity Vector3 and Quaternion.
        transform.position = transformedPoint.position.toUnityVec3;
        UnityEngine.MonoBehaviour.print("Returned position " + transformedPoint.position.toUnityVec3);
        transform.rotation = transformedPoint.rotation.toUnityQuat;
        UnityEngine.MonoBehaviour.print("Returned rotation " + transformedPoint.rotation.toUnityQuat.eulerAngles);
    }
//    IEnumerator RemoveImagineryInfluence() {
//      float timeToEnd = Time.time + 2.5f; // Disolve influence over 2.5sec
//      Vector2
//      while (Time.time < timeToEnd) {
//          Vector2.Lerp(
//      }
//    }

    void LookAt(Mathd.Vector3 pointToLookAt)
    {
        Mathd.Vector3 lookAtVector        = pointToLookAt - new Mathd.Vector3(transform.position);
        float         angleBetweenVectors = Vector3.Dot(transform.right.normalized, lookAtVector.toUnityVec3);

        transform.Rotate(transform.up, angleBetweenVectors);

        //transform.rotation = new UnityEngine.Quaternion();
    }
    // Update is called once per frame
    void Update()
    {
        // Check for camera being close enough to recieve rotation influence from each point of interest
        float[] weights = new float[pois.Length + 1]; // Extra space for balancing weight
        weights[weights.Length - 1] = 0;              // Default the extra to 0 so it only influences if we need it
        int weightCount = 0;

        for (int i = 0; i < weights.Length - 1; i++)
        {
            float distanceFromPoI = Vector3.Magnitude(pois[i].transform.position - transform.position);

            if (distanceFromPoI <= pois[i].AreaOfInterestRadius())
            {
                weightCount++;
                float weight = distanceFromPoI / pois[i].AreaOfInterestRadius();
                // Use Hermet cuve Y value to 'cushion' the approach and exit from PoIs
                weight     = R_Curve.hermit(Vector3.zero, new Vector3(1, 1, 0), new Vector3(3f, 0, 0), new Vector3(-3f, 0, 0), weight).y;
                weight     = 1 - weight;
                weights[i] = weight;
            }
            else
            {
                weights[i] = 0;
            }
        }

        // Get the total amount of influence being cast upon the camera
        float weightTotal = 0;

        foreach (float weight in weights)
        {
            weightTotal += weight;
        }

//		if (weightCount == 1) {
//			if (onlyOnePoI == false) {
//				onlyOnePoI = true;
//				imagineryPoI = PoIBlob.transform.position;
//			}
//			else {
//				onlyOnePoI = false;
//			}
//
//			weights[weights.Length - 1] = weightTotal;
//			weightTotal += weightTotal;
//		}

        // Normalise the weights
        for (int i = 0; i < weights.Length; i++)
        {
            weights[i] = weights[i] / weightTotal;
        }

        // Create compound Vector3 to look at
        Mathd.Vector3 compoundPoI = Mathd.Vector3.zero;
        for (int i = 0; i < pois.Length; i++)
        {
            compoundPoI += new Mathd.Vector3(pois[i].transform.position * weights[i]);
        }

        // Look at the compound point
        PoIBlob.transform.position = compoundPoI.toUnityVec3;
        LookAt(compoundPoI);
    }