/*-
* 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;
}
}