diff --git a/src/eu/simstadt/regionchooser/RegionExtractor.java b/src/eu/simstadt/regionchooser/RegionExtractor.java index 7175ff4b0ff84b27d8b23eb31e3570bae3632a4c..e839730e9429ed430141c1f320a8f71c1ee61527 100644 --- a/src/eu/simstadt/regionchooser/RegionExtractor.java +++ b/src/eu/simstadt/regionchooser/RegionExtractor.java @@ -3,8 +3,8 @@ import java.io.IOException; import java.nio.file.Path; import java.util.logging.Logger; -import javax.xml.stream.XMLStreamException; -import org.xml.sax.SAXParseException; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import com.vividsolutions.jts.geom.Coordinate; import com.vividsolutions.jts.geom.Envelope; import com.vividsolutions.jts.geom.Geometry; @@ -37,11 +37,16 @@ * @param wktPolygon * @param string * @return a StringBuffer, full with the extracted Citygml, including header, buildings and footer. - * @throws Exception + * @throws ParseException + * @throws IOException + * @throws XPathEvalException + * @throws NavException + * @throws XPathParseException + * @throws NumberFormatException */ static public StringBuffer selectRegionDirectlyFromCityGML(Path citygmlPath, String wktPolygon, String srsName) - throws SAXParseException, XMLStreamException, ParseException, XPathParseException, NavException, - NumberFormatException, XPathEvalException, IOException { + throws ParseException, NumberFormatException, XPathParseException, NavException, XPathEvalException, + IOException { int buildingsCount = 0; int foundBuildingsCount = 0; @@ -75,7 +80,8 @@ static public StringBuffer selectRegionDirectlyFromCityGML(Path citygmlPath, Str * region comes from a huge file (e.g. from NYC), it might inherit this header with a huge envelope. Some methods * might get confused by this wrong envelope, so this method replaces the original envelope with the bounding box * from the extracting polygon. The real envelope might be even smaller, but it could only be known at the end of the - * parsing, after having analyzed every building. The envelope should be written in the header. + * parsing, after having analyzed every building. The envelope should be written in the header. If present, min and + * max values for Z are kept. * * @param header * @param envelope @@ -84,11 +90,23 @@ static public StringBuffer selectRegionDirectlyFromCityGML(Path citygmlPath, Str */ private static String replaceEnvelopeInHeader(String header, Envelope envelope, String srsName) { //NOTE: Sorry for using a regex to parse XML. The header in itself isn't correct, so this looked like the easiest solution. - String headerWithoutEnvelope = header.replaceFirst("(?is)<gml:boundedBy>.*?</gml:boundedBy>", ""); + double zMin = 0; + double zMax = 0; + Pattern boundedByPattern = Pattern.compile( + "(?is)<gml:boundedBy>.*?<gml:lowerCorner>(.*?)</gml:lowerCorner>\\s*<gml:upperCorner>(.*?)</gml:upperCorner>.*?</gml:boundedBy>"); + Matcher matcher = boundedByPattern.matcher(header); + String headerWithoutEnvelope = header; + if (matcher.find()) { + headerWithoutEnvelope = matcher.replaceFirst(""); + zMin = Double.valueOf(matcher.group(1).split("\\s+")[2]); + zMax = Double.valueOf(matcher.group(2).split("\\s+")[2]); + } String newEnvelope = "<gml:boundedBy>\r\n" + " <gml:Envelope srsName=\"" + srsName + "\" srsDimension=\"3\">\r\n" + //NOTE: Would srsDimension="2" be better? Should the original Z get extracted? - " <gml:lowerCorner>" + envelope.getMinX() + " " + envelope.getMinY() + " 0</gml:lowerCorner>\r\n" + - " <gml:upperCorner>" + envelope.getMaxX() + " " + envelope.getMaxY() + " 0</gml:upperCorner>\r\n" + + " <gml:lowerCorner>" + envelope.getMinX() + " " + envelope.getMinY() + " " + zMin + + "</gml:lowerCorner>\r\n" + + " <gml:upperCorner>" + envelope.getMaxX() + " " + envelope.getMaxY() + " " + zMax + + "</gml:upperCorner>\r\n" + " </gml:Envelope>\r\n" + "</gml:boundedBy>\r\n"; return headerWithoutEnvelope + newEnvelope; diff --git a/test/eu/simstadt/regionchooser/RegionExtractorTests.java b/test/eu/simstadt/regionchooser/RegionExtractorTests.java index fa0fdfae5f6be88f38a6dce5ff9ab7fcd17b34e7..3ccf24b494baabf8b02c82b7b132821ee1736943 100644 --- a/test/eu/simstadt/regionchooser/RegionExtractorTests.java +++ b/test/eu/simstadt/regionchooser/RegionExtractorTests.java @@ -37,7 +37,6 @@ public void testExtract3BuildingsFromGSK3Model() throws Throwable { assertTrue(churchGMLString.contains("DEBW_LOD2_2909")); assertTrue(churchGMLString.contains("<core:CityModel")); // Header assertTrue(churchGMLString.contains("</core:CityModel")); // Footer - System.out.println(churchGMLString); assertTrue("The exported CityGML should contain a new envelope with the correct EPSG", churchGMLString .contains("<gml:Envelope srsName=\"EPSG:31467\" srsDimension=\"3\">")); assertTrue("The exported CityGML should contain a new envelope", churchGMLString @@ -72,18 +71,17 @@ public void testExtractBuildingsAndChangeEnvelope() throws Throwable { Path repo = Paths.get("../TestRepository"); Path citygmlPath = repo.resolve("NewYork.proj/FamilyCourt_LOD2_with_PLUTO_attributes.gml"); String familyCourtBuilding = RegionExtractor - .selectRegionDirectlyFromCityGML(citygmlPath, wktPolygon, "EPSG:32118") - .toString(); + .selectRegionDirectlyFromCityGML(citygmlPath, wktPolygon, "EPSG:32118").toString(); assertEquals(countRegexMatches(familyCourtBuilding, "<(core:)?cityObjectMember"), 1); assertTrue(familyCourtBuilding.contains("Bldg_12210021066")); assertFalse("The exported CityGML shouldn't contain the original envelope", familyCourtBuilding .contains("<gml:lowerCorner>298393.46959639067 59277.34021543693 -11.892070104139751</gml:lowerCorner>")); assertFalse("The exported CityGML shouldn't contain the original envelope", familyCourtBuilding .contains("<gml:upperCorner>305641.79529639013 67101.44881543722 547.7591871983744</gml:upperCorner>")); - assertTrue("The exported CityGML should contain a new envelope", familyCourtBuilding - .contains("<gml:lowerCorner>299721.46983062755 61021.99295737501 ")); - assertTrue("The exported CityGML should contain a new envelope", familyCourtBuilding - .contains("<gml:upperCorner>299823.9079725632 61122.68126771413 ")); + assertTrue("The exported CityGML should contain a new envelope with the original altitudes", familyCourtBuilding + .contains("<gml:lowerCorner>299721.46983062755 61021.99295737501 -11.89")); + assertTrue("The exported CityGML should contain a new envelope with the original altitudes", familyCourtBuilding + .contains("<gml:upperCorner>299823.9079725632 61122.68126771413 547.75")); assertTrue("The exported CityGML should contain a new envelope with the correct EPSG", familyCourtBuilding .contains("<gml:Envelope srsName=\"EPSG:32118\" srsDimension=\"3\">")); }