Commits (10)
java -classpath lib/* -Xms512m -Xmx2g -Djava.util.logging.config.file=logging.properties eu.simstadt.regionchooser.RegionChooserFX java -classpath lib/* -Xms512m -Xmx2g -Djava.util.logging.config.file=logging.properties eu.simstadt.regionchooser.RegionChooserFX
\ No newline at end of file REM TODO: Update, similar to RegionChooser.sh
\ No newline at end of file
#!/bin/bash #!/bin/bash
cd "$(dirname "$0")" # set the current working directory to the directory this script is in if [[ -z "$1" ]]
java -d64 -classpath lib/*: -Xms512m -Xmx2g -Djava.util.logging.config.file=logging.properties eu.simstadt.regionchooser.RegionChooserFX then
echo No parameter, launching RegionChooser GUI
java -classpath 'lib/*' eu.simstadt.regionchooser.RegionChooserFX
else
echo Launching RegionChooserCLI "$@"
java -classpath 'lib/*' eu.simstadt.regionchooser.RegionChooserCLI "$@"
fi
\ No newline at end of file
#!/bin/bash #!/bin/bash
java -classpath 'lib/*' -Xms512m -Xmx2g -Djava.util.logging.config.file=logging.properties eu.simstadt.regionchooser.RegionChooserFX if [[ -z "$1" ]]
\ No newline at end of file then
>&2 echo No parameter, launching RegionChooser GUI
java -classpath 'lib/*' eu.simstadt.regionchooser.RegionChooserFX
else
>&2 echo Launching RegionChooserCLI "$@"
java -classpath 'lib/*' eu.simstadt.regionchooser.RegionChooserCLI "$@"
fi
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
/** /**
* Command Line Interface for RegionChooser. Could be useful to extract large regions on server, or automate the process * Command Line Interface for RegionChooser. Could be useful to extract large regions on server, or automate the process
* from batch/python scripts. * from batch/python scripts.
* *
*/ */
// Usage: region_chooser [-hlV] [-e=31467] -o=output.gml -w=polygon.wkt -i=input. // Usage: region_chooser [-hlV] [-e=31467] -o=output.gml -w=polygon.wkt -i=input.
...@@ -109,6 +109,7 @@ public Integer call() throws Exception { ...@@ -109,6 +109,7 @@ public Integer call() throws Exception {
logInfo("CityGML written to stdout."); logInfo("CityGML written to stdout.");
PrintWriter stdOut = spec.commandLine().getOut(); PrintWriter stdOut = spec.commandLine().getOut();
count = RegionExtractor.selectRegionDirectlyFromCityGML(wktPolygon, localCRS.toString(), stdOut, citygmls); count = RegionExtractor.selectRegionDirectlyFromCityGML(wktPolygon, localCRS.toString(), stdOut, citygmls);
stdOut.flush(); // To make sure the footer is written too.
} else { } else {
try (BufferedWriter gmlWriter = Files.newBufferedWriter(outputCityGML)) { try (BufferedWriter gmlWriter = Files.newBufferedWriter(outputCityGML)) {
count = RegionExtractor.selectRegionDirectlyFromCityGML(wktPolygon, localCRS.toString(), gmlWriter, count = RegionExtractor.selectRegionDirectlyFromCityGML(wktPolygon, localCRS.toString(), gmlWriter,
......
...@@ -32,13 +32,13 @@ ...@@ -32,13 +32,13 @@
* same coordinate system as the CityGML), it iterates over each Building and checks if the building is inside the * same coordinate system as the CityGML), it iterates over each Building and checks if the building is inside the
* geometry. It only works with CityGML files smaller than 2GB. It uses VTD-XML parser instead of a whole * geometry. It only works with CityGML files smaller than 2GB. It uses VTD-XML parser instead of a whole
* Simstadt/Citydoctor/Citygml model. * Simstadt/Citydoctor/Citygml model.
* *
* @param wktPolygon * @param wktPolygon
* @param srsName * @param srsName
* @param output * @param output
* @param citygmlPaths * @param citygmlPaths
* *
* *
* @writes the extracted Citygml, including header, buildings and footer to output * @writes the extracted Citygml, including header, buildings and footer to output
* @return counts of found building. * @return counts of found building.
* @throws ParseException * @throws ParseException
...@@ -88,6 +88,7 @@ static int selectRegionDirectlyFromCityGML(String wktPolygon, String srsName, Wr ...@@ -88,6 +88,7 @@ static int selectRegionDirectlyFromCityGML(String wktPolygon, String srsName, Wr
} }
LOGGER.info("Buildings found in selected region " + foundBuildingsCount); LOGGER.info("Buildings found in selected region " + foundBuildingsCount);
//NOTE: This could be a problem if header starts with <core:CityModel> and footer ends with </CityModel>
sb.append(citygml.getFooter()); sb.append(citygml.getFooter());
return foundBuildingsCount; return foundBuildingsCount;
} }
...@@ -99,7 +100,7 @@ static int selectRegionDirectlyFromCityGML(String wktPolygon, String srsName, Wr ...@@ -99,7 +100,7 @@ static int selectRegionDirectlyFromCityGML(String wktPolygon, String srsName, Wr
* from the extracting polygon. The real envelope might be even smaller, but it could only be known at the end of the * 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. If present, min and * parsing, after having analyzed every building. The envelope should be written in the header. If present, min and
* max values for Z are kept. * max values for Z are kept.
* *
* @param header * @param header
* @param envelope * @param envelope
* @param srsName * @param srsName
......
...@@ -25,6 +25,10 @@ ...@@ -25,6 +25,10 @@
{ {
private static final Logger LOGGER = Logger.getLogger(ConvexHullCalculator.class.getName()); private static final Logger LOGGER = Logger.getLogger(ConvexHullCalculator.class.getName());
private ConvexHullCalculator() {
throw new IllegalStateException("Utility class");
}
/** /**
* Relatively fast method to extract a convex hull in WGS84 for any Citygml file for which CRS is known and whose * Relatively fast method to extract a convex hull in WGS84 for any Citygml file for which CRS is known and whose
* size is less than 2GB (VTD XML limitation). It iterates over every building, gets the bounding box as 4 * size is less than 2GB (VTD XML limitation). It iterates over every building, gets the bounding box as 4
...@@ -92,7 +96,6 @@ public static void extractHullsForEveryCityGML(Path repository, Consumer<String> ...@@ -92,7 +96,6 @@ public static void extractHullsForEveryCityGML(Path repository, Consumer<String>
try { try {
Path kmlPath = getHullPath(repository, gmlPath); Path kmlPath = getHullPath(repository, gmlPath);
if (Files.exists(kmlPath)) { if (Files.exists(kmlPath)) {
//TODO: Check if size is the same as original. Recreate otherwise.
LOGGER.fine("Using cache from " + repository.relativize(kmlPath)); LOGGER.fine("Using cache from " + repository.relativize(kmlPath));
return new String(Files.readAllBytes(kmlPath), StandardCharsets.UTF_8); return new String(Files.readAllBytes(kmlPath), StandardCharsets.UTF_8);
} else { } else {
...@@ -101,8 +104,8 @@ public static void extractHullsForEveryCityGML(Path repository, Consumer<String> ...@@ -101,8 +104,8 @@ public static void extractHullsForEveryCityGML(Path repository, Consumer<String>
} }
} catch (IOException ex) { } catch (IOException ex) {
ex.printStackTrace(); ex.printStackTrace();
return null;
} }
return null;
}) })
.filter(Objects::nonNull) .filter(Objects::nonNull)
.forEach(hullKML -> { .forEach(hullKML -> {
...@@ -190,6 +193,9 @@ public static String calculateConvexHullPlacemark(Path gmlPath, Path kmlPath, bo ...@@ -190,6 +193,9 @@ public static String calculateConvexHullPlacemark(Path gmlPath, Path kmlPath, bo
* folder and hides it. The '.cache' folder isn't specific to the project: every kml cache file is written inside the * folder and hides it. The '.cache' folder isn't specific to the project: every kml cache file is written inside the
* same repository '.cache' folder. * same repository '.cache' folder.
* *
* The original CityGML filesize is written in KML basename, in order to update the hull if the CityGML file is
* modified, e.g. LoD2_564_5512_2_BY_11946489.kml
*
* @param repository * @param repository
* @param citygmlPath * @param citygmlPath
* *
...@@ -197,7 +203,8 @@ public static String calculateConvexHullPlacemark(Path gmlPath, Path kmlPath, bo ...@@ -197,7 +203,8 @@ public static String calculateConvexHullPlacemark(Path gmlPath, Path kmlPath, bo
* @throws IOException * @throws IOException
*/ */
private static Path getHullPath(Path repository, Path citygmlPath) throws IOException { private static Path getHullPath(Path repository, Path citygmlPath) throws IOException {
String kmlFilename = citygmlPath.getFileName().toString().replaceAll("(?i)\\.gml$", ".kml"); String kmlFilename = citygmlPath.getFileName().toString().replaceAll("(?i)\\.gml$",
"_" + Files.size(citygmlPath) + ".kml");
Path cacheFolder = repository.resolve(".cache/"); Path cacheFolder = repository.resolve(".cache/");
Path hullsFolder = cacheFolder.resolve("hulls/"); Path hullsFolder = cacheFolder.resolve("hulls/");
Files.createDirectories(hullsFolder); Files.createDirectories(hullsFolder);
......
...@@ -285,12 +285,17 @@ var regionChooser = (function(){ ...@@ -285,12 +285,17 @@ var regionChooser = (function(){
draw.setActive(false); draw.setActive(false);
}); });
// Pressing ESCAPE or DELETE resets the drawing.
// With OpenLayers 3.9, draw_interaction.removeLastPoint(); might be better. // With OpenLayers 3.9, draw_interaction.removeLastPoint(); might be better.
document.addEventListener('keydown', function(e) { document.addEventListener('keydown', function(e) {
if (e.which == 27 || e.which == 46){ //NOTE: e.key isn't defined in JavaFX Browser
if (e.which == 27 || e.which == 46){ // ESCAPE or DELETE.
resetDrawing(); resetDrawing();
} }
if (e.which == 116 && fromJavaFX){ // F5 for refresh
dataPanel.prepend("<h2 class='ok'>Refreshing repository...</h2><br/>\n");
document.documentElement.className = 'wait';
fxapp.refreshHulls();
}
}); });
function resetDrawing(){ function resetDrawing(){
......
...@@ -67,8 +67,9 @@ void testExtractRegionFromTwoCitygmls() throws IOException { ...@@ -67,8 +67,9 @@ void testExtractRegionFromTwoCitygmls() throws IOException {
wkt.write(wktPolygon); wkt.write(wktPolygon);
} }
assertFalse(Files.exists(outGML)); assertFalse(Files.exists(outGML));
new CommandLine(new RegionChooserCLI()).execute("--input=" + citygml1 + "," + citygml2, new CommandLine(new RegionChooserCLI()).execute("--input=" + citygml1 + "," + citygml2, "--output=" + outGML,
"--output=" + outGML, "--wkt=" + inWKT, "--epsg=31463", "--local"); "--wkt=" + inWKT, "--epsg=31463", "--local");
assertTrue(Files.exists(outGML)); assertTrue(Files.exists(outGML));
assertTrue(Files.size(outGML) > 600_000); assertTrue(Files.size(outGML) > 600_000);
assertEquals(20, countBuildings(outGML)); assertEquals(20, countBuildings(outGML));
...@@ -123,7 +124,8 @@ void testExtractRegionWithStandardInputAndStandardOutput() throws IOException { ...@@ -123,7 +124,8 @@ void testExtractRegionWithStandardInputAndStandardOutput() throws IOException {
assertTrue(err.toString().contains(expectedLog), err.toString() + " should contain " + expectedLog); assertTrue(err.toString().contains(expectedLog), err.toString() + " should contain " + expectedLog);
String expectedBuilding = "uuid_0547df65-ae80-459e-bb15-c839c1a2e566"; String expectedBuilding = "uuid_0547df65-ae80-459e-bb15-c839c1a2e566";
assertTrue(out.toString().contains(expectedBuilding), out.toString() + " should contain " + expectedBuilding); assertTrue(out.toString().contains(expectedBuilding), out.toString() + " should contain " + expectedBuilding);
//TODO: Check if footer is here too String expectedFooter = "</CityModel>";
assertTrue(out.toString().contains(expectedFooter), out.toString() + " should contain " + expectedFooter);
assertFalse(Files.exists(noOutput)); assertFalse(Files.exists(noOutput));
} }
......