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

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

Minor fixes in mappaint code

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