Commit 5571f382 authored by Luna Riegel's avatar Luna Riegel
Browse files

Merge branch 'dev' into 'master'

CityDoctor Version 3.18.0

See merge request !37
parents 87dba3fa 61859d4f
Pipeline #12247 passed with stage
in 2 minutes and 31 seconds
......@@ -27,11 +27,14 @@ import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import de.hft.stuttgart.citydoctor2.database.FeatureCache;
import de.hft.stuttgart.citydoctor2.database.UnconnectedCache;
import org.citygml4j.core.ade.ADEException;
import org.citygml4j.core.model.CityGMLVersion;
import org.citygml4j.core.model.core.AbstractFeatureProperty;
import org.citygml4j.core.model.core.CityModel;
import org.citygml4j.xml.writer.CityGMLWriteException;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
......@@ -63,28 +66,40 @@ import de.hft.stuttgart.quality.model.types.ValidationPlan;
public class CityDoctorModelTest {
private File mockFile;
private ParserConfiguration config;
private CityDoctorModel model;
private final FeatureCache featureCache = new FeatureCache();
@Before
public void setUp(){
mockFile = Mockito.mock(File.class);
Mockito.when(mockFile.getName()).thenReturn("test");
config = new ParserConfiguration(8, false);
featureCache.resetCache();
model = new CityDoctorModel(config, mockFile, featureCache);
}
@Rule
public TemporaryFolder folder = new TemporaryFolder();
@Test(expected = IllegalArgumentException.class)
public void testCityDoctorModelNoConfig() {
new CityDoctorModel(null, null);
new CityDoctorModel(null, mockFile, new UnconnectedCache());
}
@Test(expected = IllegalArgumentException.class)
public void testCityDoctorModelNoFile() {
new CityDoctorModel(config, null, new UnconnectedCache());
}
@Test
public void testSetValidated() {
File f = Mockito.mock(File.class);
ParserConfiguration config = new ParserConfiguration(8, false);
CityDoctorModel model = new CityDoctorModel(config, f);
model.setValidated(Mockito.mock(ValidationPlan.class));
assertTrue(model.isValidated());
}
@Test
public void testAddGlobalError() {
File f = Mockito.mock(File.class);
ParserConfiguration config = new ParserConfiguration(8, false);
CityDoctorModel model = new CityDoctorModel(config, f);
CheckError err = Mockito.mock(CheckError.class);
model.addGlobalError(err);
assertEquals(err, model.getGlobalErrors().get(0));
......@@ -92,9 +107,6 @@ public class CityDoctorModelTest {
@Test
public void testAddGlobalErrors() {
File f = Mockito.mock(File.class);
ParserConfiguration config = new ParserConfiguration(8, false);
CityDoctorModel model = new CityDoctorModel(config, f);
CheckError err1 = Mockito.mock(CheckError.class);
CheckError err2 = Mockito.mock(CheckError.class);
List<CheckError> errors = new ArrayList<>();
......@@ -107,19 +119,15 @@ public class CityDoctorModelTest {
@Test
public void testGetFile() {
File f = Mockito.mock(File.class);
ParserConfiguration config = new ParserConfiguration(8, false);
CityDoctorModel model = new CityDoctorModel(config, f);
assertEquals(f, model.getFile());
assertEquals(mockFile, model.getFile());
}
@Test
public void testCreateFeatureStream() {
File f = Mockito.mock(File.class);
ParserConfiguration config = new ParserConfiguration(8, false);
CityDoctorModel model = new CityDoctorModel(config, f);
Building b = Mockito.mock(Building.class);
Mockito.when(b.getGmlId()).thenReturn(new GmlId("b"));
Vegetation v = Mockito.mock(Vegetation.class);
Mockito.when(v.getGmlId()).thenReturn(new GmlId("v"));
model.addBuilding(b);
model.addVegetation(v);
assertTrue(model.createFeatureStream().anyMatch(c -> c == b));
......@@ -129,9 +137,6 @@ public class CityDoctorModelTest {
@Test
public void testSaveAsWithoutValidation() throws CityGMLWriteException, ADEException,
IOException, CityGmlParseException, InvalidGmlFileException, CityDoctorWriteException {
File f = Mockito.mock(File.class);
ParserConfiguration config = new ParserConfiguration(8, false);
CityDoctorModel model = new CityDoctorModel(config, f);
model.setParsedCityGMLVersion(CityGMLVersion.v2_0);
CityModel cModel = new CityModel();
model.setCityModel(cModel);
......@@ -147,7 +152,7 @@ public class CityDoctorModelTest {
assertTrue(saveFile.length() > 0);
CityDoctorModel parsedModel = CityGmlParser.parseCityGmlFile(saveFile.getAbsolutePath(), config);
Building parsedBuilding = parsedModel.getBuildings().get(0);
Building parsedBuilding = parsedModel.getBuildings().toList().get(0);
assertEquals("testId", parsedBuilding.getGmlId().getGmlString());
assertEquals(1, parsedBuilding.getGeometries().size());
}
......@@ -155,9 +160,7 @@ public class CityDoctorModelTest {
@Test
public void testSaveAsWithValidation() throws CityGMLWriteException, ADEException,
IOException, CityGmlParseException, InvalidGmlFileException, CityDoctorWriteException {
File f = Mockito.mock(File.class);
ParserConfiguration config = new ParserConfiguration(8, false);
CityDoctorModel model = new CityDoctorModel(config, f);
model.setParsedCityGMLVersion(CityGMLVersion.v2_0);
CityModel cModel = new CityModel();
ValidationPlan plan = new ValidationPlan();
......@@ -214,7 +217,7 @@ public class CityDoctorModelTest {
assertTrue(saveFile.length() > 0);
CityDoctorModel parsedModel = CityGmlParser.parseCityGmlFile(saveFile.getAbsolutePath(), config);
Building parsedBuilding = parsedModel.getBuildings().get(0);
Building parsedBuilding = parsedModel.getBuildings().toList().get(0);
assertEquals("testId", parsedBuilding.getGmlId().getGmlString());
assertEquals(1, parsedBuilding.getGeometries().size());
List<CityObjectProperties> props = parsedBuilding.getGmlObject().getADEProperties(CityObjectProperties.class);
......@@ -234,9 +237,6 @@ public class CityDoctorModelTest {
@Test
public void testCollectErrors() {
File f = Mockito.mock(File.class);
ParserConfiguration config = new ParserConfiguration(8, false);
CityDoctorModel model = new CityDoctorModel(config, f);
Building b = new Building();
model.addBuilding(b);
CheckError error = Mockito.mock(CheckError.class);
......@@ -247,18 +247,12 @@ public class CityDoctorModelTest {
@Test
public void testGetFileName() {
File f = new File("test");
ParserConfiguration config = new ParserConfiguration(8, false);
CityDoctorModel model = new CityDoctorModel(config, f);
assertEquals("test", model.getFileName());
assertEquals(f, model.getFile());
assertEquals(mockFile, model.getFile());
}
@Test
public void testSetCityModel() {
File f = Mockito.mock(File.class);
ParserConfiguration config = new ParserConfiguration(8, false);
CityDoctorModel model = new CityDoctorModel(config, f);
CityModel cModel = Mockito.mock(CityModel.class);
model.setCityModel(cModel);
assertEquals(cModel, model.getCityModel());
......@@ -266,111 +260,99 @@ public class CityDoctorModelTest {
@Test
public void testAddBuilding() {
File f = Mockito.mock(File.class);
ParserConfiguration config = new ParserConfiguration(8, false);
CityDoctorModel model = new CityDoctorModel(config, f);
Building b = Mockito.mock(Building.class);
Mockito.when(b.getGmlId()).thenReturn(new GmlId("b"));
model.addBuilding(b);
assertEquals(b, model.getBuildings().get(0));
assertEquals(b, model.getBuildings().toList().get(0));
}
@Test
public void testAddBridge() {
File f = Mockito.mock(File.class);
ParserConfiguration config = new ParserConfiguration(8, false);
CityDoctorModel model = new CityDoctorModel(config, f);
BridgeObject b = Mockito.mock(BridgeObject.class);
Mockito.when(b.getGmlId()).thenReturn(new GmlId("b"));
model.addBridge(b);
assertEquals(b, model.getBridges().get(0));
assertEquals(b, model.getBridges().toList().get(0));
}
@Test
public void testAddVegetation() {
File f = Mockito.mock(File.class);
ParserConfiguration config = new ParserConfiguration(8, false);
CityDoctorModel model = new CityDoctorModel(config, f);
Vegetation veg = Mockito.mock(Vegetation.class);
Mockito.when(veg.getGmlId()).thenReturn(new GmlId("v"));
model.addVegetation(veg);
assertEquals(veg, model.getVegetation().get(0));
assertEquals(veg, model.getVegetation().toList().get(0));
}
@Test
public void testAddTunnel() {
File f = Mockito.mock(File.class);
ParserConfiguration config = new ParserConfiguration(8, false);
CityDoctorModel model = new CityDoctorModel(config, f);
Tunnel tunnel = Mockito.mock(Tunnel.class);
Mockito.when(tunnel.getGmlId()).thenReturn(new GmlId("t"));
model.addTunnel(tunnel);
assertEquals(tunnel, model.getTunnels().get(0));
assertEquals(tunnel, model.getTunnels().toList().get(0));
}
@Test
public void testAddTransportation() {
File f = Mockito.mock(File.class);
ParserConfiguration config = new ParserConfiguration(8, false);
CityDoctorModel model = new CityDoctorModel(config, f);
TransportationObject trans = Mockito.mock(TransportationObject.class);
Mockito.when(trans.getGmlId()).thenReturn(new GmlId("t"));
model.addTransportation(trans);
assertEquals(trans, model.getTransportation().get(0));
assertEquals(trans, model.getTransportation().toList().get(0));
}
@Test
public void testAddLand() {
File f = Mockito.mock(File.class);
ParserConfiguration config = new ParserConfiguration(8, false);
CityDoctorModel model = new CityDoctorModel(config, f);
LandObject land = Mockito.mock(LandObject.class);
Mockito.when(land.getGmlId()).thenReturn(new GmlId("l"));
model.addLand(land);
assertEquals(land, model.getLand().get(0));
assertEquals(land, model.getLand().toList().get(0));
}
@Test
public void testAddWater() {
File f = Mockito.mock(File.class);
ParserConfiguration config = new ParserConfiguration(8, false);
CityDoctorModel model = new CityDoctorModel(config, f);
WaterObject water = Mockito.mock(WaterObject.class);
Mockito.when(water.getGmlId()).thenReturn(new GmlId("w"));
model.addWater(water);
assertEquals(water, model.getWater().get(0));
assertEquals(water, model.getWater().toList().get(0));
}
@Test
public void testAddCityFurniture() {
File f = Mockito.mock(File.class);
ParserConfiguration config = new ParserConfiguration(8, false);
CityDoctorModel model = new CityDoctorModel(config, f);
CityFurniture cf = Mockito.mock(CityFurniture.class);
Mockito.when(cf.getGmlId()).thenReturn(new GmlId("cf"));
model.addCityFurniture(cf);
assertEquals(cf, model.getCityFurniture().get(0));
assertEquals(cf, model.getCityFurniture().toList().get(0));
}
@Test
public void testAddGenericCityObject() {
File f = Mockito.mock(File.class);
ParserConfiguration config = new ParserConfiguration(8, false);
CityDoctorModel model = new CityDoctorModel(config, f);
public void testAddOtherCityObject() {
GenericCityObject gen = Mockito.mock(GenericCityObject.class);
model.addGenericCityObject(gen);
assertEquals(gen, model.getGenericCityObjects().get(0));
Mockito.when(gen.getGmlId()).thenReturn(new GmlId("g"));
model.addOtherCityObject(gen);
assertEquals(gen, model.getOtherCityObjects().toList().get(0));
}
@Test
public void testGetNumberOfFeatures() {
File f = Mockito.mock(File.class);
ParserConfiguration config = new ParserConfiguration(8, false);
CityDoctorModel model = new CityDoctorModel(config, f);
Building b = Mockito.mock(Building.class);
Mockito.when(b.getGmlId()).thenReturn(new GmlId("b"));
BridgeObject bo = Mockito.mock(BridgeObject.class);
Mockito.when(bo.getGmlId()).thenReturn(new GmlId("bo"));
Vegetation veg = Mockito.mock(Vegetation.class);
Mockito.when(veg.getGmlId()).thenReturn(new GmlId("ve"));
Tunnel tunnel = Mockito.mock(Tunnel.class);
Mockito.when(tunnel.getGmlId()).thenReturn(new GmlId("t"));
TransportationObject trans = Mockito.mock(TransportationObject.class);
Mockito.when(trans.getGmlId()).thenReturn(new GmlId("tr"));
LandObject land = Mockito.mock(LandObject.class);
Mockito.when(land.getGmlId()).thenReturn(new GmlId("l"));
WaterObject water = Mockito.mock(WaterObject.class);
Mockito.when(water.getGmlId()).thenReturn(new GmlId("w"));
CityFurniture cf = Mockito.mock(CityFurniture.class);
Mockito.when(cf.getGmlId()).thenReturn(new GmlId("cf"));
GenericCityObject generic = Mockito.mock(GenericCityObject.class);
Mockito.when(generic.getGmlId()).thenReturn(new GmlId("g"));
model.addBuilding(b);
model.addBridge(bo);
......@@ -380,7 +362,7 @@ public class CityDoctorModelTest {
model.addLand(land);
model.addWater(water);
model.addCityFurniture(cf);
model.addGenericCityObject(generic);
model.addOtherCityObject(generic);
assertEquals(9, model.getNumberOfFeatures());
......@@ -388,31 +370,25 @@ public class CityDoctorModelTest {
@Test
public void testGetParserConfig() {
File f = Mockito.mock(File.class);
ParserConfiguration config = new ParserConfiguration(8, false);
CityDoctorModel model = new CityDoctorModel(config, f);
assertEquals(config, model.getParserConfig());
}
@Test
public void testReplaceBuilding() {
File f = Mockito.mock(File.class);
ParserConfiguration config = new ParserConfiguration(8, false);
CityDoctorModel model = new CityDoctorModel(config, f);
Building b1 = Mockito.mock(Building.class);
Mockito.when(b1.getGmlId()).thenReturn(new GmlId("b1"));
Building b2 = Mockito.mock(Building.class);
Mockito.when(b2.getGmlId()).thenReturn(new GmlId("b2"));
model.addBuilding(b1);
assertEquals(b1, model.getBuildings().get(0));
assertEquals(b1, model.getBuildings().toList().get(0));
model.replaceFeature(b1, b2);
assertEquals(b2, model.getBuildings().get(0));
assertEquals(1, model.getBuildings().size());
assertEquals(b2, model.getBuildings().toList().get(0));
assertEquals(1, model.getBuildings().toList().size());
}
@Test(expected = IllegalStateException.class)
public void testReplaceBuildingMissing() {
File f = Mockito.mock(File.class);
ParserConfiguration config = new ParserConfiguration(8, false);
CityDoctorModel model = new CityDoctorModel(config, f);
Building b1 = Mockito.mock(Building.class);
Building b2 = Mockito.mock(Building.class);
model.replaceFeature(b1, b2);
......@@ -420,23 +396,19 @@ public class CityDoctorModelTest {
@Test
public void testReplaceBridge() {
File f = Mockito.mock(File.class);
ParserConfiguration config = new ParserConfiguration(8, false);
CityDoctorModel model = new CityDoctorModel(config, f);
BridgeObject b1 = Mockito.mock(BridgeObject.class);
Mockito.when(b1.getGmlId()).thenReturn(new GmlId("b1"));
BridgeObject b2 = Mockito.mock(BridgeObject.class);
Mockito.when(b2.getGmlId()).thenReturn(new GmlId("b2"));
model.addBridge(b1);
assertEquals(b1, model.getBridges().get(0));
assertEquals(b1, model.getBridges().toList().get(0));
model.replaceFeature(b1, b2);
assertEquals(b2, model.getBridges().get(0));
assertEquals(1, model.getBridges().size());
assertEquals(b2, model.getBridges().toList().get(0));
assertEquals(1, model.getBridges().toList().size());
}
@Test(expected = IllegalStateException.class)
public void testReplaceBridgeMissing() {
File f = Mockito.mock(File.class);
ParserConfiguration config = new ParserConfiguration(8, false);
CityDoctorModel model = new CityDoctorModel(config, f);
BridgeObject b1 = Mockito.mock(BridgeObject.class);
BridgeObject b2 = Mockito.mock(BridgeObject.class);
model.replaceFeature(b1, b2);
......@@ -444,23 +416,20 @@ public class CityDoctorModelTest {
@Test
public void testReplaceVegetation() {
File f = Mockito.mock(File.class);
ParserConfiguration config = new ParserConfiguration(8, false);
CityDoctorModel model = new CityDoctorModel(config, f);
Vegetation v1 = Mockito.mock(Vegetation.class);
Mockito.when(v1.getGmlId()).thenReturn(new GmlId("v1"));
Vegetation v2 = Mockito.mock(Vegetation.class);
Mockito.when(v2.getGmlId()).thenReturn(new GmlId("v2"));
model.addVegetation(v1);
assertEquals(v1, model.getVegetation().get(0));
assertEquals(v1, model.getVegetation().toList().get(0));
model.replaceFeature(v1, v2);
assertEquals(v2, model.getVegetation().get(0));
assertEquals(1, model.getVegetation().size());
assertEquals(v2, model.getVegetation().toList().get(0));
assertEquals(1, model.getVegetation().toList().size());
}
@Test(expected = IllegalStateException.class)
public void testReplaceVegetationMissing() {
File f = Mockito.mock(File.class);
ParserConfiguration config = new ParserConfiguration(8, false);
CityDoctorModel model = new CityDoctorModel(config, f);
Vegetation v1 = Mockito.mock(Vegetation.class);
Vegetation v2 = Mockito.mock(Vegetation.class);
model.replaceFeature(v1, v2);
......@@ -468,23 +437,20 @@ public class CityDoctorModelTest {
@Test
public void testReplaceTunnel() {
File f = Mockito.mock(File.class);
ParserConfiguration config = new ParserConfiguration(8, false);
CityDoctorModel model = new CityDoctorModel(config, f);
Tunnel t1 = Mockito.mock(Tunnel.class);
Mockito.when(t1.getGmlId()).thenReturn(new GmlId("t1"));
Tunnel t2 = Mockito.mock(Tunnel.class);
Mockito.when(t2.getGmlId()).thenReturn(new GmlId("t2"));
model.addTunnel(t1);
assertEquals(t1, model.getTunnels().get(0));
assertEquals(t1, model.getTunnels().toList().get(0));
model.replaceFeature(t1, t2);
assertEquals(t2, model.getTunnels().get(0));
assertEquals(1, model.getTunnels().size());
assertEquals(t2, model.getTunnels().toList().get(0));
assertEquals(1, model.getTunnels().toList().size());
}
@Test(expected = IllegalStateException.class)
public void testReplaceTunnelMissing() {
File f = Mockito.mock(File.class);
ParserConfiguration config = new ParserConfiguration(8, false);
CityDoctorModel model = new CityDoctorModel(config, f);
Tunnel t1 = Mockito.mock(Tunnel.class);
Tunnel t2 = Mockito.mock(Tunnel.class);
model.replaceFeature(t1, t2);
......@@ -492,23 +458,20 @@ public class CityDoctorModelTest {
@Test
public void testReplaceTransportation() {
File f = Mockito.mock(File.class);
ParserConfiguration config = new ParserConfiguration(8, false);
CityDoctorModel model = new CityDoctorModel(config, f);
TransportationObject t1 = Mockito.mock(TransportationObject.class);
Mockito.when(t1.getGmlId()).thenReturn(new GmlId("t1"));
TransportationObject t2 = Mockito.mock(TransportationObject.class);
Mockito.when(t2.getGmlId()).thenReturn(new GmlId("t2"));
model.addTransportation(t1);
assertEquals(t1, model.getTransportation().get(0));
assertEquals(t1, model.getTransportation().toList().get(0));
model.replaceFeature(t1, t2);
assertEquals(t2, model.getTransportation().get(0));
assertEquals(1, model.getTransportation().size());
assertEquals(t2, model.getTransportation().toList().get(0));
assertEquals(1, model.getTransportation().toList().size());
}
@Test(expected = IllegalStateException.class)
public void testReplaceTransportationMissing() {
File f = Mockito.mock(File.class);
ParserConfiguration config = new ParserConfiguration(8, false);
CityDoctorModel model = new CityDoctorModel(config, f);
TransportationObject t1 = Mockito.mock(TransportationObject.class);
TransportationObject t2 = Mockito.mock(TransportationObject.class);
model.replaceFeature(t1, t2);
......@@ -516,23 +479,20 @@ public class CityDoctorModelTest {
@Test
public void testReplaceLand() {
File f = Mockito.mock(File.class);
ParserConfiguration config = new ParserConfiguration(8, false);
CityDoctorModel model = new CityDoctorModel(config, f);
LandObject lo1 = Mockito.mock(LandObject.class);
Mockito.when(lo1.getGmlId()).thenReturn(new GmlId("lo1"));
LandObject lo2 = Mockito.mock(LandObject.class);
Mockito.when(lo2.getGmlId()).thenReturn(new GmlId("lo2"));
model.addLand(lo1);
assertEquals(lo1, model.getLand().get(0));
assertEquals(lo1, model.getLand().toList().get(0));
model.replaceFeature(lo1, lo2);
assertEquals(lo2, model.getLand().get(0));
assertEquals(1, model.getLand().size());
assertEquals(lo2, model.getLand().toList().get(0));
assertEquals(1, model.getLand().toList().size());
}
@Test(expected = IllegalStateException.class)
public void testReplaceLandMissing() {
File f = Mockito.mock(File.class);
ParserConfiguration config = new ParserConfiguration(8, false);
CityDoctorModel model = new CityDoctorModel(config, f);
LandObject lo1 = Mockito.mock(LandObject.class);
LandObject lo2 = Mockito.mock(LandObject.class);
model.replaceFeature(lo1, lo2);
......@@ -540,23 +500,20 @@ public class CityDoctorModelTest {
@Test
public void testReplaceWater() {
File f = Mockito.mock(File.class);
ParserConfiguration config = new ParserConfiguration(8, false);
CityDoctorModel model = new CityDoctorModel(config, f);
WaterObject t1 = Mockito.mock(WaterObject.class);
Mockito.when(t1.getGmlId()).thenReturn(new GmlId("t1"));
WaterObject t2 = Mockito.mock(WaterObject.class);
Mockito.when(t2.getGmlId()).thenReturn(new GmlId("t2"));
model.addWater(t1);
assertEquals(t1, model.getWater().get(0));
assertEquals(t1, model.getWater().toList().get(0));
model.replaceFeature(t1, t2);
assertEquals(t2, model.getWater().get(0));
assertEquals(1, model.getWater().size());
assertEquals(t2, model.getWater().toList().get(0));
assertEquals(1, model.getWater().toList().size());
}
@Test(expected = IllegalStateException.class)
public void testReplaceWaterMissing() {
File f = Mockito.mock(File.class);
ParserConfiguration config = new ParserConfiguration(8, false);
CityDoctorModel model = new CityDoctorModel(config, f);
WaterObject t1 = Mockito.mock(WaterObject.class);
WaterObject t2 = Mockito.mock(WaterObject.class);
model.replaceFeature(t1, t2);
......@@ -564,23 +521,20 @@ public class CityDoctorModelTest {
@Test
public void testReplaceCityFurniture() {
File f = Mockito.mock(File.class);
ParserConfiguration config = new ParserConfiguration(8, false);
CityDoctorModel model = new CityDoctorModel(config, f);
CityFurniture cf1 = Mockito.mock(CityFurniture.class);
Mockito.when(cf1.getGmlId()).thenReturn(new GmlId("cf1"));
CityFurniture cf2 = Mockito.mock(CityFurniture.class);
Mockito.when(cf2.getGmlId()).thenReturn(new GmlId("cf2"));
model.addCityFurniture(cf1);
assertEquals(cf1, model.getCityFurniture().get(0));
assertEquals(cf1, model.getCityFurniture().toList().get(0));
model.replaceFeature(cf1, cf2);
assertEquals(cf2, model.getCityFurniture().get(0));
assertEquals(1, model.getCityFurniture().size());
assertEquals(cf2, model.getCityFurniture().toList().get(0));
assertEquals(1, model.getCityFurniture().toList().size());
}
@Test(expected = IllegalStateException.class)
public void testReplaceCityFurnitureMissing() {
File f = Mockito.mock(File.class);
ParserConfiguration config = new ParserConfiguration(8, false);
CityDoctorModel model = new CityDoctorModel(config, f);
CityFurniture cf1 = Mockito.mock(CityFurniture.class);
CityFurniture cf2 = Mockito.mock(CityFurniture.class);
model.replaceFeature(cf1, cf2);
......@@ -588,23 +542,20 @@ public class CityDoctorModelTest {
@Test
public void testReplaceGenericCityObject() {
File f = Mockito.mock(File.class);
ParserConfiguration config = new ParserConfiguration(8, false);
CityDoctorModel model = new CityDoctorModel(config, f);
GenericCityObject gco1 = Mockito.mock(GenericCityObject.class);
Mockito.when(gco1.getGmlId()).thenReturn(new GmlId("gco1"));
GenericCityObject gco2 = Mockito.mock(GenericCityObject.class);
model.addGenericCityObject(gco1);
assertEquals(gco1, model.getGenericCityObjects().get(0));
Mockito.when(gco2.getGmlId()).thenReturn(new GmlId("gco2"));
model.addOtherCityObject(gco1);
assertEquals(gco1, model.getOtherCityObjects().toList().get(0));
model.replaceFeature(gco1, gco2);
assertEquals(gco2, model.getGenericCityObjects().get(0));
assertEquals(1, model.getGenericCityObjects().size());
assertEquals(gco2, model.getOtherCityObjects().toList().get(0));
assertEquals(1, model.getOtherCityObjects().toList().size());
}
@Test(expected = IllegalStateException.class)
public void testReplaceGenericCityObjectMissing() {
File f = Mockito.mock(File.class);
ParserConfiguration config = new ParserConfiguration(8, false);
CityDoctorModel model = new CityDoctorModel(config, f);
GenericCityObject gco1 = Mockito.mock(GenericCityObject.class);
GenericCityObject gco2 = Mockito.mock(GenericCityObject.class);
model.replaceFeature(gco1, gco2);
......
......@@ -16,7 +16,7 @@ public class CompositePolygonTest {
ParserConfiguration config = new ParserConfiguration(8, false);
CityDoctorModel m = CityGmlParser.parseCityGmlFile("src/test/resources/FZK_haus.gml", config);
Building b = m.getBuildings().get(0);
Building b = m.getBuildings().toList().get(0);
assertNotNull(b);
assertFalse(b.getBoundarySurfaces().isEmpty());
for (BoundarySurface bs : b.getBoundarySurfaces()) {
......
......@@ -96,7 +96,7 @@ public class GeometryTest {
public void testRemovePolygonConcreteWithLink() {
ParserConfiguration config = new ParserConfiguration(4, false);
AbstractConstructionSurface abs = new WallSurface();
BoundarySurface bs = new BoundarySurface(SurfaceFeatureType.BUILDING, BoundarySurfaceType.WALL, abs);
BoundarySurface bs = new BoundarySurface(BoundarySurfaceType.WALL, abs);
var gmlBi = new org.citygml4j.core.model.building.BuildingInstallation();
Installation bi = new Installation();
bi.setGmlObject(gmlBi);
......@@ -133,7 +133,7 @@ public class GeometryTest {
public void testRemovePolygonOnlyConcrete() {
ParserConfiguration config = new ParserConfiguration(4, false);
AbstractConstructionSurface abs = new WallSurface();
BoundarySurface bs = new BoundarySurface(SurfaceFeatureType.BUILDING, BoundarySurfaceType.WALL, abs);
BoundarySurface bs = new BoundarySurface(BoundarySurfaceType.WALL, abs);
Geometry geom = new Geometry(GeometryType.MULTI_SURFACE, Lod.LOD2, Orientation.OUTWARD);
ConcretePolygon p = new ConcretePolygon();
......@@ -156,7 +156,7 @@ public class GeometryTest {
public void testRemovePolygonLinked() {
ParserConfiguration config = new ParserConfiguration(4, false);
AbstractConstructionSurface abs = new WallSurface();
BoundarySurface bs = new BoundarySurface(SurfaceFeatureType.BUILDING, BoundarySurfaceType.WALL, abs);
BoundarySurface bs = new BoundarySurface(BoundarySurfaceType.WALL, abs);
var gmlBi = new org.citygml4j.core.model.building.BuildingInstallation();
Installation bi = new Installation();
bi.setGmlObject(gmlBi);
......@@ -193,7 +193,7 @@ public class GeometryTest {
public void testReplacePolygon() {
ParserConfiguration config = new ParserConfiguration(4, false);
AbstractConstructionSurface abs = new WallSurface();
BoundarySurface bs = new BoundarySurface(SurfaceFeatureType.BUILDING, BoundarySurfaceType.WALL, abs);
BoundarySurface bs = new BoundarySurface(BoundarySurfaceType.WALL, abs);
var gmlBi = new org.citygml4j.core.model.building.BuildingInstallation();
Installation bi = new Installation();
bi.setGmlObject(gmlBi);
......
......@@ -26,7 +26,6 @@ import static org.mockito.Mockito.mock;
public class VegetationTest {
//TODO: Recreate geometries tests
@Test
public void testContainsError() {
......
......@@ -63,20 +63,20 @@ public class FeatureMapperTest {
public void testVisitWaterBody() {
WaterBody body = new WaterBody();
Citygml3FeatureMapper mapper = new Citygml3FeatureMapper(mock(ParserConfiguration.class),
new File("").toPath());
new File("").toPath(), false);
mapper.visit(body);
assertEquals(1, mapper.getModel().getWater().size());
assertEquals(1, mapper.getModel().getWater().toList().size());
body.setId("test1");
mapper.visit(body);
assertEquals(2, mapper.getModel().getWater().size());
WaterObject waterObject = mapper.getModel().getWater().get(1);
assertEquals(2, mapper.getModel().getWater().toList().size());
WaterObject waterObject = mapper.getModel().getWater().toList().get(1);
assertEquals("test1", waterObject.getGmlId().getGmlString());
body.getDeprecatedProperties().setLod1MultiSurface(createDummyMsp());
mapper.visit(body);
assertEquals(3, mapper.getModel().getWater().size());
assertEquals(3, mapper.getModel().getWater().toList().size());
assertNull(body.getDeprecatedProperties().getLod1MultiSurface());
Geometry geometry = mapper.getModel().getWater().get(2).getGeometries().get(0);
Geometry geometry = mapper.getModel().getWater().toList().get(2).getGeometries().get(0);
assertEquals(1, geometry.getPolygons().size());
assertEquals(Lod.LOD1, geometry.getLod());
assertEquals(GeometryType.MULTI_SURFACE, geometry.getType());
......@@ -86,7 +86,7 @@ public class FeatureMapperTest {
public void testVisitPlantCover() {
PlantCover cover = new PlantCover();
Citygml3FeatureMapper mapper = new Citygml3FeatureMapper(mock(ParserConfiguration.class),
new File("").toPath());
new File("").toPath(), false);
mapper.visit(cover);
}
......@@ -124,12 +124,12 @@ public class FeatureMapperTest {
body.getDeprecatedProperties().setLod1MultiSurface(new MultiSurfaceProperty(ms));
ParserConfiguration config = new ParserConfiguration(8, false);
Citygml3FeatureMapper mapper = new Citygml3FeatureMapper(config, folder.newFile().toPath());
Citygml3FeatureMapper mapper = new Citygml3FeatureMapper(config, folder.newFile().toPath(), false);
mapper.visit(body);
CityDoctorModel model = mapper.getModel();
assertEquals(1, model.getWater().size());
WaterObject waterObject = model.getWater().get(0);
assertEquals(1, model.getWater().toList().size());
WaterObject waterObject = model.getWater().toList().get(0);
Geometry geometry = waterObject.getGeometries().get(0);
assertEquals(1, geometry.getVertices().size());
Vertex vertex = geometry.getVertices().get(0);
......@@ -152,12 +152,12 @@ public class FeatureMapperTest {
body.getDeprecatedProperties().setLod1MultiSurface(new MultiSurfaceProperty(ms));
ParserConfiguration config = new ParserConfiguration(8, false);
Citygml3FeatureMapper mapper = new Citygml3FeatureMapper(config, folder.newFile().toPath());
Citygml3FeatureMapper mapper = new Citygml3FeatureMapper(config, folder.newFile().toPath(), false);
mapper.visit(body);
CityDoctorModel model = mapper.getModel();
assertEquals(1, model.getWater().size());
WaterObject waterObject = model.getWater().get(0);
assertEquals(1, model.getWater().toList().size());
WaterObject waterObject = model.getWater().toList().get(0);
Geometry geometry = waterObject.getGeometries().get(0);
assertEquals(2, geometry.getVertices().size());
Vertex vertex = geometry.getVertices().get(0);
......@@ -199,12 +199,12 @@ public class FeatureMapperTest {
body.getDeprecatedProperties().setLod1MultiSurface(new MultiSurfaceProperty(ms));
ParserConfiguration config = new ParserConfiguration(8, false);
Citygml3FeatureMapper mapper = new Citygml3FeatureMapper(config, folder.newFile().toPath());
Citygml3FeatureMapper mapper = new Citygml3FeatureMapper(config, folder.newFile().toPath(), false);
mapper.visit(body);
CityDoctorModel model = mapper.getModel();
assertEquals(1, model.getWater().size());
WaterObject waterObject = model.getWater().get(0);
assertEquals(1, model.getWater().toList().size());
WaterObject waterObject = model.getWater().toList().get(0);
Geometry geometry = waterObject.getGeometries().get(0);
assertEquals(7, geometry.getVertices().size());
assertEquals(8, geometry.getEdges().size());
......
......@@ -49,7 +49,7 @@ public class CityGml3ParserTest {
ParserConfiguration config = new ParserConfiguration(8, false);
CityDoctorModel model = CityGmlParser.parseCityGmlFile("src/test/resources/SimpleSolid_SrefBS.gml", config);
assertNotNull(model);
List<Building> buildings = model.getBuildings();
List<Building> buildings = model.getBuildings().toList();
assertEquals(1, buildings.size());
Building building = buildings.get(0);
assertEquals("_Simple_BD.1", building.getGmlId().getGmlString());
......
package de.hft.stuttgart.citydoctor2.zip;
import de.hft.stuttgart.citydoctor2.datastructure.CityDoctorModel;
import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration;
import org.apache.commons.io.FileUtils;
import org.junit.Test;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
public class ZipTest {
ParserConfiguration config = new ParserConfiguration(8, false);
@Test
public void testUnzipping() throws MalformedZipFileException {
CityGmlZipArchive cgmlArch = CityGmlZipArchive.register("src/test/resources/zip/mock_archive.zip");
assertNotNull(cgmlArch);
cgmlArch.mountArchive(config);
checkMockArchive(cgmlArch);
}
private void checkMockArchive(CityGmlZipArchive cgmlArch) {
assertEquals(5, cgmlArch.getEntries().size());
for (CityGmlZipEntry entry : cgmlArch.getEntries()) {
assertNotNull(entry);
assertTrue(entry.getEntrySubPath().matches("^mock[1-5].gml$"));
assertNull(entry.getErrorType());
assertNotNull(entry.getModel());
assertEquals(1, entry.getModel().getNumberOfFeatures());
}
}
@Test
public void testZipping() throws IOException {
CityGmlZipArchive cgmlArch = CityGmlZipArchive.register("src/test/resources/zip/mock_archive.zip");
assertNotNull(cgmlArch);
cgmlArch.mountArchive(config);
Path tmpDir = null;
try {
tmpDir = Files.createTempDirectory("testTmp");
tmpDir.toFile().deleteOnExit();
String expPath = tmpDir + "/export.zip";
cgmlArch.exportToZipFile(expPath);
CityGmlZipArchive cgmlExport = CityGmlZipArchive.register(expPath);
assertNotNull(cgmlExport);
cgmlExport.mountArchive(config);
checkMockArchive(cgmlExport);
} finally {
if (tmpDir != null) {
FileUtils.deleteDirectory(tmpDir.toFile());
}
}
}
@Test
public void testEpsgParsing() throws MalformedZipFileException {
CityGmlZipArchive cgmlArch = CityGmlZipArchive.register("src/test/resources/zip/epsg.zip");
assertNotNull(cgmlArch);
cgmlArch.mountArchive(config);
CityGmlZipEntry entry = cgmlArch.getEntry("epsg1.gml");
assertNotNull(entry);
String srsName = entry.getModel().getCityModel().getBoundedBy().getEnvelope().getSrsName().split(":")[6];
assertEquals("25832", srsName);
entry = cgmlArch.getEntry("epsg2.gml");
assertNotNull(entry);
srsName = entry.getModel().getCityModel().getBoundedBy().getEnvelope().getSrsName().split(":")[6];
assertEquals("7415", srsName);
}
@Test
public void testXMLValidation() throws MalformedZipFileException {
ParserConfiguration valConfig = new ParserConfiguration(8, true);
CityGmlZipArchive cgmlArch = CityGmlZipArchive.register("src/test/resources/zip/validate.zip");
assertNotNull(cgmlArch);
cgmlArch.mountArchive(valConfig);
assertNull(cgmlArch.getEntry("valCorrect.gml").getErrorType());
assertEquals(ZipEntryErrorType.INVALID_CITY_GML_FILE, cgmlArch.getEntry("valFaulty.gml").getErrorType());
}
@Test
public void testImplicitParsing() throws MalformedZipFileException {
CityGmlZipArchive cgmlArch = CityGmlZipArchive.register("src/test/resources/zip/implicit.zip");
assertNotNull(cgmlArch);
cgmlArch.mountArchive(config);
CityDoctorModel mainModel = cgmlArch.getEntry("Main_model.gml").getModel();
assertEquals(18, mainModel.getGenericCityObjects().size());
}
}
<?xml version="1.0" encoding="utf-8"?>
<!-- Exported with 3DIS GmbH (https://www.3dis.de) CityEditor 2.26.2.0 -->
<!-- Date: 2023-02-20 13:26:02 +0100 ModelName: unnamed ModelPath: S:\PUBLICATIONS\2023-05-09-Lindau\Daten\CityGML-3-0\Buildings\FZK-Haus-Storey\FZK-Haus-LoD2-Texture-CG30-V01.skp -->
<!-- This CityGML model is made for testing CityGML Version 3.0 by KHH from the Institut for Automation and Applied Informatics (IAI) at Karlsruhe Institute of Technology (KIT) -->
<!-- If you use this CityGML model for publication, please refer to the Institut for Automation and Applied Informatics (IAI) at Karlsruhe Institute of Technology (KIT) -->
<!-- This model is made using Sketchup with CityEditor (3DIS GmbH), CityGML-Tools (VCS) and manual work -->
<!-- 2023-04-28 KHH / IAI Mannually converted to CityGML 3.0 -->
<core:CityModel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:con="http://www.opengis.net/citygml/construction/3.0"
xmlns:core="http://www.opengis.net/citygml/3.0" xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:gml="http://www.opengis.net/gml/3.2"
xmlns:bldg="http://www.opengis.net/citygml/building/3.0"
xmlns:app="http://www.opengis.net/citygml/appearance/3.0"
xmlns:gen="http://www.opengis.net/citygml/generics/3.0" xmlns:xAL="urn:oasis:names:tc:ciq:xal:3"
xsi:schemaLocation="http://www.opengis.net/citygml/3.0 https://sdm-web.cloud.iai.kit.edu/CityGML-3-0/Schema/core.xsd
http://www.opengis.net/citygml/appearance/3.0 https://sdm-web.cloud.iai.kit.edu/CityGML-3-0/Schema/appearance.xsd
http://www.opengis.net/citygml/bridge/3.0 https://sdm-web.cloud.iai.kit.edu/CityGML-3-0/Schema/bridge.xsd
http://www.opengis.net/citygml/building/3.0 https://sdm-web.cloud.iai.kit.edu/CityGML-3-0/Schema/building.xsd
http://www.opengis.net/citygml/cityfurniture/3.0 https://sdm-web.cloud.iai.kit.edu/CityGML-3-0/Schema/cityFurniture.xsd
http://www.opengis.net/citygml/cityobjectgroup/3.0 https://sdm-web.cloud.iai.kit.edu/CityGML-3-0/Schema/cityObjectGroup.xsd
http://www.opengis.net/citygml/generics/3.0 https://sdm-web.cloud.iai.kit.edu/CityGML-3-0/Schema/generics.xsd
http://www.opengis.net/citygml/landuse/3.0 https://sdm-web.cloud.iai.kit.edu/CityGML-3-0/Schema/landUse.xsd
http://www.opengis.net/citygml/relief/3.0 https://sdm-web.cloud.iai.kit.edu/CityGML-3-0/Schema/relief.xsd
http://www.opengis.net/citygml/transportation/3.0 https://sdm-web.cloud.iai.kit.edu/CityGML-3-0/Schema/transportation.xsd
http://www.opengis.net/citygml/tunnel/3.0 https://sdm-web.cloud.iai.kit.edu/CityGML-3-0/Schema/tunnel.xsd
http://www.opengis.net/citygml/vegetation/3.0 https://sdm-web.cloud.iai.kit.edu/CityGML-3-0/Schema/vegetation.xsd
http://www.opengis.net/citygml/waterbody/3.0 https://sdm-web.cloud.iai.kit.edu/CityGML-3-0/Schema/waterBody.xsd">
<gml:name>FZK-Haus</gml:name>
<gml:boundedBy>
<gml:Envelope srsName="EPSG:25832" srsDimension="3">
<gml:lowerCorner>458900.0 5438785.0 113.5</gml:lowerCorner>
<gml:upperCorner>458912.0 5438795.0 120.017691</gml:upperCorner>
</gml:Envelope>
</gml:boundedBy>
<core:cityObjectMember>
<bldg:Building gml:id="KIT-Test-Building-01">
<gml:description>KIT Test Building FZK-Haus adapted for CityGML 3.0</gml:description>
<gml:name>KIT Test Building FZK-Haus for CityGML 3.0</gml:name>
<core:genericAttribute>
<gen:StringAttribute>
<gen:name>@cityeditor:layer</gen:name>
<gen:value>LoD2-Ausgeblendet</gen:value>
</gen:StringAttribute>
</core:genericAttribute>
<core:lod2Solid>
<gml:Solid>
<gml:exterior>
<gml:Shell>
<gml:surfaceMember
xlink:href="#KIT-Test-Building-01_PG.nfWbzHM5j2MqtisYAjgV"> </gml:surfaceMember>
<gml:surfaceMember
xlink:href="#KIT-Test-Building-01_PG.B9OH2yr4U3AkPsKWbFy2"> </gml:surfaceMember>
<gml:surfaceMember
xlink:href="#KIT-Test-Building-01_PG.ioJ6HX4PnhWvLSYhPA7h"> </gml:surfaceMember>
<gml:surfaceMember
xlink:href="#KIT-Test-Building-01_PG.VdnPNlkOAJHnTVZL5R37"> </gml:surfaceMember>
<gml:surfaceMember
xlink:href="#KIT-Test-Building-01_PG.as933cYedpVOQ8Wqm9j7"> </gml:surfaceMember>
<gml:surfaceMember
xlink:href="#KIT-Test-Building-01_PG.cdHLpEJXgkf3Hq9x6PF7"> </gml:surfaceMember>
<gml:surfaceMember
xlink:href="#KIT-Test-Building-01_PG.CUXCVrNXAnCgCUjdXnY1"> </gml:surfaceMember>
<gml:surfaceMember
xlink:href="#KIT-Test-Building-01_PG.WH3ZPoThoidUosBGLd28"> </gml:surfaceMember>
<gml:surfaceMember
xlink:href="#KIT-Test-Building-01_PG.8Oi6zRMGuUdvjDA3942O"> </gml:surfaceMember>
<gml:surfaceMember
xlink:href="#KIT-Test-Building-01_PG.87LG6xx5gYYjprCeHCDY"> </gml:surfaceMember>
<gml:surfaceMember
xlink:href="#KIT-Test-Building-01_PG.Y4DuK1eWWjbSOQxjL75Z"
> </gml:surfaceMember>
</gml:Shell>
</gml:exterior>
</gml:Solid>
</core:lod2Solid>
<con:conditionOfConstruction>projected</con:conditionOfConstruction>
<con:height>
<con:Height>
<con:highReference>highestRoofEdge</con:highReference>
<con:lowReference>lowestGroundPoint</con:lowReference>
<con:status>measured</con:status>
<con:value uom="urn:adv:uom:m">6.52</con:value>
</con:Height>
</con:height>
<con:occupancy>
<core:Occupancy>
<core:numberOfOccupants>2</core:numberOfOccupants>
</core:Occupancy>
</con:occupancy>
<bldg:buildingSubdivision>
<bldg:Storey>
<gml:name>Ground Floor</gml:name>
<core:boundary>
<con:GroundSurface>
<gml:name>Ground</gml:name>
<core:lod2MultiSurface>
<gml:MultiSurface>
<gml:surfaceMember>
<gml:Polygon
gml:id="KIT-Test-Building-01_PG.B9OH2yr4U3AkPsKWbFy2">
<gml:exterior>
<gml:LinearRing>
<gml:posList srsDimension="3"> 458912.0 5438785.0
113.5 458900.0 5438785.0 113.5 458900.0 5438795.0
113.5 458912.0 5438795.0 113.5 458912.0 5438785.0
113.5 </gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</core:lod2MultiSurface>
</con:GroundSurface>
</core:boundary>
<core:boundary>
<con:WallSurface>
<gml:name>Ground Floor / Wall East</gml:name>
<core:lod2MultiSurface>
<gml:MultiSurface>
<gml:surfaceMember>
<gml:Polygon
gml:id="KIT-Test-Building-01_PG.WH3ZPoThoidUosBGLd28">
<gml:exterior>
<gml:LinearRing
gml:id="KIT-Test-Building-01_LR.kb6UBRDjXdQhuZgyrrXF">
<gml:posList srsDimension="3"> 458912.0 5438795.0
113.5 458912.0 5438795.0 116.4 458912.0 5438785.0
116.4 458912.0 5438785.0 113.5 458912.0 5438795.0
113.5 </gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</core:lod2MultiSurface>
</con:WallSurface>
</core:boundary>
<core:boundary>
<con:WallSurface>
<gml:name>Ground Floor / Wall South</gml:name>
<core:lod2MultiSurface>
<gml:MultiSurface>
<gml:surfaceMember>
<gml:Polygon
gml:id="KIT-Test-Building-01_PG.8Oi6zRMGuUdvjDA3942O">
<gml:exterior>
<gml:LinearRing
gml:id="KIT-Test-Building-01_LR.dQRaAbGZocTDsiXUS3Wo">
<gml:posList srsDimension="3"> 458912.0 5438785.0
113.5 458912.0 5438785.0 116.4 458900.0 5438785.0
116.4 458900.0 5438785.0 113.5 458912.0 5438785.0
113.5 </gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</core:lod2MultiSurface>
</con:WallSurface>
</core:boundary>
<core:boundary>
<con:WallSurface>
<gml:name>Ground Floor / Wall West</gml:name>
<core:lod2MultiSurface>
<gml:MultiSurface>
<gml:surfaceMember>
<gml:Polygon
gml:id="KIT-Test-Building-01_PG.87LG6xx5gYYjprCeHCDY">
<gml:exterior>
<gml:LinearRing
gml:id="KIT-Test-Building-01_LR.z42J72DCA0DG7fsjO1iJ">
<gml:posList srsDimension="3"> 458900.0 5438785.0
113.5 458900.0 5438785.0 116.4 458900.0 5438795.0
116.4 458900.0 5438795.0 113.5 458900.0 5438785.0
113.5 </gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</core:lod2MultiSurface>
</con:WallSurface>
</core:boundary>
<core:boundary>
<con:WallSurface>
<gml:name>Ground Floor / Wall North</gml:name>
<core:lod2MultiSurface>
<gml:MultiSurface>
<gml:surfaceMember>
<gml:Polygon
gml:id="KIT-Test-Building-01_PG.Y4DuK1eWWjbSOQxjL75Z">
<gml:exterior>
<gml:LinearRing
gml:id="KIT-Test-Building-01_LR.CvfxHmYhr7DvEJeZnfKH">
<gml:posList srsDimension="3"> 458900.0 5438795.0
113.5 458900.0 5438795.0 116.4 458912.0 5438795.0
116.4 458912.0 5438795.0 113.5 458900.0 5438795.0
113.5 </gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</core:lod2MultiSurface>
</con:WallSurface>
</core:boundary>
<bldg:buildingRoom>
<bldg:BuildingRoom gml:id="_Room-Objects-Surfaces_BD.yW3mEChk0gvSkdeU7G3C">
<gml:name>02 Ground Floor - Kitchen</gml:name>
<core:boundary>
<core:ClosureSurface>
<gml:name>Ground Floor / Kitchen / Closure Surface North</gml:name>
<core:lod2MultiSurface>
<gml:MultiSurface>
<gml:surfaceMember>
<gml:Polygon
gml:id="_Room-Objects-Surfaces_BD.yW3mEChk0gvSkdeU7G3C_PG.HDg32RNpWPKMVUcmzWlH">
<gml:exterior>
<gml:LinearRing>
<gml:posList srsDimension="3">458904.695
5438789.01 116.2 458903.8 5438789.01 116.2
458903.8 5438789.01 113.7 458904.695 5438789.01
113.7 458904.695 5438789.01 116.2</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</core:lod2MultiSurface>
</core:ClosureSurface>
</core:boundary>
<core:boundary>
<core:ClosureSurface>
<gml:name>Ground Floor / Kitchen / Closure Surface East</gml:name>
<core:lod2MultiSurface>
<gml:MultiSurface>
<gml:surfaceMember>
<gml:Polygon
gml:id="_Room-Objects-Surfaces_BD.yW3mEChk0gvSkdeU7G3C_PG.h1lSemSyhjPbSya7pg52">
<gml:exterior>
<gml:LinearRing>
<gml:posList srsDimension="3">458904.695
5438789.01 116.2 458904.695 5438789.01 113.7
458904.695 5438785.3 113.7 458904.695 5438785.3
116.2 458904.695 5438789.01 116.2</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</core:lod2MultiSurface>
</core:ClosureSurface>
</core:boundary>
<core:boundary>
<con:CeilingSurface>
<gml:name>Ground Floor / Kitchen / Ceiling</gml:name>
<core:lod2MultiSurface>
<gml:MultiSurface>
<gml:surfaceMember>
<gml:Polygon
gml:id="_Room-Objects-Surfaces_BD.yW3mEChk0gvSkdeU7G3C_PG.LQ2c1FrzBD3S1F1ZULYR">
<gml:exterior>
<gml:LinearRing>
<gml:posList srsDimension="3">458900.3 5438785.3
116.2 458900.3 5438789.01 116.2 458903.8
5438789.01 116.2 458904.695 5438789.01 116.2
458904.695 5438785.3 116.2 458900.3 5438785.3
116.2</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</core:lod2MultiSurface>
</con:CeilingSurface>
</core:boundary>
<core:boundary>
<con:InteriorWallSurface>
<gml:name>Ground Floor / Kitchen / Interior Wall West</gml:name>
<core:lod2MultiSurface>
<gml:MultiSurface>
<gml:surfaceMember>
<gml:Polygon
gml:id="_Room-Objects-Surfaces_BD.yW3mEChk0gvSkdeU7G3C_PG.4wy6a0dmvxybhb3QrHf6">
<gml:exterior>
<gml:LinearRing>
<gml:posList srsDimension="3">458900.3 5438785.3
116.2 458900.3 5438785.3 113.7 458900.3 5438789.01
113.7 458900.3 5438789.01 116.2 458900.3 5438785.3
116.2</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</core:lod2MultiSurface>
</con:InteriorWallSurface>
</core:boundary>
<core:boundary>
<con:InteriorWallSurface>
<gml:name>Ground Floor / Kitchen / Interior Wall South</gml:name>
<core:lod2MultiSurface>
<gml:MultiSurface>
<gml:surfaceMember>
<gml:Polygon
gml:id="_Room-Objects-Surfaces_BD.yW3mEChk0gvSkdeU7G3C_PG.3mYYx1afWs6KeCCJ9gVM">
<gml:exterior>
<gml:LinearRing>
<gml:posList srsDimension="3">458904.695 5438785.3
116.2 458904.695 5438785.3 113.7 458900.3
5438785.3 113.7 458900.3 5438785.3 116.2
458904.695 5438785.3 116.2</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</core:lod2MultiSurface>
</con:InteriorWallSurface>
</core:boundary>
<core:boundary>
<con:InteriorWallSurface>
<gml:name>Ground Floor / Kitchen / Interior Wall North</gml:name>
<core:lod2MultiSurface>
<gml:MultiSurface>
<gml:surfaceMember>
<gml:Polygon
gml:id="_Room-Objects-Surfaces_BD.yW3mEChk0gvSkdeU7G3C_PG.opgbxC1uQdXkQuNtZf1V">
<gml:exterior>
<gml:LinearRing>
<gml:posList srsDimension="3">458900.3 5438789.01
113.7 458903.8 5438789.01 113.7 458903.8
5438789.01 116.2 458900.3 5438789.01 116.2
458900.3 5438789.01 113.7</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</core:lod2MultiSurface>
</con:InteriorWallSurface>
</core:boundary>
<core:boundary>
<con:FloorSurface>
<gml:name>Ground Floor / Kitchen / Floor</gml:name>
<core:lod2MultiSurface>
<gml:MultiSurface>
<gml:surfaceMember>
<gml:Polygon
gml:id="_Room-Objects-Surfaces_BD.yW3mEChk0gvSkdeU7G3C_PG.avFqXdbSjQLDHP36SuyA">
<gml:exterior>
<gml:LinearRing>
<gml:posList srsDimension="3">458903.8 5438789.01
113.7 458900.3 5438789.01 113.7 458900.3 5438785.3
113.7 458904.695 5438785.3 113.7 458904.695
5438789.01 113.7 458903.8 5438789.01
113.7</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</core:lod2MultiSurface>
</con:FloorSurface>
</core:boundary>
</bldg:BuildingRoom>
</bldg:buildingRoom>
<bldg:buildingRoom>
<bldg:BuildingRoom gml:id="_Room-Objects-Surfaces_BD.duiY1tKGgRCVPb6UyU7Z">
<gml:name>03 Ground Floor - Corridor</gml:name>
<core:boundary>
<core:ClosureSurface>
<gml:name>Ground Floor / Corridor / Closure Surface South</gml:name>
<core:lod2MultiSurface>
<gml:MultiSurface>
<gml:surfaceMember>
<gml:Polygon
gml:id="_Room-Objects-Surfaces_BD.duiY1tKGgRCVPb6UyU7Z_PG.nqPs4tcxPaS3p6OZw2JR">
<gml:exterior>
<gml:LinearRing>
<gml:posList srsDimension="3">458907.41 5438789.01
113.7 458904.695 5438789.01 113.7 458904.695
5438789.01 116.2 458907.41 5438789.01 116.2
458907.41 5438789.01 113.7</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</core:lod2MultiSurface>
</core:ClosureSurface>
</core:boundary>
<core:boundary>
<core:ClosureSurface>
<gml:name>Ground Floor / Corridor / Closure Surface South</gml:name>
<core:lod2MultiSurface>
<gml:MultiSurface>
<gml:surfaceMember>
<gml:Polygon
gml:id="_Room-Objects-Surfaces_BD.duiY1tKGgRCVPb6UyU7Z_PG.qg0s5acCsfhIfr6PB4Wq">
<gml:exterior>
<gml:LinearRing>
<gml:posList srsDimension="3">458903.8 5438789.01
116.2 458904.695 5438789.01 116.2 458904.695
5438789.01 113.7 458903.8 5438789.01 113.7
458903.8 5438789.01 116.2</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</core:lod2MultiSurface>
</core:ClosureSurface>
</core:boundary>
<core:boundary>
<con:CeilingSurface>
<gml:name>Ground Floor / Corridor / Ceiling</gml:name>
<core:lod2MultiSurface>
<gml:MultiSurface>
<gml:surfaceMember>
<gml:Polygon
gml:id="_Room-Objects-Surfaces_BD.duiY1tKGgRCVPb6UyU7Z_PG.3JAm3zajWz8Rynn4jCYp">
<gml:exterior>
<gml:LinearRing>
<gml:posList srsDimension="3">458903.8 5438789.25
116.2 458900.3 5438789.25 116.2 458900.3
5438790.75 116.2 458907.41 5438790.75 116.2
458907.41 5438789.01 116.2 458904.695 5438789.01
116.2 458903.8 5438789.01 116.2 458903.8
5438789.25 116.2</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</core:lod2MultiSurface>
</con:CeilingSurface>
</core:boundary>
<core:boundary>
<con:InteriorWallSurface>
<gml:name>Ground Floor / Corridor / Wall East</gml:name>
<core:lod2MultiSurface>
<gml:MultiSurface>
<gml:surfaceMember>
<gml:Polygon
gml:id="_Room-Objects-Surfaces_BD.duiY1tKGgRCVPb6UyU7Z_PG.JflNuIX7gp1oMxUXGW8Y">
<gml:exterior>
<gml:LinearRing>
<gml:posList srsDimension="3">458907.41 5438790.75
116.2 458907.41 5438790.75 113.7 458907.41
5438789.01 113.7 458907.41 5438789.01 116.2
458907.41 5438790.75 116.2</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</core:lod2MultiSurface>
</con:InteriorWallSurface>
</core:boundary>
<core:boundary>
<con:InteriorWallSurface>
<gml:name>Ground Floor / Corridor / Wall North</gml:name>
<core:lod2MultiSurface>
<gml:MultiSurface>
<gml:surfaceMember>
<gml:Polygon
gml:id="_Room-Objects-Surfaces_BD.duiY1tKGgRCVPb6UyU7Z_PG.ALQ0ACBrfU0RLMnmcma7">
<gml:exterior>
<gml:LinearRing>
<gml:posList srsDimension="3">458900.3 5438790.75
113.7 458907.41 5438790.75 113.7 458907.41
5438790.75 116.2 458900.3 5438790.75 116.2
458900.3 5438790.75 113.7</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</core:lod2MultiSurface>
</con:InteriorWallSurface>
</core:boundary>
<core:boundary>
<con:InteriorWallSurface>
<gml:name>Ground Floor / Corridor / Wall West I</gml:name>
<core:lod2MultiSurface>
<gml:MultiSurface>
<gml:surfaceMember>
<gml:Polygon
gml:id="_Room-Objects-Surfaces_BD.duiY1tKGgRCVPb6UyU7Z_PG.B3YW3ludzkRW2rTyzqaL">
<gml:exterior>
<gml:LinearRing>
<gml:posList srsDimension="3">458900.3 5438789.25
113.7 458900.3 5438790.75 113.7 458900.3
5438790.75 116.2 458900.3 5438789.25 116.2
458900.3 5438789.25 113.7</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</core:lod2MultiSurface>
</con:InteriorWallSurface>
</core:boundary>
<core:boundary>
<con:InteriorWallSurface>
<gml:name>Ground Floor / Corridor / Wall South</gml:name>
<core:lod2MultiSurface>
<gml:MultiSurface>
<gml:surfaceMember>
<gml:Polygon
gml:id="_Room-Objects-Surfaces_BD.duiY1tKGgRCVPb6UyU7Z_PG.AvVrIqiQJpKsdHwXCgRR">
<gml:exterior>
<gml:LinearRing>
<gml:posList srsDimension="3">458903.8 5438789.25
113.7 458900.3 5438789.25 113.7 458900.3
5438789.25 116.2 458903.8 5438789.25 116.2
458903.8 5438789.25 113.7</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</core:lod2MultiSurface>
</con:InteriorWallSurface>
</core:boundary>
<core:boundary>
<con:InteriorWallSurface>
<gml:name>Ground Floor / Corridor / Wall West II </gml:name>
<core:lod2MultiSurface>
<gml:MultiSurface>
<gml:surfaceMember>
<gml:Polygon
gml:id="_Room-Objects-Surfaces_BD.duiY1tKGgRCVPb6UyU7Z_PG.otBjqVnvyltlHrGgaE9a">
<gml:exterior>
<gml:LinearRing>
<gml:posList srsDimension="3">458903.8 5438789.01
113.7 458903.8 5438789.25 113.7 458903.8
5438789.25 116.2 458903.8 5438789.01 116.2
458903.8 5438789.01 113.7</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</core:lod2MultiSurface>
</con:InteriorWallSurface>
</core:boundary>
<core:boundary>
<con:FloorSurface>
<gml:name>Ground Floor / Corridor / Floor</gml:name>
<core:lod2MultiSurface>
<gml:MultiSurface>
<gml:surfaceMember>
<gml:Polygon
gml:id="_Room-Objects-Surfaces_BD.duiY1tKGgRCVPb6UyU7Z_PG.2GqEiZO40CFLu1hUeFDW">
<gml:exterior>
<gml:LinearRing>
<gml:posList srsDimension="3">458903.8 5438789.01
113.7 458904.695 5438789.01 113.7 458907.41
5438789.01 113.7 458907.41 5438790.75 113.7
458900.3 5438790.75 113.7 458900.3 5438789.25
113.7 458903.8 5438789.25 113.7 458903.8
5438789.01 113.7</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</core:lod2MultiSurface>
</con:FloorSurface>
</core:boundary>
</bldg:BuildingRoom>
</bldg:buildingRoom>
<bldg:buildingRoom>
<bldg:BuildingRoom gml:id="_Room-Objects-Surfaces_BD.Op5veFsmiFULpCjDeSwG">
<gml:name>04 Ground Floor - Living Room</gml:name>
<core:boundary>
<core:ClosureSurface>
<gml:name>Ground Floor / Living Room / Closure Surface West</gml:name>
<core:lod2MultiSurface>
<gml:MultiSurface>
<gml:surfaceMember>
<gml:Polygon
gml:id="_Room-Objects-Surfaces_BD.Op5veFsmiFULpCjDeSwG_PG.DHvu37iMnMUf6fRRZJDx">
<gml:exterior>
<gml:LinearRing>
<gml:posList srsDimension="3">458904.695 5438785.3
116.2 458904.695 5438785.3 113.7 458904.695
5438789.01 113.7 458904.695 5438789.01 116.2
458904.695 5438785.3 116.2</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</core:lod2MultiSurface>
</core:ClosureSurface>
</core:boundary>
<core:boundary>
<core:ClosureSurface>
<gml:name>Ground Floor / Living Room / Closure Surface North</gml:name>
<core:lod2MultiSurface>
<gml:MultiSurface>
<gml:surfaceMember>
<gml:Polygon
gml:id="_Room-Objects-Surfaces_BD.Op5veFsmiFULpCjDeSwG_PG.GTyC4CgGGJCAHGWCrfaU">
<gml:exterior>
<gml:LinearRing>
<gml:posList srsDimension="3">458904.695
5438789.01 113.7 458907.41 5438789.01 113.7
458907.41 5438789.01 116.2 458904.695 5438789.01
116.2 458904.695 5438789.01 113.7</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</core:lod2MultiSurface>
</core:ClosureSurface>
</core:boundary>
<core:boundary>
<con:CeilingSurface>
<gml:name>Ground Floor / Living Room / Ceiling</gml:name>
<core:lod2MultiSurface>
<gml:MultiSurface>
<gml:surfaceMember>
<gml:Polygon
gml:id="_Room-Objects-Surfaces_BD.Op5veFsmiFULpCjDeSwG_PG.9D1bOyQRA7KFEpsi1Hjr">
<gml:exterior>
<gml:LinearRing>
<gml:posList srsDimension="3">458904.695
5438789.01 116.2 458907.41 5438789.01 116.2
458911.7 5438789.01 116.2 458911.7 5438785.3 116.2
458904.695 5438785.3 116.2 458904.695 5438789.01
116.2</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</core:lod2MultiSurface>
</con:CeilingSurface>
</core:boundary>
<core:boundary>
<con:InteriorWallSurface>
<gml:name>Ground Floor / Living Room / Interior Wall North</gml:name>
<core:lod2MultiSurface>
<gml:MultiSurface>
<gml:surfaceMember>
<gml:Polygon
gml:id="_Room-Objects-Surfaces_BD.Op5veFsmiFULpCjDeSwG_PG.OIMEC4yqF8TyKbGa3bjv">
<gml:exterior>
<gml:LinearRing>
<gml:posList srsDimension="3">458911.7 5438789.01
116.2 458907.41 5438789.01 116.2 458907.41
5438789.01 113.7 458911.7 5438789.01 113.7
458911.7 5438789.01 116.2</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</core:lod2MultiSurface>
</con:InteriorWallSurface>
</core:boundary>
<core:boundary>
<con:InteriorWallSurface>
<gml:name>Ground Floor / Living Room / Interior Wall South</gml:name>
<core:lod2MultiSurface>
<gml:MultiSurface>
<gml:surfaceMember>
<gml:Polygon
gml:id="_Room-Objects-Surfaces_BD.Op5veFsmiFULpCjDeSwG_PG.jQaBBkJMFLl7D0JzhfXk">
<gml:exterior>
<gml:LinearRing>
<gml:posList srsDimension="3">458911.7 5438785.3
116.2 458911.7 5438785.3 113.7 458904.695
5438785.3 113.7 458904.695 5438785.3 116.2
458911.7 5438785.3 116.2</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</core:lod2MultiSurface>
</con:InteriorWallSurface>
</core:boundary>
<core:boundary>
<con:InteriorWallSurface>
<gml:name>Ground Floor / Living Room / Interior Wall East</gml:name>
<core:lod2MultiSurface>
<gml:MultiSurface>
<gml:surfaceMember>
<gml:Polygon
gml:id="_Room-Objects-Surfaces_BD.Op5veFsmiFULpCjDeSwG_PG.H8M9QNeJCUq5HlnwK4K0">
<gml:exterior>
<gml:LinearRing>
<gml:posList srsDimension="3">458911.7 5438789.01
116.2 458911.7 5438789.01 113.7 458911.7 5438785.3
113.7 458911.7 5438785.3 116.2 458911.7 5438789.01
116.2</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</core:lod2MultiSurface>
</con:InteriorWallSurface>
</core:boundary>
<core:boundary>
<con:FloorSurface>
<gml:name>Ground Floor / Living Room / Floor</gml:name>
<core:lod2MultiSurface>
<gml:MultiSurface>
<gml:surfaceMember>
<gml:Polygon
gml:id="_Room-Objects-Surfaces_BD.Op5veFsmiFULpCjDeSwG_PG.BJcZsFiOyU6A9c1XO6p4">
<gml:exterior>
<gml:LinearRing>
<gml:posList srsDimension="3">458904.695 5438785.3
113.7 458911.7 5438785.3 113.7 458911.7 5438789.01
113.7 458907.41 5438789.01 113.7 458904.695
5438789.01 113.7 458904.695 5438785.3
113.7</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</core:lod2MultiSurface>
</con:FloorSurface>
</core:boundary>
</bldg:BuildingRoom>
</bldg:buildingRoom>
<bldg:buildingRoom>
<bldg:BuildingRoom gml:id="_Room-Objects-Surfaces_BD.woCShAp7GrZQRRPhEnlA">
<gml:name>05 Ground Floor - Bedroom</gml:name>
<core:boundary>
<con:CeilingSurface>
<gml:name>Ground Floor / Bedroom / Ceiling</gml:name>
<core:lod2MultiSurface>
<gml:MultiSurface>
<gml:surfaceMember>
<gml:Polygon
gml:id="_Room-Objects-Surfaces_BD.woCShAp7GrZQRRPhEnlA_PG.OyFIcm7RArOIL1LdXwtq">
<gml:exterior>
<gml:LinearRing>
<gml:posList srsDimension="3">458911.7 5438789.25
116.2 458907.65 5438789.25 116.2 458907.65
5438794.7 116.2 458911.7 5438794.7 116.2 458911.7
5438789.25 116.2</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</core:lod2MultiSurface>
</con:CeilingSurface>
</core:boundary>
<core:boundary>
<con:InteriorWallSurface>
<gml:name>Ground Floor / Bedroom / Interior Wall West</gml:name>
<core:lod2MultiSurface>
<gml:MultiSurface>
<gml:surfaceMember>
<gml:Polygon
gml:id="_Room-Objects-Surfaces_BD.woCShAp7GrZQRRPhEnlA_PG.95irT11n4ZgMiX2q4250">
<gml:exterior>
<gml:LinearRing>
<gml:posList srsDimension="3">458907.65 5438789.25
116.2 458907.65 5438789.25 113.7 458907.65
5438794.7 113.7 458907.65 5438794.7 116.2
458907.65 5438789.25 116.2</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</core:lod2MultiSurface>
</con:InteriorWallSurface>
</core:boundary>
<core:boundary>
<con:InteriorWallSurface>
<gml:name>Ground Floor / Bedroom / Interior Wall South</gml:name>
<core:lod2MultiSurface>
<gml:MultiSurface>
<gml:surfaceMember>
<gml:Polygon
gml:id="_Room-Objects-Surfaces_BD.woCShAp7GrZQRRPhEnlA_PG.9t7FtD4sXx9ALWHmlDtS">
<gml:exterior>
<gml:LinearRing>
<gml:posList srsDimension="3">458911.7 5438789.25
116.2 458911.7 5438789.25 113.7 458907.65
5438789.25 113.7 458907.65 5438789.25 116.2
458911.7 5438789.25 116.2</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</core:lod2MultiSurface>
</con:InteriorWallSurface>
</core:boundary>
<core:boundary>
<con:InteriorWallSurface>
<gml:name>Ground Floor / Bedroom / Interior Wall North</gml:name>
<core:lod2MultiSurface>
<gml:MultiSurface>
<gml:surfaceMember>
<gml:Polygon
gml:id="_Room-Objects-Surfaces_BD.woCShAp7GrZQRRPhEnlA_PG.BxBfyPe1b1miAWxEeLnW">
<gml:exterior>
<gml:LinearRing>
<gml:posList srsDimension="3">458907.65 5438794.7
116.2 458907.65 5438794.7 113.7 458911.7 5438794.7
113.7 458911.7 5438794.7 116.2 458907.65 5438794.7
116.2</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</core:lod2MultiSurface>
</con:InteriorWallSurface>
</core:boundary>
<core:boundary>
<con:InteriorWallSurface>
<gml:name>Ground Floor / Bedroom / Interior Wall East</gml:name>
<core:lod2MultiSurface>
<gml:MultiSurface>
<gml:surfaceMember>
<gml:Polygon
gml:id="_Room-Objects-Surfaces_BD.woCShAp7GrZQRRPhEnlA_PG.RcepErHZFrkQD6M3yjKg">
<gml:exterior>
<gml:LinearRing>
<gml:posList srsDimension="3">458911.7 5438794.7
116.2 458911.7 5438794.7 113.7 458911.7 5438789.25
113.7 458911.7 5438789.25 116.2 458911.7 5438794.7
116.2</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</core:lod2MultiSurface>
</con:InteriorWallSurface>
</core:boundary>
<core:boundary>
<con:FloorSurface>
<gml:name>Ground Floor / Bedroom / Floor</gml:name>
<core:lod2MultiSurface>
<gml:MultiSurface>
<gml:surfaceMember>
<gml:Polygon
gml:id="_Room-Objects-Surfaces_BD.woCShAp7GrZQRRPhEnlA_PG.Eys5xIoR03TkxIj9vTk1">
<gml:exterior>
<gml:LinearRing>
<gml:posList srsDimension="3">458911.7 5438789.25
113.7 458911.7 5438794.7 113.7 458907.65 5438794.7
113.7 458907.65 5438789.25 113.7 458911.7
5438789.25 113.7</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</core:lod2MultiSurface>
</con:FloorSurface>
</core:boundary>
</bldg:BuildingRoom>
</bldg:buildingRoom>
<bldg:buildingRoom>
<bldg:BuildingRoom gml:id="_Room-Objects-Surfaces_BD.AfxdvkCh4we3s3I4Dy4W">
<gml:name>06 Ground Floor - Bathroom</gml:name>
<core:boundary>
<con:CeilingSurface>
<gml:name>Ground Floor / Bathroom / Ceiling</gml:name>
<core:lod2MultiSurface>
<gml:MultiSurface>
<gml:surfaceMember>
<gml:Polygon
gml:id="_Room-Objects-Surfaces_BD.AfxdvkCh4we3s3I4Dy4W_PG.wbld7fzImYe8NWrZcGRY">
<gml:exterior>
<gml:LinearRing>
<gml:posList srsDimension="3">458907.41 5438790.99
116.2 458904.04 5438790.99 116.2 458904.04
5438794.7 116.2 458907.41 5438794.7 116.2
458907.41 5438790.99 116.2</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</core:lod2MultiSurface>
</con:CeilingSurface>
</core:boundary>
<core:boundary>
<con:InteriorWallSurface>
<gml:name>Ground Floor / Bathroom / Interior Wall West</gml:name>
<core:lod2MultiSurface>
<gml:MultiSurface>
<gml:surfaceMember>
<gml:Polygon
gml:id="_Room-Objects-Surfaces_BD.AfxdvkCh4we3s3I4Dy4W_PG.uUYnQpymZNNZmWGwOZfy">
<gml:exterior>
<gml:LinearRing>
<gml:posList srsDimension="3">458904.04 5438790.99
116.2 458904.04 5438790.99 113.7 458904.04
5438794.7 113.7 458904.04 5438794.7 116.2
458904.04 5438790.99 116.2</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</core:lod2MultiSurface>
</con:InteriorWallSurface>
</core:boundary>
<core:boundary>
<con:InteriorWallSurface>
<gml:name>Ground Floor / Bathroom / Interior Wall South</gml:name>
<core:lod2MultiSurface>
<gml:MultiSurface>
<gml:surfaceMember>
<gml:Polygon
gml:id="_Room-Objects-Surfaces_BD.AfxdvkCh4we3s3I4Dy4W_PG.OrC8rOQfwZzlZoSOCFlx">
<gml:exterior>
<gml:LinearRing>
<gml:posList srsDimension="3">458907.41 5438790.99
116.2 458907.41 5438790.99 113.7 458904.04
5438790.99 113.7 458904.04 5438790.99 116.2
458907.41 5438790.99 116.2</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</core:lod2MultiSurface>
</con:InteriorWallSurface>
</core:boundary>
<core:boundary>
<con:InteriorWallSurface>
<gml:name>Ground Floor / Bathroom / Interior Wall North</gml:name>
<core:lod2MultiSurface>
<gml:MultiSurface>
<gml:surfaceMember>
<gml:Polygon
gml:id="_Room-Objects-Surfaces_BD.AfxdvkCh4we3s3I4Dy4W_PG.nVLVnQvjY4Gi9GmQs19d">
<gml:exterior>
<gml:LinearRing>
<gml:posList srsDimension="3">458904.04 5438794.7
116.2 458904.04 5438794.7 113.7 458907.41
5438794.7 113.7 458907.41 5438794.7 116.2
458904.04 5438794.7 116.2</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</core:lod2MultiSurface>
</con:InteriorWallSurface>
</core:boundary>
<core:boundary>
<con:InteriorWallSurface>
<gml:name>Ground Floor / Bathroom / Interior Wall East</gml:name>
<core:lod2MultiSurface>
<gml:MultiSurface>
<gml:surfaceMember>
<gml:Polygon
gml:id="_Room-Objects-Surfaces_BD.AfxdvkCh4we3s3I4Dy4W_PG.8AXQPYriLaYYGfwI2w7d">
<gml:exterior>
<gml:LinearRing>
<gml:posList srsDimension="3">458907.41 5438794.7
116.2 458907.41 5438794.7 113.7 458907.41
5438790.99 113.7 458907.41 5438790.99 116.2
458907.41 5438794.7 116.2</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</core:lod2MultiSurface>
</con:InteriorWallSurface>
</core:boundary>
<core:boundary>
<con:FloorSurface>
<gml:name>Ground Floor / Bathroom / Floor</gml:name>
<core:lod2MultiSurface>
<gml:MultiSurface>
<gml:surfaceMember>
<gml:Polygon
gml:id="_Room-Objects-Surfaces_BD.AfxdvkCh4we3s3I4Dy4W_PG.mr7MWYpWAyS3j0YfB27d">
<gml:exterior>
<gml:LinearRing>
<gml:posList srsDimension="3">458907.41 5438790.99
113.7 458907.41 5438794.7 113.7 458904.04
5438794.7 113.7 458904.04 5438790.99 113.7
458907.41 5438790.99 113.7</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</core:lod2MultiSurface>
</con:FloorSurface>
</core:boundary>
</bldg:BuildingRoom>
</bldg:buildingRoom>
<bldg:buildingRoom>
<bldg:BuildingRoom gml:id="_Room-Objects-Surfaces_BD.yVH3lRCjUIBvv88usXTL">
<gml:name>07 Ground Floor - Office</gml:name>
<core:boundary>
<con:CeilingSurface>
<gml:name>Ground Floor / Office / Ceiling</gml:name>
<core:lod2MultiSurface>
<gml:MultiSurface>
<gml:surfaceMember>
<gml:Polygon
gml:id="_Room-Objects-Surfaces_BD.yVH3lRCjUIBvv88usXTL_PG.CsTLhL534vWs7g0e1aTh">
<gml:exterior>
<gml:LinearRing>
<gml:posList srsDimension="3">458903.8 5438790.99
116.2 458900.3 5438790.99 116.2 458900.3 5438794.7
116.2 458903.8 5438794.7 116.2 458903.8 5438790.99
116.2</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</core:lod2MultiSurface>
</con:CeilingSurface>
</core:boundary>
<core:boundary>
<con:InteriorWallSurface>
<gml:name>Ground Floor / Office / Interior Wall West</gml:name>
<core:lod2MultiSurface>
<gml:MultiSurface>
<gml:surfaceMember>
<gml:Polygon
gml:id="_Room-Objects-Surfaces_BD.yVH3lRCjUIBvv88usXTL_PG.rIbl0lq2kSGyKbzXloFX">
<gml:exterior>
<gml:LinearRing>
<gml:posList srsDimension="3">458900.3 5438790.99
116.2 458900.3 5438790.99 113.7 458900.3 5438794.7
113.7 458900.3 5438794.7 116.2 458900.3 5438790.99
116.2</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</core:lod2MultiSurface>
</con:InteriorWallSurface>
</core:boundary>
<core:boundary>
<con:InteriorWallSurface>
<gml:name>Ground Floor / Office / Interior Wall South</gml:name>
<core:lod2MultiSurface>
<gml:MultiSurface>
<gml:surfaceMember>
<gml:Polygon
gml:id="_Room-Objects-Surfaces_BD.yVH3lRCjUIBvv88usXTL_PG.0BJ7pQ8ZNJTgMEdPP3hB">
<gml:exterior>
<gml:LinearRing>
<gml:posList srsDimension="3">458903.8 5438790.99
116.2 458903.8 5438790.99 113.7 458900.3
5438790.99 113.7 458900.3 5438790.99 116.2
458903.8 5438790.99 116.2</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</core:lod2MultiSurface>
</con:InteriorWallSurface>
</core:boundary>
<core:boundary>
<con:InteriorWallSurface>
<gml:name>Ground Floor / Office / Interior Wall North</gml:name>
<core:lod2MultiSurface>
<gml:MultiSurface>
<gml:surfaceMember>
<gml:Polygon
gml:id="_Room-Objects-Surfaces_BD.yVH3lRCjUIBvv88usXTL_PG.b6Nl2FrZvZc3YYCRlfjO">
<gml:exterior>
<gml:LinearRing>
<gml:posList srsDimension="3">458900.3 5438794.7
116.2 458900.3 5438794.7 113.7 458903.8 5438794.7
113.7 458903.8 5438794.7 116.2 458900.3 5438794.7
116.2</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</core:lod2MultiSurface>
</con:InteriorWallSurface>
</core:boundary>
<core:boundary>
<con:InteriorWallSurface>
<gml:name>Ground Floor / Office / Interior Wall East</gml:name>
<core:lod2MultiSurface>
<gml:MultiSurface>
<gml:surfaceMember>
<gml:Polygon
gml:id="_Room-Objects-Surfaces_BD.yVH3lRCjUIBvv88usXTL_PG.bF2t5nIuHqZao3PVpgVl">
<gml:exterior>
<gml:LinearRing>
<gml:posList srsDimension="3">458903.8 5438794.7
116.2 458903.8 5438794.7 113.7 458903.8 5438790.99
113.7 458903.8 5438790.99 116.2 458903.8 5438794.7
116.2</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</core:lod2MultiSurface>
</con:InteriorWallSurface>
</core:boundary>
<core:boundary>
<con:FloorSurface>
<gml:name>Ground Floor / Office / Floor</gml:name>
<core:lod2MultiSurface>
<gml:MultiSurface>
<gml:surfaceMember>
<gml:Polygon
gml:id="_Room-Objects-Surfaces_BD.yVH3lRCjUIBvv88usXTL_PG.eeylEeI5HrDpBEX6feEv">
<gml:exterior>
<gml:LinearRing>
<gml:posList srsDimension="3">458903.8 5438790.99
113.7 458903.8 5438794.7 113.7 458900.3 5438794.7
113.7 458900.3 5438790.99 113.7 458903.8
5438790.99 113.7</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</core:lod2MultiSurface>
</con:FloorSurface>
</core:boundary>
</bldg:BuildingRoom>
</bldg:buildingRoom>
</bldg:Storey>
</bldg:buildingSubdivision>
<bldg:buildingSubdivision>
<bldg:Storey>
<gml:name>Second Floor</gml:name>
<core:boundary>
<con:RoofSurface>
<gml:name>Second Floor / Roof South</gml:name>
<core:lod2MultiSurface>
<gml:MultiSurface>
<gml:surfaceMember>
<gml:Polygon
gml:id="KIT-Test-Building-01_PG.as933cYedpVOQ8Wqm9j7">
<gml:exterior>
<gml:LinearRing
gml:id="KIT-Test-Building-01_LR.FJ2G4jJFUVmWcdGG3gyw">
<gml:posList srsDimension="3"> 458912.0 5438790.0
120.017691 458900.0 5438790.0 120.017691 458900.0
5438785.0 117.13094 458912.0 5438785.0 117.13094
458912.0 5438790.0 120.017691 </gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</core:lod2MultiSurface>
</con:RoofSurface>
</core:boundary>
<core:boundary>
<con:RoofSurface>
<gml:name>Second Floor / Roof North</gml:name>
<core:lod2MultiSurface>
<gml:MultiSurface>
<gml:surfaceMember>
<gml:Polygon
gml:id="KIT-Test-Building-01_PG.CUXCVrNXAnCgCUjdXnY1">
<gml:exterior>
<gml:LinearRing
gml:id="KIT-Test-Building-01_LR.cYvvi9l6K4nl9jeHjt03">
<gml:posList srsDimension="3"> 458900.0 5438790.0
120.017691 458912.0 5438790.0 120.017691 458912.0
5438795.0 117.13094 458900.0 5438795.0 117.13094
458900.0 5438790.0 120.017691 </gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</core:lod2MultiSurface>
</con:RoofSurface>
</core:boundary>
<core:boundary>
<con:WallSurface>
<gml:name>Second Floor / Wall South</gml:name>
<core:lod2MultiSurface>
<gml:MultiSurface>
<gml:surfaceMember>
<gml:Polygon
gml:id="KIT-Test-Building-01_PG.nfWbzHM5j2MqtisYAjgV">
<gml:exterior>
<gml:LinearRing
gml:id="KIT-Test-Building-01_LR.l5vPQsQlvAxe0PfGrItK">
<gml:posList srsDimension="3"> 458900.0 5438785.0
117.13094 458900.0 5438785.0 116.4 458912.0
5438785.0 116.4 458912.0 5438785.0 117.13094
458900.0 5438785.0 117.13094 </gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</core:lod2MultiSurface>
</con:WallSurface>
</core:boundary>
<core:boundary>
<con:WallSurface>
<gml:name>Second Floor / Wall West</gml:name>
<core:lod2MultiSurface>
<gml:MultiSurface>
<gml:surfaceMember>
<gml:Polygon
gml:id="KIT-Test-Building-01_PG.VdnPNlkOAJHnTVZL5R37">
<gml:exterior>
<gml:LinearRing
gml:id="KIT-Test-Building-01_LR.CWPcEAowucw9pxGFPH3S">
<gml:posList srsDimension="3"> 458900.0 5438795.0
117.13094 458900.0 5438795.0 116.4 458900.0
5438785.0 116.4 458900.0 5438785.0 117.13094
458900.0 5438790.0 120.017691 458900.0 5438795.0
117.13094 </gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</core:lod2MultiSurface>
</con:WallSurface>
</core:boundary>
<core:boundary>
<con:WallSurface>
<gml:name>Second Floor / Wall East</gml:name>
<core:lod2MultiSurface>
<gml:MultiSurface>
<gml:surfaceMember>
<gml:Polygon
gml:id="KIT-Test-Building-01_PG.ioJ6HX4PnhWvLSYhPA7h">
<gml:exterior>
<gml:LinearRing
gml:id="KIT-Test-Building-01_LR.VpCnRrYqLGD4bFFZLmWC">
<gml:posList srsDimension="3"> 458912.0 5438785.0
117.13094 458912.0 5438785.0 116.4 458912.0
5438795.0 116.4 458912.0 5438795.0 117.13094
458912.0 5438790.0 120.017691 458912.0 5438785.0
117.13094 </gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</core:lod2MultiSurface>
</con:WallSurface>
</core:boundary>
<core:boundary>
<con:WallSurface>
<gml:name>Second Floor / Wall North</gml:name>
<core:lod2MultiSurface>
<gml:MultiSurface>
<gml:surfaceMember>
<gml:Polygon
gml:id="KIT-Test-Building-01_PG.cdHLpEJXgkf3Hq9x6PF7">
<gml:exterior>
<gml:LinearRing
gml:id="KIT-Test-Building-01_LR.ODQPptDGkQ9xxB6LArAA">
<gml:posList srsDimension="3"> 458912.0 5438795.0
117.13094 458912.0 5438795.0 116.4 458900.0
5438795.0 116.4 458900.0 5438795.0 117.13094
458912.0 5438795.0 117.13094 </gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</core:lod2MultiSurface>
</con:WallSurface>
</core:boundary>
<bldg:buildingRoom>
<bldg:BuildingRoom gml:id="_Room-Objects-Surfaces_BD.1k0OduRPxnDi7ZvjVnPC">
<gml:name>01 Second Floor - Galery</gml:name>
<core:boundary>
<con:CeilingSurface>
<gml:name>Second Floor / Galery / Ceiling North</gml:name>
<core:lod2MultiSurface>
<gml:MultiSurface>
<gml:surfaceMember>
<gml:Polygon
gml:id="_Room-Objects-Surfaces_BD.1k0OduRPxnDi7ZvjVnPC_PG.MrztnJe3cIqx0g03yvP8">
<gml:exterior>
<gml:LinearRing>
<gml:posList srsDimension="3">458900.3 5438794.7
117.073205 458911.7 5438794.7 117.073205 458911.7
5438790.0 119.786751 458900.3 5438790.0 119.786751
458900.3 5438794.7 117.073205</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</core:lod2MultiSurface>
</con:CeilingSurface>
</core:boundary>
<core:boundary>
<con:CeilingSurface>
<gml:name>Second Floor / Galery / Ceiling South</gml:name>
<core:lod2MultiSurface>
<gml:MultiSurface>
<gml:surfaceMember>
<gml:Polygon
gml:id="_Room-Objects-Surfaces_BD.1k0OduRPxnDi7ZvjVnPC_PG.dOu2It7QvIkAvQUT8eLp">
<gml:exterior>
<gml:LinearRing>
<gml:posList srsDimension="3">458900.3 5438785.3
117.073205 458900.3 5438790.0 119.786751 458911.7
5438790.0 119.786751 458911.7 5438785.3 117.073205
458900.3 5438785.3 117.073205</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</core:lod2MultiSurface>
</con:CeilingSurface>
</core:boundary>
<core:boundary>
<con:InteriorWallSurface>
<gml:name>Second Floor / Galery / Interior Wall North</gml:name>
<core:lod2MultiSurface>
<gml:MultiSurface>
<gml:surfaceMember>
<gml:Polygon
gml:id="_Room-Objects-Surfaces_BD.1k0OduRPxnDi7ZvjVnPC_PG.E6fMYbyqNfDDUJrvbM3a">
<gml:exterior>
<gml:LinearRing>
<gml:posList srsDimension="3">458911.7 5438794.7
116.4 458911.7 5438794.7 117.073205 458900.3
5438794.7 117.073205 458900.3 5438794.7 116.4
458911.7 5438794.7 116.4</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</core:lod2MultiSurface>
</con:InteriorWallSurface>
</core:boundary>
<core:boundary>
<con:InteriorWallSurface>
<gml:name>Second Floor / Galery / Interior Wall East</gml:name>
<core:lod2MultiSurface>
<gml:MultiSurface>
<gml:surfaceMember>
<gml:Polygon
gml:id="_Room-Objects-Surfaces_BD.1k0OduRPxnDi7ZvjVnPC_PG.A7Fo8PEsLEyMB32PGMHq">
<gml:exterior>
<gml:LinearRing>
<gml:posList srsDimension="3">458911.7 5438794.7
117.073205 458911.7 5438794.7 116.4 458911.7
5438785.3 116.4 458911.7 5438785.3 117.073205
458911.7 5438790.0 119.786751 458911.7 5438794.7
117.073205</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</core:lod2MultiSurface>
</con:InteriorWallSurface>
</core:boundary>
<core:boundary>
<con:InteriorWallSurface>
<gml:name>Second Floor / Galery / Interior Wall West</gml:name>
<core:lod2MultiSurface>
<gml:MultiSurface>
<gml:surfaceMember>
<gml:Polygon
gml:id="_Room-Objects-Surfaces_BD.1k0OduRPxnDi7ZvjVnPC_PG.yAt1pSqygx9MVsIQPGXO">
<gml:exterior>
<gml:LinearRing>
<gml:posList srsDimension="3">458900.3 5438790.0
119.786751 458900.3 5438785.3 117.073205 458900.3
5438785.3 116.4 458900.3 5438794.7 116.4 458900.3
5438794.7 117.073205 458900.3 5438790.0
119.786751</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</core:lod2MultiSurface>
</con:InteriorWallSurface>
</core:boundary>
<core:boundary>
<con:InteriorWallSurface>
<gml:name>Second Floor / Galery / Interior Wall South</gml:name>
<core:lod2MultiSurface>
<gml:MultiSurface>
<gml:surfaceMember>
<gml:Polygon
gml:id="_Room-Objects-Surfaces_BD.1k0OduRPxnDi7ZvjVnPC_PG.lViHXUkDwidWS9ze3lOE">
<gml:exterior>
<gml:LinearRing>
<gml:posList srsDimension="3">458900.3 5438785.3
116.4 458900.3 5438785.3 117.073205 458911.7
5438785.3 117.073205 458911.7 5438785.3 116.4
458900.3 5438785.3 116.4</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</core:lod2MultiSurface>
</con:InteriorWallSurface>
</core:boundary>
<core:boundary>
<con:FloorSurface>
<gml:name>Second Floor / Galery / Floor</gml:name>
<core:lod2MultiSurface>
<gml:MultiSurface>
<gml:surfaceMember>
<gml:Polygon
gml:id="_Room-Objects-Surfaces_BD.1k0OduRPxnDi7ZvjVnPC_PG.hI0W1wCa6RYPDNx4Mj1A">
<gml:exterior>
<gml:LinearRing>
<gml:posList srsDimension="3">458911.7 5438785.3
116.4 458911.7 5438794.7 116.4 458900.3 5438794.7
116.4 458900.3 5438785.3 116.4 458911.7 5438785.3
116.4</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</core:lod2MultiSurface>
</con:FloorSurface>
</core:boundary>
</bldg:BuildingRoom>
</bldg:buildingRoom>
</bldg:Storey>
</bldg:buildingSubdivision>
</bldg:Building>
</core:cityObjectMember>
<core:appearanceMember>
<app:Appearance>
<app:surfaceData>
<app:ParameterizedTexture>
<app:imageURI>textures/FZK-Haus-Front.png</app:imageURI>
<app:wrapMode>wrap</app:wrapMode>
<app:textureParameterization>
<app:TextureAssociation>
<app:target>#KIT-Test-Building-01_PG.nfWbzHM5j2MqtisYAjgV</app:target>
<app:textureParameterization>
<app:TexCoordList>
<app:textureCoordinates> -6.01592849610218e-17 1.000011046207786
-3.0079642480510886e-17 0.7987000468203478
1.0000000000000002 0.7987000468203478 1.0000000000000002
1.000011046207786 -6.01592849610218e-17
1.000011046207786</app:textureCoordinates>
<app:ring>#KIT-Test-Building-01_LR.l5vPQsQlvAxe0PfGrItK</app:ring>
</app:TexCoordList>
</app:textureParameterization>
</app:TextureAssociation>
</app:textureParameterization>
<app:textureParameterization>
<app:TextureAssociation>
<app:target>#KIT-Test-Building-01_PG.8Oi6zRMGuUdvjDA3942O</app:target>
<app:textureParameterization>
<app:TexCoordList>
<app:textureCoordinates> 1.0000000000000002
-4.454490602082857e-31 1.0000000000000002 0.7987000468203478
-3.007964248051091e-17 0.7987000468203478 0.0
-5.359579389737923e-47 1.0000000000000002
-4.454490602082857e-31 </app:textureCoordinates>
<app:ring>#KIT-Test-Building-01_LR.dQRaAbGZocTDsiXUS3Wo</app:ring>
</app:TexCoordList>
</app:textureParameterization>
</app:TextureAssociation>
</app:textureParameterization>
</app:ParameterizedTexture>
</app:surfaceData>
<app:surfaceData>
<app:ParameterizedTexture>
<app:imageURI>textures/FZK-Haus-Right.png</app:imageURI>
<app:wrapMode>wrap</app:wrapMode>
<app:textureParameterization>
<app:TextureAssociation>
<app:target>#KIT-Test-Building-01_PG.ioJ6HX4PnhWvLSYhPA7h</app:target>
<app:textureParameterization>
<app:TexCoordList>
<app:textureCoordinates> 7.560328766851198e-17
0.5570891737385654 5.087501393878691e-16 0.444942234223729
1.0000000000000004 0.44494223422372897 1.0000000000000004
0.5570891737385655 0.49999999999999994 0.9999986887435715
7.560328766851198e-17 0.5570891737385654 </app:textureCoordinates>
<app:ring>#KIT-Test-Building-01_LR.VpCnRrYqLGD4bFFZLmWC</app:ring>
</app:TexCoordList>
</app:textureParameterization>
</app:TextureAssociation>
</app:textureParameterization>
<app:textureParameterization>
<app:TextureAssociation>
<app:target>#KIT-Test-Building-01_PG.WH3ZPoThoidUosBGLd28</app:target>
<app:textureParameterization>
<app:TexCoordList>
<app:textureCoordinates> 1.0000000000000004
-2.907494171674344e-16 1.0000000000000004
0.44494223422372897 5.087501393878691e-16 0.444942234223729
7.560328766851198e-17 -2.907494171674344e-16
1.0000000000000004
-2.907494171674344e-16</app:textureCoordinates>
<app:ring>#KIT-Test-Building-01_LR.kb6UBRDjXdQhuZgyrrXF</app:ring>
</app:TexCoordList>
</app:textureParameterization>
</app:TextureAssociation>
</app:textureParameterization>
</app:ParameterizedTexture>
</app:surfaceData>
<app:surfaceData>
<app:ParameterizedTexture>
<app:imageURI>textures/FZK-Haus-Left.png</app:imageURI>
<app:wrapMode>wrap</app:wrapMode>
<app:textureParameterization>
<app:TextureAssociation>
<app:target>#KIT-Test-Building-01_PG.VdnPNlkOAJHnTVZL5R37</app:target>
<app:textureParameterization>
<app:TexCoordList>
<app:textureCoordinates> -1.0 0.5570891737385658
-0.9999999999999996 0.44494223422372936
4.331468517193571e-16 0.44494223422372936
4.331468517193571e-16 0.5570891737385657
-0.49999999999999944 0.9999986887435719 -1.0
0.5570891737385658 </app:textureCoordinates>
<app:ring>#KIT-Test-Building-01_LR.CWPcEAowucw9pxGFPH3S</app:ring>
</app:TexCoordList>
</app:textureParameterization>
</app:TextureAssociation>
</app:textureParameterization>
<app:textureParameterization>
<app:TextureAssociation>
<app:target>#KIT-Test-Building-01_PG.87LG6xx5gYYjprCeHCDY</app:target>
<app:textureParameterization>
<app:TexCoordList>
<app:textureCoordinates> 4.331468517193571e-16
-1.1157709843049066e-47 4.331468517193571e-16
0.44494223422372936 -0.9999999999999996 0.44494223422372936
-1.0 -8.368282382286802e-48 4.331468517193571e-16
-1.1157709843049066e-47 </app:textureCoordinates>
<app:ring>#KIT-Test-Building-01_LR.z42J72DCA0DG7fsjO1iJ</app:ring>
</app:TexCoordList>
</app:textureParameterization>
</app:TextureAssociation>
</app:textureParameterization>
</app:ParameterizedTexture>
</app:surfaceData>
<app:surfaceData>
<app:ParameterizedTexture>
<app:imageURI>textures/Roofing_Shingles_GAF_Estates.jpg</app:imageURI>
<app:wrapMode>wrap</app:wrapMode>
<app:textureParameterization>
<app:TextureAssociation>
<app:target>#KIT-Test-Building-01_PG.as933cYedpVOQ8Wqm9j7</app:target>
<app:textureParameterization>
<app:TexCoordList>
<app:textureCoordinates> 21.47458840372227 18.00558453022584
1.8506199769767277e-15 18.00558453022584
-1.2918958832001822e-15 4.124469685250767 21.47458840372227
4.124469685250767 21.47458840372227 18.00558453022584 </app:textureCoordinates>
<app:ring>#KIT-Test-Building-01_LR.FJ2G4jJFUVmWcdGG3gyw</app:ring>
</app:TexCoordList>
</app:textureParameterization>
</app:TextureAssociation>
</app:textureParameterization>
<app:textureParameterization>
<app:TextureAssociation>
<app:target>#KIT-Test-Building-01_PG.CUXCVrNXAnCgCUjdXnY1</app:target>
<app:textureParameterization>
<app:TexCoordList>
<app:textureCoordinates> -2.0055287249601352e-15
-2.816087737236785 -21.47458840372227 -2.816087737236785
-21.47458840372227 -16.697202582211872
1.8024740244805496e-15 -16.697202582211872
-2.0055287249601352e-15 -2.816087737236785 </app:textureCoordinates>
<app:ring>#KIT-Test-Building-01_LR.cYvvi9l6K4nl9jeHjt03</app:ring>
</app:TexCoordList>
</app:textureParameterization>
</app:TextureAssociation>
</app:textureParameterization>
</app:ParameterizedTexture>
</app:surfaceData>
<app:surfaceData>
<app:ParameterizedTexture>
<app:imageURI>textures/FZK-Haus-Back.png</app:imageURI>
<app:wrapMode>wrap</app:wrapMode>
<app:textureParameterization>
<app:TextureAssociation>
<app:target>#KIT-Test-Building-01_PG.cdHLpEJXgkf3Hq9x6PF7</app:target>
<app:textureParameterization>
<app:TexCoordList>
<app:textureCoordinates> -1.0000000000000002 1.000011046207795
-1.0000000000000002 0.7987000468203566
2.7071678232459823e-16 0.7987000468203567
3.007964248051091e-16 1.000011046207795 -1.0000000000000002
1.000011046207795 </app:textureCoordinates>
<app:ring>#KIT-Test-Building-01_LR.ODQPptDGkQ9xxB6LArAA</app:ring>
</app:TexCoordList>
</app:textureParameterization>
</app:TextureAssociation>
</app:textureParameterization>
<app:textureParameterization>
<app:TextureAssociation>
<app:target>#KIT-Test-Building-01_PG.Y4DuK1eWWjbSOQxjL75Z</app:target>
<app:textureParameterization>
<app:TexCoordList>
<app:textureCoordinates> 3.0079642480510913e-16
-1.4416909618544142e-15 2.707167823245983e-16
0.7987000468203463 -1.0000000000000002 0.7987000468203463
-1.0000000000000002 -1.4416909618544138e-15
3.0079642480510913e-16 -1.4416909618544142e-15 </app:textureCoordinates>
<app:ring>#KIT-Test-Building-01_LR.CvfxHmYhr7DvEJeZnfKH</app:ring>
</app:TexCoordList>
</app:textureParameterization>
</app:TextureAssociation>
</app:textureParameterization>
</app:ParameterizedTexture>
</app:surfaceData>
<app:surfaceData>
<app:X3DMaterial>
<app:ambientIntensity>0.2</app:ambientIntensity>
<app:diffuseColor>0.4666666666666667 0.34509803921568627
0.21176470588235294</app:diffuseColor>
<app:emissiveColor>0.0 0.0 0.0</app:emissiveColor>
<app:specularColor>1.0 1.0 1.0</app:specularColor>
<app:shininess>0.2</app:shininess>
<app:transparency>0.0</app:transparency>
<app:isSmooth>false</app:isSmooth>
<app:target>#KIT-Test-Building-01_PG.B9OH2yr4U3AkPsKWbFy2</app:target>
</app:X3DMaterial>
</app:surfaceData>
</app:Appearance>
</core:appearanceMember>
</core:CityModel>
......@@ -4,7 +4,7 @@
<parent>
<groupId>de.hft.stuttgart</groupId>
<artifactId>CityDoctorParent</artifactId>
<version>3.17.3</version>
<version>3.18.0</version>
</parent>
<artifactId>CityDoctorValidation</artifactId>
<name>CityDoctorValidation</name>
......
......@@ -21,13 +21,11 @@ package de.hft.stuttgart.citydoctor2;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.file.Path;
import java.util.List;
import de.hft.stuttgart.citydoctor2.zip.CityGmlZipArchive;
import de.hft.stuttgart.citydoctor2.utils.Localization;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.citygml4j.core.ade.ADEException;
import de.hft.stuttgart.citydoctor2.check.Checker;
import de.hft.stuttgart.citydoctor2.check.ValidationConfiguration;
......@@ -83,12 +81,12 @@ public class CityDoctorValidation {
if (optional) {
return null;
}
logger.error("No output file specified. (-out [FILE])");
logger.error(Localization.getText("CityDoctorValidation.noOutputFile"));
System.exit(11);
}
List<String> outFiles = argParser.getValues("out");
if (outFiles.size() != 1) {
logger.error("Specify exactly one file as output.");
logger.error(Localization.getText("CityDoctorValidation.notExactlyOneOutputFile"));
System.exit(12);
}
outputFile = outFiles.get(0);
......@@ -157,15 +155,13 @@ public class CityDoctorValidation {
ValidationConfiguration config, String outputFile) throws CityDoctorWriteException, CityGmlParseException, IOException, InvalidGmlFileException {
File inputFile = new File(input);
if (!inputFile.exists()) {
logger.error("Input file '{}' does not exist.", input);
logger.error(Localization.getText("CityDoctorValidation.inputFileNotExisting"), input);
System.exit(1);
}
if (inputFile.getName().endsWith(".gml") || inputFile.getName().endsWith(".xml")) {
startFileValidation(inputFile, xmlOutput, pdfOutput, config, outputFile);
} else if (inputFile.getName().endsWith(".zip")) {
startZipValidation(input, xmlOutput, pdfOutput, config, outputFile);
} else {
logger.error("Input file '{}' does not end with .gml or .xml and is not a zip archive.", input);
logger.error(Localization.getText("CityDoctorValidation.wrongInputFileFormat"), input);
System.exit(1);
}
}
......@@ -179,10 +175,11 @@ public class CityDoctorValidation {
* @param pdfOutput the output path for the pdf report (optional)
* @param config the configuration path for the validation plan
* @param outputFile storing the validated gml file with quality ade
* @throws CityDoctorWriteException if something goes wrong while writing the gml
* file
* @throws CityGMLBuilderException
* @throws ADEException
*
* @throws IOException When an exception while writing the report files happens.
* @throws CityGmlParseException When an error while parsing the cityGML file happens.
* @throws InvalidGmlFileException If the cityGML file is not valid according to the cityGML schema.
* @throws CityDoctorWriteException If something goes wrong while writing the output gml file
*/
public static void startFileValidation(File inputFile, String xmlOutput, String pdfOutput,
ValidationConfiguration config, String outputFile) throws IOException, CityGmlParseException,
......@@ -201,34 +198,11 @@ public class CityDoctorValidation {
}
}
public static void startZipValidation(String inputZipFile, String xmlOutput, String pdfOutput,
ValidationConfiguration config, String outputFile) throws CityGmlParseException, IOException {
xmlOutput = toDirectoryPath(xmlOutput);
pdfOutput = toDirectoryPath(pdfOutput);
outputFile = toDirectoryPath(outputFile);
if (xmlOutput == null && pdfOutput == null && outputFile == null) {
logger.warn("No output locations specified, results of validation will not be saved");
}
CityGmlZipArchive archive = CityGmlZipArchive.register(inputZipFile);
Checker.streamCheck(archive, xmlOutput, pdfOutput, config, outputFile);
}
public static String toDirectoryPath(String input) {
if (input == null) {
return null;
}
String parentDirectory = Path.of(input).getParent().toString() + File.separator;
String name = Path.of(input).getFileName().toString().replaceFirst("\\..+", "") + File.separator;
File f = new File(parentDirectory + name);
f.mkdir();
return f.getPath() + File.separator;
}
public static String getPdfOutput(ArgumentParser argParser) {
if (argParser.containsOption("pdfreport")) {
List<String> reportFiles = argParser.getValues("pdfreport");
if (reportFiles.size() != 1) {
logger.error("Specify exactly one file as pdfReport");
logger.error(Localization.getText("CityDoctorValidation.notExactlyOnePDFOutput"));
System.exit(6);
}
return reportFiles.get(0);
......@@ -240,7 +214,7 @@ public class CityDoctorValidation {
if (argParser.containsOption("xmlreport")) {
List<String> reportFiles = argParser.getValues("xmlreport");
if (reportFiles.size() != 1) {
logger.error("Specify exactly one file as xmlReport");
logger.error(Localization.getText("CityDoctorValidation.notExactlyOneXMLOutput"));
System.exit(5);
}
return reportFiles.get(0);
......@@ -257,16 +231,16 @@ public class CityDoctorValidation {
if (argParser.containsOption("config")) {
List<String> configFiles = argParser.getValues("config");
if (configFiles.size() != 1) {
logger.error("Specify exactly one file as configuration");
logger.error(Localization.getText("CityDoctorValidation.notExactlyOneConfigFile"));
System.exit(4);
}
return ValidationConfiguration.loadValidationConfig(configFiles.get(0));
} else {
if (optional) {
logger.warn("No configuration file given, loading default configuration");
logger.warn(Localization.getText("CityDoctorValidation.loadingDefaultConfig"));
return ValidationConfiguration.loadStandardValidationConfig();
} else {
logger.error("No configuration file specified with -config [FILE]");
logger.error(Localization.getText("CityDoctorValidation.noConfig"));
System.exit(7);
return null;
}
......@@ -278,7 +252,7 @@ public class CityDoctorValidation {
if (argParser.containsOption("out")) {
List<String> outFiles = argParser.getValues("out");
if (outFiles.size() != 1) {
logger.error("Specify exactly one file as output.");
logger.error(Localization.getText("CityDoctorValidation.multipleOutputFiles"));
System.exit(3);
}
return outFiles.get(0);
......@@ -297,12 +271,12 @@ public class CityDoctorValidation {
if (optional) {
return null;
}
logger.error("No input file specified. (-in [FILE])");
logger.error(Localization.getText("CityDoctorValidation.noInputFile"));
System.exit(1);
}
List<String> inFiles = argParser.getValues("in");
if (inFiles.size() != 1) {
logger.error("Specify exactly one file as input.");
logger.error(Localization.getText("CityDoctorValidation.notExactlyOneInputFile"));
System.exit(2);
}
inputFile = inFiles.get(0);
......
package de.hft.stuttgart.citydoctor2;
import java.util.concurrent.Callable;
import de.hft.stuttgart.citydoctor2.check.ValidationConfiguration;
import de.hft.stuttgart.citydoctor2.exceptions.CityDoctorWriteException;
import de.hft.stuttgart.citydoctor2.parser.CityGmlParseException;
import de.hft.stuttgart.citydoctor2.parser.InvalidGmlFileException;
import picocli.CommandLine;
import picocli.CommandLine.Command;
import picocli.CommandLine.Option;
import java.io.File;
import java.io.IOException;
@Command(name = "citydoctor2", mixinStandardHelpOptions = true, description = "Validates CityGML files according to a provided validation-plan.")
public class CityDoctorValidationCLI implements Callable<Integer> {
public class CityDoctorValidationCLI implements Runnable {
@Option(names = {"-i" , "--in" , "--input"},
description = "Filepath of the CityGML file.",
......@@ -15,23 +22,41 @@ public class CityDoctorValidationCLI implements Callable<Integer> {
@Option(names = {"-c" , "--config" , "--configuration", "--plan"},
description = "Filepath of the validation configuration .yml",
required = true)
private String config;
defaultValue = Option.NULL_VALUE)
private File config;
@Option(names = {"-x" , "--xml" , "--xmlReport"},
description = "Create a XML validation report at target location")
description = "Create a XML validation report at target location",
defaultValue = Option.NULL_VALUE)
private String xmlReport;
@Option(names = {"-p" , "--pdf" , "--pdfReport"},
description = "Create a PDF validation report at target location")
description = "Create a PDF validation report at target location",
defaultValue = Option.NULL_VALUE)
private String pdfReport;
@Option(names = {"-o" , "--out" , "--output"},
description = "Create a validated copy of the CityGML input with QualityADE at target location.")
description = "Create a validated copy of the CityGML input with QualityADE at target location.",
defaultValue = Option.NULL_VALUE)
private String output;
@Override
public Integer call() throws Exception {
return 0;
public void run(){
try {
ValidationConfiguration valConfig;
if(config == null){
valConfig=ValidationConfiguration.loadStandardValidationConfig();
} else{
valConfig=ValidationConfiguration.loadValidationConfig(config.getAbsolutePath());
}
CityDoctorValidation.startValidationProcess(input, xmlReport, pdfReport, valConfig,output);
} catch (CityDoctorWriteException | CityGmlParseException | IOException | InvalidGmlFileException e) {
throw new RuntimeException(e);
}
}
public static void main(String[] args) {
int exitCode = new CommandLine(new CityDoctorValidationCLI()).execute(args);
System.exit(exitCode);
}
}
......@@ -28,9 +28,14 @@ import de.hft.stuttgart.citydoctor2.checks.CheckPrototype;
import de.hft.stuttgart.citydoctor2.checks.Checks;
import de.hft.stuttgart.citydoctor2.checks.SvrlContentHandler;
import de.hft.stuttgart.citydoctor2.checks.util.FeatureCheckedListener;
import de.hft.stuttgart.citydoctor2.database.CityObjectCache;
import de.hft.stuttgart.citydoctor2.database.CityObjectCache;
import de.hft.stuttgart.citydoctor2.datastructure.CityDoctorModel;
import de.hft.stuttgart.citydoctor2.datastructure.CityObject;
import de.hft.stuttgart.citydoctor2.datastructure.FeatureType;
import de.hft.stuttgart.citydoctor2.datastructure.GmlId;
import de.hft.stuttgart.citydoctor2.datastructure.ImplicitGeometryHolder;
import de.hft.stuttgart.citydoctor2.datastructure.GmlId;
import de.hft.stuttgart.citydoctor2.parser.CityGmlConsumer;
import de.hft.stuttgart.citydoctor2.parser.CityGmlParseException;
import de.hft.stuttgart.citydoctor2.parser.CityGmlParser;
......@@ -42,11 +47,8 @@ import de.hft.stuttgart.citydoctor2.reporting.XmlStreamReporter;
import de.hft.stuttgart.citydoctor2.reporting.XmlValidationReporter;
import de.hft.stuttgart.citydoctor2.reporting.pdf.PdfReporter;
import de.hft.stuttgart.citydoctor2.reporting.pdf.PdfStreamReporter;
import de.hft.stuttgart.citydoctor2.utils.ArchivePacker;
import de.hft.stuttgart.citydoctor2.utils.Localization;
import de.hft.stuttgart.citydoctor2.zip.CityGmlZipArchive;
import de.hft.stuttgart.citydoctor2.zip.CityGmlZipEntry;
import de.hft.stuttgart.citydoctor2.zip.CityGmlZipEntryFile;
import de.hft.stuttgart.citydoctor2.utils.TimeFormatter;
import de.hft.stuttgart.quality.model.enums.RequirementId;
import de.hft.stuttgart.quality.model.enums.TopLevelFeatureType;
import de.hft.stuttgart.quality.model.properties.CheckingProperty;
......@@ -57,7 +59,6 @@ import de.hft.stuttgart.quality.model.properties.RequirementProperty;
import de.hft.stuttgart.quality.model.types.Checking;
import de.hft.stuttgart.quality.model.types.Parameter;
import de.hft.stuttgart.quality.model.types.ValidationPlan;
import org.apache.commons.io.FilenameUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
......@@ -79,6 +80,7 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UncheckedIOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collections;
......@@ -89,7 +91,8 @@ import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.stream.Stream;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
/**
* The main container class for checking. It contains the logic for validation,
......@@ -191,38 +194,93 @@ public class Checker {
if (config == null) {
config = ValidationConfiguration.loadStandardValidationConfig();
}
checkCityModel(model, l);
if (logger.isInfoEnabled()) {
logger.info(Localization.getText("Checker.checksFinished"));
AutoCloseable checkingContext = model.getCache().startCheckingMode();
try(checkingContext){
Callable<SvrlContentHandler> schematronThread = () -> executeSchematronValidationIfAvailable(config, model.getFile());
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<SvrlContentHandler> handlerFuture = executor.submit(schematronThread);
executor.shutdown();
checkCityModel(model, l);
getSchematronResults(handlerFuture, l);
model.setValidated(createValidationPlan());
} catch (Exception e){
logger.error("Validation failed due to encountering error", e);
}
}
private void getSchematronResults(Future<SvrlContentHandler> handlerFuture, ProgressListener l) {
if (!handlerFuture.isDone()) {
if (logger.isInfoEnabled()) {
logger.info(Localization.getText("Checker.schematronStillRunning"));
}
if(l !=null){
l.updateProgress(-0.5f);
}
}
SvrlContentHandler handler = executeSchematronValidationIfAvailable(config, model.getFile());
if (handler != null) {
handleSchematronResults(handler);
try {
SvrlContentHandler handler = handlerFuture.get();
if (handler != null) {
handleSchematronResults(handler);
}
} catch (ExecutionException e) {
logger.error(e);
} catch (InterruptedException e) {
logger.error(Localization.getText("Checker.schematronInterrupted"), e);
Thread.currentThread().interrupt();
}
model.setValidated(createValidationPlan());
}
private void handleSchematronResults(SvrlContentHandler handler) {
model.addGlobalErrors(handler.getGeneralErrors());
CityObjectCache cache = model.getCache();
handleSchematronErrorsGlobal(handler.getGeneralErrors());
Map<String, CityObject> featureMap = new HashMap<>();
model.createFeatureStream().forEach(f -> featureMap.put(f.getGmlId().getGmlString(), f));
boolean onlySchematron = execLayers.isEmpty();
if (onlySchematron) {
CheckableUtilsVisitor visitor = new CheckableUtilsVisitor() {
@Override
public void check(Checkable checkable) {
checkable.setValidated(true);
}
};
model.createFeatureStream().forEach(f -> {
featureMap.put(f.getGmlId().getGmlString(), f);
f.accept(visitor);
});
} else {
model.createFeatureStream().forEach(f -> featureMap.put(f.getGmlId().getGmlString(), f));
}
handler.getFeatureErrors().forEach((k, v) -> {
if (k.trim().isEmpty()) {
// missing gml id, ignore?
return;
}
CityObject co = featureMap.get(k);
String trimmedId = k.trim();
CityObject co = cache.get(new GmlId(k));
if (co == null) {
// gml id reported by schematron was not found, add to general errors
for (SchematronError se : v) {
model.addGlobalError(se);
}
handleSchematronErrorsGlobal(v);
} else {
handleSchematronErrorsForCityObject(v, co);
co.setValidated(true);
}
});
}
private void handleSchematronErrorsGlobal(List<SchematronError> v) {
for (SchematronError se : v) {
CheckError err;
if (AttributeMissingError.ID.getIdString().equals(se.getErrorIdString())) {
err = new AttributeMissingError(null, se.getChildId(), se.getNameOfAttribute());
} else if (AttributeValueWrongError.ID.getIdString().equals(se.getErrorIdString())) {
err = new AttributeValueWrongError(null, se.getChildId(), se.getNameOfAttribute());
} else if (AttributeInvalidError.ID.getIdString().equals(se.getErrorIdString())) {
err = new AttributeInvalidError(null, se.getChildId(), se.getNameOfAttribute());
} else {
throw new IllegalStateException(
"Unknown error ID was given in schematron file: " + se.getErrorIdString());
}
model.addGlobalError(err);
}
}
public static void handleSchematronErrorsForCityObject(List<SchematronError> v, CityObject co) {
int count = 0;
for (SchematronError se : v) {
......@@ -435,13 +493,16 @@ public class Checker {
}
}
@SuppressWarnings("resource")
public static SvrlContentHandler executeSchematronValidationIfAvailable(ValidationConfiguration config,
InputStream in) {
if (config.getSchematronFilePath() != null && !config.getSchematronFilePath().isEmpty()) {
if (logger.isInfoEnabled()) {
logger.info(Localization.getText("Checker.schematronValidation"));
}
if (!Files.exists(Path.of(config.getSchematronFilePath()))) {
logger.warn(Localization.getText("Checker.schematronFileNotFound"), config.getSchematronFilePath());
return null;
}
try {
TransformerFactory transformerFactory = TransformerFactory.newInstance("net.sf.saxon.TransformerFactoryImpl", Checker.class.getClassLoader());
......@@ -559,7 +620,7 @@ public class Checker {
for (Entry<String, RequirementConfiguration> e : config.getRequirements().entrySet()) {
de.hft.stuttgart.citydoctor2.check.Requirement req = Checks.getAvailableRequirements().get(e.getKey());
if (req == null) {
logger.warn("Could not find any check that satisfies requirement {}, it will not be checked",
logger.warn(Localization.getText("Checker.noCheckSatisfiesRequirement"),
e.getKey());
} else {
if (e.getValue().isEnabled()) {
......@@ -626,31 +687,110 @@ public class Checker {
}
}
private void checkCityModel(CityDoctorModel model, ProgressListener l) {
Stream<CityObject> features = model.createFeatureStream();
float featureSum = model.getNumberOfFeatures();
private void checkCityModel(CityDoctorModel model, ProgressListener l){
List<GmlId> features = model.getFeatureIds();
AtomicInteger checkedCount = new AtomicInteger(0);
// clear global errors
model.getGlobalErrors().clear();
// stupid lamda with final variable restrictions
int[] currentFeature = new int[1];
features.forEach(co -> {
if (config.getParserConfiguration().useLowMemoryConsumption()) {
// no edges have been created yet, create them
co.prepareForChecking();
CityObjectCache cache = model.getCache();
logger.trace("Setting up ThreadPool");
int threadCount = Runtime.getRuntime().availableProcessors() * 5;
ExecutorService exec = new ThreadPoolExecutor
(threadCount, threadCount, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<>());
try{
long startTime = System.nanoTime();
ImplicitGeometryHolder.preparePrototypeGeometriesForChecking();
List<Future<GmlId>> futures = runChecksOnFeatures(exec, cache, features, checkedCount, l);
List<GmlId> missedFeatures = getMissedFeatures(futures);
ImplicitGeometryHolder.clearMetaDataOfPrototypeGeometries();
if (!missedFeatures.isEmpty()){
logger.error(Localization.getText("Checker.dbUnresponsive"));
if (logger.isDebugEnabled()){
logger.debug(missedFeatures.toString());
}
}
// check every feature
executeChecksForCityObject(co);
long endTime = System.nanoTime();
if (logger.isInfoEnabled()){
long totalTime = (endTime - startTime) / 1_000_000; // Convert ns to ms
String messageString = Localization.getText("Checker.checksFinished");
String timeString = TimeFormatter.format(totalTime);
messageString = messageString.replace("{0}", timeString);
logger.info(messageString);
}
} catch (InterruptedException e){
// No interrupts implemented, so this block should actually never be entered
logger.error(Localization.getText("Checker.validationInterrupted"), e);
Thread.currentThread().interrupt();
} finally {
exec.shutdown();
try {
if(!exec.awaitTermination(1, TimeUnit.MINUTES)){
exec.shutdownNow();
}
if (config.getParserConfiguration().useLowMemoryConsumption()) {
// low memory consumption, remove edges again
co.clearMetaInformation();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
logger.error(Localization.getText("Checker.shutdownInterrupted"));
}
if (l != null) {
currentFeature[0]++;
l.updateProgress(currentFeature[0] / featureSum);
}
}
private List<Future<GmlId>> runChecksOnFeatures(ExecutorService exec, CityObjectCache cache, List<GmlId> ids, AtomicInteger checkedCount,
ProgressListener l)
throws InterruptedException {
float featureSum = ids.size() + (float) checkedCount.get();
logger.trace("Queueing up Checker tasks");
List<Callable<GmlId>> tasks = new ArrayList<>();
for (GmlId id : ids) {
tasks.add(()->{
CityObject co = cache.get(id);
if (co == null) {
return id;
}
if(Thread.interrupted()){
Thread.currentThread().interrupt();
return null;
}
co.prepareForChecking();
executeChecksForCityObject(co);
co.clearMetaInformation();
cache.put(co);
checkedCount.incrementAndGet();
if (l!=null){
l.updateProgress((checkedCount.get()) / featureSum);
}
return null;
});
}
logger.trace("Queueing up finished, invoking all tasks");
return exec.invokeAll(tasks);
}
private List<GmlId> getMissedFeatures(List<Future<GmlId>> futures) throws InterruptedException{
List<GmlId> missedList = new ArrayList<>();
Set<ExecutionException> errors = new HashSet<>();
for (Future<GmlId> future : futures) {
try{
GmlId gmlId = future.get();
if (gmlId != null) {
missedList.add(gmlId);
}
} catch (ExecutionException e){
logger.debug("A Task failed due to an unexpected exception", e);
logger.debug(e.getCause());
errors.add(e);
}
});
}
if (!errors.isEmpty()) {
logger.error(Localization.getText("Checker.futuresCheckFailures"));
logger.error(errors.toString());
}
return missedList;
}
private boolean filterObject(CityObject co) {
......@@ -756,73 +896,6 @@ public class Checker {
return hasUnusedDependency;
}
public static void streamCheck(CityGmlZipArchive archive, String xmlDirectory, String pdfDirectory, ValidationConfiguration config,
String outputDirectory) throws IOException, CityGmlParseException {
streamCheck(archive, xmlDirectory, pdfDirectory, config, null, outputDirectory);
}
public static void streamCheck(CityGmlZipArchive archive, String xmlDirectory, String pdfDirectory, ValidationConfiguration config,
FeatureCheckedListener l, String outputDirectory) throws IOException, CityGmlParseException {
for (CityGmlZipEntry entry : archive.getEntries()) {
String entryName = FilenameUtils.removeExtension(entry.getDisplayName());
String xmlOutput = null;
String pdfOutput = null;
String outputFile = null;
if (xmlDirectory != null) {
xmlOutput = Path.of(xmlDirectory).resolve(entryName + "_report.xml").toString();
}
if (pdfDirectory != null) {
pdfOutput = Path.of(pdfDirectory).resolve(entryName + "_report.pdf").toString();
}
if (outputDirectory != null) {
outputFile = Path.of(outputDirectory).resolve(entryName + "_validated.gml").toString();
}
streamCheck(entry, xmlOutput, pdfOutput, config, l, outputFile);
}
if (outputDirectory != null) {
ArchivePacker.packAndDeleteDirectory(outputDirectory);
}
}
public static void streamCheck(CityGmlZipEntry entry, String xmlOutput, String pdfOutput, ValidationConfiguration config,
String outputFile) throws IOException, CityGmlParseException {
streamCheck(entry, xmlOutput, pdfOutput, config, null, outputFile);
}
public static void streamCheck(CityGmlZipEntry entry, String xmlOutput, String pdfOutput, ValidationConfiguration config,
FeatureCheckedListener l, String outputFile) throws IOException, CityGmlParseException {
try (BufferedOutputStream xmlBos = getXmlOutputMaybe(xmlOutput);
BufferedOutputStream pdfBos = getPdfOutputMaybe(pdfOutput)) {
Checker c = new Checker(config, null);
String fileName = entry.getEntrySubPath();
// create reporter if available
XmlStreamReporter xmlReporter = getXmlReporter(config, xmlBos, fileName);
PdfStreamReporter pdfReporter = getPdfReporter(config, pdfBos, fileName);
// execute schematron first
try (CityGmlZipEntryFile entryFile = new CityGmlZipEntryFile(entry)) {
SvrlContentHandler handler = executeSchematronValidationIfAvailable(config, entryFile.getInputStream());
CityGmlConsumer con = new StreamCityGmlConsumer(c, xmlReporter, pdfReporter, handler, config, l);
// parse and validate
CityGmlParser.streamCityGml(entry, config.getParserConfiguration(), con, outputFile);
// write reports if available
writeReport(xmlReporter);
writeReport(pdfReporter);
}
} catch (CheckReportWriteException e) {
logger.error(Localization.getText("Checker.failReports"), e);
}
}
public static void streamCheck(File inputFile, String xmlOutput, String pdfOutput, ValidationConfiguration config,
String outputFile) throws IOException, CityGmlParseException {
streamCheck(inputFile, xmlOutput, pdfOutput, config, null, outputFile);
......
......@@ -134,7 +134,7 @@ public class StreamCityGmlConsumer implements CityGmlConsumer {
pdfReporter.report(co);
}
// TODO: Update QualityADE to be compatible with CityGML 3.0 or deprecate it, unhandled top-level feature types are just skipped for now
// TODO: Update QualityADE to be compatible with CityGML 3.0, unhandled top-level feature types are just skipped for now
if (!(co instanceof AbstractTunnel || co instanceof CityFurniture || co instanceof GenericCityObject)) {
// store quality ade datastructures in cityobject
QualityADEUtils.writeQualityAde(co, val);
......
......@@ -230,6 +230,24 @@ public class CheckContainer extends Check {
}
}
@Override
public void check(TinObject to) {
try {
check.check(to);
}catch (Exception e) {
handleException(e, to);
}
}
@Override
public void check(ReliefObject ro) {
try {
check.check(ro);
}catch (Exception e) {
handleException(e, ro);
}
}
@Override
public void check(CityFurniture cf){
try {
......@@ -248,6 +266,15 @@ public class CheckContainer extends Check {
}
}
@Override
public void check(OtherConstructionObject oco) {
try {
check.check(oco);
}catch (Exception e) {
handleException(e, oco);
}
}
@Override
public RequirementType getType() {
return check.getType();
......
......@@ -106,12 +106,12 @@ public class SvrlContentHandler implements ContentHandler {
throw new IllegalStateException(
"Schematron File is not formed according to specification for CityDoctor.");
}
String gmlId = split[0];
String gmlId = split[0].strip();
String childId = split[1];
String errorId = split[2];
String nameOfAttribute = split[3];
SchematronError err = new SchematronError(errorId, gmlId, childId, nameOfAttribute);
if (gmlId == null || gmlId.isEmpty()) {
if (gmlId == null || gmlId.isBlank()) {
// general error
generalErrors.add(err);
} else {
......
......@@ -57,10 +57,12 @@ import de.hft.stuttgart.citydoctor2.tesselation.TesselatedPolygon;
*/
public class PlanarCheck extends Check {
private static final String DISTANCE = "distance";
private static final String DISTANCE_TOLERANCE = "distanceTolerance";
public static final String ANGLE = "angle";
public static final String DISTANCE = "distance";
public static final String BOTH = "both";
public static final String DISTANCE_TOLERANCE = "distanceTolerance";
private static final String ANGLE_TOLERANCE = "angleTolerance";
private static final String TYPE = "type";
public static final String TYPE = "type";
private static final List<CheckId> dependencies;
......@@ -97,7 +99,7 @@ public class PlanarCheck extends Check {
public void check(Polygon p) {
if (DISTANCE.equals(planarCheckType)) {
planarDistance(p);
} else if ("angle".equals(planarCheckType)) {
} else if (ANGLE.equals(planarCheckType)) {
planarNormalDeviation(p);
} else if ("both".equals(planarCheckType)) {
planarDistance(p);
......
......@@ -21,13 +21,13 @@ package de.hft.stuttgart.citydoctor2.checks.geometry;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import de.hft.stuttgart.citydoctor2.check.Check;
import de.hft.stuttgart.citydoctor2.check.CheckError;
import de.hft.stuttgart.citydoctor2.check.CheckId;
import de.hft.stuttgart.citydoctor2.check.CheckResult;
import de.hft.stuttgart.citydoctor2.check.GeometrySelfIntersection;
import de.hft.stuttgart.citydoctor2.check.Requirement;
import de.hft.stuttgart.citydoctor2.check.RequirementType;
import de.hft.stuttgart.citydoctor2.check.ResultStatus;
......@@ -36,6 +36,7 @@ import de.hft.stuttgart.citydoctor2.checks.util.CollectionUtils;
import de.hft.stuttgart.citydoctor2.checks.util.SelfIntersectionUtil;
import de.hft.stuttgart.citydoctor2.datastructure.Geometry;
import de.hft.stuttgart.citydoctor2.datastructure.GeometryType;
import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration;
import de.hft.stuttgart.citydoctor2.utils.PolygonIntersection;
/**
......@@ -47,7 +48,9 @@ import de.hft.stuttgart.citydoctor2.utils.PolygonIntersection;
public class SolidSelfIntCheck extends Check {
private static final List<CheckId> dependencies;
private double delta = 0.01;
static {
ArrayList<CheckId> deps = new ArrayList<>();
dependencies = Collections.unmodifiableList(deps);
......@@ -68,6 +71,13 @@ public class SolidSelfIntCheck extends Check {
deps.add(CheckId.C_GE_S_NON_MANIFOLD_VERTEX);
deps.add(CheckId.C_GE_S_POLYGON_WRONG_ORIENTATION);
}
@Override
public void init(Map<String, String> parameters, ParserConfiguration config) {
if (parameters.containsKey(PlanarCheck.DISTANCE_TOLERANCE)) {
delta = Double.parseDouble(parameters.get(PlanarCheck.DISTANCE_TOLERANCE));
}
}
@Override
public void check(Geometry g) {
......@@ -75,7 +85,7 @@ public class SolidSelfIntCheck extends Check {
return;
}
CheckResult cr;
List<PolygonIntersection> intersections = SelfIntersectionUtil.calculateSolidSelfIntersection(g);
List<PolygonIntersection> intersections = SelfIntersectionUtil.calculateSolidSelfIntersection(g, delta);
if (intersections.isEmpty()) {
cr = new CheckResult(this, ResultStatus.OK, null);
} else {
......@@ -85,18 +95,6 @@ public class SolidSelfIntCheck extends Check {
g.addCheckResult(cr);
}
@SuppressWarnings("unused")
private CheckResult oldIntersectionAlgorithm(Geometry g) {
CheckResult cr;
GeometrySelfIntersection intersect = SelfIntersectionUtil.doesSolidSelfIntersect(g);
if (intersect != null) {
cr = new CheckResult(this, ResultStatus.ERROR, null);
} else {
cr = new CheckResult(this, ResultStatus.OK, null);
}
return cr;
}
@Override
public List<CheckId> getDependencies() {
return dependencies;
......
......@@ -21,6 +21,7 @@ package de.hft.stuttgart.citydoctor2.checks.util;
import java.util.ArrayList;
import java.util.Collections;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
......@@ -39,6 +40,8 @@ import org.locationtech.jts.geom.impl.CoordinateArraySequence;
import org.locationtech.jts.operation.overlay.OverlayOp;
import org.locationtech.jts.operation.overlay.snap.SnapIfNeededOverlayOp;
import Jama.EigenvalueDecomposition;
import Jama.Matrix;
import de.hft.stuttgart.citydoctor2.check.GeometrySelfIntersection;
import de.hft.stuttgart.citydoctor2.datastructure.ConcretePolygon;
import de.hft.stuttgart.citydoctor2.datastructure.Geometry;
......@@ -50,8 +53,10 @@ import de.hft.stuttgart.citydoctor2.edge.EdgePolygon;
import de.hft.stuttgart.citydoctor2.edge.IntersectPlanarPolygons;
import de.hft.stuttgart.citydoctor2.edge.MeshSurface;
import de.hft.stuttgart.citydoctor2.edge.PolygonPolygonIntersection;
import de.hft.stuttgart.citydoctor2.math.CovarianceMatrix;
import de.hft.stuttgart.citydoctor2.math.MovedPolygon;
import de.hft.stuttgart.citydoctor2.math.MovedRing;
import de.hft.stuttgart.citydoctor2.math.OrthogonalRegressionPlane;
import de.hft.stuttgart.citydoctor2.math.Plane;
import de.hft.stuttgart.citydoctor2.math.PlaneSegmentIntersection;
import de.hft.stuttgart.citydoctor2.math.PlaneSegmentIntersection.Type;
......@@ -83,18 +88,37 @@ public class SelfIntersectionUtil {
private SelfIntersectionUtil() {
}
public static List<PolygonIntersection> calculateSolidSelfIntersection(Geometry g) {
public static List<PolygonIntersection> calculateSolidSelfIntersection(Geometry g, double delta) {
List<TesselatedPolygon> tesselatedPolygons = new ArrayList<>();
for (Polygon p : g.getPolygons()) {
tesselatedPolygons.add(EarcutTesselator.tesselatePolygon(p));
TesselatedPolygon tessPolygon = EarcutTesselator.tesselatePolygon(p);
for (Iterator<Triangle3d> iterator = tessPolygon.getTriangles().iterator(); iterator.hasNext();) {
Triangle3d t = iterator.next();
List<Vector3d> vertices = new ArrayList<>(3);
vertices.add(t.getP1());
vertices.add(t.getP2());
vertices.add(t.getP3());
Vector3d centroid = CovarianceMatrix.getCentroid(vertices);
EigenvalueDecomposition ed = OrthogonalRegressionPlane.decompose(vertices, centroid);
Matrix eigenValues = ed.getD();
double[] eigenValuesArray = new double[3];
eigenValuesArray[0] = eigenValues.get(0, 0);
eigenValuesArray[1] = eigenValues.get(1, 1);
eigenValuesArray[2] = eigenValues.get(2, 2);
if (eigenValuesArray[1] < delta) {
iterator.remove();
}
}
tesselatedPolygons.add(tessPolygon);
}
List<PolygonIntersection> intersections = new ArrayList<>();
for (int i = 0; i < tesselatedPolygons.size() - 1; i++) {
TesselatedPolygon p1 = tesselatedPolygons.get(i);
for (int j = i + 1; j < tesselatedPolygons.size(); j++) {
TesselatedPolygon p2 = tesselatedPolygons.get(j);
GeometrySelfIntersection intersection = doPolygonsIntersect(p1, p2);
GeometrySelfIntersection intersection = doPolygonsIntersect(p1, p2, delta);
if (intersection != null) {
intersections.add(PolygonIntersection.triangles(intersection.t1(), intersection.t2()));
}
......@@ -103,8 +127,8 @@ public class SelfIntersectionUtil {
return intersections;
}
public static GeometrySelfIntersection doesSolidSelfIntersect(Geometry g) {
return selfIntersectionJava(g);
public static GeometrySelfIntersection doesSolidSelfIntersect(Geometry g, double epsilon) {
return selfIntersectionJava(g, epsilon);
}
public static List<PolygonIntersection> doesSolidSelfIntersect2(Geometry g) {
......@@ -404,7 +428,7 @@ public class SelfIntersectionUtil {
return sign != 0;
}
private static GeometrySelfIntersection selfIntersectionJava(Geometry g) {
private static GeometrySelfIntersection selfIntersectionJava(Geometry g, double epsilon) {
List<TesselatedPolygon> tessPolys = new ArrayList<>();
for (Polygon p : g.getPolygons()) {
tessPolys.add(JoglTesselator.tesselatePolygon(p));
......@@ -413,7 +437,7 @@ public class SelfIntersectionUtil {
TesselatedPolygon p1 = tessPolys.get(i);
for (int j = i + 1; j < tessPolys.size(); j++) {
TesselatedPolygon p2 = tessPolys.get(j);
GeometrySelfIntersection intersection = doPolygonsIntersect(p1, p2);
GeometrySelfIntersection intersection = doPolygonsIntersect(p1, p2, epsilon);
if (intersection != null) {
return intersection;
}
......@@ -422,12 +446,12 @@ public class SelfIntersectionUtil {
return null;
}
private static GeometrySelfIntersection doPolygonsIntersect(TesselatedPolygon p1, TesselatedPolygon p2) {
private static GeometrySelfIntersection doPolygonsIntersect(TesselatedPolygon p1, TesselatedPolygon p2, double epsilon) {
for (int p1Index = 0; p1Index < p1.getTriangles().size(); p1Index++) {
for (int p2Index = 0; p2Index < p2.getTriangles().size(); p2Index++) {
Triangle3d t1 = p1.getTriangles().get(p1Index);
Triangle3d t2 = p2.getTriangles().get(p2Index);
if (t1.doesIntersect(t2)) {
if (t1.doesIntersect(t2, epsilon)) {
logger.trace("{} intersects {}", t1, t2);
logger.trace("GML-ID: {} intersects {}", t1.getPartOf().getOriginal().getGmlId(),
t2.getPartOf().getOriginal().getGmlId());
......
......@@ -45,33 +45,8 @@ public class XmlValidationReporter implements Reporter {
@Override
public void writeReport(Checks checks, OutputStream filePath, CityDoctorModel model, ValidationConfiguration config) throws CheckReportWriteException {
StreamReporter streamReporter = new XmlStreamReporter(filePath, model.getFileName(), config);
for (BridgeObject bo : model.getBridges()) {
streamReporter.report(bo);
}
for (Building b : model.getBuildings()) {
streamReporter.report(b);
}
for (TransportationObject to : model.getTransportation()) {
streamReporter.report(to);
}
for (CityObject lo : model.getLand()) {
streamReporter.report(lo);
}
for (Vegetation v : model.getVegetation()) {
streamReporter.report(v);
}
for (WaterObject wo : model.getWater()) {
streamReporter.report(wo);
}
for (Tunnel tunnel : model.getTunnels()) {
streamReporter.report(tunnel);
}
for (CityFurniture cf : model.getCityFurniture()) {
streamReporter.report(cf);
}
for (GenericCityObject gco : model.getGenericCityObjects()) {
streamReporter.report(gco);
}
model.createFeatureStream().forEach(streamReporter::report);
for (CheckError err : model.getGlobalErrors()) {
streamReporter.reportGlobalError(err);
}
......
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Configuration>
<Configuration status="INFO">
<Appenders>
<Console name="console" target="SYSTEM_OUT">
<PatternLayout
pattern="[%-5level] %d{HH:mm:ss.SSS} %c{1} - %msg%n" />
</Console>
</Appenders>
<Loggers>
<Root level="debug" additivity="false">
<AppenderRef ref="console" />
</Root>
<Logger name="com.zaxxer.hikari" level="INFO" additivity="false">
<AppenderRef ref="console"/>
</Logger>
</Loggers>
</Configuration>
\ No newline at end of file
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment