source: josm/trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/AbstractMapRenderer.java@ 7395

Last change on this file since 7395 was 6069, checked in by stoecker, 11 years ago

see #8853 remove tabs, trailing spaces, windows line ends, strange characters

  • Property svn:eol-style set to native
File size: 8.8 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.data.osm.visitor.paint;
3
4import java.awt.Color;
5import java.awt.Graphics2D;
6import java.awt.Point;
7import java.awt.geom.GeneralPath;
8import java.awt.geom.Point2D;
9import java.util.Iterator;
10
11import org.openstreetmap.josm.Main;
12import org.openstreetmap.josm.data.osm.BBox;
13import org.openstreetmap.josm.data.osm.DataSet;
14import org.openstreetmap.josm.data.osm.Node;
15import org.openstreetmap.josm.data.osm.Way;
16import org.openstreetmap.josm.data.osm.WaySegment;
17import org.openstreetmap.josm.gui.NavigatableComponent;
18import org.openstreetmap.josm.tools.CheckParameterUtil;
19
20/**
21 * <p>Abstract common superclass for {@link Rendering} implementations.</p>
22 *
23 */
24public abstract class AbstractMapRenderer implements Rendering {
25
26 /** the graphics context to which the visitor renders OSM objects */
27 protected Graphics2D g;
28 /** the map viewport - provides projection and hit detection functionality */
29 protected NavigatableComponent nc;
30
31 /** if true, the paint visitor shall render OSM objects such that they
32 * look inactive. Example: rendering of data in an inactive layer using light gray as color only. */
33 protected boolean isInactiveMode;
34 /** Color Preference for background */
35 protected Color backgroundColor;
36 /** Color Preference for inactive objects */
37 protected Color inactiveColor;
38 /** Color Preference for selected objects */
39 protected Color selectedColor;
40 /** Color Preference for nodes */
41 protected Color nodeColor;
42
43 /** Color Preference for hightlighted objects */
44 protected Color highlightColor;
45 /** Preference: size of virtual nodes (0 displayes display) */
46 protected int virtualNodeSize;
47 /** Preference: minimum space (displayed way length) to display virtual nodes */
48 protected int virtualNodeSpace;
49
50 /** Preference: minimum space (displayed way length) to display segment numbers */
51 protected int segmentNumberSpace;
52
53 /**
54 * <p>Creates an abstract paint visitor</p>
55 *
56 * @param g the graphics context. Must not be null.
57 * @param nc the map viewport. Must not be null.
58 * @param isInactiveMode if true, the paint visitor shall render OSM objects such that they
59 * look inactive. Example: rendering of data in an inactive layer using light gray as color only.
60 * @throws IllegalArgumentException thrown if {@code g} is null
61 * @throws IllegalArgumentException thrown if {@code nc} is null
62 */
63 public AbstractMapRenderer(Graphics2D g, NavigatableComponent nc, boolean isInactiveMode) throws IllegalArgumentException{
64 CheckParameterUtil.ensureParameterNotNull(g);
65 CheckParameterUtil.ensureParameterNotNull(nc);
66 this.g = g;
67 this.nc = nc;
68 this.isInactiveMode = isInactiveMode;
69 }
70
71 /**
72 * Draw the node as small rectangle with the given color.
73 *
74 * @param n The node to draw.
75 * @param color The color of the node.
76 */
77 public abstract void drawNode(Node n, Color color, int size, boolean fill);
78
79 /**
80 * Draw an number of the order of the two consecutive nodes within the
81 * parents way
82 *
83 * @param p1 First point of the way segment.
84 * @param p2 Second point of the way segment.
85 * @param orderNumber The number of the segment in the way.
86 */
87 protected void drawOrderNumber(Point p1, Point p2, int orderNumber, Color clr) {
88 if (isSegmentVisible(p1, p2) && isLargeSegment(p1, p2, segmentNumberSpace)) {
89 String on = Integer.toString(orderNumber);
90 int strlen = on.length();
91 int x = (p1.x+p2.x)/2 - 4*strlen;
92 int y = (p1.y+p2.y)/2 + 4;
93
94 if (virtualNodeSize != 0 && isLargeSegment(p1, p2, virtualNodeSpace)) {
95 y = (p1.y+p2.y)/2 - virtualNodeSize - 3;
96 }
97
98 g.setColor(backgroundColor);
99 g.fillRect(x-1, y-12, 8*strlen+1, 14);
100 g.setColor(clr);
101 g.drawString(on, x, y);
102 }
103 }
104
105 /**
106 * Draws virtual nodes.
107 *
108 * @param data The data set being rendered.
109 * @param bbox The bounding box being displayed.
110 */
111 public void drawVirtualNodes(DataSet data, BBox bbox) {
112 if (virtualNodeSize == 0 || data == null || bbox == null)
113 return;
114 // print normal virtual nodes
115 GeneralPath path = new GeneralPath();
116 for (Way osm : data.searchWays(bbox)) {
117 if (osm.isUsable() && !osm.isDisabledAndHidden() && !osm.isDisabled()) {
118 visitVirtual(path, osm);
119 }
120 }
121 g.setColor(nodeColor);
122 g.draw(path);
123 try {
124 // print highlighted virtual nodes. Since only the color changes, simply
125 // drawing them over the existing ones works fine (at least in their current
126 // simple style)
127 path = new GeneralPath();
128 for (WaySegment wseg: data.getHighlightedVirtualNodes()) {
129 if (wseg.way.isUsable() && !wseg.way.isDisabled()) {
130 visitVirtual(path, wseg.toWay());
131 }
132 }
133 g.setColor(highlightColor);
134 g.draw(path);
135 } catch (ArrayIndexOutOfBoundsException e) {
136 // Silently ignore any ArrayIndexOutOfBoundsException that may be raised
137 // if the way has changed while being rendered (fix #7979)
138 // TODO: proper solution ?
139 // Idea from bastiK: avoid the WaySegment class and add another data class with { Way way; Node firstNode, secondNode; int firstIdx; }.
140 // On read, it would first check, if the way still has firstIdx+2 nodes, then check if the corresponding way nodes are still the same
141 // and report changes in a more controlled manner.
142 }
143 }
144
145 /**
146 * Reads the color definitions from preferences. This function is <code>public</code>, so that
147 * color names in preferences can be displayed even without calling the wireframe display before.
148 */
149 public void getColors() {
150 this.backgroundColor = PaintColors.BACKGROUND.get();
151 this.inactiveColor = PaintColors.INACTIVE.get();
152 this.selectedColor = PaintColors.SELECTED.get();
153 this.nodeColor = PaintColors.NODE.get();
154 this.highlightColor = PaintColors.HIGHLIGHT.get();
155 }
156
157 /**
158 * Reads all the settings from preferences. Calls the @{link #getColors}
159 * function.
160 *
161 * @param virtual <code>true</code> if virtual nodes are used
162 */
163 protected void getSettings(boolean virtual) {
164 this.virtualNodeSize = virtual ? Main.pref.getInteger("mappaint.node.virtual-size", 8) / 2 : 0;
165 this.virtualNodeSpace = Main.pref.getInteger("mappaint.node.virtual-space", 70);
166 this.segmentNumberSpace = Main.pref.getInteger("mappaint.segmentnumber.space", 40);
167 getColors();
168 }
169
170 /**
171 * Checks if a way segemnt is large enough for additional information display.
172 *
173 * @param p1 First point of the way segment.
174 * @param p2 Second point of the way segment.
175 * @param space The free space to check against.
176 * @return <code>true</code> if segment is larger than required space
177 */
178 public static boolean isLargeSegment(Point2D p1, Point2D p2, int space) {
179 double xd = Math.abs(p1.getX()-p2.getX());
180 double yd = Math.abs(p1.getY()-p2.getY());
181 return (xd+yd > space);
182 }
183
184 /**
185 * Checks if segment is visible in display.
186 *
187 * @param p1 First point of the way segment.
188 * @param p2 Second point of the way segment.
189 * @return <code>true</code> if segment is visible.
190 */
191 protected boolean isSegmentVisible(Point p1, Point p2) {
192 if ((p1.x < 0) && (p2.x < 0)) return false;
193 if ((p1.y < 0) && (p2.y < 0)) return false;
194 if ((p1.x > nc.getWidth()) && (p2.x > nc.getWidth())) return false;
195 if ((p1.y > nc.getHeight()) && (p2.y > nc.getHeight())) return false;
196 return true;
197 }
198
199 /**
200 * Creates path for drawing virtual nodes for one way.
201 *
202 * @param path The path to append drawing to.
203 * @param w The ways to draw node for.
204 */
205 public void visitVirtual(GeneralPath path, Way w) {
206 Iterator<Node> it = w.getNodes().iterator();
207 if (it.hasNext()) {
208 Point lastP = nc.getPoint(it.next());
209 while (it.hasNext())
210 {
211 Point p = nc.getPoint(it.next());
212 if (isSegmentVisible(lastP, p) && isLargeSegment(lastP, p, virtualNodeSpace))
213 {
214 int x = (p.x+lastP.x)/2;
215 int y = (p.y+lastP.y)/2;
216 path.moveTo(x-virtualNodeSize, y);
217 path.lineTo(x+virtualNodeSize, y);
218 path.moveTo(x, y-virtualNodeSize);
219 path.lineTo(x, y+virtualNodeSize);
220 }
221 lastP = p;
222 }
223 }
224 }
225}
Note: See TracBrowser for help on using the repository browser.