13using System.Collections.Generic;
18 public static class Utils {
28 public static void Swap<T>(ref T a, ref T b) {
37 public static void Swap<T>(
this IList<T> list,
int a,
int b) {
46 public static void Swap<T>(
this T[] array,
int a,
int b) {
47 Swap(ref array[a], ref array[b]);
55 public static T[] Reverse<T>(
this T[] array) {
56 int mid = array.Length / 2;
69 public static void Reverse<T>(
this T[] array,
int start,
int length) {
70 int mid = start + length / 2;
72 int j = start + length;
81 public static void Shuffle<T>(
this IList<T> list) {
82 for (
int i = 0; i < list.Count; i++) {
83 Utils.Swap(list, i,
UnityEngine.Random.Range(i, list.Count));
87 public static void DoubleCapacity<T>(ref T[] array) {
88 T[] newArray =
new T[array.Length * 2];
89 Array.Copy(array, newArray, array.Length);
96 public static bool AreEqualUnordered<T>(IList<T> a, IList<T> b) {
97 var _count = Pool<Dictionary<T, int>>.Spawn();
101 foreach (var i
in a) {
106 if (!_count.TryGetValue(i, out count)) {
109 _count[i] = count + 1;
113 foreach (var i
in b) {
118 if (!_count.TryGetValue(i, out count)) {
121 _count[i] = count - 1;
125 if (_nullCount != 0) {
129 foreach (var pair
in _count) {
130 if (pair.Value != 0) {
138 Pool<Dictionary<T, int>>.Recycle(_count);
147 public static bool ImplementsInterface(
this Type type, Type ifaceType) {
148 Type[] intf = type.GetInterfaces();
149 for (
int i = 0; i < intf.Length; i++) {
150 if (intf[i] == ifaceType) {
157 public static bool IsActiveRelativeToParent(
this Transform obj, Transform parent) {
158 Assert.IsTrue(obj.IsChildOf(parent));
160 if (!obj.gameObject.activeSelf) {
163 if (obj.parent ==
null || obj.parent == parent) {
166 return obj.parent.IsActiveRelativeToParent(parent);
176 public static List<int> GetSortedOrder<T>(
this IList<T> list) where T : IComparable<T> {
177 Assert.IsNotNull(list);
179 List<int> ordering =
new List<int>();
180 for (
int i = 0; i < list.Count; i++) {
184 ordering.Sort((a, b) => list[a].CompareTo(list[b]));
193 public static void ApplyOrdering<T>(
this IList<T> list, List<int> ordering) {
194 Assert.IsNotNull(list);
195 Assert.IsNotNull(ordering);
196 Assert.AreEqual(list.Count, ordering.Count,
"List must be the same length as the ordering.");
198 List<T> copy = Pool<List<T>>.Spawn();
201 for (
int i = 0; i < list.Count; i++) {
202 list[i] = copy[ordering[i]];
206 Pool<List<T>>.Recycle(copy);
210 public static string MakeRelativePath(
string relativeTo,
string path) {
211 if (
string.IsNullOrEmpty(relativeTo))
throw new ArgumentNullException(
"relativeTo");
212 if (
string.IsNullOrEmpty(path))
throw new ArgumentNullException(
"path");
214 Uri relativeToUri =
new Uri(relativeTo);
215 Uri pathUri =
new Uri(path);
217 if (relativeToUri.Scheme != pathUri.Scheme) {
return path; }
219 Uri relativeUri = relativeToUri.MakeRelativeUri(pathUri);
220 string relativePath = Uri.UnescapeDataString(relativeUri.ToString());
222 if (pathUri.Scheme.Equals(
"file", StringComparison.InvariantCultureIgnoreCase)) {
223 relativePath = relativePath.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
233 public static T[] Require<T>(ref T[] arr) {
237 if (oldArr !=
null) {
238 for (var i = 0; i < oldArr.Length && i < arr.Length; i++) {
248 public static T[] Require<T>(ref T[] arr,
int length, Func<int, T> createAtIdx) {
249 if (arr ==
null || arr.Length != length) {
251 for (var i = 0; i < length; i++) {
252 arr[i] = createAtIdx(i);
267 public static T[] Require<T>(ref T[] arr,
int length) {
268 if (arr ==
null || arr.Length != length) {
271 if (oldArr !=
null) {
272 for (var i = 0; i < oldArr.Length && i < arr.Length; i++) {
290 public static T[] Require<T>(ref T[] arr, T item0) {
306 public static T[] Require<T>(ref T[] arr, T item0, T item1) {
308 arr[0] = item0; arr[1] = item1;
322 public static T[] Require<T>(ref T[] arr, T item0, T item1, T item2, T item3) {
324 arr[0] = item0; arr[1] = item1; arr[2] = item2; arr[3] = item3;
338 public static T[] Require<T>(ref T[] arr, T item0, T item1, T item2, T item3,
342 arr[0] = item0; arr[1] = item1; arr[2] = item2; arr[3] = item3;
350 public static List<T> RequireLen<T>(ref List<T> list,
int length) {
351 list = Require(ref list);
353 while (list.Count < length) { list.Add(
default(T)); }
363 public static List<T> Require<T>(ref List<T> list, T item0) {
364 list = Require(ref list);
376 public static List<T> Require<T>(ref List<T> list, T item0, T item1) {
377 list = Require(ref list);
387 public static List<T> Require<T>(ref List<T> list, T item, T[] items) {
388 list = Require(ref list);
391 list.AddRange(items);
403 public static T Require<T>(ref T t, Func<T> makeValidT) where T :
class {
404 if (t ==
default(T)) {
418 public static T? Require<T>(ref T? t, Func<T> makeValidT) where T :
struct {
433 public static T Require<T>(ref T t) where T :
class,
new() {
434 if (t ==
default(T)) {
442 public static T OrIfNull<T>(
this T t, T otherwise) where T :
class {
443 if (t ==
null) {
return otherwise; }
457 public static string TrimEnd(
this string str,
int characters) {
458 return str.Substring(0, Mathf.Max(0, str.Length - characters));
467 public static string TrimStart(
this string str,
int characters) {
468 return str.Substring(Mathf.Min(str.Length, characters));
476 public static string Capitalize(
this string str) {
478 if (
char.IsLetter(c)) {
479 return char.ToUpper(c) + str.Substring(1);
485 public static string[] GetNamePieces(
string value) {
486 var niceName = GenerateNiceName(value).ToLower();
487 return niceName.Split(
new char[] {
' '});
503 public static string GenerateNiceName(
string value) {
507 Func<char, bool> wordFunc = c => {
509 if (curr.Length > 0 &&
char.IsUpper(curr[0])) {
514 if (!
char.IsLetter(c)) {
522 Func<char, bool> acronymFunc = c => {
524 if (!
char.IsLetter(c)) {
529 if (
char.IsLower(c)) {
537 Func<char, bool> numberFunc = c => {
539 if (!
char.IsDigit(c)) {
547 Func<char, bool> fluffFunc = c => {
549 if (
char.IsDigit(c) ||
char.IsLetter(c)) {
557 Func<char, bool> currFunc =
null;
558 int currIndex = value.Length;
560 while (currIndex != 0) {
562 char c = value[currIndex];
564 if (currFunc !=
null && currFunc(c)) {
569 result =
" " + curr.Capitalize() + result;
573 if (acronymFunc(c)) {
574 currFunc = acronymFunc;
575 }
else if (wordFunc(c)) {
577 }
else if (numberFunc(c)) {
578 currFunc = numberFunc;
579 }
else if (fluffFunc(c)) {
580 currFunc = fluffFunc;
582 throw new Exception(
"Unexpected state, no function matched character " + c);
587 result = curr.Capitalize() + result;
590 result = result.Trim();
592 if (result.StartsWith(
"M ") || result.StartsWith(
"K ")) {
593 result = result.Substring(2);
596 return result.Trim();
599 public static int Count(
this string str,
char toCount) {
601 foreach (var c
in str) {
602 if (c == toCount) { count++; }
615 public static string ToArrayString<T>(
this IEnumerable<T> enumerable,
616 System.Func<T,
string> toStringFunc =
null)
618 var str =
"[" + typeof(T).Name +
": ";
619 bool addedFirstElement =
false;
620 foreach (var t
in enumerable) {
621 if (addedFirstElement) {
624 if (toStringFunc !=
null) {
625 if (t ==
null) { str +=
"<null>"; }
626 else { str += toStringFunc(t); }
629 if (t ==
null) { str +=
"<null>"; }
630 else { str += t.ToString(); }
633 addedFirstElement =
true;
641 public static string ToCodeArrayString(
this IEnumerable<Vector3> vectors,
string language =
null) {
642 var sb =
new System.Text.StringBuilder();
644 bool csharp =
false, python =
false;
645 if (language ==
null || language.Equals(
"csharp")) { csharp =
true; }
646 if (language.Equals(
"python")) { python =
true; }
649 if (csharp) { arrPrefix =
"new Vector3[] { \n"; }
650 else if (python) { arrPrefix =
"np.array([ \n"; }
651 sb.Append(arrPrefix);
654 if (csharp) { elPrefix =
" new Vector3("; }
655 else if (python) { elPrefix =
" ["; }
657 Func<float, string> f2s = f => f.ToString(
"R") +
"";
658 if (csharp) { f2s = f => f.ToString(
"R") +
"f"; }
659 else if (python) { f2s = f => (f * 1000).ToString(
"R") +
""; }
662 if (csharp) { compSep =
", "; }
663 else if (python) { compSep =
", "; }
666 if (csharp) { elPostfix =
"),\n"; }
667 else if (python) { elPostfix =
"],\n"; }
669 foreach (var v
in vectors) {
671 sb.Append(f2s(v[0]) + compSep);
672 sb.Append(f2s(v[1]) + compSep);
673 sb.Append(f2s(v[2]));
674 sb.Append(elPostfix);
685 return sb.ToString();
688 public static string ToCodeArrayString(
this IEnumerable<Quaternion> quats) {
689 var sb =
new System.Text.StringBuilder();
690 sb.Append(
"new Quaternion[] { \n");
691 foreach (var q
in quats) {
692 sb.Append(
" new Quaternion(");
693 sb.Append(q[0].ToString(
"R") +
"f, ");
694 sb.Append(q[1].ToString(
"R") +
"f, ");
695 sb.Append(q[2].ToString(
"R") +
"f, ");
696 sb.Append(q[3].ToString(
"R") +
"f),\n");
701 return sb.ToString();
708 public static class Math {
710 public const float PHI = 1.61803398875f;
713 public static int Repeat(
int x,
int m) {
715 return r < 0 ? r + m : r;
718 public static int Sign(
int value) {
721 }
else if (value > 0) {
733 public static Vector2 Perpendicular(
this Vector2 vector) {
734 return new Vector2(vector.y, -vector.x);
743 public static Vector3 Perpendicular(
this Vector3 vector) {
744 float x2 = vector.x * vector.x;
745 float y2 = vector.y * vector.y;
746 float z2 = vector.z * vector.z;
748 float mag0 = z2 + x2;
749 float mag1 = y2 + x2;
750 float mag2 = z2 + y2;
754 return new Vector3(-vector.z, 0, vector.x);
756 return new Vector3(0, vector.z, -vector.y);
760 return new Vector3(vector.y, -vector.x, 0);
762 return new Vector3(0, vector.z, -vector.y);
767 public static bool ContainsNaN(
this Vector3 v) {
768 return float.IsNaN(v.x)
773 public static bool IsBetween(
this float f,
float f0,
float f1) {
774 if (f0 > f1) Utils.Swap(ref f0, ref f1);
776 return f0 <= f && f <= f1;
779 public static bool IsBetween(
this double d,
double d0,
double d1) {
780 if (d0 > d1) Utils.Swap(ref d0, ref d1);
782 return d0 <= d && d <= d1;
788 public static Vector3 TimedExtrapolate(Vector3 a,
float aTime,
789 Vector3 b,
float bTime,
790 float extrapolatedTime) {
791 return Vector3.LerpUnclamped(a, b, extrapolatedTime.MapUnclamped(aTime, bTime, 0f, 1f));
797 public static Quaternion TimedExtrapolate(Quaternion a,
float aTime,
798 Quaternion b,
float bTime,
799 float extrapolatedTime) {
800 return Quaternion.SlerpUnclamped(a, b, extrapolatedTime.MapUnclamped(aTime, bTime, 0f, 1f));
807 public static bool NextTuple(IList<int> tuple,
int maxValue) {
808 return NextTuple(tuple, i => (i + 1) % maxValue);
822 public static bool NextTuple<T>(IList<T> tuple, Func<T, T> nextItem) where T : IComparable<T> {
823 int index = tuple.Count - 1;
825 T value = tuple[index];
826 T newValue = nextItem(value);
827 tuple[index] = newValue;
829 if (newValue.CompareTo(value) > 0) {
846 public static T[] ClearWithDefaults<T>(
this T[] arr) {
847 for (
int i = 0; i < arr.Length; i++) {
856 public static T[] ClearWith<T>(
this T[] arr, T value) {
857 for (
int i = 0; i < arr.Length; i++) {
865 public static void ForEach<T>(
this T[] arr, Action<T> doFunc)
868 foreach (var t
in arr) {
869 if (t !=
null) { doFunc(t); }
876 public static void ForEach<T>(
this object[] arr, Action<T> doFunc)
879 foreach (var obj
in arr) {
881 if (t !=
null) { doFunc(t); }
887 public static void Transform<T>(
this T[] arr, Func<T, T> mapFunc) {
888 for (var i = 0; i < arr.Length; i++) {
889 arr[i] = mapFunc(arr[i]);
895 public static bool ContainsValue<T>(
this T[] arr, T value) where T: IEquatable<T> {
896 for (var i = 0; i < arr.Length; i++) {
897 if (arr[i].Equals(value)) {
return true; }
903 public static bool Contains<T>(
this T[] arr, T value) {
904 return System.Array.IndexOf(arr, value) != -1;
911 public static void EnsureListExists<T>(ref List<T> list) {
913 list =
new List<T>();
917 public static void EnsureListCount<T>(
this List<T> list,
int count) {
918 if (list.Count == count)
return;
920 while (list.Count < count) {
921 list.Add(
default(T));
924 while (list.Count > count) {
925 list.RemoveAt(list.Count - 1);
929 public static void EnsureListCount<T>(
this List<T> list,
int count, Func<T> createT, Action<T> deleteT =
null) {
930 while (list.Count < count) {
934 while (list.Count > count) {
935 T tempT = list[list.Count - 1];
936 list.RemoveAt(list.Count - 1);
938 if (deleteT !=
null) {
947 public static void Add<T>(
this List<T> list, T t0, T t1) {
955 public static void Add<T>(
this List<T> list, T t0, T t1, T t2) {
964 public static void Add<T>(
this List<T> list, T t0, T t1, T t2, T t3) {
973 public static void ForEach<T>(
this List<T> list, Func<T, T> applyFunc) {
974 for (var i = 0; i < list.Count; i++) {
975 list[i] = applyFunc(list[i]);
982 public static List<T> Cleared<T>(
this List<T> list) {
983 list.Clear();
return list;
991 public static List<T> CopyFrom<T>(
this List<T> dst, List<T> src,
992 System.Action<T, T> copyElementFunc,
bool dontClear =
false)
993 where T: class, new()
995 if (!dontClear) { dst.Clear(); }
996 if (src ==
null) {
return dst; }
997 foreach (var srcT
in src) {
999 copyElementFunc(srcT, dstT);
1007 #region Nullable Utils
1012 public static T UnwrapOr<T>(
this T? nullable, T defaultValue)
1015 if (nullable.HasValue) {
1016 return nullable.Value;
1018 return defaultValue;
1025 #region Unity Utilities
1027 #region Unity Object Utils
1030 public static bool IsObjectPartOfPrefabAsset(
UnityEngine.Object obj) {
1032 #if UNITY_2018_3_OR_NEWER
1034 return UnityEditor.PrefabUtility.IsPartOfAnyPrefab(obj) &&
1053 return Resources.FindObjectsOfTypeAll<T>().
Query()
1057 if (IsObjectPartOfPrefabAsset(o)) {
return false; }
1066 #region Transform Utils
1071 public static ChildrenEnumerator GetChildren(
this Transform t) {
1072 return new ChildrenEnumerator(t);
1076 private Transform _t;
1083 _count = t.childCount;
1089 if (_idx < _count) _idx += 1;
1090 if (_idx == _count) {
return false; }
else {
return true; }
1093 get {
return _t ==
null ? null : _t.GetChild(_idx); }
1095 object System.Collections.IEnumerator.Current {
get {
return Current; } }
1098 _count = _t.childCount;
1103 public static List<Transform> GetSelfAndAllChildren(
this Transform t,
1104 bool breadthFirst =
false)
1106 var transforms =
new List<Transform>();
1108 GetAllChildren(t, transforms, breadthFirst);
1118 public static void GetAllChildren(
this Transform t, List<Transform> toFill,
1119 bool breadthFirst =
false) {
1121 var cursor = t; var cursorIdx = toFill.Count; var endIdx = cursorIdx;
1123 endIdx += addImmediateChildren(cursor, toFill);
1125 if (cursorIdx >= endIdx)
break;
1126 cursor = toFill[cursorIdx];
1130 addChildrenRecursive(t, toFill);
1133 private static void addChildrenRecursive(Transform t, List<Transform> list) {
1134 if (t ==
null) {
return; }
1135 foreach (var child
in t.GetChildren()) {
1137 addChildrenRecursive(child, list);
1140 private static int addImmediateChildren(Transform t, List<Transform> list) {
1141 int numChildren = 0;
1142 foreach (var child
in t.GetChildren()) {
1143 list.Add(child); numChildren++;
1149 public static Transform FindChild(
this Transform t,
string[] possibleNames,
1150 bool caseSensitive =
true)
1152 foreach (var name
in possibleNames) {
1153 var found = FindChild(t, name, caseSensitive);
1154 if (found !=
null) {
return found; }
1160 public static Transform FindChild(
this Transform t,
string withName,
1161 bool caseSensitive =
true)
1163 var children = Utils.Require(ref _b_findChildBuffer);
1165 t.GetAllChildren(children);
1166 if (!caseSensitive) { withName = withName.ToLower(); }
1167 foreach (var child
in children) {
1168 var name = child.name;
1169 if (!caseSensitive) { name = name.ToLower(); }
1170 if (child.name.Contains(withName)) {
return child; }
1174 private static List<Transform> _b_findChildBuffer =
new List<Transform>();
1180 public static void ResetLocalTransform(
this Transform t) {
1181 t.localPosition =
Vector3.zero;
1190 public static void ResetLocalPose(
this Transform t) {
1191 t.localPosition =
Vector3.zero;
1200 public static Vector3 GetClosestAxisDirection(
this Transform t, Vector3 toDir) {
1201 return t.rotation.GetClosestAxisDirection(toDir);
1210 public static void SetMatrix(
this Transform t, Matrix4x4 targetMatrix,
1211 bool allowAtEditTime =
false)
1213 var pose = targetMatrix.GetPose();
1214 var scale = targetMatrix.lossyScale;
1216 if (!Application.isPlaying && !allowAtEditTime) {
1217 throw new System.Exception(
"Transform.SetMatrix extension was called " +
1218 "at edit-time without `allowAtEditTime` set. Because attempting " +
1219 "to set the matrix of a Transform is a non-guaranteed operation and " +
1220 "would modify the Transform data at edit-time, you must opt-in to this " +
1221 "behavior (at your own risk).");
1225 if (t.parent !=
null) { scale = scale.CompDiv(t.parent.lossyScale); }
1226 t.localScale = scale;
1231 public static Matrix4x4 LocalFromWorld(
this Transform t) {
1232 return t.worldToLocalMatrix;
1236 public static Matrix4x4 WorldFromLocal(
this Transform t) {
1237 return t.localToWorldMatrix;
1242 public static void SetLossyScale(
this Transform t, Vector3 lossyScale) {
1243 var scale = lossyScale;
1244 if (t.parent !=
null) { scale = scale.CompDiv(t.parent.lossyScale); }
1245 t.localScale = scale;
1250 public static float Distance(Transform t0, Transform t1) {
1251 return Vector3.Distance(t0.position, t1.position);
1256 #region Component Utils
1287 public static void FindOwnedChildComponents<ComponentType, OwnerType>
1289 List<ComponentType> ownedComponents,
1290 bool includeInactiveObjects =
false)
1292 ownedComponents.Clear();
1293 Stack<Transform> toVisit = Pool<Stack<Transform>>.Spawn();
1294 List<ComponentType> componentsBuffer = Pool<List<ComponentType>>.Spawn();
1297 toVisit.Push(rootObj.transform);
1298 Transform curTransform;
1299 while (toVisit.Count > 0) {
1300 curTransform = toVisit.Pop();
1303 foreach (var child
in curTransform.GetChildren()) {
1307 if (child.GetComponent<OwnerType>() ==
null
1308 && (includeInactiveObjects || child.gameObject.activeInHierarchy)) {
1309 toVisit.Push(child);
1315 componentsBuffer.Clear();
1316 curTransform.GetComponents<ComponentType>(componentsBuffer);
1317 foreach (var component
in componentsBuffer) {
1318 ownedComponents.Add(component);
1323 Pool<Stack<Transform>>.Recycle(toVisit);
1325 componentsBuffer.Clear();
1326 Pool<List<ComponentType>>.Recycle(componentsBuffer);
1332 #region Orientation Utils
1344 public static void LookAwayFrom(
this Transform thisTransform, Transform transform) {
1345 thisTransform.rotation =
Quaternion.LookRotation(thisTransform.position - transform.position,
Vector3.up);
1356 public static void LookAwayFrom(
this Transform thisTransform,
1357 Transform transform, Vector3 upwards)
1359 thisTransform.rotation =
Quaternion.LookRotation(thisTransform.position - transform.position, upwards);
1367 public static Vector3 GetClosestAxisDirection(
this Quaternion q,
1370 var localDir = (
Quaternion.Inverse(q) * toDir).normalized;
1371 var closestAxis =
Vector3.right;
1372 var largestDot = -1f;
1373 for (var sign = 1; sign >= -1; sign -= 2) {
1374 for (var axis = 0; axis < 3; axis++) {
1375 var testAxis =
Vector3.zero; testAxis[axis] = 1f * sign;
1376 var testDot =
Vector3.Dot(localDir, testAxis);
1377 if (testDot > largestDot) {
1378 largestDot = testDot;
1379 closestAxis = testAxis;
1383 return (q * closestAxis).normalized;
1391 public static Vector3 GetClosestLocalAxisDirection(Vector3 toLocalDir)
1393 var closestAxis =
Vector3.right;
1394 var largestDot = -1f;
1395 for (var sign = 1; sign >= -1; sign -= 2) {
1396 for (var axis = 0; axis < 3; axis++) {
1397 var testAxis =
Vector3.zero; testAxis[axis] = 1f * sign;
1398 var testDot =
Vector3.Dot(toLocalDir, testAxis);
1399 if (testDot > largestDot) {
1400 largestDot = testDot;
1401 closestAxis = testAxis;
1405 return closestAxis.normalized;
1410 #region Vector3 Utils
1417 public static Vector3 ToVector3(
this Vector4 v4) {
1418 return new Vector3(v4.x, v4.y, v4.z);
1425 public static Vector3 InLocalSpace(
this Vector3 v, Transform t) {
1426 return t.InverseTransformPoint(v);
1432 public static Vector4 WithW(
this Vector3 v,
float w) {
1433 return new Vector4(v.x, v.y, v.z, w);
1438 public static Vector3 Pivot(
this Vector3 point, Vector3 pivot,
1439 Quaternion rotation)
1441 var pointFromPivot = point - pivot;
1442 var rotatedPointFromPivot = rotation * pointFromPivot;
1443 return pivot + rotatedPointFromPivot;
1453 public static Quaternion GetAxisFromToRotation(
this Vector3 v, Vector3 toDir,
1454 Vector3 axis, out
float angle,
float? minAngle =
null,
1455 float? maxAngle =
null)
1457 v =
Vector3.ProjectOnPlane(v, axis);
1458 var toDir_axis =
Vector3.ProjectOnPlane(toDir, axis);
1459 angle =
Vector3.SignedAngle(v, toDir_axis, axis);
1460 if (minAngle !=
null) { angle = Mathf.Max(minAngle.Value, angle); }
1461 if (maxAngle !=
null) { angle = Mathf.Min(maxAngle.Value, angle); }
1462 var rotation =
Quaternion.AngleAxis(angle, axis);
1470 public static Quaternion GetAxisFromToRotation(
this Vector3 v, Vector3 toDir,
1471 Vector3 axis,
float? minAngle =
null,
float? maxAngle =
null)
1473 var unusedAngle = 0f;
1474 return GetAxisFromToRotation(v, toDir, axis, out unusedAngle, minAngle,
1478 public static Vector3 GetCentroid(
1479 System.Action<List<Vector3>> fillPoints)
1481 var points = Pool<List<Vector3>>.Spawn().Cleared();
1483 if (points.Count == 0) {
return default(Vector3); }
1486 for (var i = 0; i < points.Count; i++) {
1487 centroid += points[i];
1489 centroid /= points.Count;
1494 public static Vector3 GetCentroid(Vector3[] points)
1497 for (var i = 0; i < points.Length; i++) {
1498 centroid += points[i];
1500 centroid /= points.Length;
1505 public static Vector3 ConstrainToNormal(
this Vector3 direction,
1506 Vector3 normalDirection,
float maxAngle)
1508 if (maxAngle <= 0f)
return normalDirection.normalized * direction.magnitude;
1509 if (maxAngle >= 180f)
return direction;
1510 float angle = Mathf.Acos(Mathf.Clamp(
1511 Vector3.Dot(direction.normalized, normalDirection.normalized),
1512 -1f, 1f)) * Mathf.Rad2Deg;
1513 return Vector3.Slerp(direction.normalized, normalDirection.normalized,
1514 (angle - maxAngle) / angle) * direction.magnitude;
1519 #region Quaternion Utils
1521 public static bool ContainsNaN(
this Quaternion q) {
1522 return float.IsNaN(q.x)
1525 ||
float.IsNaN(q.w);
1534 public static Vector3 ToAngleAxisVector(
this Quaternion q) {
1537 q.ToAngleAxis(out angle, out axis);
1538 return axis * angle;
1545 public static Quaternion QuaternionFromAngleAxisVector(Vector3 angleAxisVector) {
1547 return Quaternion.AngleAxis(angleAxisVector.magnitude, angleAxisVector);
1555 public static Quaternion ToNormalized(
this Quaternion quaternion) {
1556 float x = quaternion.x, y = quaternion.y, z = quaternion.z, w = quaternion.w;
1557 float magnitude = Mathf.Sqrt(x * x + y * y + z * z + w * w);
1559 if (Mathf.Approximately(magnitude, 0f)) {
1563 return new Quaternion(x / magnitude, y / magnitude, z / magnitude, w / magnitude);
1575 public static Quaternion FaceTargetWithoutTwist(Vector3 fromPosition,
1576 Vector3 targetPosition,
1577 bool flip180 =
false) {
1578 return FaceTargetWithoutTwist(fromPosition, targetPosition,
Vector3.up, flip180);
1589 public static Quaternion FaceTargetWithoutTwist(Vector3 fromPosition,
1590 Vector3 targetPosition,
1591 Vector3 upwardDirection,
1592 bool flip180 =
false) {
1593 Vector3 objToTarget = targetPosition - fromPosition;
1594 return Quaternion.LookRotation((flip180 ? -1 : 1) * objToTarget,
1599 public static Quaternion Flipped(
this Quaternion q) {
1600 return new Quaternion(-q.x, -q.y, -q.z, -q.w);
1604 public static Quaternion MirroredX(
this Quaternion q) {
1609 public static Quaternion MirroredY(
this Quaternion q) {
1614 public static Quaternion MirroredZ(
this Quaternion q) {
1634 public static void CompressQuatToBytes(Quaternion quat,
1640 float abs_w = Mathf.Abs(quat.w);
1641 float abs_x = Mathf.Abs(quat.x);
1642 float abs_y = Mathf.Abs(quat.y);
1643 float abs_z = Mathf.Abs(quat.z);
1645 float largest_value = abs_x;
1647 if (abs_y > largest_value) {
1649 largest_value = abs_y;
1651 if (abs_z > largest_value) {
1653 largest_value = abs_z;
1655 if (abs_w > largest_value) {
1657 largest_value = abs_w;
1659 if (quat[largest] >= 0f) {
1660 a = quat[(largest + 1) % 4];
1661 b = quat[(largest + 2) % 4];
1662 c = quat[(largest + 3) % 4];
1665 a = -quat[(largest + 1) % 4];
1666 b = -quat[(largest + 2) % 4];
1667 c = -quat[(largest + 3) % 4];
1671 const float minimum = -1.0f / 1.414214f;
1672 const float maximum = +1.0f / 1.414214f;
1673 const float delta = maximum - minimum;
1674 const uint maxIntegerValue = (1 << 10) - 1;
1675 const float maxIntegerValueF = (float)maxIntegerValue;
1676 float normalizedValue;
1679 uint sentData = ((uint)largest) << 30;
1681 normalizedValue = Mathf.Clamp01((a - minimum) / delta);
1682 integerValue = (uint)Mathf.Floor(normalizedValue * maxIntegerValueF + 0.5f);
1683 sentData = sentData | ((integerValue & maxIntegerValue) << 20);
1685 normalizedValue = Mathf.Clamp01((b - minimum) / delta);
1686 integerValue = (uint)Mathf.Floor(normalizedValue * maxIntegerValueF + 0.5f);
1687 sentData = sentData | ((integerValue & maxIntegerValue) << 10);
1689 normalizedValue = Mathf.Clamp01((c - minimum) / delta);
1690 integerValue = (uint)Mathf.Floor(normalizedValue * maxIntegerValueF + 0.5f);
1691 sentData = sentData | (integerValue & maxIntegerValue);
1693 BitConverterNonAlloc.GetBytes(sentData, buffer, ref offset);
1709 public static Quaternion DecompressBytesToQuat(
byte[] bytes, ref
int offset) {
1710 uint readData = BitConverterNonAlloc.ToUInt32(bytes, ref offset);
1712 int largest = (int)(readData >> 30);
1715 const float minimum = -1.0f / 1.414214f;
1716 const float maximum = +1.0f / 1.414214f;
1717 const float delta = maximum - minimum;
1718 const uint maxIntegerValue = (1 << 10) - 1;
1719 const float maxIntegerValueF = (float)maxIntegerValue;
1721 float normalizedValue;
1723 integerValue = (readData >> 20) & maxIntegerValue;
1724 normalizedValue = (float)integerValue / maxIntegerValueF;
1725 a = (normalizedValue * delta) + minimum;
1727 integerValue = (readData >> 10) & maxIntegerValue;
1728 normalizedValue = (float)integerValue / maxIntegerValueF;
1729 b = (normalizedValue * delta) + minimum;
1731 integerValue = readData & maxIntegerValue;
1732 normalizedValue = (float)integerValue / maxIntegerValueF;
1733 c = (normalizedValue * delta) + minimum;
1736 float d = Mathf.Sqrt(1f - a * a - b * b - c * c);
1738 value[(largest + 1) % 4] = a;
1739 value[(largest + 2) % 4] = b;
1740 value[(largest + 3) % 4] = c;
1749 #region Matrix4x4 Utils
1751 public static Matrix4x4 CompMul(Matrix4x4 m,
float f) {
1752#if UNITY_2017_1_OR_NEWER
1753 return new Matrix4x4(m.GetColumn(0) * f,
1756 m.GetColumn(3) * f);
1758 Matrix4x4 toReturn = m;
1759 for (
int i = 0; i < 4; i++) {
1760 toReturn.SetColumn(i, toReturn.GetColumn(i) * f);
1767 public static Vector3 GetTranslation(
this Matrix4x4 m) {
1768 return m.GetColumn(3);
1771 public static Vector3 GetVector3(
this Matrix4x4 m) {
1772 return m.GetColumn(3);
1775 public static Quaternion GetQuaternion_LookRot(
this Matrix4x4 m) {
1776 if (m.GetColumn(2) == m.GetColumn(1)) {
return Quaternion.identity; }
1777 return Quaternion.LookRotation(m.GetColumn(2), m.GetColumn(1));
1780 public static Quaternion GetQuaternion_CopySign(
this Matrix4x4 m) {
1790 q.w = Mathf.Sqrt( Mathf.Max( 0, 1 + m.m00 + m.m11 + m.m22 ) ) / 2;
1792 q.x = Mathf.Sqrt( Mathf.Max( 0, 1 + m.m00 - m.m11 - m.m22 ) ) / 2;
1793 q.y = Mathf.Sqrt( Mathf.Max( 0, 1 - m.m00 + m.m11 - m.m22 ) ) / 2;
1794 q.z = Mathf.Sqrt( Mathf.Max( 0, 1 - m.m00 - m.m11 + m.m22 ) ) / 2;
1795 q.x = copySign(q.x, m.m21 - m.m12);
1796 q.y = copySign(q.y, m.m02 - m.m20);
1797 q.z = copySign(q.z, m.m10 - m.m01);
1810 private static float copySign(
float toValue,
float signSource) {
1811 if (signSource == 0f) {
throw new System.InvalidOperationException(
1812 "signSource of zero is not supported in copySign."); }
1813 return Mathf.Abs(toValue) * Mathf.Sign(signSource);
1818 public static Quaternion GetQuaternion_Manual(
this Matrix4x4 m) {
1848 var trace = m.m00 + m.m11 + m.m22;
1850 var s = 0.5f / Mathf.Sqrt(trace + 1.0f);
1852 q.x = (m.m21 - m.m12) * s;
1853 q.y = (m.m02 - m.m20) * s;
1854 q.z = (m.m10 - m.m01) * s;
1857 if (m.m00 > m.m11 && m.m00 > m.m22) {
1858 var s = 2.0f * Mathf.Sqrt(1f + m.m00 - m.m11 - m.m22);
1859 q.w = (m.m21 - m.m12) / s;
1861 q.y = (m.m01 + m.m10) / s;
1862 q.z = (m.m02 + m.m20) / s;
1864 else if (m.m11 > m.m22) {
1865 var s = 2.0f * Mathf.Sqrt(1f + m.m11 - m.m00 - m.m22);
1866 q.w = (m.m02 - m.m20) / s;
1867 q.x = (m.m01 + m.m10) / s;
1869 q.z = (m.m12 + m.m21) / s;
1872 var s = 2.0f * Mathf.Sqrt(1f + m.m22 - m.m00 - m.m11);
1873 q.w = (m.m10 - m.m01) / s;
1874 q.x = (m.m02 + m.m20) / s;
1875 q.y = (m.m12 + m.m21) / s;
1883 public static Quaternion GetQuaternion_SpacePuppy(
this Matrix4x4 m) {
1886 q.w = Mathf.Sqrt(Mathf.Max(0, 1 + m[0,0] + m[1,1] + m[2,2])) / 2;
1887 q.x = Mathf.Sqrt(Mathf.Max(0, 1 + m[0,0] - m[1,1] - m[2,2])) / 2;
1888 q.y = Mathf.Sqrt(Mathf.Max(0, 1 - m[0,0] + m[1,1] - m[2,2])) / 2;
1889 q.z = Mathf.Sqrt(Mathf.Max(0, 1 - m[0,0] - m[1,1] + m[2,2])) / 2;
1890 q.x *= Mathf.Sign(q.x *(m[2,1] - m[1,2]));
1891 q.y *= Mathf.Sign(q.y *(m[0,2] - m[2,0]));
1892 q.z *= Mathf.Sign(q.z *(m[1,0] - m[0,1]));
1901 public static Quaternion GetQuaternion(
this Matrix4x4 m) {
1902 var forward = m.MultiplyVector(
Vector3.forward);
1903 var up = m.MultiplyVector(
Vector3.up);
1910 public static void FillMatrixFromQuaternion(
this Quaternion q,
1911 ref Vector3[] matrix) {
1912 matrix[0] = q *
Vector3.right;
1914 matrix[2] = q *
Vector3.forward;
1923 public static Vector3 GetClosestAxisDirection(
this Matrix4x4 m, Vector3 toDir) {
1924 var localDir = (m.inverse.MultiplyVector(toDir)).normalized;
1925 var closestAxis =
Vector3.right;
1926 var largestDot = -1f;
1927 for (var sign = 1; sign >= -1; sign -= 2) {
1928 for (var axis = 0; axis < 2; axis++) {
1929 var testAxis =
Vector3.zero; testAxis[axis] = 1f * sign;
1930 var testDot =
Vector3.Dot(localDir, testAxis);
1931 if (testDot > largestDot) {
1932 largestDot = testDot;
1933 closestAxis = testAxis;
1937 return (m.MultiplyVector(closestAxis)).normalized;
1941 public static Vector3 GetPosition(
this Matrix4x4 m) {
1942 return m.MultiplyPoint3x4(
Vector3.zero);
1945 public static Vector3 GetRight(
this Matrix4x4 m) {
1946 return m.MultiplyVector(
Vector3.right);
1949 public static Vector3 GetUp(
this Matrix4x4 m) {
1950 return m.MultiplyVector(
Vector3.up);
1953 public static Vector3 GetForward(
this Matrix4x4 m) {
1954 return m.MultiplyVector(
Vector3.forward);
1957 public static Vector3 GetAxis(
this Matrix4x4 m,
int i) {
1958 if (i == 0) {
return m.GetRight(); }
1959 if (i == 1) {
return m.GetUp(); }
1960 if (i == 2) {
return m.GetForward(); }
1961 throw new System.InvalidOperationException(
"Invalid axis index " + i);
1970 public static Matrix4x4 Pivot(
this Matrix4x4 m, Quaternion q) {
1971 var origPos = m.GetPosition();
1972 var toTranslateBack = Matrix4x4.Rotate(q) * m;
1973 var newPos = toTranslateBack.GetPosition();
1974 var translatedBack = Matrix4x4.Translate(origPos - newPos) * toTranslateBack;
1975 return translatedBack;
1982 public static Matrix4x4 Pivot(
this Matrix4x4 m, Quaternion q, Vector3 p) {
1985 var preservePos = p;
1986 var preservePos_local = m.inverse.MultiplyPoint3x4(p);
1987 var toTranslateBack = Matrix4x4.Rotate(q) * m;
1988 var newPos = toTranslateBack.MultiplyPoint3x4(preservePos_local);
1989 var translatedBack = Matrix4x4.Translate(preservePos - newPos) *
1991 return translatedBack;
1996 public static Matrix4x4 PivotTo(
this Matrix4x4 m, Quaternion q) {
1997 var origPos = m.GetPosition();
1998 var origRot = m.GetQuaternion();
1999 var toTranslateBack = Matrix4x4.Rotate(q *
Quaternion.Inverse(origRot)) *
2001 var newPos = toTranslateBack.GetPosition();
2002 var translatedBack = Matrix4x4.Translate(origPos - newPos) * toTranslateBack;
2003 return translatedBack;
2008 #region Physics Utils
2017 public static void IgnoreCollisions(GameObject first, GameObject second,
2018 bool ignore =
true) {
2019 if (first ==
null || second ==
null)
2022 var firstColliders = Pool<List<Collider>>.Spawn(); firstColliders.Clear();
2023 var secondColliders = Pool<List<Collider>>.Spawn(); secondColliders.Clear();
2025 first.GetComponentsInChildren(firstColliders);
2026 second.GetComponentsInChildren(secondColliders);
2028 for (
int i = 0; i < firstColliders.Count; ++i) {
2029 for (
int j = 0; j < secondColliders.Count; ++j) {
2030 if (firstColliders[i] != secondColliders[j] &&
2031 firstColliders[i].enabled && secondColliders[j].enabled) {
2032 Physics.IgnoreCollision(firstColliders[i], secondColliders[j], ignore);
2038 firstColliders.Clear(); Pool<List<Collider>>.Recycle(firstColliders);
2039 secondColliders.Clear(); Pool<List<Collider>>.Recycle(secondColliders);
2045 #region Collider Utils
2047 #region Capsule Collider Utils
2049 public static Vector3 GetDirection(
this CapsuleCollider capsule) {
2050 switch (capsule.direction) {
2053 case 2:
default:
return Vector3.forward;
2057 public static float GetEffectiveRadius(
this CapsuleCollider capsule) {
2058 return capsule.radius * capsule.GetEffectiveRadiusMultiplier();
2061 public static float GetEffectiveRadiusMultiplier(
this CapsuleCollider capsule) {
2062 var effRadiusMult = 0f;
2063 switch (capsule.direction) {
2065 effRadiusMult = Swizzle.Swizzle.yz(capsule.transform.lossyScale).CompMax();
2068 effRadiusMult = Swizzle.Swizzle.xz(capsule.transform.lossyScale).CompMax();
2072 effRadiusMult = Swizzle.Swizzle.xy(capsule.transform.lossyScale).CompMax();
2075 return effRadiusMult;
2078 public static void GetCapsulePoints(
this CapsuleCollider capsule, out Vector3 a,
2080 var effRadiusMult = capsule.GetEffectiveRadiusMultiplier();
2081 var capsuleDir = capsule.GetDirection();
2083 a = capsuleDir * (capsule.height / 2f);
2086 a = capsule.transform.TransformPoint(a);
2087 b = capsule.transform.TransformPoint(b);
2089 a -= capsuleDir * effRadiusMult * capsule.radius;
2090 b += capsuleDir * effRadiusMult * capsule.radius;
2097 public static void SetCapsulePoints(
this CapsuleCollider capsule, Vector3 a, Vector3 b) {
2098 capsule.center =
Vector3.zero;
2100 capsule.transform.position = (a + b) / 2F;
2102 Vector3 capsuleDirection = capsule.GetDirection();
2104 Vector3 capsuleDirWorldSpace = capsule.transform.TransformDirection(capsuleDirection);
2105 Quaternion necessaryRotation =
Quaternion.FromToRotation(capsuleDirWorldSpace, a - capsule.transform.position);
2106 capsule.transform.rotation = necessaryRotation * capsule.transform.rotation;
2108 Vector3 aCapsuleSpace = capsule.transform.InverseTransformPoint(a);
2109 float capsuleSpaceDistToA = aCapsuleSpace.magnitude;
2110 capsule.height = (capsuleSpaceDistToA + capsule.radius) * 2;
2126 public static void FindColliders<T>(GameObject obj, List<T> colliders,
2127 bool includeInactiveObjects =
false)
2128 where T : Collider {
2130 Stack<Transform> toVisit = Pool<Stack<Transform>>.Spawn();
2131 List<T> collidersBuffer = Pool<List<T>>.Spawn();
2136 toVisit.Push(obj.transform);
2137 Transform curTransform;
2138 while (toVisit.Count > 0) {
2139 curTransform = toVisit.Pop();
2142 foreach (var child
in curTransform.GetChildren()) {
2145 if (child.GetComponent<Rigidbody>() ==
null
2146 && (includeInactiveObjects || child.gameObject.activeSelf)) {
2147 toVisit.Push(child);
2153 collidersBuffer.Clear();
2154 curTransform.GetComponents<T>(collidersBuffer);
2155 foreach (var collider
in collidersBuffer) {
2156 colliders.Add(collider);
2161 Pool<Stack<Transform>>.Recycle(toVisit);
2163 collidersBuffer.Clear();
2164 Pool<List<T>>.Recycle(collidersBuffer);
2172 public static Color WithAlpha(
this Color color,
float alpha) {
2173 return new Color(color.r, color.g, color.b, alpha);
2180 public static Color ParseHtmlColorString(
string htmlString) {
2182 if (!ColorUtility.TryParseHtmlString(htmlString, out color)) {
2183 throw new ArgumentException(
"The string [" + htmlString +
"] is not a valid color code. Valid color codes include:\n" +
2188 "For more information, see the documentation for ColorUtility.TryParseHtmlString.");
2198 public static Color LerpHSV(
this Color color,
Color towardsColor,
float t) {
2200 Color.RGBToHSV(color, out h0, out s0, out v0);
2203 Color.RGBToHSV(towardsColor, out h1, out s1, out v1);
2206 if (h0 - h1 < -0.5f) h0 += 1f;
2207 if (h0 - h1 > 0.5f) h1 += 1f;
2208 float hL = Mathf.Lerp(h0, h1, t) % 1f;
2210 float sL = Mathf.Lerp(s0, s1, t);
2211 float vL = Mathf.Lerp(v0, v1, t);
2212 return Color.HSVToRGB(hL, sL, vL);
2218 public static float LerpHue(
float h0,
float h1,
float t) {
2220 if (h0 < 0f) h0 = 1f - (-h0 % 1f);
2221 if (h1 < 0f) h1 = 1f - (-h1 % 1f);
2222 if (h0 > 1f) h0 = h0 % 1f;
2223 if (h1 > 1f) h1 = h1 % 1f;
2225 if (h0 - h1 < -0.5f) h0 += 1f;
2226 if (h0 - h1 > 0.5f) h1 += 1f;
2227 return Mathf.Lerp(h0, h1, t) % 1f;
2232 public static Vector3 HSVToRGB(Vector3 hsv) {
2233 var c =
Color.HSVToRGB(hsv.x, hsv.y, hsv.z);
2234 return new Vector3(c.r, c.g, c.b);
2241 public static void DrawCircle(Vector3 center,
2247 bool depthTest =
true) {
2249 DrawArc(360, center, planeA, normal, radius, color, quality);
2254 public static void DrawArc(
float arc,
2262 Gizmos.color = color;
2264 float deltaAngle = arc / quality;
2265 Vector3 thisPoint = center + forward * radius;
2267 for (
float angle = 0; Mathf.Abs(angle) <= Mathf.Abs(arc); angle += deltaAngle) {
2268 float cosAngle = Mathf.Cos(angle * Constants.DEG_TO_RAD);
2269 float sinAngle = Mathf.Sin(angle * Constants.DEG_TO_RAD);
2270 nextPoint.x = center.x + radius * (cosAngle * forward.x + sinAngle * right.x);
2271 nextPoint.y = center.y + radius * (cosAngle * forward.y + sinAngle * right.y);
2272 nextPoint.z = center.z + radius * (cosAngle * forward.z + sinAngle * right.z);
2273 Gizmos.DrawLine(thisPoint, nextPoint);
2274 thisPoint = nextPoint;
2278 public static void DrawCone(Vector3 origin,
2285 bool depthTest =
true) {
2287 float step = height / quality;
2288 for (
float q = step; q <= height; q += step) {
2289 DrawCircle(origin + direction * q, direction, Mathf.Tan(angle * Constants.DEG_TO_RAD) * q, color, quality * 8, duration, depthTest);
2295 #region Texture Utils
2297 private static TextureFormat[] _incompressibleFormats =
new TextureFormat[] {
2299 TextureFormat.EAC_R,
2300 TextureFormat.EAC_R_SIGNED,
2301 TextureFormat.EAC_RG,
2302 TextureFormat.EAC_RG_SIGNED
2303 #if !UNITY_2018_2_OR_NEWER
2305 TextureFormat.ETC_RGB4_3DS,
2306 TextureFormat.ETC_RGBA8_3DS
2313 public static bool IsCompressible(TextureFormat format) {
2318 return Array.IndexOf(_incompressibleFormats, format) < 0;
2328 public static float Area(
this Rect rect) {
2329 return rect.width * rect.height;
2336 public static Rect Extrude(
this Rect r,
float margin) {
2337 return new Rect(r.x - margin, r.y - margin,
2338 r.width + (margin * 2f), r.height + (margin * 2f));
2345 public static Rect PadInner(
this Rect r,
float padding) {
2346 return PadInner(r, padding, padding, padding, padding);
2355 public static Rect PadInner(
this Rect r,
float padTop,
float padBottom,
2356 float padLeft,
float padRight) {
2357 var x = r.x + padLeft;
2358 var y = r.y + padBottom;
2359 var w = r.width - padRight - padLeft;
2360 var h = r.height - padTop - padBottom;
2362 x = r.x + (padLeft / (padLeft + padRight)) * r.width;
2366 y = r.y + (padBottom / (padBottom + padTop)) * r.height;
2369 return new Rect(x, y, w, h);
2374 public static Rect PadTop(
this Rect r,
float padding) {
2375 return PadInner(r, padding, 0f, 0f, 0f);
2378 public static Rect PadBottom(
this Rect r,
float padding) {
2379 return PadInner(r, 0f, padding, 0f, 0f);
2382 public static Rect PadLeft(
this Rect r,
float padding) {
2383 return PadInner(r, 0f, 0f, padding, 0f);
2386 public static Rect PadRight(
this Rect r,
float padding) {
2387 return PadInner(r, 0f, 0f, 0f, padding);
2392 #region Pad, With Out
2398 public static Rect PadTop(
this Rect r,
float padding, out Rect marginRect) {
2399 marginRect = r.TakeTop(padding);
2400 return PadTop(r, padding);
2407 public static Rect PadBottom(
this Rect r,
float padding, out Rect marginRect) {
2408 marginRect = r.TakeBottom(padding);
2409 return PadBottom(r, padding);
2416 public static Rect PadLeft(
this Rect r,
float padding, out Rect marginRect) {
2417 marginRect = r.TakeLeft(padding);
2418 return PadLeft(r, padding);
2425 public static Rect PadRight(
this Rect r,
float padding, out Rect marginRect) {
2426 marginRect = r.TakeRight(padding);
2427 return PadRight(r, padding);
2432 #region Pad Percent, Two Sides
2434 public static Rect PadTopBottomPercent(
this Rect r,
float padPercent) {
2435 float padHeight = r.height * padPercent;
2436 return r.PadInner(padHeight, padHeight, 0f, 0f);
2439 public static Rect PadLeftRightPercent(
this Rect r,
float padPercent) {
2440 float padWidth = r.width * padPercent;
2441 return r.PadInner(0f, 0f, padWidth, padWidth);
2448 public static Rect PadTopPercent(
this Rect r,
float padPercent) {
2449 float padHeight = r.height * padPercent;
2450 return PadTop(r, padHeight);
2453 public static Rect PadBottomPercent(
this Rect r,
float padPercent) {
2454 float padHeight = r.height * padPercent;
2455 return PadBottom(r, padHeight);
2458 public static Rect PadLeftPercent(
this Rect r,
float padPercent) {
2459 return PadLeft(r, r.width * padPercent);
2462 public static Rect PadRightPercent(
this Rect r,
float padPercent) {
2463 return PadRight(r, r.width * padPercent);
2468 #region Take, No Out
2474 public static Rect TakeTop(
this Rect r,
float heightFromTop) {
2475 heightFromTop = Mathf.Clamp(heightFromTop, 0f, r.height);
2476 return new Rect(r.x, r.y + r.height - heightFromTop, r.width, heightFromTop);
2483 public static Rect TakeBottom(
this Rect r,
float heightFromBottom) {
2484 heightFromBottom = Mathf.Clamp(heightFromBottom, 0f, r.height);
2485 return new Rect(r.x, r.y, r.width, heightFromBottom);
2492 public static Rect TakeLeft(
this Rect r,
float widthFromLeft) {
2493 widthFromLeft = Mathf.Clamp(widthFromLeft, 0f, r.width);
2494 return new Rect(r.x, r.y, widthFromLeft, r.height);
2501 public static Rect TakeRight(
this Rect r,
float widthFromRight) {
2502 widthFromRight = Mathf.Clamp(widthFromRight, 0f, r.width);
2503 return new Rect(r.x + r.width - widthFromRight, r.y, widthFromRight, r.height);
2508 #region Take, With Out
2514 public static Rect TakeTop(
this Rect r,
float padding, out Rect theRest) {
2515 theRest = r.PadTop(padding);
2516 return r.TakeTop(padding);
2523 public static Rect TakeBottom(
this Rect r,
float padding, out Rect theRest) {
2524 theRest = r.PadBottom(padding);
2525 return r.TakeBottom(padding);
2532 public static Rect TakeLeft(
this Rect r,
float padding, out Rect theRest) {
2533 theRest = r.PadLeft(padding);
2534 return r.TakeLeft(padding);
2541 public static Rect TakeRight(
this Rect r,
float padding, out Rect theRest) {
2542 theRest = r.PadRight(padding);
2543 return r.TakeRight(padding);
2552 public static Rect TakeHorizontal(
this Rect r,
float lineHeight,
2554 bool fromTop =
true) {
2555 theRest =
new Rect(r.x, (fromTop ? r.y + lineHeight : r.y), r.width, r.height - lineHeight);
2556 return new Rect(r.x, (fromTop ? r.y : r.y + r.height - lineHeight), r.width, lineHeight);
2559 public static void SplitHorizontallyWithLeft(
this Rect rect, out Rect left, out Rect right,
float leftWidth) {
2561 left.width = leftWidth;
2563 right.x += left.width;
2564 right.width = rect.width - leftWidth;
2576 public static HorizontalLineRectEnumerator TakeAllLines(
this Rect r,
int numLines) {
2577 return new HorizontalLineRectEnumerator(r, numLines);
2608 List<Rect> rects = Pool<List<Rect>>.Spawn();
2611 foreach (var
rect in this) {
2618 Pool<List<Rect>>.Recycle(rects);
2629 #region Leap Utilities
2637 public static Pose From(
this Vector3 position,
Pose fromPose) {
2638 return new Pose(position, fromPose.
rotation).From(fromPose);
2641 public static Pose GetPose(
this Rigidbody rigidbody) {
2642 return new Pose(rigidbody.position, rigidbody.rotation);
2648 public static Pose MirroredX(
this Pose pose) {
2649 var v = pose.position;
2650 var q = pose.rotation;
2651 return new Pose(
new Vector3(-v.x, v.y, v.z),
2652 new Quaternion(-q.x, q.y, q.z, -q.w).Flipped());
2658 public static Pose Negated(
this Pose pose) {
2659 var v = pose.position;
2660 var q = pose.rotation;
2661 return new Pose(
new Vector3(-v.x, -v.y, -v.z),
2666 public static Pose Pivot(
this Pose p, Quaternion q) {
2667 var origPos = p.position;
2668 var toTranslateBack = q * p;
2669 var newPos = toTranslateBack.position;
2670 var translatedBack =
new Pose(origPos - newPos) * toTranslateBack;
2671 return translatedBack;
2675 public static Pose Pivot(
this Pose p, Quaternion q, Vector3 pivotPoint) {
2676 var preservePos = pivotPoint;
2677 var preservePos_local = p.inverse * pivotPoint;
2678 var toTranslateBack = q * p;
2679 var newPos = (toTranslateBack * preservePos_local).position;
2680 var translatedBack =
new Pose(preservePos - newPos) * toTranslateBack;
2681 return translatedBack;
2685 public static Pose PivotTo(
this Pose p, Quaternion q) {
2686 var origPos = p.position;
2687 var origRot = p.rotation;
2688 var toTranslateBack =
new Pose(q *
Quaternion.Inverse(origRot)) *
2690 var newPos = toTranslateBack.position;
2691 var translatedBack =
new Pose(origPos - newPos) * toTranslateBack;
2692 return translatedBack;
2699 #region Value Mapping Utils ("Map")
2705 public static float Map(
this float value,
float valueMin,
float valueMax,
float resultMin,
float resultMax) {
2706 if (valueMin == valueMax)
return resultMin;
2707 return Mathf.Lerp(resultMin, resultMax, ((value - valueMin) / (valueMax - valueMin)));
2714 public static float MapUnclamped(
this float value,
float valueMin,
float valueMax,
float resultMin,
float resultMax) {
2715 if (valueMin == valueMax)
return resultMin;
2716 return Mathf.LerpUnclamped(resultMin, resultMax, ((value - valueMin) / (valueMax - valueMin)));
2723 public static Vector2 Map(
this Vector2 value,
float valueMin,
float valueMax,
float resultMin,
float resultMax) {
2724 return new Vector2(value.x.Map(valueMin, valueMax, resultMin, resultMax),
2725 value.y.Map(valueMin, valueMax, resultMin, resultMax));
2732 public static Vector2 MapUnclamped(
this Vector2 value,
float valueMin,
float valueMax,
float resultMin,
float resultMax) {
2733 return new Vector2(value.x.MapUnclamped(valueMin, valueMax, resultMin, resultMax),
2734 value.y.MapUnclamped(valueMin, valueMax, resultMin, resultMax));
2741 public static Vector3 Map(
this Vector3 value,
float valueMin,
float valueMax,
float resultMin,
float resultMax) {
2742 return new Vector3(value.x.Map(valueMin, valueMax, resultMin, resultMax),
2743 value.y.Map(valueMin, valueMax, resultMin, resultMax),
2744 value.z.Map(valueMin, valueMax, resultMin, resultMax));
2751 public static Vector3 MapUnclamped(
this Vector3 value,
float valueMin,
float valueMax,
float resultMin,
float resultMax) {
2752 return new Vector3(value.x.MapUnclamped(valueMin, valueMax, resultMin, resultMax),
2753 value.y.MapUnclamped(valueMin, valueMax, resultMin, resultMax),
2754 value.z.MapUnclamped(valueMin, valueMax, resultMin, resultMax));
2761 public static Vector4 Map(
this Vector4 value,
float valueMin,
float valueMax,
float resultMin,
float resultMax) {
2762 return new Vector4(value.x.Map(valueMin, valueMax, resultMin, resultMax),
2763 value.y.Map(valueMin, valueMax, resultMin, resultMax),
2764 value.z.Map(valueMin, valueMax, resultMin, resultMax),
2765 value.w.Map(valueMin, valueMax, resultMin, resultMax));
2772 public static Vector4 MapUnclamped(
this Vector4 value,
float valueMin,
float valueMax,
float resultMin,
float resultMax) {
2773 return new Vector4(value.x.MapUnclamped(valueMin, valueMax, resultMin, resultMax),
2774 value.y.MapUnclamped(valueMin, valueMax, resultMin, resultMax),
2775 value.z.MapUnclamped(valueMin, valueMax, resultMin, resultMax),
2776 value.w.MapUnclamped(valueMin, valueMax, resultMin, resultMax));
2784 public static Vector2 Map(
float input,
float valueMin,
float valueMax, Vector2 resultMin, Vector2 resultMax) {
2785 return Vector2.Lerp(resultMin, resultMax, Mathf.InverseLerp(valueMin, valueMax, input));
2793 public static Vector3 Map(
float input,
float valueMin,
float valueMax, Vector3 resultMin, Vector3 resultMax) {
2794 return Vector3.Lerp(resultMin, resultMax, Mathf.InverseLerp(valueMin, valueMax, input));
2802 public static Vector4 Map(
float input,
float valueMin,
float valueMax, Vector4 resultMin, Vector4 resultMax) {
2803 return Vector4.Lerp(resultMin, resultMax, Mathf.InverseLerp(valueMin, valueMax, input));
2810 public static Vector2 CompMul(
this Vector2 A, Vector2 B) {
2818 public static Vector3 CompMul(
this Vector3 A, Vector3 B) {
2826 public static Vector4 CompMul(
this Vector4 A, Vector4 B) {
2834 public static Vector2 CompDiv(
this Vector2 A, Vector2 B) {
2842 public static Vector3 CompDiv(
this Vector3 A, Vector3 B) {
2850 public static Vector4 CompDiv(
this Vector4 A, Vector4 B) {
2858 public static Vector2 CompAdd(
this Vector2 A, Vector2 B) {
2866 public static Vector3 CompAdd(
this Vector3 A, Vector3 B) {
2874 public static Vector4 CompAdd(
this Vector4 A, Vector4 B) {
2882 public static Vector2 CompSub(
this Vector2 A, Vector2 B) {
2890 public static Vector3 CompSub(
this Vector3 A, Vector3 B) {
2898 public static Vector4 CompSub(
this Vector4 A, Vector4 B) {
2905 public static float CompSum(
this Vector2 v) {
2912 public static float CompSum(
this Vector3 v) {
2913 return v.x + v.y + v.z;
2919 public static float CompSum(
this Vector4 v) {
2920 return v.x + v.y + v.z + v.w;
2926 public static float CompMax(
this Vector2 v) {
2927 return Mathf.Max(v.x, v.y);
2933 public static float CompMax(
this Vector3 v) {
2934 return Mathf.Max(Mathf.Max(v.x, v.y), v.z);
2940 public static float CompMax(
this Vector4 v) {
2941 return Mathf.Max(Mathf.Max(Mathf.Max(v.x, v.y), v.z), v.w);
2947 public static float CompMin(
this Vector2 v) {
2948 return Mathf.Min(v.x, v.y);
2954 public static float CompMin(
this Vector3 v) {
2955 return Mathf.Min(Mathf.Min(v.x, v.y), v.z);
2961 public static float CompMin(
this Vector4 v) {
2962 return Mathf.Min(Mathf.Min(Mathf.Min(v.x, v.y), v.z), v.w);
2968 public static Vector2 CompLerp(
this Vector2 A, Vector2 B, Vector2 Ts) {
2969 return new Vector2(Mathf.Lerp(
A.x,
B.x, Ts.x), Mathf.Lerp(
A.y,
B.y, Ts.y));
2975 public static Vector3 CompLerp(
this Vector3 A, Vector3 B, Vector3 Ts) {
2976 return new Vector3(Mathf.Lerp(
A.x,
B.x, Ts.x), Mathf.Lerp(
A.y,
B.y, Ts.y),
2977 Mathf.Lerp(
A.z,
B.z, Ts.z));
2983 public static Vector4 CompLerp(
this Vector4 A, Vector4 B, Vector4 Ts) {
2984 return new Vector4(Mathf.Lerp(
A.x,
B.x, Ts.x), Mathf.Lerp(
A.y,
B.y, Ts.y),
2985 Mathf.Lerp(
A.z,
B.z, Ts.z), Mathf.Lerp(
A.w,
B.w, Ts.w));
2991 public static Vector2 CompWise(
this Vector2 A, Func<float, float> op) {
2998 public static Vector3 CompWise(
this Vector3 A, Func<float, float> op) {
2999 return new Vector3(op(
A.x), op(
A.y), op(
A.z));
3005 public static Vector4 CompWise(
this Vector4 A, Func<float, float> op) {
3006 return new Vector4(op(
A.x), op(
A.y), op(
A.z), op(
A.w));
3011 #region From/Then Utilities
3022 public static float From(
this float thisFloat,
float otherFloat) {
3023 return thisFloat - otherFloat;
3033 public static float To(
this float thisFloat,
float otherFloat) {
3034 return otherFloat - thisFloat;
3040 public static float Then(
this float thisFloat,
float otherFloat) {
3041 return thisFloat + otherFloat;
3049 public static float Lerp(
this Vector2 betweenXAndY,
float t) {
3050 return Mathf.Lerp(betweenXAndY.x, betweenXAndY.y, t);
3060 public static Vector3 From(
this Vector3 thisVector, Vector3 otherVector) {
3061 return thisVector - otherVector;
3067 public static Vector3 To(
this Vector3 thisVector, Vector3 otherVector) {
3068 return otherVector - thisVector;
3075 public static Vector3 Then(
this Vector3 thisVector, Vector3 otherVector) {
3076 return thisVector + otherVector;
3088 public static Quaternion From(
this Quaternion thisQuaternion, Quaternion otherQuaternion) {
3089 return Quaternion.Inverse(otherQuaternion) * thisQuaternion;
3097 public static Quaternion To(
this Quaternion thisQuaternion, Quaternion otherQuaternion) {
3098 return Quaternion.Inverse(thisQuaternion) * otherQuaternion;
3105 public static Quaternion Then(
this Quaternion thisQuaternion, Quaternion otherQuaternion) {
3106 return thisQuaternion * otherQuaternion;
3119 public static Pose From(
this Pose thisPose, Pose otherPose) {
3120 return otherPose.inverse * thisPose;
3129 public static Pose To(
this Pose thisPose, Pose otherPose) {
3130 return thisPose.inverse * otherPose;
3141 public static Pose Then(
this Pose thisPose, Pose otherPose) {
3142 return thisPose * otherPose;
3156 public static Matrix4x4 From(
this Matrix4x4 thisMatrix, Matrix4x4 otherMatrix) {
3157 return thisMatrix * otherMatrix.inverse;
3167 public static Matrix4x4 To(
this Matrix4x4 thisMatrix, Matrix4x4 otherMatrix) {
3168 return otherMatrix * thisMatrix.inverse;
3175 public static Matrix4x4 Then(
this Matrix4x4 thisMatrix, Matrix4x4 otherMatrix) {
3176 return otherMatrix * thisMatrix;
UnityEngine.Component Component
A position and rotation. You can multiply two poses; this acts like Matrix4x4 multiplication,...
A Query object is a type of immutable ordered collection of elements that can be used to perform usef...
ChildrenEnumerator GetEnumerator()
object System.Collections.IEnumerator. Current
ChildrenEnumerator(Transform t)
HorizontalLineRectEnumerator(Rect rect, int numLines)
HorizontalLineRectEnumerator GetEnumerator()