예제 #1
0
        public bool Add(Vertex[] Edge1, Vertex[] Edge2)
        {
            PointF[] edge1 = new PointF[2];
            PointF[] edge2 = new PointF[2];

            edge1 = VertToPoint(Edge1);
            edge2 = VertToPoint(Edge2);

            HashSet<PointF> crossing = new HashSet<PointF>();
            crossing.Add(edge1[0]);
            crossing.Add(edge1[1]);
            crossing.Add(edge2[0]);
            crossing.Add(edge2[1]);

            foreach (HashSet<PointF> storedCrossing in set)
            {
                if (crossing.SetEquals(storedCrossing))
                // Crossing already exists in set, so return false and don't add
                {
                    return false;
                }
            }

            set.Add(crossing);
            return true;
        }
예제 #2
0
        internal Vertex[] GenerateVertices(int verticesAmt)
        {
            Vertex[] vertices = new Vertex[verticesAmt];

            for (int i = 0; i < verticesAmt; i++)
            {
                // Random Position
                int x = StaticRandom.Rand(100, 400);
                int y = StaticRandom.Rand(100, 400);

                // Random Connections
                int connections = StaticRandom.Rand(0, 2);
                HashSet<int> connectionSet = new HashSet<int>();

                if (i > 0)
                    connectionSet.Add(StaticRandom.Rand(0, i - 1));

                for (int c = 0; c < connections; c++)
                {
                    int conn = StaticRandom.Rand(0, verticesAmt);
                    if (conn != i)
                        connectionSet.Add(conn);
                }

                // The ID is its position in the array
                vertices[i] = new Vertex(i, new Vector(x, y), connectionSet);
            }

            // Each of the connections should go both ways.
            for (int i = 0; i < verticesAmt; i++)
                foreach (int connected in vertices[i].connectedVertexIDs)
                    vertices[connected].AddConnection(i);

            return vertices;
        }
예제 #3
0
        internal override Vertex[] UpdateForces(int VerticesAmt, Vertex[] Vertices, double aWeight, double rWeight, double k = 0)
        {
            // Works the same way as array, but can be used concurrently (as we're both reading and writing)
            var forcesDict = new Dictionary<int, Vector>();
            var closed = new Dictionary<int, bool>();

            // Needs to be instantiated to something
            for (int i = 0; i < VerticesAmt; i++)
                forcesDict[i] = new Vector(0, 0);

            for (int i = 0; i < VerticesAmt; i++)
                closed[i] = false;

            for (int i = 0; i < VerticesAmt; i++)
            {
                foreach (int connection in Vertices[i].connectedVertexIDs)
                {
                    if (closed[connection])
                        continue;

                    // Omdat FurchtRein raar is:
                    // radius <- rWeight,
                    // rWeight == aWeight <- aWeight
                    // c <- k
                    Double FRConstant = Algorithms.FruchtReinConstant(Vertices[i], Vertices, k, rWeight);

                    Vector aForce = Algorithms.FruchtReinAttractive(Vertices[i], Vertices[connection], FRConstant, aWeight);

                    forcesDict[i] += aForce;
                }

                closed[i] = true;
            }

            // Add Repulsive Forces Into the mix:
            for (int i = 0; i < VerticesAmt; i++)
                closed[i] = false;

            for (int i = 0; i < VerticesAmt; i++)
            {
                for (int j = 0; j < VerticesAmt; j++)
                {
                    if (closed[j] || i == j)
                        continue;

                    Double FRConstant = Algorithms.FruchtReinConstant(Vertices[i], Vertices, k, rWeight);
                    Vector rForce = Algorithms.FruchtReinRepulsive(Vertices[i], Vertices[j], FRConstant, aWeight);

                    forcesDict[i] += rForce;
                }
                closed[i] = true;
            }

            // Apply the forces
            for (int i = 1; i < VerticesAmt; i++)
                Vertices[i].ApplyForce(forcesDict[i]);

            return Vertices;
        }
예제 #4
0
        public static Vector EadesAttractive(Vertex node1, Vertex node2, double aWeight, double aWeight2)
        {
            Vector r = Vertex.VectorBetween(node2, node1);
            double distance = Math.Abs(r.Length);
            r.Normalize();

            Vector forceVector = r * Math.Log(distance / aWeight2, 2);

            return aWeight * forceVector;
        }
예제 #5
0
        public static Vector EadesRepulsive(Vertex node1, Vertex node2, double rWeight)
        {
            Vector r = Vertex.VectorBetween(node2, node1);
            double distance = Math.Abs(r.Length);
            r.Normalize();

            Vector forceVector = r / (distance * distance);

            return rWeight * forceVector;
        }
예제 #6
0
        public static Vector FruchtReinAttractive(Vertex node1, Vertex node2, double k, double weight)
        {
            Vector r = Vertex.VectorBetween(node1, node2);
            double distance = Math.Abs(r.Length);
            r.Normalize();

            Vector forceVector = r * (distance * distance) / k;

            return weight * forceVector;
        }
예제 #7
0
        public static Vector FruchtReinRepulsive(Vertex node1, Vertex node2, double k, double weight)
        {
            Vector r = Vertex.VectorBetween(node1, node2);
            double distance = Math.Abs(r.Length);
            r.Normalize();

            Vector forceVector = r * -(k * k) / distance;

            return weight * forceVector;
        }
예제 #8
0
        /// <summary>
        /// Calculate the attractive force between two vertices.
        /// This is done using Hooke's Algorithm
        /// </summary>
        /// <param name="node1"></param>
        /// <param name="node2"></param>
        /// <param name="aWeight"></param>
        /// <returns></returns>
        public static Vector HCAttractive(Vertex node1, Vertex node2, double aWeight)
        {
            Vector r = Vertex.VectorBetween(node1, node2);
            double distance = Math.Abs(r.Length);
            r.Normalize();

            Vector forceVector = r * (distance - 1);

            return aWeight * forceVector;
        }
예제 #9
0
        private PointF[] VertToPoint(Vertex[] input)
        {
            PointF[] edge = new PointF[2];

            edge[0].X = (float)input[0].PositionVector.X;
            edge[0].Y = (float)input[0].PositionVector.Y;
            edge[1].X = (float)input[1].PositionVector.X;
            edge[1].Y = (float)input[1].PositionVector.Y;

            return edge;
        }
예제 #10
0
        /// <summary>
        /// Calculates the translation for Vertex node1 based on the repulsive and attractive forces between it and node2.
        /// The attractive force is calculated according to a logarithmic variation on Hooke's law while the repulsive force is calculated according to Coulomb's law.
        /// The total translation for node1 is then the sum of the translations on node1 based on every other node.
        /// </summary>
        /// <param name="node1">The vertex to be translated</param>
        /// <param name="node2">The vertex that's interacting with node1 via repulsive and attractive forces</param>
        /// <param name="c1">A constant that determines the strength of the attractive force</param>
        /// <param name="c2">A constant that determines the logarithmic scaling factor of the attractive force</param>
        /// <param name="c3">A constant that determines the strength of the repulsive force</param>
        /// <param name="s">The ratio between the size of the translation and the size of the combined attractive and repulsive force</param>
        /// <returns>The translation vector to be applied to node1</returns>
        public static Vector EadesForce(Vertex node1, Vertex node2, double c1, double c2, double c3, double s)
        {
            Vector r = Vertex.VectorBetween(node2, node1);
            Vector rn = r;
            rn.Normalize();
            double d = r.Length;

            Vector fAtt = node1.ConnectedWith(node2) ? c1 * Math.Log(d / c2, 2) * rn : new Vector(0, 0);
            Vector fRep = (c3 / (d * d)) * rn;

            return s * (fAtt + fRep);
        }
예제 #11
0
        /// <summary>
        /// Calculates the translation for Vertex node1 based on the repulsive and attractive forces between it and node2.
        /// The attractive and repulsive forces are calculated according to the optimal vertex distribution based on the algorithm of Fruchterman and Reingold
        /// The total translation for node1 is then the sum of the translations on node1 based on every other node.
        /// </summary>
        /// <param name="node1">The vertex to be translated</param>
        /// <param name="node2">The vertex that's interacting with node1 via repulsive and attractive forces</param>
        /// <param name="c">A constant that determines the weight of the optimal vertex distribution parameter</param>
        /// <param name="radius">A constant that determines the radius around the vertex to count the vertices in</param>
        /// <param name="s">The ratio between the size of the translation and the size of the combined attractive and repulsive force</param>
        /// <returns>The translation vector to be applied to node1</returns>
        public static Vector FruchtRein(Vertex node1, Vertex node2, double c, double radius, double s)
        {
            Vector r = Vertex.VectorBetween(node1, node2);
            Vector rn = r;
            rn.Normalize();
            double d = r.Length;

            double k = c * Math.Sqrt((Math.PI * radius * radius) / (1)); // Function to count number of objects in radius around Vertex v here
            Vector fAtt = node1.ConnectedWith(node2) ? ((d * d) / k) * rn : new Vector(0, 0);
            Vector fRep = (-(k * k) / d) * rn;

            return s * (fAtt + fRep);
        }
예제 #12
0
파일: IO.cs 프로젝트: michielvh1995/OMI
        // Converts a list of vertices to a list of strings
        // Helper function for CreateGraphs
        private static List<string> GraphToStrings(Vertex[] vertices)
        {
            List<string> lines = new List<string>();
            string id, x, y, connections;

            for (int i = 0; i < vertices.Length; i++)
            {
                id = vertices[i].ID.ToString();
                x = vertices[i].PositionVector.X.ToString();
                y = vertices[i].PositionVector.Y.ToString();
                connections = string.Join(",", vertices[i].connectedVertexIDs.ToArray());

                lines.Add(id + " " + x + " " + y + " " + connections);
            }

            return lines;
        }
예제 #13
0
        public void DrawGraph(Graphics g, Vertex[] vertices)
        {
            RectangleF node;

            foreach (var vertex in vertices)
            {
                // Draw the vertex
                PointF vertexPos = new PointF((float)vertex.PositionVector.X, (float)vertex.PositionVector.Y);
                node = new RectangleF(vertexPos.X - (nodeSize / 2f), vertexPos.Y - (nodeSize / 2f), nodeSize, nodeSize);
                g.FillEllipse(brush, node);
                g.DrawEllipse(pen1, node);

                // Draw the connections
                PointF connectedVertPos;
                foreach (var id in vertex.connectedVertexIDs)
                {
                    connectedVertPos = new PointF((float)vertices[id].PositionVector.X, (float)vertices[id].PositionVector.Y);
                    g.DrawLine(pen2, vertexPos, connectedVertPos);
                }
            }
        }
예제 #14
0
파일: Save.cs 프로젝트: michielvh1995/OMI
        //, int[] qualityValues)
        // Stores a graph in .txt format
        public static bool SaveGraph(double[] paramStrings, Vertex[] vertices)
        {
            double[] nameDoubles = new double[paramStrings.Length];

            for (int i = 0; i < paramStrings.Length; i++)
                nameDoubles[i] = paramStrings[i] * 10;

            String fileName = "/output/graph" + String.Join("", nameDoubles) + ".txt";

            // Check whether the file already exists, we don't want to overwrite it
            if (File.Exists(Directory.GetCurrentDirectory() + fileName))
                return false;

            String[] vertexStrings = new string[vertices.Length];

            for (int i = 0; i < vertices.Length; i++)
                vertexStrings[i] = vertices[i].ToString();

            File.WriteAllLines(Directory.GetCurrentDirectory() + fileName, vertexStrings);

            return true;
        }
