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

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

close bug #1588, code cleanup by bruce89

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