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

Last change on this file since 13989 was 13989, checked in by Don-vip, 6 years ago

see #16128 - display names by default

  • Property svn:eol-style set to native
File size: 10.3 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.geom.GeneralPath;
7import java.awt.geom.Path2D;
8import java.awt.geom.Rectangle2D;
9import java.util.Iterator;
10
11import org.openstreetmap.josm.data.osm.BBox;
12import org.openstreetmap.josm.data.osm.INode;
13import org.openstreetmap.josm.data.osm.IWay;
14import org.openstreetmap.josm.data.osm.OsmData;
15import org.openstreetmap.josm.data.osm.WaySegment;
16import org.openstreetmap.josm.gui.MapViewState;
17import org.openstreetmap.josm.gui.MapViewState.MapViewPoint;
18import org.openstreetmap.josm.gui.MapViewState.MapViewRectangle;
19import org.openstreetmap.josm.gui.NavigatableComponent;
20import org.openstreetmap.josm.spi.preferences.Config;
21import org.openstreetmap.josm.tools.CheckParameterUtil;
22import org.openstreetmap.josm.tools.Logging;
23
24/**
25 * <p>Abstract common superclass for {@link Rendering} implementations.</p>
26 * @since 4087
27 */
28public abstract class AbstractMapRenderer implements Rendering {
29
30 /** the graphics context to which the visitor renders OSM objects */
31 protected final Graphics2D g;
32 /** the map viewport - provides projection and hit detection functionality */
33 protected final NavigatableComponent nc;
34
35 /**
36 * The {@link MapViewState} to use to convert between coordinates.
37 */
38 protected final MapViewState mapState;
39
40 /** if true, the paint visitor shall render OSM objects such that they
41 * look inactive. Example: rendering of data in an inactive layer using light gray as color only. */
42 protected boolean isInactiveMode;
43 /** Color Preference for background */
44 protected Color backgroundColor;
45 /** Color Preference for inactive objects */
46 protected Color inactiveColor;
47 /** Color Preference for selected objects */
48 protected Color selectedColor;
49 /** Color Preference for members of selected relations */
50 protected Color relationSelectedColor;
51 /** Color Preference for nodes */
52 protected Color nodeColor;
53
54 /** Color Preference for hightlighted objects */
55 protected Color highlightColor;
56 /** Preference: size of virtual nodes (0 displayes display) */
57 protected int virtualNodeSize;
58 /** Preference: minimum space (displayed way length) to display virtual nodes */
59 protected int virtualNodeSpace;
60
61 /** Preference: minimum space (displayed way length) to display segment numbers */
62 protected int segmentNumberSpace;
63
64 /** Performs slow operations by default. Can be disabled when fast partial rendering is required */
65 protected boolean doSlowOperations = true;
66
67 /**
68 * <p>Creates an abstract paint visitor</p>
69 *
70 * @param g the graphics context. Must not be null.
71 * @param nc the map viewport. Must not be null.
72 * @param isInactiveMode if true, the paint visitor shall render OSM objects such that they
73 * look inactive. Example: rendering of data in an inactive layer using light gray as color only.
74 * @throws IllegalArgumentException if {@code g} is null
75 * @throws IllegalArgumentException if {@code nc} is null
76 */
77 public AbstractMapRenderer(Graphics2D g, NavigatableComponent nc, boolean isInactiveMode) {
78 CheckParameterUtil.ensureParameterNotNull(g);
79 CheckParameterUtil.ensureParameterNotNull(nc);
80 this.g = g;
81 this.nc = nc;
82 this.mapState = nc.getState();
83 this.isInactiveMode = isInactiveMode;
84 }
85
86 /**
87 * Draw the node as small square with the given color.
88 *
89 * @param n The node to draw.
90 * @param color The color of the node.
91 * @param size size in pixels
92 * @param fill determines if the square mmust be filled
93 */
94 public abstract void drawNode(INode n, Color color, int size, boolean fill);
95
96 /**
97 * Draw an number of the order of the two consecutive nodes within the
98 * parents way
99 *
100 * @param p1 First point of the way segment.
101 * @param p2 Second point of the way segment.
102 * @param orderNumber The number of the segment in the way.
103 * @param clr The color to use for drawing the text.
104 * @since 10827
105 */
106 protected void drawOrderNumber(MapViewPoint p1, MapViewPoint p2, int orderNumber, Color clr) {
107 if (isSegmentVisible(p1, p2) && isLargeSegment(p1, p2, segmentNumberSpace)) {
108 String on = Integer.toString(orderNumber);
109 int strlen = on.length();
110 double centerX = (p1.getInViewX()+p2.getInViewX())/2;
111 double centerY = (p1.getInViewY()+p2.getInViewY())/2;
112 double x = centerX - 4*strlen;
113 double y = centerY + 4;
114
115 if (virtualNodeSize != 0 && isLargeSegment(p1, p2, virtualNodeSpace)) {
116 y = centerY - virtualNodeSize - 3;
117 }
118
119 g.setColor(backgroundColor);
120 g.fill(new Rectangle2D.Double(x-1, y-12, 8*strlen+1, 14));
121 g.setColor(clr);
122 g.drawString(on, (int) x, (int) y);
123 }
124 }
125
126 /**
127 * Draws virtual nodes.
128 *
129 * @param data The data set being rendered.
130 * @param bbox The bounding box being displayed.
131 * @since 13810 (signature)
132 */
133 public void drawVirtualNodes(OsmData<?, ?, ?, ?> data, BBox bbox) {
134 if (virtualNodeSize == 0 || data == null || bbox == null || data.isLocked())
135 return;
136 // print normal virtual nodes
137 GeneralPath path = new GeneralPath();
138 for (IWay<?> osm : data.searchWays(bbox)) {
139 if (osm.isUsable() && !osm.isDisabledAndHidden() && !osm.isDisabled()) {
140 visitVirtual(path, osm);
141 }
142 }
143 g.setColor(nodeColor);
144 g.draw(path);
145 try {
146 // print highlighted virtual nodes. Since only the color changes, simply
147 // drawing them over the existing ones works fine (at least in their current simple style)
148 path = new GeneralPath();
149 for (WaySegment wseg: data.getHighlightedVirtualNodes()) {
150 if (wseg.way.isUsable() && !wseg.way.isDisabled()) {
151 visitVirtual(path, wseg.toWay());
152 }
153 }
154 g.setColor(highlightColor);
155 g.draw(path);
156 } catch (ArrayIndexOutOfBoundsException e) {
157 // Silently ignore any ArrayIndexOutOfBoundsException that may be raised
158 // if the way has changed while being rendered (fix #7979)
159 // TODO: proper solution ?
160 // Idea from bastiK:
161 // avoid the WaySegment class and add another data class with { Way way; Node firstNode, secondNode; int firstIdx; }.
162 // On read, it would first check, if the way still has firstIdx+2 nodes, then check if the corresponding way nodes are still
163 // the same and report changes in a more controlled manner.
164 Logging.trace(e);
165 }
166 }
167
168 /**
169 * Reads the color definitions from preferences. This function is <code>public</code>, so that
170 * color names in preferences can be displayed even without calling the wireframe display before.
171 */
172 public void getColors() {
173 this.backgroundColor = PaintColors.BACKGROUND.get();
174 this.inactiveColor = PaintColors.INACTIVE.get();
175 this.selectedColor = PaintColors.SELECTED.get();
176 this.relationSelectedColor = PaintColors.RELATIONSELECTED.get();
177 this.nodeColor = PaintColors.NODE.get();
178 this.highlightColor = PaintColors.HIGHLIGHT.get();
179 }
180
181 /**
182 * Reads all the settings from preferences. Calls the @{link #getColors}
183 * function.
184 *
185 * @param virtual <code>true</code> if virtual nodes are used
186 */
187 protected void getSettings(boolean virtual) {
188 this.virtualNodeSize = virtual ? Config.getPref().getInt("mappaint.node.virtual-size", 8) / 2 : 0;
189 this.virtualNodeSpace = Config.getPref().getInt("mappaint.node.virtual-space", 70);
190 this.segmentNumberSpace = Config.getPref().getInt("mappaint.segmentnumber.space", 40);
191 getColors();
192 }
193
194 /**
195 * Checks if a way segemnt is large enough for additional information display.
196 *
197 * @param p1 First point of the way segment.
198 * @param p2 Second point of the way segment.
199 * @param space The free space to check against.
200 * @return <code>true</code> if segment is larger than required space
201 * @since 10827
202 */
203 public static boolean isLargeSegment(MapViewPoint p1, MapViewPoint p2, int space) {
204 return p1.oneNormInView(p2) > space;
205 }
206
207 /**
208 * Checks if segment is visible in display.
209 *
210 * @param p1 First point of the way segment.
211 * @param p2 Second point of the way segment.
212 * @return <code>true</code> if segment may be visible.
213 * @since 10827
214 */
215 protected boolean isSegmentVisible(MapViewPoint p1, MapViewPoint p2) {
216 MapViewRectangle view = mapState.getViewArea();
217 // not outside in the same direction
218 return (p1.getOutsideRectangleFlags(view) & p2.getOutsideRectangleFlags(view)) == 0;
219 }
220
221 /**
222 * Creates path for drawing virtual nodes for one way.
223 *
224 * @param path The path to append drawing to.
225 * @param w The ways to draw node for.
226 * @since 10827
227 * @since 13810 (signature)
228 */
229 public void visitVirtual(Path2D path, IWay<?> w) {
230 Iterator<? extends INode> it = w.getNodes().iterator();
231 MapViewPoint lastP = null;
232 while (it.hasNext()) {
233 INode n = it.next();
234 if (n.isLatLonKnown()) {
235 MapViewPoint p = mapState.getPointFor(n);
236 if (lastP != null && isSegmentVisible(lastP, p) && isLargeSegment(lastP, p, virtualNodeSpace)) {
237 double x = (p.getInViewX()+lastP.getInViewX())/2;
238 double y = (p.getInViewY()+lastP.getInViewY())/2;
239 path.moveTo(x-virtualNodeSize, y);
240 path.lineTo(x+virtualNodeSize, y);
241 path.moveTo(x, y-virtualNodeSize);
242 path.lineTo(x, y+virtualNodeSize);
243 }
244 lastP = p;
245 }
246 }
247 }
248
249 /**
250 * Sets whether slow operations such as text rendering must be performed (true by default).
251 * @param enable whether slow operations such as text rendering must be performed
252 * @since 13987
253 */
254 public final void enableSlowOperations(boolean enable) {
255 doSlowOperations = enable;
256 }
257}
Note: See TracBrowser for help on using the repository browser.