예제 #15
0
파일: Vertex.cs 프로젝트: michielvh1995/OMI
 public static Vector VectorBetween(Vertex node1, Vertex node2)
 {
     return node2.PositionVector - node1.PositionVector;
 }
예제 #16
0
파일: Tests.cs 프로젝트: michielvh1995/OMI
        // Generates a specified number of vertices and their connections
        // Guaranteed is that the graph that these vertices form will be completely connected,
        // ie every vertex can be directly or indirectly reached by every other vertex
        public static Vertex[] GenerateVertices(int amount)
        {
            for (int i = 0; i < amount; i++)
            {
                // Random Position
                //int x = rndGen.Next(100, 400);
                //int y = rndGen.Next(100, 400);
                double x = rndGen.NextDouble();
                double y = rndGen.NextDouble();

                // Random Connections
                int connections = rndGen.Next(2);
                HashSet<int> connectionSet = new HashSet<int>();
                HashSet<int> connectedVertices = new HashSet<int>();

                int connection;
                do
                {
                    connection = connectedVertices.Count > 0 ? connectedVertices.ToList()[rndGen.Next(connectedVertices.Count)] : rndGen.Next(amount);
                } while (connection == i);
                connectionSet.Add(connection);
                connectedVertices.Add(i);

                for (int c = 0; c < connections; c++)
                {
                    int conn = rndGen.Next(amount);
                    if (conn != i)
                    {
                        connectionSet.Add(conn);
                        connectedVertices.Add(i);
                        connectedVertices.Add(conn);
                    }
                }

                // The ID is its position in the array
                Vertices[i] = new Vertex(i, new Vector(x, y), connectionSet);
            }

            // Each of the connections should go both ways.
            for (int i = 0; i < amount; i++)
            {
                foreach (int connected in Vertices[i].connectedVertexIDs)
                {
                    Vertices[connected].AddConnection(i);
                }
            }

            return Vertices;
        }
예제 #17
0
파일: Tests.cs 프로젝트: michielvh1995/OMI
 // General function to calculate the repulsive force for each algorithm
 private static Vector RepulsiveForce(AlgorithmType type, Vertex node1, Vertex node2, double k)
 {
     switch (type)
     {
         case AlgorithmType.HookeCoulomb:
             return Algorithms.HCRepulsive(node1, node2, rWeight);
         case AlgorithmType.Eades:
             return Algorithms.EadesRepulsive(node1, node2, rWeight);
         case AlgorithmType.FruchtRein:
             return Algorithms.FruchtReinRepulsive(node1, node2, k, FRWeight);
         default:
             return new Vector(0, 0);
     }
 }
예제 #18
0
 public static double FruchtReinConstant(Vertex node, Vertex[] graph, double c, double radius)
 {
     return c * Math.Sqrt((Math.PI * radius * radius) / CountVertices(node, graph, radius));
 }
예제 #19
0
        public static int GetEdgeCrossings(Vertex[] vertices)
        {
            int edgeCrossings = 0;
            //Console.WriteLine("Getting edge crossings...");

            EdgeCrossingSet done = new EdgeCrossingSet();
            foreach (var vertex in vertices)
            {
                foreach (var connectedVert in vertex.connectedVertexIDs)
                {
                    Vertex[] edge = { vertex, vertices[connectedVert] };
                    foreach (var otherEdgeVert1 in vertices)
                    {
                        foreach (var otherEdgeVert2 in otherEdgeVert1.connectedVertexIDs)
                        {
                            Vertex[] otherEdge = { otherEdgeVert1, vertices[otherEdgeVert2] };
                            if (CheckCross(edge, otherEdge))
                            {
                                if (done.Add(edge, otherEdge)) edgeCrossings++;
                            }
                        }
                    }
                }
            }

            return edgeCrossings;
        }
