Changeset 34247 in osm for applications/editors/josm/plugins/pt_assistant
- Timestamp:
- 2018-06-04T12:10:57+02:00 (6 years ago)
- 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 40 40 public class PTAssistantPaintVisitor extends PaintVisitor { 41 41 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 } 639 681 640 682 }
Note:
See TracChangeset
for help on using the changeset viewer.