Skip to content

Commit

Permalink
AER-2975 Add error on too many buildings
Browse files Browse the repository at this point in the history
  • Loading branch information
wtenbosch committed Jun 3, 2024
1 parent 7f97105 commit 180fa11
Show file tree
Hide file tree
Showing 11 changed files with 89 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

import nl.overheid.aerius.gml.base.source.ship.v31.GMLInlandShippingSupplier;
import nl.overheid.aerius.shared.domain.geo.ReceptorGridSettings;
import nl.overheid.aerius.shared.domain.v2.building.BuildingLimits;
import nl.overheid.aerius.shared.domain.v2.source.EmissionSourceFeature;
import nl.overheid.aerius.shared.exception.AeriusException;
import nl.overheid.aerius.shared.geometry.EmissionSourceLimits;
Expand Down Expand Up @@ -57,4 +58,9 @@ default EmissionSourceLimits getEmissionSourceGeometryLimits() {
// Added default for backward compatibility. Will be removed when used in Calculator.
return null;
}

/**
* @return The building limits.
*/
BuildingLimits getBuildingLimits();
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
import nl.overheid.aerius.shared.domain.Theme;
import nl.overheid.aerius.shared.domain.scenario.SituationType;
import nl.overheid.aerius.shared.domain.v2.building.BuildingFeature;
import nl.overheid.aerius.shared.domain.v2.building.BuildingLimits;
import nl.overheid.aerius.shared.domain.v2.cimlk.CIMLKCorrection;
import nl.overheid.aerius.shared.domain.v2.cimlk.CIMLKDispersionLineFeature;
import nl.overheid.aerius.shared.domain.v2.cimlk.CIMLKMeasureFeature;
Expand Down Expand Up @@ -75,12 +76,14 @@ public class ImaerImporter {

private final GMLReaderFactory factory;
private final EPSG epsg;
private final EmissionSourceLimits limits;
private final EmissionSourceLimits sourceLimits;
private final BuildingLimits buildingLimits;

public ImaerImporter(final GMLHelper gmlHelper) throws AeriusException {
factory = GMLReaderFactory.getFactory(gmlHelper);
epsg = gmlHelper.getReceptorGridSettings().getEPSG();
limits = gmlHelper.getEmissionSourceGeometryLimits();
sourceLimits = gmlHelper.getEmissionSourceGeometryLimits();
buildingLimits = gmlHelper.getBuildingLimits();
}

/**
Expand Down Expand Up @@ -140,7 +143,7 @@ public void importStream(final InputStream inputStream, final Set<ImportOption>
addCimlkMeasures(reader, importOptions, result, situation);
addCimlkDispersionLines(reader, importOptions, situation);
addCimlkCorrections(reader, importOptions, situation);
addBuildings(reader, importOptions, result, situation);
addBuildings(reader, importOptions, result, situation, buildingLimits);
addDefinitions(reader, importOptions, result, situation);
setCrs(result);

Expand Down Expand Up @@ -189,7 +192,7 @@ private void addEmissionSources(final GMLReader reader, final Set<ImportOption>
EmissionSourceValidator.validateSourcesWithEmissions(sources, result.getExceptions(), result.getWarnings());
}
if (ImportOption.WARNING_ON_GEOMETRY_LIMITS.in(importOptions)) {
result.getWarnings().addAll(EmissionSourceLimitValidator.checkGeometries(sources, limits));
result.getWarnings().addAll(EmissionSourceLimitValidator.checkGeometries(sources, sourceLimits));
}
result.getSituation().getEmissionSourcesList().addAll(sources);
}
Expand Down Expand Up @@ -342,11 +345,11 @@ private static void addCimlkCorrections(final GMLReader reader, final Set<Import
}

private static void addBuildings(final GMLReader reader, final Set<ImportOption> importOptions, final ImportParcel result,
final ScenarioSituation situation) {
final ScenarioSituation situation, final BuildingLimits limits) {
if (ImportOption.INCLUDE_SOURCES.in(importOptions)) {
final List<BuildingFeature> buildings = reader.getBuildings();
if (ImportOption.VALIDATE_SOURCES.in(importOptions)) {
BuildingValidator.validateBuildings(buildings, result.getExceptions(), result.getWarnings());
BuildingValidator.validateBuildings(limits, buildings, result.getExceptions(), result.getWarnings());
}
situation.getBuildingsList().addAll(buildings);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,10 @@
import nl.overheid.aerius.gml.base.conversion.PlanConversion;
import nl.overheid.aerius.shared.domain.Substance;
import nl.overheid.aerius.shared.domain.ops.DiurnalVariation;
import nl.overheid.aerius.shared.domain.v2.building.BuildingLimits;
import nl.overheid.aerius.shared.domain.v2.characteristics.HeatContentType;
import nl.overheid.aerius.shared.domain.v2.characteristics.OPSSourceCharacteristics;
import nl.overheid.aerius.shared.domain.v2.characteristics.adms.ADMSLimits;
import nl.overheid.aerius.shared.domain.v2.geojson.Geometry;
import nl.overheid.aerius.shared.domain.v2.source.road.RoadStandardEmissionFactorsKey;
import nl.overheid.aerius.shared.domain.v2.source.road.RoadStandardsInterpolationValues;
Expand Down Expand Up @@ -1139,4 +1141,8 @@ private Optional<RoadConstructHelper> roadStandard(final RoadStandardEmissionFac
}
}

@Override
public BuildingLimits buildingLimits() {
return ADMSLimits.INSTANCE;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -484,4 +484,9 @@ public double buildingLengthMinimum() {
public double buildingLengthMaximum() {
return SCOPE_BUILDING_LENGTH_MAXIMUM;
}

@Override
public Integer buildingMaximumPerSituation() {
return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,6 @@ default boolean isCircularBuildingSupported() {
double buildingLengthMinimum();

double buildingLengthMaximum();

Integer buildingMaximumPerSituation();
}
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,8 @@ public final class ADMSLimits implements BuildingLimits {
public static final boolean SPATIALLY_VARYING_ROUGHNESS_DEFAULT = true;
public static final boolean ADMS_COMPLEX_TERRAIN_DEFAULT = false;

private static final int ADMS_MAX_BUILDINGS_PER_SITUATION = 50;

public static final ADMSLimits INSTANCE = new ADMSLimits();

private ADMSLimits() {
Expand Down Expand Up @@ -174,4 +176,9 @@ public double buildingLengthMinimum() {
public double buildingLengthMaximum() {
return BUILDING_LENGTH_MAXIMUM;
}

@Override
public Integer buildingMaximumPerSituation() {
return ADMS_MAX_BUILDINGS_PER_SITUATION;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -641,6 +641,13 @@ public enum ImaerExceptionReason implements Reason {
*/
CIRCULAR_BUILDING_INCORRECT_DIAMETER(5243),

/**
* There are more buildings in a situation than the maximum
*
* @param 0 The maximum number of allowed buildings
*/
TOO_MANY_BUILDINGS_IN_SITUATION(5244),

/**
* Value is <= 0.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

import nl.overheid.aerius.shared.domain.v2.building.Building;
import nl.overheid.aerius.shared.domain.v2.building.BuildingFeature;
import nl.overheid.aerius.shared.domain.v2.building.BuildingLimits;
import nl.overheid.aerius.shared.domain.v2.geojson.Point;
import nl.overheid.aerius.shared.domain.v2.geojson.Polygon;
import nl.overheid.aerius.shared.exception.AeriusException;
Expand All @@ -31,13 +32,23 @@ public final class BuildingValidator {
// Util class
}

public static void validateBuildings(final List<BuildingFeature> buildings, final List<AeriusException> errors,
public static void validateBuildings(final BuildingLimits limits, final List<BuildingFeature> buildings, final List<AeriusException> errors,
final List<AeriusException> warnings) {
checkBuildingCount(limits, buildings, errors);
checkBuildingGeometry(buildings, errors);
checkBuildingHeight(buildings, errors, warnings);
checkBuildingDiameter(buildings, errors);
}

private static void checkBuildingCount(final BuildingLimits limits, final List<BuildingFeature> buildings, final List<AeriusException> errors) {
if (limits.buildingMaximumPerSituation() == null) {
return;
}
if (buildings.size() > limits.buildingMaximumPerSituation()) {
errors.add(new AeriusException(ImaerExceptionReason.TOO_MANY_BUILDINGS_IN_SITUATION, String.valueOf(limits.buildingMaximumPerSituation())));
}
}

private static void checkBuildingGeometry(final List<BuildingFeature> buildings, final List<AeriusException> errors) {
for (final BuildingFeature feature : buildings) {
// Only polygon and point geometries are supported.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ private ScenarioSituationValidator() {
*/
public static void validateSituation(final ScenarioSituation situation, final ValidationHelper validationHelper) throws AeriusException {
validateSources(situation.getEmissionSourcesList(), validationHelper);
validateBuildings(situation.getBuildingsList());
validateBuildings(situation.getBuildingsList(), validationHelper);
validateCimlkMeasures(situation.getCimlkMeasuresList());
validateDefinitions(situation.getDefinitions());
}
Expand All @@ -57,9 +57,9 @@ public static void validateSources(final List<EmissionSourceFeature> sources, fi
}
}

