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

Last change on this file since 2392 was 2392, checked in by bastiK, 15 years ago

Objects on inactive osm-layers should be painted in a shade of gray.
(The same goes for filtered / deactivated primitives.)

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