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

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

fixed line style problem with segment numbers

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