Ignore:
Timestamp:
2018-06-04T12:10:57+02:00 (6 years ago)
Author:
biswesh
Message:

Draw 3 parallel ways in case of repetitive ways in relation

File:
1 edited

Legend:

Unmodified
Added
Removed
  • applications/editors/josm/plugins/pt_assistant/src/org/openstreetmap/josm/plugins/pt_assistant/gui/PTAssistantPaintVisitor.java

    r33594 r34247  
    4040public class PTAssistantPaintVisitor extends PaintVisitor {
    4141
    42     /** The graphics */
    43     private final Graphics g;
    44     /** The MapView */
    45     private final MapView mv;
    46 
    47     /**
    48      * Constructor
    49      *
    50      * @param g graphics
    51      * @param mv map view
    52      */
    53     public PTAssistantPaintVisitor(Graphics g, MapView mv) {
    54         super((Graphics2D) g, mv);
    55         this.g = g;
    56         this.mv = mv;
    57     }
    58 
    59     @Override
    60     public void visit(Relation r) {
    61 
    62         if (RouteUtils.isBicycleRoute(r)
    63                 || RouteUtils.isFootRoute(r)
    64                 || RouteUtils.isHorseRoute(r)) {
    65             drawCycleRoute(r);
    66             return;
    67         }
    68 
    69         // first, draw primitives:
    70         for (RelationMember rm : r.getMembers()) {
    71 
    72             if (PTStop.isPTStopPosition(rm)) {
    73                 drawStop(rm.getMember(), true);
    74             } else if (PTStop.isPTPlatform(rm)) {
    75                 drawStop(rm.getMember(), false);
    76             } else if (RouteUtils.isPTWay(rm)) {
    77                 if (rm.isWay()) {
    78                     visit(rm.getWay());
    79                 } else if (rm.isRelation()) {
    80                     visit(rm.getRelation());
    81                 }
    82             }
    83         }
    84 
    85         // in the end, draw labels:
    86         HashMap<Long, String> stopOrderMap = new HashMap<>();
    87         int stopCount = 1;
    88 
    89         for (RelationMember rm : r.getMembers()) {
    90             if (PTStop.isPTStop(rm) || (rm.getMember().isIncomplete() && (rm.isNode() || rm.hasRole("stop")
    91                     || rm.hasRole("stop_entry_only") || rm.hasRole("stop_exit_only") || rm.hasRole("platform")
    92                     || rm.hasRole("platform_entry_only") || rm.hasRole("platform_exit_only")))) {
    93 
    94                 StringBuilder sb = new StringBuilder();
    95 
    96                 if (stopOrderMap.containsKey(rm.getUniqueId())) {
    97                     sb.append(stopOrderMap.get(rm.getUniqueId()))
    98                         .append(";")
    99                         .append(stopCount);
    100                 } else {
    101                     if (r.hasKey("ref")) {
    102                         sb.append(r.get("ref"));
    103                     } else if (r.hasKey("name")) {
    104                         sb.append(r.get("name"));
    105                     } else {
    106                         sb.append("NA");
    107                     }
    108                     sb.append(" - ")
    109                         .append(stopCount);
    110                 }
    111 
    112                 stopOrderMap.put(rm.getUniqueId(), sb.toString());
    113                 try {
    114                     if (PTStop.isPTStopPosition(rm))
    115                         drawStopLabel(rm.getMember(), sb.toString(), false);
    116                     else if (PTStop.isPTPlatform(rm))
    117                         drawStopLabel(rm.getMember(), sb.toString(), true);
    118                 } catch (NullPointerException ex) {
    119                     // do nothing
    120                     Logging.trace(ex);
    121                 }
    122                 stopCount++;
    123             }
    124         }
    125 
    126     }
    127 
    128     private void drawCycleRoute(Relation r) {
    129 
    130         List<RelationMember> members = new ArrayList<>(r.getMembers());
    131         members.removeIf(m -> !m.isWay());
    132         WayConnectionTypeCalculator connectionTypeCalculator = new WayConnectionTypeCalculator();
    133         List<WayConnectionType> links = connectionTypeCalculator.updateLinks(members);
    134 
    135         for (int i = 0; i < links.size(); i++) {
    136             WayConnectionType link = links.get(i);
    137             Way way = members.get(i).getWay();
    138             if (!link.isOnewayLoopForwardPart && !link.isOnewayLoopBackwardPart) {
    139                 drawWay(way, new Color(0, 255, 255, 100));
    140             } else if (link.isOnewayLoopForwardPart) {
    141                 drawWay(way, new Color(255, 0, 0, 100));
    142             } else {
    143                 drawWay(way, new Color(0, 0, 255, 100));
    144             }
    145         }
    146     }
    147 
    148     private void drawWay(Way way, Color color) {
    149         List<Node> nodes = way.getNodes();
    150         for (int i = 0; i < nodes.size()-1; i++) {
    151             drawSegment(nodes.get(i), nodes.get(i + 1), color, 1);
    152         }
    153     }
    154 
    155     @Override
    156     public void visit(Way w) {
    157 
    158         if (w == null) {
    159             return;
    160         }
    161 
    162         /*-
    163          * oneway values:
    164          * 0 two-way street
    165          * 1 oneway street in the way's direction
    166          * 2 oneway street in ways's direction but public transport allowed
    167          * -1 oneway street in reverse direction
    168          * -2 oneway street in reverse direction but public transport allowed
    169          */
    170         int oneway = 0;
    171 
    172         if (w.hasTag("junction", "roundabout") || w.hasTag("highway", "motorway")) {
    173             oneway = 1;
    174         } else if (w.hasTag("oneway", "1") || w.hasTag("oneway", "yes") || w.hasTag("oneway", "true")) {
    175             if (w.hasTag("busway", "lane") || w.hasTag("busway:left", "lane") || w.hasTag("busway:right", "lane")
    176                     || w.hasTag("oneway:bus", "no") || w.hasTag("busway", "opposite_lane")
    177                     || w.hasTag("oneway:psv", "no") || w.hasTag("trolley_wire", "backward")) {
    178                 oneway = 2;
    179             } else {
    180                 oneway = 1;
    181             }
    182         } else if (w.hasTag("oneway", "-1") || w.hasTag("oneway", "reverse")) {
    183             if (w.hasTag("busway", "lane") || w.hasTag("busway:left", "lane") || w.hasTag("busway:right", "lane")
    184                     || w.hasTag("oneway:bus", "no") || w.hasTag("busway", "opposite_lane")
    185                     || w.hasTag("oneway:psv", "no") || w.hasTag("trolley_wire", "backward")) {
    186                 oneway = -2;
    187             } else {
    188                 oneway = -1;
    189             }
    190         }
    191 
    192         visit(w.getNodes(), oneway);
    193 
    194     }
    195 
    196     /**
    197      * Variation of the visit method that allows a special visualization of
    198      * oneway roads
    199      *
    200      * @param nodes nodes
    201      * @param oneway oneway
    202      */
    203     public void visit(List<Node> nodes, int oneway) {
    204         Node lastN = null;
    205         for (Node n : nodes) {
    206             if (lastN == null) {
    207                 lastN = n;
    208                 continue;
    209             }
    210             drawSegment(lastN, n, new Color(128, 0, 128, 100), oneway);
    211             lastN = n;
    212         }
    213     }
    214 
    215     /**
    216      * Draw a small rectangle. White if selected (as always) or red otherwise.
    217      *
    218      * @param n
    219      *            The node to draw.
    220      */
    221     @Override
    222     public void visit(Node n) {
    223         if (n.isDrawable() && isNodeVisible(n)) {
    224             drawNode(n, Color.BLUE);
    225         }
    226     }
    227 
    228     /**
    229      * Draws a line around the segment
    230      *
    231      * @param n1
    232      *            The first node of segment
    233      * @param n2
    234      *            The second node of segment
    235      * @param color
    236      *            The color
    237      */
    238     protected void drawSegment(Node n1, Node n2, Color color, int oneway) {
    239         if (n1.isDrawable() && n2.isDrawable() && isSegmentVisible(n1, n2)) {
    240             try {
    241                 drawSegment(mv.getPoint(n1), mv.getPoint(n2), color, oneway);
    242             } catch (NullPointerException ex) {
    243                 // do nothing
    244                 Logging.trace(ex);
    245             }
    246 
    247         }
    248     }
    249 
    250     /**
    251      * Draws a line around the segment
    252      *
    253      * @param p1
    254      *            The first point of segment
    255      * @param p2
    256      *            The second point of segment
    257      * @param color
    258      *            The color
    259      */
    260     protected void drawSegment(Point p1, Point p2, Color color, int oneway) {
    261 
    262         double t = Math.atan2((double) p2.x - p1.x, (double) p2.y - p1.y);
    263         double cosT = 9 * Math.cos(t);
    264         double sinT = 9 * Math.sin(t);
    265 
    266         int[] xPoints = {(int) (p1.x + cosT), (int) (p2.x + cosT), (int) (p2.x - cosT), (int) (p1.x - cosT)};
    267         int[] yPoints = {(int) (p1.y - sinT), (int) (p2.y - sinT), (int) (p2.y + sinT), (int) (p1.y + sinT)};
    268         g.setColor(color);
    269         g.fillPolygon(xPoints, yPoints, 4);
    270         g.fillOval(p1.x - 9, p1.y - 9, 18, 18);
    271         g.fillOval(p2.x - 9, p2.y - 9, 18, 18);
    272 
    273         if (oneway != 0) {
    274             double middleX = (p1.x + p2.x) / 2.0;
    275             double middleY = (p1.y + p2.y) / 2.0;
    276             double cosTriangle = 6 * Math.cos(t);
    277             double sinTriangle = 6 * Math.sin(t);
    278             g.setColor(Color.WHITE);
    279 
    280             if (oneway > 0) {
    281                 int[] xFillTriangle = {(int) (middleX + cosTriangle), (int) (middleX - cosTriangle),
    282                         (int) (middleX + 2 * sinTriangle)};
    283                 int[] yFillTriangle = {(int) (middleY - sinTriangle), (int) (middleY + sinTriangle),
    284                         (int) (middleY + 2 * cosTriangle)};
    285                 g.fillPolygon(xFillTriangle, yFillTriangle, 3);
    286 
    287                 if (oneway == 2) {
    288                     int[] xDrawTriangle = {(int) (middleX + cosTriangle), (int) (middleX - cosTriangle),
    289                             (int) (middleX - 2 * sinTriangle)};
    290                     int[] yDrawTriangle = {(int) (middleY - sinTriangle), (int) (middleY + sinTriangle),
    291                             (int) (middleY - 2 * cosTriangle)};
    292                     g.drawPolygon(xDrawTriangle, yDrawTriangle, 3);
    293                 }
    294             }
    295 
    296             if (oneway < 0) {
    297                 int[] xFillTriangle = {(int) (middleX + cosTriangle), (int) (middleX - cosTriangle),
    298                         (int) (middleX - 2 * sinTriangle)};
    299                 int[] yFillTriangle = {(int) (middleY - sinTriangle), (int) (middleY + sinTriangle),
    300                         (int) (middleY - 2 * cosTriangle)};
    301                 g.fillPolygon(xFillTriangle, yFillTriangle, 3);
    302 
    303                 if (oneway == -2) {
    304                     int[] xDrawTriangle = {(int) (middleX + cosTriangle), (int) (middleX - cosTriangle),
    305                             (int) (middleX + 2 * sinTriangle)};
    306                     int[] yDrawTriangle = {(int) (middleY - sinTriangle), (int) (middleY + sinTriangle),
    307                             (int) (middleY + 2 * cosTriangle)};
    308                     g.drawPolygon(xDrawTriangle, yDrawTriangle, 3);
    309                 }
    310             }
    311 
    312         }
    313 
    314     }
    315 
    316     /**
    317      * Draws a circle around the node
    318      *
    319      * @param n
    320      *            The node
    321      * @param color
    322      *            The circle color
    323      */
    324     @Override
    325     protected void drawNode(Node n, Color color) {
    326         if (mv == null || g == null) {
    327             return;
    328         }
    329         Point p = mv.getPoint(n);
    330         if (p == null) {
    331             return;
    332         }
    333         g.setColor(color);
    334         g.drawOval(p.x - 5, p.y - 5, 10, 10);
    335 
    336     }
    337 
    338     /**
    339      * Draws s stop_position as a blue circle; draws a platform as a blue square
    340      *
    341      * @param primitive primitive
    342      */
    343     protected void drawStop(OsmPrimitive primitive, Boolean stopPosition) {
    344 
    345         // find the point to which the stop visualization will be linked:
    346         Node n = new Node(primitive.getBBox().getCenter());
    347 
    348         Point p = mv.getPoint(n);
    349 
    350         g.setColor(Color.BLUE);
    351 
    352         if (stopPosition) {
    353             g.fillOval(p.x - 8, p.y - 8, 16, 16);
    354         } else {
    355             g.fillRect(p.x - 8, p.y - 8, 16, 16);
    356         }
    357 
    358     }
    359 
    360     /**
    361      * Draws the labels for the stops, which include the ordered position of the
    362      * stop in the route and the ref numbers of other routes that use this stop
    363      *
    364      * @param primitive primitive
    365      * @param label label
    366      */
    367     protected void drawStopLabel(OsmPrimitive primitive, String label, Boolean platform) {
    368 
    369         // find the point to which the stop visualization will be linked:
    370         Node n = new Node(primitive.getBBox().getCenter());
    371 
    372         Point p = mv.getPoint(n);
    373 
    374         if (label != null && !label.equals("")) {
    375             Font stringFont = new Font("SansSerif", Font.PLAIN, 24);
    376             if (platform) {
    377                 g.setColor(new Color(255, 255, 102));
    378                 g.setFont(stringFont);
    379                 g.drawString(label, p.x + 20, p.y - 40);
    380             } else {
    381                 g.setColor(Color.WHITE);
    382                 g.setFont(stringFont);
    383                 g.drawString(label, p.x + 20, p.y - 20);
    384             }
    385         }
    386 
    387         // draw the ref values of all parent routes:
    388         List<String> parentsLabelList = new ArrayList<>();
    389         for (OsmPrimitive parent : primitive.getReferrers()) {
    390             if (parent.getType().equals(OsmPrimitiveType.RELATION)) {
    391                 Relation relation = (Relation) parent;
    392                 if (RouteUtils.isVersionTwoPTRoute(relation) && relation.get("ref") != null
    393                         && !relation.get("ref").equals("")) {
    394 
    395                     boolean stringFound = false;
    396                     for (String s : parentsLabelList) {
    397                         if (s.equals(relation.get("ref"))) {
    398                             stringFound = true;
    399                         }
    400                     }
    401                     if (!stringFound) {
    402                         parentsLabelList.add(relation.get("ref"));
    403                     }
    404 
    405                 }
    406             }
    407         }
    408 
    409         Collections.sort(parentsLabelList, new RefTagComparator());
    410 
    411         StringBuilder sb = new StringBuilder();
    412         for (String s : parentsLabelList) {
    413             sb.append(s).append(";");
    414         }
    415 
    416         if (sb.length() > 0) {
    417             // remove the last semicolon:
    418             String parentsLabel = sb.substring(0, sb.length() - 1);
    419 
    420             g.setColor(new Color(255, 20, 147));
    421             Font parentLabelFont = new Font("SansSerif", Font.ITALIC, 20);
    422             g.setFont(parentLabelFont);
    423             g.drawString(parentsLabel, p.x + 20, p.y + 20);
    424         }
    425 
    426     }
    427 
    428     /**
    429      * Compares route ref numbers
    430      * @author darya
    431      *
    432      */
    433     private static class RefTagComparator implements Comparator<String> {
    434 
    435         @Override
    436         public int compare(String s1, String s2) {
    437 
    438             if (s1 == null || s1.equals("") || s2 == null || s2.equals("")) {
    439                 // if at least one of the strings is null or empty, there is no
    440                 // point in comparing:
    441                 return 0;
    442             }
    443 
    444             String[] splitString1 = s1.split("\\D");
    445             String[] splitString2 = s2.split("\\D");
    446 
    447             if (splitString1.length == 0 && splitString2.length != 0) {
    448                 // if the first ref does not start a digit and the second ref
    449                 // starts with a digit:
    450                 return 1;
    451             }
    452 
    453             if (splitString1.length != 0 && splitString2.length == 0) {
    454                 // if the first ref starts a digit and the second ref does not
    455                 // start with a digit:
    456                 return -1;
    457             }
    458 
    459             if (splitString1.length == 0 && splitString2.length == 0) {
    460                 // if both ref values do not start with a digit:
    461                 return s1.compareTo(s2);
    462             }
    463 
    464             String firstNumberString1 = splitString1[0];
    465             String firstNumberString2 = splitString2[0];
    466 
    467             try {
    468                 int firstNumber1 = Integer.parseInt(firstNumberString1);
    469                 int firstNumber2 = Integer.parseInt(firstNumberString2);
    470                 if (firstNumber1 > firstNumber2) {
    471                     return 1;
    472                 } else if (firstNumber1 < firstNumber2) {
    473                     return -1;
    474                 } else {
    475                     // if the first number is the same:
    476 
    477                     return s1.compareTo(s2);
    478 
    479                 }
    480             } catch (NumberFormatException ex) {
    481                 return s1.compareTo(s2);
    482             }
    483 
    484         }
    485 
    486     }
    487 
    488     /**
    489      * Visualizes the fix variants, assigns colors to them based on their order
    490      * @param fixVariants fix variants
    491      */
    492     protected void visitFixVariants(HashMap<Character, List<PTWay>> fixVariants,
    493             HashMap<Way, List<Character>> wayColoring) {
    494 
    495         drawFixVariantsWithParallelLines(wayColoring);
    496 
    497         Color[] colors = {
    498                 new Color(255, 0, 0, 150),
    499                 new Color(0, 255, 0, 150),
    500                 new Color(0, 0, 255, 150),
    501                 new Color(255, 255, 0, 150),
    502                 new Color(0, 255, 255, 150)};
    503 
    504         int colorIndex = 0;
    505 
    506         double letterX = MainApplication.getMap().mapView.getBounds().getMinX() + 20;
    507         double letterY = MainApplication.getMap().mapView.getBounds().getMinY() + 100;
    508 
    509         for (Entry<Character, List<PTWay>> entry : fixVariants.entrySet()) {
    510             Character c = entry.getKey();
    511             if (fixVariants.get(c) != null) {
    512                 drawFixVariantLetter(c.toString(), colors[colorIndex % 5], letterX, letterY);
    513                 colorIndex++;
    514                 letterY = letterY + 60;
    515             }
    516         }
    517 
    518         // display the "Esc" label:
    519         if (!fixVariants.isEmpty()) {
    520             drawFixVariantLetter("Esc", Color.WHITE, letterX, letterY);
    521         }
    522     }
    523 
    524     @SuppressWarnings("unused")
    525     private void drawFixVariant(List<PTWay> fixVariant, Color color) {
    526         for (PTWay ptway : fixVariant) {
    527             for (Way way : ptway.getWays()) {
    528                 for (Pair<Node, Node> nodePair : way.getNodePairs(false)) {
    529                     drawSegment(nodePair.a, nodePair.b, color, 0);
    530                 }
    531             }
    532         }
    533     }
    534 
    535     protected void drawFixVariantsWithParallelLines(Map<Way, List<Character>> wayColoring) {
    536 
    537         HashMap<Character, Color> colors = new HashMap<>();
    538         colors.put('A', new Color(255, 0, 0, 200));
    539         colors.put('B', new Color(0, 255, 0, 200));
    540         colors.put('C', new Color(0, 0, 255, 200));
    541         colors.put('D', new Color(255, 255, 0, 200));
    542         colors.put('E', new Color(0, 255, 255, 200));
    543 
    544         for (Entry<Way, List<Character>> entry : wayColoring.entrySet()) {
    545             Way way = entry.getKey();
    546             List<Character> letterList = wayColoring.get(way);
    547             List<Color> wayColors = new ArrayList<>();
    548             for (Character letter : letterList) {
    549                 wayColors.add(colors.get(letter));
    550             }
    551             for (Pair<Node, Node> nodePair : way.getNodePairs(false)) {
    552                 drawSegmentWithParallelLines(nodePair.a, nodePair.b, wayColors);
    553             }
    554         }
    555     }
    556 
    557     protected void drawSegmentWithParallelLines(Node n1, Node n2, List<Color> colors) {
    558         if (!n1.isDrawable() || !n2.isDrawable() || !isSegmentVisible(n1, n2)) {
    559             return;
    560         }
    561 
    562         Point p1 = mv.getPoint(n1);
    563         Point p2 = mv.getPoint(n2);
    564         double t = Math.atan2((double) p2.x - p1.x, (double) p2.y - p1.y);
    565         double cosT = 9 * Math.cos(t);
    566         double sinT = 9 * Math.sin(t);
    567         double heightCosT = 9 * Math.cos(t);
    568         double heightSinT = 9 * Math.sin(t);
    569 
    570         double prevPointX = p1.x;
    571         double prevPointY = p1.y;
    572         double nextPointX = p1.x + heightSinT;
    573         double nextPointY = p1.y + heightCosT;
    574 
    575         Color currentColor = colors.get(0);
    576         int i = 0;
    577         g.setColor(currentColor);
    578         g.fillOval(p1.x - 9, p1.y - 9, 18, 18);
    579 
    580         if (colors.size() == 1) {
    581             int[] xPoints = {(int) (p1.x + cosT), (int) (p2.x + cosT), (int) (p2.x - cosT), (int) (p1.x - cosT)};
    582             int[] yPoints = {(int) (p1.y - sinT), (int) (p2.y - sinT), (int) (p2.y + sinT), (int) (p1.y + sinT)};
    583             g.setColor(currentColor);
    584             g.fillPolygon(xPoints, yPoints, 4);
    585         } else {
    586             boolean iterate = true;
    587             while (iterate) {
    588                 currentColor = colors.get(i % colors.size());
    589 
    590                 int[] xPoints = {(int) (prevPointX + cosT), (int) (nextPointX + cosT), (int) (nextPointX - cosT),
    591                         (int) (prevPointX - cosT)};
    592                 int[] yPoints = {(int) (prevPointY - sinT), (int) (nextPointY - sinT), (int) (nextPointY + sinT),
    593                         (int) (prevPointY + sinT)};
    594                 g.setColor(currentColor);
    595                 g.fillPolygon(xPoints, yPoints, 4);
    596 
    597                 prevPointX = prevPointX + heightSinT;
    598                 prevPointY = prevPointY + heightCosT;
    599                 nextPointX = nextPointX + heightSinT;
    600                 nextPointY = nextPointY + heightCosT;
    601                 i++;
    602                 if ((p1.x < p2.x && nextPointX >= p2.x) || (p1.x >= p2.x && nextPointX <= p2.x)) {
    603                     iterate = false;
    604                 }
    605             }
    606 
    607             int[] lastXPoints = {(int) (prevPointX + cosT), (int) (p2.x + cosT), (int) (p2.x - cosT),
    608                     (int) (prevPointX - cosT)};
    609             int[] lastYPoints = {(int) (prevPointY - sinT), (int) (p2.y - sinT), (int) (p2.y + sinT),
    610                     (int) (prevPointY + sinT)};
    611             g.setColor(currentColor);
    612             g.fillPolygon(lastXPoints, lastYPoints, 4);
    613         }
    614 
    615         g.setColor(currentColor);
    616         g.fillOval(p2.x - 9, p2.y - 9, 18, 18);
    617     }
    618 
    619     /**
    620      * Visuallizes the letters for each fix variant
    621      * @param letter letter
    622      * @param color color
    623      * @param letterX letter X
    624      * @param letterY letter Y
    625      */
    626     private void drawFixVariantLetter(String letter, Color color, double letterX, double letterY) {
    627         g.setColor(color);
    628         Font stringFont = new Font("SansSerif", Font.PLAIN, 50);
    629         g.setFont(stringFont);
    630         try {
    631             g.drawString(letter, (int) letterX, (int) letterY);
    632             g.drawString(letter, (int) letterX, (int) letterY);
    633         } catch (NullPointerException ex) {
    634             // do nothing
    635             Logging.trace(ex);
    636         }
    637 
    638     }
     42        private static final String Node = null;
     43        /** The graphics */
     44        private final Graphics g;
     45        /** The MapView */
     46        private final MapView mv;
     47
     48        /**
     49         * Constructor
     50         *
     51         * @param g
     52         *            graphics
     53         * @param mv
     54         *            map view
     55         */
     56        public PTAssistantPaintVisitor(Graphics g, MapView mv) {
     57                super((Graphics2D) g, mv);
     58                this.g = g;
     59                this.mv = mv;
     60        }
     61
     62        @Override
     63        public void visit(Relation r) {
     64                if (RouteUtils.isBicycleRoute(r) || RouteUtils.isFootRoute(r) || RouteUtils.isHorseRoute(r)) {
     65                        drawCycleRoute(r);
     66                        return;
     67                }
     68
     69                List<RelationMember> rmList = new ArrayList<>();
     70                List<RelationMember> revisitedWayList = new ArrayList<>();
     71                // first, draw primitives:
     72                for (RelationMember rm : r.getMembers()) {
     73
     74                        if (PTStop.isPTStopPosition(rm)) {
     75                                drawStop(rm.getMember(), true);
     76                        } else if (PTStop.isPTPlatform(rm)) {
     77                                drawStop(rm.getMember(), false);
     78                        } else if (RouteUtils.isPTWay(rm)) {
     79                                if (rm.isWay()) {
     80                                        if (rmList.contains(rm)) {
     81                                                if (!revisitedWayList.contains(rm)) {
     82                                                        visit(rm.getWay(), true);
     83                                                        revisitedWayList.add(rm);
     84                                                }
     85                                        } else {
     86                                                visit(rm.getWay(), false);
     87                                        }
     88                                } else if (rm.isRelation()) {
     89                                        visit(rm.getRelation());
     90                                }
     91                                rmList.add(rm);
     92                        }
     93                }
     94
     95                // in the end, draw labels:
     96                HashMap<Long, String> stopOrderMap = new HashMap<>();
     97                int stopCount = 1;
     98
     99                for (RelationMember rm : r.getMembers()) {
     100                        if (PTStop.isPTStop(rm) || (rm.getMember().isIncomplete() && (rm.isNode() || rm.hasRole("stop")
     101                                        || rm.hasRole("stop_entry_only") || rm.hasRole("stop_exit_only") || rm.hasRole("platform")
     102                                        || rm.hasRole("platform_entry_only") || rm.hasRole("platform_exit_only")))) {
     103
     104                                StringBuilder sb = new StringBuilder();
     105
     106                                if (stopOrderMap.containsKey(rm.getUniqueId())) {
     107                                        sb.append(stopOrderMap.get(rm.getUniqueId())).append(";").append(stopCount);
     108                                } else {
     109                                        if (r.hasKey("ref")) {
     110                                                sb.append(r.get("ref"));
     111                                        } else if (r.hasKey("name")) {
     112                                                sb.append(r.get("name"));
     113                                        } else {
     114                                                sb.append("NA");
     115                                        }
     116                                        sb.append(" - ").append(stopCount);
     117                                }
     118
     119                                stopOrderMap.put(rm.getUniqueId(), sb.toString());
     120                                try {
     121                                        if (PTStop.isPTStopPosition(rm))
     122                                                drawStopLabel(rm.getMember(), sb.toString(), false);
     123                                        else if (PTStop.isPTPlatform(rm))
     124                                                drawStopLabel(rm.getMember(), sb.toString(), true);
     125                                } catch (NullPointerException ex) {
     126                                        // do nothing
     127                                        Logging.trace(ex);
     128                                }
     129                                stopCount++;
     130                        }
     131                }
     132
     133        }
     134
     135        private void drawCycleRoute(Relation r) {
     136
     137                List<RelationMember> members = new ArrayList<>(r.getMembers());
     138                members.removeIf(m -> !m.isWay());
     139                WayConnectionTypeCalculator connectionTypeCalculator = new WayConnectionTypeCalculator();
     140                List<WayConnectionType> links = connectionTypeCalculator.updateLinks(members);
     141
     142                for (int i = 0; i < links.size(); i++) {
     143                        WayConnectionType link = links.get(i);
     144                        Way way = members.get(i).getWay();
     145                        if (!link.isOnewayLoopForwardPart && !link.isOnewayLoopBackwardPart) {
     146                                drawWay(way, new Color(0, 255, 255, 100));
     147                        } else if (link.isOnewayLoopForwardPart) {
     148                                drawWay(way, new Color(255, 0, 0, 100));
     149                        } else {
     150                                drawWay(way, new Color(0, 0, 255, 100));
     151                        }
     152                }
     153        }
     154
     155        private void drawWay(Way way, Color color) {
     156                List<Node> nodes = way.getNodes();
     157                for (int i = 0; i < nodes.size() - 1; i++) {
     158                        drawSegment(nodes.get(i), nodes.get(i + 1), color, 1, false);
     159                }
     160        }
     161
     162        public void visit(Way w, boolean revisit) {
     163                if (w == null) {
     164                        return;
     165                }
     166
     167                /*-
     168                 * oneway values:
     169                 * 0 two-way street
     170                 * 1 oneway street in the way's direction
     171                 * 2 oneway street in ways's direction but public transport allowed
     172                 * -1 oneway street in reverse direction
     173                 * -2 oneway street in reverse direction but public transport allowed
     174                 */
     175                int oneway = 0;
     176
     177                if (w.hasTag("junction", "roundabout") || w.hasTag("highway", "motorway")) {
     178                        oneway = 1;
     179                } else if (w.hasTag("oneway", "1") || w.hasTag("oneway", "yes") || w.hasTag("oneway", "true")) {
     180                        if (w.hasTag("busway", "lane") || w.hasTag("busway:left", "lane") || w.hasTag("busway:right", "lane")
     181                                        || w.hasTag("oneway:bus", "no") || w.hasTag("busway", "opposite_lane")
     182                                        || w.hasTag("oneway:psv", "no") || w.hasTag("trolley_wire", "backward")) {
     183                                oneway = 2;
     184                        } else {
     185                                oneway = 1;
     186                        }
     187                } else if (w.hasTag("oneway", "-1") || w.hasTag("oneway", "reverse")) {
     188                        if (w.hasTag("busway", "lane") || w.hasTag("busway:left", "lane") || w.hasTag("busway:right", "lane")
     189                                        || w.hasTag("oneway:bus", "no") || w.hasTag("busway", "opposite_lane")
     190                                        || w.hasTag("oneway:psv", "no") || w.hasTag("trolley_wire", "backward")) {
     191                                oneway = -2;
     192                        } else {
     193                                oneway = -1;
     194                        }
     195                }
     196
     197                visit(w.getNodes(), oneway, revisit);
     198
     199        }
     200
     201        /**
     202         * Variation of the visit method that allows a special visualization of oneway
     203         * roads
     204         *
     205         * @param nodes
     206         *            nodes
     207         * @param oneway
     208         *            oneway
     209         */
     210        public void visit(List<Node> nodes, int oneway, boolean revisit) {
     211                Node lastN = null;
     212                for (Node n : nodes) {
     213                        if (lastN == null) {
     214                                lastN = n;
     215                                continue;
     216                        }
     217                        if (!revisit)
     218                                drawSegment(lastN, n, new Color(128, 0, 128, 100), oneway, revisit);
     219                        else
     220                                drawSegment(lastN, n, new Color(0, 0, 0, 180), oneway, revisit);
     221                        lastN = n;
     222                }
     223        }
     224
     225        /**
     226         * Draw a small rectangle. White if selected (as always) or red otherwise.
     227         *
     228         * @param n
     229         *            The node to draw.
     230         */
     231        @Override
     232        public void visit(Node n) {
     233                if (n.isDrawable() && isNodeVisible(n)) {
     234                        drawNode(n, Color.BLUE);
     235                }
     236        }
     237
     238        /**
     239         * Draws a line around the segment
     240         *
     241         * @param n1
     242         *            The first node of segment
     243         * @param n2
     244         *            The second node of segment
     245         * @param color
     246         *            The color
     247         */
     248        protected void drawSegment(Node n1, Node n2, Color color, int oneway, boolean revisit) {
     249                if (n1.isDrawable() && n2.isDrawable() && isSegmentVisible(n1, n2)) {
     250                        try {
     251                                drawSegment(mv.getPoint(n1), mv.getPoint(n2), color, oneway, revisit);
     252                        } catch (NullPointerException ex) {
     253                                // do nothing
     254                                Logging.trace(ex);
     255                        }
     256
     257                }
     258        }
     259
     260        /**
     261         * Draws a line around the segment
     262         *
     263         * @param p1
     264         *            The first point of segment
     265         * @param p2
     266         *            The second point of segment
     267         * @param color
     268         *            The color
     269         */
     270        protected void drawSegment(Point p1, Point p2, Color color, int oneway, boolean revisit) {
     271
     272                double t = Math.atan2((double) p2.x - p1.x, (double) p2.y - p1.y);
     273                double cosT = 9 * Math.cos(t);
     274                double sinT = 9 * Math.sin(t);
     275
     276                if (revisit) {
     277                        // draw 3 separate lines
     278                        g.setColor(new Color(0, 0, 0, 140));
     279                        int[] xPointsMiddle = { (int) (p1.x + 0.3 * cosT), (int) (p2.x + 0.3 * cosT), (int) (p2.x - 0.3 * cosT),
     280                                        (int) (p1.x - 0.3 * cosT) };
     281                        int[] yPointsMiddle = { (int) (p1.y - 0.3 * sinT), (int) (p2.y - 0.3 * sinT), (int) (p2.y + 0.3 * sinT),
     282                                        (int) (p1.y + 0.3 * sinT) };
     283                        g.fillPolygon(xPointsMiddle, yPointsMiddle, 4);
     284
     285                        g.setColor(color);
     286
     287                        int[] xPointsBottom = { (int) (p1.x - cosT + 0.2 * cosT), (int) (p2.x - cosT + 0.2 * cosT),
     288                                        (int) (p2.x - 1.3 * cosT), (int) (p1.x - 1.3 * cosT) };
     289                        int[] yPointsBottom = { (int) (p1.y + sinT - 0.2 * sinT), (int) (p2.y + sinT - 0.2 * sinT),
     290                                        (int) (p2.y + 1.3 * sinT), (int) (p1.y + 1.3 * sinT) };
     291                        g.fillPolygon(xPointsBottom, yPointsBottom, 4);
     292
     293                        int[] xPointsTop = { (int) (p1.x + 1.3 * cosT), (int) (p2.x + 1.3 * cosT), (int) (p2.x + cosT - 0.2 * cosT),
     294                                        (int) (p1.x + cosT - 0.2 * cosT) };
     295                        int[] yPointsTop = { (int) (p1.y - 1.3 * sinT), (int) (p2.y - 1.3 * sinT), (int) (p2.y - sinT + 0.2 * sinT),
     296                                        (int) (p1.y - sinT + 0.2 * sinT) };
     297                        g.fillPolygon(xPointsTop, yPointsTop, 4);
     298
     299                } else {
     300                        int[] xPoints = { (int) (p1.x + cosT), (int) (p2.x + cosT), (int) (p2.x - cosT), (int) (p1.x - cosT) };
     301                        int[] yPoints = { (int) (p1.y - sinT), (int) (p2.y - sinT), (int) (p2.y + sinT), (int) (p1.y + sinT) };
     302                        g.setColor(color);
     303                        g.fillPolygon(xPoints, yPoints, 4);
     304                        g.fillOval(p1.x - 9, p1.y - 9, 18, 18);
     305                        g.fillOval(p2.x - 9, p2.y - 9, 18, 18);
     306                }
     307
     308                if (oneway != 0) {
     309                        double middleX = (p1.x + p2.x) / 2.0;
     310                        double middleY = (p1.y + p2.y) / 2.0;
     311                        double cosTriangle = 6 * Math.cos(t);
     312                        double sinTriangle = 6 * Math.sin(t);
     313                        g.setColor(Color.WHITE);
     314
     315                        if (oneway > 0) {
     316                                int[] xFillTriangle = { (int) (middleX + cosTriangle), (int) (middleX - cosTriangle),
     317                                                (int) (middleX + 2 * sinTriangle) };
     318                                int[] yFillTriangle = { (int) (middleY - sinTriangle), (int) (middleY + sinTriangle),
     319                                                (int) (middleY + 2 * cosTriangle) };
     320                                g.fillPolygon(xFillTriangle, yFillTriangle, 3);
     321
     322                                if (oneway == 2) {
     323                                        int[] xDrawTriangle = { (int) (middleX + cosTriangle), (int) (middleX - cosTriangle),
     324                                                        (int) (middleX - 2 * sinTriangle) };
     325                                        int[] yDrawTriangle = { (int) (middleY - sinTriangle), (int) (middleY + sinTriangle),
     326                                                        (int) (middleY - 2 * cosTriangle) };
     327                                        g.drawPolygon(xDrawTriangle, yDrawTriangle, 3);
     328                                }
     329                        }
     330
     331                        if (oneway < 0) {
     332                                int[] xFillTriangle = { (int) (middleX + cosTriangle), (int) (middleX - cosTriangle),
     333                                                (int) (middleX - 2 * sinTriangle) };
     334                                int[] yFillTriangle = { (int) (middleY - sinTriangle), (int) (middleY + sinTriangle),
     335                                                (int) (middleY - 2 * cosTriangle) };
     336                                g.fillPolygon(xFillTriangle, yFillTriangle, 3);
     337
     338                                if (oneway == -2) {
     339                                        int[] xDrawTriangle = { (int) (middleX + cosTriangle), (int) (middleX - cosTriangle),
     340                                                        (int) (middleX + 2 * sinTriangle) };
     341                                        int[] yDrawTriangle = { (int) (middleY - sinTriangle), (int) (middleY + sinTriangle),
     342                                                        (int) (middleY + 2 * cosTriangle) };
     343                                        g.drawPolygon(xDrawTriangle, yDrawTriangle, 3);
     344                                }
     345                        }
     346
     347                }
     348
     349        }
     350
     351        /**
     352         * Draws a circle around the node
     353         *
     354         * @param n
     355         *            The node
     356         * @param color
     357         *            The circle color
     358         */
     359        @Override
     360        protected void drawNode(Node n, Color color) {
     361                if (mv == null || g == null) {
     362                        return;
     363                }
     364                Point p = mv.getPoint(n);
     365                if (p == null) {
     366                        return;
     367                }
     368                g.setColor(color);
     369                g.drawOval(p.x - 5, p.y - 5, 10, 10);
     370
     371        }
     372
     373        /**
     374         * Draws s stop_position as a blue circle; draws a platform as a blue square
     375         *
     376         * @param primitive
     377         *            primitive
     378         */
     379        protected void drawStop(OsmPrimitive primitive, Boolean stopPosition) {
     380
     381                // find the point to which the stop visualization will be linked:
     382                Node n = new Node(primitive.getBBox().getCenter());
     383
     384                Point p = mv.getPoint(n);
     385
     386                g.setColor(Color.BLUE);
     387
     388                if (stopPosition) {
     389                        g.fillOval(p.x - 8, p.y - 8, 16, 16);
     390                } else {
     391                        g.fillRect(p.x - 8, p.y - 8, 16, 16);
     392                }
     393
     394        }
     395
     396        /**
     397         * Draws the labels for the stops, which include the ordered position of the
     398         * stop in the route and the ref numbers of other routes that use this stop
     399         *
     400         * @param primitive
     401         *            primitive
     402         * @param label
     403         *            label
     404         */
     405        protected void drawStopLabel(OsmPrimitive primitive, String label, Boolean platform) {
     406
     407                // find the point to which the stop visualization will be linked:
     408                Node n = new Node(primitive.getBBox().getCenter());
     409
     410                Point p = mv.getPoint(n);
     411
     412                if (label != null && !label.equals("")) {
     413                        Font stringFont = new Font("SansSerif", Font.PLAIN, 24);
     414                        if (platform) {
     415                                g.setColor(new Color(255, 255, 102));
     416                                g.setFont(stringFont);
     417                                g.drawString(label, p.x + 20, p.y - 40);
     418                        } else {
     419                                g.setColor(Color.WHITE);
     420                                g.setFont(stringFont);
     421                                g.drawString(label, p.x + 20, p.y - 20);
     422                        }
     423                }
     424
     425                // draw the ref values of all parent routes:
     426                List<String> parentsLabelList = new ArrayList<>();
     427                for (OsmPrimitive parent : primitive.getReferrers()) {
     428                        if (parent.getType().equals(OsmPrimitiveType.RELATION)) {
     429                                Relation relation = (Relation) parent;
     430                                if (RouteUtils.isVersionTwoPTRoute(relation) && relation.get("ref") != null
     431                                                && !relation.get("ref").equals("")) {
     432
     433                                        boolean stringFound = false;
     434                                        for (String s : parentsLabelList) {
     435                                                if (s.equals(relation.get("ref"))) {
     436                                                        stringFound = true;
     437                                                }
     438                                        }
     439                                        if (!stringFound) {
     440                                                parentsLabelList.add(relation.get("ref"));
     441                                        }
     442
     443                                }
     444                        }
     445                }
     446
     447                Collections.sort(parentsLabelList, new RefTagComparator());
     448
     449                StringBuilder sb = new StringBuilder();
     450                for (String s : parentsLabelList) {
     451                        sb.append(s).append(";");
     452                }
     453
     454                if (sb.length() > 0) {
     455                        // remove the last semicolon:
     456                        String parentsLabel = sb.substring(0, sb.length() - 1);
     457
     458                        g.setColor(new Color(255, 20, 147));
     459                        Font parentLabelFont = new Font("SansSerif", Font.ITALIC, 20);
     460                        g.setFont(parentLabelFont);
     461                        g.drawString(parentsLabel, p.x + 20, p.y + 20);
     462                }
     463
     464        }
     465
     466        /**
     467         * Compares route ref numbers
     468         *
     469         * @author darya
     470         *
     471         */
     472        private static class RefTagComparator implements Comparator<String> {
     473
     474                @Override
     475                public int compare(String s1, String s2) {
     476
     477                        if (s1 == null || s1.equals("") || s2 == null || s2.equals("")) {
     478                                // if at least one of the strings is null or empty, there is no
     479                                // point in comparing:
     480                                return 0;
     481                        }
     482
     483                        String[] splitString1 = s1.split("\\D");
     484                        String[] splitString2 = s2.split("\\D");
     485
     486                        if (splitString1.length == 0 && splitString2.length != 0) {
     487                                // if the first ref does not start a digit and the second ref
     488                                // starts with a digit:
     489                                return 1;
     490                        }
     491
     492                        if (splitString1.length != 0 && splitString2.length == 0) {
     493                                // if the first ref starts a digit and the second ref does not
     494                                // start with a digit:
     495                                return -1;
     496                        }
     497
     498                        if (splitString1.length == 0 && splitString2.length == 0) {
     499                                // if both ref values do not start with a digit:
     500                                return s1.compareTo(s2);
     501                        }
     502
     503                        String firstNumberString1 = splitString1[0];
     504                        String firstNumberString2 = splitString2[0];
     505
     506                        try {
     507                                int firstNumber1 = Integer.parseInt(firstNumberString1);
     508                                int firstNumber2 = Integer.parseInt(firstNumberString2);
     509                                if (firstNumber1 > firstNumber2) {
     510                                        return 1;
     511                                } else if (firstNumber1 < firstNumber2) {
     512                                        return -1;
     513                                } else {
     514                                        // if the first number is the same:
     515
     516                                        return s1.compareTo(s2);
     517
     518                                }
     519                        } catch (NumberFormatException ex) {
     520                                return s1.compareTo(s2);
     521                        }
     522
     523                }
     524
     525        }
     526
     527        /**
     528         * Visualizes the fix variants, assigns colors to them based on their order
     529         *
     530         * @param fixVariants
     531         *            fix variants
     532         */
     533        protected void visitFixVariants(HashMap<Character, List<PTWay>> fixVariants,
     534                        HashMap<Way, List<Character>> wayColoring) {
     535
     536                drawFixVariantsWithParallelLines(wayColoring);
     537
     538                Color[] colors = { new Color(255, 0, 0, 150), new Color(0, 255, 0, 150), new Color(0, 0, 255, 150),
     539                                new Color(255, 255, 0, 150), new Color(0, 255, 255, 150) };
     540
     541                int colorIndex = 0;
     542
     543                double letterX = MainApplication.getMap().mapView.getBounds().getMinX() + 20;
     544                double letterY = MainApplication.getMap().mapView.getBounds().getMinY() + 100;
     545
     546                for (Entry<Character, List<PTWay>> entry : fixVariants.entrySet()) {
     547                        Character c = entry.getKey();
     548                        if (fixVariants.get(c) != null) {
     549                                drawFixVariantLetter(c.toString(), colors[colorIndex % 5], letterX, letterY);
     550                                colorIndex++;
     551                                letterY = letterY + 60;
     552                        }
     553                }
     554
     555                // display the "Esc" label:
     556                if (!fixVariants.isEmpty()) {
     557                        drawFixVariantLetter("Esc", Color.WHITE, letterX, letterY);
     558                }
     559        }
     560
     561        @SuppressWarnings("unused")
     562        private void drawFixVariant(List<PTWay> fixVariant, Color color) {
     563                for (PTWay ptway : fixVariant) {
     564                        for (Way way : ptway.getWays()) {
     565                                for (Pair<Node, Node> nodePair : way.getNodePairs(false)) {
     566                                        drawSegment(nodePair.a, nodePair.b, color, 0, false);
     567                                }
     568                        }
     569                }
     570        }
     571
     572        protected void drawFixVariantsWithParallelLines(Map<Way, List<Character>> wayColoring) {
     573
     574                HashMap<Character, Color> colors = new HashMap<>();
     575                colors.put('A', new Color(255, 0, 0, 200));
     576                colors.put('B', new Color(0, 255, 0, 200));
     577                colors.put('C', new Color(0, 0, 255, 200));
     578                colors.put('D', new Color(255, 255, 0, 200));
     579                colors.put('E', new Color(0, 255, 255, 200));
     580
     581                for (Entry<Way, List<Character>> entry : wayColoring.entrySet()) {
     582                        Way way = entry.getKey();
     583                        List<Character> letterList = wayColoring.get(way);
     584                        List<Color> wayColors = new ArrayList<>();
     585                        for (Character letter : letterList) {
     586                                wayColors.add(colors.get(letter));
     587                        }
     588                        for (Pair<Node, Node> nodePair : way.getNodePairs(false)) {
     589                                drawSegmentWithParallelLines(nodePair.a, nodePair.b, wayColors);
     590                        }
     591                }
     592        }
     593
     594        protected void drawSegmentWithParallelLines(Node n1, Node n2, List<Color> colors) {
     595                if (!n1.isDrawable() || !n2.isDrawable() || !isSegmentVisible(n1, n2)) {
     596                        return;
     597                }
     598
     599                Point p1 = mv.getPoint(n1);
     600                Point p2 = mv.getPoint(n2);
     601                double t = Math.atan2((double) p2.x - p1.x, (double) p2.y - p1.y);
     602                double cosT = 9 * Math.cos(t);
     603                double sinT = 9 * Math.sin(t);
     604                double heightCosT = 9 * Math.cos(t);
     605                double heightSinT = 9 * Math.sin(t);
     606
     607                double prevPointX = p1.x;
     608                double prevPointY = p1.y;
     609                double nextPointX = p1.x + heightSinT;
     610                double nextPointY = p1.y + heightCosT;
     611
     612                Color currentColor = colors.get(0);
     613                int i = 0;
     614                g.setColor(currentColor);
     615                g.fillOval(p1.x - 9, p1.y - 9, 18, 18);
     616
     617                if (colors.size() == 1) {
     618                        int[] xPoints = { (int) (p1.x + cosT), (int) (p2.x + cosT), (int) (p2.x - cosT), (int) (p1.x - cosT) };
     619                        int[] yPoints = { (int) (p1.y - sinT), (int) (p2.y - sinT), (int) (p2.y + sinT), (int) (p1.y + sinT) };
     620                        g.setColor(currentColor);
     621                        g.fillPolygon(xPoints, yPoints, 4);
     622                } else {
     623                        boolean iterate = true;
     624                        while (iterate) {
     625                                currentColor = colors.get(i % colors.size());
     626
     627                                int[] xPoints = { (int) (prevPointX + cosT), (int) (nextPointX + cosT), (int) (nextPointX - cosT),
     628                                                (int) (prevPointX - cosT) };
     629                                int[] yPoints = { (int) (prevPointY - sinT), (int) (nextPointY - sinT), (int) (nextPointY + sinT),
     630                                                (int) (prevPointY + sinT) };
     631                                g.setColor(currentColor);
     632                                g.fillPolygon(xPoints, yPoints, 4);
     633
     634                                prevPointX = prevPointX + heightSinT;
     635                                prevPointY = prevPointY + heightCosT;
     636                                nextPointX = nextPointX + heightSinT;
     637                                nextPointY = nextPointY + heightCosT;
     638                                i++;
     639                                if ((p1.x < p2.x && nextPointX >= p2.x) || (p1.x >= p2.x && nextPointX <= p2.x)) {
     640                                        iterate = false;
     641                                }
     642                        }
     643
     644                        int[] lastXPoints = { (int) (prevPointX + cosT), (int) (p2.x + cosT), (int) (p2.x - cosT),
     645                                        (int) (prevPointX - cosT) };
     646                        int[] lastYPoints = { (int) (prevPointY - sinT), (int) (p2.y - sinT), (int) (p2.y + sinT),
     647                                        (int) (prevPointY + sinT) };
     648                        g.setColor(currentColor);
     649                        g.fillPolygon(lastXPoints, lastYPoints, 4);
     650                }
     651
     652                g.setColor(currentColor);
     653                g.fillOval(p2.x - 9, p2.y - 9, 18, 18);
     654        }
     655
     656        /**
     657         * Visuallizes the letters for each fix variant
     658         *
     659         * @param letter
     660         *            letter
     661         * @param color
     662         *            color
     663         * @param letterX
     664         *            letter X
     665         * @param letterY
     666         *            letter Y
     667         */
     668        private void drawFixVariantLetter(String letter, Color color, double letterX, double letterY) {
     669                g.setColor(color);
     670                Font stringFont = new Font("SansSerif", Font.PLAIN, 50);
     671                g.setFont(stringFont);
     672                try {
     673                        g.drawString(letter, (int) letterX, (int) letterY);
     674                        g.drawString(letter, (int) letterX, (int) letterY);
     675                } catch (NullPointerException ex) {
     676                        // do nothing
     677                        Logging.trace(ex);
     678                }
     679
     680        }
    639681
    640682}
Note: See TracChangeset for help on using the changeset viewer.