Beispiel #1
0
        static FiniteStateMachineLayoutScore()
        {
            Perfect = new FiniteStateMachineLayoutScore();
            Perfect.AnalyzeData();

            Worst = new FiniteStateMachineLayoutScore();
            Worst.AnalyzeData();
            Worst.Penalty = Double.MinValue;
        }
Beispiel #2
0
        /*
         * private Dictionary<int, double> GetStatesTooCloseToEdge(Dictionary<int, Point> layout,
         *      int stateId1, int stateId2, double threshold)
         * {
         *      if (stateId1 == stateId2)
         *              return null;
         *
         *      if (!transitions.Any(x => x.Item1 == stateId1 && x.Item3 == stateId2))
         *              return null;
         *
         *      var p1 = layout[stateId1];
         *      var p2 = layout[stateId2];
         *
         *      Dictionary<int, double> results = null;
         *      foreach (var key in layout.Keys)
         *      {
         *              if (key == stateId1 || key == stateId2)
         *                      continue;
         *
         *              double dist = layout[key].DistanceToLine(p1, p2);
         *
         *              if (dist < threshold)
         *              {
         *                      if (results == null)
         *                              results = new Dictionary<int, double>();
         *                      results.Add(key, dist);
         *              }
         *      }
         *      return results;
         * }
         */

        /// <summary>
        /// Returns a score of a given layout.
        ///
        /// This score is relative, and unless it is zero (perfect score),
        /// there needs to be another layout for comparison in order for any conclusions to be drawn.
        /// Zero means that if the machine is drawn using this layout, it will be very easy for human eye
        /// to analyse it, and that humans in generally will think of it as a clear and understandable drawing.
        /// For example, you can receive -1000, and think this is bad, but new layout may receive -10^6.
        /// Also if you receive -0.001 yo may think this is good, but new layout can still receive -10^-6.
        ///
        /// Score is based on number of intersecting edges, number of nodes that lay on some edge,
        /// number of nodes that are very close to each other, etc.
        /// </summary>
        /// <returns>zero if layout is perfect, negative value if it is not</returns>
        private FiniteStateMachineLayoutScore CalculateScore(Dictionary <int, Point> layoutVertices)
        {
            FiniteStateMachineLayoutScore currentScore = null;

            if (layoutVertices == null || layoutVertices.Count <= 1)
            {
                return(FiniteStateMachineLayoutScore.Perfect);
            }

            foreach (var key1 in layoutVertices.Keys)
            {
                foreach (var key2 in layoutVertices.Keys)
                {
                    if (key1 == key2)
                    {
                        continue;
                    }

                    var p1 = layoutVertices[key1];
                    var p2 = layoutVertices[key2];

                    #region state on state
                    // check if point are too close to each other
                    if (key1 < key2)
                    {
                        double dist = p1.Distance(p2);
                        if (dist < MinimumStateDistance)
                        {
                            //nodesDistanceScore -= Math.Sqrt(50 - dist);
                            if (currentScore == null)
                            {
                                currentScore = new FiniteStateMachineLayoutScore();
                            }
                            currentScore.VerticesOnVertices.Add(new Tuple <int, int, double>(key1, key2, dist));
                        }
                    }
                    #endregion

                    // check connected vertices
                    int transitionIndex = transitions.IndexOf(x => x.InitialStateId == key1 && x.ResultingStateId == key2);
                    if (transitionIndex == -1)
                    {
                        continue;
                    }

                    #region state on edge
                    // check if any state is obstructed by the edge
                    foreach (var key in layoutVertices.Keys)
                    {
                        if (key == key1 || key == key2)
                        {
                            continue;
                        }

                        double dist = layoutVertices[key].DistanceToLine(p1, p2);

                        if (dist < 30)
                        {
                            if (currentScore == null)
                            {
                                currentScore = new FiniteStateMachineLayoutScore();
                            }
                            currentScore.VerticesOnEdges.Add(new Tuple <int, int, double>(key, transitionIndex, dist));
                        }
                    }
                    #endregion

                    // check if the edge intersects with any other edge
                    foreach (var keyOther1 in layoutVertices.Keys)
                    {
                        foreach (var keyOther2 in layoutVertices.Keys)
                        {
                            if (keyOther1 == keyOther2)
                            {
                                continue;
                            }
                            if (keyOther1 == key1 || keyOther2 == key2 || keyOther1 == key2 || keyOther2 == key1)
                            {
                                continue;
                            }
                            int transitionIndexOther = transitions.IndexOf(
                                x => x.InitialStateId == keyOther1 && x.ResultingStateId == keyOther2);
                            if (transitionIndexOther == -1)
                            {
                                continue;
                            }

                            var pOther1 = layoutVertices[keyOther1];
                            var pOther2 = layoutVertices[keyOther2];

                            if (p1.Intersects(p2, pOther1, pOther2))
                            {
                                if (currentScore == null)
                                {
                                    currentScore = new FiniteStateMachineLayoutScore();
                                }
                                currentScore.IntersectingEdges.Add(new Tuple <int, int>(transitionIndex, transitionIndexOther));
                            }
                        }
                    }
                }
            }

            return(currentScore == null ? FiniteStateMachineLayoutScore.Perfect : currentScore);
        }