public static void validateBuildings(final List<BuildingFeature> buildings) throws AeriusException {
public static void validateBuildings(final List<BuildingFeature> buildings, final ValidationHelper validationHelper) throws AeriusException {
final List<AeriusException> errors = new ArrayList<>();
BuildingValidator.validateBuildings(buildings, errors, new ArrayList<>());
BuildingValidator.validateBuildings(validationHelper.buildingLimits(), buildings, errors, new ArrayList<>());
if (!errors.isEmpty()) {
throw errors.get(0);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@
*/
package nl.overheid.aerius.validation;

import nl.overheid.aerius.shared.domain.v2.building.BuildingLimits;

/**
* Interface to help with validating sources.
* Interface to help with validating sources and buildings.
*/
public interface ValidationHelper {

Expand All @@ -40,4 +42,6 @@ default FarmAnimalHousingValidationHelper farmAnimalHousingValidation() {
InlandShippingValidationHelper inlandShippingValidation();

MaritimeShippingValidationHelper maritimeShippingValidation();

BuildingLimits buildingLimits();
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,14 @@

import java.util.ArrayList;
import java.util.List;
import java.util.stream.IntStream;

import org.junit.jupiter.api.Test;

import nl.overheid.aerius.shared.domain.v2.building.Building;
import nl.overheid.aerius.shared.domain.v2.building.BuildingFeature;
import nl.overheid.aerius.shared.domain.v2.building.BuildingLimits;
import nl.overheid.aerius.shared.domain.v2.characteristics.adms.ADMSLimits;
import nl.overheid.aerius.shared.domain.v2.geojson.LineString;
import nl.overheid.aerius.shared.domain.v2.geojson.Point;
import nl.overheid.aerius.shared.domain.v2.geojson.Polygon;
Expand All @@ -34,6 +37,7 @@

class BuildingValidatorTest {

private static final BuildingLimits BUILDING_LIMITS = ADMSLimits.INSTANCE;
private static final String BUILDING_ID = "OurBuildingId";
private static final String BUILDING_LABEL = "One More Building";

Expand All @@ -44,7 +48,7 @@ void testValidBuilding() {
final List<AeriusException> errors = new ArrayList<>();
final List<AeriusException> warnings = new ArrayList<>();

BuildingValidator.validateBuildings(List.of(building), errors, warnings);
BuildingValidator.validateBuildings(BUILDING_LIMITS, List.of(building), errors, warnings);

assertEquals(List.of(), errors, "No errors");
assertEquals(List.of(), warnings, "No warnings");
Expand All @@ -58,7 +62,7 @@ void testBuildingLineStringGeometry() {
final List<AeriusException> errors = new ArrayList<>();
final List<AeriusException> warnings = new ArrayList<>();

BuildingValidator.validateBuildings(List.of(building), errors, warnings);
BuildingValidator.validateBuildings(BUILDING_LIMITS, List.of(building), errors, warnings);

assertEquals(1, errors.size(), "Number of errors");
assertEquals(ImaerExceptionReason.GML_GEOMETRY_NOT_PERMITTED, errors.get(0).getReason(), "Error reason");
Expand All @@ -73,7 +77,7 @@ void testBuildingZeroHeight() {
final List<AeriusException> errors = new ArrayList<>();
final List<AeriusException> warnings = new ArrayList<>();

BuildingValidator.validateBuildings(List.of(building), errors, warnings);
BuildingValidator.validateBuildings(BUILDING_LIMITS, List.of(building), errors, warnings);

assertEquals(List.of(), errors, "No errors");
assertEquals(1, warnings.size(), "Number of warnings");
Expand All @@ -88,7 +92,7 @@ void testBuildingNegativeHeight() {
final List<AeriusException> errors = new ArrayList<>();
final List<AeriusException> warnings = new ArrayList<>();

BuildingValidator.validateBuildings(List.of(building), errors, warnings);
BuildingValidator.validateBuildings(BUILDING_LIMITS, List.of(building), errors, warnings);

assertEquals(1, errors.size(), "Number of errors");
assertEquals(ImaerExceptionReason.BUILDING_HEIGHT_TOO_LOW, errors.get(0).getReason(), "Error reason");
Expand All @@ -105,7 +109,7 @@ void testValidCircularBuilding() {
final List<AeriusException> errors = new ArrayList<>();
final List<AeriusException> warnings = new ArrayList<>();

BuildingValidator.validateBuildings(List.of(building), errors, warnings);
BuildingValidator.validateBuildings(BUILDING_LIMITS, List.of(building), errors, warnings);

assertEquals(List.of(), errors, "No errors");
assertEquals(List.of(), warnings, "No warnings");
Expand All @@ -120,14 +124,31 @@ void testCircularBuildingIncorrectDiameter() {
final List<AeriusException> errors = new ArrayList<>();
final List<AeriusException> warnings = new ArrayList<>();

BuildingValidator.validateBuildings(List.of(building), errors, warnings);
BuildingValidator.validateBuildings(BUILDING_LIMITS, List.of(building), errors, warnings);

assertEquals(1, errors.size(), "Number of errors");
assertEquals(ImaerExceptionReason.CIRCULAR_BUILDING_INCORRECT_DIAMETER, errors.get(0).getReason(), "Error reason");
assertArrayEquals(new Object[] {BUILDING_LABEL}, errors.get(0).getArgs(), "Arguments");
assertEquals(List.of(), warnings, "No warnings");
}

@Test
void testTooManyBuildings() {
final BuildingFeature building = createBuilding(1);
building.setGeometry(new Point(0, 0));
building.getProperties().setDiameter(1);

final List<AeriusException> errors = new ArrayList<>();
final List<AeriusException> warnings = new ArrayList<>();

BuildingValidator.validateBuildings(BUILDING_LIMITS, IntStream.range(1, 80).mapToObj(s -> building).toList(), errors, warnings);

assertEquals(1, errors.size(), "Number of errors");
assertEquals(ImaerExceptionReason.TOO_MANY_BUILDINGS_IN_SITUATION, errors.get(0).getReason(), "Error reason");
assertArrayEquals(new Object[] {"50"}, errors.get(0).getArgs(), "Arguments");
assertEquals(List.of(), warnings, "No warnings");
}

private static BuildingFeature createBuilding(final double height) {
final BuildingFeature feature = new BuildingFeature();
feature.setGeometry(new Polygon());
Expand Down

0 comments on commit 180fa11

Please sign in to comment.