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

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

fixed area border display

  • Property svn:eol-style set to native
File size: 11.1 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 || virtualNodeSize != 0)
160 drawSeg(lastN, n, selectedColor, showDirection, width, false, false);
161 }
162 else
163 drawSeg(lastN, n, untaggedColor, showDirection, width, dashed, true);
164 }
165 else
166 drawSeg(lastN, n, w.selected ? selectedColor : colour, showDirection, width, true, 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 drawVirtualNode(p1, p2, col);
247 if(drawway)
248 {
249 currentPath.moveTo(p1.x, p1.y);
250 currentPath.lineTo(p2.x, p2.y);
251 }
252
253 if (showDirection) {
254 double t = Math.atan2(p2.y-p1.y, p2.x-p1.x) + Math.PI;
255 if(!drawway)
256 currentPath.moveTo(p2.x, p2.y);
257 currentPath.lineTo((int)(p2.x + 10*Math.cos(t-PHI)), (int)(p2.y + 10*Math.sin(t-PHI)));
258 currentPath.moveTo((int)(p2.x + 10*Math.cos(t+PHI)), (int)(p2.y + 10*Math.sin(t+PHI)));
259 currentPath.lineTo(p2.x, p2.y);
260 }
261 }
262
263 protected void displaySegments() {
264 displaySegments(null, 0, false);
265 }
266
267 protected void displaySegments(Color newColor, int newWidth, boolean newDash) {
268
269 if (currentPath != null) {
270 Graphics2D g2d = (Graphics2D)g;
271 g2d.setColor(inactive ? inactiveColor : currentColor);
272 if (currentStroke == null) {
273 if (currentDashed)
274 g2d.setStroke(new BasicStroke(currentWidth,BasicStroke.CAP_BUTT,BasicStroke.JOIN_ROUND,0,new float[] {9},0));
275 else
276 g2d.setStroke(new BasicStroke(currentWidth,BasicStroke.CAP_ROUND,BasicStroke.JOIN_ROUND));
277 }
278 g2d.draw(currentPath);
279 g2d.setStroke(new BasicStroke(1));
280
281 currentPath = new GeneralPath();
282 currentColor = newColor;
283 currentWidth = newWidth;
284 currentDashed = newDash;
285 currentStroke = null;
286 }
287 }
288
289 /**
290 * Draw the node as small rectangle with the given color.
291 *
292 * @param n The node to draw.
293 * @param color The color of the node.
294 */
295 public void drawNode(Node n, Color color, int size, int radius, boolean fill) {
296 if (isZoomOk(null) && size > 1) {
297 Point p = nc.getPoint(n.eastNorth);
298 if ((p.x < 0) || (p.y < 0) || (p.x > nc.getWidth())
299 || (p.y > nc.getHeight()))
300 return;
301 g.setColor(color);
302 if (fill) {
303 g.fillRect(p.x - radius, p.y - radius, size, size);
304 g.drawRect(p.x - radius, p.y - radius, size, size);
305 } else
306 g.drawRect(p.x - radius, p.y - radius, size, size);
307 }
308 }
309
310 // NW 111106 Overridden from SimplePaintVisitor in josm-1.4-nw1
311 // Shows areas before non-areas
312 public void visitAll(DataSet data, Boolean virtual) {
313 getSettings(virtual);
314 untaggedColor = Main.pref.getColor(marktr("untagged"),Color.GRAY);
315 textColor = Main.pref.getColor (marktr("text"), Color.WHITE);
316 useRealWidth = Main.pref.getBoolean("mappaint.useRealWidth",false);
317 zoomLevelDisplay = Main.pref.getBoolean("mappaint.zoomLevelDisplay",false);
318 fillAreas = Main.pref.getBoolean("mappaint.fillareas", true);
319 fillAlpha = Math.min(255, Math.max(0, Integer.valueOf(Main.pref.getInteger("mappaint.fillalpha", 50))));
320
321 Collection<Way> noAreaWays = new LinkedList<Way>();
322
323 for (final OsmPrimitive osm : data.ways)
324 if (!osm.incomplete && !osm.deleted && MapPaintStyles.isArea(osm))
325 osm.visit(this);
326 else if (!osm.deleted && !osm.incomplete)
327 noAreaWays.add((Way)osm);
328
329 for (final OsmPrimitive osm : noAreaWays)
330 osm.visit(this);
331
332 for (final OsmPrimitive osm : data.getSelected())
333 if (!osm.incomplete && !osm.deleted){
334 osm.visit(this);
335 }
336
337 displaySegments();
338
339 for (final OsmPrimitive osm : data.nodes)
340 if (!osm.incomplete && !osm.deleted)
341 osm.visit(this);
342 }
343
344 /**
345 * Draw a number of the order of the two consecutive nodes within the
346 * parents way
347 */
348 protected void drawOrderNumber(Node n1, Node n2, int orderNumber) {
349 Point p1 = nc.getPoint(n1.eastNorth);
350 Point p2 = nc.getPoint(n2.eastNorth);
351 if (!isSegmentVisible(p1, p2)) {
352 return;
353 }
354 int strlen = (""+orderNumber).length();
355 int x = (p1.x+p2.x)/2 - 4*strlen;
356 int y = (p1.y+p2.y)/2 + 4;
357
358 Color c = g.getColor();
359 g.setColor(backgroundColor);
360 g.fillRect(x-1, y-12, 8*strlen+1, 14);
361 g.setColor(c);
362 g.drawString(""+orderNumber, x, y);
363 }
364}
Note: See TracBrowser for help on using the repository browser.