Commit 6aab3d8b authored by duminil's avatar duminil
Browse files

RegionChooser: CityGML envelope is updated when extracted.

No related merge requests found
Showing with 67 additions and 23 deletions
+67 -23
...@@ -37,6 +37,9 @@ ...@@ -37,6 +37,9 @@
public class RegionChooserBrowser extends Region public class RegionChooserBrowser extends Region
{ {
/**
* JavaFX Backend for RegionChooser. Inside simstadt_openlayers.js frontend, this class is available as `fxapp`.
*/
public class JavaScriptFXBridge public class JavaScriptFXBridge
{ {
private Path repo; private Path repo;
...@@ -95,10 +98,11 @@ public void extractZIPtoGML(String zipFilename) throws IOException { ...@@ -95,10 +98,11 @@ public void extractZIPtoGML(String zipFilename) throws IOException {
zipFile.close(); zipFile.close();
} }
public void downloadRegionFromCityGML(String wktPolygon, String project, String citygml) public void downloadRegionFromCityGML(String wktPolygon, String project, String citygml, String srsName)
throws IOException, ParseException, SAXParseException, XMLStreamException, NumberFormatException, throws IOException, ParseException, SAXParseException, XMLStreamException, NumberFormatException,
XPathParseException, NavException, XPathEvalException { XPathParseException, NavException, XPathEvalException {
StringBuffer sb = RegionExtractor.selectRegionDirectlyFromCityGML(citygmlPath(project, citygml), wktPolygon); StringBuffer sb = RegionExtractor.selectRegionDirectlyFromCityGML(citygmlPath(project, citygml), wktPolygon,
srsName);
File buildingIdsFile = selectSaveFileWithDialog(project, citygml, "selected_region"); File buildingIdsFile = selectSaveFileWithDialog(project, citygml, "selected_region");
if (buildingIdsFile != null) { if (buildingIdsFile != null) {
......
...@@ -13,7 +13,7 @@ public class RegionChooserFX extends Application ...@@ -13,7 +13,7 @@ public class RegionChooserFX extends Application
protected final static Logger LOGGER = Logger.getLogger(RegionChooserFX.class.getName()); protected final static Logger LOGGER = Logger.getLogger(RegionChooserFX.class.getName());
/** /**
* Start point of RegionChooser application. Either "Run as Java" from Eclipse or run * Starting point of RegionChooser application. Either "Run as Java" from Eclipse or run
* "RegionChooser.bat/.sh/.command" from deployed SimStadt folder. * "RegionChooser.bat/.sh/.command" from deployed SimStadt folder.
* *
* This application is basically just a scene and a browser for the RegionChooser website (HTML + Javascript frontend * This application is basically just a scene and a browser for the RegionChooser website (HTML + Javascript frontend
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamException;
import org.xml.sax.SAXParseException; import org.xml.sax.SAXParseException;
import com.vividsolutions.jts.geom.Coordinate; import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Envelope;
import com.vividsolutions.jts.geom.Geometry; import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryFactory; import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.Point; import com.vividsolutions.jts.geom.Point;
...@@ -34,10 +35,11 @@ ...@@ -34,10 +35,11 @@
* *
* @param citygmlPath * @param citygmlPath
* @param wktPolygon * @param wktPolygon
* @return * @param string
* @return a StringBuffer, full with the extracted Citygml, including header, buildings and footer.
* @throws Exception * @throws Exception
*/ */
static public StringBuffer selectRegionDirectlyFromCityGML(Path citygmlPath, String wktPolygon) static public StringBuffer selectRegionDirectlyFromCityGML(Path citygmlPath, String wktPolygon, String srsName)
throws SAXParseException, XMLStreamException, ParseException, XPathParseException, NavException, throws SAXParseException, XMLStreamException, ParseException, XPathParseException, NavException,
NumberFormatException, XPathEvalException, IOException { NumberFormatException, XPathEvalException, IOException {
...@@ -49,10 +51,7 @@ static public StringBuffer selectRegionDirectlyFromCityGML(Path citygmlPath, Str ...@@ -49,10 +51,7 @@ static public StringBuffer selectRegionDirectlyFromCityGML(Path citygmlPath, Str
CityGmlIterator citygml = new CityGmlIterator(citygmlPath); CityGmlIterator citygml = new CityGmlIterator(citygmlPath);
for (BuildingXmlNode buildingXmlNode : citygml) { for (BuildingXmlNode buildingXmlNode : citygml) {
if (buildingsCount == 0) { if (buildingsCount == 0) {
//TODO: Replace original CityGML envelope with a smaller one, corresponding to wktPolygon sb.append(replaceEnvelopeInHeader(citygml.getHeader(), poly.getEnvelopeInternal(), srsName));
// Envelope env = poly.getEnvelopeInternal();
// System.out.println(env);
sb.append(citygml.getHeader());
} }
buildingsCount += 1; buildingsCount += 1;
Coordinate coord = new Coordinate(buildingXmlNode.x, buildingXmlNode.y); Coordinate coord = new Coordinate(buildingXmlNode.x, buildingXmlNode.y);
...@@ -68,7 +67,30 @@ static public StringBuffer selectRegionDirectlyFromCityGML(Path citygmlPath, Str ...@@ -68,7 +67,30 @@ static public StringBuffer selectRegionDirectlyFromCityGML(Path citygmlPath, Str
LOGGER.info("Buildings found in selected region " + foundBuildingsCount); LOGGER.info("Buildings found in selected region " + foundBuildingsCount);
sb.append(citygml.getFooter()); sb.append(citygml.getFooter());
return sb; return sb;
} }
/**
* Some Citygml files include an envelope (bounding box), defined at the very beginning of the file. If the extracted
* 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.
*
* @param header
* @param envelope
* @param srsName
* @return CityGML Header with an updated envelope
*/
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>", "");
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:Envelope>\r\n" +
"</gml:boundedBy>\r\n";
return headerWithoutEnvelope + newEnvelope;
}
} }
...@@ -229,7 +229,7 @@ function downloadRegionFromCityGML(i) { ...@@ -229,7 +229,7 @@ function downloadRegionFromCityGML(i) {
if (proj4.defs(srsName)){ if (proj4.defs(srsName)){
$("html").addClass("wait"); $("html").addClass("wait");
console.log("Selected region is written in " + srsName + " coordinate system."); console.log("Selected region is written in " + srsName + " coordinate system.");
fxapp.downloadRegionFromCityGML(sketchAsWKT(srsName), feature.get("project"), feature.get("name")); fxapp.downloadRegionFromCityGML(sketchAsWKT(srsName), feature.get("project"), feature.get("name"), srsName);
var end = new Date().getTime(); var end = new Date().getTime();
var time = end - start; var time = end - start;
console.log('DL Execution time: ' + time); console.log('DL Execution time: ' + time);
......
...@@ -25,11 +25,11 @@ public static int countRegexMatches(String str, String subStr) { ...@@ -25,11 +25,11 @@ public static int countRegexMatches(String str, String subStr) {
@Test @Test
public void testExtract3BuildingsFromGSK3Model() throws Throwable { public void testExtract3BuildingsFromGSK3Model() throws Throwable {
//NOTE: Small region around Martinskirche in Grünbühl //NOTE: Small region around Martinskirche in Grünbühl
// "EPSG:31467"
String wktPolygon = "POLYGON((3515848.896028535 5415823.108586172,3515848.9512289143 5415803.590347393,3515829.0815150724 5415803.338023346,3515830.9784850604 5415793.437034622,3515842.0946056456 5415793.272282251,3515843.3515515197 5415766.204935087,3515864.1064344468 5415766.557899496,3515876.489172751 5415805.433782301,3515876.343844858 5415822.009293416,3515848.896028535 5415823.108586172))"; String wktPolygon = "POLYGON((3515848.896028535 5415823.108586172,3515848.9512289143 5415803.590347393,3515829.0815150724 5415803.338023346,3515830.9784850604 5415793.437034622,3515842.0946056456 5415793.272282251,3515843.3515515197 5415766.204935087,3515864.1064344468 5415766.557899496,3515876.489172751 5415805.433782301,3515876.343844858 5415822.009293416,3515848.896028535 5415823.108586172))";
Path repo = Paths.get("../TestRepository"); Path repo = Paths.get("../TestRepository");
Path citygmlPath = repo.resolve("Gruenbuehl.proj/20140218_Gruenbuehl_LOD2.gml"); Path citygmlPath = repo.resolve("Gruenbuehl.proj/20140218_Gruenbuehl_LOD2.gml");
String churchGMLString = RegionExtractor.selectRegionDirectlyFromCityGML(citygmlPath, wktPolygon).toString(); String churchGMLString = RegionExtractor.selectRegionDirectlyFromCityGML(citygmlPath, wktPolygon, "EPSG:31467")
.toString();
assertEquals(countRegexMatches(churchGMLString, "<(core:)?cityObjectMember"), 3); assertEquals(countRegexMatches(churchGMLString, "<(core:)?cityObjectMember"), 3);
assertTrue(churchGMLString.contains("Donaustr")); assertTrue(churchGMLString.contains("Donaustr"));
assertTrue(churchGMLString.contains("DEBW_LOD2_203056")); assertTrue(churchGMLString.contains("DEBW_LOD2_203056"));
...@@ -37,24 +37,33 @@ public void testExtract3BuildingsFromGSK3Model() throws Throwable { ...@@ -37,24 +37,33 @@ public void testExtract3BuildingsFromGSK3Model() throws Throwable {
assertTrue(churchGMLString.contains("DEBW_LOD2_2909")); assertTrue(churchGMLString.contains("DEBW_LOD2_2909"));
assertTrue(churchGMLString.contains("<core:CityModel")); // Header assertTrue(churchGMLString.contains("<core:CityModel")); // Header
assertTrue(churchGMLString.contains("</core:CityModel")); // Footer 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
.contains("<gml:lowerCorner>3515829.0815150724 5415766.204935087 "));
assertTrue("The exported CityGML should contain a new envelope", churchGMLString
.contains("<gml:upperCorner>3515876.489172751 5415823.108586172 "));
} }
@Test @Test
public void testExtractBuildingsWithoutCommentsInBetween() throws Throwable { public void testExtractBuildingsWithoutCommentsInBetween() throws Throwable {
//NOTE: Small region around WashingtonSquare //NOTE: Small region around WashingtonSquare
// "EPSG:32118"
String wktPolygon = "POLYGON((300259.78663489706 62835.835907766595,300230.33294975647 62792.0482567884,300213.5667431851 62770.83143720031,300183.6592861123 62730.20347659383,300252.9947486632 62676.938468840905,300273.3862256562 62701.767105345614,300257.5250407747 62715.760413539596,300308.2754543957 62805.14198211394,300259.78663489706 62835.835907766595))"; String wktPolygon = "POLYGON((300259.78663489706 62835.835907766595,300230.33294975647 62792.0482567884,300213.5667431851 62770.83143720031,300183.6592861123 62730.20347659383,300252.9947486632 62676.938468840905,300273.3862256562 62701.767105345614,300257.5250407747 62715.760413539596,300308.2754543957 62805.14198211394,300259.78663489706 62835.835907766595))";
Path repo = Paths.get("../TestRepository"); Path repo = Paths.get("../TestRepository");
Path citygmlPath = repo.resolve("NewYork.proj/ManhattanSmall.gml"); Path citygmlPath = repo.resolve("NewYork.proj/ManhattanSmall.gml");
String archGMLString = RegionExtractor.selectRegionDirectlyFromCityGML(citygmlPath, wktPolygon).toString(); String archGMLString = RegionExtractor.selectRegionDirectlyFromCityGML(citygmlPath, wktPolygon, "EPSG:32118")
.toString();
assertEquals(countRegexMatches(archGMLString, "<(core:)?cityObjectMember"), 2); assertEquals(countRegexMatches(archGMLString, "<(core:)?cityObjectMember"), 2);
assertTrue(archGMLString.contains("WASHINGTON SQUARE")); assertTrue(archGMLString.contains("WASHINGTON SQUARE"));
assertTrue(archGMLString.contains("uuid_c0980a6e-05ea-4d09-bc83-efab226945a1")); assertTrue(archGMLString.contains("uuid_c0980a6e-05ea-4d09-bc83-efab226945a1"));
assertTrue(archGMLString.contains("uuid_0985cebb-922d-4b3e-95e5-15dc6089cd28")); assertTrue(archGMLString.contains("uuid_0985cebb-922d-4b3e-95e5-15dc6089cd28"));
assertTrue(archGMLString.contains("<CityModel")); // Header assertTrue(archGMLString.contains("<CityModel")); // Header
assertTrue(archGMLString.contains("</CityModel")); // Footer assertTrue(archGMLString.contains("</CityModel")); // Footer
assertFalse(archGMLString.contains("comment between buildings")); // Comment assertFalse("Comments between buildings shouldn't be extracted",
assertFalse(archGMLString.contains("comment after last building")); // Comment archGMLString.contains("comment between buildings")); // Comment
assertFalse("Comments after buildings shouldn't be extracted",
archGMLString.contains("comment after last building")); // Comment
} }
@Test @Test
...@@ -62,23 +71,31 @@ public void testExtractBuildingsAndChangeEnvelope() throws Throwable { ...@@ -62,23 +71,31 @@ public void testExtractBuildingsAndChangeEnvelope() throws Throwable {
String wktPolygon = "POLYGON((299761.8123557725 61122.68126771413,299721.46983062755 61058.11626595352,299780.84627343423 61021.99295737501,299823.9079725632 61083.3979344517,299761.8123557725 61122.68126771413))"; String wktPolygon = "POLYGON((299761.8123557725 61122.68126771413,299721.46983062755 61058.11626595352,299780.84627343423 61021.99295737501,299823.9079725632 61083.3979344517,299761.8123557725 61122.68126771413))";
Path repo = Paths.get("../TestRepository"); Path repo = Paths.get("../TestRepository");
Path citygmlPath = repo.resolve("NewYork.proj/FamilyCourt_LOD2_with_PLUTO_attributes.gml"); Path citygmlPath = repo.resolve("NewYork.proj/FamilyCourt_LOD2_with_PLUTO_attributes.gml");
String familyCourtBuilding = RegionExtractor.selectRegionDirectlyFromCityGML(citygmlPath, wktPolygon).toString(); String familyCourtBuilding = RegionExtractor
.selectRegionDirectlyFromCityGML(citygmlPath, wktPolygon, "EPSG:32118")
.toString();
assertEquals(countRegexMatches(familyCourtBuilding, "<(core:)?cityObjectMember"), 1); assertEquals(countRegexMatches(familyCourtBuilding, "<(core:)?cityObjectMember"), 1);
assertTrue(familyCourtBuilding.contains("Bldg_12210021066")); assertTrue(familyCourtBuilding.contains("Bldg_12210021066"));
assertFalse("The exported CityGML shouldn't contain the original envelope", familyCourtBuilding assertFalse("The exported CityGML shouldn't contain the original envelope", familyCourtBuilding
.contains("<gml:lowerCorner>298393.46959639067 59277.34021543693 -11.892070104139751</gml:lowerCorner>")); .contains("<gml:lowerCorner>298393.46959639067 59277.34021543693 -11.892070104139751</gml:lowerCorner>"));
assertFalse("The exported CityGML shouldn't contain the original envelope", familyCourtBuilding assertFalse("The exported CityGML shouldn't contain the original envelope", familyCourtBuilding
.contains("<gml:upperCorner>305641.79529639013 67101.44881543722 547.7591871983744</gml:upperCorner>")); .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 correct EPSG", familyCourtBuilding
.contains("<gml:Envelope srsName=\"EPSG:32118\" srsDimension=\"3\">"));
} }
@Test @Test
public void testExtract0BuildingsWithWrongCoordinates() throws Throwable { public void testExtract0BuildingsWithWrongCoordinates() throws Throwable {
//NOTE: Small region, far away from NYC //NOTE: Small region, far away from NYC
// "EPSG:32118"
String wktPolygon = "POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))"; String wktPolygon = "POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))";
Path repo = Paths.get("../TestRepository"); Path repo = Paths.get("../TestRepository");
Path citygmlPath = repo.resolve("NewYork.proj/ManhattanSmall.gml"); Path citygmlPath = repo.resolve("NewYork.proj/ManhattanSmall.gml");
String emptyGMLString = RegionExtractor.selectRegionDirectlyFromCityGML(citygmlPath, wktPolygon).toString(); String emptyGMLString = RegionExtractor.selectRegionDirectlyFromCityGML(citygmlPath, wktPolygon, "EPSG:32118")
.toString();
assertEquals(countRegexMatches(emptyGMLString, "<(core:)?cityObjectMember"), 0); assertEquals(countRegexMatches(emptyGMLString, "<(core:)?cityObjectMember"), 0);
assertTrue(emptyGMLString.contains("<CityModel")); // Header assertTrue(emptyGMLString.contains("<CityModel")); // Header
assertTrue(emptyGMLString.contains("</CityModel")); // Footer assertTrue(emptyGMLString.contains("</CityModel")); // Footer
...@@ -87,11 +104,11 @@ public void testExtract0BuildingsWithWrongCoordinates() throws Throwable { ...@@ -87,11 +104,11 @@ public void testExtract0BuildingsWithWrongCoordinates() throws Throwable {
@Test @Test
public void testExtract0BuildingsFromEmptyGML() throws Throwable { public void testExtract0BuildingsFromEmptyGML() throws Throwable {
//NOTE: Small region, with too many spaces between coordinates //NOTE: Small region, with too many spaces between coordinates
// "EPSG:32118"
String wktPolygon = "POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))"; String wktPolygon = "POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))";
Path repo = Paths.get("../TestRepository"); Path repo = Paths.get("../TestRepository");
Path citygmlPath = repo.resolve("NewYork.proj/empty_model.gml"); Path citygmlPath = repo.resolve("NewYork.proj/empty_model.gml");
String emptyGMLString = RegionExtractor.selectRegionDirectlyFromCityGML(citygmlPath, wktPolygon).toString(); String emptyGMLString = RegionExtractor.selectRegionDirectlyFromCityGML(citygmlPath, wktPolygon, "EPSG:32118")
.toString();
assertEquals(countRegexMatches(emptyGMLString, "<(core:)?cityObjectMember"), 0); assertEquals(countRegexMatches(emptyGMLString, "<(core:)?cityObjectMember"), 0);
assertTrue(emptyGMLString.contains("<core:CityModel")); // Header assertTrue(emptyGMLString.contains("<core:CityModel")); // Header
assertTrue(emptyGMLString.contains("</core:CityModel")); // Footer assertTrue(emptyGMLString.contains("</core:CityModel")); // Footer
...@@ -103,7 +120,8 @@ public void testExtract0BuildingsFromWeirdGML() throws Throwable { ...@@ -103,7 +120,8 @@ public void testExtract0BuildingsFromWeirdGML() throws Throwable {
String wktPolygon = "POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))"; String wktPolygon = "POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))";
Path repo = Paths.get("../TestRepository"); Path repo = Paths.get("../TestRepository");
Path citygmlPath = repo.resolve("NewYork.proj/broken_nyc_lod2.gml"); Path citygmlPath = repo.resolve("NewYork.proj/broken_nyc_lod2.gml");
String emptyGMLString = RegionExtractor.selectRegionDirectlyFromCityGML(citygmlPath, wktPolygon).toString(); String emptyGMLString = RegionExtractor.selectRegionDirectlyFromCityGML(citygmlPath, wktPolygon, "EPSG:32118")
.toString();
assertEquals(countRegexMatches(emptyGMLString, "<(core:)?cityObjectMember"), 0); assertEquals(countRegexMatches(emptyGMLString, "<(core:)?cityObjectMember"), 0);
assertTrue(emptyGMLString.contains("<core:CityModel")); // Header assertTrue(emptyGMLString.contains("<core:CityModel")); // Header
assertTrue(emptyGMLString.contains("</core:CityModel")); // Footer assertTrue(emptyGMLString.contains("</core:CityModel")); // Footer
......
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