private Vector2 ForceDirectedRepulsion(GraphVertex vertex, float repulsion)
        {
            IEnumerable <GraphEdge> inEdges;

            _project.DependencyGraph.TryGetInEdges(vertex, out inEdges);
            List <GraphEdge> edgeList = inEdges.ToList();
            Vector2          force    = Vector2.zero;

            foreach (GraphVertex other in _project.DependencyGraph.Vertices)
            {
                GraphEdge edge = edgeList.Find(x => (x.Source == other) || (x.Target == other));
                if (other == vertex || edge != null)
                {
                    continue;
                }

                Vector2 direction = _simulationData[vertex].position - _simulationData[other].position;

                float distanceToBounds = direction.magnitude - (vertex.Island.Radius + other.Island.Radius);

                if (distanceToBounds < 0.0f)
                {
                    Vector2 constrainedPosition = _simulationData[vertex].position - direction.normalized * distanceToBounds;
                    _simulationData[other] = new VertexPositionData(constrainedPosition, constrainedPosition);
                    distanceToBounds       = 0f;
                }

                float divisor = distanceToBounds + 0.1f;
                force += (direction.normalized * repulsion) / (divisor * divisor);
            }

            return(force);
        }
        public void BuildForceDirectedLayout(OSGiProject project)
        {
            _simulationData = new Dictionary <GraphVertex, VertexPositionData>();
            _project        = project;

            // TODO: Refactor
            float attraction      = 10.0f;
            float spring          = 1.0f;
            float repulsion       = 5.0f;
            float attractToCenter = 0.005f;
            float friction        = 0.105f;
            float timestep        = StepSize;

            foreach (GraphVertex vertex in project.DependencyGraph.Vertices)
            {
                float rr = 20f;

                float x = (SyncDataStorage.Instance.GetRandomNumber(_random) - 0.5f) * rr;
                float y = (SyncDataStorage.Instance.GetRandomNumber(_random) - 0.5f) * rr;

                Vector2            startPos   = new Vector2(x, y);
                VertexPositionData vertexData = new VertexPositionData(startPos, startPos);
                _simulationData.Add(vertex, vertexData);
            }

            int stepCounter = 0;

            while (stepCounter < SimulationSteps)
            {
                foreach (GraphVertex vertex in project.DependencyGraph.Vertices)
                {
                    Vector2 netForce = Vector2.zero;

                    netForce += ForceDirectedAttraction(vertex, attraction, spring);
                    netForce += ForceDirectedRepulsion(vertex, repulsion);
                    netForce -= ForceDirectedAttractToCenter(vertex, attractToCenter);
                    VerletIntegration(vertex, netForce, friction, timestep);

                    netForce = new Vector2((float)Math.Truncate(netForce.x * 10) / 10, (float)Math.Truncate(netForce.y * 10) / 10);
                    stepCounter++;
                }
            }

            foreach (GraphVertex vertex in project.DependencyGraph.Vertices)
            {
                VertexPositionData vertexData = _simulationData[vertex];
                Vector3            pos        = new Vector3(vertexData.position.x, 0, vertexData.position.y);
                vertex.Position = pos;
            }
        }
        private void VerletIntegration(GraphVertex vertex, Vector2 force, float friction, float timestep)
        {
            Vector2 posDiff    = _simulationData[vertex].position - _simulationData[vertex].oldPosition;
            Vector2 velocity   = posDiff / timestep;
            Vector2 resistance = velocity * timestep * friction;

            Vector2 oldPosition = _simulationData[vertex].position;
            Vector2 newPosition = 2.0f * _simulationData[vertex].position - _simulationData[vertex].oldPosition
                                  + timestep * timestep * force;

            newPosition -= resistance;

            VertexPositionData vertexData = new VertexPositionData(newPosition, oldPosition);

            _simulationData[vertex] = vertexData;
        }
        private void computeForceDirectedLayoutThreaded(int simulationSteps, float stepSize)
        {
            status = Status.Working;
            Debug.Log("Starting forcedirected graph layout construction.");

            //Attract Strength multi
            float c1 = 10.0f;
            //"Spring" length for maximal dependency strength
            float c3 = 1.0f;
            //Repulsion
            float c4 = 5.0f;
            //Attract-To-Center
            float c5 = 0.005f;
            //Friction
            float c6 = 0.105f;
            //TimeStep
            float t = stepSize;



            Dictionary <GraphVertex, VertexPositionData> simulationData = new Dictionary <GraphVertex, VertexPositionData>();

            #region init start values
            foreach (GraphVertex vert in graph.Vertices)
            {
                float              rr       = 20f;
                Vector2            startPos = new Vector2((float)RNG.NextDouble() * rr, (float)RNG.NextDouble() * rr);
                VertexPositionData vpd      = new VertexPositionData(startPos, startPos);
                simulationData.Add(vert, vpd);
            }
            #endregion
            int stepCounter = 0;

            while (stepCounter < simulationSteps)
            {
                foreach (GraphVertex thisVert in graph.Vertices)
                {
                    // total force affecting "thisVert"
                    Vector2 netForce = Vector2.zero;

                    #region Attraction
                    IEnumerable <GraphEdge> outEdges;
                    graph.TryGetOutEdges(thisVert, out outEdges);
                    List <GraphEdge> edgeList    = outEdges.ToList();
                    Vector2          springForce = Vector2.zero;
                    foreach (GraphEdge importEdge in edgeList)
                    {
                        GraphVertex otherVert = importEdge.Target;
                        Vector2     direction = simulationData[otherVert].position - simulationData[thisVert].position;

                        float springEquilibriumLength = (thisVert.getIsland().getRadius() + otherVert.getIsland().getRadius()) + c3 * (project.getMaxImportCount() / importEdge.getWeight());

                        springForce += c1 * direction.normalized * Mathf.Log((direction.magnitude / springEquilibriumLength));
                    }
                    IEnumerable <GraphEdge> inEdges;
                    graph.TryGetInEdges(thisVert, out inEdges);
                    edgeList = inEdges.ToList();

                    /*
                     * foreach (GraphEdge exportEdge in edgeList)
                     * {
                     *  GraphVertex otherVert = exportEdge.Source;
                     *  Vector2 direction = simulationData[otherVert].position - simulationData[thisVert].position;
                     *
                     *  float springEquilibriumLength = (thisVert.getIsland().getRadius() + otherVert.getIsland().getRadius()) + c3 / exportEdge.getWeight();
                     *
                     *  springForce += c1 * direction.normalized * Mathf.Log((direction.magnitude / springEquilibriumLength));
                     * }
                     */
                    netForce += springForce;
                    #endregion


                    #region Repulsion
                    foreach (GraphVertex otherVert in graph.Vertices)
                    {
                        if (otherVert == thisVert || (edgeList.Find(x => (x.Source == otherVert) || (x.Target == otherVert))) != null)
                        {
                            continue;
                        }
                        Vector2 direction = simulationData[thisVert].position - simulationData[otherVert].position;

                        float distanceToBounds = direction.magnitude - (thisVert.getIsland().getRadius() + otherVert.getIsland().getRadius());

                        if (distanceToBounds < 0.0f)
                        {
                            Vector2 constrainedPosition = simulationData[thisVert].position - direction.normalized * distanceToBounds;
                            simulationData[thisVert] = new VertexPositionData(constrainedPosition, constrainedPosition);
                            distanceToBounds         = 0f;
                        }
                        netForce += (direction.normalized * c4) / (Mathf.Pow(distanceToBounds + 0.1f, 2f));
                    }
                    #endregion



                    #region Attract-to-Center
                    netForce -= simulationData[thisVert].position * c5;
                    #endregion

                    #region position computation through Verlet-Integration
                    Vector2 currentVelocity = (simulationData[thisVert].position - simulationData[thisVert].oldPosition) / t;
                    Vector2 resistance      = currentVelocity * t * c6;

                    Vector2 newPosition = 2.0f * simulationData[thisVert].position - simulationData[thisVert].oldPosition + t * t * netForce;
                    newPosition -= resistance;
                    Vector2            oldPosition = simulationData[thisVert].position;
                    VertexPositionData vpd         = new VertexPositionData(newPosition, oldPosition);
                    simulationData[thisVert] = vpd;
                    #endregion

                    stepCounter++;
                }
            }

            #region assign computed positions to graph vertices
            foreach (GraphVertex vert in graph.Vertices)
            {
                VertexPositionData vpd = simulationData[vert];
                Vector3            pos = new Vector3(vpd.position.x, 0, vpd.position.y);
                vert.setPosition(pos);
            }
            #endregion


            status = Status.Finished;
            Debug.Log("Forcedirected Graph layout is computed!");
            cb();
        }