AR Design
UBC EML collab with UBC SALA - visualizing IoT data in AR
MathUtils.cs
Go to the documentation of this file.
1 // Copyright (c) Microsoft Corporation. All rights reserved.
2 // Licensed under the MIT License. See LICENSE in the project root for license information.
3 
4 using System.Collections.Generic;
5 using System.Linq;
6 using UnityEngine;
7 
8 namespace HoloToolkit.Unity
9 {
13  public static class MathUtils
14  {
19  [System.Obsolete("Use CameraExtensions.GetHorizontalFieldOfViewRadians(Camera camera) instead.")]
20  public static float GetHorizontalFieldOfViewRadians()
21  {
22  return CameraCache.Main.GetHorizontalFieldOfViewRadians();
23  }
24 
30  [System.Obsolete("Use CameraExtensions.IsInFOV(Camera camera, Vector3 position) instead.")]
31  public static bool IsInFOV(Vector3 position)
32  {
33  return CameraCache.Main.IsInFOV(position);
34  }
35 
44  public static Vector3 TransformPointFromTo(Transform from, Transform to, Vector3 ptInFrom)
45  {
46  Vector3 ptInWorld = (from == null) ? ptInFrom : from.TransformPoint(ptInFrom);
47  Vector3 ptInTo = (to == null) ? ptInWorld : to.InverseTransformPoint(ptInWorld);
48  return ptInTo;
49  }
50 
59  public static Vector3 TransformDirectionFromTo(Transform from, Transform to, Vector3 dirInFrom)
60  {
61  Vector3 dirInWorld = (from == null) ? dirInFrom : from.TransformDirection(dirInFrom);
62  Vector3 dirInTo = (to == null) ? dirInWorld : to.InverseTransformDirection(dirInWorld);
63  return dirInTo;
64  }
65 
74  public static Vector3 TransformVectorFromTo(Transform from, Transform to, Vector3 vecInFrom)
75  {
76  Vector3 vecInWorld = (from == null) ? vecInFrom : from.TransformVector(vecInFrom);
77  Vector3 vecInTo = (to == null) ? vecInWorld : to.InverseTransformVector(vecInWorld);
78  return vecInTo;
79  }
80 
84  public static Ray TransformRayFromTo(Transform from, Transform to, Ray rayToConvert)
85  {
86  Ray outputRay = new Ray
87  {
88  origin = TransformPointFromTo(from, to, rayToConvert.origin),
89  direction = TransformDirectionFromTo(from, to, rayToConvert.direction)
90  };
91 
92  return outputRay;
93  }
94 
100  public static Quaternion QuaternionFromMatrix(Matrix4x4 m)
101  {
102  // TODO: test and replace with this simpler, more unity-friendly code
103  // Quaternion q = Quaternion.LookRotation(m.GetColumn(2),m.GetColumn(1));
104 
105  Quaternion q = new Quaternion();
106  q.w = Mathf.Sqrt(Mathf.Max(0, 1 + m[0, 0] + m[1, 1] + m[2, 2])) / 2;
107  q.x = Mathf.Sqrt(Mathf.Max(0, 1 + m[0, 0] - m[1, 1] - m[2, 2])) / 2;
108  q.y = Mathf.Sqrt(Mathf.Max(0, 1 - m[0, 0] + m[1, 1] - m[2, 2])) / 2;
109  q.z = Mathf.Sqrt(Mathf.Max(0, 1 - m[0, 0] - m[1, 1] + m[2, 2])) / 2;
110  q.x *= Mathf.Sign(q.x * (m[2, 1] - m[1, 2]));
111  q.y *= Mathf.Sign(q.y * (m[0, 2] - m[2, 0]));
112  q.z *= Mathf.Sign(q.z * (m[1, 0] - m[0, 1]));
113  return q;
114  }
115 
119  public static void ToTranslationRotation(Matrix4x4 unityMtx, out Vector3 translation, out Quaternion rotation)
120  {
121  Vector3 upwards = new Vector3(unityMtx.m01, unityMtx.m11, unityMtx.m21);
122  Vector3 forward = new Vector3(unityMtx.m02, unityMtx.m12, unityMtx.m22);
123  translation = new Vector3(unityMtx.m03, unityMtx.m13, unityMtx.m23);
124  rotation = Quaternion.LookRotation(forward, upwards);
125  }
126 
132  public static Vector3 XZProject(Vector3 v)
133  {
134  return new Vector3(v.x, 0.0f, v.z);
135  }
136 
142  public static Vector3 YZProject(Vector3 v)
143  {
144  return new Vector3(0.0f, v.y, v.z);
145  }
146 
152  public static Vector3 XYProject(Vector3 v)
153  {
154  return new Vector3(v.x, v.y, 0.0f);
155  }
156 
164  public static float DistanceOfPointToLine(Vector3 point, Vector3 linePointA, Vector3 linePointB)
165  {
166  Vector3 closestPoint = ClosestPointOnLineToPoint(point, linePointA, linePointB);
167  return (point - closestPoint).magnitude;
168  }
169 
170  public static Vector3 ClosestPointOnLineToPoint(Vector3 point, Vector3 linePointA, Vector3 linePointB)
171  {
172  Vector3 v = linePointB - linePointA;
173  Vector3 w = point - linePointA;
174 
175  float c1 = Vector3.Dot(w, v);
176  float c2 = Vector3.Dot(v, v);
177  float b = c1 / c2;
178 
179  Vector3 pointB = linePointA + (v * b);
180 
181  return pointB;
182  }
183 
184  public static float DistanceOfPointToLineSegment(Vector3 point, Vector3 lineStart, Vector3 lineEnd)
185  {
186  Vector3 closestPoint = ClosestPointOnLineSegmentToPoint(point, lineStart, lineEnd);
187  return (point - closestPoint).magnitude;
188  }
189 
190  public static Vector3 ClosestPointOnLineSegmentToPoint(Vector3 point, Vector3 lineStart, Vector3 lineEnd)
191  {
192  Vector3 v = lineEnd - lineStart;
193  Vector3 w = point - lineStart;
194 
195  float c1 = Vector3.Dot(w, v);
196  if (c1 <= 0)
197  {
198  return lineStart;
199  }
200 
201  float c2 = Vector3.Dot(v, v);
202  if (c2 <= c1)
203  {
204  return lineEnd;
205  }
206 
207  float b = c1 / c2;
208 
209  Vector3 pointB = lineStart + (v * b);
210 
211  return pointB;
212  }
213 
214  public static bool TestPlanesAABB(Plane[] planes, int planeMask, Bounds bounds, out bool entirelyInside)
215  {
216  int planeIndex = 0;
217  int entirelyInsideCount = 0;
218  Vector3 boundsCenter = bounds.center; // center of bounds
219  Vector3 boundsExtent = bounds.extents; // half diagonal
220  // do intersection test for each active frame
221  int mask = 1;
222 
223  // while active frames
224  while (mask <= planeMask)
225  {
226  // if active
227  if ((uint)(planeMask & mask) != 0)
228  {
229  Plane p = planes[planeIndex];
230  Vector3 n = p.normal;
231  n.x = Mathf.Abs(n.x);
232  n.y = Mathf.Abs(n.y);
233  n.z = Mathf.Abs(n.z);
234 
235  float distance = p.GetDistanceToPoint(boundsCenter);
236  float radius = Vector3.Dot(boundsExtent, n);
237 
238  if (distance + radius < 0)
239  {
240  // behind clip plane
241  entirelyInside = false;
242  return false;
243  }
244 
245  if (distance > radius)
246  {
247  entirelyInsideCount++;
248  }
249  }
250 
251  mask += mask;
252  planeIndex++;
253  }
254 
255  entirelyInside = entirelyInsideCount == planes.Length;
256  return true;
257  }
258 
266  public static bool InRange(Vector2 vec, Vector2 lower, Vector2 upper)
267  {
268  return vec.x >= lower.x && vec.x <= upper.x && vec.y >= lower.y && vec.y <= upper.y;
269  }
270 
278  public static bool InRange(Vector3 vec, Vector3 lower, Vector3 upper)
279  {
280  return vec.x >= lower.x && vec.x <= upper.x && vec.y >= lower.y && vec.y <= upper.y && vec.z >= lower.z && vec.z <= upper.z;
281  }
282 
289  public static Matrix4x4 Add(Matrix4x4 a, Matrix4x4 b)
290  {
291  Matrix4x4 result = new Matrix4x4();
292  result.SetColumn(0, a.GetColumn(0) + b.GetColumn(0));
293  result.SetColumn(1, a.GetColumn(1) + b.GetColumn(1));
294  result.SetColumn(2, a.GetColumn(2) + b.GetColumn(2));
295  result.SetColumn(3, a.GetColumn(3) + b.GetColumn(3));
296  return result;
297  }
298 
305  public static Matrix4x4 Subtract(Matrix4x4 a, Matrix4x4 b)
306  {
307  Matrix4x4 result = new Matrix4x4();
308  result.SetColumn(0, a.GetColumn(0) - b.GetColumn(0));
309  result.SetColumn(1, a.GetColumn(1) - b.GetColumn(1));
310  result.SetColumn(2, a.GetColumn(2) - b.GetColumn(2));
311  result.SetColumn(3, a.GetColumn(3) - b.GetColumn(3));
312  return result;
313  }
314 
321  public static float DistanceOfPointToLine(Ray ray, Vector3 point)
322  {
323  return Vector3.Cross(ray.direction, point - ray.origin).magnitude;
324  }
325 
332  public static Vector3 NearestPointToLines(Ray p, Ray q)
333  {
334  float a = Vector3.Dot(p.direction, p.direction);
335  float b = Vector3.Dot(p.direction, q.direction);
336  float c = Vector3.Dot(q.direction, q.direction);
337  Vector3 w0 = p.origin - q.origin;
338  float den = a * c - b * b;
339  float epsilon = 0.00001f;
340  if (den < epsilon)
341  {
342  // parallel, so just average origins
343  return 0.5f * (p.origin + q.origin);
344  }
345  float d = Vector3.Dot(p.direction, w0);
346  float e = Vector3.Dot(q.direction, w0);
347  float sc = (b * e - c * d) / den;
348  float tc = (a * e - b * d) / den;
349  Vector3 point = 0.5f * (p.origin + sc * p.direction + q.origin + tc * q.direction);
350  return point;
351  }
352 
365  public static Vector3 NearestPointToLinesRANSAC(List<Ray> rays, int ransac_iterations, float ransac_threshold, out int numActualInliers)
366  {
367  // start with something, just in case no inliers - this works for case of 1 or 2 rays
368  Vector3 nearestPoint = NearestPointToLines(rays[0], rays[rays.Count - 1]);
369  numActualInliers = 0;
370  if (rays.Count > 2)
371  {
372  for (int it = 0; it < ransac_iterations; it++)
373  {
374  Vector3 testPoint = NearestPointToLines(rays[Random.Range(0, rays.Count)], rays[Random.Range(0, rays.Count)]);
375 
376  // count inliers
377  int numInliersForIteration = 0;
378  for (int ind = 0; ind < rays.Count; ++ind)
379  {
380  if (DistanceOfPointToLine(rays[ind], testPoint) < ransac_threshold)
381  ++numInliersForIteration;
382  }
383 
384  // remember best
385  if (numInliersForIteration > numActualInliers)
386  {
387  numActualInliers = numInliersForIteration;
388  nearestPoint = testPoint;
389  }
390  }
391  }
392 
393  // now find and count actual inliers and do least-squares to find best fit
394  var inlierList = rays.Where(r => DistanceOfPointToLine(r, nearestPoint) < ransac_threshold);
395  numActualInliers = inlierList.Count();
396  if (numActualInliers >= 2)
397  {
398  nearestPoint = NearestPointToLinesLeastSquares(inlierList);
399  }
400  return nearestPoint;
401  }
402 
408  public static Vector3 NearestPointToLinesLeastSquares(IEnumerable<Ray> rays)
409  {
410  // finding the point nearest to the set of lines specified by rays
411  // Use the following formula, where u_i are normalized direction
412  // vectors along each ray and p_i is a point along each ray.
413 
414  // -1
415  // / ===== \ =====
416  // | \ / T\ | \ / T\
417  // | > |I - u u | | > |I - u u | p
418  // | / \ i i/ | / \ i i/ i
419  // | ===== | =====
420  // \ i / i
421 
422  Matrix4x4 sumOfProduct = Matrix4x4.zero;
423  Vector4 sumOfProductTimesDirection = Vector4.zero;
424 
425  foreach (Ray r in rays)
426  {
427  Vector4 point = r.origin;
428  Matrix4x4 directionColumnMatrix = new Matrix4x4();
429  Vector3 rNormal = r.direction.normalized;
430  directionColumnMatrix.SetColumn(0, rNormal);
431  Matrix4x4 directionRowMatrix = directionColumnMatrix.transpose;
432  Matrix4x4 product = directionColumnMatrix * directionRowMatrix;
433  Matrix4x4 identityMinusDirectionProduct = Subtract(Matrix4x4.identity, product);
434  sumOfProduct = Add(sumOfProduct, identityMinusDirectionProduct);
435  Vector4 vectorProduct = identityMinusDirectionProduct * point;
436  sumOfProductTimesDirection += vectorProduct;
437  }
438 
439  Matrix4x4 sumOfProductInverse = sumOfProduct.inverse;
440  Vector3 nearestPoint = sumOfProductInverse * sumOfProductTimesDirection;
441  return nearestPoint;
442  }
443  }
444 }
static float GetHorizontalFieldOfViewRadians()
Get the horizontal FOV from the stereo camera
Definition: MathUtils.cs:20
static Matrix4x4 Subtract(Matrix4x4 a, Matrix4x4 b)
Element-wise subtraction of two Matrix4x4s - extension method
Definition: MathUtils.cs:305
static float DistanceOfPointToLine(Vector3 point, Vector3 linePointA, Vector3 linePointB)
Returns the distance between a point and an infinite line defined by two points; linePointA and lineP...
Definition: MathUtils.cs:164
static Vector3 TransformDirectionFromTo(Transform from, Transform to, Vector3 dirInFrom)
Takes a direction in the coordinate space specified by the "from" transform and transforms it to be t...
Definition: MathUtils.cs:59
static Vector3 NearestPointToLinesRANSAC(List< Ray > rays, int ransac_iterations, float ransac_threshold, out int numActualInliers)
Find 3D point that minimizes distance to a set of 2 or more lines, ignoring outliers ...
Definition: MathUtils.cs:365
static bool InRange(Vector3 vec, Vector3 lower, Vector3 upper)
Tests component-wise if a Vector3 is in a given range
Definition: MathUtils.cs:278
static float DistanceOfPointToLineSegment(Vector3 point, Vector3 lineStart, Vector3 lineEnd)
Definition: MathUtils.cs:184
static void ToTranslationRotation(Matrix4x4 unityMtx, out Vector3 translation, out Quaternion rotation)
Extract the translation and rotation components of a Unity matrix
Definition: MathUtils.cs:119
static Quaternion QuaternionFromMatrix(Matrix4x4 m)
Creates a quaternion containing the rotation from the input matrix.
Definition: MathUtils.cs:100
static bool InRange(Vector2 vec, Vector2 lower, Vector2 upper)
Tests component-wise if a Vector2 is in a given range
Definition: MathUtils.cs:266
static Vector3 XYProject(Vector3 v)
Project vector onto XY plane
Definition: MathUtils.cs:152
static bool IsInFOV(Vector3 position)
Returns if a point will be rendered on the screen in either eye
Definition: MathUtils.cs:31
static Vector3 XZProject(Vector3 v)
Project vector onto XZ plane
Definition: MathUtils.cs:132
static Vector3 ClosestPointOnLineToPoint(Vector3 point, Vector3 linePointA, Vector3 linePointB)
Definition: MathUtils.cs:170
The purpose of this class is to provide a cached reference to the main camera. Calling Camera...
Definition: CameraCache.cs:12
static Vector3 ClosestPointOnLineSegmentToPoint(Vector3 point, Vector3 lineStart, Vector3 lineEnd)
Definition: MathUtils.cs:190
static Matrix4x4 Add(Matrix4x4 a, Matrix4x4 b)
Element-wise addition of two Matrix4x4s - extension method
Definition: MathUtils.cs:289
static bool TestPlanesAABB(Plane[] planes, int planeMask, Bounds bounds, out bool entirelyInside)
Definition: MathUtils.cs:214
static Vector3 NearestPointToLines(Ray p, Ray q)
Find 3D point that minimizes distance to 2 lines, midpoint of the shortest perpendicular line segment...
Definition: MathUtils.cs:332
static Camera Main
Returns a cached reference to the main camera and uses Camera.main if it hasn&#39;t been cached yet...
Definition: CameraCache.cs:20
static float DistanceOfPointToLine(Ray ray, Vector3 point)
find unsigned distance of 3D point to an infinite line
Definition: MathUtils.cs:321
Math Utilities class.
Definition: MathUtils.cs:13
static Vector3 TransformVectorFromTo(Transform from, Transform to, Vector3 vecInFrom)
Takes a vectpr in the coordinate space specified by the "from" transform and transforms it to be the ...
Definition: MathUtils.cs:74
static Ray TransformRayFromTo(Transform from, Transform to, Ray rayToConvert)
Takes a ray in the coordinate space specified by the "from" transform and transforms it to be the cor...
Definition: MathUtils.cs:84
static Vector3 NearestPointToLinesLeastSquares(IEnumerable< Ray > rays)
Find 3D point that minimizes distance to a set of 2 or more lines
Definition: MathUtils.cs:408
static Vector3 YZProject(Vector3 v)
Project vector onto YZ plane
Definition: MathUtils.cs:142
static Vector3 TransformPointFromTo(Transform from, Transform to, Vector3 ptInFrom)
Takes a point in the coordinate space specified by the "from" transform and transforms it to be the c...
Definition: MathUtils.cs:44