Merge lp:~tapaal-contributor/tapaal/cpn-gui-TikZ-support into lp:~tapaal-contributor/tapaal/cpn-gui-dev

Proposed by Kristian Morsing Pedersen
Status: Superseded
Proposed branch: lp:~tapaal-contributor/tapaal/cpn-gui-TikZ-support
Merge into: lp:~tapaal-contributor/tapaal/cpn-gui-dev
Diff against target: 485 lines (+200/-139)
1 file modified
src/net/tapaal/export/TikZExporter.java (+200/-139)
To merge this branch: bzr merge lp:~tapaal-contributor/tapaal/cpn-gui-TikZ-support
Reviewer Review Type Date Requested Status
Jiri Srba Needs Fixing
Kenneth Yrke Jørgensen code Pending
Review via email: mp+416423@code.launchpad.net

This proposal supersedes a proposal from 2022-02-21.

This proposal has been superseded by a proposal from 2022-03-07.

Commit message

Added TikZ support for colored nets.
Added a framed box to the Tikz output for global variables/constants/color types.
Removed subscripiting from transition- and place names
Changed \mathrm to \mathit
Added more adjustment options for transitions, places and arcs
Merged with cpn-gui-dev

Description of the change

The TikZ export now shows all of the new features associated with colored nets.
Also added a framed box that contains all the global variables, constants and/or color types for a given net.
Subscripting from transition- and place names have been removed, so it looks more like the GUI.
\mathrm has also been replaces with \mathit.

To post a comment you must log in.
Revision history for this message
Kenneth Yrke Jørgensen (yrke) : Posted in a previous version of this proposal
review: Approve (code)
Revision history for this message
Jiri Srba (srba) wrote : Posted in a previous version of this proposal

It would be nice if instead of (in referendum colored timed):

1′v[1, 2]Voters1 → [1, 4]

one would print:

1′v
[1, 2]
Voters1 → [1, 4]

(on three sepratate lines).

review: Needs Fixing
Revision history for this message
Jiri Srba (srba) wrote : Posted in a previous version of this proposal

Please, set the default position for arc lables to pos=0.5

review: Needs Fixing
Revision history for this message
Jiri Srba (srba) wrote :

At the end of the labels, there is a redundant \\ that makes the spacing look ugly. E.g. in

\node[place, label={[align=left,label distance=0cm]270:$\mathrm{voting} ... $\mathit{4}$ \\}] at (390,-345) (voting) {};

The label should finish with just ... $\mathit{4}$ }] without the extra \\

review: Needs Fixing
Revision history for this message
Jiri Srba (srba) wrote :

Also, when exporting age of tokens in the initial marking, please write 0.0 instead of 0,0

review: Needs Fixing
1578. By Kristian Morsing Pedersen <email address hidden>

Removed redundant \\ and changed 0,0 -> 0.0 for age of tokens in initial markings

1579. By Kristian Morsing Pedersen <email address hidden>

