/*-
* 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.writer;
import java.io.File;
import java.time.ZonedDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicInteger;
import org.citygml4j.core.model.CityGMLVersion;
import org.citygml4j.core.model.core.AbstractCityObjectProperty;
import org.citygml4j.core.model.core.AbstractFeatureProperty;
import org.citygml4j.core.model.core.CityModel;
import org.citygml4j.core.util.geometry.GeometryFactory;
import org.citygml4j.xml.CityGMLContext;
import org.citygml4j.xml.writer.CityGMLOutputFactory;
import org.citygml4j.xml.writer.CityGMLWriteException;
import org.citygml4j.xml.writer.CityGMLWriter;
import de.hft.stuttgart.citydoctor2.check.CheckError;
import de.hft.stuttgart.citydoctor2.check.ErrorId;
import de.hft.stuttgart.citydoctor2.datastructure.CityDoctorModel;
import de.hft.stuttgart.citydoctor2.datastructure.CityObject;
import de.hft.stuttgart.citydoctor2.exceptions.CityDoctorWriteException;
import de.hft.stuttgart.citydoctor2.parser.CityGmlParser;
import de.hft.stuttgart.citydoctor2.utils.Localization;
import de.hft.stuttgart.citydoctor2.utils.QualityADEUtils;
import de.hft.stuttgart.quality.QualityADEModule;
import de.hft.stuttgart.quality.model.properties.ErrorProperty;
import de.hft.stuttgart.quality.model.properties.FeatureStatisticsProperty;
import de.hft.stuttgart.quality.model.properties.StatisticsProperty;
import de.hft.stuttgart.quality.model.properties.ValidationPlanProperty;
import de.hft.stuttgart.quality.model.types.FeatureStatistics;
import de.hft.stuttgart.quality.model.types.Statistics;
import de.hft.stuttgart.quality.model.types.Validation;
public class CityGMLWriterUtils {
public static void writeCityModel(String file, CityDoctorModel model) throws CityDoctorWriteException {
CityGMLContext gmlContext = CityGmlParser.getContext();
CityModel cModel = model.getCityModel();
CityGMLOutputFactory factory = gmlContext.createCityGMLOutputFactory(CityGMLVersion.v2_0);
try (CityGMLWriter writer = factory.createCityGMLWriter(new File(file))) {
writer.withIndent(" ");
writer.withDefaultPrefixes();
writer.withDefaultSchemaLocations();
Validation val = null;
if (model.isValidated()) {
writer.withPrefix("qual", QualityADEModule.NAMESPACE_URI);
writer.withSchemaLocation(QualityADEModule.NAMESPACE_URI,
QualityADEModule.NAMESPACE_URI + "/qualityAde.xsd");
// create new quality ade validation datastructures
val = createValidation(model);
// add to city model
cModel.getFeatureMembers().add(new AbstractFeatureProperty(val));
}
GeometryFactory gmlFactory = GeometryFactory.newInstance();
storeCityObjects(model.getBuildings(), gmlFactory, model, cModel, val);
storeCityObjects(model.getVegetation(), gmlFactory, model, cModel, val);
storeCityObjects(model.getBridges(), gmlFactory, model, cModel, val);
storeCityObjects(model.getLand(), gmlFactory, model, cModel, val);
storeCityObjects(model.getTransportation(), gmlFactory, model, cModel, val);
storeCityObjects(model.getWater(), gmlFactory, model, cModel, val);
writer.write(cModel);
} catch (CityGMLWriteException e) {
throw new CityDoctorWriteException(e);
}
}
private static Validation createValidation(CityDoctorModel model) {
Validation val = new Validation();
val.setId("CD" + UUID.randomUUID().toString());
val.setValidationDate(ZonedDateTime.now());
val.setValidationSoftware("CityDoctor " + Localization.getText(Localization.VERSION));
Statistics statistics = new Statistics();
Set errors = model.collectErrors();
Map errorCount = new HashMap<>();
for (CheckError e : errors) {
errorCount.compute(e.getErrorId(), (k, v) -> {
if (v == null) {
return new AtomicInteger(1);
}
v.incrementAndGet();
return v;
});
}
for (Entry e : errorCount.entrySet()) {
de.hft.stuttgart.quality.model.types.Error stats = new de.hft.stuttgart.quality.model.types.Error();
stats.setOccurrences(e.getValue().get());
de.hft.stuttgart.quality.model.enums.ErrorId adeId = QualityADEUtils.mapErrorIdToAdeId(e.getKey());
if (adeId == null) {
// error that is not part of the ade standard
continue;
}
stats.setName(adeId);
statistics.getErrors().add(new ErrorProperty(stats));
}
statistics.setNumErrorBuildings(new FeatureStatisticsProperty(countValidatedCityObjects(model.getBuildings())));
statistics.setNumErrorBridgeObjects(new FeatureStatisticsProperty(countValidatedCityObjects(model.getBridges())));
statistics.setNumErrorLandObjects(new FeatureStatisticsProperty(countValidatedCityObjects(model.getLand())));
statistics.setNumErrorTransportation(new FeatureStatisticsProperty(countValidatedCityObjects(model.getTransportation())));
statistics.setNumErrorVegetation(new FeatureStatisticsProperty(countValidatedCityObjects(model.getVegetation())));
statistics.setNumErrorWaterObjects(new FeatureStatisticsProperty(countValidatedCityObjects(model.getWater())));
val.setStatistics(new StatisticsProperty(statistics));
val.setValidationPlan(new ValidationPlanProperty(model.getValidationPlan()));
return val;
}
private static FeatureStatistics countValidatedCityObjects(List extends CityObject> cos) {
int numChecked = 0;
int numError = 0;
for (CityObject co : cos) {
if (co.isValidated()) {
numChecked++;
if (co.containsAnyError()) {
numError++;
}
}
}
return new FeatureStatistics(numChecked, numError);
}
private static void storeCityObjects(List extends CityObject> cos, GeometryFactory gmlFactory, CityDoctorModel model, CityModel cModel, Validation val) {
for (CityObject co : cos) {
if (model.isValidated() && val != null) {
QualityADEUtils.writeQualityAde(co, val);
}
co.reCreateGeometries(gmlFactory, model.getParserConfig());
cModel.getCityObjectMembers().add(new AbstractCityObjectProperty(co.getGmlObject()));
}
}
}