"...energy-ade-3-citygml4j.git" did not exist on "25f5a94c3be00a64316bcdac99b81d85bec79015"
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; ...@@ -27,11 +27,14 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.UUID; 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.ade.ADEException;
import org.citygml4j.core.model.CityGMLVersion; import org.citygml4j.core.model.CityGMLVersion;
import org.citygml4j.core.model.core.AbstractFeatureProperty; import org.citygml4j.core.model.core.AbstractFeatureProperty;
import org.citygml4j.core.model.core.CityModel; import org.citygml4j.core.model.core.CityModel;
import org.citygml4j.xml.writer.CityGMLWriteException; import org.citygml4j.xml.writer.CityGMLWriteException;
import org.junit.Before;
import org.junit.Rule; import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.junit.rules.TemporaryFolder; import org.junit.rules.TemporaryFolder;
...@@ -63,28 +66,40 @@ import de.hft.stuttgart.quality.model.types.ValidationPlan; ...@@ -63,28 +66,40 @@ import de.hft.stuttgart.quality.model.types.ValidationPlan;
public class CityDoctorModelTest { 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 @Rule
public TemporaryFolder folder = new TemporaryFolder(); public TemporaryFolder folder = new TemporaryFolder();
@Test(expected = IllegalArgumentException.class) @Test(expected = IllegalArgumentException.class)
public void testCityDoctorModelNoConfig() { 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 @Test
public void testSetValidated() { 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)); model.setValidated(Mockito.mock(ValidationPlan.class));
assertTrue(model.isValidated()); assertTrue(model.isValidated());
} }
@Test @Test
public void testAddGlobalError() { 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); CheckError err = Mockito.mock(CheckError.class);
model.addGlobalError(err); model.addGlobalError(err);
assertEquals(err, model.getGlobalErrors().get(0)); assertEquals(err, model.getGlobalErrors().get(0));
...@@ -92,9 +107,6 @@ public class CityDoctorModelTest { ...@@ -92,9 +107,6 @@ public class CityDoctorModelTest {
@Test @Test
public void testAddGlobalErrors() { 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 err1 = Mockito.mock(CheckError.class);
CheckError err2 = Mockito.mock(CheckError.class); CheckError err2 = Mockito.mock(CheckError.class);
List<CheckError> errors = new ArrayList<>(); List<CheckError> errors = new ArrayList<>();
...@@ -107,19 +119,15 @@ public class CityDoctorModelTest { ...@@ -107,19 +119,15 @@ public class CityDoctorModelTest {
@Test @Test
public void testGetFile() { public void testGetFile() {
File f = Mockito.mock(File.class); assertEquals(mockFile, model.getFile());
ParserConfiguration config = new ParserConfiguration(8, false);
CityDoctorModel model = new CityDoctorModel(config, f);
assertEquals(f, model.getFile());
} }
@Test @Test
public void testCreateFeatureStream() { 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); Building b = Mockito.mock(Building.class);
Mockito.when(b.getGmlId()).thenReturn(new GmlId("b"));
Vegetation v = Mockito.mock(Vegetation.class); Vegetation v = Mockito.mock(Vegetation.class);
Mockito.when(v.getGmlId()).thenReturn(new GmlId("v"));
model.addBuilding(b); model.addBuilding(b);
model.addVegetation(v); model.addVegetation(v);
assertTrue(model.createFeatureStream().anyMatch(c -> c == b)); assertTrue(model.createFeatureStream().anyMatch(c -> c == b));
...@@ -129,9 +137,6 @@ public class CityDoctorModelTest { ...@@ -129,9 +137,6 @@ public class CityDoctorModelTest {
@Test @Test
public void testSaveAsWithoutValidation() throws CityGMLWriteException, ADEException, public void testSaveAsWithoutValidation() throws CityGMLWriteException, ADEException,
IOException, CityGmlParseException, InvalidGmlFileException, CityDoctorWriteException { 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); model.setParsedCityGMLVersion(CityGMLVersion.v2_0);
CityModel cModel = new CityModel(); CityModel cModel = new CityModel();
model.setCityModel(cModel); model.setCityModel(cModel);
...@@ -147,7 +152,7 @@ public class CityDoctorModelTest { ...@@ -147,7 +152,7 @@ public class CityDoctorModelTest {
assertTrue(saveFile.length() > 0); assertTrue(saveFile.length() > 0);
CityDoctorModel parsedModel = CityGmlParser.parseCityGmlFile(saveFile.getAbsolutePath(), config); 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("testId", parsedBuilding.getGmlId().getGmlString());
assertEquals(1, parsedBuilding.getGeometries().size()); assertEquals(1, parsedBuilding.getGeometries().size());
} }
...@@ -155,9 +160,7 @@ public class CityDoctorModelTest { ...@@ -155,9 +160,7 @@ public class CityDoctorModelTest {
@Test @Test
public void testSaveAsWithValidation() throws CityGMLWriteException, ADEException, public void testSaveAsWithValidation() throws CityGMLWriteException, ADEException,
IOException, CityGmlParseException, InvalidGmlFileException, CityDoctorWriteException { 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); model.setParsedCityGMLVersion(CityGMLVersion.v2_0);
CityModel cModel = new CityModel(); CityModel cModel = new CityModel();
ValidationPlan plan = new ValidationPlan(); ValidationPlan plan = new ValidationPlan();
...@@ -214,7 +217,7 @@ public class CityDoctorModelTest { ...@@ -214,7 +217,7 @@ public class CityDoctorModelTest {
assertTrue(saveFile.length() > 0); assertTrue(saveFile.length() > 0);
CityDoctorModel parsedModel = CityGmlParser.parseCityGmlFile(saveFile.getAbsolutePath(), config); 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("testId", parsedBuilding.getGmlId().getGmlString());
assertEquals(1, parsedBuilding.getGeometries().size()); assertEquals(1, parsedBuilding.getGeometries().size());
List<CityObjectProperties> props = parsedBuilding.getGmlObject().getADEProperties(CityObjectProperties.class); List<CityObjectProperties> props = parsedBuilding.getGmlObject().getADEProperties(CityObjectProperties.class);
...@@ -234,9 +237,6 @@ public class CityDoctorModelTest { ...@@ -234,9 +237,6 @@ public class CityDoctorModelTest {
@Test @Test
public void testCollectErrors() { 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(); Building b = new Building();
model.addBuilding(b); model.addBuilding(b);
CheckError error = Mockito.mock(CheckError.class); CheckError error = Mockito.mock(CheckError.class);
...@@ -247,18 +247,12 @@ public class CityDoctorModelTest { ...@@ -247,18 +247,12 @@ public class CityDoctorModelTest {
@Test @Test
public void testGetFileName() { 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("test", model.getFileName());
assertEquals(f, model.getFile()); assertEquals(mockFile, model.getFile());
} }
@Test @Test
public void testSetCityModel() { 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); CityModel cModel = Mockito.mock(CityModel.class);
model.setCityModel(cModel); model.setCityModel(cModel);
assertEquals(cModel, model.getCityModel()); assertEquals(cModel, model.getCityModel());
...@@ -266,111 +260,99 @@ public class CityDoctorModelTest { ...@@ -266,111 +260,99 @@ public class CityDoctorModelTest {
@Test @Test
public void testAddBuilding() { 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); Building b = Mockito.mock(Building.class);
Mockito.when(b.getGmlId()).thenReturn(new GmlId("b"));
model.addBuilding(b); model.addBuilding(b);
assertEquals(b, model.getBuildings().get(0)); assertEquals(b, model.getBuildings().toList().get(0));
} }
@Test @Test
public void testAddBridge() { 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); BridgeObject b = Mockito.mock(BridgeObject.class);
Mockito.when(b.getGmlId()).thenReturn(new GmlId("b"));
model.addBridge(b); model.addBridge(b);
assertEquals(b, model.getBridges().get(0)); assertEquals(b, model.getBridges().toList().get(0));
} }
@Test @Test
public void testAddVegetation() { 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); Vegetation veg = Mockito.mock(Vegetation.class);
Mockito.when(veg.getGmlId()).thenReturn(new GmlId("v"));
model.addVegetation(veg); model.addVegetation(veg);
assertEquals(veg, model.getVegetation().get(0)); assertEquals(veg, model.getVegetation().toList().get(0));
} }
@Test @Test
public void testAddTunnel() { 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); Tunnel tunnel = Mockito.mock(Tunnel.class);
Mockito.when(tunnel.getGmlId()).thenReturn(new GmlId("t"));
model.addTunnel(tunnel); model.addTunnel(tunnel);
assertEquals(tunnel, model.getTunnels().get(0)); assertEquals(tunnel, model.getTunnels().toList().get(0));
} }
@Test @Test
public void testAddTransportation() { 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); TransportationObject trans = Mockito.mock(TransportationObject.class);
Mockito.when(trans.getGmlId()).thenReturn(new GmlId("t"));
model.addTransportation(trans); model.addTransportation(trans);
assertEquals(trans, model.getTransportation().get(0)); assertEquals(trans, model.getTransportation().toList().get(0));
} }
@Test @Test
public void testAddLand() { 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); LandObject land = Mockito.mock(LandObject.class);
Mockito.when(land.getGmlId()).thenReturn(new GmlId("l"));
model.addLand(land); model.addLand(land);
assertEquals(land, model.getLand().get(0)); assertEquals(land, model.getLand().toList().get(0));
} }
@Test @Test
public void testAddWater() { 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); WaterObject water = Mockito.mock(WaterObject.class);
Mockito.when(water.getGmlId()).thenReturn(new GmlId("w"));
model.addWater(water); model.addWater(water);
assertEquals(water, model.getWater().get(0)); assertEquals(water, model.getWater().toList().get(0));
} }
@Test @Test
public void testAddCityFurniture() { 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); CityFurniture cf = Mockito.mock(CityFurniture.class);
Mockito.when(cf.getGmlId()).thenReturn(new GmlId("cf"));
model.addCityFurniture(cf); model.addCityFurniture(cf);
assertEquals(cf, model.getCityFurniture().get(0)); assertEquals(cf, model.getCityFurniture().toList().get(0));
} }
@Test @Test
public void testAddGenericCityObject() { public void testAddOtherCityObject() {
File f = Mockito.mock(File.class);
ParserConfiguration config = new ParserConfiguration(8, false);
CityDoctorModel model = new CityDoctorModel(config, f);
GenericCityObject gen = Mockito.mock(GenericCityObject.class); GenericCityObject gen = Mockito.mock(GenericCityObject.class);
model.addGenericCityObject(gen); Mockito.when(gen.getGmlId()).thenReturn(new GmlId("g"));
assertEquals(gen, model.getGenericCityObjects().get(0)); model.addOtherCityObject(gen);
assertEquals(gen, model.getOtherCityObjects().toList().get(0));
} }
@Test @Test
public void testGetNumberOfFeatures() { 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); Building b = Mockito.mock(Building.class);
Mockito.when(b.getGmlId()).thenReturn(new GmlId("b"));
BridgeObject bo = Mockito.mock(BridgeObject.class); BridgeObject bo = Mockito.mock(BridgeObject.class);
Mockito.when(bo.getGmlId()).thenReturn(new GmlId("bo"));
Vegetation veg = Mockito.mock(Vegetation.class); Vegetation veg = Mockito.mock(Vegetation.class);
Mockito.when(veg.getGmlId()).thenReturn(new GmlId("ve"));
Tunnel tunnel = Mockito.mock(Tunnel.class); Tunnel tunnel = Mockito.mock(Tunnel.class);
Mockito.when(tunnel.getGmlId()).thenReturn(new GmlId("t"));
TransportationObject trans = Mockito.mock(TransportationObject.class); TransportationObject trans = Mockito.mock(TransportationObject.class);
Mockito.when(trans.getGmlId()).thenReturn(new GmlId("tr"));
LandObject land = Mockito.mock(LandObject.class); LandObject land = Mockito.mock(LandObject.class);
Mockito.when(land.getGmlId()).thenReturn(new GmlId("l"));
WaterObject water = Mockito.mock(WaterObject.class); WaterObject water = Mockito.mock(WaterObject.class);
Mockito.when(water.getGmlId()).thenReturn(new GmlId("w"));
CityFurniture cf = Mockito.mock(CityFurniture.class); CityFurniture cf = Mockito.mock(CityFurniture.class);
Mockito.when(cf.getGmlId()).thenReturn(new GmlId("cf"));
GenericCityObject generic = Mockito.mock(GenericCityObject.class); GenericCityObject generic = Mockito.mock(GenericCityObject.class);
Mockito.when(generic.getGmlId()).thenReturn(new GmlId("g"));
model.addBuilding(b); model.addBuilding(b);
model.addBridge(bo); model.addBridge(bo);
...@@ -380,7 +362,7 @@ public class CityDoctorModelTest { ...@@ -380,7 +362,7 @@ public class CityDoctorModelTest {
model.addLand(land); model.addLand(land);
model.addWater(water); model.addWater(water);
model.addCityFurniture(cf); model.addCityFurniture(cf);
model.addGenericCityObject(generic); model.addOtherCityObject(generic);
assertEquals(9, model.getNumberOfFeatures()); assertEquals(9, model.getNumberOfFeatures());
...@@ -388,31 +370,25 @@ public class CityDoctorModelTest { ...@@ -388,31 +370,25 @@ public class CityDoctorModelTest {
@Test @Test
public void testGetParserConfig() { 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()); assertEquals(config, model.getParserConfig());
} }
@Test @Test
public void testReplaceBuilding() { 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); Building b1 = Mockito.mock(Building.class);
Mockito.when(b1.getGmlId()).thenReturn(new GmlId("b1"));
Building b2 = Mockito.mock(Building.class); Building b2 = Mockito.mock(Building.class);
Mockito.when(b2.getGmlId()).thenReturn(new GmlId("b2"));
model.addBuilding(b1); model.addBuilding(b1);
assertEquals(b1, model.getBuildings().get(0)); assertEquals(b1, model.getBuildings().toList().get(0));
model.replaceFeature(b1, b2); model.replaceFeature(b1, b2);
assertEquals(b2, model.getBuildings().get(0)); assertEquals(b2, model.getBuildings().toList().get(0));
assertEquals(1, model.getBuildings().size()); assertEquals(1, model.getBuildings().toList().size());
} }
@Test(expected = IllegalStateException.class) @Test(expected = IllegalStateException.class)
public void testReplaceBuildingMissing() { 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 b1 = Mockito.mock(Building.class);
Building b2 = Mockito.mock(Building.class); Building b2 = Mockito.mock(Building.class);
model.replaceFeature(b1, b2); model.replaceFeature(b1, b2);
...@@ -420,23 +396,19 @@ public class CityDoctorModelTest { ...@@ -420,23 +396,19 @@ public class CityDoctorModelTest {
@Test @Test
public void testReplaceBridge() { 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); BridgeObject b1 = Mockito.mock(BridgeObject.class);
Mockito.when(b1.getGmlId()).thenReturn(new GmlId("b1"));
BridgeObject b2 = Mockito.mock(BridgeObject.class); BridgeObject b2 = Mockito.mock(BridgeObject.class);
Mockito.when(b2.getGmlId()).thenReturn(new GmlId("b2"));
model.addBridge(b1); model.addBridge(b1);
assertEquals(b1, model.getBridges().get(0)); assertEquals(b1, model.getBridges().toList().get(0));
model.replaceFeature(b1, b2); model.replaceFeature(b1, b2);
assertEquals(b2, model.getBridges().get(0)); assertEquals(b2, model.getBridges().toList().get(0));
assertEquals(1, model.getBridges().size()); assertEquals(1, model.getBridges().toList().size());
} }
@Test(expected = IllegalStateException.class) @Test(expected = IllegalStateException.class)
public void testReplaceBridgeMissing() { 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 b1 = Mockito.mock(BridgeObject.class);
BridgeObject b2 = Mockito.mock(BridgeObject.class); BridgeObject b2 = Mockito.mock(BridgeObject.class);
model.replaceFeature(b1, b2); model.replaceFeature(b1, b2);
...@@ -444,23 +416,20 @@ public class CityDoctorModelTest { ...@@ -444,23 +416,20 @@ public class CityDoctorModelTest {
@Test @Test
public void testReplaceVegetation() { 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); Vegetation v1 = Mockito.mock(Vegetation.class);
Mockito.when(v1.getGmlId()).thenReturn(new GmlId("v1"));
Vegetation v2 = Mockito.mock(Vegetation.class); Vegetation v2 = Mockito.mock(Vegetation.class);
Mockito.when(v2.getGmlId()).thenReturn(new GmlId("v2"));
model.addVegetation(v1); model.addVegetation(v1);
assertEquals(v1, model.getVegetation().get(0)); assertEquals(v1, model.getVegetation().toList().get(0));
model.replaceFeature(v1, v2); model.replaceFeature(v1, v2);
assertEquals(v2, model.getVegetation().get(0)); assertEquals(v2, model.getVegetation().toList().get(0));
assertEquals(1, model.getVegetation().size()); assertEquals(1, model.getVegetation().toList().size());
} }
@Test(expected = IllegalStateException.class) @Test(expected = IllegalStateException.class)
public void testReplaceVegetationMissing() { 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 v1 = Mockito.mock(Vegetation.class);
Vegetation v2 = Mockito.mock(Vegetation.class); Vegetation v2 = Mockito.mock(Vegetation.class);
model.replaceFeature(v1, v2); model.replaceFeature(v1, v2);
...@@ -468,23 +437,20 @@ public class CityDoctorModelTest { ...@@ -468,23 +437,20 @@ public class CityDoctorModelTest {
@Test @Test
public void testReplaceTunnel() { 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); Tunnel t1 = Mockito.mock(Tunnel.class);
Mockito.when(t1.getGmlId()).thenReturn(new GmlId("t1"));
Tunnel t2 = Mockito.mock(Tunnel.class); Tunnel t2 = Mockito.mock(Tunnel.class);
Mockito.when(t2.getGmlId()).thenReturn(new GmlId("t2"));
model.addTunnel(t1); model.addTunnel(t1);
assertEquals(t1, model.getTunnels().get(0)); assertEquals(t1, model.getTunnels().toList().get(0));
model.replaceFeature(t1, t2); model.replaceFeature(t1, t2);
assertEquals(t2, model.getTunnels().get(0)); assertEquals(t2, model.getTunnels().toList().get(0));
assertEquals(1, model.getTunnels().size()); assertEquals(1, model.getTunnels().toList().size());
} }
@Test(expected = IllegalStateException.class) @Test(expected = IllegalStateException.class)
public void testReplaceTunnelMissing() { 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 t1 = Mockito.mock(Tunnel.class);
Tunnel t2 = Mockito.mock(Tunnel.class); Tunnel t2 = Mockito.mock(Tunnel.class);
model.replaceFeature(t1, t2); model.replaceFeature(t1, t2);
...@@ -492,23 +458,20 @@ public class CityDoctorModelTest { ...@@ -492,23 +458,20 @@ public class CityDoctorModelTest {
@Test @Test
public void testReplaceTransportation() { 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); TransportationObject t1 = Mockito.mock(TransportationObject.class);
Mockito.when(t1.getGmlId()).thenReturn(new GmlId("t1"));
TransportationObject t2 = Mockito.mock(TransportationObject.class); TransportationObject t2 = Mockito.mock(TransportationObject.class);
Mockito.when(t2.getGmlId()).thenReturn(new GmlId("t2"));
model.addTransportation(t1); model.addTransportation(t1);
assertEquals(t1, model.getTransportation().get(0)); assertEquals(t1, model.getTransportation().toList().get(0));
model.replaceFeature(t1, t2); model.replaceFeature(t1, t2);
assertEquals(t2, model.getTransportation().get(0)); assertEquals(t2, model.getTransportation().toList().get(0));
assertEquals(1, model.getTransportation().size()); assertEquals(1, model.getTransportation().toList().size());
} }
@Test(expected = IllegalStateException.class) @Test(expected = IllegalStateException.class)
public void testReplaceTransportationMissing() { 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 t1 = Mockito.mock(TransportationObject.class);
TransportationObject t2 = Mockito.mock(TransportationObject.class); TransportationObject t2 = Mockito.mock(TransportationObject.class);
model.replaceFeature(t1, t2); model.replaceFeature(t1, t2);
...@@ -516,23 +479,20 @@ public class CityDoctorModelTest { ...@@ -516,23 +479,20 @@ public class CityDoctorModelTest {
@Test @Test
public void testReplaceLand() { 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); LandObject lo1 = Mockito.mock(LandObject.class);
Mockito.when(lo1.getGmlId()).thenReturn(new GmlId("lo1"));
LandObject lo2 = Mockito.mock(LandObject.class); LandObject lo2 = Mockito.mock(LandObject.class);
Mockito.when(lo2.getGmlId()).thenReturn(new GmlId("lo2"));
model.addLand(lo1); model.addLand(lo1);
assertEquals(lo1, model.getLand().get(0)); assertEquals(lo1, model.getLand().toList().get(0));
model.replaceFeature(lo1, lo2); model.replaceFeature(lo1, lo2);
assertEquals(lo2, model.getLand().get(0)); assertEquals(lo2, model.getLand().toList().get(0));
assertEquals(1, model.getLand().size()); assertEquals(1, model.getLand().toList().size());
} }
@Test(expected = IllegalStateException.class) @Test(expected = IllegalStateException.class)
public void testReplaceLandMissing() { 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 lo1 = Mockito.mock(LandObject.class);
LandObject lo2 = Mockito.mock(LandObject.class); LandObject lo2 = Mockito.mock(LandObject.class);
model.replaceFeature(lo1, lo2); model.replaceFeature(lo1, lo2);
...@@ -540,23 +500,20 @@ public class CityDoctorModelTest { ...@@ -540,23 +500,20 @@ public class CityDoctorModelTest {
@Test @Test
public void testReplaceWater() { 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); WaterObject t1 = Mockito.mock(WaterObject.class);
Mockito.when(t1.getGmlId()).thenReturn(new GmlId("t1"));
WaterObject t2 = Mockito.mock(WaterObject.class); WaterObject t2 = Mockito.mock(WaterObject.class);
Mockito.when(t2.getGmlId()).thenReturn(new GmlId("t2"));
model.addWater(t1); model.addWater(t1);
assertEquals(t1, model.getWater().get(0)); assertEquals(t1, model.getWater().toList().get(0));
model.replaceFeature(t1, t2); model.replaceFeature(t1, t2);
assertEquals(t2, model.getWater().get(0)); assertEquals(t2, model.getWater().toList().get(0));
assertEquals(1, model.getWater().size()); assertEquals(1, model.getWater().toList().size());
} }
@Test(expected = IllegalStateException.class) @Test(expected = IllegalStateException.class)
public void testReplaceWaterMissing() { 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 t1 = Mockito.mock(WaterObject.class);
WaterObject t2 = Mockito.mock(WaterObject.class); WaterObject t2 = Mockito.mock(WaterObject.class);
model.replaceFeature(t1, t2); model.replaceFeature(t1, t2);
...@@ -564,23 +521,20 @@ public class CityDoctorModelTest { ...@@ -564,23 +521,20 @@ public class CityDoctorModelTest {
@Test @Test
public void testReplaceCityFurniture() { 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); CityFurniture cf1 = Mockito.mock(CityFurniture.class);
Mockito.when(cf1.getGmlId()).thenReturn(new GmlId("cf1"));
CityFurniture cf2 = Mockito.mock(CityFurniture.class); CityFurniture cf2 = Mockito.mock(CityFurniture.class);
Mockito.when(cf2.getGmlId()).thenReturn(new GmlId("cf2"));
model.addCityFurniture(cf1); model.addCityFurniture(cf1);
assertEquals(cf1, model.getCityFurniture().get(0)); assertEquals(cf1, model.getCityFurniture().toList().get(0));
model.replaceFeature(cf1, cf2); model.replaceFeature(cf1, cf2);
assertEquals(cf2, model.getCityFurniture().get(0)); assertEquals(cf2, model.getCityFurniture().toList().get(0));
assertEquals(1, model.getCityFurniture().size()); assertEquals(1, model.getCityFurniture().toList().size());
} }
@Test(expected = IllegalStateException.class) @Test(expected = IllegalStateException.class)
public void testReplaceCityFurnitureMissing() { 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 cf1 = Mockito.mock(CityFurniture.class);
CityFurniture cf2 = Mockito.mock(CityFurniture.class); CityFurniture cf2 = Mockito.mock(CityFurniture.class);
model.replaceFeature(cf1, cf2); model.replaceFeature(cf1, cf2);
...@@ -588,23 +542,20 @@ public class CityDoctorModelTest { ...@@ -588,23 +542,20 @@ public class CityDoctorModelTest {
@Test @Test
public void testReplaceGenericCityObject() { 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); GenericCityObject gco1 = Mockito.mock(GenericCityObject.class);
Mockito.when(gco1.getGmlId()).thenReturn(new GmlId("gco1"));
GenericCityObject gco2 = Mockito.mock(GenericCityObject.class); GenericCityObject gco2 = Mockito.mock(GenericCityObject.class);
model.addGenericCityObject(gco1); Mockito.when(gco2.getGmlId()).thenReturn(new GmlId("gco2"));
assertEquals(gco1, model.getGenericCityObjects().get(0));
model.addOtherCityObject(gco1);
assertEquals(gco1, model.getOtherCityObjects().toList().get(0));
model.replaceFeature(gco1, gco2); model.replaceFeature(gco1, gco2);
assertEquals(gco2, model.getGenericCityObjects().get(0)); assertEquals(gco2, model.getOtherCityObjects().toList().get(0));
assertEquals(1, model.getGenericCityObjects().size()); assertEquals(1, model.getOtherCityObjects().toList().size());
} }
@Test(expected = IllegalStateException.class) @Test(expected = IllegalStateException.class)
public void testReplaceGenericCityObjectMissing() { 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 gco1 = Mockito.mock(GenericCityObject.class);
GenericCityObject gco2 = Mockito.mock(GenericCityObject.class); GenericCityObject gco2 = Mockito.mock(GenericCityObject.class);
model.replaceFeature(gco1, gco2); model.replaceFeature(gco1, gco2);
......
...@@ -16,7 +16,7 @@ public class CompositePolygonTest { ...@@ -16,7 +16,7 @@ public class CompositePolygonTest {
ParserConfiguration config = new ParserConfiguration(8, false); ParserConfiguration config = new ParserConfiguration(8, false);
CityDoctorModel m = CityGmlParser.parseCityGmlFile("src/test/resources/FZK_haus.gml", config); 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); assertNotNull(b);
assertFalse(b.getBoundarySurfaces().isEmpty()); assertFalse(b.getBoundarySurfaces().isEmpty());
for (BoundarySurface bs : b.getBoundarySurfaces()) { for (BoundarySurface bs : b.getBoundarySurfaces()) {
......
...@@ -96,7 +96,7 @@ public class GeometryTest { ...@@ -96,7 +96,7 @@ public class GeometryTest {
public void testRemovePolygonConcreteWithLink() { public void testRemovePolygonConcreteWithLink() {
ParserConfiguration config = new ParserConfiguration(4, false); ParserConfiguration config = new ParserConfiguration(4, false);
AbstractConstructionSurface abs = new WallSurface(); 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(); var gmlBi = new org.citygml4j.core.model.building.BuildingInstallation();
Installation bi = new Installation(); Installation bi = new Installation();
bi.setGmlObject(gmlBi); bi.setGmlObject(gmlBi);
...@@ -133,7 +133,7 @@ public class GeometryTest { ...@@ -133,7 +133,7 @@ public class GeometryTest {
public void testRemovePolygonOnlyConcrete() { public void testRemovePolygonOnlyConcrete() {
ParserConfiguration config = new ParserConfiguration(4, false); ParserConfiguration config = new ParserConfiguration(4, false);
AbstractConstructionSurface abs = new WallSurface(); 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); Geometry geom = new Geometry(GeometryType.MULTI_SURFACE, Lod.LOD2, Orientation.OUTWARD);
ConcretePolygon p = new ConcretePolygon(); ConcretePolygon p = new ConcretePolygon();
...@@ -156,7 +156,7 @@ public class GeometryTest { ...@@ -156,7 +156,7 @@ public class GeometryTest {
public void testRemovePolygonLinked() { public void testRemovePolygonLinked() {
ParserConfiguration config = new ParserConfiguration(4, false); ParserConfiguration config = new ParserConfiguration(4, false);
AbstractConstructionSurface abs = new WallSurface(); 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(); var gmlBi = new org.citygml4j.core.model.building.BuildingInstallation();
Installation bi = new Installation(); Installation bi = new Installation();
bi.setGmlObject(gmlBi); bi.setGmlObject(gmlBi);
...@@ -193,7 +193,7 @@ public class GeometryTest { ...@@ -193,7 +193,7 @@ public class GeometryTest {
public void testReplacePolygon() { public void testReplacePolygon() {
ParserConfiguration config = new ParserConfiguration(4, false); ParserConfiguration config = new ParserConfiguration(4, false);
AbstractConstructionSurface abs = new WallSurface(); 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(); var gmlBi = new org.citygml4j.core.model.building.BuildingInstallation();
Installation bi = new Installation(); Installation bi = new Installation();
bi.setGmlObject(gmlBi); bi.setGmlObject(gmlBi);
......
...@@ -26,7 +26,6 @@ import static org.mockito.Mockito.mock; ...@@ -26,7 +26,6 @@ import static org.mockito.Mockito.mock;
public class VegetationTest { public class VegetationTest {
//TODO: Recreate geometries tests
@Test @Test
public void testContainsError() { public void testContainsError() {
......
...@@ -63,20 +63,20 @@ public class FeatureMapperTest { ...@@ -63,20 +63,20 @@ public class FeatureMapperTest {
public void testVisitWaterBody() { public void testVisitWaterBody() {
WaterBody body = new WaterBody(); WaterBody body = new WaterBody();
Citygml3FeatureMapper mapper = new Citygml3FeatureMapper(mock(ParserConfiguration.class), Citygml3FeatureMapper mapper = new Citygml3FeatureMapper(mock(ParserConfiguration.class),
new File("").toPath()); new File("").toPath(), false);
mapper.visit(body); mapper.visit(body);
assertEquals(1, mapper.getModel().getWater().size()); assertEquals(1, mapper.getModel().getWater().toList().size());
body.setId("test1"); body.setId("test1");
mapper.visit(body); mapper.visit(body);
assertEquals(2, mapper.getModel().getWater().size()); assertEquals(2, mapper.getModel().getWater().toList().size());
WaterObject waterObject = mapper.getModel().getWater().get(1); WaterObject waterObject = mapper.getModel().getWater().toList().get(1);
assertEquals("test1", waterObject.getGmlId().getGmlString()); assertEquals("test1", waterObject.getGmlId().getGmlString());
body.getDeprecatedProperties().setLod1MultiSurface(createDummyMsp()); body.getDeprecatedProperties().setLod1MultiSurface(createDummyMsp());
mapper.visit(body); mapper.visit(body);
assertEquals(3, mapper.getModel().getWater().size()); assertEquals(3, mapper.getModel().getWater().toList().size());
assertNull(body.getDeprecatedProperties().getLod1MultiSurface()); 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(1, geometry.getPolygons().size());
assertEquals(Lod.LOD1, geometry.getLod()); assertEquals(Lod.LOD1, geometry.getLod());
assertEquals(GeometryType.MULTI_SURFACE, geometry.getType()); assertEquals(GeometryType.MULTI_SURFACE, geometry.getType());
...@@ -86,7 +86,7 @@ public class FeatureMapperTest { ...@@ -86,7 +86,7 @@ public class FeatureMapperTest {
public void testVisitPlantCover() { public void testVisitPlantCover() {
PlantCover cover = new PlantCover(); PlantCover cover = new PlantCover();
Citygml3FeatureMapper mapper = new Citygml3FeatureMapper(mock(ParserConfiguration.class), Citygml3FeatureMapper mapper = new Citygml3FeatureMapper(mock(ParserConfiguration.class),
new File("").toPath()); new File("").toPath(), false);
mapper.visit(cover); mapper.visit(cover);
} }
...@@ -124,12 +124,12 @@ public class FeatureMapperTest { ...@@ -124,12 +124,12 @@ public class FeatureMapperTest {
body.getDeprecatedProperties().setLod1MultiSurface(new MultiSurfaceProperty(ms)); body.getDeprecatedProperties().setLod1MultiSurface(new MultiSurfaceProperty(ms));
ParserConfiguration config = new ParserConfiguration(8, false); 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); mapper.visit(body);
CityDoctorModel model = mapper.getModel(); CityDoctorModel model = mapper.getModel();
assertEquals(1, model.getWater().size()); assertEquals(1, model.getWater().toList().size());
WaterObject waterObject = model.getWater().get(0); WaterObject waterObject = model.getWater().toList().get(0);
Geometry geometry = waterObject.getGeometries().get(0); Geometry geometry = waterObject.getGeometries().get(0);
assertEquals(1, geometry.getVertices().size()); assertEquals(1, geometry.getVertices().size());
Vertex vertex = geometry.getVertices().get(0); Vertex vertex = geometry.getVertices().get(0);
...@@ -152,12 +152,12 @@ public class FeatureMapperTest { ...@@ -152,12 +152,12 @@ public class FeatureMapperTest {
body.getDeprecatedProperties().setLod1MultiSurface(new MultiSurfaceProperty(ms)); body.getDeprecatedProperties().setLod1MultiSurface(new MultiSurfaceProperty(ms));
ParserConfiguration config = new ParserConfiguration(8, false); 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); mapper.visit(body);
CityDoctorModel model = mapper.getModel(); CityDoctorModel model = mapper.getModel();
assertEquals(1, model.getWater().size()); assertEquals(1, model.getWater().toList().size());
WaterObject waterObject = model.getWater().get(0); WaterObject waterObject = model.getWater().toList().get(0);
Geometry geometry = waterObject.getGeometries().get(0); Geometry geometry = waterObject.getGeometries().get(0);
assertEquals(2, geometry.getVertices().size()); assertEquals(2, geometry.getVertices().size());
Vertex vertex = geometry.getVertices().get(0); Vertex vertex = geometry.getVertices().get(0);
...@@ -199,12 +199,12 @@ public class FeatureMapperTest { ...@@ -199,12 +199,12 @@ public class FeatureMapperTest {
body.getDeprecatedProperties().setLod1MultiSurface(new MultiSurfaceProperty(ms)); body.getDeprecatedProperties().setLod1MultiSurface(new MultiSurfaceProperty(ms));
ParserConfiguration config = new ParserConfiguration(8, false); 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); mapper.visit(body);
CityDoctorModel model = mapper.getModel(); CityDoctorModel model = mapper.getModel();
assertEquals(1, model.getWater().size()); assertEquals(1, model.getWater().toList().size());
WaterObject waterObject = model.getWater().get(0); WaterObject waterObject = model.getWater().toList().get(0);
Geometry geometry = waterObject.getGeometries().get(0); Geometry geometry = waterObject.getGeometries().get(0);
assertEquals(7, geometry.getVertices().size()); assertEquals(7, geometry.getVertices().size());
assertEquals(8, geometry.getEdges().size()); assertEquals(8, geometry.getEdges().size());
......
...@@ -49,7 +49,7 @@ public class CityGml3ParserTest { ...@@ -49,7 +49,7 @@ public class CityGml3ParserTest {
ParserConfiguration config = new ParserConfiguration(8, false); ParserConfiguration config = new ParserConfiguration(8, false);
CityDoctorModel model = CityGmlParser.parseCityGmlFile("src/test/resources/SimpleSolid_SrefBS.gml", config); CityDoctorModel model = CityGmlParser.parseCityGmlFile("src/test/resources/SimpleSolid_SrefBS.gml", config);
assertNotNull(model); assertNotNull(model);
List<Building> buildings = model.getBuildings(); List<Building> buildings = model.getBuildings().toList();
assertEquals(1, buildings.size()); assertEquals(1, buildings.size());
Building building = buildings.get(0); Building building = buildings.get(0);
assertEquals("_Simple_BD.1", building.getGmlId().getGmlString()); 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 @@ ...@@ -4,7 +4,7 @@
<parent> <parent>
<groupId>de.hft.stuttgart</groupId> <groupId>de.hft.stuttgart</groupId>
<artifactId>CityDoctorParent</artifactId> <artifactId>CityDoctorParent</artifactId>
<version>3.17.3</version> <version>3.18.0</version>
</parent> </parent>
<artifactId>CityDoctorValidation</artifactId> <artifactId>CityDoctorValidation</artifactId>
<name>CityDoctorValidation</name> <name>CityDoctorValidation</name>
......
...@@ -21,13 +21,11 @@ package de.hft.stuttgart.citydoctor2; ...@@ -21,13 +21,11 @@ package de.hft.stuttgart.citydoctor2;
import java.io.File; import java.io.File;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Path;
import java.util.List; 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.LogManager;
import org.apache.logging.log4j.Logger; 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.Checker;
import de.hft.stuttgart.citydoctor2.check.ValidationConfiguration; import de.hft.stuttgart.citydoctor2.check.ValidationConfiguration;
...@@ -83,12 +81,12 @@ public class CityDoctorValidation { ...@@ -83,12 +81,12 @@ public class CityDoctorValidation {
if (optional) { if (optional) {
return null; return null;
} }
logger.error("No output file specified. (-out [FILE])"); logger.error(Localization.getText("CityDoctorValidation.noOutputFile"));
System.exit(11); System.exit(11);
} }
List<String> outFiles = argParser.getValues("out"); List<String> outFiles = argParser.getValues("out");
if (outFiles.size() != 1) { if (outFiles.size() != 1) {
logger.error("Specify exactly one file as output."); logger.error(Localization.getText("CityDoctorValidation.notExactlyOneOutputFile"));
System.exit(12); System.exit(12);
} }
outputFile = outFiles.get(0); outputFile = outFiles.get(0);
...@@ -157,15 +155,13 @@ public class CityDoctorValidation { ...@@ -157,15 +155,13 @@ public class CityDoctorValidation {
ValidationConfiguration config, String outputFile) throws CityDoctorWriteException, CityGmlParseException, IOException, InvalidGmlFileException { ValidationConfiguration config, String outputFile) throws CityDoctorWriteException, CityGmlParseException, IOException, InvalidGmlFileException {
File inputFile = new File(input); File inputFile = new File(input);
if (!inputFile.exists()) { if (!inputFile.exists()) {
logger.error("Input file '{}' does not exist.", input); logger.error(Localization.getText("CityDoctorValidation.inputFileNotExisting"), input);
System.exit(1); System.exit(1);
} }
if (inputFile.getName().endsWith(".gml") || inputFile.getName().endsWith(".xml")) { if (inputFile.getName().endsWith(".gml") || inputFile.getName().endsWith(".xml")) {
startFileValidation(inputFile, xmlOutput, pdfOutput, config, outputFile); startFileValidation(inputFile, xmlOutput, pdfOutput, config, outputFile);
} else if (inputFile.getName().endsWith(".zip")) {
startZipValidation(input, xmlOutput, pdfOutput, config, outputFile);
} else { } 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); System.exit(1);
} }
} }
...@@ -179,10 +175,11 @@ public class CityDoctorValidation { ...@@ -179,10 +175,11 @@ public class CityDoctorValidation {
* @param pdfOutput the output path for the pdf report (optional) * @param pdfOutput the output path for the pdf report (optional)
* @param config the configuration path for the validation plan * @param config the configuration path for the validation plan
* @param outputFile storing the validated gml file with quality ade * @param outputFile storing the validated gml file with quality ade
* @throws CityDoctorWriteException if something goes wrong while writing the gml *
* file * @throws IOException When an exception while writing the report files happens.
* @throws CityGMLBuilderException * @throws CityGmlParseException When an error while parsing the cityGML file happens.
* @throws ADEException * @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, public static void startFileValidation(File inputFile, String xmlOutput, String pdfOutput,
ValidationConfiguration config, String outputFile) throws IOException, CityGmlParseException, ValidationConfiguration config, String outputFile) throws IOException, CityGmlParseException,
...@@ -201,34 +198,11 @@ public class CityDoctorValidation { ...@@ -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) { public static String getPdfOutput(ArgumentParser argParser) {
if (argParser.containsOption("pdfreport")) { if (argParser.containsOption("pdfreport")) {
List<String> reportFiles = argParser.getValues("pdfreport"); List<String> reportFiles = argParser.getValues("pdfreport");
if (reportFiles.size() != 1) { if (reportFiles.size() != 1) {
logger.error("Specify exactly one file as pdfReport"); logger.error(Localization.getText("CityDoctorValidation.notExactlyOnePDFOutput"));
System.exit(6); System.exit(6);
} }
return reportFiles.get(0); return reportFiles.get(0);
...@@ -240,7 +214,7 @@ public class CityDoctorValidation { ...@@ -240,7 +214,7 @@ public class CityDoctorValidation {
if (argParser.containsOption("xmlreport")) { if (argParser.containsOption("xmlreport")) {
List<String> reportFiles = argParser.getValues("xmlreport"); List<String> reportFiles = argParser.getValues("xmlreport");
if (reportFiles.size() != 1) { if (reportFiles.size() != 1) {
logger.error("Specify exactly one file as xmlReport"); logger.error(Localization.getText("CityDoctorValidation.notExactlyOneXMLOutput"));
System.exit(5); System.exit(5);
} }
return reportFiles.get(0); return reportFiles.get(0);
...@@ -257,16 +231,16 @@ public class CityDoctorValidation { ...@@ -257,16 +231,16 @@ public class CityDoctorValidation {
if (argParser.containsOption("config")) { if (argParser.containsOption("config")) {
List<String> configFiles = argParser.getValues("config"); List<String> configFiles = argParser.getValues("config");
if (configFiles.size() != 1) { if (configFiles.size() != 1) {
logger.error("Specify exactly one file as configuration"); logger.error(Localization.getText("CityDoctorValidation.notExactlyOneConfigFile"));
System.exit(4); System.exit(4);
} }
return ValidationConfiguration.loadValidationConfig(configFiles.get(0)); return ValidationConfiguration.loadValidationConfig(configFiles.get(0));
} else { } else {
if (optional) { if (optional) {
logger.warn("No configuration file given, loading default configuration"); logger.warn(Localization.getText("CityDoctorValidation.loadingDefaultConfig"));
return ValidationConfiguration.loadStandardValidationConfig(); return ValidationConfiguration.loadStandardValidationConfig();
} else { } else {
logger.error("No configuration file specified with -config [FILE]"); logger.error(Localization.getText("CityDoctorValidation.noConfig"));
System.exit(7); System.exit(7);
return null; return null;
} }
...@@ -278,7 +252,7 @@ public class CityDoctorValidation { ...@@ -278,7 +252,7 @@ public class CityDoctorValidation {
if (argParser.containsOption("out")) { if (argParser.containsOption("out")) {
List<String> outFiles = argParser.getValues("out"); List<String> outFiles = argParser.getValues("out");
if (outFiles.size() != 1) { if (outFiles.size() != 1) {
logger.error("Specify exactly one file as output."); logger.error(Localization.getText("CityDoctorValidation.multipleOutputFiles"));
System.exit(3); System.exit(3);
} }
return outFiles.get(0); return outFiles.get(0);
...@@ -297,12 +271,12 @@ public class CityDoctorValidation { ...@@ -297,12 +271,12 @@ public class CityDoctorValidation {
if (optional) { if (optional) {
return null; return null;
} }
logger.error("No input file specified. (-in [FILE])"); logger.error(Localization.getText("CityDoctorValidation.noInputFile"));
System.exit(1); System.exit(1);
} }
List<String> inFiles = argParser.getValues("in"); List<String> inFiles = argParser.getValues("in");
if (inFiles.size() != 1) { if (inFiles.size() != 1) {
logger.error("Specify exactly one file as input."); logger.error(Localization.getText("CityDoctorValidation.notExactlyOneInputFile"));
System.exit(2); System.exit(2);
} }
inputFile = inFiles.get(0); inputFile = inFiles.get(0);
......
package de.hft.stuttgart.citydoctor2; 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.Command;
import picocli.CommandLine.Option; 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.") @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"}, @Option(names = {"-i" , "--in" , "--input"},
description = "Filepath of the CityGML file.", description = "Filepath of the CityGML file.",
...@@ -15,23 +22,41 @@ public class CityDoctorValidationCLI implements Callable<Integer> { ...@@ -15,23 +22,41 @@ public class CityDoctorValidationCLI implements Callable<Integer> {
@Option(names = {"-c" , "--config" , "--configuration", "--plan"}, @Option(names = {"-c" , "--config" , "--configuration", "--plan"},
description = "Filepath of the validation configuration .yml", description = "Filepath of the validation configuration .yml",
required = true) defaultValue = Option.NULL_VALUE)
private String config; private File config;
@Option(names = {"-x" , "--xml" , "--xmlReport"}, @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; private String xmlReport;
@Option(names = {"-p" , "--pdf" , "--pdfReport"}, @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; private String pdfReport;
@Option(names = {"-o" , "--out" , "--output"}, @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; private String output;
@Override @Override
public Integer call() throws Exception { public void run(){
return 0; 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; ...@@ -28,9 +28,14 @@ import de.hft.stuttgart.citydoctor2.checks.CheckPrototype;
import de.hft.stuttgart.citydoctor2.checks.Checks; import de.hft.stuttgart.citydoctor2.checks.Checks;
import de.hft.stuttgart.citydoctor2.checks.SvrlContentHandler; import de.hft.stuttgart.citydoctor2.checks.SvrlContentHandler;
import de.hft.stuttgart.citydoctor2.checks.util.FeatureCheckedListener; 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.CityDoctorModel;
import de.hft.stuttgart.citydoctor2.datastructure.CityObject; import de.hft.stuttgart.citydoctor2.datastructure.CityObject;
import de.hft.stuttgart.citydoctor2.datastructure.FeatureType; 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.CityGmlConsumer;
import de.hft.stuttgart.citydoctor2.parser.CityGmlParseException; import de.hft.stuttgart.citydoctor2.parser.CityGmlParseException;
import de.hft.stuttgart.citydoctor2.parser.CityGmlParser; import de.hft.stuttgart.citydoctor2.parser.CityGmlParser;
...@@ -42,11 +47,8 @@ import de.hft.stuttgart.citydoctor2.reporting.XmlStreamReporter; ...@@ -42,11 +47,8 @@ import de.hft.stuttgart.citydoctor2.reporting.XmlStreamReporter;
import de.hft.stuttgart.citydoctor2.reporting.XmlValidationReporter; import de.hft.stuttgart.citydoctor2.reporting.XmlValidationReporter;
import de.hft.stuttgart.citydoctor2.reporting.pdf.PdfReporter; import de.hft.stuttgart.citydoctor2.reporting.pdf.PdfReporter;
import de.hft.stuttgart.citydoctor2.reporting.pdf.PdfStreamReporter; 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.utils.Localization;
import de.hft.stuttgart.citydoctor2.zip.CityGmlZipArchive; import de.hft.stuttgart.citydoctor2.utils.TimeFormatter;
import de.hft.stuttgart.citydoctor2.zip.CityGmlZipEntry;
import de.hft.stuttgart.citydoctor2.zip.CityGmlZipEntryFile;
import de.hft.stuttgart.quality.model.enums.RequirementId; import de.hft.stuttgart.quality.model.enums.RequirementId;
import de.hft.stuttgart.quality.model.enums.TopLevelFeatureType; import de.hft.stuttgart.quality.model.enums.TopLevelFeatureType;
import de.hft.stuttgart.quality.model.properties.CheckingProperty; import de.hft.stuttgart.quality.model.properties.CheckingProperty;
...@@ -57,7 +59,6 @@ import de.hft.stuttgart.quality.model.properties.RequirementProperty; ...@@ -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.Checking;
import de.hft.stuttgart.quality.model.types.Parameter; import de.hft.stuttgart.quality.model.types.Parameter;
import de.hft.stuttgart.quality.model.types.ValidationPlan; 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.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
...@@ -79,6 +80,7 @@ import java.io.FileOutputStream; ...@@ -79,6 +80,7 @@ import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.UncheckedIOException; import java.io.UncheckedIOException;
import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
...@@ -89,7 +91,8 @@ import java.util.List; ...@@ -89,7 +91,8 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.Set; 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, * The main container class for checking. It contains the logic for validation,
...@@ -191,38 +194,93 @@ public class Checker { ...@@ -191,38 +194,93 @@ public class Checker {
if (config == null) { if (config == null) {
config = ValidationConfiguration.loadStandardValidationConfig(); config = ValidationConfiguration.loadStandardValidationConfig();
} }
checkCityModel(model, l); AutoCloseable checkingContext = model.getCache().startCheckingMode();
if (logger.isInfoEnabled()) { try(checkingContext){
logger.info(Localization.getText("Checker.checksFinished")); 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()); try {
if (handler != null) { SvrlContentHandler handler = handlerFuture.get();
handleSchematronResults(handler); 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) { private void handleSchematronResults(SvrlContentHandler handler) {
model.addGlobalErrors(handler.getGeneralErrors()); CityObjectCache cache = model.getCache();
handleSchematronErrorsGlobal(handler.getGeneralErrors());
Map<String, CityObject> featureMap = new HashMap<>(); 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) -> { handler.getFeatureErrors().forEach((k, v) -> {
if (k.trim().isEmpty()) { String trimmedId = k.trim();
// missing gml id, ignore? CityObject co = cache.get(new GmlId(k));
return;
}
CityObject co = featureMap.get(k);
if (co == null) { if (co == null) {
// gml id reported by schematron was not found, add to general errors // gml id reported by schematron was not found, add to general errors
for (SchematronError se : v) { handleSchematronErrorsGlobal(v);
model.addGlobalError(se);
}
} else { } else {
handleSchematronErrorsForCityObject(v, co); 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) { public static void handleSchematronErrorsForCityObject(List<SchematronError> v, CityObject co) {
int count = 0; int count = 0;
for (SchematronError se : v) { for (SchematronError se : v) {
...@@ -435,13 +493,16 @@ public class Checker { ...@@ -435,13 +493,16 @@ public class Checker {
} }
} }
@SuppressWarnings("resource")
public static SvrlContentHandler executeSchematronValidationIfAvailable(ValidationConfiguration config, public static SvrlContentHandler executeSchematronValidationIfAvailable(ValidationConfiguration config,
InputStream in) { InputStream in) {
if (config.getSchematronFilePath() != null && !config.getSchematronFilePath().isEmpty()) { if (config.getSchematronFilePath() != null && !config.getSchematronFilePath().isEmpty()) {
if (logger.isInfoEnabled()) { if (logger.isInfoEnabled()) {
logger.info(Localization.getText("Checker.schematronValidation")); logger.info(Localization.getText("Checker.schematronValidation"));
} }
if (!Files.exists(Path.of(config.getSchematronFilePath()))) {
logger.warn(Localization.getText("Checker.schematronFileNotFound"), config.getSchematronFilePath());
return null;
}
try { try {
TransformerFactory transformerFactory = TransformerFactory.newInstance("net.sf.saxon.TransformerFactoryImpl", Checker.class.getClassLoader()); TransformerFactory transformerFactory = TransformerFactory.newInstance("net.sf.saxon.TransformerFactoryImpl", Checker.class.getClassLoader());
...@@ -559,7 +620,7 @@ public class Checker { ...@@ -559,7 +620,7 @@ public class Checker {
for (Entry<String, RequirementConfiguration> e : config.getRequirements().entrySet()) { for (Entry<String, RequirementConfiguration> e : config.getRequirements().entrySet()) {
de.hft.stuttgart.citydoctor2.check.Requirement req = Checks.getAvailableRequirements().get(e.getKey()); de.hft.stuttgart.citydoctor2.check.Requirement req = Checks.getAvailableRequirements().get(e.getKey());
if (req == null) { 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()); e.getKey());
} else { } else {
if (e.getValue().isEnabled()) { if (e.getValue().isEnabled()) {
...@@ -626,31 +687,110 @@ public class Checker { ...@@ -626,31 +687,110 @@ public class Checker {
} }
} }
private void checkCityModel(CityDoctorModel model, ProgressListener l) { private void checkCityModel(CityDoctorModel model, ProgressListener l){
Stream<CityObject> features = model.createFeatureStream(); List<GmlId> features = model.getFeatureIds();
float featureSum = model.getNumberOfFeatures();
AtomicInteger checkedCount = new AtomicInteger(0);
// clear global errors // clear global errors
model.getGlobalErrors().clear(); model.getGlobalErrors().clear();
CityObjectCache cache = model.getCache();
// stupid lamda with final variable restrictions logger.trace("Setting up ThreadPool");
int[] currentFeature = new int[1]; int threadCount = Runtime.getRuntime().availableProcessors() * 5;
features.forEach(co -> { ExecutorService exec = new ThreadPoolExecutor
if (config.getParserConfiguration().useLowMemoryConsumption()) { (threadCount, threadCount, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<>());
// no edges have been created yet, create them try{
co.prepareForChecking(); 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 long endTime = System.nanoTime();
executeChecksForCityObject(co); 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()) { } catch (InterruptedException e) {
// low memory consumption, remove edges again Thread.currentThread().interrupt();
co.clearMetaInformation(); 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) { private boolean filterObject(CityObject co) {
...@@ -756,73 +896,6 @@ public class Checker { ...@@ -756,73 +896,6 @@ public class Checker {
return hasUnusedDependency; 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, public static void streamCheck(File inputFile, String xmlOutput, String pdfOutput, ValidationConfiguration config,
String outputFile) throws IOException, CityGmlParseException { String outputFile) throws IOException, CityGmlParseException {
streamCheck(inputFile, xmlOutput, pdfOutput, config, null, outputFile); streamCheck(inputFile, xmlOutput, pdfOutput, config, null, outputFile);
......
...@@ -134,7 +134,7 @@ public class StreamCityGmlConsumer implements CityGmlConsumer { ...@@ -134,7 +134,7 @@ public class StreamCityGmlConsumer implements CityGmlConsumer {
pdfReporter.report(co); 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)) { if (!(co instanceof AbstractTunnel || co instanceof CityFurniture || co instanceof GenericCityObject)) {
// store quality ade datastructures in cityobject // store quality ade datastructures in cityobject
QualityADEUtils.writeQualityAde(co, val); QualityADEUtils.writeQualityAde(co, val);
......
...@@ -230,6 +230,24 @@ public class CheckContainer extends Check { ...@@ -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 @Override
public void check(CityFurniture cf){ public void check(CityFurniture cf){
try { try {
...@@ -248,6 +266,15 @@ public class CheckContainer extends Check { ...@@ -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 @Override
public RequirementType getType() { public RequirementType getType() {
return check.getType(); return check.getType();
......
...@@ -106,12 +106,12 @@ public class SvrlContentHandler implements ContentHandler { ...@@ -106,12 +106,12 @@ public class SvrlContentHandler implements ContentHandler {
throw new IllegalStateException( throw new IllegalStateException(
"Schematron File is not formed according to specification for CityDoctor."); "Schematron File is not formed according to specification for CityDoctor.");
} }
String gmlId = split[0]; String gmlId = split[0].strip();
String childId = split[1]; String childId = split[1];
String errorId = split[2]; String errorId = split[2];
String nameOfAttribute = split[3]; String nameOfAttribute = split[3];
SchematronError err = new SchematronError(errorId, gmlId, childId, nameOfAttribute); SchematronError err = new SchematronError(errorId, gmlId, childId, nameOfAttribute);
if (gmlId == null || gmlId.isEmpty()) { if (gmlId == null || gmlId.isBlank()) {
// general error // general error
generalErrors.add(err); generalErrors.add(err);
} else { } else {
......
...@@ -57,10 +57,12 @@ import de.hft.stuttgart.citydoctor2.tesselation.TesselatedPolygon; ...@@ -57,10 +57,12 @@ import de.hft.stuttgart.citydoctor2.tesselation.TesselatedPolygon;
*/ */
public class PlanarCheck extends Check { public class PlanarCheck extends Check {
private static final String DISTANCE = "distance"; public static final String ANGLE = "angle";
private static final String DISTANCE_TOLERANCE = "distanceTolerance"; 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 ANGLE_TOLERANCE = "angleTolerance";
private static final String TYPE = "type"; public static final String TYPE = "type";
private static final List<CheckId> dependencies; private static final List<CheckId> dependencies;
...@@ -97,7 +99,7 @@ public class PlanarCheck extends Check { ...@@ -97,7 +99,7 @@ public class PlanarCheck extends Check {
public void check(Polygon p) { public void check(Polygon p) {
if (DISTANCE.equals(planarCheckType)) { if (DISTANCE.equals(planarCheckType)) {
planarDistance(p); planarDistance(p);
} else if ("angle".equals(planarCheckType)) { } else if (ANGLE.equals(planarCheckType)) {
planarNormalDeviation(p); planarNormalDeviation(p);
} else if ("both".equals(planarCheckType)) { } else if ("both".equals(planarCheckType)) {
planarDistance(p); planarDistance(p);
......
...@@ -21,13 +21,13 @@ package de.hft.stuttgart.citydoctor2.checks.geometry; ...@@ -21,13 +21,13 @@ package de.hft.stuttgart.citydoctor2.checks.geometry;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Set; import java.util.Set;
import de.hft.stuttgart.citydoctor2.check.Check; import de.hft.stuttgart.citydoctor2.check.Check;
import de.hft.stuttgart.citydoctor2.check.CheckError; import de.hft.stuttgart.citydoctor2.check.CheckError;
import de.hft.stuttgart.citydoctor2.check.CheckId; import de.hft.stuttgart.citydoctor2.check.CheckId;
import de.hft.stuttgart.citydoctor2.check.CheckResult; 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.Requirement;
import de.hft.stuttgart.citydoctor2.check.RequirementType; import de.hft.stuttgart.citydoctor2.check.RequirementType;
import de.hft.stuttgart.citydoctor2.check.ResultStatus; import de.hft.stuttgart.citydoctor2.check.ResultStatus;
...@@ -36,6 +36,7 @@ import de.hft.stuttgart.citydoctor2.checks.util.CollectionUtils; ...@@ -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.checks.util.SelfIntersectionUtil;
import de.hft.stuttgart.citydoctor2.datastructure.Geometry; import de.hft.stuttgart.citydoctor2.datastructure.Geometry;
import de.hft.stuttgart.citydoctor2.datastructure.GeometryType; import de.hft.stuttgart.citydoctor2.datastructure.GeometryType;
import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration;
import de.hft.stuttgart.citydoctor2.utils.PolygonIntersection; import de.hft.stuttgart.citydoctor2.utils.PolygonIntersection;
/** /**
...@@ -47,7 +48,9 @@ import de.hft.stuttgart.citydoctor2.utils.PolygonIntersection; ...@@ -47,7 +48,9 @@ import de.hft.stuttgart.citydoctor2.utils.PolygonIntersection;
public class SolidSelfIntCheck extends Check { public class SolidSelfIntCheck extends Check {
private static final List<CheckId> dependencies; private static final List<CheckId> dependencies;
private double delta = 0.01;
static { static {
ArrayList<CheckId> deps = new ArrayList<>(); ArrayList<CheckId> deps = new ArrayList<>();
dependencies = Collections.unmodifiableList(deps); dependencies = Collections.unmodifiableList(deps);
...@@ -68,6 +71,13 @@ public class SolidSelfIntCheck extends Check { ...@@ -68,6 +71,13 @@ public class SolidSelfIntCheck extends Check {
deps.add(CheckId.C_GE_S_NON_MANIFOLD_VERTEX); deps.add(CheckId.C_GE_S_NON_MANIFOLD_VERTEX);
deps.add(CheckId.C_GE_S_POLYGON_WRONG_ORIENTATION); 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 @Override
public void check(Geometry g) { public void check(Geometry g) {
...@@ -75,7 +85,7 @@ public class SolidSelfIntCheck extends Check { ...@@ -75,7 +85,7 @@ public class SolidSelfIntCheck extends Check {
return; return;
} }
CheckResult cr; CheckResult cr;
List<PolygonIntersection> intersections = SelfIntersectionUtil.calculateSolidSelfIntersection(g); List<PolygonIntersection> intersections = SelfIntersectionUtil.calculateSolidSelfIntersection(g, delta);
if (intersections.isEmpty()) { if (intersections.isEmpty()) {
cr = new CheckResult(this, ResultStatus.OK, null); cr = new CheckResult(this, ResultStatus.OK, null);
} else { } else {
...@@ -85,18 +95,6 @@ public class SolidSelfIntCheck extends Check { ...@@ -85,18 +95,6 @@ public class SolidSelfIntCheck extends Check {
g.addCheckResult(cr); 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 @Override
public List<CheckId> getDependencies() { public List<CheckId> getDependencies() {
return dependencies; return dependencies;
......
...@@ -21,6 +21,7 @@ package de.hft.stuttgart.citydoctor2.checks.util; ...@@ -21,6 +21,7 @@ package de.hft.stuttgart.citydoctor2.checks.util;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.IdentityHashMap; import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
...@@ -39,6 +40,8 @@ import org.locationtech.jts.geom.impl.CoordinateArraySequence; ...@@ -39,6 +40,8 @@ import org.locationtech.jts.geom.impl.CoordinateArraySequence;
import org.locationtech.jts.operation.overlay.OverlayOp; import org.locationtech.jts.operation.overlay.OverlayOp;
import org.locationtech.jts.operation.overlay.snap.SnapIfNeededOverlayOp; 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.check.GeometrySelfIntersection;
import de.hft.stuttgart.citydoctor2.datastructure.ConcretePolygon; import de.hft.stuttgart.citydoctor2.datastructure.ConcretePolygon;
import de.hft.stuttgart.citydoctor2.datastructure.Geometry; import de.hft.stuttgart.citydoctor2.datastructure.Geometry;
...@@ -50,8 +53,10 @@ import de.hft.stuttgart.citydoctor2.edge.EdgePolygon; ...@@ -50,8 +53,10 @@ import de.hft.stuttgart.citydoctor2.edge.EdgePolygon;
import de.hft.stuttgart.citydoctor2.edge.IntersectPlanarPolygons; import de.hft.stuttgart.citydoctor2.edge.IntersectPlanarPolygons;
import de.hft.stuttgart.citydoctor2.edge.MeshSurface; import de.hft.stuttgart.citydoctor2.edge.MeshSurface;
import de.hft.stuttgart.citydoctor2.edge.PolygonPolygonIntersection; 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.MovedPolygon;
import de.hft.stuttgart.citydoctor2.math.MovedRing; 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.Plane;
import de.hft.stuttgart.citydoctor2.math.PlaneSegmentIntersection; import de.hft.stuttgart.citydoctor2.math.PlaneSegmentIntersection;
import de.hft.stuttgart.citydoctor2.math.PlaneSegmentIntersection.Type; import de.hft.stuttgart.citydoctor2.math.PlaneSegmentIntersection.Type;
...@@ -83,18 +88,37 @@ public class SelfIntersectionUtil { ...@@ -83,18 +88,37 @@ public class SelfIntersectionUtil {
private SelfIntersectionUtil() { private SelfIntersectionUtil() {
} }
public static List<PolygonIntersection> calculateSolidSelfIntersection(Geometry g) { public static List<PolygonIntersection> calculateSolidSelfIntersection(Geometry g, double delta) {
List<TesselatedPolygon> tesselatedPolygons = new ArrayList<>(); List<TesselatedPolygon> tesselatedPolygons = new ArrayList<>();
for (Polygon p : g.getPolygons()) { 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<>(); List<PolygonIntersection> intersections = new ArrayList<>();
for (int i = 0; i < tesselatedPolygons.size() - 1; i++) { for (int i = 0; i < tesselatedPolygons.size() - 1; i++) {
TesselatedPolygon p1 = tesselatedPolygons.get(i); TesselatedPolygon p1 = tesselatedPolygons.get(i);
for (int j = i + 1; j < tesselatedPolygons.size(); j++) { for (int j = i + 1; j < tesselatedPolygons.size(); j++) {
TesselatedPolygon p2 = tesselatedPolygons.get(j); TesselatedPolygon p2 = tesselatedPolygons.get(j);
GeometrySelfIntersection intersection = doPolygonsIntersect(p1, p2); GeometrySelfIntersection intersection = doPolygonsIntersect(p1, p2, delta);
if (intersection != null) { if (intersection != null) {
intersections.add(PolygonIntersection.triangles(intersection.t1(), intersection.t2())); intersections.add(PolygonIntersection.triangles(intersection.t1(), intersection.t2()));
} }
...@@ -103,8 +127,8 @@ public class SelfIntersectionUtil { ...@@ -103,8 +127,8 @@ public class SelfIntersectionUtil {
return intersections; return intersections;
} }
public static GeometrySelfIntersection doesSolidSelfIntersect(Geometry g) { public static GeometrySelfIntersection doesSolidSelfIntersect(Geometry g, double epsilon) {
return selfIntersectionJava(g); return selfIntersectionJava(g, epsilon);
} }
public static List<PolygonIntersection> doesSolidSelfIntersect2(Geometry g) { public static List<PolygonIntersection> doesSolidSelfIntersect2(Geometry g) {
...@@ -404,7 +428,7 @@ public class SelfIntersectionUtil { ...@@ -404,7 +428,7 @@ public class SelfIntersectionUtil {
return sign != 0; return sign != 0;
} }
private static GeometrySelfIntersection selfIntersectionJava(Geometry g) { private static GeometrySelfIntersection selfIntersectionJava(Geometry g, double epsilon) {
List<TesselatedPolygon> tessPolys = new ArrayList<>(); List<TesselatedPolygon> tessPolys = new ArrayList<>();
for (Polygon p : g.getPolygons()) { for (Polygon p : g.getPolygons()) {
tessPolys.add(JoglTesselator.tesselatePolygon(p)); tessPolys.add(JoglTesselator.tesselatePolygon(p));
...@@ -413,7 +437,7 @@ public class SelfIntersectionUtil { ...@@ -413,7 +437,7 @@ public class SelfIntersectionUtil {
TesselatedPolygon p1 = tessPolys.get(i); TesselatedPolygon p1 = tessPolys.get(i);
for (int j = i + 1; j < tessPolys.size(); j++) { for (int j = i + 1; j < tessPolys.size(); j++) {
TesselatedPolygon p2 = tessPolys.get(j); TesselatedPolygon p2 = tessPolys.get(j);
GeometrySelfIntersection intersection = doPolygonsIntersect(p1, p2); GeometrySelfIntersection intersection = doPolygonsIntersect(p1, p2, epsilon);
if (intersection != null) { if (intersection != null) {
return intersection; return intersection;
} }
...@@ -422,12 +446,12 @@ public class SelfIntersectionUtil { ...@@ -422,12 +446,12 @@ public class SelfIntersectionUtil {
return null; 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 p1Index = 0; p1Index < p1.getTriangles().size(); p1Index++) {
for (int p2Index = 0; p2Index < p2.getTriangles().size(); p2Index++) { for (int p2Index = 0; p2Index < p2.getTriangles().size(); p2Index++) {
Triangle3d t1 = p1.getTriangles().get(p1Index); Triangle3d t1 = p1.getTriangles().get(p1Index);
Triangle3d t2 = p2.getTriangles().get(p2Index); Triangle3d t2 = p2.getTriangles().get(p2Index);
if (t1.doesIntersect(t2)) { if (t1.doesIntersect(t2, epsilon)) {
logger.trace("{} intersects {}", t1, t2); logger.trace("{} intersects {}", t1, t2);
logger.trace("GML-ID: {} intersects {}", t1.getPartOf().getOriginal().getGmlId(), logger.trace("GML-ID: {} intersects {}", t1.getPartOf().getOriginal().getGmlId(),
t2.getPartOf().getOriginal().getGmlId()); t2.getPartOf().getOriginal().getGmlId());
......
...@@ -45,33 +45,8 @@ public class XmlValidationReporter implements Reporter { ...@@ -45,33 +45,8 @@ public class XmlValidationReporter implements Reporter {
@Override @Override
public void writeReport(Checks checks, OutputStream filePath, CityDoctorModel model, ValidationConfiguration config) throws CheckReportWriteException { public void writeReport(Checks checks, OutputStream filePath, CityDoctorModel model, ValidationConfiguration config) throws CheckReportWriteException {
StreamReporter streamReporter = new XmlStreamReporter(filePath, model.getFileName(), config); StreamReporter streamReporter = new XmlStreamReporter(filePath, model.getFileName(), config);
for (BridgeObject bo : model.getBridges()) { model.createFeatureStream().forEach(streamReporter::report);
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);
}
for (CheckError err : model.getGlobalErrors()) { for (CheckError err : model.getGlobalErrors()) {
streamReporter.reportGlobalError(err); 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