예제 #20
0
        private static double CountVertices(Vertex node, Vertex[] graph, double radius)
        {
            int count = 0;
            foreach (Vertex v in graph)
                if (Math.Abs(Vertex.VectorBetween(node, v).Length) <= radius)
                    count++;

            return count;
        }
예제 #21
0
        // Calculates the total amount of unique edges
        public static double getTotalEdges(Vertex[] vertices)
        {
            List<Tuple<int, int>> edgeList = new List<Tuple<int, int>>();
            Tuple<int, int> index, inverseIndex;

            for (int i = 0; i < vertices.Length; i++)
            {
                foreach(int id in vertices[i].connectedVertexIDs)
                {
                    index = Tuple.Create<int, int>(i, id);
                    inverseIndex = Tuple.Create<int, int>(id, i);
                    if (!edgeList.Contains(index) && !edgeList.Contains(inverseIndex))
                        edgeList.Add(index);
                }
            }

            return edgeList.Count;
        }
예제 #22
0
        // Calculates the dispersion of the edge lengths for each vertex using the coefficient of variation (standard deviation / median)
        // This is usually a value between 0 and 1, though it can be up to sqrt(n - 1) with n the size fo the data set
        public static double edgeLengthDispersion(Vertex[] vertices)
        {
            Dictionary<Tuple<int, int>, double> edgeDict = new Dictionary<Tuple<int, int>, double>();
            Tuple<int, int> index, inverseIndex;

            for (int i = 0; i < vertices.Length; i++)
            {
                foreach (int id in vertices[i].connectedVertexIDs)
                {
                    index = Tuple.Create<int, int>(i, id);
                    inverseIndex = Tuple.Create<int, int>(id, i);
                    if (!edgeDict.ContainsKey(index) && !edgeDict.ContainsKey(inverseIndex))
                        edgeDict.Add(index, Math.Abs(Vertex.VectorBetween(vertices[i], vertices[id]).Length));
                }
            }

            return standardDeviation(edgeDict.Values.ToArray()) / edgeDict.Values.Average();
        }
예제 #23
0
        /// <summary>
        /// Calculate the repulsive force between two vertices.
        /// This is done using Coulomb's Algorithm
        /// </summary>
        /// <param name="node1"></param>
        /// <param name="node2"></param>
        /// <param name="rWeight"></param>
        /// <returns></returns>
        public static Vector HCRepulsive(Vertex node1, Vertex node2, double rWeight)
        {
            // The vector between the two vertices (basically the line connecting them)
            Vector r = Vertex.VectorBetween(node1, node2);
            double distance = Math.Abs(r.Length);
            r.Normalize();

            Vector forceVector = -r / (distance * distance);

            return rWeight * forceVector;
        }
예제 #24
0
 public static double qualityTest(Vertex[] vertices)
 {
     return GetEdgeCrossings(vertices) / getTotalEdges(vertices) +
            edgeLengthDispersion(vertices) +
            vertexDensityDispersion(vertices);
 }
예제 #25
0
파일: Vertex.cs 프로젝트: michielvh1995/OMI
 // Add a new connection
 // Should not be used when the nodes are properly generated
 public void AddConnection(Vertex otherVertex)
 {
     this.connectedVertexIDs.Add(otherVertex.ID);
 }
