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

Last change on this file since 1071 was 1019, checked in by stoecker, 16 years ago

allow localized name display. close #1586

  • Property svn:eol-style set to native
File size: 11.2 KB
Line 
1// License: GPL. Copyright 2007 by Immanuel Scholz and others
2package org.openstreetmap.josm.data.osm.visitor;
3
4import static org.openstreetmap.josm.tools.I18n.marktr;
5
6import java.awt.BasicStroke;
7import java.awt.Color;
8import java.awt.Font;
9import java.awt.Graphics2D;
10import java.awt.Point;
11import java.awt.Polygon;
12import java.awt.Stroke;
13import java.awt.geom.GeneralPath;
14import java.util.Collection;
15import java.util.LinkedList;
16import java.util.Locale;
17
18import javax.swing.ImageIcon;
19
20import org.openstreetmap.josm.Main;
21import org.openstreetmap.josm.data.osm.DataSet;
22import org.openstreetmap.josm.data.osm.Node;
23import org.openstreetmap.josm.data.osm.OsmPrimitive;
24import org.openstreetmap.josm.data.osm.Relation;
25import org.openstreetmap.josm.data.osm.Way;
26import org.openstreetmap.josm.data.osm.visitor.SimplePaintVisitor;
27import org.openstreetmap.josm.gui.mappaint.AreaElemStyle;
28import org.openstreetmap.josm.gui.mappaint.ElemStyle;
29import org.openstreetmap.josm.gui.mappaint.ElemStyles;
30import org.openstreetmap.josm.gui.mappaint.IconElemStyle;
31import org.openstreetmap.josm.gui.mappaint.LineElemStyle;
32import org.openstreetmap.josm.gui.mappaint.MapPaintStyles;
33
34public class MapPaintVisitor extends SimplePaintVisitor {
35 protected boolean useRealWidth;
36 protected boolean zoomLevelDisplay;
37 protected boolean fillAreas;
38 protected int fillAlpha;
39 protected Color untaggedColor;
40 protected Color textColor;
41 protected boolean currentDashed = false;
42 protected int currentWidth = 0;
43 protected Stroke currentStroke = null;
44 protected Font orderFont;
45 protected ElemStyles styles;
46 protected double circum;
47 protected String regionalNameOrder[];
48
49 protected boolean isZoomOk(ElemStyle e) {
50 if (!zoomLevelDisplay) /* show everything if the user wishes so */
51 return true;
52
53 if(e == null) /* the default for things that don't have a rule (show, if scale is smaller than 1500m) */
54 return (circum < 1500);
55
56 // formula to calculate a map scale: natural size / map size = scale
57 // example: 876000mm (876m as displayed) / 22mm (roughly estimated screen size of legend bar) = 39818
58 //
59 // so the exact "correcting value" below depends only on the screen size and resolution
60 // XXX - do we need a Preference setting for this (if things vary widely)?
61 return !(circum >= e.maxScale / 22 || circum < e.minScale / 22);
62 }
63
64 /**
65 * Draw a small rectangle.
66 * White if selected (as always) or red otherwise.
67 *
68 * @param n The node to draw.
69 */
70 public void visit(Node n) {
71 IconElemStyle nodeStyle = styles.get(n);
72 if (nodeStyle != null && isZoomOk(nodeStyle))
73 drawNode(n, nodeStyle.icon, nodeStyle.annotate);
74 else if (n.selected)
75 drawNode(n, selectedColor, selectedNodeSize, selectedNodeRadius, fillSelectedNode);
76 else if (n.tagged)
77 drawNode(n, nodeColor, taggedNodeSize, taggedNodeRadius, fillUnselectedNode);
78 else
79 drawNode(n, nodeColor, unselectedNodeSize, unselectedNodeRadius, fillUnselectedNode);
80 }
81
82 /**
83 * Draw a line for all segments, according to tags.
84 * @param w The way to draw.
85 */
86 public void visit(Way w) {
87 if(w.nodes.size() < 2)
88 return;
89 // show direction arrows, if draw.segment.relevant_directions_only is not set, the way is tagged with a direction key
90 // (even if the tag is negated as in oneway=false) or the way is selected
91 boolean showDirection = w.selected || ((!useRealWidth) && (showDirectionArrow
92 && (!showRelevantDirectionsOnly || w.hasDirectionKeys)));
93
94 Color color = untaggedColor;
95 int width = defaultSegmentWidth;
96 int realWidth = 0; //the real width of the element in meters
97 boolean dashed = false;
98 ElemStyle wayStyle = styles.get(w);
99
100 if(!isZoomOk(wayStyle))
101 return;
102
103 LineElemStyle l = null;
104 if(wayStyle!=null)
105 {
106 Color areacolor = untaggedColor;
107 boolean area = false;
108 if(wayStyle instanceof LineElemStyle)
109 l = (LineElemStyle)wayStyle;
110 else if (wayStyle instanceof AreaElemStyle)
111 {
112 areacolor = ((AreaElemStyle)wayStyle).color;
113 color = areacolor;
114 l = ((AreaElemStyle)wayStyle).line;
115 area = true;
116 }
117 if(l != null)
118 {
119 color = l.color;
120 width = l.width;
121 realWidth = l.realWidth;
122 dashed = l.dashed;
123 }
124 if (area && fillAreas)
125 drawWayAsArea(w, areacolor);
126 }
127
128 if (realWidth > 0 && useRealWidth && !showDirection)
129 {
130 int tmpWidth = (int) (100 / (float) (circum / realWidth));
131 if (tmpWidth > width) width = tmpWidth;
132 }
133 if(w.selected)
134 color = selectedColor;
135
136 Node lastN;
137 if(l != null && l.overlays != null)
138 {
139 for(LineElemStyle s : l.overlays)
140 {
141 if(!s.over)
142 {
143 lastN = null;
144 for(Node n : w.nodes)
145 {
146 if(lastN != null)
147 {
148 drawSeg(lastN, n, s.color != null && !w.selected ? s.color : color,
149 false, s.getWidth(width), s.dashed);
150 }
151 lastN = n;
152 }
153 }
154 }
155 }
156
157 lastN = null;
158 for(Node n : w.nodes)
159 {
160 if(lastN != null)
161 drawSeg(lastN, n, color, showDirection, width, dashed);
162 lastN = n;
163 }
164
165 if(l != null && l.overlays != null)
166 {
167 for(LineElemStyle s : l.overlays)
168 {
169 if(s.over)
170 {
171 lastN = null;
172 for(Node n : w.nodes)
173 {
174 if(lastN != null)
175 {
176 drawSeg(lastN, n, s.color != null && !w.selected ? s.color : color,
177 false, s.getWidth(width), s.dashed);
178 }
179 lastN = n;
180 }
181 }
182 }
183 }
184
185 if(showOrderNumber)
186 {
187 int orderNumber = 0;
188 lastN = null;
189 for(Node n : w.nodes)
190 {
191 if(lastN != null)
192 {
193 orderNumber++;
194 drawOrderNumber(lastN, n, orderNumber);
195 }
196 lastN = n;
197 }
198 }
199 displaySegments();
200 }
201
202 public void visit(Relation e) {
203 // relations are not (yet?) drawn.
204 }
205
206 // This assumes that all segments are aligned in the same direction!
207 protected void drawWayAsArea(Way w, Color color)
208 {
209 Polygon polygon = new Polygon();
210
211 for (Node n : w.nodes)
212 {
213 Point p = nc.getPoint(n.eastNorth);
214 polygon.addPoint(p.x,p.y);
215 }
216
217 Color mycolor = w.selected ? selectedColor : color;
218 // set the opacity (alpha) level of the filled polygon
219 g.setColor(new Color( mycolor.getRed(), mycolor.getGreen(), mycolor.getBlue(), fillAlpha));
220
221 g.fillPolygon(polygon);
222 }
223
224 // NEW
225 protected void drawNode(Node n, ImageIcon icon, boolean annotate) {
226 Point p = nc.getPoint(n.eastNorth);
227 if ((p.x < 0) || (p.y < 0) || (p.x > nc.getWidth()) || (p.y > nc.getHeight())) return;
228 int w = icon.getIconWidth(), h=icon.getIconHeight();
229 icon.paintIcon ( Main.map.mapView, g, p.x-w/2, p.y-h/2 );
230 String name = getNodeName(n);
231 if (name!=null && annotate)
232 {
233 g.setColor(textColor);
234 Font defaultFont = g.getFont();
235 g.setFont (orderFont);
236 g.drawString (name, p.x+w/2+2, p.y+h/2+2);
237 g.setFont(defaultFont);
238 }
239 if (n.selected)
240 {
241 g.setColor ( selectedColor );
242 g.drawRect (p.x-w/2-2,p.y-w/2-2, w+4, h+4);
243 }
244 }
245
246 protected String getNodeName(Node n) {
247 String name = null;
248 if (n.keys != null) {
249 for (int i = 0; i < regionalNameOrder.length; i++) {
250 name = n.keys.get(regionalNameOrder[i]);
251 if (name != null) break;
252 }
253 }
254 return name;
255 }
256
257 private void drawSeg(Node n1, Node n2, Color col, boolean showDirection, int width, boolean dashed) {
258 if (col != currentColor || width != currentWidth || dashed != currentDashed) {
259 displaySegments(col, width, dashed);
260 }
261 Point p1 = nc.getPoint(n1.eastNorth);
262 Point p2 = nc.getPoint(n2.eastNorth);
263
264 if (!isSegmentVisible(p1, p2)) {
265 return;
266 }
267 currentPath.moveTo(p1.x, p1.y);
268 currentPath.lineTo(p2.x, p2.y);
269
270 if (showDirection) {
271 double t = Math.atan2(p2.y-p1.y, p2.x-p1.x) + Math.PI;
272 currentPath.lineTo((int)(p2.x + 10*Math.cos(t-PHI)), (int)(p2.y + 10*Math.sin(t-PHI)));
273 currentPath.moveTo((int)(p2.x + 10*Math.cos(t+PHI)), (int)(p2.y + 10*Math.sin(t+PHI)));
274 currentPath.lineTo(p2.x, p2.y);
275 }
276 }
277
278 protected void displaySegments() {
279 displaySegments(null, 0, false);
280 }
281
282 protected void displaySegments(Color newColor, int newWidth, boolean newDash) {
283 if (currentPath != null) {
284 Graphics2D g2d = (Graphics2D)g;
285 g2d.setColor(inactive ? inactiveColor : currentColor);
286 if (currentStroke == null) {
287 if (currentDashed)
288 g2d.setStroke(new BasicStroke(currentWidth,BasicStroke.CAP_BUTT,BasicStroke.JOIN_ROUND,0,new float[] {9},0));
289 else
290 g2d.setStroke(new BasicStroke(currentWidth,BasicStroke.CAP_ROUND,BasicStroke.JOIN_ROUND));
291 }
292 g2d.draw(currentPath);
293 g2d.setStroke(new BasicStroke(1));
294
295 currentPath = new GeneralPath();
296 currentColor = newColor;
297 currentWidth = newWidth;
298 currentDashed = newDash;
299 currentStroke = null;
300 }
301 }
302
303 /**
304 * Draw the node as small rectangle with the given color.
305 *
306 * @param n The node to draw.
307 * @param color The color of the node.
308 */
309 public void drawNode(Node n, Color color, int size, int radius, boolean fill) {
310 if (isZoomOk(null) && size > 1) {
311 Point p = nc.getPoint(n.eastNorth);
312 if ((p.x < 0) || (p.y < 0) || (p.x > nc.getWidth())
313 || (p.y > nc.getHeight()))
314 return;
315 g.setColor(color);
316 if (fill) {
317 g.fillRect(p.x - radius, p.y - radius, size, size);
318 g.drawRect(p.x - radius, p.y - radius, size, size);
319 } else
320 g.drawRect(p.x - radius, p.y - radius, size, size);
321 }
322 }
323
324 // NW 111106 Overridden from SimplePaintVisitor in josm-1.4-nw1
325 // Shows areas before non-areas
326 public void visitAll(DataSet data, Boolean virtual) {
327 getSettings(virtual);
328 untaggedColor = Main.pref.getColor(marktr("untagged"),Color.GRAY);
329 textColor = Main.pref.getColor (marktr("text"), Color.WHITE);
330 useRealWidth = Main.pref.getBoolean("mappaint.useRealWidth",false);
331 zoomLevelDisplay = Main.pref.getBoolean("mappaint.zoomLevelDisplay",false);
332 fillAreas = Main.pref.getBoolean("mappaint.fillareas", true);
333 fillAlpha = Math.min(255, Math.max(0, Integer.valueOf(Main.pref.getInteger("mappaint.fillalpha", 50))));
334 circum = Main.map.mapView.getScale()*100*Main.proj.scaleFactor()*40041455; // circumference of the earth in meter
335 styles = MapPaintStyles.getStyles();
336 orderFont = new Font(Main.pref.get("mappaint.font","Helvetica"), Font.PLAIN, Main.pref.getInteger("mappaint.fontsize", 8));
337 String currentLocale = Locale.getDefault().getLanguage();
338 regionalNameOrder = Main.pref.get("mappaint.nameOrder", "name:"+currentLocale+";name;int_name").split(";");
339
340 if(styles.hasAreas())
341 {
342 Collection<Way> noAreaWays = new LinkedList<Way>();
343
344 for (final OsmPrimitive osm : data.ways)
345 if (!osm.incomplete && !osm.deleted && styles.isArea((Way)osm))
346 osm.visit(this);
347 else if (!osm.deleted && !osm.incomplete)
348 noAreaWays.add((Way)osm);
349
350 for (final OsmPrimitive osm : noAreaWays)
351 osm.visit(this);
352 }
353 else
354 {
355 for (final OsmPrimitive osm : data.ways)
356 if (!osm.incomplete && !osm.deleted)
357 osm.visit(this);
358 }
359
360 for (final OsmPrimitive osm : data.getSelected())
361 if (!osm.incomplete && !osm.deleted){
362 osm.visit(this);
363 }
364
365 displaySegments();
366
367 for (final OsmPrimitive osm : data.nodes)
368 if (!osm.incomplete && !osm.deleted)
369 osm.visit(this);
370
371 if(virtualNodeSize != 0)
372 {
373 currentColor = nodeColor;
374 for (final OsmPrimitive osm : data.ways)
375 if (!osm.deleted)
376 visitVirtual((Way)osm);
377 displaySegments(null);
378 }
379 }
380
381 /**
382 * Draw a number of the order of the two consecutive nodes within the
383 * parents way
384 */
385 protected void drawOrderNumber(Node n1, Node n2, int orderNumber) {
386 Point p1 = nc.getPoint(n1.eastNorth);
387 Point p2 = nc.getPoint(n2.eastNorth);
388 drawOrderNumber(p1, p2, orderNumber);
389 }
390}
Note: See TracBrowser for help on using the repository browser.