Пример #1
0
 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));
     }
 }
Пример #2
0
        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);
        }
Пример #3
0
        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);
        }
Пример #4
0
        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);
        }
Пример #5
0
        public int[] GenerateIndices()
        {
            dataAttributes.TryGetValue(IATKProperty.X, out DataAttribute xAttribute);
            dataAttributes.TryGetValue(IATKProperty.Y, out DataAttribute yAttribute);

            // Create our 2D list of points from x and y attributes
            int numPoints = xAttribute.Length;

            Vector2[] allPoints = new Vector2[numPoints];
            for (int i = 0; i < numPoints; i++)
            {
                allPoints[i].x = xAttribute.Data[i];
                allPoints[i].y = yAttribute.Data[i];
            }

            List <int> triangles = new List <int>();

            // Get the attribute that we're grouping by
            DataAttribute grouping = ExpressoParser.ParseExpression(VisualisationReference, VisualisationReference.Group);
            DataAttribute piecing  = ExpressoParser.ParseExpression(VisualisationReference, VisualisationReference.Piece);

            int dataIdx   = 0;
            int vertexIdx = 0;

            foreach (int group in grouping.ReverseLevels.Keys)
            {
                foreach (int piece in piecing.ReverseLevels.Keys)
                {
                    // Create a smaller list of points just for this group
                    List <Vector2> pointsList = new List <Vector2>();
                    for (int i = dataIdx; i < numPoints; i++)
                    {
                        if (grouping.Data[i] != group || piecing.Data[i] != piece)
                        {
                            dataIdx = i;
                            break;
                        }

                        pointsList.Add(allPoints[i]);
                    }

                    if (pointsList.Count == 0)
                    {
                        continue;
                    }

                    Vector2[]    points       = pointsList.ToArray();
                    Triangulator triangulator = new Triangulator(points);
                    int[]        tris         = triangulator.Triangulate();

                    bool isClockwise = UtilMath.IsPointListClockwise(points);

                    // Front vertices
                    for (int i = 0; i < tris.Length; i += 3)
                    {
                        triangles.Add(vertexIdx + tris[i]);
                        triangles.Add(vertexIdx + tris[i + 1]);
                        triangles.Add(vertexIdx + tris[i + 2]);
                    }

                    // Back vertices
                    for (int i = 0; i < tris.Length; i += 3)
                    {
                        triangles.Add(numPoints + vertexIdx + tris[i + 2]);
                        triangles.Add(numPoints + vertexIdx + tris[i + 1]);
                        triangles.Add(numPoints + vertexIdx + tris[i]);
                    }

                    for (int i = 0; i < points.Length; i++)
                    {
                        int n = (i + 1) % points.Length;
                        triangles.Add(vertexIdx + n);
                        triangles.Add(vertexIdx + i + numPoints);
                        triangles.Add(vertexIdx + i);
                        triangles.Add(vertexIdx + n);
                        triangles.Add(vertexIdx + i + numPoints);
                        triangles.Add(vertexIdx + n + numPoints);
                    }

                    vertexIdx += pointsList.Count;
                }
            }

            return(triangles.ToArray());
        }