/// <summary> /// Draws the line transition latex. /// </summary> /// <param name="file">The file.</param> /// <param name="origin">The origin.</param> /// <param name="destination">The destination.</param> /// <param name="transitionName">Name of the transition.</param> /// <param name="fontSize">Size of the font.</param> public static void drawLineTransitionLatex(StreamWriter file, DrawingState origin, DrawingState destination, string transitionName, string fontSize) { Vector length; Vector arrowOrigin = new Vector(); Vector arrowDestination = new Vector(); Vector arrowPoint = new Vector(); Vector textPoint = new Vector(); double textOffset = 0, transitionGap = 0, stateAngle = 0; double arrowAngleOffset = 0, arrowInclination = 0; length = destination.position - origin.position; stateAngle = Math.Atan2(-length.Y, length.X); if (stateAngle < 0) { stateAngle += 2 * Math.PI; } if (origin.isAOrigin(destination)) { transitionGap = Constants.TRANSITION_OFFSET; arrowAngleOffset = Math.Atan2(transitionGap, length.Length - Constants.STATE_RADIUS - Constants.DISTANCE); if (arrowAngleOffset < 0) { arrowAngleOffset += 2 * Math.PI; } } arrowOrigin.X = origin.position.X + Constants.STATE_RADIUS + Constants.DISTANCE; arrowOrigin.Y = origin.position.Y - transitionGap; arrowDestination.X = origin.position.X + length.Length - Constants.STATE_RADIUS - Constants.DISTANCE; arrowDestination.Y = arrowOrigin.Y; arrowPoint.X = origin.position.X + Math.Cos(stateAngle + arrowAngleOffset) * (length.Length - Constants.STATE_RADIUS - Constants.DISTANCE); arrowPoint.Y = origin.position.Y - Math.Sin(stateAngle + arrowAngleOffset) * (length.Length - Constants.STATE_RADIUS - Constants.DISTANCE); arrowInclination = stateAngle + Math.PI; drawLatexLine(file, arrowOrigin, arrowDestination, stateAngle, origin.position); drawLatexArrow(file, arrowPoint, -arrowInclination, arrowPoint); textOffset = Math.Atan2(Constants.TEXT_OFFSET + transitionGap, length.Length / 2); if (textOffset < 0) { textOffset += 2 * Math.PI; } textPoint.X = origin.position.X + Math.Cos(-textOffset + stateAngle) * (length.Length / 2); textPoint.Y = origin.position.Y - Math.Sin(-textOffset + stateAngle) * (length.Length / 2); writeTextLatex(file, textPoint, transitionName, fontSize, -stateAngle); }
//insere um estado na lista de estado de anterior public void addOrigin(DrawingState state) { int value; if (originStates.TryGetValue(state, out value)) { originStates[state] = value + 1; } else { originStates.Add(state, 1); } }
/// <summary> /// Draws the state of the latex. /// </summary> /// <param name="file">The file.</param> /// <param name="state">The state.</param> /// <param name="radius">The radius.</param> /// <param name="fontSize">Size of the font.</param> public static void drawLatexState(StreamWriter file, DrawingState state, int radius, string fontSize) { string y = Drawing.round(state.position.Y); string x = Drawing.round(state.position.X); file.WriteLine("\\draw [black, line width= 0.8pt] (" + x + "," + y + ") circle (" + radius + ");"); if (state.IsMarked) { file.WriteLine("\\draw [black, line width= 0.8pt] (" + x + "," + y + ") circle (" + (radius - 4) + ");"); } writeTextLatex(file, state.position, state.Alias, fontSize, 0); }
//insere um estado na lita de estado de destino public void addDestination(DrawingState state, string eventName) { Tuple <string, int> value; if (destinationStates.TryGetValue(state, out value)) { value = new Tuple <string, int>(value.Item1 + ", " + eventName, value.Item2 + 1); destinationStates[state] = value; } else { destinationStates.Add(state, new Tuple <string, int>(eventName, 1)); } }
/// <summary> /// Draws the state of the SVG. /// </summary> /// <param name="file">The file.</param> /// <param name="state">The state.</param> /// <param name="radius">The radius.</param> public static void drawSVGState(StreamWriter file, DrawingState state, int radius) { string y = Drawing.round(state.position.Y); string x = Drawing.round(state.position.X); file.WriteLine("\t<circle cx=\"" + x + "\" cy=\"" + y + "\" r=\"" + radius + "\" stroke=\"black\" stroke-width=\"1\" fill=\"none\" />"); if (state.IsMarked) { file.WriteLine("\t<circle cx=\"" + x + "\" cy=\"" + y + "\" r=\"" + (radius - 4) + "\" stroke=\"black\" stroke-width=\"1\" fill=\"none\" />"); } int fontSize = 17; Vector gap = new Vector(0, fontSize / 3); writeTextSVG(file, state.position, state.Alias, 0, gap, "none", fontSize); }
// verifica se o estado dado eh igual a algum na lista de destino public bool IsADestination(DrawingState state) { return(destinationStates.ContainsKey(state)); }
// verifica se o estado dado eh igual a algum anterior public bool isAOrigin(DrawingState state) { return(originStates.ContainsKey(state)); }
//Simula a dinamica de força do sistema /// <summary> /// Prepares the specified g. /// </summary> /// <param name="G">The g.</param> /// <returns>Dictionary<System.String, DrawingState>.</returns> private static Dictionary <string, DrawingState> prepare(DeterministicFiniteAutomaton G) { //CRIANDO MÉTODO QUE SERA UTILIZADO PARA O DESENVOLVIMENTO DA BIBLIOTECA var drawingStatesList = new Dictionary <string, DrawingState>(); // lista de estados com cordenadas //Cria uma lista de estados com parametros de posição para serem desenhados foreach (var item in G.States) { var state = new DrawingState(item.ToString(), item.Marking) { initialState = item.Equals(G.InitialState) }; drawingStatesList.Add(item.ToString(), state); } // aloca os estados dentro de um circulo de raio e centro que serão determinados var radius = Constants.SPRING_LENGTH * drawingStatesList.Count; var center = new Vector(radius + Constants.AREA_LIMIT_OFFSET, radius + Constants.AREA_LIMIT_OFFSET); initialConfiguration(drawingStatesList, radius, center); // Atraves da lista de transiçoes associa para cada estado quais sao os estados de origem e qual era o anterior; foreach (var item in G.Transitions) { if (drawingStatesList.TryGetValue(item.Origin.ToString(), out var state)) { var transitionName = item.Trigger + ((item.IsControllableTransition) ? "" : "'"); state.addDestination(drawingStatesList[item.Destination.ToString()], transitionName); } if (drawingStatesList.TryGetValue(item.Destination.ToString(), out state)) { state.addOrigin(drawingStatesList[item.Origin.ToString()]); } } var force = new Vector(); var biggestForce = new Vector(); for (int j = 0; j < Constants.MAX_ITERATIONS; ++j) { force.X = 0; force.Y = 0; foreach (var item in drawingStatesList) { var attractionForce = item.Value.attractionForce(Constants.SPRING_CONSTANT, Constants.SPRING_LENGTH); var repulsionForce = item.Value.repulsionForce(Constants.CONSTANT_OF_REPULSION, drawingStatesList); force = attractionForce + repulsionForce; if (force.Length > biggestForce.Length) { biggestForce = force; } // desloca estado para uma posição melhor if (item.Value.initialState) { continue; } var position = item.Value.position + Constants.DELTA * force; position.X = Max(position.X, Constants.AREA_LIMIT_OFFSET); position.X = Min(position.X, Constants.AREA_LIMIT_OFFSET + 2 * radius); position.Y = Max(position.Y, Constants.AREA_LIMIT_OFFSET); position.Y = Min(position.Y, Constants.AREA_LIMIT_OFFSET + 2 * radius); item.Value.position = position; } if (biggestForce.Length <= Constants.STOP_CRITERION.Length) { break; } } return(drawingStatesList); }
/// <summary> /// Draws the curve transition latex. /// </summary> /// <param name="file">The file.</param> /// <param name="origin">The origin.</param> /// <param name="destination">The destination.</param> /// <param name="transitionName">Name of the transition.</param> /// <param name="fontSize">Size of the font.</param> public static void drawCurveTransitionLatex(StreamWriter file, DrawingState origin, DrawingState destination, string transitionName, string fontSize) { Vector startArc = new Vector(); Vector arcDestination = new Vector(); Vector firstArcPoint = new Vector(); Vector secondArcPoint = new Vector(); Vector statesDistance = new Vector(); Vector transitionNamePoint = new Vector(); Vector distanceArrowDestination = new Vector(); //distancia entre estado origem e destino seta Vector arrowPoint = new Vector(); double startArcAngle = Math.PI / 8; double stateAngle; double arrowAnglePointFix; double arrowInclination, arrowAngleFix; string stateAngleDegree; statesDistance = destination.position - origin.position; stateAngle = Math.Atan2(statesDistance.Y, statesDistance.X); if (stateAngle < 0) { stateAngle += 2 * Math.PI; } stateAngleDegree = Drawing.round(stateAngle * 180 / Math.PI); //calculo do ponto de incio transiçao startArc.X = origin.position.X + Math.Cos(startArcAngle) * Constants.STATE_RADIUS; startArc.Y = origin.position.Y + Math.Sin(startArcAngle) * Constants.STATE_RADIUS; //calculo do ponto de destino transição arcDestination.X = origin.position.X + statesDistance.Length - Math.Cos(startArcAngle) * Constants.STATE_RADIUS; arcDestination.Y = startArc.Y; //calculo primeiro ponto do arco firstArcPoint.X = origin.position.X + statesDistance.Length / 3; firstArcPoint.Y = origin.position.Y + statesDistance.Length / 5; //calculo segundo ponto do arco secondArcPoint.X = origin.position.X + 2 * statesDistance.Length / 3; secondArcPoint.Y = origin.position.Y + statesDistance.Length / 5; //calculo posião seta distanceArrowDestination = arcDestination - origin.position; arrowAnglePointFix = Math.Atan2(distanceArrowDestination.Y, distanceArrowDestination.X); arrowPoint.X = origin.position.X + Math.Cos(arrowAnglePointFix + stateAngle) * distanceArrowDestination.Length; arrowPoint.Y = origin.position.Y + Math.Sin(arrowAnglePointFix + stateAngle) * distanceArrowDestination.Length; arrowAngleFix = Math.Atan2(firstArcPoint.Y - startArc.Y, firstArcPoint.X - startArc.X) * 0.75; arrowInclination = stateAngle + Math.PI - arrowAngleFix; //arredondamento string x1 = Drawing.round(origin.position.X); string y1 = Drawing.round(origin.position.Y); string x2 = Drawing.round(startArc.X); string y2 = Drawing.round(startArc.Y); string x3 = Drawing.round(firstArcPoint.X); string y3 = Drawing.round(firstArcPoint.Y); string x4 = Drawing.round(secondArcPoint.X); string y4 = Drawing.round(secondArcPoint.Y); string x5 = Drawing.round(arcDestination.X); string y5 = Drawing.round(arcDestination.Y); file.WriteLine("\\draw[line width=0.8pt, rotate around={" + stateAngleDegree + ":(" + x1 + "," + y1 + ")}, line width=.5pt, smooth] (" + x2 + "," + y2 + ") .. controls (" + x3 + "," + y3 + ") and (" + x4 + "," + y4 + ") .. (" + x5 + "," + y5 + ");"); //COLCOCAR SETA NA TRANSICAO drawLatexArrow(file, arrowPoint, arrowInclination, arrowPoint); // COLOCAR A CODIGO PARA INSERIR NOME NAS TRANSIÇOES double textAngleFix = Math.Atan2(statesDistance.Length / 4, statesDistance.Length / 2); transitionNamePoint.X = origin.position.X + Math.Cos(stateAngle + textAngleFix) * statesDistance.Length / 2; transitionNamePoint.Y = origin.position.Y + Math.Sin(stateAngle + textAngleFix) * statesDistance.Length / 2; transitionNamePoint = Drawing.RoundVector(transitionNamePoint); writeTextLatex(file, transitionNamePoint, transitionName, fontSize, stateAngle); }
/// <summary> /// Draws the curve transition2. /// </summary> /// <param name="file">The file.</param> /// <param name="origin">The origin.</param> /// <param name="destination">The destination.</param> /// <param name="transitionName">Name of the transition.</param> /// <param name="fontFill">The font fill.</param> /// <param name="fontSize">Size of the font.</param> public static void drawCurveTransition2(StreamWriter file, DrawingState origin, DrawingState destination, string transitionName, string fontFill, int fontSize) { Vector stateDistance = destination.position - origin.position; double curveHeight; double transitionInclination = Math.Atan2(-stateDistance.Y, stateDistance.X); double startArrowAngle = 0; double endArrowAngle = 0; double offset = 0; double arrowAngleFix; double textAngleFix = 0; double textPointFix = 0; double arrowAngle; double ArcLength; Vector startArcPoint = new Vector(); Vector destinationArcPoint = new Vector(); string startArcBeginRef; if (transitionInclination < 0) { transitionInclination += 2 * Math.PI; } double transitionIncDegree = -Math.Round(180 * transitionInclination / Math.PI); startArcBeginRef = Drawing.round(origin.position.X + Constants.STATE_RADIUS + Constants.DISTANCE, 0); ArcLength = stateDistance.Length - 2 * (Constants.STATE_RADIUS + Constants.DISTANCE); curveHeight = -Math.Round(ArcLength / 3); offset = -Constants.TRANSITION_OFFSET; startArrowAngle = Math.Atan2(-offset, (Constants.STATE_RADIUS + Constants.DISTANCE)); endArrowAngle = Math.Atan2(-offset, (Constants.STATE_RADIUS + Constants.DISTANCE + ArcLength)); arrowAngleFix = Math.PI - Math.Atan2(-curveHeight, ArcLength / 2); arrowAngle = transitionInclination + arrowAngleFix; startArcPoint.X = origin.position.X + Math.Cos(transitionInclination + startArrowAngle) * (Constants.STATE_RADIUS + Constants.DISTANCE); startArcPoint.Y = origin.position.Y - Math.Sin(transitionInclination + startArrowAngle) * (Constants.STATE_RADIUS + Constants.DISTANCE); destinationArcPoint.X = origin.position.X + Math.Cos(transitionInclination + endArrowAngle) * (Constants.STATE_RADIUS + Constants.DISTANCE + ArcLength); destinationArcPoint.Y = origin.position.Y - Math.Sin(transitionInclination + endArrowAngle) * (Constants.STATE_RADIUS + Constants.DISTANCE + ArcLength); string p1 = Drawing.round(origin.position.Y + offset); string x1 = Drawing.round(origin.position.X); string y1 = Drawing.round(origin.position.Y); file.WriteLine("\t<path d=\"M " + startArcBeginRef + " " + p1 + " q " + Math.Round(ArcLength / 2) + " " + curveHeight + " " + Math.Round(ArcLength) + " " + 0 + "\" stroke=\"black\" stroke-width=\"1\" fill=\"none\" transform =\"rotate(" + transitionIncDegree + " " + x1 + "," + y1 + ")\" />"); drawSVGArrow(file, destinationArcPoint, arrowAngle, destinationArcPoint); textPointFix = Constants.TEXT_OFFSET; if (transitionInclination > Math.PI / 2 && transitionInclination < 3 * Math.PI / 2) { textPointFix = Constants.TEXT_OFFSET + 6; } Vector textPoint = new Vector(); double distanceArrowOriginText = Math.Sqrt((-curveHeight / 2 + textPointFix) * (-curveHeight / 2 + textPointFix) + (ArcLength / 2) * (ArcLength / 2)); textAngleFix = Math.Atan2(-curveHeight / 2 + textPointFix, ArcLength / 2); textPoint.X = startArcPoint.X + Math.Cos(transitionInclination + textAngleFix) * distanceArrowOriginText; textPoint.Y = startArcPoint.Y - Math.Sin(transitionInclination + textAngleFix) * distanceArrowOriginText; textPoint = Drawing.RoundVector(textPoint); Vector gap = new Vector(); writeTextSVG(file, textPoint, transitionName, transitionInclination, gap, fontFill, fontSize); }
/// <summary> /// Draws the line transition. /// </summary> /// <param name="file">The file.</param> /// <param name="origin">The origin.</param> /// <param name="destination">The destination.</param> /// <param name="transitionName">Name of the transition.</param> /// <param name="fontFill">The font fill.</param> /// <param name="fontSize">Size of the font.</param> public static void drawLineTransition(StreamWriter file, DrawingState origin, DrawingState destination, string transitionName, string fontFill, int fontSize) { Vector length, originPoint, destinationPoint, arrowPoint; Vector textPoint = new Vector(); Vector fixTextPosition = new Vector(); double x, y, textOffset = 0, transitionGap = 0; double stateAngle = 0, arrowAngleOffset = 0, arrowInclination = 0; length = destination.position - origin.position; stateAngle = Math.Atan2(-length.Y, length.X); if (stateAngle < 0) { stateAngle += 2 * Math.PI; } if (origin.isAOrigin(destination)) { transitionGap = Constants.TRANSITION_OFFSET; arrowAngleOffset = Math.Atan2(transitionGap, length.Length - Constants.STATE_RADIUS - Constants.DISTANCE); if (arrowAngleOffset < 0) { arrowAngleOffset += 2 * Math.PI; } } x = origin.position.X + Constants.STATE_RADIUS + Constants.DISTANCE; y = origin.position.Y - transitionGap; originPoint = new Vector(x, y); x = origin.position.X + length.Length - Constants.STATE_RADIUS - Constants.DISTANCE; y = originPoint.Y; destinationPoint = new Vector(x, y); x = origin.position.X + Math.Cos(stateAngle + arrowAngleOffset) * (length.Length - Constants.STATE_RADIUS - Constants.DISTANCE); y = origin.position.Y - Math.Sin(stateAngle + arrowAngleOffset) * (length.Length - Constants.STATE_RADIUS - Constants.DISTANCE); arrowPoint = new Vector(x, y); arrowInclination = stateAngle + Math.PI; drawSVGLine(file, originPoint, destinationPoint, -stateAngle, origin.position); drawSVGArrow(file, arrowPoint, arrowInclination, arrowPoint); textOffset = Math.Atan2(Constants.TEXT_OFFSET + transitionGap, length.Length / 2); if (textOffset < 0) { textOffset += 2 * Math.PI; } //correcão do posicionamnto do texto quando angulo vara entre 90 e 270 graus if (stateAngle >= Math.PI / 2 && stateAngle <= 3 * Math.PI / 2) { fixTextPosition.X = -Math.Sin(stateAngle) * Constants.TEXT_OFFSET; fixTextPosition.Y = -Math.Cos(stateAngle) * Constants.TEXT_OFFSET; } x = origin.position.X + Math.Cos(textOffset + stateAngle) * (length.Length / 2) + fixTextPosition.X; y = origin.position.Y - Math.Sin(textOffset + stateAngle) * (length.Length / 2) + fixTextPosition.Y; Vector gap = new Vector(); writeTextSVG(file, textPoint, transitionName, stateAngle, gap, fontFill, fontSize); }