001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.data.validation.tests; 003 004import static org.openstreetmap.josm.tools.I18n.tr; 005 006import java.util.Arrays; 007import java.util.List; 008 009import org.openstreetmap.josm.actions.OrthogonalizeAction; 010import org.openstreetmap.josm.actions.OrthogonalizeAction.InvalidUserInputException; 011import org.openstreetmap.josm.data.osm.Node; 012import org.openstreetmap.josm.data.osm.Way; 013import org.openstreetmap.josm.data.validation.Severity; 014import org.openstreetmap.josm.data.validation.Test; 015import org.openstreetmap.josm.data.validation.TestError; 016import org.openstreetmap.josm.gui.progress.ProgressMonitor; 017import org.openstreetmap.josm.spi.preferences.Config; 018import org.openstreetmap.josm.tools.Logging; 019import org.openstreetmap.josm.tools.Pair; 020 021/** 022 * Checks for buildings with angles close to right angle. 023 * 024 * @author marxin 025 * @since 13670 026 */ 027public class RightAngleBuildingTest extends Test { 028 029 /** Maximum angle difference from right angle that is considered as invalid. */ 030 protected double maxAngleDelta; 031 032 /** Minimum angle difference from right angle that is considered as invalid. */ 033 protected double minAngleDelta; 034 035 /** 036 * Constructs a new {@code RightAngleBuildingTest} test. 037 */ 038 public RightAngleBuildingTest() { 039 super(tr("Almost right angle buildings"), 040 tr("Checks for buildings that have angles close to right angle and are not orthogonalized.")); 041 } 042 043 @Override 044 public void visit(Way w) { 045 if (!w.isUsable() || !w.isClosed() || !isBuilding(w) || !IN_DOWNLOADED_AREA_STRICT.test(w)) return; 046 047 List<Pair<Double, Node>> angles = w.getAngles(); 048 for (Pair<Double, Node> pair: angles) { 049 if (checkAngle(pair.a)) { 050 TestError.Builder builder = TestError.builder(this, Severity.OTHER, 3701) 051 .message(tr("Building with an almost square angle")) 052 .primitives(w) 053 .highlight(pair.b); 054 builder.fix(() -> { 055 try { 056 return OrthogonalizeAction.orthogonalize(Arrays.asList(w, pair.b)); 057 } catch (InvalidUserInputException e) { 058 Logging.warn(e); 059 return null; 060 } 061 }); 062 errors.add(builder.build()); 063 return; 064 } 065 } 066 } 067 068 @Override 069 public void startTest(ProgressMonitor monitor) { 070 super.startTest(monitor); 071 maxAngleDelta = Config.getPref().getDouble("validator.RightAngleBuilding.maximumDelta", 10.0); 072 minAngleDelta = Config.getPref().getDouble("validator.RightAngleBuilding.minimumDelta", 1.0); 073 } 074 075 private boolean checkAngle(double angle) { 076 double difference = Math.abs(angle - 90); 077 return difference > minAngleDelta && difference < maxAngleDelta; 078 } 079}