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

Last change on this file since 1221 was 1221, checked in by stoecker, 15 years ago

cleanup color handling

  • Property svn:eol-style set to native
File size: 13.5 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.Graphics;
9import java.awt.Graphics2D;
10import java.awt.Point;
11import java.awt.Rectangle;
12import java.awt.RenderingHints;
13import java.awt.Stroke;
14import java.awt.geom.GeneralPath;
15import java.util.Iterator;
16
17import org.openstreetmap.josm.Main;
18import org.openstreetmap.josm.data.osm.DataSet;
19import org.openstreetmap.josm.data.osm.RelationMember;
20import org.openstreetmap.josm.data.osm.Node;
21import org.openstreetmap.josm.data.osm.OsmPrimitive;
22import org.openstreetmap.josm.data.osm.Relation;
23import org.openstreetmap.josm.data.osm.Way;
24import org.openstreetmap.josm.gui.NavigatableComponent;
25
26/**
27 * A visitor that paints a simple scheme of every primitive it visits to a
28 * previous set graphic environment.
29 *
30 * @author imi
31 */
32public class SimplePaintVisitor implements Visitor {
33
34 public final static Color darkerblue = new Color(0,0,96);
35 public final static Color darkblue = new Color(0,0,128);
36 public final static Color darkgreen = new Color(0,128,0);
37 public final static Color teal = new Color(0,128,128);
38
39 /**
40 * The environment to paint to.
41 */
42 protected Graphics g;
43 /**
44 * MapView to get screen coordinates.
45 */
46 protected NavigatableComponent nc;
47
48 public boolean inactive;
49
50 protected static final double PHI = Math.toRadians(20);
51
52 /**
53 * Preferences
54 */
55 protected Color inactiveColor;
56 protected Color selectedColor;
57 protected Color nodeColor;
58 protected Color dfltWayColor;
59 protected Color relationColor;
60 protected Color untaggedWayColor;
61 protected Color incompleteColor;
62 protected Color backgroundColor;
63 protected boolean showDirectionArrow;
64 protected boolean showRelevantDirectionsOnly;
65 protected boolean showOrderNumber;
66 protected boolean fillSelectedNode;
67 protected boolean fillUnselectedNode;
68 protected int selectedNodeRadius;
69 protected int unselectedNodeRadius;
70 protected int selectedNodeSize;
71 protected int unselectedNodeSize;
72 protected int defaultSegmentWidth;
73 protected int virtualNodeSize;
74 protected int virtualNodeSpace;
75 protected int segmentNumberSpace;
76 protected int taggedNodeRadius;
77 protected int taggedNodeSize;
78
79 /**
80 * Draw subsequent segments of same color as one Path
81 */
82 protected Color currentColor = null;
83 protected GeneralPath currentPath = new GeneralPath();
84
85 Rectangle bbox = new Rectangle();
86
87 public void getColors()
88 {
89 inactiveColor = Main.pref.getColor(marktr("inactive"), Color.darkGray);
90 selectedColor = Main.pref.getColor(marktr("selected"), Color.red);
91 nodeColor = Main.pref.getColor(marktr("node"), Color.yellow);
92 dfltWayColor = Main.pref.getColor(marktr("way"), darkblue);
93 relationColor = Main.pref.getColor(marktr("relation"), teal);
94 untaggedWayColor = Main.pref.getColor(marktr("untagged way"), darkgreen);
95 incompleteColor = Main.pref.getColor(marktr("incomplete way"), darkerblue);
96 backgroundColor = Main.pref.getColor(marktr("background"), Color.BLACK);
97 }
98
99 protected void getSettings(Boolean virtual) {
100 showDirectionArrow = Main.pref.getBoolean("draw.segment.direction");
101 showRelevantDirectionsOnly = Main.pref.getBoolean("draw.segment.relevant_directions_only", true);
102 showOrderNumber = Main.pref.getBoolean("draw.segment.order_number");
103 selectedNodeRadius = Main.pref.getInteger("mappaint.node.selected-size", 5) / 2;
104 selectedNodeSize = selectedNodeRadius * 2;
105 unselectedNodeRadius = Main.pref.getInteger("mappaint.node.unselected-size", 3) / 2;
106 unselectedNodeSize = unselectedNodeRadius * 2;
107 taggedNodeRadius = Main.pref.getInteger("mappaint.node.tagged-size", 5) / 2;
108 taggedNodeSize = taggedNodeRadius * 2;
109 defaultSegmentWidth = Main.pref.getInteger("mappaint.segment.default-width", 2);
110 fillSelectedNode = Main.pref.getBoolean("mappaint.node.fill-selected", true);
111 fillUnselectedNode = Main.pref.getBoolean("mappaint.node.fill-unselected", false);
112 virtualNodeSize = virtual ? Main.pref.getInteger("mappaint.node.virtual-size", 8) / 2 : 0;
113 virtualNodeSpace = Main.pref.getInteger("mappaint.node.virtual-space", 70);
114 segmentNumberSpace = Main.pref.getInteger("mappaint.segmentnumber.space", 40);
115
116 ((Graphics2D)g).setRenderingHint(RenderingHints.KEY_ANTIALIASING,
117 Main.pref.getBoolean("mappaint.use-antialiasing", false) ?
118 RenderingHints.VALUE_ANTIALIAS_ON : RenderingHints.VALUE_ANTIALIAS_OFF);
119 }
120
121 public void visitAll(DataSet data, Boolean virtual) {
122 getSettings(virtual);
123 // draw tagged ways first, then untagged ways. takes
124 // time to iterate through list twice, OTOH does not
125 // require changing the colour while painting...
126 for (final OsmPrimitive osm : data.relations)
127 if (!osm.deleted && !osm.selected)
128 osm.visit(this);
129
130 for (final OsmPrimitive osm : data.ways)
131 if (!osm.deleted && !osm.selected && osm.tagged)
132 osm.visit(this);
133 displaySegments();
134
135 for (final OsmPrimitive osm : data.ways)
136 if (!osm.deleted && !osm.selected && !osm.tagged)
137 osm.visit(this);
138 displaySegments();
139
140 for (final OsmPrimitive osm : data.getSelected())
141 if (!osm.deleted)
142 osm.visit(this);
143 displaySegments();
144
145 for (final OsmPrimitive osm : data.nodes)
146 if (!osm.deleted && !osm.selected)
147 osm.visit(this);
148 if(virtualNodeSize != 0)
149 {
150 currentColor = nodeColor;
151 for (final OsmPrimitive osm : data.ways)
152 if (!osm.deleted)
153 visitVirtual((Way)osm);
154 displaySegments();
155 }
156 }
157
158 /**
159 * Draw a small rectangle.
160 * White if selected (as always) or red otherwise.
161 *
162 * @param n The node to draw.
163 */
164 public void visit(Node n) {
165 if (n.incomplete) return;
166
167 if (inactive)
168 drawNode(n, inactiveColor, unselectedNodeSize, unselectedNodeRadius, fillUnselectedNode);
169 else if (n.selected)
170 drawNode(n, selectedColor, selectedNodeSize, selectedNodeRadius, fillSelectedNode);
171 else if(n.tagged)
172 drawNode(n, nodeColor, taggedNodeSize, taggedNodeRadius, fillUnselectedNode);
173 else
174 drawNode(n, nodeColor, unselectedNodeSize, unselectedNodeRadius, fillUnselectedNode);
175 }
176
177 public static Boolean isLargeSegment(Point p1, Point p2, int space)
178 {
179 int xd = p1.x-p2.x; if(xd < 0) xd = -xd;
180 int yd = p1.y-p2.y; if(yd < 0) yd = -yd;
181 return (xd+yd > space);
182 }
183
184 public void visitVirtual(Way w) {
185 Iterator<Node> it = w.nodes.iterator();
186 if (it.hasNext()) {
187 Point lastP = nc.getPoint(it.next().eastNorth);
188 while(it.hasNext())
189 {
190 Point p = nc.getPoint(it.next().eastNorth);
191 if(isSegmentVisible(lastP, p) && isLargeSegment(lastP, p, virtualNodeSpace))
192 {
193 int x = (p.x+lastP.x)/2;
194 int y = (p.y+lastP.y)/2;
195 currentPath.moveTo(x-virtualNodeSize, y);
196 currentPath.lineTo(x+virtualNodeSize, y);
197 currentPath.moveTo(x, y-virtualNodeSize);
198 currentPath.lineTo(x, y+virtualNodeSize);
199 }
200 lastP = p;
201 }
202 }
203 }
204
205 /**
206 * Draw a darkblue line for all segments.
207 * @param w The way to draw.
208 */
209 public void visit(Way w) {
210 if (w.incomplete || w.nodes.size() < 2)
211 return;
212
213 // show direction arrows, if draw.segment.relevant_directions_only is not set, the way is tagged with a direction key
214 // (even if the tag is negated as in oneway=false) or the way is selected
215
216 boolean showThisDirectionArrow = w.selected
217 || (showDirectionArrow && (!showRelevantDirectionsOnly || w.hasDirectionKeys));
218 Color wayColor;
219
220 if (inactive) {
221 wayColor = inactiveColor;
222 } else if (!w.tagged) {
223 wayColor = untaggedWayColor;
224 } else {
225 wayColor = dfltWayColor;
226 }
227
228 Iterator<Node> it = w.nodes.iterator();
229 if (it.hasNext()) {
230 Point lastP = nc.getPoint(it.next().eastNorth);
231 for (int orderNumber = 1; it.hasNext(); orderNumber++) {
232 Point p = nc.getPoint(it.next().eastNorth);
233 drawSegment(lastP, p, w.selected && !inactive ? selectedColor : wayColor, showThisDirectionArrow);
234 if (showOrderNumber)
235 drawOrderNumber(lastP, p, orderNumber);
236 lastP = p;
237 }
238 }
239 }
240
241 private Stroke relatedWayStroke = new BasicStroke(
242 4, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_BEVEL);
243 public void visit(Relation r) {
244 if (r.incomplete) return;
245
246 Color col;
247 if (inactive) {
248 col = inactiveColor;
249 } else if (r.selected) {
250 col = selectedColor;
251 } else {
252 col = relationColor;
253 }
254 g.setColor(col);
255
256 for (RelationMember m : r.members) {
257 if (m.member.incomplete || m.member.deleted) continue;
258
259 if (m.member instanceof Node) {
260 Point p = nc.getPoint(((Node) m.member).eastNorth);
261 if (p.x < 0 || p.y < 0
262 || p.x > nc.getWidth() || p.y > nc.getHeight()) continue;
263
264 g.drawOval(p.x-3, p.y-3, 6, 6);
265 } else if (m.member instanceof Way) {
266 GeneralPath path = new GeneralPath();
267
268 boolean first = true;
269 for (Node n : ((Way) m.member).nodes) {
270 if (n.incomplete || n.deleted) continue;
271 Point p = nc.getPoint(n.eastNorth);
272 if (first) {
273 path.moveTo(p.x, p.y);
274 first = false;
275 } else {
276 path.lineTo(p.x, p.y);
277 }
278 }
279
280 ((Graphics2D) g).draw(relatedWayStroke.createStrokedShape(path));
281 }
282 }
283 }
284
285 /**
286 * Draw an number of the order of the two consecutive nodes within the
287 * parents way
288 */
289 protected void drawOrderNumber(Point p1, Point p2, int orderNumber) {
290 if (isSegmentVisible(p1, p2) && isLargeSegment(p1, p2, segmentNumberSpace)) {
291 String on = Integer.toString(orderNumber);
292 int strlen = on.length();
293 int x = (p1.x+p2.x)/2 - 4*strlen;
294 int y = (p1.y+p2.y)/2 + 4;
295
296 if(virtualNodeSize != 0 && isLargeSegment(p1, p2, virtualNodeSpace))
297 {
298 y = (p1.y+p2.y)/2 - virtualNodeSize - 3;
299 }
300
301 displaySegments(); // draw nodes on top!
302 Color c = g.getColor();
303 g.setColor(backgroundColor);
304 g.fillRect(x-1, y-12, 8*strlen+1, 14);
305 g.setColor(c);
306 g.drawString(on, x, y);
307 }
308 }
309
310 /**
311 * Draw the node as small rectangle with the given color.
312 *
313 * @param n The node to draw.
314 * @param color The color of the node.
315 */
316 public void drawNode(Node n, Color color, int size, int radius, boolean fill) {
317 if (size > 1) {
318 Point p = nc.getPoint(n.eastNorth);
319 if ((p.x < 0) || (p.y < 0) || (p.x > nc.getWidth())
320 || (p.y > nc.getHeight()))
321 return;
322 g.setColor(color);
323 if (fill) {
324 g.fillRect(p.x - radius, p.y - radius, size, size);
325 g.drawRect(p.x - radius, p.y - radius, size, size);
326 } else
327 g.drawRect(p.x - radius, p.y - radius, size, size);
328 }
329 }
330
331 /**
332 * Draw a line with the given color.
333 */
334 protected void drawSegment(Point p1, Point p2, Color col, boolean showDirection) {
335 if (col != currentColor) displaySegments(col);
336
337 if (isSegmentVisible(p1, p2)) {
338 currentPath.moveTo(p1.x, p1.y);
339 currentPath.lineTo(p2.x, p2.y);
340
341 if (showDirection) {
342 double t = Math.atan2(p2.y-p1.y, p2.x-p1.x) + Math.PI;
343 currentPath.lineTo((int)(p2.x + 10*Math.cos(t-PHI)), (int)(p2.y + 10*Math.sin(t-PHI)));
344 currentPath.moveTo((int)(p2.x + 10*Math.cos(t+PHI)), (int)(p2.y + 10*Math.sin(t+PHI)));
345 currentPath.lineTo(p2.x, p2.y);
346 }
347 }
348 }
349
350 protected boolean isSegmentVisible(Point p1, Point p2) {
351 if ((p1.x < 0) && (p2.x < 0)) return false;
352 if ((p1.y < 0) && (p2.y < 0)) return false;
353 if ((p1.x > nc.getWidth()) && (p2.x > nc.getWidth())) return false;
354 if ((p1.y > nc.getHeight()) && (p2.y > nc.getHeight())) return false;
355 return true;
356 }
357
358 public void setGraphics(Graphics g) {
359 this.g = g;
360 }
361
362 public void setNavigatableComponent(NavigatableComponent nc) {
363 this.nc = nc;
364 }
365
366 protected void displaySegments() {
367 displaySegments(null);
368 }
369 protected void displaySegments(Color newColor) {
370 if (currentPath != null) {
371 g.setColor(currentColor);
372 ((Graphics2D) g).draw(currentPath);
373 currentPath = new GeneralPath();
374 currentColor = newColor;
375 }
376 }
377}
Note: See TracBrowser for help on using the repository browser.