source: josm/trunk/src/org/openstreetmap/josm/data/osm/visitor/SimplePaintVisitor.java@ 2578

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

Encalupse OsmPrimitive.incomplete

  • Property svn:eol-style set to native
File size: 17.9 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;
7
8import java.awt.BasicStroke;
9import java.awt.Color;
10import java.awt.Graphics;
11import java.awt.Graphics2D;
12import java.awt.Point;
13import java.awt.Polygon;
14import java.awt.Rectangle;
15import java.awt.RenderingHints;
16import java.awt.Stroke;
17import java.awt.geom.GeneralPath;
18import java.util.Iterator;
19
20import org.openstreetmap.josm.Main;
21import org.openstreetmap.josm.data.Bounds;
22import org.openstreetmap.josm.data.osm.DataSet;
23import org.openstreetmap.josm.data.osm.Node;
24import org.openstreetmap.josm.data.osm.OsmPrimitive;
25import org.openstreetmap.josm.data.osm.Relation;
26import org.openstreetmap.josm.data.osm.RelationMember;
27import org.openstreetmap.josm.data.osm.Way;
28import org.openstreetmap.josm.gui.NavigatableComponent;
29
30/**
31 * A visitor that paints a simple scheme of every primitive it visits to a
32 * previous set graphic environment.
33 *
34 * @author imi
35 */
36public class SimplePaintVisitor extends AbstractVisitor {
37
38 public final static Color darkerblue = new Color(0,0,96);
39 public final static Color darkblue = new Color(0,0,128);
40 public final static Color darkgreen = new Color(0,128,0);
41 public final static Color teal = new Color(0,128,128);
42 public final static Color lightteal= new Color(0, 255, 186);
43
44 /**
45 * The environment to paint to.
46 */
47 protected Graphics g;
48 /**
49 * MapView to get screen coordinates.
50 */
51 protected NavigatableComponent nc;
52
53 public boolean inactive;
54
55 protected static final double PHI = Math.toRadians(20);
56
57 /**
58 * Preferences
59 */
60 protected Color inactiveColor;
61 protected Color selectedColor;
62 protected Color nodeColor;
63 protected Color dfltWayColor;
64 protected Color relationColor;
65 protected Color untaggedWayColor;
66 protected Color incompleteColor;
67 protected Color backgroundColor;
68 protected Color highlightColor;
69 protected boolean showDirectionArrow;
70 protected boolean showRelevantDirectionsOnly;
71 protected boolean showHeadArrowOnly;
72 protected boolean showOrderNumber;
73 protected boolean fillSelectedNode;
74 protected boolean fillUnselectedNode;
75 protected int selectedNodeRadius;
76 protected int unselectedNodeRadius;
77 protected int selectedNodeSize;
78 protected int unselectedNodeSize;
79 protected int defaultSegmentWidth;
80 protected int virtualNodeSize;
81 protected int virtualNodeSpace;
82 protected int segmentNumberSpace;
83 protected int taggedNodeRadius;
84 protected int taggedNodeSize;
85
86 /**
87 * Draw subsequent segments of same color as one Path
88 */
89 protected Color currentColor = null;
90 protected GeneralPath currentPath = new GeneralPath();
91
92 Rectangle bbox = new Rectangle();
93
94 public void getColors()
95 {
96 inactiveColor = Main.pref.getColor(marktr("inactive"), Color.darkGray);
97 selectedColor = Main.pref.getColor(marktr("selected"), Color.red);
98 nodeColor = Main.pref.getColor(marktr("node"), Color.yellow);
99 dfltWayColor = Main.pref.getColor(marktr("way"), darkblue);
100 relationColor = Main.pref.getColor(marktr("relation"), teal);
101 untaggedWayColor = Main.pref.getColor(marktr("untagged way"), darkgreen);
102 incompleteColor = Main.pref.getColor(marktr("incomplete way"), darkerblue);
103 backgroundColor = Main.pref.getColor(marktr("background"), Color.BLACK);
104 highlightColor = Main.pref.getColor(marktr("highlight"), lightteal);
105 }
106
107 protected void getSettings(boolean virtual) {
108 showDirectionArrow = Main.pref.getBoolean("draw.segment.direction", true);
109 showRelevantDirectionsOnly = Main.pref.getBoolean("draw.segment.relevant_directions_only", true);
110 showHeadArrowOnly = Main.pref.getBoolean("draw.segment.head_only", false);
111 showOrderNumber = Main.pref.getBoolean("draw.segment.order_number", false);
112 selectedNodeRadius = Main.pref.getInteger("mappaint.node.selected-size", 5) / 2;
113 selectedNodeSize = selectedNodeRadius * 2;
114 unselectedNodeRadius = Main.pref.getInteger("mappaint.node.unselected-size", 3) / 2;
115 unselectedNodeSize = unselectedNodeRadius * 2;
116 taggedNodeRadius = Main.pref.getInteger("mappaint.node.tagged-size", 5) / 2;
117 taggedNodeSize = taggedNodeRadius * 2;
118 defaultSegmentWidth = Main.pref.getInteger("mappaint.segment.default-width", 2);
119 fillSelectedNode = Main.pref.getBoolean("mappaint.node.fill-selected", true);
120 fillUnselectedNode = Main.pref.getBoolean("mappaint.node.fill-unselected", false);
121 virtualNodeSize = virtual ? Main.pref.getInteger("mappaint.node.virtual-size", 8) / 2 : 0;
122 virtualNodeSpace = Main.pref.getInteger("mappaint.node.virtual-space", 70);
123 segmentNumberSpace = Main.pref.getInteger("mappaint.segmentnumber.space", 40);
124 getColors();
125
126 ((Graphics2D)g).setRenderingHint(RenderingHints.KEY_ANTIALIASING,
127 Main.pref.getBoolean("mappaint.use-antialiasing", false) ?
128 RenderingHints.VALUE_ANTIALIAS_ON : RenderingHints.VALUE_ANTIALIAS_OFF);
129 }
130
131 DataSet ds;
132 public void visitAll(DataSet data, boolean virtual, Bounds bounds) {
133 this.ds = data;
134 //boolean profiler = Main.pref.getBoolean("simplepaint.profiler",false);
135 //long profilerStart = java.lang.System.currentTimeMillis();
136 //long profilerLast = profilerStart;
137 //int profilerN = 0;
138 //if(profiler)
139 // System.out.println("Simplepaint Profiler");
140
141 getSettings(virtual);
142
143 //if(profiler)
144 //{
145 // System.out.format("Prepare : %4dms\n", (java.lang.System.currentTimeMillis()-profilerLast));
146 // profilerLast = java.lang.System.currentTimeMillis();
147 //}
148
149 /* draw tagged ways first, then untagged ways. takes
150 time to iterate through list twice, OTOH does not
151 require changing the colour while painting... */
152 //profilerN = 0;
153 for (final OsmPrimitive osm: data.getRelations()) {
154 if (!osm.isDeleted() && !ds.isSelected(osm) && !osm.isFiltered()) {
155 osm.visit(this);
156 // profilerN++;
157 }
158 }
159
160 //if(profiler)
161 //{
162 // System.out.format("Relations: %4dms, n=%5d\n", (java.lang.System.currentTimeMillis()-profilerLast), profilerN);
163 // profilerLast = java.lang.System.currentTimeMillis();
164 //}
165
166 //profilerN = 0;
167 for (final OsmPrimitive osm:data.getWays()){
168 if (!osm.isDeleted() && !ds.isSelected(osm) && !osm.isFiltered() && osm.isTagged()) {
169 osm.visit(this);
170 // profilerN++;
171 }
172 }
173 displaySegments();
174
175 for (final OsmPrimitive osm:data.getWays()){
176 if (!osm.isDeleted() && !ds.isSelected(osm) && !osm.isFiltered() && !osm.isTagged()) {
177 osm.visit(this);
178 // profilerN++;
179 }
180 }
181 displaySegments();
182
183 //if(profiler)
184 //{
185 // System.out.format("Ways : %4dms, n=%5d\n",
186 // (java.lang.System.currentTimeMillis()-profilerLast), profilerN);
187 // profilerLast = java.lang.System.currentTimeMillis();
188 //}
189
190 //profilerN = 0;
191 for (final OsmPrimitive osm : data.getSelected())
192 if (!osm.isDeleted()) {
193 osm.visit(this);
194 // profilerN++;
195 }
196 displaySegments();
197
198 //if(profiler)
199 //{
200 // System.out.format("Selected : %4dms, n=%5d\n", (java.lang.System.currentTimeMillis()-profilerLast), profilerN);
201 // profilerLast = java.lang.System.currentTimeMillis();
202 //}
203
204 //profilerN = 0;
205 for (final OsmPrimitive osm: data.getNodes()) {
206 if (!osm.isDeleted() && !ds.isSelected(osm) && !osm.isFiltered())
207 {
208 osm.visit(this);
209 // profilerN++;
210 }
211 }
212
213 //if(profiler)
214 //{
215 // System.out.format("Nodes : %4dms, n=%5d\n",
216 // (java.lang.System.currentTimeMillis()-profilerLast), profilerN);
217 // profilerLast = java.lang.System.currentTimeMillis();
218 //}
219
220 if (virtualNodeSize != 0) {
221 // profilerN = 0;
222 currentColor = nodeColor;
223 for (final OsmPrimitive osm:data.getWays()){
224 if (!osm.isDeleted() && !osm.isDisabled() && !osm.isFiltered()) {
225 visitVirtual((Way) osm);
226 // profilerN++;
227 }
228 }
229 displaySegments();
230
231 // if(profiler)
232 // {
233 // System.out.format("Virtual : %4dms, n=%5d\n", (java.lang.System.currentTimeMillis()-profilerLast), profilerN);
234 // profilerLast = java.lang.System.currentTimeMillis();
235 // }
236 }
237
238 //if(profiler)
239 //{
240 // System.out.format("All : %4dms\n", (profilerLast-profilerStart));
241 //}
242 }
243
244 /**
245 * Draw a small rectangle.
246 * White if selected (as always) or red otherwise.
247 *
248 * @param n The node to draw.
249 */
250 public void visit(Node n) {
251 if (n.isIncomplete()) return;
252
253 if (inactive || n.isDisabled()) {
254 drawNode(n, inactiveColor, unselectedNodeSize, unselectedNodeRadius, fillUnselectedNode);
255 } else if (n.highlighted) {
256 drawNode(n, highlightColor, selectedNodeSize, selectedNodeRadius, fillSelectedNode);
257 } else if (ds.isSelected(n)) {
258 drawNode(n, selectedColor, selectedNodeSize, selectedNodeRadius, fillSelectedNode);
259 } else if(n.isTagged()) {
260 drawNode(n, nodeColor, taggedNodeSize, taggedNodeRadius, fillUnselectedNode);
261 } else {
262 drawNode(n, nodeColor, unselectedNodeSize, unselectedNodeRadius, fillUnselectedNode);
263 }
264 }
265
266 public static boolean isLargeSegment(Point p1, Point p2, int space)
267 {
268 int xd = p1.x-p2.x; if(xd < 0) {
269 xd = -xd;
270 }
271 int yd = p1.y-p2.y; if(yd < 0) {
272 yd = -yd;
273 }
274 return (xd+yd > space);
275 }
276
277 public void visitVirtual(Way w) {
278 Iterator<Node> it = w.getNodes().iterator();
279 if (it.hasNext()) {
280 Point lastP = nc.getPoint(it.next());
281 while(it.hasNext())
282 {
283 Point p = nc.getPoint(it.next());
284 if(isSegmentVisible(lastP, p) && isLargeSegment(lastP, p, virtualNodeSpace))
285 {
286 int x = (p.x+lastP.x)/2;
287 int y = (p.y+lastP.y)/2;
288 currentPath.moveTo(x-virtualNodeSize, y);
289 currentPath.lineTo(x+virtualNodeSize, y);
290 currentPath.moveTo(x, y-virtualNodeSize);
291 currentPath.lineTo(x, y+virtualNodeSize);
292 }
293 lastP = p;
294 }
295 }
296 }
297
298 /**
299 * Draw a darkblue line for all segments.
300 * @param w The way to draw.
301 */
302 public void visit(Way w) {
303 if (w.isIncomplete() || w.getNodesCount() < 2)
304 return;
305
306 /* show direction arrows, if draw.segment.relevant_directions_only is not set, the way is tagged with a direction key
307 (even if the tag is negated as in oneway=false) or the way is selected */
308
309 boolean showThisDirectionArrow = ds.isSelected(w)
310 || (showDirectionArrow && (!showRelevantDirectionsOnly || w.hasDirectionKeys()));
311 /* head only takes over control if the option is true,
312 the direction should be shown at all and not only because it's selected */
313 boolean showOnlyHeadArrowOnly = showThisDirectionArrow && !ds.isSelected(w) && showHeadArrowOnly;
314 Color wayColor;
315
316 if (inactive || w.isDisabled()) {
317 wayColor = inactiveColor;
318 } else if(w.highlighted) {
319 wayColor = highlightColor;
320 } else if(ds.isSelected(w)) {
321 wayColor = selectedColor;
322 } else if (!w.isTagged()) {
323 wayColor = untaggedWayColor;
324 } else {
325 wayColor = dfltWayColor;
326 }
327
328 Iterator<Node> it = w.getNodes().iterator();
329 if (it.hasNext()) {
330 Point lastP = nc.getPoint(it.next());
331 for (int orderNumber = 1; it.hasNext(); orderNumber++) {
332 Point p = nc.getPoint(it.next());
333 drawSegment(lastP, p, wayColor,
334 showOnlyHeadArrowOnly ? !it.hasNext() : showThisDirectionArrow);
335 if (showOrderNumber) {
336 drawOrderNumber(lastP, p, orderNumber);
337 }
338 lastP = p;
339 }
340 }
341 }
342
343 private Stroke relatedWayStroke = new BasicStroke(
344 4, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_BEVEL);
345 public void visit(Relation r) {
346 if (r.isIncomplete()) return;
347
348 Color col;
349 if (inactive || r.isDisabled()) {
350 col = inactiveColor;
351 } else if (ds.isSelected(r)) {
352 col = selectedColor;
353 } else {
354 col = relationColor;
355 }
356 g.setColor(col);
357
358 for (RelationMember m : r.getMembers()) {
359 if (m.getMember().isIncomplete() || m.getMember().isDeleted()) {
360 continue;
361 }
362
363 if (m.isNode()) {
364 Point p = nc.getPoint(m.getNode());
365 if (p.x < 0 || p.y < 0
366 || p.x > nc.getWidth() || p.y > nc.getHeight()) {
367 continue;
368 }
369
370 g.drawOval(p.x-3, p.y-3, 6, 6);
371 } else if (m.isWay()) {
372 GeneralPath path = new GeneralPath();
373
374 boolean first = true;
375 for (Node n : m.getWay().getNodes()) {
376 if (n.isIncomplete() || n.isDeleted()) {
377 continue;
378 }
379 Point p = nc.getPoint(n);
380 if (first) {
381 path.moveTo(p.x, p.y);
382 first = false;
383 } else {
384 path.lineTo(p.x, p.y);
385 }
386 }
387
388 ((Graphics2D) g).draw(relatedWayStroke.createStrokedShape(path));
389 }
390 }
391 }
392
393 /**
394 * Draw an number of the order of the two consecutive nodes within the
395 * parents way
396 */
397 protected void drawOrderNumber(Point p1, Point p2, int orderNumber) {
398 if (isSegmentVisible(p1, p2) && isLargeSegment(p1, p2, segmentNumberSpace)) {
399 String on = Integer.toString(orderNumber);
400 int strlen = on.length();
401 int x = (p1.x+p2.x)/2 - 4*strlen;
402 int y = (p1.y+p2.y)/2 + 4;
403
404 if(virtualNodeSize != 0 && isLargeSegment(p1, p2, virtualNodeSpace))
405 {
406 y = (p1.y+p2.y)/2 - virtualNodeSize - 3;
407 }
408
409 displaySegments(); /* draw nodes on top! */
410 Color c = g.getColor();
411 g.setColor(backgroundColor);
412 g.fillRect(x-1, y-12, 8*strlen+1, 14);
413 g.setColor(c);
414 g.drawString(on, x, y);
415 }
416 }
417
418 /**
419 * Draw the node as small rectangle with the given color.
420 *
421 * @param n The node to draw.
422 * @param color The color of the node.
423 */
424 public void drawNode(Node n, Color color, int size, int radius, boolean fill) {
425 if (size > 1) {
426 Point p = nc.getPoint(n);
427 if ((p.x < 0) || (p.y < 0) || (p.x > nc.getWidth())
428 || (p.y > nc.getHeight()))
429 return;
430 g.setColor(color);
431 if (fill) {
432 g.fillRect(p.x - radius, p.y - radius, size, size);
433 g.drawRect(p.x - radius, p.y - radius, size, size);
434 } else {
435 g.drawRect(p.x - radius, p.y - radius, size, size);
436 }
437 }
438 }
439
440 /**
441 * Draw a line with the given color.
442 */
443 protected void drawSegment(Point p1, Point p2, Color col, boolean showDirection) {
444 if (col != currentColor) {
445 displaySegments(col);
446 }
447
448 if (isSegmentVisible(p1, p2)) {
449 currentPath.moveTo(p1.x, p1.y);
450 currentPath.lineTo(p2.x, p2.y);
451
452 if (showDirection) {
453 double t = Math.atan2(p2.y-p1.y, p2.x-p1.x) + Math.PI;
454 currentPath.lineTo((int)(p2.x + 10*Math.cos(t-PHI)), (int)(p2.y + 10*Math.sin(t-PHI)));
455 currentPath.moveTo((int)(p2.x + 10*Math.cos(t+PHI)), (int)(p2.y + 10*Math.sin(t+PHI)));
456 currentPath.lineTo(p2.x, p2.y);
457 }
458 }
459 }
460
461 protected boolean isSegmentVisible(Point p1, Point p2) {
462 if ((p1.x < 0) && (p2.x < 0)) return false;
463 if ((p1.y < 0) && (p2.y < 0)) return false;
464 if ((p1.x > nc.getWidth()) && (p2.x > nc.getWidth())) return false;
465 if ((p1.y > nc.getHeight()) && (p2.y > nc.getHeight())) return false;
466 return true;
467 }
468
469 protected boolean isPolygonVisible(Polygon polygon) {
470 Rectangle bounds = polygon.getBounds();
471 if (bounds.width == 0 && bounds.height == 0) return false;
472 if (bounds.x > nc.getWidth()) return false;
473 if (bounds.y > nc.getHeight()) return false;
474 if (bounds.x + bounds.width < 0) return false;
475 if (bounds.y + bounds.height < 0) return false;
476 return true;
477 }
478
479 public void setGraphics(Graphics g) {
480 this.g = g;
481 }
482
483 public void setNavigatableComponent(NavigatableComponent nc) {
484 this.nc = nc;
485 }
486
487 protected void displaySegments() {
488 displaySegments(null);
489 }
490 protected void displaySegments(Color newColor) {
491 if (currentPath != null) {
492 g.setColor(currentColor);
493 ((Graphics2D) g).draw(currentPath);
494 currentPath = new GeneralPath();
495 currentColor = newColor;
496 }
497 }
498}
Note: See TracBrowser for help on using the repository browser.