예제 #26
0
        // Check whether two line segments cross each other
        // Source: http://csharphelper.com/blog/2014/08/determine-where-two-lines-intersect-in-c/
        private static bool CheckCross(Vertex[] line1, Vertex[] line2)
        {
            PointF p1 = new PointF((float)line1[0].PositionVector.X, (float)line1[0].PositionVector.Y);
            PointF p2 = new PointF((float)line1[1].PositionVector.X, (float)line1[1].PositionVector.Y);
            PointF p3 = new PointF((float)line2[0].PositionVector.X, (float)line2[0].PositionVector.Y);
            PointF p4 = new PointF((float)line2[1].PositionVector.X, (float)line2[1].PositionVector.Y);

            if (p1 == p2 || p2 == p3 || p1 == p4 || p2 == p4 || p1 == p3 || p3 == p4)
                return false;

            // Get the segments' parameters.
            float dx12 = p2.X - p1.X;
            float dy12 = p2.Y - p1.Y;
            float dx34 = p4.X - p3.X;
            float dy34 = p4.Y - p3.Y;

            // Solve for t1 and t2
            float denominator = (dy12 * dx34 - dx12 * dy34);
            float t1 = ((p1.X - p3.X) * dy34 + (p3.Y - p1.Y) * dx34) / denominator;
            if (float.IsInfinity(t1))
            {
                return false;
            }

            float t2 = ((p3.X - p1.X) * dy12 + (p1.Y - p3.Y) * dx12) / -denominator;

            // The segments intersect if t1 and t2 are between 0 and 1.
            return ((t1 >= 0) && (t1 <= 1) && (t2 >= 0) && (t2 <= 1));
        }
예제 #27
0
        // Calculates the length of the diagonal of the axis-aligned bounding box of a set of vertices
        private static double boundingBoxDiagonal(Vertex[] vertices)
        {
            double[] xPositions = vertices.Select(v => v.PositionVector.X).ToArray();
            double[] yPositions = vertices.Select(v => v.PositionVector.Y).ToArray();

            double minX = xPositions.Min();
            double maxX = xPositions.Max();
            double minY = yPositions.Min();
            double maxY = yPositions.Max();

            double deltaX = maxX - minX;
            double deltaY = maxY - minY;

            return Math.Sqrt(deltaX * deltaX + deltaY * deltaY);
        }
예제 #28
0
        // Calculates the dispersion of the vertex densities (the amount of vertices in a fixed radius around the vertex)
        // for each vertex using the coefficient of variation (standard deviation / median).
        // This is usually a value between 0 and 1, though it can be up to sqrt(n - 1) with n the size of the data set
        public static double vertexDensityDispersion(Vertex[] vertices)
        {
            double radius = 0.2d * boundingBoxDiagonal(vertices) / 2d;
            double[] vertexCounts = new double[vertices.Length];

            for (int i = 0; i < vertexCounts.Length; i++ )
                foreach (Vertex w in vertices)
                    if (Math.Abs(Vertex.VectorBetween(vertices[i], w).Length) <= radius)
                        vertexCounts[i]++;

            return standardDeviation(vertexCounts) / vertexCounts.Average();
        }
예제 #29
0
파일: Vertex.cs 프로젝트: michielvh1995/OMI
 // Check whether 2 nodes are connected
 public bool ConnectedWith(Vertex otherVertex)
 {
     return this.connectedVertexIDs.Contains(otherVertex.ID);
 }
예제 #30
0
파일: IO.cs 프로젝트: michielvh1995/OMI
        // Converts a list of strings representing a graph as generated by GraphToStrings
        // back to a Vertex array
        // Helper function for LoadGraphs
        private static Vertex[] StringsToGraph(List<string> lines)
        {
            Vertex[] graph = new Vertex[lines.Count];
            string[] fields, connectionStrings;
            HashSet<int> connections;
            int id;
            Vector position;

            for (int i = 0; i < lines.Count; i++)
            {
                fields = lines[i].Split(' ');
                connectionStrings = fields[3].Split(',');

                id = Convert.ToInt32(fields[0]);
                position = new Vector(Convert.ToDouble(fields[1]), Convert.ToDouble(fields[2]));

                connections = new HashSet<int>();
                foreach (string s in connectionStrings)
                    connections.Add(Convert.ToInt32(s));

                graph[i] = new Vertex(id, position, connections);
            }

            return graph;
        }