/*- * Copyright 2020 Beuth Hochschule für Technik Berlin, Hochschule für Technik Stuttgart * * This file is part of CityDoctor2. * * CityDoctor2 is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * CityDoctor2 is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with CityDoctor2. If not, see . */ package de.hft.stuttgart.citydoctor2.checks; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.ServiceLoader; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import de.hft.stuttgart.citydoctor2.check.Check; import de.hft.stuttgart.citydoctor2.check.CheckId; import de.hft.stuttgart.citydoctor2.check.Requirement; import de.hft.stuttgart.citydoctor2.checks.geometry.AllPolygonsWrongOrientationCheck; import de.hft.stuttgart.citydoctor2.checks.geometry.DuplicatePointsCheck; import de.hft.stuttgart.citydoctor2.checks.geometry.HoleOutsideCheck; import de.hft.stuttgart.citydoctor2.checks.geometry.InteriorDisconnectedCheck; import de.hft.stuttgart.citydoctor2.checks.geometry.ManifoldVertexCheck; import de.hft.stuttgart.citydoctor2.checks.geometry.MultipleConnectedComponentCheck; import de.hft.stuttgart.citydoctor2.checks.geometry.NestedRingsCheck; import de.hft.stuttgart.citydoctor2.checks.geometry.NonManifoldEdgeCheck; import de.hft.stuttgart.citydoctor2.checks.geometry.PlanarCheck; import de.hft.stuttgart.citydoctor2.checks.geometry.PolygonIntersectingRingsCheck; import de.hft.stuttgart.citydoctor2.checks.geometry.PolygonSameOrientationCheck; import de.hft.stuttgart.citydoctor2.checks.geometry.PolygonWrongOrientationCheck; import de.hft.stuttgart.citydoctor2.checks.geometry.RingNotClosedCheck; import de.hft.stuttgart.citydoctor2.checks.geometry.RingSelfIntCheck; import de.hft.stuttgart.citydoctor2.checks.geometry.SolidNotClosedCheck; import de.hft.stuttgart.citydoctor2.checks.geometry.SolidSelfIntCheck; import de.hft.stuttgart.citydoctor2.checks.geometry.TooFewPointsCheck; import de.hft.stuttgart.citydoctor2.checks.geometry.TooFewPolygonsCheck; import de.hft.stuttgart.citydoctor2.checks.semantics.IsCeilingCheck; import de.hft.stuttgart.citydoctor2.checks.semantics.IsFloorCheck; import de.hft.stuttgart.citydoctor2.checks.semantics.IsGroundCheck; import de.hft.stuttgart.citydoctor2.checks.semantics.IsWallCheck; import de.hft.stuttgart.citydoctor2.checks.semantics.PolygonWithoutSurfaceCheck; import de.hft.stuttgart.citydoctor2.checks.semantics.RoofSurfaceUnfragmentedCheck; import de.hft.stuttgart.citydoctor2.utils.Localization; /** * Container class for all checks. If new checks are added, they need to be * published here to be accessed by the checker instance. * * @author Matthias Betz * */ public class Checks { public static final double MIN_VERTEX_DISTANCE_DEFAULT = 0.0001; private static final Logger logger = LogManager.getLogger(Checks.class); private static List checkPrototypes; private static Map prototypeMap; private static Map availableRequirements; private Map checkMap; static { checkPrototypes = new ArrayList<>(); prototypeMap = new HashMap<>(); // add new checks here // ring checks publish(new TooFewPointsCheck()); publish(new RingNotClosedCheck()); publish(new DuplicatePointsCheck()); publish(new RingSelfIntCheck()); // polygon checks publish(new PlanarCheck()); publish(new PolygonSameOrientationCheck()); publish(new HoleOutsideCheck()); publish(new NestedRingsCheck()); publish(new PolygonIntersectingRingsCheck()); publish(new InteriorDisconnectedCheck()); // solid checks publish(new MultipleConnectedComponentCheck()); publish(new SolidNotClosedCheck()); publish(new NonManifoldEdgeCheck()); publish(new PolygonWrongOrientationCheck()); publish(new AllPolygonsWrongOrientationCheck()); publish(new TooFewPolygonsCheck()); publish(new ManifoldVertexCheck()); publish(new SolidSelfIntCheck()); // semantic checks publish(new IsWallCheck()); publish(new IsFloorCheck()); publish(new IsCeilingCheck()); publish(new IsGroundCheck()); publish(new RoofSurfaceUnfragmentedCheck()); publish(new PolygonWithoutSurfaceCheck()); // load checks from service loader ServiceLoader checkLoader = ServiceLoader.load(Check.class); for (Check c : checkLoader) { publish(c); } } /** * Creates new checks for every available check prototype and stores them in * this container. Access the checks with {@link Checks#getCheckForId(CheckId)}. */ public Checks() { checkMap = new HashMap<>(); for (CheckPrototype proto : checkPrototypes) { Check check = proto.createCheck(); checkMap.put(check.getCheckId(), check); } } private static Map collectRequirements() { Map requirements = new HashMap<>(); for (CheckPrototype proto : checkPrototypes) { for (Requirement req : proto.checksRequirements()) { requirements.put(req.getId(), req); } } return requirements; } /** * Gets all requirements for which there are checks that can verify the * requirements. This is dependent on the available checks as only the checks * know which requirements they check. * * @return a set of available requirements */ public static Map getAvailableRequirements() { if (availableRequirements == null) { availableRequirements = collectRequirements(); } return availableRequirements; } private static void publish(Check check) { CheckPrototype prototype = new CheckPrototype(check); checkPrototypes.add(prototype); prototypeMap.put(prototype.getCheckId(), prototype); } /** * * @return All available checks as prototypes, where they can be instantiated. */ public static List getCheckPrototypes() { return checkPrototypes; } /** * * @param key The check ID * @return The prototype for the given ID or null if there is no such prototype. */ public static CheckPrototype getCheckPrototypeForId(CheckId key) { return prototypeMap.get(key); } /** * * @param id The check ID * @return The check for the check ID or null if it does not exist */ public Check getCheckForId(CheckId id) { Check c = checkMap.get(id); if (c == null && logger.isWarnEnabled()) { logger.warn(Localization.getText("Checks.missingCheck"), id); } return c; } }