public float GetNormalisedValue(int index, float min = 0, float max = 1) { if (DataType == IATKDataType.Translate) { return(Data[index]); } else { float _min = (Min == Max) ? Min - 1 : Min; return(UtilMath.NormaliseValue(Data[index], _min, Max, min, max)); } }
private float CalculateFloatFromAngle() { // Get angle float angle = Mathf.Abs(Vector3.SignedAngle(Vector3.up, transform.up, transform.forward)); // Clamp between -90 and 0 angle = Mathf.Clamp(angle, 0, 90); // Normalise float normalised = UtilMath.NormaliseValue(angle, 0, 90, 0, 1); return(normalised); }
private static void AddCustomObservables() { // LINEAR DISTANCE EXAMPLE: Create an observable that calculates distance between two objects, but filtered between 0 and 1 var distanceObservable = GetObservable("LinearDistanceVisPosition") .CombineLatest(GetObservable("LinearDistanceHandlePosition"), (v1, v2) => Vector3.Distance((Vector3)v1, (Vector3)v2)) .Where(x => 0 <= x && x <= 1) .Select(x => (object)x) .StartWith(0) .DistinctUntilChanged(); SaveObservable("LinearDistance", distanceObservable); // TILT EXAMPLE: Create an observable that gets the rotation of a gameobject, but normalises it between 0 and 1 IObservable <object> rotationObservable1 = GetObservable("TiltVisForward") .CombineLatest(GetObservable("TiltVisUp"), (f, u) => { Vector3 forward = (Vector3)f; Vector3 up = (Vector3)u; // Get angle float angle = Mathf.Abs(Vector3.SignedAngle(Vector3.up, up, forward)); // Clamp between 0 and 110 angle = Mathf.Clamp(angle, 0, 110); // Normalise return(UtilMath.NormaliseValue(angle, 0, 110, 0, 1)); }) .Select(x => (object)x) .StartWith(0) .DistinctUntilChanged(); SaveObservable("TiltTween", rotationObservable1); // ORTHOGONAL FLATTENING EXAMPLE #1: Create an observable that calculates the dot product of two directions IObservable <object> dotProductObservable = GetObservable("CameraForward") .CombineLatest(GetObservable("OrthogonalVisForward"), (c, v) => { Vector3 camera = (Vector3)c; Vector3 vis = (Vector3)v; return(Mathf.Abs(Vector3.Dot(camera.normalized, vis.normalized))); }) .Select(x => (object)x) .StartWith(1) .DistinctUntilChanged(); SaveObservable("OrthogonalDotProduct", dotProductObservable); // ORTHOGONAL FLATTENING EXAMPLE #2: Create an observable that calculates the distance between the visualisation and camera IObservable <object> cameraDistanceObservable = GetObservable("CameraPosition") .CombineLatest(GetObservable("OrthogonalVisPosition"), (c, v) => { Vector3 camera = (Vector3)c; Vector3 vis = (Vector3)v; return(Vector3.Distance(camera, vis)); }) .Select(x => (object)x) .StartWith(1) .DistinctUntilChanged(); SaveObservable("OrthogonalDistance", cameraDistanceObservable); // COMPOSABILITY EXAMPLE: Create an observable that returns the name of the gameobject that collides IObservable <object> xTriggerObservable = GetObservable("XTriggerEnter") .Select(x => ((Collider)x).gameObject.name) .Merge(GetObservable("XTriggerExit").Select(_ => "")) .StartWith("") .DistinctUntilChanged(); SaveObservable("XTriggerDimension", xTriggerObservable); IObservable <object> yTriggerObservable = GetObservable("YTriggerEnter") .Select(x => ((Collider)x).gameObject.name) .Merge(GetObservable("YTriggerExit").Select(_ => "")) .StartWith("") .DistinctUntilChanged(); SaveObservable("YTriggerDimension", yTriggerObservable); IObservable <object> zTriggerObservable = GetObservable("ZTriggerEnter") .Select(x => ((Collider)x).gameObject.name) .Merge(GetObservable("ZTriggerExit").Select(_ => "")) .StartWith("") .DistinctUntilChanged(); SaveObservable("ZTriggerDimension", zTriggerObservable); // BILLBOARDING EXAMPLE: Create an observable that returns the distance between the camera and vis IObservable <object> billboardingObservable = GetObservable("BillboardingVisPosition") .CombineLatest(GetObservable("CameraPosition"), (v1, v2) => Vector3.Distance((Vector3)v1, (Vector3)v2)) .Select(x => (object)x) .StartWith(0) .DistinctUntilChanged(); SaveObservable("BillboardDistance", billboardingObservable); // // VELOCITY EXAMPLE: Create an observable that calculates the change in position over time // IObservable<object> velocityObservable = GetObservable("VelocityVisPosition") // .Buffer(5) // .Pairwise() // .CombineLatest(GetObservable("DeltaTime").Buffer(5), (pair, time) => // { // float acc = 0; // for (int i = 0; i < 5; i++) // { // acc += Vector3.Distance((Vector3)pair.Previous[i], (Vector3)pair.Current[i]); // } // return acc / 5f; // }) // .Select(x => (object)x) // .DistinctUntilChanged(); // SaveObservable("Velocity", velocityObservable); // // EXAMPLE 5: Create an observable that returns the number of times the user clicked the left mouse button in a row // var clickObservableL = Observable.EveryUpdate() // .Where(_ => Input.GetMouseButtonDown(0)); // IObservable<object> multiClickObservableL = clickObservableL // .Buffer(clickObservableL.Throttle(TimeSpan.FromMilliseconds(250))) // .Select(xs => (object)xs.Count) // .StartWith(10); // SaveObservable("multiclickL", multiClickObservableL); // // EXAMPLE 6: Create an observable that returns the number of times the user clicked the RIGHT mouse button in a row // var clickObservableR = Observable.EveryUpdate() // .Where(_ => Input.GetMouseButtonDown(1)); // IObservable<object> multiClickObservableR = clickObservableR // .Buffer(clickObservableR.Throttle(TimeSpan.FromMilliseconds(250))) // .Select(xs => (object)xs.Count) // .StartWith(11); // SaveObservable("multiclickR", multiClickObservableR); // // EXAMPLE 6: Create an observable that returns the speed of mouse movement // IObservable<object> mouseMoveObservable = Observable.EveryUpdate() // .Select(_ => Input.mousePosition) // .Buffer(2) // .CombineLatest(GetObservable("deltatime"), (mouseDelta, time) => Vector3.Distance(mouseDelta[0], mouseDelta[1]) / (float)time / 500f) // .Select(x => (object)x) // .StartWith(0) // .DistinctUntilChanged(); // SaveObservable("mousemovement", mouseMoveObservable); }
private static Interpreter SetInterpreterFunctions() { Func <DataAttribute, DataAttribute, double, DataAttribute> Lerp = (da1, da2, t) => { float[] floatArray = new float[da1.Length]; float time = (float)t; for (int i = 0; i < floatArray.Length; i++) { floatArray[i] = Mathf.Lerp(da1.Data[i], da2.Data[i], time); } return(new DataAttribute(string.Format("Lerp({0}, {1}, {2})", da1.Name, da2.Name, t), IATKDataType.Numeric, floatArray)); }; interpreter.SetFunction("Lerp", Lerp); Func <DataAttribute, DataAttribute, double, string, DataAttribute> Lerp_Ease = (da1, da2, t, ease) => { float[] floatArray = new float[da1.Length]; float time = (float)t; for (int i = 0; i < floatArray.Length; i++) { var easing = (EasingFunction.Ease)Enum.Parse(typeof(EasingFunction.Ease), ease); floatArray[i] = EasingFunction.GetEasingFunction(easing)(da1.Data[i], da2.Data[i], time);// Mathf.Lerp(da1.Data[i], da2.Data[i], (float)time); } return(new DataAttribute(string.Format("Lerp({0}, {1}, {2})", da1.Name, da2.Name, t), IATKDataType.Numeric, floatArray)); }; interpreter.SetFunction("Lerp", Lerp_Ease); Func <DataAttribute, double, double, DataAttribute> Lerp_1 = (da, d, t) => { float[] floatArray = new float[da.Length]; float f = (float)d; float time = (float)t; for (int i = 0; i < floatArray.Length; i++) { floatArray[i] = Mathf.Lerp(da.Data[i], f, time); } return(new DataAttribute(string.Format("Lerp({0}, {1}, {2})", da.Name, d, t), IATKDataType.Numeric, floatArray)); }; interpreter.SetFunction("Lerp", Lerp_1); Func <double, DataAttribute, double, DataAttribute> Lerp_2 = (d, da, t) => { float[] floatArray = new float[da.Length]; float f = (float)d; float time = (float)t; for (int i = 0; i < floatArray.Length; i++) { floatArray[i] = Mathf.Lerp(f, da.Data[i], time); } return(new DataAttribute(string.Format("Lerp({0}, {1}, {2})", d, da.Name, t), IATKDataType.Numeric, floatArray)); }; interpreter.SetFunction("Lerp", Lerp_2); Func <double, double, double, double> Lerp_3 = (d1, d2, t) => { return((double)Mathf.Lerp((float)d1, (float)d2, (float)t)); }; interpreter.SetFunction("Lerp", Lerp_3); Func <Vector3, Vector3, double, Vector3> Lerp_4 = (v1, v2, t) => Vector3.Lerp(v1, v2, (float)t); interpreter.SetFunction("Lerp", Lerp_4); Func <DataAttribute, DataAttribute, DataAttribute> DistributeOverplotted = (da1, da2) => { float[] floatArray = new float[da1.Length]; Dictionary <Vector2, List <int> > visitedPoints = new Dictionary <Vector2, List <int> >(); // Determine number of overlapping points for (int i = 0; i < da1.Length; i++) { var pos = new Vector2(da1.Data[i], da2.Data[i]); if (visitedPoints.TryGetValue(pos, out List <int> points)) { points.Add(i); } else { visitedPoints[pos] = new List <int>(i); } } foreach (var list in visitedPoints.Values) { if (list.Count > 1) { for (int i = 1; i < list.Count; i++) { floatArray[list[i]] = UtilMath.NormaliseValue(i, 0, list.Count, 0, 1); } } } return(new DataAttribute(string.Format("DistributeOverplotted({0}, {1})", da1.Name, da2.Name), IATKDataType.Numeric, floatArray)); }; interpreter.SetFunction("DistributeOverplotted", DistributeOverplotted); Func <DataAttribute, DataAttribute> Translate = (da) => { da.OverrideType(IATKDataType.Translate); da.SetName(string.Format("Translate({0})", da.Name)); return(da); }; interpreter.SetFunction("Translate", Translate); Func <DataAttribute, DataAttribute> Normalise_1 = (da) => { float[] floatArray = new float[da.Length]; for (int i = 0; i < da.Length; i++) { floatArray[i] = da.GetNormalisedValue(i); } return(new DataAttribute(string.Format("Normalise({0})", da.Name), da.DataType, floatArray)); }; interpreter.SetFunction("Normalise", Normalise_1); Func <double, double, double, double, double, double> Normalise_2 = (value, i0, i1, j0, j1) => { double L = (j0 - j1) / (i0 - i1); return(j0 - (L * i0) + (L * value)); }; interpreter.SetFunction("Normalise", Normalise_2); Func <double, double, double, double> Clamp = (value, min, max) => { if (value < min) { return(min); } else if (max < value) { return(max); } else { return(value); } }; interpreter.SetFunction("Clamp", Clamp); Func <string, DataAttribute> GetData = (name) => { if (currentVisualisationReference.DataSource[name] != null) { return(currentVisualisationReference.DataSource[name]); } else { return(new DataAttribute("", IATKDataType.Translate, new float[currentVisualisationReference.DataSource.DataCount])); } }; interpreter.SetFunction("GetData", GetData); Func <double, double, double, Vector3> Vector_3 = (x, y, z) => { return(new Vector3((float)x, (float)y, (float)z)); }; interpreter.SetFunction("Vector3", Vector_3); Func <double, double, double, double, Quaternion> Quat = (x, y, z, w) => { return(new Quaternion((float)x, (float)y, (float)z, (float)w)); }; interpreter.SetFunction("Quaternion", Quat); Func <Vector3, Quaternion> ToQuat = (v) => { return(Quaternion.Euler(v)); }; interpreter.SetFunction("ToQuaternion", ToQuat); Func <Vector3, Vector3, Quaternion> LookAt = (source, target) => { Vector3 lookPos = target - source; return(Quaternion.LookRotation(lookPos)); }; interpreter.SetFunction("LookAt", LookAt); Func <DataAttribute, DataAttribute, DataAttribute, DataAttribute, int, int, DataAttribute> DistributeShortestPath = (nodeDa, fromDa, toDa, weightDa, startIdx, endIdx) => { int nodeCount = nodeDa.Length; int edgeCount = fromDa.Length; float[] floatArray = new float[nodeCount]; // First we have to create our matrix of shortest paths float[,] distanceMatrix = new float[nodeCount, nodeCount]; for (int i = 0; i < nodeCount; i++) { for (int j = 0; j < nodeCount; j++) { if (i == j) { distanceMatrix[i, j] = 0; } else { distanceMatrix[i, j] = Mathf.Infinity; } } } for (int i = 0; i < edgeCount; i++) { string fromString = fromDa.ReverseLevels[(int)fromDa.Data[i]]; int from = nodeDa.Levels[fromString]; string toString = toDa.ReverseLevels[(int)toDa.Data[i]]; int to = nodeDa.Levels[toString]; distanceMatrix[from, to] = weightDa.Data[i]; } for (int k = 0; k < nodeCount; k++) { for (int i = 0; i < nodeCount; i++) { for (int j = 0; j < nodeCount; j++) { if (distanceMatrix[i, j] > distanceMatrix[i, k] + distanceMatrix[k, j]) { distanceMatrix[i, j] = distanceMatrix[i, k] + distanceMatrix[k, j]; } } } } // Add the points that make up the shortest path (Dijkstra's) bool[] visited = new bool[nodeCount]; float[] distances = new float[nodeCount]; int[] previous = new int[nodeCount]; int count = 1; for (int i = 0; i < nodeCount; i++) { visited[i] = false; distances[i] = Mathf.Infinity; previous[i] = -1; } distances[startIdx] = 0; while (!visited.All(x => x) && count < nodeCount - 1) { // Get minimum index int u = -1; float min = Mathf.Infinity; for (int i = 0; i < nodeCount; i++) { float dist = distances[i]; if (!visited[i] && dist < min) { u = i; min = dist; } } visited[u] = true; // Stop when we find the second index if (u == endIdx) { break; } // Iterate through neighbours List <int> neighbours = new List <int>(); for (int i = 0; i < nodeCount; i++) { if (distanceMatrix[0, i] > 0 && distanceMatrix[0, i] != Mathf.Infinity) { neighbours.Add(i); } } foreach (int v in neighbours) { float alt = distances[u] + distanceMatrix[u, v]; if (alt < distances[v]) { distances[v] = alt; previous[v] = u; } } count++; } List <int> path = new List <int>(); path.Add(startIdx); int w = startIdx; if (previous[w] != -1 || startIdx == endIdx) { while (previous[w] != -1) { path.Add(w); w = previous[w]; } } // Determine the longest "shortest path" between either the source or destination nodes. // For a given target node, we pick the shorter path between either the source or destination float max = 0; for (int i = 0; i < nodeCount; i++) { if (!path.Contains(i)) { float value = Mathf.Min(distanceMatrix[startIdx, i], distanceMatrix[endIdx, i]); if (value != Mathf.Infinity && max < value) { max = value; } } } for (int i = 0; i < nodeCount; i++) { if (i != startIdx || i != endIdx) { // Use the smaller of shortest paths between the source and destination float weight = Mathf.Min(distanceMatrix[startIdx, i], distanceMatrix[endIdx, i]); if (weight == Mathf.Infinity) { floatArray[i] = 0; } else { floatArray[i] = UtilMath.NormaliseValue(weight, 0, max, 1, 0); } } } return(new DataAttribute(string.Format("DistributeShortestPath({0}, {1}, {2}, {3}, {4}, {5})", nodeDa.Name, fromDa.Name, toDa.Name, weightDa.Name, startIdx, endIdx), IATKDataType.Translate, floatArray)); }; interpreter.SetFunction("DistributeShortestPath", DistributeShortestPath); return(interpreter); }