AR Design
UBC EML collab with UBC SALA - visualizing IoT data in AR
LineBase.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 HoloToolkit.Unity;
5 using System.Collections.Generic;
6 using UnityEngine;
7 
8 namespace HoloToolkit.Unity.UX
9 {
10  public abstract class LineBase : MonoBehaviour
11  {
12  protected const float MinRotationMagnitude = 0.0001f;
13 
14  #region fields & properties
15 
16  public float UnclampedWorldLength
17  {
18  get
19  {
20  return GetUnclampedWorldLengthInternal();
21  }
22  }
23 
24  [Header("Basic Settings")]
25  [Tooltip("Clamps the line's normalized start point. This setting will affect line renderers.")]
26  [Range(0f, 1f)]
27  public float LineStartClamp = 0f;
28  [Range(0f, 1f)]
29  [Tooltip("Clamps the line's normalized end point. This setting will affect line renderers.")]
30  public float LineEndClamp = 1f;
31 
32  public virtual bool Loops
33  {
34  get
35  {
36  return loops;
37  }
38  }
39 
40  [Header("Rotation")]
41  [Tooltip("The rotation mode used in the GetRotation function. You can visualize rotations by checking Draw Rotations under Editor Settings.")]
42  public RotationTypeEnum RotationType = RotationTypeEnum.Velocity;
43 
44  [Tooltip("Reverses up vector when determining rotation along line")]
45  public bool FlipUpVector = false;
46 
47  [Tooltip("Local space offset to transform position. Used to determine rotation along line in RelativeToOrigin rotation mode")]
48  public Vector3 OriginOffset = Vector3.zero;
49 
50  [Tooltip("The weight of manual up vectors in Velocity rotation mode")]
51  [Range(0f,1f)]
52  public float ManualUpVectorBlend = 0f;
53 
54  [Tooltip("These vectors are used with ManualUpVectorBlend to determine rotation along the line in Velocity rotation mode. Vectors are distributed along the normalized length of the line.")]
55  public Vector3[] ManualUpVectors = new Vector3[] { Vector3.up, Vector3.up, Vector3.up };
56 
57  [Tooltip("Used in Velocity rotation mode. Smaller values are more accurate but more expensive")]
58  [Range(0.0001f, 0.1f)]
59  public float VelocitySearchRange = 0.02f;
60  [Range(0f, 1f)]
61  public float VelocityBlend = 0.5f;
62 
63  [Header ("Distortion")]
64  [Tooltip("NormalizedLength mode uses the DistortionStrength curve for distortion strength, Uniform uses UniformDistortionStrength along entire line")]
65  public DistortionTypeEnum DistortionType = DistortionTypeEnum.NormalizedLength;
66  public AnimationCurve DistortionStrength = AnimationCurve.Linear(0f, 1f, 1f, 1f);
67  [Range(0f, 1f)]
68  public float UniformDistortionStrength = 1f;
69 
70  [SerializeField]
71  [Tooltip("A list of distorters that apply to this line")]
72  protected List<Distorter> distorters = new List<Distorter>();
73 
74  [Tooltip("Controls whether this line loops (Note: some classes override this setting)")]
75  [SerializeField]
76  protected bool loops = false;
77 
78  #endregion
79 
80  #region abstract
81 
82  public abstract int NumPoints { get; }
83 
84  protected abstract void SetPointInternal(int pointIndex, Vector3 point);
85 
92  protected abstract Vector3 GetPointInternal(float normalizedLength);
93 
100  protected abstract Vector3 GetPointInternal(int pointIndex);
101 
107  protected virtual Vector3 GetUpVectorInternal(float normalizedLength)
108  {
109  return transform.forward;
110  }
111 
116  protected abstract float GetUnclampedWorldLengthInternal();
117 
118  #endregion
119 
120  #region public
121 
122  // Convenience
123  public Vector3 FirstPoint
124  {
125  get
126  {
127  return GetPoint(0);
128  }
129  set
130  {
131  SetPoint(0, value);
132  }
133  }
134 
135  public Vector3 LastPoint
136  {
137  get
138  {
139  return GetPoint(NumPoints - 1);
140  }
141  set
142  {
143  SetPoint(NumPoints - 1, value);
144  }
145  }
146 
147  public void AddDistorter(Distorter newDistorter)
148  {
149  if (!distorters.Contains(newDistorter))
150  {
151  distorters.Add(newDistorter);
152  }
153  }
154 
158  public virtual void MakeStraightLine()
159  {
160  if (NumPoints > 2)
161  {
162  Vector3 startPosition = GetPoint(0);
163  Vector3 endPosition = GetPoint(NumPoints - 1);
164  for (int i = 1; i < NumPoints - 2; i++)
165  {
166  SetPoint(i, Vector3.Lerp(startPosition, endPosition, (1f / NumPoints * 1)));
167  }
168  }
169  }
170 
178  public float GetNormalizedLengthFromWorldLength (float worldLength, int searchResolution = 10)
179  {
180  Vector3 lastPoint = GetUnclampedPoint(0f);
181  Vector3 currentPoint = Vector3.zero;
182  float normalizedLength = 0f;
183  float distanceSoFar = 0f;
184 
185  for (int i = 1; i < searchResolution; i++)
186  {
187  // Get the normalized length of this position along the line
188  normalizedLength = (1f / searchResolution) * i;
189  currentPoint = GetUnclampedPoint(normalizedLength);
190  distanceSoFar += Vector3.Distance(lastPoint, currentPoint);
191  lastPoint = currentPoint;
192 
193  if (distanceSoFar >= worldLength)
194  {
195  // We've reached the world length
196  break;
197  };
198  }
199 
200  return Mathf.Clamp01 (normalizedLength);
201  }
202 
208  public Vector3 GetVelocity(float normalizedLength)
209  {
210  Vector3 velocity = Vector3.zero;
211  if (normalizedLength < VelocitySearchRange)
212  {
213  Vector3 currentPos = GetPoint(normalizedLength);
214  Vector3 nextPos = GetPoint(normalizedLength + VelocitySearchRange);
215  velocity = (nextPos - currentPos).normalized;
216  }
217  else
218  {
219  Vector3 currentPos = GetPoint(normalizedLength);
220  Vector3 prevPos = GetPoint(normalizedLength - VelocitySearchRange);
221  velocity = (currentPos - prevPos).normalized;
222  }
223  return velocity;
224  }
225 
232  public Quaternion GetRotation(float normalizedLength, RotationTypeEnum rotationType = RotationTypeEnum.None)
233  {
234  rotationType = (rotationType != RotationTypeEnum.None) ? rotationType : RotationType;
235  Vector3 rotationVector = Vector3.zero;
236 
237  switch (rotationType)
238  {
239  case RotationTypeEnum.None:
240  default:
241  break;
242 
243  case RotationTypeEnum.Velocity:
244  rotationVector = GetVelocity(normalizedLength);
245  break;
246 
247  case RotationTypeEnum.RelativeToOrigin:
248  Vector3 point = GetPoint(normalizedLength);
249  Vector3 origin = transform.TransformPoint(OriginOffset);
250  rotationVector = (point - origin).normalized;
251  break;
252  }
253 
254  if (rotationVector.magnitude < MinRotationMagnitude)
255  {
256  return transform.rotation;
257  }
258 
259  Vector3 upVector = GetUpVectorInternal(normalizedLength);
260 
261  if (ManualUpVectorBlend > 0f)
262  {
263  Vector3 manualUpVector = LineUtils.GetVectorCollectionBlend(ManualUpVectors, normalizedLength, Loops);
264  upVector = Vector3.Lerp(upVector, manualUpVector, manualUpVector.magnitude);
265  }
266 
267  if (FlipUpVector)
268  {
269  upVector = -upVector;
270  }
271 
272  return Quaternion.LookRotation(rotationVector, upVector);
273  }
274 
281  public Quaternion GetRotation (int pointIndex, RotationTypeEnum rotationType = RotationTypeEnum.None)
282  {
283  return GetRotation((float)pointIndex / NumPoints, (rotationType != RotationTypeEnum.None) ? rotationType : RotationType);
284  }
285 
291  public Vector3 GetPoint(float normalizedLength)
292  {
293  normalizedLength = ClampedLength(normalizedLength);
294  return DistortPoint (transform.TransformPoint(GetPointInternal(normalizedLength)), normalizedLength);
295  }
296 
302  public Vector3 GetUnclampedPoint(float normalizedLength)
303  {
304  normalizedLength = Mathf.Clamp01(normalizedLength);
305  return DistortPoint(transform.TransformPoint(GetPointInternal(normalizedLength)), normalizedLength);
306  }
307 
313  public Vector3 GetPoint (int pointIndex)
314  {
315  if (pointIndex < 0 || pointIndex >= NumPoints)
316  {
317  throw new System.IndexOutOfRangeException();
318  }
319 
320  return transform.TransformPoint(GetPointInternal(pointIndex));
321  }
322 
329  public void SetPoint (int pointIndex, Vector3 point)
330  {
331  if (pointIndex < 0 || pointIndex >= NumPoints)
332  {
333  throw new System.IndexOutOfRangeException();
334  }
335 
336  SetPointInternal(pointIndex, transform.InverseTransformPoint(point));
337  }
338 
339  public virtual void AppendPoint(Vector3 point)
340  {
341  // Does nothing by default
342  }
343 
344  #endregion
345 
346  #region private & protected
347 
348  protected virtual void OnEnable()
349  {
350  // Sort our distorters
351  distorters.Sort();
352  }
353 
354  private Vector3 DistortPoint (Vector3 point, float normalizedLength)
355  {
356  float strength = UniformDistortionStrength;
357  switch (DistortionType)
358  {
359  case DistortionTypeEnum.Uniform:
360  default:
361  break;
362 
363  case DistortionTypeEnum.NormalizedLength:
364  strength = DistortionStrength.Evaluate(normalizedLength);
365  break;
366  }
367 
368  for (int i = 0; i < distorters.Count; i++)
369  {
370  // Components may be added or removed
371  if (distorters[i] != null)
372  {
373  point = distorters[i].DistortPoint(point, strength);
374  }
375  }
376  return point;
377  }
378 
379  private float ClampedLength(float normalizedLength)
380  {
381  return Mathf.Lerp(Mathf.Max (LineStartClamp, 0.0001f), Mathf.Min (LineEndClamp, 0.9999f), Mathf.Clamp01(normalizedLength));
382  }
383 
384  #endregion
385 
386 #if UNITY_EDITOR
387  protected virtual void OnDrawGizmos()
388  {
389  // Show gizmos if this object is not selected
390  // (SceneGUI will display it otherwise)
391 
392  if (Application.isPlaying)
393  {
394  return;
395  }
396 
397  if (UnityEditor.Selection.activeGameObject == this.gameObject)
398  {
399  return;
400  }
401 
402  // Only draw a gizmo if we don't have a line renderer
403  LineRendererBase lineRenderer = gameObject.GetComponent<LineRendererBase>();
404  if (lineRenderer != null)
405  {
406  return;
407  }
408 
409  Vector3 firstPos = GetPoint(0f);
410  Vector3 lastPos = firstPos;
411  Gizmos.color = Color.Lerp (LineBaseEditor.DefaultDisplayLineColor, Color.clear, 0.25f);
412  int numSteps = 16;
413 
414  for (int i = 1; i < numSteps; i++)
415  {
416  float normalizedLength = (1f / (numSteps - 1)) * i;
417  Vector3 currentPos = GetPoint(normalizedLength);
418  Gizmos.DrawLine(lastPos, currentPos);
419  lastPos = currentPos;
420  }
421 
422  if (Loops)
423  {
424  Gizmos.DrawLine(lastPos, firstPos);
425  }
426  }
427 #endif
428  }
429 }
float GetNormalizedLengthFromWorldLength(float worldLength, int searchResolution=10)
Returns a normalized length corresponding to a world length Useful for determining LineStartClamp / L...
Definition: LineBase.cs:178
Vector3 GetVelocity(float normalizedLength)
Gets the velocity along the line
Definition: LineBase.cs:208
RotationTypeEnum
Default options for getting a rotation along a line
Definition: LineUtility.cs:20
Vector3 GetUnclampedPoint(float normalizedLength)
Gets a point along the line at the specified length without using LineStartClamp or LineEndClamp ...
Definition: LineBase.cs:302
Quaternion GetRotation(int pointIndex, RotationTypeEnum rotationType=RotationTypeEnum.None)
Gets the rotation of a point along the line at the specified index
Definition: LineBase.cs:281
virtual Vector3 GetUpVectorInternal(float normalizedLength)
Gets the up vector at a normalized length along line (used for rotation)
Definition: LineBase.cs:107
Vector3 GetPoint(int pointIndex)
Gets a point along the line at the specified index
Definition: LineBase.cs:313
void AddDistorter(Distorter newDistorter)
Definition: LineBase.cs:147
void SetPoint(int pointIndex, Vector3 point)
Sets a point in the line This function is not guaranteed to have an effect
Definition: LineBase.cs:329
static Vector3 GetVectorCollectionBlend(Vector3[] vectorCollection, float normalizedLength, bool repeat)
Returns a blended value from a collection of vectors
Definition: LineUtility.cs:102
virtual void MakeStraightLine()
Places all points between the first and last point in a straight line
Definition: LineBase.cs:158
virtual void AppendPoint(Vector3 point)
Definition: LineBase.cs:339
Quaternion GetRotation(float normalizedLength, RotationTypeEnum rotationType=RotationTypeEnum.None)
Gets the rotation of a point along the line at the specified length
Definition: LineBase.cs:232
Vector3 GetPoint(float normalizedLength)
Gets a point along the line at the specified length
Definition: LineBase.cs:291