source: josm/trunk/src/org/openstreetmap/josm/data/validation/PaintVisitor.java@ 12700

Last change on this file since 12700 was 12161, checked in by michael2402, 7 years ago

See #13415: Add the ILatLon interface, unify handling of Nodes and CachedLatLon

  • Property svn:eol-style set to native
File size: 8.3 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.data.validation;
3
4import java.awt.Color;
5import java.awt.Graphics2D;
6import java.awt.Point;
7import java.util.HashSet;
8import java.util.List;
9import java.util.Objects;
10import java.util.Set;
11
12import org.openstreetmap.josm.data.coor.LatLon;
13import org.openstreetmap.josm.data.osm.Node;
14import org.openstreetmap.josm.data.osm.OsmPrimitive;
15import org.openstreetmap.josm.data.osm.Relation;
16import org.openstreetmap.josm.data.osm.Way;
17import org.openstreetmap.josm.data.osm.WaySegment;
18import org.openstreetmap.josm.data.osm.visitor.AbstractVisitor;
19import org.openstreetmap.josm.gui.MapView;
20import org.openstreetmap.josm.gui.draw.MapViewPath;
21import org.openstreetmap.josm.gui.draw.SymbolShape;
22import org.openstreetmap.josm.tools.Utils;
23
24/**
25 * Visitor that highlights the primitives affected by an error
26 * @author frsantos
27 * @since 5671
28 */
29public class PaintVisitor extends AbstractVisitor implements ValidatorVisitor {
30 /** The graphics */
31 private final Graphics2D g;
32 /** The MapView */
33 private final MapView mv;
34
35 /** The severity color */
36 private Color color;
37 /** Is the error selected ? */
38 private boolean selected;
39
40 private final Set<PaintedPoint> paintedPoints = new HashSet<>();
41 private final Set<PaintedSegment> paintedSegments = new HashSet<>();
42
43 /**
44 * Constructor
45 * @param g The graphics
46 * @param mv The Mapview
47 */
48 public PaintVisitor(Graphics2D g, MapView mv) {
49 this.g = g;
50 this.mv = mv;
51 }
52
53 protected static class PaintedPoint {
54 protected final LatLon p1;
55 protected final Color color;
56
57 public PaintedPoint(LatLon p1, Color color) {
58 this.p1 = p1;
59 this.color = color;
60 }
61
62 @Override
63 public int hashCode() {
64 return Objects.hash(p1, color);
65 }
66
67 @Override
68 public boolean equals(Object obj) {
69 if (this == obj) return true;
70 if (obj == null || getClass() != obj.getClass()) return false;
71 PaintedPoint that = (PaintedPoint) obj;
72 return Objects.equals(p1, that.p1) &&
73 Objects.equals(color, that.color);
74 }
75 }
76
77 protected static class PaintedSegment extends PaintedPoint {
78 private final LatLon p2;
79
80 public PaintedSegment(LatLon p1, LatLon p2, Color color) {
81 super(p1, color);
82 this.p2 = p2;
83 }
84
85 @Override
86 public int hashCode() {
87 return Objects.hash(super.hashCode(), p2);
88 }
89
90 @Override
91 public boolean equals(Object obj) {
92 if (this == obj) return true;
93 if (obj == null || getClass() != obj.getClass()) return false;
94 if (!super.equals(obj)) return false;
95 PaintedSegment that = (PaintedSegment) obj;
96 return Objects.equals(p2, that.p2);
97 }
98 }
99
100 @Override
101 public void visit(TestError error) {
102 if (error != null && !error.isIgnored()) {
103 color = error.getSeverity().getColor();
104 selected = error.isSelected();
105 error.visitHighlighted(this);
106 }
107 }
108
109 @Override
110 public void visit(OsmPrimitive p) {
111 if (p.isUsable()) {
112 p.accept(this);
113 }
114 }
115
116 /**
117 * Draws a circle around the node
118 * @param n The node
119 * @param color The circle color
120 */
121 protected void drawNode(Node n, Color color) {
122 PaintedPoint pp = new PaintedPoint(n.getCoor(), color);
123
124 if (!paintedPoints.contains(pp)) {
125 MapViewPath circle = new MapViewPath(mv.getState()).shapeAround(n, SymbolShape.CIRCLE, 10);
126
127 if (selected) {
128 g.setColor(getHighlightColor(color));
129 g.fill(circle);
130 }
131 g.setColor(color);
132 g.draw(circle);
133 paintedPoints.add(pp);
134 }
135 }
136
137 /**
138 * Draws a line around the segment
139 *
140 * @param p1 The first point of segment
141 * @param p2 The second point of segment
142 * @param color The color
143 */
144 protected void drawSegment(Point p1, Point p2, Color color) {
145
146 double t = Math.atan2((double) p2.x - p1.x, (double) p2.y - p1.y);
147 double cosT = 5 * Math.cos(t);
148 double sinT = 5 * Math.sin(t);
149 int deg = (int) Utils.toDegrees(t);
150 if (selected) {
151 g.setColor(getHighlightColor(color));
152 int[] x = new int[] {(int) (p1.x + cosT), (int) (p2.x + cosT),
153 (int) (p2.x - cosT), (int) (p1.x - cosT)};
154 int[] y = new int[] {(int) (p1.y - sinT), (int) (p2.y - sinT),
155 (int) (p2.y + sinT), (int) (p1.y + sinT)};
156 g.fillPolygon(x, y, 4);
157 g.fillArc(p1.x - 5, p1.y - 5, 10, 10, deg, 180);
158 g.fillArc(p2.x - 5, p2.y - 5, 10, 10, deg, -180);
159 }
160 g.setColor(color);
161 g.drawLine((int) (p1.x + cosT), (int) (p1.y - sinT),
162 (int) (p2.x + cosT), (int) (p2.y - sinT));
163 g.drawLine((int) (p1.x - cosT), (int) (p1.y + sinT),
164 (int) (p2.x - cosT), (int) (p2.y + sinT));
165 g.drawArc(p1.x - 5, p1.y - 5, 10, 10, deg, 180);
166 g.drawArc(p2.x - 5, p2.y - 5, 10, 10, deg, -180);
167 }
168
169 /**
170 * Draws a line around the segment
171 *
172 * @param n1 The first node of segment
173 * @param n2 The second node of segment
174 * @param color The color
175 */
176 protected void drawSegment(Node n1, Node n2, Color color) {
177 if (n1.isDrawable() && n2.isDrawable() && isSegmentVisible(n1, n2)) {
178 PaintedSegment ps = new PaintedSegment(n1.getCoor(), n2.getCoor(), color);
179 if (!paintedSegments.contains(ps)) {
180 drawSegment(mv.getPoint(n1), mv.getPoint(n2), color);
181 paintedSegments.add(ps);
182 }
183 }
184 }
185
186 /**
187 * Draw a small rectangle.
188 * White if selected (as always) or red otherwise.
189 *
190 * @param n The node to draw.
191 */
192 @Override
193 public void visit(Node n) {
194 if (n.isDrawable() && isNodeVisible(n)) {
195 drawNode(n, color);
196 }
197 }
198
199 @Override
200 public void visit(Way w) {
201 visit(w.getNodes());
202 }
203
204 @Override
205 public void visit(WaySegment ws) {
206 if (ws.lowerIndex < 0 || ws.lowerIndex + 1 >= ws.way.getNodesCount())
207 return;
208 Node a = ws.way.getNodes().get(ws.lowerIndex);
209 Node b = ws.way.getNodes().get(ws.lowerIndex + 1);
210 drawSegment(a, b, color);
211 }
212
213 @Override
214 public void visit(Relation r) {
215 /* No idea how to draw a relation. */
216 }
217
218 /**
219 * Checks if the given node is in the visible area.
220 * @param n The node to check for visibility
221 * @return true if the node is visible
222 */
223 protected boolean isNodeVisible(Node n) {
224 Point p = mv.getPoint(n);
225 return !((p.x < 0) || (p.y < 0) || (p.x > mv.getWidth()) || (p.y > mv.getHeight()));
226 }
227
228 /**
229 * Checks if the given segment is in the visible area.
230 * NOTE: This will return true for a small number of non-visible segments.
231 * @param n1 The first point of the segment to check
232 * @param n2 The second point of the segment to check
233 * @return {@code true} if the segment is visible
234 */
235 protected boolean isSegmentVisible(Node n1, Node n2) {
236 Point p1 = mv.getPoint(n1);
237 Point p2 = mv.getPoint(n2);
238 return (p1.x >= 0 || p2.x >= 0)
239 && (p1.y >= 0 || p2.y >= 0)
240 && (p1.x <= mv.getWidth() || p2.x <= mv.getWidth())
241 && (p1.y <= mv.getHeight() || p2.y <= mv.getHeight());
242 }
243
244 @Override
245 public void visit(List<Node> nodes) {
246 Node lastN = null;
247 for (Node n : nodes) {
248 if (lastN == null) {
249 lastN = n;
250 continue;
251 }
252 drawSegment(lastN, n, color);
253 lastN = n;
254 }
255 }
256
257 /**
258 * Gets the color to draw highlight markers with.
259 * @param color severity color
260 * @return The color.
261 */
262 private static Color getHighlightColor(Color color) {
263 return new Color(color.getRed(), color.getGreen(), color.getBlue(), (int) (color.getAlpha() * .4));
264 }
265
266 /**
267 * Clears the internal painted objects collections.
268 */
269 public void clearPaintedObjects() {
270 paintedPoints.clear();
271 paintedSegments.clear();
272 }
273}
Note: See TracBrowser for help on using the repository browser.