source: josm/trunk/src/org/openstreetmap/josm/data/osm/visitor/MapPaintVisitor.java@ 2526

Last change on this file since 2526 was 2526, checked in by bastiK, 14 years ago

draw turn restrictions in gray if when the layer is inactive

  • Property svn:eol-style set to native
File size: 62.4 KB
Line 
1/* License: GPL. Copyright 2007 by Immanuel Scholz and others */
2package org.openstreetmap.josm.data.osm.visitor;
3
4/* To enable debugging or profiling remove the double / signs */
5
6import static org.openstreetmap.josm.tools.I18n.marktr;
7import static org.openstreetmap.josm.tools.I18n.tr;
8
9import java.awt.BasicStroke;
10import java.awt.Color;
11import java.awt.Font;
12import java.awt.FontMetrics;
13import java.awt.Graphics2D;
14import java.awt.Image;
15import java.awt.Point;
16import java.awt.Polygon;
17import java.awt.Rectangle;
18import java.awt.Stroke;
19import java.awt.geom.GeneralPath;
20import java.awt.geom.Point2D;
21import java.awt.geom.Rectangle2D;
22import java.util.ArrayList;
23import java.util.Arrays;
24import java.util.Collection;
25import java.util.Collections;
26import java.util.Comparator;
27import java.util.Iterator;
28import java.util.LinkedList;
29import java.util.List;
30
31import javax.swing.ImageIcon;
32
33import org.openstreetmap.josm.Main;
34import org.openstreetmap.josm.data.Bounds;
35import org.openstreetmap.josm.data.coor.EastNorth;
36import org.openstreetmap.josm.data.coor.LatLon;
37import org.openstreetmap.josm.data.osm.BBox;
38import org.openstreetmap.josm.data.osm.DataSet;
39import org.openstreetmap.josm.data.osm.Node;
40import org.openstreetmap.josm.data.osm.OsmPrimitive;
41import org.openstreetmap.josm.data.osm.OsmUtils;
42import org.openstreetmap.josm.data.osm.Relation;
43import org.openstreetmap.josm.data.osm.RelationMember;
44import org.openstreetmap.josm.data.osm.Way;
45import org.openstreetmap.josm.gui.DefaultNameFormatter;
46import org.openstreetmap.josm.gui.mappaint.AreaElemStyle;
47import org.openstreetmap.josm.gui.mappaint.ElemStyle;
48import org.openstreetmap.josm.gui.mappaint.ElemStyles;
49import org.openstreetmap.josm.gui.mappaint.IconElemStyle;
50import org.openstreetmap.josm.gui.mappaint.LineElemStyle;
51import org.openstreetmap.josm.gui.mappaint.MapPaintStyles;
52import org.openstreetmap.josm.tools.ImageProvider;
53import org.openstreetmap.josm.tools.LanguageInfo;
54
55public class MapPaintVisitor extends SimplePaintVisitor {
56 protected boolean useRealWidth;
57 protected boolean zoomLevelDisplay;
58 protected boolean drawMultipolygon;
59 protected boolean drawRestriction;
60 protected boolean leftHandTraffic;
61 //protected boolean restrictionDebug;
62 protected int showNames;
63 protected int showIcons;
64 protected int useStrokes;
65 protected int fillAlpha;
66 protected Color untaggedColor;
67 protected Color textColor;
68 protected Color areaTextColor;
69 protected float[] currentDashed = new float[0];
70 protected Color currentDashedColor;
71 protected int currentWidth = 0;
72 protected Stroke currentStroke = null;
73 protected Font orderFont;
74 protected ElemStyles.StyleSet styles;
75 protected double circum;
76 protected double dist;
77 protected Collection<String> regionalNameOrder;
78 protected boolean useStyleCache;
79 private static int paintid = 0;
80 private EastNorth minEN;
81 private EastNorth maxEN;
82
83 //protected int profilerVisibleNodes;
84 //protected int profilerVisibleWays;
85 //protected int profilerVisibleAreas;
86 //protected int profilerSegments;
87 //protected int profilerVisibleSegments;
88 //protected boolean profilerOmitDraw;
89
90 protected boolean isZoomOk(ElemStyle e) {
91 if (!zoomLevelDisplay) /* show everything if the user wishes so */
92 return true;
93
94 if(e == null) /* the default for things that don't have a rule (show, if scale is smaller than 1500m) */
95 return (circum < 1500);
96
97 return !(circum >= e.maxScale || circum < e.minScale);
98 }
99
100 public ElemStyle getPrimitiveStyle(OsmPrimitive osm) {
101 if(!useStyleCache)
102 return (styles != null) ? styles.get(osm) : null;
103
104 if(osm.mappaintStyle == null && styles != null) {
105 osm.mappaintStyle = styles.get(osm);
106 if(osm instanceof Way) {
107 ((Way)osm).isMappaintArea = styles.isArea(osm);
108 }
109 }
110 return osm.mappaintStyle;
111 }
112
113 public IconElemStyle getPrimitiveNodeStyle(OsmPrimitive osm) {
114 if(!useStyleCache)
115 return (styles != null) ? styles.getIcon(osm) : null;
116
117 if(osm.mappaintStyle == null && styles != null) {
118 osm.mappaintStyle = styles.getIcon(osm);
119 }
120
121 return (IconElemStyle)osm.mappaintStyle;
122 }
123
124 public boolean isPrimitiveArea(Way osm) {
125 if(!useStyleCache)
126 return styles.isArea(osm);
127
128 if(osm.mappaintStyle == null && styles != null) {
129 osm.mappaintStyle = styles.get(osm);
130 osm.isMappaintArea = styles.isArea(osm);
131 }
132 return osm.isMappaintArea;
133 }
134
135 /**
136 * Draw a small rectangle.
137 * White if selected (as always) or red otherwise.
138 *
139 * @param n The node to draw.
140 */
141 @Override
142 public void visit(Node n) {}
143 public void drawNode(Node n) {
144 /* check, if the node is visible at all */
145 if((n.getEastNorth().east() > maxEN.east() ) ||
146 (n.getEastNorth().north() > maxEN.north()) ||
147 (n.getEastNorth().east() < minEN.east() ) ||
148 (n.getEastNorth().north() < minEN.north()))
149 return;
150
151 IconElemStyle nodeStyle = (IconElemStyle)getPrimitiveStyle(n);
152
153 //if(profilerOmitDraw)
154 // return;
155
156 if (nodeStyle != null && isZoomOk(nodeStyle) && showIcons > dist) {
157 if (inactive || n.isDisabled()) {
158 drawNode(n, nodeStyle.getDisabledIcon(), nodeStyle.annotate, data.isSelected(n));
159 } else {
160 drawNode(n, nodeStyle.icon, nodeStyle.annotate, data.isSelected(n));
161 }
162 } else if (n.highlighted) {
163 drawNode(n, highlightColor, selectedNodeSize, selectedNodeRadius, fillSelectedNode);
164 } else if (data.isSelected(n)) {
165 drawNode(n, selectedColor, selectedNodeSize, selectedNodeRadius, fillSelectedNode);
166 } else if (n.isTagged()) {
167 drawNode(n, nodeColor, taggedNodeSize, taggedNodeRadius, fillUnselectedNode);
168 } else if (inactive || n.isDisabled()) {
169 drawNode(n, inactiveColor, unselectedNodeSize, unselectedNodeRadius, fillUnselectedNode);
170 } else {
171 drawNode(n, nodeColor, unselectedNodeSize, unselectedNodeRadius, fillUnselectedNode);
172 }
173 }
174
175 /**
176 * Draw a line for all segments, according to tags.
177 * @param w The way to draw.
178 */
179 @Override
180 public void visit(Way w) {}
181 public void drawWay(Way w, int fillAreas) {
182 if(w.getNodesCount() < 2)
183 return;
184
185 /* check, if the way is visible at all */
186 double minx = 10000;
187 double maxx = -10000;
188 double miny = 10000;
189 double maxy = -10000;
190
191 for (Node n : w.getNodes())
192 {
193 if(n.getEastNorth().east() > maxx) {
194 maxx = n.getEastNorth().east();
195 }
196 if(n.getEastNorth().north() > maxy) {
197 maxy = n.getEastNorth().north();
198 }
199 if(n.getEastNorth().east() < minx) {
200 minx = n.getEastNorth().east();
201 }
202 if(n.getEastNorth().north() < miny) {
203 miny = n.getEastNorth().north();
204 }
205 }
206
207 if ((minx > maxEN.east()) ||
208 (miny > maxEN.north()) ||
209 (maxx < minEN.east()) ||
210 (maxy < minEN.north()))
211 return;
212
213 ElemStyle wayStyle = getPrimitiveStyle(w);
214
215 if(!isZoomOk(wayStyle))
216 return;
217
218 if(wayStyle==null)
219 {
220 /* way without style */
221 //profilerVisibleWays++;
222 //if(!profilerOmitDraw)
223 drawWay(w, null, untaggedColor, data.isSelected(w));
224 }
225 else if(wayStyle instanceof LineElemStyle)
226 {
227 /* way with line style */
228 //profilerVisibleWays++;
229 //if(!profilerOmitDraw)
230 drawWay(w, (LineElemStyle)wayStyle, untaggedColor, data.isSelected(w));
231 }
232 else if (wayStyle instanceof AreaElemStyle)
233 {
234 AreaElemStyle areaStyle = (AreaElemStyle) wayStyle;
235 /* way with area style */
236 //if(!profilerOmitDraw)
237 //{
238 if (fillAreas > dist)
239 {
240 // profilerVisibleAreas++;
241 drawArea(w, data.isSelected(w) ? selectedColor : areaStyle.color);
242 if(!w.isClosed()) {
243 putError(w, tr("Area style way is not closed."), true);
244 }
245 }
246 drawWay(w, areaStyle.line, areaStyle.color, data.isSelected(w));
247 //}
248 }
249 }
250
251 public void drawWay(Way w, LineElemStyle l, Color color, boolean selected) {
252 /* show direction arrows, if draw.segment.relevant_directions_only is not set,
253 the way is tagged with a direction key
254 (even if the tag is negated as in oneway=false) or the way is selected */
255 boolean showDirection = data.isSelected(w) || ((!useRealWidth) && (showDirectionArrow
256 && (!showRelevantDirectionsOnly || w.hasDirectionKeys())));
257 /* head only takes over control if the option is true,
258 the direction should be shown at all and not only because it's selected */
259 boolean showOnlyHeadArrowOnly = showDirection && !data.isSelected(w) && showHeadArrowOnly;
260 int width = defaultSegmentWidth;
261 int realWidth = 0; /* the real width of the element in meters */
262 float dashed[] = new float[0];
263 Color dashedColor = null;
264 Node lastN;
265
266 if(l != null)
267 {
268 if (l.color != null) {
269 color = l.color;
270 }
271 width = l.width;
272 realWidth = l.realWidth;
273 dashed = l.dashed;
274 dashedColor = l.dashedColor;
275 }
276 if(selected) {
277 color = selectedColor;
278 }
279 if (realWidth > 0 && useRealWidth && !showDirection)
280 {
281 int tmpWidth = (int) (100 / (float) (circum / realWidth));
282 if (tmpWidth > width) {
283 width = tmpWidth;
284 }
285
286 /* if we have a "width" tag, try use it */
287 /* (this might be slow and could be improved by caching the value in the Way, on the other hand only used if "real width" is enabled) */
288 String widthTag = w.get("width");
289 if(widthTag == null) {
290 widthTag = w.get("est_width");
291 }
292 if(widthTag != null) {
293 try {
294 width = Integer.parseInt(widthTag);
295 }
296 catch(NumberFormatException nfe) {
297 }
298 }
299 }
300
301 if(w.highlighted) {
302 color = highlightColor;
303 } else if(data.isSelected(w)) {
304 color = selectedColor;
305 } else if(w.isDisabled()) {
306 color = inactiveColor;
307 }
308
309 /* draw overlays under the way */
310 if(l != null && l.overlays != null)
311 {
312 for(LineElemStyle s : l.overlays)
313 {
314 if(!s.over)
315 {
316 lastN = null;
317 for(Node n : w.getNodes())
318 {
319 if(lastN != null)
320 {
321 drawSeg(lastN, n, s.color != null && !data.isSelected(w) ? s.color : color,
322 false, s.getWidth(width), s.dashed, s.dashedColor);
323 }
324 lastN = n;
325 }
326 }
327 }
328 }
329
330 /* draw the way */
331 lastN = null;
332 Iterator<Node> it = w.getNodes().iterator();
333 while (it.hasNext())
334 {
335 Node n = it.next();
336 if(lastN != null) {
337 drawSeg(lastN, n, color,
338 showOnlyHeadArrowOnly ? !it.hasNext() : showDirection, width, dashed, dashedColor);
339 }
340 lastN = n;
341 }
342
343 /* draw overlays above the way */
344 if(l != null && l.overlays != null)
345 {
346 for(LineElemStyle s : l.overlays)
347 {
348 if(s.over)
349 {
350 lastN = null;
351 for(Node n : w.getNodes())
352 {
353 if(lastN != null)
354 {
355 drawSeg(lastN, n, s.color != null && !data.isSelected(w) ? s.color : color,
356 false, s.getWidth(width), s.dashed, s.dashedColor);
357 }
358 lastN = n;
359 }
360 }
361 }
362 }
363
364 if(showOrderNumber)
365 {
366 int orderNumber = 0;
367 lastN = null;
368 for(Node n : w.getNodes())
369 {
370 if(lastN != null)
371 {
372 orderNumber++;
373 drawOrderNumber(lastN, n, orderNumber);
374 }
375 lastN = n;
376 }
377 }
378 displaySegments();
379 }
380
381 public Collection<PolyData> joinWays(Collection<Way> join, OsmPrimitive errs)
382 {
383 Collection<PolyData> res = new LinkedList<PolyData>();
384 Object[] joinArray = join.toArray();
385 int left = join.size();
386 while(left != 0)
387 {
388 Way w = null;
389 boolean selected = false;
390 List<Node> n = null;
391 boolean joined = true;
392 while(joined && left != 0)
393 {
394 joined = false;
395 for(int i = 0; i < joinArray.length && left != 0; ++i)
396 {
397 if(joinArray[i] != null)
398 {
399 Way c = (Way)joinArray[i];
400 if(w == null)
401 { w = c; selected = data.isSelected(w); joinArray[i] = null; --left; }
402 else
403 {
404 int mode = 0;
405 int cl = c.getNodesCount()-1;
406 int nl;
407 if(n == null)
408 {
409 nl = w.getNodesCount()-1;
410 if(w.getNode(nl) == c.getNode(0)) {
411 mode = 21;
412 } else if(w.getNode(nl) == c.getNode(cl)) {
413 mode = 22;
414 } else if(w.getNode(0) == c.getNode(0)) {
415 mode = 11;
416 } else if(w.getNode(0) == c.getNode(cl)) {
417 mode = 12;
418 }
419 }
420 else
421 {
422 nl = n.size()-1;
423 if(n.get(nl) == c.getNode(0)) {
424 mode = 21;
425 } else if(n.get(0) == c.getNode(cl)) {
426 mode = 12;
427 } else if(n.get(0) == c.getNode(0)) {
428 mode = 11;
429 } else if(n.get(nl) == c.getNode(cl)) {
430 mode = 22;
431 }
432 }
433 if(mode != 0)
434 {
435 joinArray[i] = null;
436 joined = true;
437 if(data.isSelected(c)) {
438 selected = true;
439 }
440 --left;
441 if(n == null) {
442 n = w.getNodes();
443 }
444 n.remove((mode == 21 || mode == 22) ? nl : 0);
445 if(mode == 21) {
446 n.addAll(c.getNodes());
447 } else if(mode == 12) {
448 n.addAll(0, c.getNodes());
449 } else if(mode == 22)
450 {
451 for(Node node : c.getNodes()) {
452 n.add(nl, node);
453 }
454 }
455 else /* mode == 11 */
456 {
457 for(Node node : c.getNodes()) {
458 n.add(0, node);
459 }
460 }
461 }
462 }
463 }
464 } /* for(i = ... */
465 } /* while(joined) */
466 if(n != null)
467 {
468 w = new Way(w);
469 w.setNodes(n);
470 // Do not mess with the DataSet's contents here.
471 }
472 if(!w.isClosed())
473 {
474 if(errs != null)
475 {
476 putError(errs, tr("multipolygon way ''{0}'' is not closed.",
477 w.getDisplayName(DefaultNameFormatter.getInstance())), true);
478 }
479 }
480 PolyData pd = new PolyData(w);
481 pd.selected = selected;
482 res.add(pd);
483 } /* while(left != 0) */
484
485 return res;
486 }
487
488 public void drawSelectedMember(OsmPrimitive osm, ElemStyle style, boolean area,
489 boolean areaselected)
490 {
491 if(osm instanceof Way)
492 {
493 if(style instanceof AreaElemStyle)
494 {
495 Way way = (Way)osm;
496 AreaElemStyle areaStyle = (AreaElemStyle)style;
497 drawWay(way, areaStyle.line, selectedColor, true);
498 if(area) {
499 drawArea(way, areaselected ? selectedColor : areaStyle.color);
500 }
501 }
502 else
503 {
504 drawWay((Way)osm, (LineElemStyle)style, selectedColor, true);
505 }
506 }
507 else if(osm instanceof Node)
508 {
509 if(style != null && isZoomOk(style)) {
510 drawNode((Node)osm, ((IconElemStyle)style).icon,
511 ((IconElemStyle)style).annotate, true);
512 } else {
513 drawNode((Node)osm, selectedColor, selectedNodeSize, selectedNodeRadius, fillSelectedNode);
514 }
515 }
516 osm.mappaintDrawnCode = paintid;
517 }
518
519 @Override
520 public void visit(Relation r) {}
521 public void paintUnselectedRelation(Relation r) {
522
523 if (drawMultipolygon && "multipolygon".equals(r.get("type")))
524 {
525 if(drawMultipolygon(r))
526 return;
527 }
528 else if (drawRestriction && "restriction".equals(r.get("type")))
529 {
530 drawRestriction(r);
531 }
532
533 if(data.isSelected(r)) /* draw ways*/
534 {
535 for (RelationMember m : r.getMembers())
536 {
537 if (m.isWay() && drawable(m.getMember()))
538 {
539 drawSelectedMember(m.getMember(), styles != null ? getPrimitiveStyle(m.getMember())
540 : null, true, true);
541 }
542 }
543 }
544 }
545
546 /* this current experimental implementation will only work for standard restrictions:
547 from(Way) / via(Node) / to(Way) */
548 public void drawRestriction(Relation r) {
549 //if(restrictionDebug)
550 // System.out.println("Restriction: " + r.keys.get("name") + " restriction " + r.keys.get("restriction"));
551
552 Way fromWay = null;
553 Way toWay = null;
554 OsmPrimitive via = null;
555
556 /* find the "from", "via" and "to" elements */
557 for (RelationMember m : r.getMembers())
558 {
559 //if(restrictionDebug)
560 // System.out.println("member " + m.member + " selected " + r.selected);
561
562 if (m.getMember().isDeleted()) {
563 putError(r, tr("Deleted member ''{0}'' in relation.",
564 m.getMember().getDisplayName(DefaultNameFormatter.getInstance())), true);
565 } else if(m.getMember().incomplete)
566 return;
567 else
568 {
569 if(m.isWay())
570 {
571 Way w = m.getWay();
572 if(w.getNodesCount() < 2)
573 {
574 putError(r, tr("Way ''{0}'' with less than two points.",
575 w.getDisplayName(DefaultNameFormatter.getInstance())), true);
576 }
577 else if("from".equals(m.getRole())) {
578 if(fromWay != null) {
579 putError(r, tr("More than one \"from\" way found."), true);
580 } else {
581 fromWay = w;
582 }
583 } else if("to".equals(m.getRole())) {
584 if(toWay != null) {
585 putError(r, tr("More than one \"to\" way found."), true);
586 } else {
587 toWay = w;
588 }
589 } else if("via".equals(m.getRole())) {
590 if(via != null) {
591 putError(r, tr("More than one \"via\" found."), true);
592 } else {
593 via = w;
594 }
595 } else {
596 putError(r, tr("Unknown role ''{0}''.", m.getRole()), true);
597 }
598 }
599 else if(m.isNode())
600 {
601 Node n = m.getNode();
602 if("via".equals(m.getRole()))
603 {
604 if(via != null) {
605 putError(r, tr("More than one \"via\" found."), true);
606 } else {
607 via = n;
608 }
609 } else {
610 putError(r, tr("Unknown role ''{0}''.", m.getRole()), true);
611 }
612 } else {
613 putError(r, tr("Unknown member type for ''{0}''.", m.getMember().getDisplayName(DefaultNameFormatter.getInstance())), true);
614 }
615 }
616 }
617
618 if (fromWay == null) {
619 putError(r, tr("No \"from\" way found."), true);
620 return;
621 }
622 if (toWay == null) {
623 putError(r, tr("No \"to\" way found."), true);
624 return;
625 }
626 if (via == null) {
627 putError(r, tr("No \"via\" node or way found."), true);
628 return;
629 }
630
631 Node viaNode;
632 if(via instanceof Node)
633 {
634 viaNode = (Node) via;
635 if(!fromWay.isFirstLastNode(viaNode)) {
636 putError(r, tr("The \"from\" way doesn't start or end at a \"via\" node."), true);
637 return;
638 }
639 if(!toWay.isFirstLastNode(viaNode)) {
640 putError(r, tr("The \"to\" way doesn't start or end at a \"via\" node."), true);
641 }
642 }
643 else
644 {
645 Way viaWay = (Way) via;
646 Node firstNode = viaWay.firstNode();
647 Node lastNode = viaWay.lastNode();
648 boolean onewayvia = false;
649
650 String onewayviastr = viaWay.get("oneway");
651 if(onewayviastr != null)
652 {
653 if("-1".equals(onewayviastr)) {
654 onewayvia = true;
655 Node tmp = firstNode;
656 firstNode = lastNode;
657 lastNode = tmp;
658 } else {
659 onewayvia = OsmUtils.getOsmBoolean(onewayviastr);
660 }
661 }
662
663 if(fromWay.isFirstLastNode(firstNode)) {
664 viaNode = firstNode;
665 } else if (!onewayvia && fromWay.isFirstLastNode(lastNode)) {
666 viaNode = lastNode;
667 } else {
668 putError(r, tr("The \"from\" way doesn't start or end at the \"via\" way."), true);
669 return;
670 }
671 if(!toWay.isFirstLastNode(viaNode == firstNode ? lastNode : firstNode)) {
672 putError(r, tr("The \"to\" way doesn't start or end at the \"via\" way."), true);
673 }
674 }
675
676 /* find the "direct" nodes before the via node */
677 Node fromNode = null;
678 if(fromWay.firstNode() == via) {
679 //System.out.println("From way heading away from via");
680 fromNode = fromWay.getNode(1);
681 } else {
682 //System.out.println("From way heading towards via");
683 fromNode = fromWay.getNode(fromWay.getNodesCount()-2);
684 }
685
686 Point pFrom = nc.getPoint(fromNode);
687 Point pVia = nc.getPoint(viaNode);
688
689 //if(restrictionDebug) {
690 /* find the "direct" node after the via node */
691 // Node toNode = null;
692 // if(toWay.firstNode() == via) {
693 // System.out.println("To way heading away from via");
694 // toNode = toWay.nodes.get(1);
695 // } else {
696 // System.out.println("To way heading towards via");
697 // toNode = toWay.nodes.get(toWay.nodes.size()-2);
698 // }
699 // Point pTo = nc.getPoint(toNode);
700
701 // /* debug output of interesting nodes */
702 // System.out.println("From: " + fromNode);
703 // drawNode(fromNode, selectedColor, selectedNodeSize, selectedNodeRadius, fillSelectedNode);
704 // System.out.println("Via: " + via);
705 // drawNode(via, selectedColor, selectedNodeSize, selectedNodeRadius, fillSelectedNode);
706 // System.out.println("To: " + toNode);
707 // drawNode(toNode, selectedColor, selectedNodeSize, selectedNodeRadius, fillSelectedNode);
708 // System.out.println("From X: " + pFrom.x + " Y " + pFrom.y);
709 // System.out.println("Via X: " + pVia.x + " Y " + pVia.y);
710 // System.out.println("To X: " + pTo.x + " Y " + pTo.y);
711 //}
712
713 /* starting from via, go back the "from" way a few pixels
714 (calculate the vector vx/vy with the specified length and the direction
715 away from the "via" node along the first segment of the "from" way)
716 */
717 double distanceFromVia=14;
718 double dx = (pFrom.x >= pVia.x) ? (pFrom.x - pVia.x) : (pVia.x - pFrom.x);
719 double dy = (pFrom.y >= pVia.y) ? (pFrom.y - pVia.y) : (pVia.y - pFrom.y);
720
721 double fromAngle;
722 if(dx == 0.0) {
723 fromAngle = Math.PI/2;
724 } else {
725 fromAngle = Math.atan(dy / dx);
726 }
727 double fromAngleDeg = Math.toDegrees(fromAngle);
728
729 double vx = distanceFromVia * Math.cos(fromAngle);
730 double vy = distanceFromVia * Math.sin(fromAngle);
731
732 if(pFrom.x < pVia.x) {
733 vx = -vx;
734 }
735 if(pFrom.y < pVia.y) {
736 vy = -vy;
737 }
738
739 //if(restrictionDebug)
740 // System.out.println("vx " + vx + " vy " + vy);
741
742 /* go a few pixels away from the way (in a right angle)
743 (calculate the vx2/vy2 vector with the specified length and the direction
744 90degrees away from the first segment of the "from" way)
745 */
746 double distanceFromWay=10;
747 double vx2 = 0;
748 double vy2 = 0;
749 double iconAngle = 0;
750
751 if(pFrom.x >= pVia.x && pFrom.y >= pVia.y) {
752 if(!leftHandTraffic) {
753 vx2 = distanceFromWay * Math.cos(Math.toRadians(fromAngleDeg - 90));
754 vy2 = distanceFromWay * Math.sin(Math.toRadians(fromAngleDeg - 90));
755 } else {
756 vx2 = distanceFromWay * Math.cos(Math.toRadians(fromAngleDeg + 90));
757 vy2 = distanceFromWay * Math.sin(Math.toRadians(fromAngleDeg + 90));
758 }
759 iconAngle = 270+fromAngleDeg;
760 }
761 if(pFrom.x < pVia.x && pFrom.y >= pVia.y) {
762 if(!leftHandTraffic) {
763 vx2 = distanceFromWay * Math.sin(Math.toRadians(fromAngleDeg));
764 vy2 = distanceFromWay * Math.cos(Math.toRadians(fromAngleDeg));
765 } else {
766 vx2 = distanceFromWay * Math.sin(Math.toRadians(fromAngleDeg + 180));
767 vy2 = distanceFromWay * Math.cos(Math.toRadians(fromAngleDeg + 180));
768 }
769 iconAngle = 90-fromAngleDeg;
770 }
771 if(pFrom.x < pVia.x && pFrom.y < pVia.y) {
772 if(!leftHandTraffic) {
773 vx2 = distanceFromWay * Math.cos(Math.toRadians(fromAngleDeg + 90));
774 vy2 = distanceFromWay * Math.sin(Math.toRadians(fromAngleDeg + 90));
775 } else {
776 vx2 = distanceFromWay * Math.cos(Math.toRadians(fromAngleDeg - 90));
777 vy2 = distanceFromWay * Math.sin(Math.toRadians(fromAngleDeg - 90));
778 }
779 iconAngle = 90+fromAngleDeg;
780 }
781 if(pFrom.x >= pVia.x && pFrom.y < pVia.y) {
782 if(!leftHandTraffic) {
783 vx2 = distanceFromWay * Math.sin(Math.toRadians(fromAngleDeg + 180));
784 vy2 = distanceFromWay * Math.cos(Math.toRadians(fromAngleDeg + 180));
785 } else {
786 vx2 = distanceFromWay * Math.sin(Math.toRadians(fromAngleDeg));
787 vy2 = distanceFromWay * Math.cos(Math.toRadians(fromAngleDeg));
788 }
789 iconAngle = 270-fromAngleDeg;
790 }
791
792 IconElemStyle nodeStyle = getPrimitiveNodeStyle(r);
793
794 if (nodeStyle == null) {
795 putError(r, tr("Style for restriction {0} not found.", r.get("restriction")), true);
796 return;
797 }
798
799 /* rotate icon with direction last node in from to */
800 //if(restrictionDebug)
801 // System.out.println("Deg1 " + fromAngleDeg + " Deg2 " + (fromAngleDeg + 180) + " Icon " + iconAngle);
802 ImageIcon rotatedIcon = ImageProvider.createRotatedImage(null /*icon2*/, inactive || r.isDisabled() ?
803 nodeStyle.getDisabledIcon() :
804 nodeStyle.icon, iconAngle);
805
806 /* scale down icon to 16*16 pixels */
807 ImageIcon smallIcon = new ImageIcon(rotatedIcon.getImage().getScaledInstance(16 , 16, Image.SCALE_SMOOTH));
808 int w = smallIcon.getIconWidth(), h=smallIcon.getIconHeight();
809 smallIcon.paintIcon ( Main.map.mapView, g, (int)(pVia.x+vx+vx2)-w/2, (int)(pVia.y+vy+vy2)-h/2 );
810
811 if (data.isSelected(r))
812 {
813 g.setColor ( selectedColor );
814 g.drawRect ((int)(pVia.x+vx+vx2)-w/2-2,(int)(pVia.y+vy+vy2)-h/2-2, w+4, h+4);
815 }
816 }
817
818 class PolyData {
819 public Polygon poly = new Polygon();
820 public Way way;
821 public boolean selected = false;
822 private Point p = null;
823 private Collection<Polygon> inner = null;
824 PolyData(Way w)
825 {
826 way = w;
827 for (Node n : w.getNodes())
828 {
829 p = nc.getPoint(n);
830 poly.addPoint(p.x,p.y);
831 }
832 }
833 public int contains(Polygon p)
834 {
835 int contains = p.npoints;
836 for(int i = 0; i < p.npoints; ++i)
837 {
838 if(poly.contains(p.xpoints[i],p.ypoints[i])) {
839 --contains;
840 }
841 }
842 if(contains == 0) return 1;
843 if(contains == p.npoints) return 0;
844 return 2;
845 }
846 public void addInner(Polygon p)
847 {
848 if(inner == null) {
849 inner = new ArrayList<Polygon>();
850 }
851 inner.add(p);
852 }
853 public boolean isClosed()
854 {
855 return (poly.npoints >= 3
856 && poly.xpoints[0] == poly.xpoints[poly.npoints-1]
857 && poly.ypoints[0] == poly.ypoints[poly.npoints-1]);
858 }
859 public Polygon get()
860 {
861 if(inner != null)
862 {
863 for (Polygon pp : inner)
864 {
865 for(int i = 0; i < pp.npoints; ++i) {
866 poly.addPoint(pp.xpoints[i],pp.ypoints[i]);
867 }
868 poly.addPoint(p.x,p.y);
869 }
870 inner = null;
871 }
872 return poly;
873 }
874 }
875 void addInnerToOuters(Relation r, boolean incomplete, PolyData pdInner, LinkedList<PolyData> outerPolygons)
876 {
877 Way wInner = pdInner.way;
878 if(wInner != null && !wInner.isClosed())
879 {
880 Point pInner = nc.getPoint(wInner.getNode(0));
881 pdInner.poly.addPoint(pInner.x,pInner.y);
882 }
883 PolyData o = null;
884 for (PolyData pdOuter : outerPolygons)
885 {
886 Integer c = pdOuter.contains(pdInner.poly);
887 if(c >= 1)
888 {
889 if(c > 1 && pdOuter.way != null && pdOuter.way.isClosed())
890 {
891 putError(r, tr("Intersection between ways ''{0}'' and ''{1}''.",
892 pdOuter.way.getDisplayName(DefaultNameFormatter.getInstance()), wInner.getDisplayName(DefaultNameFormatter.getInstance())), true);
893 }
894 if(o == null || o.contains(pdOuter.poly) > 0) {
895 o = pdOuter;
896 }
897 }
898 }
899 if(o == null)
900 {
901 if(!incomplete)
902 {
903 putError(r, tr("Inner way ''{0}'' is outside.",
904 wInner.getDisplayName(DefaultNameFormatter.getInstance())), true);
905 }
906 o = outerPolygons.get(0);
907 }
908 o.addInner(pdInner.poly);
909 }
910
911 public boolean drawMultipolygon(Relation r) {
912 Collection<Way> inner = new LinkedList<Way>();
913 Collection<Way> outer = new LinkedList<Way>();
914 Collection<Way> innerclosed = new LinkedList<Way>();
915 Collection<Way> outerclosed = new LinkedList<Way>();
916 boolean incomplete = false;
917 boolean drawn = false;
918
919 for (RelationMember m : r.getMembers())
920 {
921 if (m.getMember().isDeleted()) {
922 putError(r, tr("Deleted member ''{0}'' in relation.",
923 m.getMember().getDisplayName(DefaultNameFormatter.getInstance())), true);
924 } else if(m.getMember().incomplete) {
925 incomplete = true;
926 } else {
927 if(m.isWay()) {
928 Way w = m.getWay();
929 if(w.getNodesCount() < 2) {
930 putError(r, tr("Way ''{0}'' with less than two points.",
931 w.getDisplayName(DefaultNameFormatter.getInstance())), true);
932 }
933 else if("inner".equals(m.getRole())) {
934 inner.add(w);
935 } else if("outer".equals(m.getRole())) {
936 outer.add(w);
937 } else {
938 putError(r, tr("No useful role ''{0}'' for Way ''{1}''.",
939 m.getRole(), w.getDisplayName(DefaultNameFormatter.getInstance())), true);
940 if(!m.hasRole()) {
941 outer.add(w);
942 } else if(data.isSelected(r)) {
943 drawSelectedMember(m.getMember(), styles != null
944 ? getPrimitiveStyle(m.getMember()) : null, true, true);
945 }
946 }
947 }
948 else
949 {
950 putError(r, tr("Non-Way ''{0}'' in multipolygon.",
951 m.getMember().getDisplayName(DefaultNameFormatter.getInstance())), true);
952 }
953 }
954 }
955
956 ElemStyle wayStyle = styles != null ? getPrimitiveStyle(r) : null;
957 if(styles != null && (wayStyle == null || !(wayStyle instanceof AreaElemStyle)))
958 {
959 for (Way w : outer)
960 {
961 if(wayStyle == null) {
962 wayStyle = styles.getArea(w);
963 }
964 }
965 r.mappaintStyle = wayStyle;
966 }
967
968 if(wayStyle != null && wayStyle instanceof AreaElemStyle)
969 {
970 boolean zoomok = isZoomOk(wayStyle);
971 boolean visible = false;
972 Collection<Way> outerjoin = new LinkedList<Way>();
973 Collection<Way> innerjoin = new LinkedList<Way>();
974
975 drawn = true;
976 for (Way w : outer)
977 {
978 if(w.isClosed()) {
979 outerclosed.add(w);
980 } else {
981 outerjoin.add(w);
982 }
983 }
984 for (Way w : inner)
985 {
986 if(w.isClosed()) {
987 innerclosed.add(w);
988 } else {
989 innerjoin.add(w);
990 }
991 }
992 if(outerclosed.size() == 0 && outerjoin.size() == 0)
993 {
994 putError(r, tr("No outer way for multipolygon ''{0}''.",
995 r.getDisplayName(DefaultNameFormatter.getInstance())), true);
996 visible = true; /* prevent killing remaining ways */
997 }
998 else if(zoomok)
999 {
1000 LinkedList<PolyData> outerPoly = new LinkedList<PolyData>();
1001 for (Way w : outerclosed) {
1002 outerPoly.add(new PolyData(w));
1003 }
1004 outerPoly.addAll(joinWays(outerjoin, incomplete ? null : r));
1005 for (Way wInner : innerclosed)
1006 {
1007 PolyData pdInner = new PolyData(wInner);
1008 // incomplete is probably redundant
1009 addInnerToOuters(r, incomplete, pdInner, outerPoly);
1010 }
1011 for (PolyData pdInner : joinWays(innerjoin, incomplete ? null : r)) {
1012 addInnerToOuters(r, incomplete, pdInner, outerPoly);
1013 }
1014 AreaElemStyle areaStyle = (AreaElemStyle)wayStyle;
1015 for (PolyData pd : outerPoly) {
1016 Polygon p = pd.get();
1017 if(!isPolygonVisible(p)) {
1018 continue;
1019 }
1020
1021 boolean selected = pd.selected || data.isSelected(pd.way) || data.isSelected(r);
1022 drawAreaPolygon(p, selected ? selectedColor : areaStyle.color);
1023 visible = true;
1024 }
1025 }
1026 if(!visible)
1027 return drawn;
1028 for (Way wInner : inner)
1029 {
1030 ElemStyle innerStyle = getPrimitiveStyle(wInner);
1031 if(innerStyle == null)
1032 {
1033 if (data.isSelected(wInner)) {
1034 continue;
1035 }
1036 if(zoomok && (wInner.mappaintDrawnCode != paintid
1037 || outer.size() == 0))
1038 {
1039 drawWay(wInner, ((AreaElemStyle)wayStyle).line,
1040 ((AreaElemStyle)wayStyle).color, data.isSelected(wInner)
1041 || data.isSelected(r));
1042 }
1043 wInner.mappaintDrawnCode = paintid;
1044 }
1045 else
1046 {
1047 if(data.isSelected(r))
1048 {
1049 drawSelectedMember(wInner, innerStyle,
1050 !wayStyle.equals(innerStyle), data.isSelected(wInner));
1051 }
1052 if(wayStyle.equals(innerStyle))
1053 {
1054 putError(r, tr("Style for inner way ''{0}'' equals multipolygon.",
1055 wInner.getDisplayName(DefaultNameFormatter.getInstance())), false);
1056 if(!data.isSelected(r)) {
1057 wInner.mappaintDrawnAreaCode = paintid;
1058 }
1059 }
1060 }
1061 }
1062 for (Way wOuter : outer)
1063 {
1064 ElemStyle outerStyle = getPrimitiveStyle(wOuter);
1065 if(outerStyle == null)
1066 {
1067 // Selected ways are drawn at the very end
1068 if (data.isSelected(wOuter)) {
1069 continue;
1070 }
1071 if(zoomok)
1072 {
1073 drawWay(wOuter, ((AreaElemStyle)wayStyle).line,
1074 ((AreaElemStyle)wayStyle).color, data.isSelected(wOuter)
1075 || data.isSelected(r));
1076 }
1077 wOuter.mappaintDrawnCode = paintid;
1078 }
1079 else
1080 {
1081 if(outerStyle instanceof AreaElemStyle
1082 && !wayStyle.equals(outerStyle))
1083 {
1084 putError(r, tr("Style for outer way ''{0}'' mismatches.",
1085 wOuter.getDisplayName(DefaultNameFormatter.getInstance())), true);
1086 }
1087 if(data.isSelected(r))
1088 {
1089 drawSelectedMember(wOuter, outerStyle, false, false);
1090 }
1091 else if(outerStyle instanceof AreaElemStyle) {
1092 wOuter.mappaintDrawnAreaCode = paintid;
1093 }
1094 }
1095 }
1096 }
1097 return drawn;
1098 }
1099
1100 protected Polygon getPolygon(Way w)
1101 {
1102 Polygon polygon = new Polygon();
1103
1104 for (Node n : w.getNodes())
1105 {
1106 Point p = nc.getPoint(n);
1107 polygon.addPoint(p.x,p.y);
1108 }
1109 return polygon;
1110 }
1111
1112 protected Point2D getCentroid(Polygon p)
1113 {
1114 double cx = 0.0, cy = 0.0, a = 0.0;
1115
1116 // usually requires points[0] == points[npoints] and can then use i+1 instead of j.
1117 // Faked it slowly using j. If this is really gets used, this should be fixed.
1118 for (int i = 0; i < p.npoints; i++) {
1119 int j = i+1 == p.npoints ? 0 : i+1;
1120 a += (p.xpoints[i] * p.ypoints[j]) - (p.ypoints[i] * p.xpoints[j]);
1121 cx += (p.xpoints[i] + p.xpoints[j]) * (p.xpoints[i] * p.ypoints[j] - p.ypoints[i] * p.xpoints[j]);
1122 cy += (p.ypoints[i] + p.ypoints[j]) * (p.xpoints[i] * p.ypoints[j] - p.ypoints[i] * p.xpoints[j]);
1123 }
1124 return new Point2D.Double(cx / (3.0*a), cy / (3.0*a));
1125 }
1126
1127 protected double getArea(Polygon p)
1128 {
1129 double sum = 0.0;
1130
1131 // usually requires points[0] == points[npoints] and can then use i+1 instead of j.
1132 // Faked it slowly using j. If this is really gets used, this should be fixed.
1133 for (int i = 0; i < p.npoints; i++) {
1134 int j = i+1 == p.npoints ? 0 : i+1;
1135 sum = sum + (p.xpoints[i] * p.ypoints[j]) - (p.ypoints[i] * p.xpoints[j]);
1136 }
1137 return Math.abs(sum/2.0);
1138 }
1139
1140 protected void drawArea(Way w, Color color)
1141 {
1142 Polygon polygon = getPolygon(w);
1143
1144 /* set the opacity (alpha) level of the filled polygon */
1145 g.setColor(new Color(color.getRed(), color.getGreen(), color.getBlue(), fillAlpha));
1146 g.fillPolygon(polygon);
1147
1148 if (showNames > dist) {
1149 String name = getWayName(w);
1150 if (name!=null /* && annotate */) {
1151 Rectangle pb = polygon.getBounds();
1152 FontMetrics fontMetrics = g.getFontMetrics(orderFont); // if slow, use cache
1153 Rectangle2D nb = fontMetrics.getStringBounds(name, g); // if slow, approximate by strlen()*maxcharbounds(font)
1154
1155 // Point2D c = getCentroid(polygon);
1156 // Using the Centroid is Nicer for buildings like: +--------+
1157 // but this needs to be fast. As most houses are | 42 |
1158 // boxes anyway, the center of the bounding box +---++---+
1159 // will have to do. ++
1160 // Centroids are not optimal either, just imagine a U-shaped house.
1161 // Point2D c = new Point2D.Double(pb.x + pb.width / 2.0, pb.y + pb.height / 2.0);
1162 // Rectangle2D.Double centeredNBounds =
1163 // new Rectangle2D.Double(c.getX() - nb.getWidth()/2,
1164 // c.getY() - nb.getHeight()/2,
1165 // nb.getWidth(),
1166 // nb.getHeight());
1167
1168 Rectangle centeredNBounds = new Rectangle(pb.x + (int)((pb.width - nb.getWidth())/2.0),
1169 pb.y + (int)((pb.height - nb.getHeight())/2.0),
1170 (int)nb.getWidth(),
1171 (int)nb.getHeight());
1172
1173 //// Draw name bounding box for debugging:
1174 // g.setColor(new Color(255,255,0,128));
1175 // g.drawRect((int)centeredNBounds.getMinX(),
1176 // (int)centeredNBounds.getMinY(),
1177 // (int)centeredNBounds.getWidth(),
1178 // (int)centeredNBounds.getHeight());
1179
1180 if ((pb.width >= nb.getWidth() && pb.height >= nb.getHeight()) && // quick check
1181 polygon.contains(centeredNBounds) // slow but nice
1182 ) {
1183 g.setColor(areaTextColor);
1184 Font defaultFont = g.getFont();
1185 g.setFont (orderFont);
1186 g.drawString (name,
1187 (int)(centeredNBounds.getMinX() - nb.getMinX()),
1188 (int)(centeredNBounds.getMinY() - nb.getMinY()));
1189 g.setFont(defaultFont);
1190 }
1191 }
1192 }
1193 }
1194
1195 protected String getWayName(Way w) {
1196 String name = null;
1197 if (w.hasKeys()) {
1198 for (String rn : regionalNameOrder) {
1199 name = w.get(rn);
1200 if (name != null) {
1201 break;
1202 }
1203 }
1204 }
1205 return name;
1206 }
1207
1208 protected void drawAreaPolygon(Polygon polygon, Color color)
1209 {
1210 /* set the opacity (alpha) level of the filled polygon */
1211 g.setColor(new Color(color.getRed(), color.getGreen(), color.getBlue(), fillAlpha));
1212 g.fillPolygon(polygon);
1213 }
1214
1215 protected void drawNode(Node n, ImageIcon icon, boolean annotate, boolean selected) {
1216 Point p = nc.getPoint(n);
1217 if ((p.x < 0) || (p.y < 0) || (p.x > nc.getWidth()) || (p.y > nc.getHeight())) return;
1218
1219 //profilerVisibleNodes++;
1220
1221 int w = icon.getIconWidth(), h=icon.getIconHeight();
1222 icon.paintIcon ( Main.map.mapView, g, p.x-w/2, p.y-h/2 );
1223 if(showNames > dist)
1224 {
1225 String name = getNodeName(n);
1226 if (name!=null && annotate)
1227 {
1228 if (inactive || n.isDisabled()) {
1229 g.setColor(inactiveColor);
1230 } else {
1231 g.setColor(textColor);
1232 }
1233 Font defaultFont = g.getFont();
1234 g.setFont (orderFont);
1235 g.drawString (name, p.x+w/2+2, p.y+h/2+2);
1236 g.setFont(defaultFont);
1237 }
1238 }
1239 if (selected)
1240 {
1241 g.setColor ( selectedColor );
1242 g.drawRect (p.x-w/2-2, p.y-h/2-2, w+4, h+4);
1243 }
1244 }
1245
1246 protected String getNodeName(Node n) {
1247 String name = null;
1248 if (n.hasKeys()) {
1249 for (String rn : regionalNameOrder) {
1250 name = n.get(rn);
1251 if (name != null) {
1252 break;
1253 }
1254 }
1255 }
1256 return name;
1257 }
1258
1259 private void drawSeg(Node n1, Node n2, Color col, boolean showDirection, int width, float dashed[], Color dashedColor) {
1260 //profilerSegments++;
1261 if (col != currentColor || width != currentWidth || !Arrays.equals(dashed,currentDashed) || dashedColor != currentDashedColor) {
1262 displaySegments(col, width, dashed, dashedColor);
1263 }
1264 Point p1 = nc.getPoint(n1);
1265 Point p2 = nc.getPoint(n2);
1266
1267 if (!isSegmentVisible(p1, p2))
1268 return;
1269 //profilerVisibleSegments++;
1270 currentPath.moveTo(p1.x, p1.y);
1271 currentPath.lineTo(p2.x, p2.y);
1272
1273 if (showDirection) {
1274 double t = Math.atan2(p2.y-p1.y, p2.x-p1.x) + Math.PI;
1275 currentPath.lineTo((int)(p2.x + 10*Math.cos(t-PHI)), (int)(p2.y + 10*Math.sin(t-PHI)));
1276 currentPath.moveTo((int)(p2.x + 10*Math.cos(t+PHI)), (int)(p2.y + 10*Math.sin(t+PHI)));
1277 currentPath.lineTo(p2.x, p2.y);
1278 }
1279 }
1280
1281 @Override
1282 protected void displaySegments() {
1283 displaySegments(null, 0, new float[0], null);
1284 }
1285
1286 protected void displaySegments(Color newColor, int newWidth, float newDash[], Color newDashedColor) {
1287 if (currentPath != null) {
1288 Graphics2D g2d = (Graphics2D)g;
1289 g2d.setColor(inactive ? inactiveColor : currentColor);
1290 if (currentStroke == null && useStrokes > dist) {
1291 if (currentDashed.length > 0) {
1292 try {
1293 g2d.setStroke(new BasicStroke(currentWidth,BasicStroke.CAP_BUTT,BasicStroke.JOIN_ROUND,0,currentDashed,0));
1294 } catch (IllegalArgumentException e) {
1295 g2d.setStroke(new BasicStroke(currentWidth,BasicStroke.CAP_ROUND,BasicStroke.JOIN_ROUND));
1296 }
1297 } else {
1298 g2d.setStroke(new BasicStroke(currentWidth,BasicStroke.CAP_ROUND,BasicStroke.JOIN_ROUND));
1299 }
1300 }
1301 g2d.draw(currentPath);
1302
1303 if(currentDashedColor != null) {
1304 g2d.setColor(currentDashedColor);
1305 if (currentStroke == null && useStrokes > dist) {
1306 if (currentDashed.length > 0) {
1307 float[] currentDashedOffset = new float[currentDashed.length];
1308 System.arraycopy(currentDashed, 1, currentDashedOffset, 0, currentDashed.length - 1);
1309 currentDashedOffset[currentDashed.length-1] = currentDashed[0];
1310 float offset = currentDashedOffset[0];
1311 try {
1312 g2d.setStroke(new BasicStroke(currentWidth,BasicStroke.CAP_BUTT,BasicStroke.JOIN_ROUND,0,currentDashedOffset,offset));
1313 } catch (IllegalArgumentException e) {
1314 g2d.setStroke(new BasicStroke(currentWidth,BasicStroke.CAP_ROUND,BasicStroke.JOIN_ROUND));
1315 }
1316 } else {
1317 g2d.setStroke(new BasicStroke(currentWidth,BasicStroke.CAP_ROUND,BasicStroke.JOIN_ROUND));
1318 }
1319 }
1320 g2d.draw(currentPath);
1321 }
1322
1323 if(useStrokes > dist) {
1324 g2d.setStroke(new BasicStroke(1));
1325 }
1326
1327 currentPath = new GeneralPath();
1328 currentColor = newColor;
1329 currentWidth = newWidth;
1330 currentDashed = newDash;
1331 currentDashedColor = newDashedColor;
1332 currentStroke = null;
1333 }
1334 }
1335
1336 /**
1337 * Draw the node as small rectangle with the given color.
1338 *
1339 * @param n The node to draw.
1340 * @param color The color of the node.
1341 */
1342 @Override
1343 public void drawNode(Node n, Color color, int size, int radius, boolean fill) {
1344 if (isZoomOk(null) && size > 1) {
1345 Point p = nc.getPoint(n);
1346 if ((p.x < 0) || (p.y < 0) || (p.x > nc.getWidth())
1347 || (p.y > nc.getHeight()))
1348 return;
1349
1350 //profilerVisibleNodes++;
1351
1352 if (inactive || n.isDisabled()) {
1353 g.setColor(inactiveColor);
1354 } else {
1355 g.setColor(color);
1356 }
1357 if (fill) {
1358 g.fillRect(p.x - radius, p.y - radius, size, size);
1359 g.drawRect(p.x - radius, p.y - radius, size, size);
1360 } else {
1361 g.drawRect(p.x - radius, p.y - radius, size, size);
1362 }
1363
1364 if(showNames > dist)
1365 {
1366 String name = getNodeName(n);
1367 if (name!=null /* && annotate */)
1368 {
1369 if (inactive || n.isDisabled()) {
1370 g.setColor(inactiveColor);
1371 } else {
1372 g.setColor(textColor);
1373 }
1374 Font defaultFont = g.getFont();
1375 g.setFont (orderFont);
1376 g.drawString (name, p.x+radius+2, p.y+radius+2);
1377 g.setFont(defaultFont);
1378 }
1379 }
1380 }
1381 }
1382
1383 boolean drawable(OsmPrimitive osm)
1384 {
1385 return !osm.isDeleted() && !osm.isFiltered() && !osm.incomplete;
1386 }
1387
1388 @Override
1389 public void getColors()
1390 {
1391 super.getColors();
1392 untaggedColor = Main.pref.getColor(marktr("untagged"),Color.GRAY);
1393 textColor = Main.pref.getColor (marktr("text"), Color.WHITE);
1394 areaTextColor = Main.pref.getColor (marktr("areatext"), Color.LIGHT_GRAY);
1395 }
1396
1397 DataSet data;
1398
1399 <T extends OsmPrimitive> Collection<T> selectedLast(final DataSet data, Collection <T> prims) {
1400 ArrayList<T> sorted = new ArrayList<T>(prims);
1401 Collections.sort(sorted,
1402 new Comparator<T>() {
1403 public int compare(T o1, T o2) {
1404 boolean s1 = data.isSelected(o1);
1405 boolean s2 = data.isSelected(o2);
1406 if (s1 && !s2)
1407 return 1;
1408 if (!s1 && s2)
1409 return -1;
1410 return o1.compareTo(o2);
1411 }
1412 });
1413 return sorted;
1414 }
1415
1416 /* Shows areas before non-areas */
1417 @Override
1418 public void visitAll(DataSet data, boolean virtual, Bounds bounds) {
1419 BBox bbox = new BBox(bounds);
1420 this.data = data;
1421 //boolean profiler = Main.pref.getBoolean("mappaint.profiler",false);
1422 //profilerOmitDraw = Main.pref.getBoolean("mappaint.profiler.omitdraw",false);
1423
1424 useStyleCache = Main.pref.getBoolean("mappaint.cache", true);
1425 int fillAreas = Main.pref.getInteger("mappaint.fillareas", 10000000);
1426 fillAlpha = Math.min(255, Math.max(0, Integer.valueOf(Main.pref.getInteger("mappaint.fillalpha", 50))));
1427 showNames = Main.pref.getInteger("mappaint.shownames", 10000000);
1428 showIcons = Main.pref.getInteger("mappaint.showicons", 10000000);
1429 useStrokes = Main.pref.getInteger("mappaint.strokes", 10000000);
1430 LatLon ll1 = nc.getLatLon(0, 0);
1431 LatLon ll2 = nc.getLatLon(100, 0);
1432 dist = ll1.greatCircleDistance(ll2);
1433
1434 //long profilerStart = java.lang.System.currentTimeMillis();
1435 //long profilerLast = profilerStart;
1436 //int profilerN;
1437 //if(profiler)
1438 // System.out.println("Mappaint Profiler (" +
1439 // (useStyleCache ? "cache=true, " : "cache=false, ") +
1440 // "fillareas " + fillAreas + ", " +
1441 // "fillalpha=" + fillAlpha + "%, " +
1442 // "dist=" + (int)dist + "m)");
1443
1444 getSettings(virtual);
1445 useRealWidth = Main.pref.getBoolean("mappaint.useRealWidth", false);
1446 zoomLevelDisplay = Main.pref.getBoolean("mappaint.zoomLevelDisplay", false);
1447 circum = Main.map.mapView.getDist100Pixel();
1448 styles = MapPaintStyles.getStyles().getStyleSet();
1449 drawMultipolygon = Main.pref.getBoolean("mappaint.multipolygon", true);
1450 drawRestriction = Main.pref.getBoolean("mappaint.restriction", true);
1451 //restrictionDebug = Main.pref.getBoolean("mappaint.restriction.debug",false);
1452 leftHandTraffic = Main.pref.getBoolean("mappaint.lefthandtraffic", false);
1453 orderFont = new Font(Main.pref.get("mappaint.font", "Helvetica"), Font.PLAIN, Main.pref.getInteger("mappaint.fontsize", 8));
1454 String[] names = {"name:" + LanguageInfo.getJOSMLocaleCode(), "name", "int_name", "ref", "operator", "brand", "addr:housenumber"};
1455 regionalNameOrder = Main.pref.getCollection("mappaint.nameOrder", Arrays.asList(names));
1456 minEN = nc.getEastNorth(0, nc.getHeight() - 1);
1457 maxEN = nc.getEastNorth(nc.getWidth() - 1, 0);
1458
1459 data.clearErrors();
1460
1461 ++paintid;
1462
1463 //profilerVisibleNodes = 0;
1464 //profilerVisibleWays = 0;
1465 //profilerVisibleAreas = 0;
1466 //profilerSegments = 0;
1467 //profilerVisibleSegments = 0;
1468
1469 //if(profiler)
1470 //{
1471 // System.out.format("Prepare : %5dms\n", (java.lang.System.currentTimeMillis()-profilerLast));
1472 // profilerLast = java.lang.System.currentTimeMillis();
1473 //}
1474
1475 if (fillAreas > dist && styles != null && styles.hasAreas()) {
1476 Collection<Way> noAreaWays = new LinkedList<Way>();
1477
1478 /*** RELATIONS ***/
1479 // profilerN = 0;
1480 for (final Relation osm: data.getRelations()) {
1481 if (drawable(osm)) {
1482 paintUnselectedRelation(osm);
1483 // profilerN++;
1484 }
1485 }
1486
1487 // if(profiler)
1488 // {
1489 // System.out.format("Relations: %5dms, calls=%7d\n", (java.lang.System.currentTimeMillis()-profilerLast), profilerN);
1490 // profilerLast = java.lang.System.currentTimeMillis();
1491 // }
1492
1493 /*** AREAS ***/
1494 // profilerN = 0;
1495 for (final Way osm : selectedLast(data, data.searchWays(bbox))) {
1496 if (drawable(osm) && osm.mappaintDrawnCode != paintid) {
1497 if (isPrimitiveArea(osm) && osm.mappaintDrawnAreaCode != paintid) {
1498 drawWay(osm, fillAreas);
1499 // profilerN++;
1500 }// else {
1501 noAreaWays.add(osm);
1502 //}
1503 }
1504 }
1505
1506 // if(profiler)
1507 // {
1508 // System.out.format("Areas : %5dms, calls=%7d, visible=%d\n",
1509 // (java.lang.System.currentTimeMillis()-profilerLast), profilerN, profilerVisibleAreas);
1510 // profilerLast = java.lang.System.currentTimeMillis();
1511 // }
1512
1513 /*** WAYS ***/
1514 // profilerN = 0;
1515 for (final Way osm : noAreaWays) {
1516 drawWay(osm, 0);
1517 // profilerN++;
1518 }
1519
1520 // if(profiler)
1521 // {
1522 // System.out.format("Ways : %5dms, calls=%7d, visible=%d\n",
1523 // (java.lang.System.currentTimeMillis()-profilerLast), profilerN, profilerVisibleWays);
1524 // profilerLast = java.lang.System.currentTimeMillis();
1525 // }
1526 } else {
1527 /*** WAYS (filling disabled) ***/
1528 // profilerN = 0;
1529 for (final Way way: data.getWays()) {
1530 if (drawable(way) && !data.isSelected(way)) {
1531 drawWay(way, 0);
1532 // profilerN++;
1533 }
1534 }
1535
1536 // if(profiler)
1537 // {
1538 // System.out.format("Ways : %5dms, calls=%7d, visible=%d\n",
1539 // (java.lang.System.currentTimeMillis()-profilerLast), profilerN, profilerVisibleWays);
1540 // profilerLast = java.lang.System.currentTimeMillis();
1541 // }
1542 }
1543
1544 /*** SELECTED ***/
1545 //profilerN = 0;
1546 for (final OsmPrimitive osm : data.getSelected()) {
1547 if (!osm.incomplete && !osm.isDeleted() && !(osm instanceof Node)
1548 && osm.mappaintDrawnCode != paintid
1549 ) {
1550 osm.visit(new AbstractVisitor() {
1551 public void visit(Way w) {
1552 drawWay(w, 0);
1553 }
1554
1555 public void visit(Node n) {
1556 drawNode(n);
1557 }
1558
1559 public void visit(Relation r) {
1560 /* TODO: is it possible to do this like the nodes/ways code? */
1561 //if(profilerOmitDraw)
1562 // return;
1563 for (RelationMember m : r.getMembers()) {
1564 if (m.isNode() && drawable(m.getMember())) {
1565 drawSelectedMember(m.getMember(), styles != null ? getPrimitiveStyle(m.getMember()) : null, true, true);
1566 }
1567 }
1568 }
1569 });
1570 // profilerN++;
1571 }
1572 }
1573
1574 //if(profiler)
1575 //{
1576 // System.out.format("Selected : %5dms, calls=%7d\n", (java.lang.System.currentTimeMillis()-profilerLast), profilerN);
1577 // profilerLast = java.lang.System.currentTimeMillis();
1578 //}
1579
1580 /*** DISPLAY CACHED SEGMENTS (WAYS) NOW ***/
1581 displaySegments();
1582
1583 /*** NODES ***/
1584 //profilerN = 0;
1585 for (final Node osm: data.searchNodes(bbox)) {
1586 if (!osm.incomplete && !osm.isDeleted() && (data.isSelected(osm) || !osm.isFiltered())
1587 && osm.mappaintDrawnCode != paintid)
1588 {
1589 drawNode(osm);
1590 // profilerN++;
1591 }
1592 }
1593
1594 //if(profiler)
1595 //{
1596 // System.out.format("Nodes : %5dms, calls=%7d, visible=%d\n",
1597 // (java.lang.System.currentTimeMillis()-profilerLast), profilerN, profilerVisibleNodes);
1598 // profilerLast = java.lang.System.currentTimeMillis();
1599 //}
1600
1601 /*** VIRTUAL ***/
1602 if (virtualNodeSize != 0) {
1603 // profilerN = 0;
1604 currentColor = nodeColor;
1605 for (final OsmPrimitive osm: data.searchWays(bbox)) {
1606 if (osm.isUsable() && !osm.isFiltered())
1607 {
1608 /* TODO: move this into the SimplePaint code? */
1609 // if(!profilerOmitDraw)
1610 visitVirtual((Way)osm);
1611 // profilerN++;
1612 }
1613 }
1614
1615 // if(profiler)
1616 // {
1617 // System.out.format("Virtual : %5dms, calls=%7d\n", (java.lang.System.currentTimeMillis()-profilerLast), profilerN);
1618 // profilerLast = java.lang.System.currentTimeMillis();
1619 // }
1620
1621 displaySegments(null);
1622 }
1623
1624 //if(profiler)
1625 //{
1626 // System.out.format("Segments : calls=%7d, visible=%d\n", profilerSegments, profilerVisibleSegments);
1627 // System.out.format("All : %5dms\n", (profilerLast-profilerStart));
1628 //}
1629 }
1630
1631 /**
1632 * Draw a number of the order of the two consecutive nodes within the
1633 * parents way
1634 */
1635 protected void drawOrderNumber(Node n1, Node n2, int orderNumber) {
1636 Point p1 = nc.getPoint(n1);
1637 Point p2 = nc.getPoint(n2);
1638 drawOrderNumber(p1, p2, orderNumber);
1639 }
1640
1641 public void putError(OsmPrimitive p, String text, boolean isError)
1642 {
1643 data.addError(p, isError ? tr("Error: {0}", text) : tr("Warning: {0}", text));
1644 }
1645}
Note: See TracBrowser for help on using the repository browser.