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

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