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

Last change on this file since 2590 was 2590, checked in by jttt, 14 years ago

Fix #4114 NPE when zooming out while relation editor is open

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