using UnityEngine; namespace ECM2 { public static class Extensions { /// /// Return the square of the given value. /// public static int square(this int value) { return value * value; } /// /// Return the square of the given value. /// public static float square(this float value) { return value * value; } /// /// Checks whether value is near to zero within a tolerance. /// public static bool isZero(this float value) { const float kTolerance = 0.0000000001f; return Mathf.Abs(value) < kTolerance; } /// /// Returns a copy of given vector with only X component of the vector. /// public static Vector3 onlyX(this Vector3 vector3) { vector3.y = 0.0f; vector3.z = 0.0f; return vector3; } /// /// Returns a copy of given vector with only Y component of the vector. /// public static Vector3 onlyY(this Vector3 vector3) { vector3.x = 0.0f; vector3.z = 0.0f; return vector3; } /// /// Returns a copy of given vector with only Z component of the vector. /// public static Vector3 onlyZ(this Vector3 vector3) { vector3.x = 0.0f; vector3.y = 0.0f; return vector3; } /// /// Returns a copy of given vector with only X and Y components of the vector. /// public static Vector3 onlyXY(this Vector3 vector3) { vector3.z = 0.0f; return vector3; } /// /// Returns a copy of given vector with only X and Z components of the vector. /// public static Vector3 onlyXZ(this Vector3 vector3) { vector3.y = 0.0f; return vector3; } /// /// Checks whether vector is near to zero within a tolerance. /// public static bool isZero(this Vector2 vector2) { return vector2.sqrMagnitude < 9.99999943962493E-11; } /// /// Checks whether vector is near to zero within a tolerance. /// public static bool isZero(this Vector3 vector3) { return vector3.sqrMagnitude < 9.99999943962493E-11; } /// /// Checks whether vector is exceeding the magnitude within a small error tolerance. /// public static bool isExceeding(this Vector3 vector3, float magnitude) { // Allow 1% error tolerance, to account for numeric imprecision. const float kErrorTolerance = 1.01f; return vector3.sqrMagnitude > magnitude * magnitude * kErrorTolerance; } /// /// Returns a copy of given vector with a magnitude of 1, /// and outs its magnitude before normalization. /// /// If the vector is too small to be normalized a zero vector will be returned. /// public static Vector3 normalized(this Vector3 vector3, out float magnitude) { magnitude = vector3.magnitude; if (magnitude > 9.99999974737875E-06) return vector3 / magnitude; magnitude = 0.0f; return Vector3.zero; } /// /// Dot product of two vectors. /// public static float dot(this Vector3 vector3, Vector3 otherVector3) { return Vector3.Dot(vector3, otherVector3); } /// /// Returns a copy of given vector projected onto normal vector. /// public static Vector3 projectedOn(this Vector3 thisVector, Vector3 normal) { return Vector3.Project(thisVector, normal); } /// /// Returns a copy of given vector projected onto a plane defined by a normal orthogonal to the plane. /// public static Vector3 projectedOnPlane(this Vector3 thisVector, Vector3 planeNormal) { return Vector3.ProjectOnPlane(thisVector, planeNormal); } /// /// Returns a copy of given vector with its magnitude clamped to maxLength. /// public static Vector3 clampedTo(this Vector3 vector3, float maxLength) { return Vector3.ClampMagnitude(vector3, maxLength); } /// /// Returns a copy of given vector perpendicular to other vector. /// public static Vector3 perpendicularTo(this Vector3 thisVector, Vector3 otherVector) { return Vector3.Cross(thisVector, otherVector).normalized; } /// /// Returns a copy of given vector adjusted to be tangent to a specified surface normal relatively to given up axis. /// public static Vector3 tangentTo(this Vector3 thisVector, Vector3 normal, Vector3 up) { Vector3 r = thisVector.perpendicularTo(up); Vector3 t = normal.perpendicularTo(r); return t * thisVector.magnitude; } /// /// Transforms a vector to be relative to given transform. /// If isPlanar == true, the transform will be applied on the plane defined by world up axis. /// public static Vector3 relativeTo(this Vector3 vector3, Transform relativeToThis, bool isPlanar = true) { Vector3 forward = relativeToThis.forward; if (isPlanar) { Vector3 upAxis = Vector3.up; forward = forward.projectedOnPlane(upAxis); if (forward.isZero()) forward = Vector3.ProjectOnPlane(relativeToThis.up, upAxis); } Quaternion q = Quaternion.LookRotation(forward); return q * vector3; } /// /// Transforms a vector to be relative to given transform. /// If isPlanar == true, the transform will be applied on the plane defined by upAxis. /// public static Vector3 relativeTo(this Vector3 vector3, Transform relativeToThis, Vector3 upAxis, bool isPlanar = true) { Vector3 forward = relativeToThis.forward; if (isPlanar) { forward = Vector3.ProjectOnPlane(forward, upAxis); if (forward.isZero()) forward = Vector3.ProjectOnPlane(relativeToThis.up, upAxis); } Quaternion q = Quaternion.LookRotation(forward, upAxis); return q * vector3; } /// /// Clamps the given quaternion pitch rotation between the given minPitchAngle and maxPitchAngle. /// public static Quaternion clampPitch(this Quaternion quaternion, float minPitchAngle, float maxPitchAngle) { quaternion.x /= quaternion.w; quaternion.y /= quaternion.w; quaternion.z /= quaternion.w; quaternion.w = 1.0f; float pitch = Mathf.Clamp(2.0f * Mathf.Rad2Deg * Mathf.Atan(quaternion.x), minPitchAngle, maxPitchAngle); quaternion.x = Mathf.Tan(pitch * 0.5f * Mathf.Deg2Rad); return quaternion; } } }