Changed x -> \times in inhibitor arcs

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/net/tapaal/export/TikZExporter.java'
2--- src/net/tapaal/export/TikZExporter.java 2022-02-21 19:46:59 +0000
3+++ src/net/tapaal/export/TikZExporter.java 2022-03-07 14:26:18 +0000
4@@ -3,16 +3,17 @@
5 import java.io.FileWriter;
6 import java.io.IOException;
7 import java.io.PrintWriter;
8-import java.util.List;
9+import java.util.*;
10
11+import dk.aau.cs.model.CPN.ColorType;
12+import dk.aau.cs.model.CPN.Variable;
13+import dk.aau.cs.model.tapn.Constant;
14 import dk.aau.cs.model.tapn.TimedToken;
15
16+import net.tapaal.gui.petrinet.Context;
17 import pipe.gui.petrinet.dataLayer.DataLayer;
18 import pipe.gui.TAPAALGUI;
19-import pipe.gui.petrinet.graphicElements.Arc;
20-import pipe.gui.petrinet.graphicElements.ArcPathPoint;
21-import pipe.gui.petrinet.graphicElements.Place;
22-import pipe.gui.petrinet.graphicElements.Transition;
23+import pipe.gui.petrinet.graphicElements.*;
24 import pipe.gui.petrinet.graphicElements.tapn.TimedInhibitorArcComponent;
25 import pipe.gui.petrinet.graphicElements.tapn.TimedInputArcComponent;
26 import pipe.gui.petrinet.graphicElements.tapn.TimedPlaceComponent;
27@@ -45,7 +46,7 @@
28 if (option == TikZOutputOption.FULL_LATEX) {
29 out.println("\\documentclass[a4paper]{article}");
30 out.println("\\usepackage{tikz}");
31- out.println("\\usetikzlibrary{petri,arrows}");
32+ out.println("\\usetikzlibrary{petri,arrows,positioning}");
33 out.println("\\usepackage{amstext}");
34 out.println();
35 out.println("\\begin{document}");
36@@ -62,6 +63,8 @@
37 out.print(exportTransitions(net.getTransitions()));
38 out.print(exportArcs(net.getArcs()));
39
40+ out.println(exportGlobalVariables());
41+
42 out.println("\\end{tikzpicture}");
43 if (option == TikZOutputOption.FULL_LATEX) {
44 out.println("\\end{document}");
45@@ -94,7 +97,7 @@
46 ArcPathPoint currentPoint = arc.getArcPath().getArcPathPoint(i);
47
48 if(currentPoint.getPointType() == ArcPathPoint.STRAIGHT) {
49- arcPoints += "to[bend right=0] (" + (currentPoint.getX()) + "," + (currentPoint.getY() * (-1)) + ") ";
50+ arcPoints += "to [bend right=0] (" + (currentPoint.getX()) + "," + (currentPoint.getY() * (-1)) + ") ";
51 } else if (currentPoint.getPointType() == ArcPathPoint.CURVED) {
52 double xCtrl1 = Math.round(currentPoint.getControl1().getX());
53 double yCtrl1 = Math.round(currentPoint.getControl1().getY() * (-1));
54@@ -109,21 +112,19 @@
55 }
56
57 String arrowType = getArcArrowType(arc);
58- String arcLabel = getArcLabels(arc);
59
60+ out.append("% Arc between " + arc.getSource().getName() + " and " + arc.getTarget().getName() + "\n");
61 out.append("\\draw[");
62 out.append(arrowType);
63- out.append("] (");
64+ out.append(",pos=0.5] (");
65 out.append(arc.getSource().getId());
66 out.append(") ");
67 out.append(arcPoints);
68- out.append("to[bend right=0]");
69- out.append(" (");
70- out.append(arc.getTarget().getId());
71- out.append(") {};\n");
72- if(!arcLabel.equals(""))
73- out.append("%% Label for arc between " + arc.getSource().getName() + " and " + arc.getTarget().getName() + "\n");
74- out.append(arcLabel);
75+ out.append("to node[bend right=0,auto,align=left]");
76+ out.append(" {");
77+ out.append(handleNameLabel(arc.getNameLabel().getText()));
78+ out.append("} ");
79+ out.append("(" + arc.getTarget().getId() + ");\n");
80 }
81 return out;
82 }
83@@ -142,50 +143,6 @@
84 return arrowType;
85 }
86
87- protected String getArcLabels(Arc arc) {
88- String arcLabel = "";
89- String arcLabelPositionString = "\\draw (" + (arc.getNameLabel().getX()) + "," + (arc.getNameLabel().getY())*(-1) + ") node {";
90-
91- if (arc instanceof TimedInputArcComponent) {
92- if (!(arc.getSource() instanceof TimedTransitionComponent)) {
93- arcLabel = arcLabelPositionString;
94- if (arc.getWeight().value() > 1) {
95- arcLabel += "$" + arc.getWeight().value() + "\\times$\\ ";
96- }
97-
98- if(TAPAALGUI.getCurrentTab().getLens().isTimed()) {
99- arcLabel += "$\\mathrm{" + replaceWithMathLatex(getGuardAsStringIfNotHidden((TimedInputArcComponent) arc)) + "}$";
100- if (arc instanceof TimedTransportArcComponent)
101- arcLabel += ":" + ((TimedTransportArcComponent) arc).getGroupNr();
102- arcLabel += "};\n";
103- } else {
104- arcLabel += "};\n";
105- }
106-
107- } else {
108- arcLabel = arcLabelPositionString;
109- if (arc.getWeight().value() > 1) {
110- arcLabel += "$" + arc.getWeight().value() + "\\times$\\ ";
111- }
112- arcLabel += ":" + ((TimedTransportArcComponent) arc).getGroupNr() + "};\n";
113- }
114-
115- } else {
116- if (arc.getWeight().value() > 1) {
117- arcLabel += arcLabelPositionString + "$" + arc.getWeight().value() + "\\times$\\ };\n";
118- }
119- }
120- return arcLabel;
121- }
122-
123- private String getGuardAsStringIfNotHidden(TimedInputArcComponent arc) {
124- if (!TAPAALGUI.getAppGui().showZeroToInfinityIntervals() && arc.getGuardAsString().equals("[0,inf)")){
125- return "";
126- } else {
127- return arc.getGuardAsString();
128- }
129- }
130-
131 private StringBuffer exportTransitions(Transition[] transitions) {
132 StringBuffer out = new StringBuffer();
133 for (Transition trans : transitions) {
134@@ -195,7 +152,8 @@
135
136
137 out.append("\\node[transition");
138- out.append(angle);
139+ out.append(angle);
140+ out.append(handlePlaceAndTransitionLabel(trans.getNameLabel().getText(), trans.getName(), trans.getAttributesVisible()));
141 out.append("] at (");
142 out.append((trans.getPositionX()));
143 out.append(',');
144@@ -226,31 +184,30 @@
145 out.append(trans.getId());
146 out.append(".center) { };\n");
147 }
148- if (trans.getAttributesVisible()){
149- boolean isLabelAboveTransition = trans.getY() > trans.getNameLabel().getY();
150- boolean isLabelBehindTrans = trans.getX() < trans.getNameLabel().getX();
151- double xOffset = trans.getName().length() > 5 && !isLabelAboveTransition && !isLabelBehindTrans ? trans.getLayerOffset() : 0;
152-
153- out.append("%% label for transition " + trans.getName() + "\n");
154- out.append("\\draw (");
155- out.append(trans.getNameLabel().getX() + xOffset + "," + (trans.getNameLabel().getY() * -1) + ")");
156- out.append(" node ");
157- out.append(" {");
158- out.append(exportMathName(trans.getName()));
159- out.append("};\n");
160- }
161 }
162 return out;
163 }
164
165+ private String handlePlaceAndTransitionLabel(String nameLabelText, String name, boolean isVisible) {
166+ if(!isVisible)
167+ return "";
168+
169+ String result = ", label={[align=left,label distance=0cm]90:";
170+ result += "$\\mathrm{" + (name.replace("_","\\_")) + "}$";
171+ result += handleNameLabel(nameLabelText);
172+ result += "}";
173+ return result;
174+ }
175+
176 private StringBuffer exportPlacesWithTokens(Place[] places) {
177 StringBuffer out = new StringBuffer();
178
179 for (Place place : places) {
180- String invariant = getPlaceInvariantString(place);
181+ String invariant = "$" + getPlaceInvariantString(place) + "$";
182 String tokensInPlace = getTokenListStringFor(place);
183
184 out.append("\\node[place");
185+ out.append(handlePlaceAndTransitionLabel(place.getNameLabel().getText(), place.getName(), place.getAttributesVisible()));
186 out.append("] at (");
187 out.append(place.getPositionX());
188 out.append(',');
189@@ -262,37 +219,36 @@
190 exportPlaceTokens(place, out, ((TimedPlaceComponent) place).underlyingPlace().tokens().size());
191
192 if(((TimedPlaceComponent)place).underlyingPlace().isShared()){
193- out.append("\\node[sharedplace] at (");
194+ out.append("\\node[sharedplace ");
195+ out.append("] at (");
196 out.append(place.getId());
197 out.append(".center) { };\n");
198 }
199- if (place.getAttributesVisible() || !invariant.equals("")){
200- boolean isLabelAbovePlace = place.getY() > place.getNameLabel().getY();
201- boolean isLabelBehindPlace = place.getX() < place.getNameLabel().getX();
202- double xOffset = place.getName().length() > 6 && !isLabelAbovePlace && !isLabelBehindPlace ? place.getLayerOffset() : 0;
203- double yOffset = isLabelAbovePlace ? (place.getNameLabel().getHeight() / 2) : 0;
204-
205- out.append("%% label for place " + place.getName() + "\n");
206- out.append("\\draw (");
207- out.append((place.getNameLabel().getX() + xOffset) + "," + ((place.getNameLabel().getY() * -1) + yOffset) +")");
208- out.append(" node[align=left] ");
209- out.append("{");
210- if(place.getAttributesVisible())
211- out.append(exportMathName(place.getName()));
212- if(!invariant.equals("")) {
213- if((place.getAttributesVisible()))
214- out.append("\\\\");
215- out.append(invariant);
216- }else {
217- out.append("};\n");
218- }
219-
220- }
221 }
222-
223 return out;
224 }
225
226+ private String handleNameLabel(String nameLabel) {
227+ String nameLabelsString = "";
228+ String[] labelsInName = nameLabel.split("\n");
229+ for(int i = 0; i < labelsInName.length; i++) {
230+ if(labelsInName[i].contains("[")) {
231+ nameLabelsString += escapeSpacesInAndOrNot(replaceWithMathLatex(labelsInName[i]));
232+ }
233+ else if(!labelsInName[i].isEmpty()){
234+ nameLabelsString += escapeSpacesInAndOrNot(replaceWithMathLatex(labelsInName[i]));
235+ }
236+ if(i != labelsInName.length - 1) {
237+ nameLabelsString += "\\\\";
238+ }
239+ }
240+ return nameLabelsString;
241+ }
242+
243+ private String escapeSpacesInAndOrNot(String str) {
244+ return str.replace(" and ", "\\ and\\ ").replace(" or", "\\ or\\ ").replace(" not", "\\ not\\ ");
245+ }
246+
247 private void exportPlaceTokens(Place place, StringBuffer out, int numOfTokens) {
248 // Dot radius
249 final double tRadius = 1;
250@@ -317,14 +273,14 @@
251 out.append(",");
252 out.append(placeYpos + 4);
253 out.append(")");
254- out.append("{0,0};\n");
255+ out.append("{0.0};\n");
256
257 out.append("\\node at ("); // Bottom
258 out.append(placeXpos);
259 out.append(",");
260 out.append(placeYpos - 5);
261 out.append(")");
262- out.append("{0,0};\n");
263+ out.append("{0.0};\n");
264 return;
265 case 1:
266 out.append("\\node at ("); // Top
267@@ -332,7 +288,7 @@
268 out.append(",");
269 out.append(placeYpos);
270 out.append(")");
271- out.append("{0,0};\n");
272+ out.append("{0.0};\n");
273 return;
274 default:
275 out.append("\\node at (");
276@@ -437,6 +393,124 @@
277 }
278 }
279
280+ private StringBuffer exportGlobalVariables() {
281+ StringBuffer out = new StringBuffer();
282+
283+ Context context = new Context(TAPAALGUI.getCurrentTab());
284+ List<ColorType> listColorTypes = context.network().colorTypes();
285+ List<Constant> constantsList = new ArrayList<>(context.network().constants());
286+ List<Variable> variableList = context.network().variables();
287+
288+ if(!context.network().isColored()) {
289+ if(constantsList.isEmpty()) {
290+ return out;
291+ }
292+ out.append("%%Global box which contains global color types, variables and/or constants.\n");
293+ out.append("\\node [globalBox] (globalBox) at (current bounding box.north west) [anchor=south west] {");
294+ exportConstants(constantsList, out);
295+ out.append("};");
296+ return out;
297+ }
298+
299+ if((listColorTypes.isEmpty() && constantsList.isEmpty() && variableList.isEmpty()))
300+ return out;
301+
302+ out.append("%%Global box which contains global color types, variables and/or constants.\n");
303+ out.append("\\node [globalBox] (globalBox) at (current bounding box.north west) [anchor=south west] {");
304+
305+ exportColorTypes(listColorTypes, out);
306+
307+ if(listColorTypes.size() > 0 && (variableList.size() > 0 || constantsList.size() > 0)) {
308+ out.append("\\\\");
309+ }
310+
311+ exportVariables(variableList, out);
312+
313+ if(variableList.size() > 0 && !constantsList.isEmpty()) {
314+ out.append("\\\\");
315+ }
316+
317+ exportConstants(constantsList, out);
318+
319+ out.append("};");
320+
321+ return out;
322+ }
323+
324+ private void exportColorTypes(List<ColorType> listColorTypes, StringBuffer out) {
325+ String stringColorList = "";
326+ for(int i = 0; i < listColorTypes.size(); i++) {
327+ if(i == 0) {
328+ out.append("Color Types:\\\\");
329+ }
330+ out.append("$\\mathit{" + listColorTypes.get(i).getName() + "}$ \\textbf{is} ");
331+
332+ if(listColorTypes.get(i).isProductColorType()) {
333+ out.append("$\\mathit{<");
334+ for(int x = 0; x < listColorTypes.get(i).getProductColorTypes().size(); x++) {
335+ stringColorList += listColorTypes.get(i).getProductColorTypes().get(x).getName().replace("_", "\\_");
336+
337+ if(x != listColorTypes.get(i).getProductColorTypes().size() - 1){
338+ stringColorList += ", ";
339+ }
340+ }
341+ out.append(stringColorList + ">}$\\\\");
342+ stringColorList = "";
343+
344+ } else if(listColorTypes.get(i).isIntegerRange()) {
345+ out.append("$\\mathit{");
346+ if(listColorTypes.get(i).size() > 1) {
347+ int listSize = listColorTypes.get(i).size();
348+ out.append("[" + listColorTypes.get(i).getColors().get(0).getColorName().replace("_","\\_") + ".." + listColorTypes.get(i).getColors().get(listSize - 1).getColorName().replace("_","\\_") + "]");
349+ } else {
350+ out.append("[" + listColorTypes.get(i).getFirstColor().getColorName().replace("_","\\_") + "]");
351+ }
352+ out.append("}$\\\\");
353+
354+ } else {
355+ out.append("$\\mathit{[");
356+ for(int x = 0; x < listColorTypes.get(i).getColors().size(); x++) {
357+ stringColorList += listColorTypes.get(i).getColors().get(x).getName().replace("_","\\_");
358+
359+ if(x != listColorTypes.get(i).getColors().size() - 1){
360+ stringColorList += ", ";
361+ }
362+ }
363+ out.append(stringColorList + "]}$\\\\");
364+ stringColorList = "";
365+ }
366+ }
367+ }
368+
369+ private void exportVariables(List<Variable> variableList, StringBuffer out) {
370+ String result = "";
371+ for(int i = 0; i < variableList.size(); i++) {
372+ if (i == 0) {
373+ result += "Variables:\\\\ ";
374+ }
375+ result += "$\\mathit{" + variableList.get(i).getName().replace("_","\\_") + " \\textbf{ in } " + variableList.get(i).getColorType().getName().replace("_","\\_") + "}$";
376+ if(i != variableList.size() - 1) {
377+ result += "\\\\";
378+ }
379+ }
380+ out.append(result);
381+ }
382+
383+ private void exportConstants(List<Constant> constantsList, StringBuffer out) {
384+ String result = "";
385+
386+ for(int i = 0; i < constantsList.size(); i++) {
387+ if(i == 0) {
388+ result += "Constants:\\\\";
389+ }
390+ result += "$\\mathit{" + constantsList.get(i).toString().replace("_","\\_") + "}$";
391+ if(i != constantsList.size() - 1) {
392+ result += "\\\\";
393+ }
394+ }
395+ out.append(result);
396+ }
397+
398 protected String getTokenListStringFor(Place place) {
399 List<TimedToken> tokens = ((TimedPlaceComponent) place).underlyingPlace().tokens();
400
401@@ -455,7 +529,7 @@
402 String invariant = "";
403
404 if (!((TimedPlaceComponent) place).getInvariantAsString().contains("inf"))
405- invariant = "$\\mathrm{" + replaceWithMathLatex(((TimedPlaceComponent) place).getInvariantAsString()) + "}$};\n";
406+ invariant = replaceWithMathLatex(((TimedPlaceComponent) place).getInvariantAsString()) + "};\n";
407 return invariant;
408 }
409
410@@ -480,12 +554,14 @@
411 StringBuffer out = new StringBuffer();
412
413 out.append("\\begin{tikzpicture}[font=\\scriptsize, xscale=0.45, yscale=0.45, x=1.33pt, y=1.33pt]\n");
414- out.append("%% the figure can be scaled by changing xscale and yscale\n");
415+ out.append("%% the figure can be scaled by changing xscale and yscale or the size of the x- and y-coordinates\n");
416 out.append("%% positions of place/transition labels that are currently fixed to label=135 degrees\n");
417- out.append("%% can be adjusted so that they do not cover arcs\n");
418- out.append("%% similarly the curving of arcs can be done by adjusting bend left/right=XX\n");
419- out.append("%% labels may be slightly skewed compared to the tapaal drawing due to rounding.\n");
420- out.append("%% This can be adjusted by tuning the coordinates of the label\n");
421+ out.append("%% these can be adjusted by adjusting either the coordinates, the label distance or the label degree\n");
422+ out.append("%% that is placed right after the 'label-distance'. 90: is above (default), 180 is left, 270 is below etc.\n");
423+ out.append("%% The curving of arcs can be done by adjusting bend left/right=XX\n");
424+ out.append("%% labels may be slightly skewed compared to the Tapaal drawing due to rounding.\n");
425+ out.append("%% This can be adjusted by tuning the coordinates of the label, or the degree (see above)\n");
426+ out.append("%% The box containing global variables can also be moved by adjusting the anchor points / bounding box in the [globalBox] node at the end of the Tikz document\n");
427 out.append("\\tikzstyle{arc}=[->,>=stealth,thick]\n");
428
429 out.append("\\tikzstyle{transportArc}=[->,>=diamond,thick]\n");
430@@ -496,39 +572,24 @@
431 out.append("\\tikzstyle{every token}=[fill=white,text=black]\n");
432 out.append("\\tikzstyle{sharedplace}=[place,minimum size=7.5mm,dashed,thin]\n");
433 out.append("\\tikzstyle{sharedtransition}=[transition, fill opacity=0, minimum width=3.5mm, minimum height=6.5mm,dashed]\n");
434- out.append("\\tikzstyle{urgenttransition}=[place,fill=white,minimum size=2.0mm,thin]");
435- out.append("\\tikzstyle{uncontrollabletransition}=[transition,fill=white,draw=black,very thick]");
436+ out.append("\\tikzstyle{urgenttransition}=[place,fill=white,minimum size=2.0mm,thin]\n");
437+ out.append("\\tikzstyle{uncontrollabletransition}=[transition,fill=white,draw=black,very thick]\n");
438+ out.append("\\tikzstyle{globalBox} = [draw,thick,align=left]");
439 return out;
440 }
441
442 protected String replaceWithMathLatex(String text) {
443- return text.replace("inf", "\\infty").replace("<=", "\\leq ").replace("*", "\\cdot ");
444- }
445-
446- private String exportMathName(String name) {
447- StringBuilder out = new StringBuilder("$\\mathrm{");
448- int subscripts = 0;
449- for (int i = 0; i < name.length() - 1; i++) {
450- char c = name.charAt(i);
451- if (c == '_') {
452- out.append("_{");
453- subscripts++;
454- } else {
455- out.append(c);
456- }
457- }
458-
459- char last = name.charAt(name.length() - 1);
460- if (last == '_') {
461- out.append("\\_");
462- } else
463- out.append(last);
464-
465- for (int i = 0; i < subscripts; i++) {
466- out.append('}');
467- }
468- out.append("}$");
469- return out.toString();
470- }
471-
472+ String[] stringList = text.split(" ");
473+ String result = "";
474+
475+ for(int i = 0; i < stringList.length; i++) {
476+ result += "$\\mathit{" + replaceSpecialSymbols(stringList[i]) + "}$ ";
477+ }
478+ return result;
479+ }
480+
481+ protected String replaceSpecialSymbols(String text) {
482+ return text.replace("inf", "\\infty").replace("<=", "\\leq").replace("*", "\\cdot")
483+ .replace("\u2192", "\\rightarrow").replace("\u221E", "\\infty");
484+ }
485 }

Subscribers

People subscribed via source and target branches

to all changes: