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.List;
007
008import org.openstreetmap.josm.data.osm.Node;
009import org.openstreetmap.josm.data.osm.Way;
010import org.openstreetmap.josm.data.validation.Severity;
011import org.openstreetmap.josm.data.validation.Test;
012import org.openstreetmap.josm.data.validation.TestError;
013import org.openstreetmap.josm.gui.progress.ProgressMonitor;
014import org.openstreetmap.josm.spi.preferences.Config;
015import org.openstreetmap.josm.tools.Pair;
016
017/**
018 * Checks for buildings with angles close to right angle.
019 *
020 * @author marxin
021 * @since 13670
022 */
023public class RightAngleBuildingTest extends Test {
024
025    /** Maximum angle difference from right angle that is considered as invalid. */
026    protected double maxAngleDelta;
027
028    /** Minimum angle difference from right angle that is considered as invalid. */
029    protected double minAngleDelta;
030
031    /**
032     * Constructs a new {@code RightAngleBuildingTest} test.
033     */
034    public RightAngleBuildingTest() {
035        super(tr("Almost right angle buildings"),
036                tr("Checks for buildings that have angles close to right angle and are not orthogonalized."));
037    }
038
039    @Override
040    public void visit(Way w) {
041        if (!w.isUsable() || !w.isClosed() || !isBuilding(w) || !IN_DOWNLOADED_AREA_STRICT.test(w)) return;
042
043        List<Pair<Double, Node>> angles = w.getAngles();
044        for (Pair<Double, Node> pair: angles) {
045            if (checkAngle(pair.a)) {
046                TestError.Builder builder = TestError.builder(this, Severity.OTHER, 3701)
047                                                     .message(tr("Building with an almost square angle"))
048                                                     .primitives(w)
049                                                     .highlight(pair.b);
050                errors.add(builder.build());
051                return;
052            }
053        }
054    }
055
056    @Override
057    public void startTest(ProgressMonitor monitor) {
058        super.startTest(monitor);
059        maxAngleDelta = Config.getPref().getDouble("validator.RightAngleBuilding.maximumDelta", 10.0);
060        minAngleDelta = Config.getPref().getDouble("validator.RightAngleBuilding.minimumDelta", 1.0);
061    }
062
063    private boolean checkAngle(double angle) {
064        double difference = Math.abs(angle - 90);
065        return difference > minAngleDelta && difference < maxAngleDelta;
066    }
067}