using System.Collections.Generic; using System.Linq; using UnityEngine; namespace Rokid.UXR.Exentesions { /// /// Extension methods for Unity's Vector struct /// public static class VectorExtensions { public static Vector2 Mul(this Vector2 value, Vector2 scale) { return new Vector2(value.x * scale.x, value.y * scale.y); } public static Vector2 Div(this Vector2 value, Vector2 scale) { return new Vector2(value.x / scale.x, value.y / scale.y); } public static Vector3 Mul(this Vector3 value, Vector3 scale) { return new Vector3(value.x * scale.x, value.y * scale.y, value.z * scale.z); } public static Vector3 Div(this Vector3 value, Vector3 scale) { return new Vector3(value.x / scale.x, value.y / scale.y, value.z / scale.z); } public static Vector3 RotateAround(this Vector3 point, Vector3 pivot, Quaternion rotation) { return rotation * (point - pivot) + pivot; } public static Vector3 RotateAround(this Vector3 point, Vector3 pivot, Vector3 eulerAngles) { return RotateAround(point, pivot, Quaternion.Euler(eulerAngles)); } public static Vector3 TransformPoint(this Vector3 point, Vector3 translation, Quaternion rotation, Vector3 lossyScale) { return rotation * Vector3.Scale(lossyScale, point) + translation; } public static Vector3 InverseTransformPoint(this Vector3 point, Vector3 translation, Quaternion rotation, Vector3 lossyScale) { var scaleInv = new Vector3(1 / lossyScale.x, 1 / lossyScale.y, 1 / lossyScale.z); return Vector3.Scale(scaleInv, (Quaternion.Inverse(rotation) * (point - translation))); } public static Vector2 Average(this IEnumerable vectors) { float x = 0f; float y = 0f; int count = 0; foreach (var pos in vectors) { x += pos.x; y += pos.y; count++; } return new Vector2(x / count, y / count); } public static Vector3 Average(this IEnumerable vectors) { float x = 0f; float y = 0f; float z = 0f; int count = 0; foreach (var pos in vectors) { x += pos.x; y += pos.y; z += pos.z; count++; } return new Vector3(x / count, y / count, z / count); } public static Vector2 Average(this ICollection vectors) { int count = vectors.Count; if (count == 0) { return Vector2.zero; } float x = 0f; float y = 0f; foreach (var pos in vectors) { x += pos.x; y += pos.y; } return new Vector2(x / count, y / count); } public static Vector3 Average(this ICollection vectors) { int count = vectors.Count; if (count == 0) { return Vector3.zero; } float x = 0f; float y = 0f; float z = 0f; foreach (var pos in vectors) { x += pos.x; y += pos.y; z += pos.z; } return new Vector3(x / count, y / count, z / count); } public static Vector2 Median(this IEnumerable vectors) { var enumerable = vectors as Vector2[] ?? vectors.ToArray(); int count = enumerable.Length; return count == 0 ? Vector2.zero : enumerable.OrderBy(v => v.sqrMagnitude).ElementAt(count / 2); } public static Vector3 Median(this IEnumerable vectors) { var enumerable = vectors as Vector3[] ?? vectors.ToArray(); int count = enumerable.Length; return count == 0 ? Vector3.zero : enumerable.OrderBy(v => v.sqrMagnitude).ElementAt(count / 2); } public static Vector2 Median(this ICollection vectors) { int count = vectors.Count; return count == 0 ? Vector2.zero : vectors.OrderBy(v => v.sqrMagnitude).ElementAt(count / 2); } public static Vector3 Median(this ICollection vectors) { int count = vectors.Count; return count == 0 ? Vector3.zero : vectors.OrderBy(v => v.sqrMagnitude).ElementAt(count / 2); } public static bool IsValidVector(this Vector3 vector) { return !float.IsNaN(vector.x) && !float.IsNaN(vector.y) && !float.IsNaN(vector.z) && !float.IsInfinity(vector.x) && !float.IsInfinity(vector.y) && !float.IsInfinity(vector.z); } /// /// Determines if the distance between two vectors is within a given tolerance. /// /// The first vector. /// The second vector. /// The maximum distance that will cause this to return true. /// True if the distance between the two vectors is within the tolerance, false otherwise. public static bool CloseEnough(Vector3 v1, Vector3 v2, float distanceTolerance) { return Mathf.Abs(Vector3.Distance(v1, v2)) < distanceTolerance; } /// /// Get the relative mapping based on a source Vec3 and a radius for spherical mapping. /// /// The source Vector3 to be mapped to sphere /// This is a for the radius of the sphere public static Vector3 SphericalMapping(Vector3 source, float radius) { float circ = 2f * Mathf.PI * radius; float xAngle = (source.x / circ) * 360f; float yAngle = -(source.y / circ) * 360f; source.Set(0.0f, 0.0f, radius); Quaternion rot = Quaternion.Euler(yAngle, xAngle, 0.0f); source = rot * source; return source; } /// /// Get the relative mapping based on a source Vec3 and a radius for cylinder mapping. /// /// The source Vector3 to be mapped to cylinder /// This is a for the radius of the cylinder public static Vector3 CylindricalMapping(Vector3 source, float radius) { float circ = 2f * Mathf.PI * radius; float xAngle = (source.x / circ) * 360f; source.Set(0.0f, source.y, radius); Quaternion rot = Quaternion.Euler(0.0f, xAngle, 0.0f); source = rot * source; return source; } /// /// Get the relative mapping based on a source Vec3 and a radius for radial mapping. /// /// The source Vector3 to be mapped to cylinder /// The total range of the radial in degrees as a /// This is a for the radius of the radial /// The current row as a for the radial calculation /// The total rows as a for the radial calculation /// The current column as a for the radial calculation /// The total columns as a for the radial calculation public static Vector3 RadialMapping(Vector3 source, float radialRange, float radius, int row, int totalRows, int column, int totalColumns) { float radialCellAngle = radialRange / totalColumns; source.x = 0f; source.y = 0f; source.z = (radius / totalRows) * row; float yAngle = radialCellAngle * (column - (totalColumns * 0.5f)) + (radialCellAngle * .5f); Quaternion rot = Quaternion.Euler(0.0f, yAngle, 0.0f); source = rot * source; return source; } /// /// Randomized mapping based on a source Vec3 and a radius for randomization distance. /// /// The source Vector3 to be mapped to cylinder /// This is a for the radius of the cylinder public static Vector3 ScatterMapping(Vector3 source, float radius) { source.x = UnityEngine.Random.Range(-radius, radius); source.y = UnityEngine.Random.Range(-radius, radius); return source; } } }