Ticket #18127: 18127.8.patch

File 18127.8.patch, 13.5 KB (added by taylor.smock, 7 years ago)

FIx ant pmd checkstyle issues

Line 
1Index: src/org/openstreetmap/josm/data/validation/OsmValidator.java
2===================================================================
3--- src/org/openstreetmap/josm/data/validation/OsmValidator.java (revision 15353)
4+++ src/org/openstreetmap/josm/data/validation/OsmValidator.java (working copy)
5@@ -61,6 +61,7 @@
6 import org.openstreetmap.josm.data.validation.tests.RelationChecker;
7 import org.openstreetmap.josm.data.validation.tests.RightAngleBuildingTest;
8 import org.openstreetmap.josm.data.validation.tests.SelfIntersectingWay;
9+import org.openstreetmap.josm.data.validation.tests.SharpAngles;
10 import org.openstreetmap.josm.data.validation.tests.SimilarNamedWays;
11 import org.openstreetmap.josm.data.validation.tests.TagChecker;
12 import org.openstreetmap.josm.data.validation.tests.TurnrestrictionTest;
13@@ -148,6 +150,8 @@
14 LongSegment.class, // 3500 .. 3599
15 PublicTransportRouteTest.class, // 3600 .. 3699
16 RightAngleBuildingTest.class, // 3700 .. 3799
17+ SharpAngles.class, // 3800 .. 3899
18 };
19
20 /**
21Index: src/org/openstreetmap/josm/data/validation/tests/SharpAngles.java
22===================================================================
23--- src/org/openstreetmap/josm/data/validation/tests/SharpAngles.java (nonexistent)
24+++ src/org/openstreetmap/josm/data/validation/tests/SharpAngles.java (working copy)
25@@ -0,0 +1,196 @@
26+// License: GPL. For details, see LICENSE file.
27+package org.openstreetmap.josm.data.validation.tests;
28+
29+import static org.openstreetmap.josm.tools.I18n.tr;
30+
31+import java.util.ArrayList;
32+import java.util.Collection;
33+import java.util.Collections;
34+import java.util.Comparator;
35+import java.util.LinkedHashMap;
36+import java.util.List;
37+import java.util.Map;
38+import java.util.Map.Entry;
39+import java.util.Optional;
40+import java.util.TreeSet;
41+
42+import org.openstreetmap.josm.data.coor.EastNorth;
43+import org.openstreetmap.josm.data.osm.Node;
44+import org.openstreetmap.josm.data.osm.OsmPrimitive;
45+import org.openstreetmap.josm.data.osm.Way;
46+import org.openstreetmap.josm.data.osm.WaySegment;
47+import org.openstreetmap.josm.data.validation.Severity;
48+import org.openstreetmap.josm.data.validation.Test;
49+import org.openstreetmap.josm.data.validation.TestError;
50+import org.openstreetmap.josm.gui.progress.ProgressMonitor;
51+import org.openstreetmap.josm.tools.Geometry;
52+import org.openstreetmap.josm.tools.Logging;
53+
54+/**
55+ * Find highways that have sharp angles
56+ * @author Taylor Smock
57+ * @since xxx
58+ */
59+public class SharpAngles extends Test {
60+ private static final int SHARPANGLESCODE = 3800;
61+ /** The code for a sharp angle */
62+ protected static final int SHARP_ANGLES = SHARPANGLESCODE + 0;
63+ /** The maximum angle for sharp angles */
64+ protected double maxAngle = 45.0; // degrees
65+ /** The length that at least one way segment must be shorter than */
66+ protected double maxLength = 10.0; // meters
67+ /** The stepping points for severity */
68+ protected Map<Double, Severity> severityBreakPoints = new LinkedHashMap<>();
69+ /** Specific highway types to ignore */
70+ protected Collection<String> ignoreHighways = new TreeSet<>();
71+
72+ ArrayList<Way> allWays;
73+ /**
74+ * Construct a new {@code IntersectionIssues} object
75+ */
76+ public SharpAngles() {
77+ super(tr("Sharp angles"), tr("Check for sharp angles on roads"));
78+ setBreakPoints();
79+ addIgnoredHighway("rest_area");
80+ addIgnoredHighway("platform");
81+ addIgnoredHighway("services");
82+ addIgnoredHighway("via_ferrata"); // mountainside paths
83+ }
84+
85+ @Override
86+ public void startTest(ProgressMonitor monitor) {
87+ super.startTest(monitor);
88+ allWays = new ArrayList<>();
89+ }
90+
91+ @Override
92+ public void endTest() {
93+ Way pWay = null;
94+ try {
95+ for (Way way : allWays) {
96+ pWay = way;
97+ checkWayForSharpAngles(way);
98+ }
99+ } catch (Exception e) {
100+ if (pWay != null) {
101+ Logging.debug("Way https://osm.org/way/{0} caused an error ({1})", pWay.getOsmId(), e);
102+ }
103+ Logging.warn(e);
104+ }
105+ allWays = null;
106+ super.endTest();
107+ }
108+
109+ @Override
110+ public void visit(Way way) {
111+ if (!way.isUsable()) return;
112+ if (way.hasKey("highway") && !way.hasTag("area", "yes") &&
113+ !ignoreHighways.contains(way.get("highway"))) {
114+ allWays.add(way);
115+ }
116+ }
117+
118+ /**
119+ * Check nodes in a way for sharp angles
120+ * @param way A way to check for sharp angles
121+ */
122+ public void checkWayForSharpAngles(Way way) {
123+ Node node1 = null;
124+ Node node2 = null;
125+ Node node3 = null;
126+ int i = -2;
127+ for (Node node : way.getNodes()) {
128+ node1 = node2;
129+ node2 = node3;
130+ node3 = node;
131+ checkAngle(node1, node2, node3, i, way, false);
132+ i++;
133+ }
134+ if (way.isClosed() && way.getNodesCount() > 2) {
135+ node1 = node2;
136+ node2 = node3;
137+ // Get the second node, not the first node, since a closed way has first node == second node
138+ node3 = way.getNode(1);
139+ checkAngle(node1, node2, node3, i, way, true);
140+ }
141+ }
142+
143+ private void checkAngle(Node node1, Node node2, Node node3, int i, Way way, boolean last) {
144+ if (node1 == null || node2 == null || node3 == null) return;
145+ EastNorth n1 = node1.getEastNorth();
146+ EastNorth n2 = node2.getEastNorth();
147+ EastNorth n3 = node3.getEastNorth();
148+ double angle = Math.toDegrees(Math.abs(Geometry.getCornerAngle(n1, n2, n3)));
149+ if (angle < maxAngle) {
150+ processSharpAngleForErrorCreation(angle, i, way, last, node2);
151+ }
152+ }
153+
154+ private void processSharpAngleForErrorCreation(double angle, int i, Way way, boolean last, Node pointNode) {
155+ List<WaySegment> waysegmentList = new ArrayList<>();
156+ waysegmentList.add(new WaySegment(way, i));
157+ if (last) {
158+ waysegmentList.add(new WaySegment(way, 0));
159+ } else {
160+ waysegmentList.add(new WaySegment(way, i+1));
161+ }
162+ Optional<WaySegment> possibleShortSegment = waysegmentList.stream()
163+ .min(Comparator.comparing(segment -> segment.toWay().getLength()));
164+ if (possibleShortSegment.isPresent() && possibleShortSegment.get().toWay().getLength() < maxLength) {
165+ createNearlyOverlappingError(angle, Collections.singleton(way), pointNode);
166+ }
167+ }
168+
169+ private void createNearlyOverlappingError(double angle,
170+ Collection<? extends OsmPrimitive> primitiveIssues, OsmPrimitive primitive) {
171+ TestError.Builder testError = TestError.builder(this, getSeverity(angle), SHARP_ANGLES)
172+ .primitives(primitiveIssues)
173+ .highlight(primitive)
174+ .message(tr("Sharp angle"));
175+ errors.add(testError.build());
176+ }
177+
178+ private Severity getSeverity(double angle) {
179+ Severity rSeverity = Severity.OTHER;
180+ for (Entry<Double, Severity> entry : severityBreakPoints.entrySet()) {
181+ if (angle < entry.getKey()) {
182+ rSeverity = entry.getValue();
183+ }
184+ }
185+ return rSeverity;
186+ }
187+
188+ /**
189+ * Set the maximum length for the shortest segment
190+ * @param length The max length in meters
191+ */
192+ public void setMaxLength(double length) {
193+ maxLength = length;
194+ }
195+
196+ /**
197+ * Add a highway to ignore
198+ * @param highway The highway type to ignore (e.g., if you want to ignore residential roads, use "residential")
199+ */
200+ public void addIgnoredHighway(String highway) {
201+ ignoreHighways.add(highway);
202+ }
203+
204+ /**
205+ * Set the maximum angle
206+ * @param angle The maximum angle in degrees.
207+ */
208+ public void setMaxAngle(double angle) {
209+ maxAngle = angle;
210+ setBreakPoints();
211+ }
212+
213+ /**
214+ * Set the breakpoints for the test
215+ */
216+ private void setBreakPoints() {
217+ severityBreakPoints.put(maxAngle, Severity.OTHER);
218+ severityBreakPoints.put(maxAngle * 2 / 3, Severity.WARNING);
219+ severityBreakPoints.put(maxAngle / 3, Severity.ERROR);
220+ }
221+}
222Index: test/unit/org/openstreetmap/josm/data/validation/tests/SharpAnglesTest.java
223===================================================================
224--- test/unit/org/openstreetmap/josm/data/validation/tests/SharpAnglesTest.java (nonexistent)
225+++ test/unit/org/openstreetmap/josm/data/validation/tests/SharpAnglesTest.java (working copy)
226@@ -0,0 +1,145 @@
227+// License: GPL. For details, see LICENSE file.
228+package org.openstreetmap.josm.data.validation.tests;
229+
230+import org.junit.Assert;
231+import org.junit.Before;
232+import org.junit.Test;
233+import org.openstreetmap.josm.JOSMFixture;
234+import org.openstreetmap.josm.TestUtils;
235+import org.openstreetmap.josm.data.coor.LatLon;
236+import org.openstreetmap.josm.data.osm.Node;
237+import org.openstreetmap.josm.data.osm.Way;
238+
239+/**
240+ * JUnit Test of the Sharp Angles validation test.
241+ */
242+
243+public class SharpAnglesTest {
244+ private SharpAngles angles;
245+
246+ /**
247+ * Setup test.
248+ * @throws Exception if an error occurs
249+ */
250+ @Before
251+ public void setUp() throws Exception {
252+ JOSMFixture.createUnitTestFixture().init();
253+ angles = new SharpAngles();
254+ angles.initialize();
255+ angles.startTest(null);
256+ }
257+
258+ /**
259+ * Check a closed loop with no sharp angles
260+ */
261+ @Test
262+ public void closedLoopNoSharpAngles() {
263+ Way way = TestUtils.newWay("highway=residential",
264+ new Node(new LatLon(0, 0)), new Node(new LatLon(0.1, 0.1)),
265+ new Node(new LatLon(0.1, -0.2)), new Node(new LatLon(-0.1, -0.1)));
266+ way.addNode(way.firstNode());
267+ angles.visit(way);
268+ angles.endTest();
269+ Assert.assertEquals(0, angles.getErrors().size());
270+ }
271+
272+ /**
273+ * Check a closed loop with a sharp angle
274+ */
275+ @Test
276+ public void closedLoopSharpAngles() {
277+ Way way = TestUtils.newWay("highway=residential",
278+ new Node(new LatLon(0, 0)), new Node(new LatLon(0.1, 0.1)),
279+ new Node(new LatLon(0.1, -0.2)));
280+ way.addNode(way.firstNode());
281+ angles.setMaxLength(Double.MAX_VALUE);
282+ angles.visit(way);
283+ angles.endTest();
284+ Assert.assertEquals(1, angles.getErrors().size());
285+ }
286+
287+ /**
288+ * Check a way for multiple sharp angles
289+ */
290+ @Test
291+ public void testMultipleSharpAngles() {
292+ Way way = TestUtils.newWay("highway=residential",
293+ new Node(new LatLon(0.005069377713748322, -0.0014832642674429382)),
294+ new Node(new LatLon(0.005021097951663415, 0.0008636686205880686)),
295+ new Node(new LatLon(0.005085470967776624, -0.00013411313295197088)),
296+ new Node(new LatLon(0.005031826787678042, 0.0020116540789620915)));
297+ angles.setMaxLength(Double.MAX_VALUE);
298+ angles.visit(way);
299+ angles.endTest();
300+ Assert.assertEquals(2, angles.getErrors().size());
301+ }
302+
303+ /**
304+ * Check for no sharp angles
305+ */
306+ @Test
307+ public void testNoSharpAngles() {
308+ Way way = TestUtils.newWay("highway=residential",
309+ new Node(new LatLon(0, 0)), new Node(new LatLon(0.1, 0.1)),
310+ new Node(new LatLon(0.2, 0.3)), new Node(new LatLon(0.3, 0.1)));
311+ angles.visit(way);
312+ angles.endTest();
313+ Assert.assertEquals(0, angles.getErrors().size());
314+ }
315+
316+ /**
317+ * Ensure that we aren't accidentally using the same node twice.
318+ * This was found during initial testing. See way 10041221 (on 20190914)
319+ */
320+ @Test
321+ public void testCheckBadAnglesFromSameNodeTwice() {
322+ Way way = TestUtils.newWay("highway=service oneway=yes",
323+ new Node(new LatLon(52.8903308, 8.4302322)),
324+ new Node(new LatLon(52.8902468, 8.4302138)),
325+ new Node(new LatLon(52.8902191, 8.4302282)),
326+ new Node(new LatLon(52.8901155, 8.4304753)),
327+ new Node(new LatLon(52.8900669, 8.430763)),
328+ new Node(new LatLon(52.8901138, 8.4308262)),
329+ new Node(new LatLon(52.8902482, 8.4307568)));
330+ way.addNode(way.firstNode());
331+ angles.visit(way);
332+ angles.endTest();
333+ Assert.assertEquals(0, angles.getErrors().size());
334+ }
335+
336+ /**
337+ * Check that special cases are ignored
338+ */
339+ @Test
340+ public void testIgnoredCases() {
341+ Way way = TestUtils.newWay("highway=residential",
342+ new Node(new LatLon(0, 0)), new Node(new LatLon(0.1, 0.1)),
343+ new Node(new LatLon(0, 0.01)));
344+ angles.setMaxLength(Double.MAX_VALUE);
345+ angles.visit(way);
346+ angles.endTest();
347+ Assert.assertEquals(1, angles.getErrors().size());
348+
349+ way.put("highway", "rest_area");
350+ angles.startTest(null);
351+ angles.visit(way);
352+ angles.endTest();
353+ Assert.assertEquals(0, angles.getErrors().size());
354+
355+ way.put("highway", "residential");
356+ angles.startTest(null);
357+ angles.visit(way);
358+ angles.endTest();
359+ Assert.assertEquals(1, angles.getErrors().size());
360+ way.put("area", "yes");
361+ angles.startTest(null);
362+ angles.visit(way);
363+ angles.endTest();
364+ Assert.assertEquals(0, angles.getErrors().size());
365+ way.put("area", "no");
366+ angles.startTest(null);
367+ angles.visit(way);
368+ angles.endTest();
369+ Assert.assertEquals(1, angles.getErrors().size());
370+ }
371+}