Beispiel #3
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="sessionId"></param>
        /// <param name="currentSessionId"></param>
        /// <exception cref="ApplicationException">when at least one of the layout threads fails</exception>
        /// <returns></returns>
        public bool Create(int sessionId, ref int currentSessionId)
        {
            int workGroupSize = 8;

            var layoutsAll = new List <KeyValuePair <Dictionary <int, Point>, FiniteStateMachineLayoutScore> >();
            int bestLayout = 0;

            double defaultDistanceRatio = MinimumStateDistance / 72;

            for (int i = 0; i < 32; ++i)
            {
                var layoutsScores = new FiniteStateMachineLayoutScore[workGroupSize];
                var layouts       = new Dictionary <int, Point> [workGroupSize];

                try
                {
                    // try several layouts in parallel
                    Parallel.For(0, workGroupSize, (int n) =>
                    {
                        IDictionary <string, Point> createdVertices = null;

                        //if (n % 2 == 0)
                        createdVertices = Create4();
                        //else
                        //	createdVertices = Create6();

                        var layout = new Dictionary <int, Point>();

                        var firstCreatedVertex = createdVertices[vertexLabels[0]];

                        double minX = firstCreatedVertex.X, minY = firstCreatedVertex.Y;
                        foreach (var pos in createdVertices)
                        {
                            var location = pos.Value;
                            double x     = location.X * defaultDistanceRatio;
                            double y     = location.Y * defaultDistanceRatio;
                            if (x < minX)
                            {
                                minX = x;
                            }
                            if (y < minY)
                            {
                                minY = y;
                            }
                            layout.Add(int.Parse(pos.Key), new Point(x, y));
                        }

                        minX -= LayoutOffset + 1;
                        minY -= LayoutOffset + 1;

                        //bool invalid = false;
                        for (int key = 0; key < layout.Count; ++key)
                        {
                            layout[key] = new Point(layout[key].X - minX, layout[key].Y - minY);
                            //if (layout[key].X < LayoutOffset || layout[key].Y < LayoutOffset) invalid = true;
                        }

                        var score = CalculateScore(layout);

                        score.AnalyzeData();

                        //if (invalid)
                        //	score = FiniteStateMachineLayoutScore.Perfect;
                        //else
                        //	score = FiniteStateMachineLayoutScore.Worst;

                        layoutsScores[n] = score;
                        layouts[n]       = layout;
                    });
                }
                catch (AggregateException e)
                {
                    //foreach (var exception in e.InnerExceptions)
                    //{
                    //	System.Console.Out.WriteLine("one of the layout jobs failed:");
                    //	System.Console.Out.WriteLine(exception.ToString());
                    //}
                    throw new ApplicationException("at least one of the layout finding threads caused an error", e);
                }

                if (sessionId != currentSessionId)
                {
                    return(false);
                }

                int newBestLayout = 0;
                for (int j = 1; j < workGroupSize; ++j)
                {
                    if (layoutsScores[j] == FiniteStateMachineLayoutScore.Perfect)
                    {
                        newBestLayout = j;
                        break;
                    }
                    if (layoutsScores[j].CompareTo(layoutsScores[newBestLayout]) > 0)
                    {
                        newBestLayout = j;
                    }
                }

                layoutsAll.Add(new KeyValuePair <Dictionary <int, Point>, FiniteStateMachineLayoutScore>(
                                   layouts[newBestLayout], layoutsScores[newBestLayout]));

                if (layoutsScores[newBestLayout] == FiniteStateMachineLayoutScore.Perfect)
                {
                    bestLayout = layoutsAll.Count - 1;
                    break;
                }

                if (layoutsScores[newBestLayout].CompareTo(layoutsAll[bestLayout].Value) > 0)
                {
                    bestLayout = layoutsAll.Count - 1;
                }
            }

            vertices    = layoutsAll[bestLayout].Key;
            layoutScore = layoutsAll[bestLayout].Value;
            CreateEdges();
            return(true);
        }