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

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

see #11889, see #11924, see #13387 - use backported versions of Math.toDegrees/toRadians (more accurate and faster) - to revert when migrating to Java 9

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