missedFeatures = getMissedFeatures(futures);
- ImplicitGeometryHolder.clearMetaDataOfPrototypeGeometries();
+
if (!missedFeatures.isEmpty()){
logger.error(Localization.getText("Checker.dbUnresponsive"));
if (logger.isDebugEnabled()){
@@ -747,8 +741,22 @@ public class Checker {
}
}
+ /**
+ * Runs the validation on a list of Features. The checks are run asynchronously and multithreaded. Returns a list
+ * of {@link Future Futures} for evaluation if Features failed to be checked due to exceptions or failing to load from
+ * the cache. If failed, the respective Future will return the affected Feature's GmlID.
+ * Checks finding an error in a Feature, or not having their dependencies met, are not a check-failure in this
+ * context.
+ * @param exec the threadpool for the tasks
+ * @param cache the cache of the model
+ * @param ids the list of GmlIds to check
+ * @param checkedCount the number of already checked Features for tracking the total progress of validation across retries
+ * @param l a listener for the progress of the validation, can be null
+ * @return a list of Futures containing the GmlId of Features that failed to execute all checks, and contain null otherwise
+ * @throws InterruptedException if interrupted while invoking the tasks for checking
+ */
private List> runChecksOnFeatures(ExecutorService exec, CityObjectCache cache, List ids, AtomicInteger checkedCount,
- ProgressListener l)
+ @Nullable ProgressListener l)
throws InterruptedException {
float featureSum = ids.size() + (float) checkedCount.get();
@@ -762,11 +770,9 @@ public class Checker {
}
if(Thread.interrupted()){
Thread.currentThread().interrupt();
- return null;
+ return id;
}
- co.prepareForChecking();
executeChecksForCityObject(co);
- co.clearMetaInformation();
cache.put(co);
checkedCount.incrementAndGet();
if (l!=null){
@@ -781,7 +787,7 @@ public class Checker {
private List getMissedFeatures(List> futures) throws InterruptedException{
List missedList = new ArrayList<>();
- Set errors = new HashSet<>();
+ Set errors = new HashSet<>();
for (Future future : futures) {
try{
GmlId gmlId = future.get();
@@ -791,7 +797,7 @@ public class Checker {
} catch (ExecutionException e){
logger.debug("A Task failed due to an unexpected exception", e);
logger.debug(e.getCause());
- errors.add(e);
+ errors.add(e.getCause().toString());
}
}
if (!errors.isEmpty()) {
@@ -839,7 +845,9 @@ public class Checker {
if (!filterObject(co)) {
return;
}
+ co.prepareForChecking();
executeChecksForCheckable(co);
+ co.clearMetaInformation();
}
/**
@@ -938,7 +946,7 @@ public class Checker {
SvrlContentHandler handler = executeSchematronValidationIfAvailable(config, inputFile);
CityGmlConsumer con = new StreamCityGmlConsumer(c, xmlReporter, pdfReporter, handler, config, l);
// parse and validate
- CityGmlParser.streamCityGml(inputFile.getAbsolutePath(), config.getParserConfiguration(), con, outputFile);
+ CityGmlParser.streamCityGml(inputFile, config.getParserConfiguration(), con, outputFile);
// write reports if available
writeReport(xmlReporter);
diff --git a/CityDoctorParent/CityDoctorValidation/src/main/java/de/hft/stuttgart/citydoctor2/checks/util/CollectionUtils.java b/CityDoctorParent/CityDoctorValidation/src/main/java/de/hft/stuttgart/citydoctor2/checks/util/CollectionUtils.java
index cdbe4667f80817a29e9b36460c8bbbfd94ba4c67..b6987c9be72debadab354fc25bff3217701a5239 100644
--- a/CityDoctorParent/CityDoctorValidation/src/main/java/de/hft/stuttgart/citydoctor2/checks/util/CollectionUtils.java
+++ b/CityDoctorParent/CityDoctorValidation/src/main/java/de/hft/stuttgart/citydoctor2/checks/util/CollectionUtils.java
@@ -20,7 +20,9 @@ package de.hft.stuttgart.citydoctor2.checks.util;
import java.util.Arrays;
import java.util.HashSet;
+import java.util.List;
import java.util.Set;
+import java.util.stream.IntStream;
public class CollectionUtils {
@@ -40,4 +42,11 @@ public class CollectionUtils {
return set;
}
+ public static List> partition(List list, int chunkSize){
+ return IntStream.iterate(0, i-> i < list.size(), i-> i+ chunkSize)
+ .mapToObj(i -> list.subList(i, Math.min(i+chunkSize, list.size())))
+ .toList();
+
+ }
+
}
diff --git a/CityDoctorParent/Extensions/CityDoctorAutoPro/pom.xml b/CityDoctorParent/Extensions/CityDoctorAutoPro/pom.xml
index 5c148498917e4946c5442cd558c1e9a11651ea21..a50ad983fd7744a69911de1d8ac2fb35b976c6c4 100644
--- a/CityDoctorParent/Extensions/CityDoctorAutoPro/pom.xml
+++ b/CityDoctorParent/Extensions/CityDoctorAutoPro/pom.xml
@@ -6,7 +6,7 @@
de.hft.stuttgart
CityDoctorParent
- 3.18.1
+ 3.18.2
../../pom.xml
CityDoctorAutoPro
diff --git a/CityDoctorParent/Extensions/CityDoctorGUI/pom.xml b/CityDoctorParent/Extensions/CityDoctorGUI/pom.xml
index 96ca688805d727146643f86cb4fb4c960384f2f5..233c78343e5432c95d2300163e0b2cf23c99be58 100644
--- a/CityDoctorParent/Extensions/CityDoctorGUI/pom.xml
+++ b/CityDoctorParent/Extensions/CityDoctorGUI/pom.xml
@@ -6,7 +6,7 @@
de.hft.stuttgart
CityDoctorParent
- 3.18.1
+ 3.18.2
../../pom.xml
CityDoctorGUI
diff --git a/CityDoctorParent/Extensions/CityDoctorGUI/src/main/java/de/hft/stuttgart/citydoctor2/gui/CheckDialog.java b/CityDoctorParent/Extensions/CityDoctorGUI/src/main/java/de/hft/stuttgart/citydoctor2/gui/CheckDialog.java
index edc94a4c3c7f2ef6b58438f630aa135a5a19eb8e..578280c9921e4590d7ca5736f31259a8222cbfb8 100644
--- a/CityDoctorParent/Extensions/CityDoctorGUI/src/main/java/de/hft/stuttgart/citydoctor2/gui/CheckDialog.java
+++ b/CityDoctorParent/Extensions/CityDoctorGUI/src/main/java/de/hft/stuttgart/citydoctor2/gui/CheckDialog.java
@@ -1,8 +1,11 @@
package de.hft.stuttgart.citydoctor2.gui;
+import java.awt.*;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
+import java.net.URI;
+import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
@@ -10,6 +13,12 @@ import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
+import javafx.scene.control.Alert;
+import javafx.scene.control.ButtonType;
+import javafx.scene.control.Hyperlink;
+import javafx.scene.control.Tooltip;
+import javafx.scene.input.Clipboard;
+import javafx.scene.input.ClipboardContent;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@@ -112,6 +121,18 @@ public class CheckDialog {
@FXML
private Button selectBtn;
+ @FXML
+ private Button selectAllGCBtn;
+
+ @FXML
+ private Button selectNoneGCBtn;
+
+ @FXML
+ private Button selectAllSCBtn;
+
+ @FXML
+ private Button selectNoneSCBtn;
+
@FXML
private TextField schematronField;
@@ -133,6 +154,12 @@ public class CheckDialog {
@FXML
private Label schematronFileLabel;
+ @FXML
+ private Label checkDescriptionsLabel;
+
+ @FXML
+ private Hyperlink homepageHyperlink;
+
@FXML
private CheckBox streamCheckOption;
@FXML
@@ -153,6 +180,7 @@ public class CheckDialog {
private CityDoctorController controller;
private FilterPane filterPane;
private MainWindow window;
+ private IndeterminateSpinnerDialog waitingDialog;
public CheckDialog(MainWindow window, Window parent, CityDoctorController controller) throws IOException {
this.window = window;
@@ -190,9 +218,15 @@ public class CheckDialog {
geometricChecksLabel.setText(Localization.getText("CheckDialog.geometricChecksLabel"));
semanticChecksLabel.setText(Localization.getText("CheckDialog.semanticChecksLabel"));
schematronFileLabel.setText(Localization.getText("CheckDialog.schematronFileLabel"));
+ checkDescriptionsLabel.setText(Localization.getText("CheckDialog.checkDescriptionsLabel"));
+ homepageHyperlink.setText(Localization.getText("CheckDialog.clickHereToOpen"));
selectBtn.setText(Localization.getText("CheckDialog.selectBtn"));
checkBtn.setText(Localization.getText("CheckDialog.checkBtn"));
cancelBtn.setText(Localization.getText("CheckDialog.cancelBtn"));
+ selectAllGCBtn.setText(Localization.getText("CheckDialog.selectAllChecksBtn"));
+ selectNoneGCBtn.setText(Localization.getText("CheckDialog.unselectAllChecksBtn"));
+ selectAllSCBtn.setText(Localization.getText("CheckDialog.selectAllChecksBtn"));
+ selectNoneSCBtn.setText(Localization.getText("CheckDialog.unselectAllChecksBtn"));
List> columns = globalParametersTable.getColumns();
TableColumn nameCol = new TableColumn<>(NAME);
@@ -258,7 +292,51 @@ public class CheckDialog {
// failed to read config, ignore as default values are still available
}
}
- }
+
+ selectAllGCBtn.setOnAction(ae ->
+ geometricTable.getRoot().getChildren().forEach(item -> item.getValue().setEnabled(true)));
+
+ selectNoneGCBtn.setOnAction(ae ->
+ geometricTable.getRoot().getChildren().forEach(item -> item.getValue().setEnabled(false)));
+
+ selectAllSCBtn.setOnAction(ae ->
+ semanticTable.getRoot().getChildren().forEach(item -> item.getValue().setEnabled(true)));
+
+ selectNoneSCBtn.setOnAction(ae ->
+ semanticTable.getRoot().getChildren().forEach(item -> item.getValue().setEnabled(false)));
+
+ try {
+ homepageHyperlink.setTooltip(new Tooltip(Localization.getText("CheckDialog.homepageHyperlink")));
+ final URI hpUrl = new URI(Localization.getText("CheckDialog.homepageHyperlink"));
+ homepageHyperlink.setOnAction(event -> {
+ try {
+ Desktop.getDesktop().browse(hpUrl);
+ } catch (IOException e) {
+ homepageHyperlink.setText("[Hyperlink blocked]");
+ Alert alert = new Alert(Alert.AlertType.ERROR,
+ "Opening of hyperlink was blocked by the system, URL has been copied to Clipboard",
+ ButtonType.OK);
+ Clipboard cb = Clipboard.getSystemClipboard();
+ ClipboardContent content = new ClipboardContent();
+ content.putString(hpUrl.toString());
+ cb.setContent(content);
+ alert.showAndWait();
+ }
+ });
+ } catch (URISyntaxException e) {
+ //Should never actually occur
+ homepageHyperlink.setText("[Hyperlink missing/invalid]");
+ }
+
+ try{
+ waitingDialog = new IndeterminateSpinnerDialog(window.getMainStage(),"Schematron still running, please wait");
+ } catch (IOException e) {
+ logger.error("Failed to load IndeterminateSpinnerDialog");
+ }
+
+
+ }
+
private void setupValueColumns(List> columns) {
TableColumn valueCol = new TableColumn<>(VALUE);
@@ -462,7 +540,12 @@ public class CheckDialog {
ProgressListener l = new ProgressListener() {
@Override
public void updateProgress(float state) {
- Platform.runLater(() -> progress.setProgress(state));
+ Platform.runLater(() -> {
+ progress.setProgress(state);
+ if (state < 0 ){
+ waitingDialog.show();
+ }
+ });
}
};
controller.startChecks(config, l);
@@ -484,6 +567,7 @@ public class CheckDialog {
Platform.runLater(() -> {
checkBtn.setDisable(false);
cancelBtn.setDisable(false);
+ waitingDialog.hide();
stage.setOnCloseRequest(null);
stage.close();
});
diff --git a/CityDoctorParent/Extensions/CityDoctorGUI/src/main/java/de/hft/stuttgart/citydoctor2/gui/CityDoctorController.java b/CityDoctorParent/Extensions/CityDoctorGUI/src/main/java/de/hft/stuttgart/citydoctor2/gui/CityDoctorController.java
index c01bc3d7f33222edcfdea3e0c6b342c937b8a4c1..57849884f35d68170f26d2d4ea5c580719ac3212 100644
--- a/CityDoctorParent/Extensions/CityDoctorGUI/src/main/java/de/hft/stuttgart/citydoctor2/gui/CityDoctorController.java
+++ b/CityDoctorParent/Extensions/CityDoctorGUI/src/main/java/de/hft/stuttgart/citydoctor2/gui/CityDoctorController.java
@@ -1379,7 +1379,9 @@ public class CityDoctorController {
if (model == null) {
return;
}
- buildTrees();
+ mainWindow.rebuildErrorFilterTrees();
+
+// buildTrees();
}
public Series createErrorSeries() {
@@ -1414,7 +1416,8 @@ public class CityDoctorController {
List idList = model.getBuildingIds();
foundBuildings.removeIf(gmlId -> (!idList.contains(gmlId)));
- Supplier> supply = () -> model.getCache().getStream(foundBuildings).map(co -> (Building) co);
+ //Supplier> supply = () -> model.getCache().getStream(foundBuildings).map(co -> (Building) co);
+ Supplier> supply = () -> model.getCache().getAll(foundBuildings).stream().map(co -> (Building) co);
buildBuildingTreeFromList(supply, root);
updateTree(root);
addMoreButtonForBuildings(buildingsView, root, buildingChunkNr, supply, foundBuildings.size());
@@ -1659,6 +1662,8 @@ public class CityDoctorController {
public void errorFilterIndexChanged(Number newV) {
mainWindow.getMeshGroup().getChildren().clear();
mainWindow.unselectEverything();
+ mainWindow.resetSearchBar();
+ renderer.clearCurrentRender();
if (newV.intValue() == 0) { // Error filter was set to "All"
buildTrees();
updateFeatureTrees();
diff --git a/CityDoctorParent/Extensions/CityDoctorGUI/src/main/java/de/hft/stuttgart/citydoctor2/gui/IndeterminateSpinnerDialog.java b/CityDoctorParent/Extensions/CityDoctorGUI/src/main/java/de/hft/stuttgart/citydoctor2/gui/IndeterminateSpinnerDialog.java
new file mode 100644
index 0000000000000000000000000000000000000000..7dc87fe12d4c3d35a151f7ba8aca37161cdfad38
--- /dev/null
+++ b/CityDoctorParent/Extensions/CityDoctorGUI/src/main/java/de/hft/stuttgart/citydoctor2/gui/IndeterminateSpinnerDialog.java
@@ -0,0 +1,51 @@
+package de.hft.stuttgart.citydoctor2.gui;
+
+import javafx.fxml.FXML;
+import javafx.fxml.FXMLLoader;
+import javafx.scene.Scene;
+import javafx.scene.control.Label;
+import javafx.scene.layout.VBox;
+import javafx.stage.Modality;
+import javafx.stage.Stage;
+import javafx.stage.StageStyle;
+import javafx.stage.Window;
+
+import java.io.IOException;
+
+public class IndeterminateSpinnerDialog {
+
+ private Stage stage;
+
+ @FXML
+ private Label messageLbl;
+
+ public IndeterminateSpinnerDialog(Window parent, String message) throws IOException {
+ FXMLLoader loader = new FXMLLoader(LoadingInfoDialog.class.getResource("IndeterminateSpinnerDialog.fxml"));
+ loader.setController(this);
+ VBox box = loader.load();
+
+ stage = new Stage(StageStyle.UNDECORATED);
+ Scene scene = new Scene(box);
+ scene.setFill(null);
+ stage.setScene(scene);
+ stage.initOwner(parent);
+ stage.initModality(Modality.APPLICATION_MODAL);
+ messageLbl.setText(message);
+ }
+
+ public void changeMessage(String message){
+ messageLbl.setText(message);
+ }
+
+
+ public void show() {
+ stage.show();
+ }
+
+ public void hide() {
+ stage.hide();
+ }
+
+}
+
+
diff --git a/CityDoctorParent/Extensions/CityDoctorGUI/src/main/java/de/hft/stuttgart/citydoctor2/gui/MainWindow.java b/CityDoctorParent/Extensions/CityDoctorGUI/src/main/java/de/hft/stuttgart/citydoctor2/gui/MainWindow.java
index 1ca7c4f094dba008369d522c0f6777234a7617c2..736cdafd5333862a869f392344d01220b4469892 100644
--- a/CityDoctorParent/Extensions/CityDoctorGUI/src/main/java/de/hft/stuttgart/citydoctor2/gui/MainWindow.java
+++ b/CityDoctorParent/Extensions/CityDoctorGUI/src/main/java/de/hft/stuttgart/citydoctor2/gui/MainWindow.java
@@ -592,6 +592,10 @@ public class MainWindow extends Application {
showCityObjectsCombo.getSelectionModel().selectedIndexProperty().addListener(filterChangeListener);
}
+ public void rebuildErrorFilterTrees(){
+ controller.errorFilterIndexChanged(showCityObjectsCombo.getSelectionModel().getSelectedIndex());
+ }
+
private ChangeListener setupFilterSelectionListener() {
return (obs, oldV, newV) -> controller.errorFilterIndexChanged(newV);
}
diff --git a/CityDoctorParent/Extensions/CityDoctorGUI/src/main/resources/de/hft/stuttgart/citydoctor2/gui/CheckDialog.fxml b/CityDoctorParent/Extensions/CityDoctorGUI/src/main/resources/de/hft/stuttgart/citydoctor2/gui/CheckDialog.fxml
index e0924a244fe035c2460abb84e1d48a4a7ba8c0d5..d98412615274cd9868ff6ad2922b320ee5613b93 100644
--- a/CityDoctorParent/Extensions/CityDoctorGUI/src/main/resources/de/hft/stuttgart/citydoctor2/gui/CheckDialog.fxml
+++ b/CityDoctorParent/Extensions/CityDoctorGUI/src/main/resources/de/hft/stuttgart/citydoctor2/gui/CheckDialog.fxml
@@ -2,6 +2,7 @@
+
@@ -60,6 +61,15 @@
+
+
@@ -71,6 +81,16 @@
+
+
+
+
+
+
@@ -81,6 +101,16 @@
+
+
+
+
+
+
diff --git a/CityDoctorParent/Extensions/CityDoctorGUI/src/main/resources/de/hft/stuttgart/citydoctor2/gui/IndeterminateSpinnerDialog.fxml b/CityDoctorParent/Extensions/CityDoctorGUI/src/main/resources/de/hft/stuttgart/citydoctor2/gui/IndeterminateSpinnerDialog.fxml
new file mode 100644
index 0000000000000000000000000000000000000000..c9650b629f77436cd1c2b44fc3d72c6d1beb1902
--- /dev/null
+++ b/CityDoctorParent/Extensions/CityDoctorGUI/src/main/resources/de/hft/stuttgart/citydoctor2/gui/IndeterminateSpinnerDialog.fxml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/CityDoctorParent/Extensions/CityDoctorHealer/pom.xml b/CityDoctorParent/Extensions/CityDoctorHealer/pom.xml
index 6076712be924666b5d72e9ccd3b3f17ce61aade3..ee969799a96ee5d5da1bef8c95b367b8011e3052 100644
--- a/CityDoctorParent/Extensions/CityDoctorHealer/pom.xml
+++ b/CityDoctorParent/Extensions/CityDoctorHealer/pom.xml
@@ -6,7 +6,7 @@
de.hft.stuttgart
CityDoctorParent
- 3.18.1
+ 3.18.2
../../pom.xml
CityDoctorHealer
diff --git a/CityDoctorParent/Extensions/CityDoctorHealer/src/main/java/de/hft/stuttgart/citydoctor2/connect/edge/CppTest.java b/CityDoctorParent/Extensions/CityDoctorHealer/src/main/java/de/hft/stuttgart/citydoctor2/connect/edge/CppTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..a7d600420825db6a1868b8f37760d76eff6d7467
--- /dev/null
+++ b/CityDoctorParent/Extensions/CityDoctorHealer/src/main/java/de/hft/stuttgart/citydoctor2/connect/edge/CppTest.java
@@ -0,0 +1,8 @@
+package de.hft.stuttgart.citydoctor2.connect.edge;
+
+/**
+ * Marker interface for excluding testcases that use the deprecated connection to the C++ library.
+ * The tests are kept for the Java replacement library that is currently being developed.
+ */
+public interface CppTest {
+}
diff --git a/CityDoctorParent/Extensions/CityDoctorHealer/src/main/java/de/hft/stuttgart/citydoctor2/healer/Healer.java b/CityDoctorParent/Extensions/CityDoctorHealer/src/main/java/de/hft/stuttgart/citydoctor2/healer/Healer.java
index 06be694b7b8aa39f91f02cfa82c54101ad104773..f6b3c068fadf3078ceeafa26167a7ad9a86ea432 100644
--- a/CityDoctorParent/Extensions/CityDoctorHealer/src/main/java/de/hft/stuttgart/citydoctor2/healer/Healer.java
+++ b/CityDoctorParent/Extensions/CityDoctorHealer/src/main/java/de/hft/stuttgart/citydoctor2/healer/Healer.java
@@ -12,6 +12,9 @@ import java.util.List;
import java.util.Map;
import java.util.Objects;
+import de.hft.stuttgart.citydoctor2.database.CityObjectCache;
+import de.hft.stuttgart.citydoctor2.database.UnconnectedCache;
+import de.hft.stuttgart.citydoctor2.exceptions.CityObjectCacheException;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.citygml4j.core.ade.ADEException;
@@ -64,7 +67,7 @@ public class Healer {
private Checker checker;
private ModificationListener l;
private HealingPlan plan;
-
+ private CityObjectCache cache;
static {
// CppInitializer.initCpp();
}
@@ -187,6 +190,12 @@ public class Healer {
}
};
}
+ if(checker.getModel() != null){
+ cache = checker.getModel().getCache();
+ } else {
+ //Stream healing is being used, use an unconnected cache
+ cache = new UnconnectedCache();
+ }
this.l = l;
}
@@ -208,7 +217,12 @@ public class Healer {
}
public void healModel(CityDoctorModel model) {
- model.createFeatureStream().forEach(this::healCityObject);
+ try (AutoCloseable checkingContext = model.getCache().startCheckingMode()){
+ model.createFeatureStream().forEach(this::healCityObject);
+ } catch (Exception e) {
+ throw new CityObjectCacheException("Healer critically failed during attempt to heal the model",e);
+ }
+
}
public void healCityObject(CityObject co) {
@@ -282,9 +296,7 @@ public class Healer {
*
* @param aco the feature to write
* @return the byte array containing the feature
- * @throws ADEException
- * @throws CityGMLBuilderException
- * @throws CityGMLWriteException
+ * @throws CityGMLWriteException if writing of the CityGML file fails
*/
private byte[] writeCityGml(AbstractCityObject aco) throws CityGMLWriteException {
CityModel model = new CityModel();
@@ -348,6 +360,8 @@ public class Healer {
if (checker.getConfig().getParserConfiguration().useLowMemoryConsumption()) {
co.clearMetaInformation();
}
+ //Reinsert object into cache and release locks
+ cache.put(co);
}
}
diff --git a/CityDoctorParent/Extensions/CityDoctorHealer/src/main/resources/log4j2.xml b/CityDoctorParent/Extensions/CityDoctorHealer/src/main/resources/log4j2.xml
new file mode 100644
index 0000000000000000000000000000000000000000..1b1a09f31c1dea7e13e9f9a70aa5b80703e4a8d0
--- /dev/null
+++ b/CityDoctorParent/Extensions/CityDoctorHealer/src/main/resources/log4j2.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/CityDoctorParent/Extensions/CityDoctorHealer/src/test/java/de/hft/stuttgart/citydoctor2/healing/HealMissingSolidTest.java b/CityDoctorParent/Extensions/CityDoctorHealer/src/test/java/de/hft/stuttgart/citydoctor2/healing/HealMissingSolidTest.java
index 07adf8c1e520aaaa8d5595768de7217957f5a7c1..5ee9be12da054ac17f3003bce7ebd5cd81bc6c9d 100644
--- a/CityDoctorParent/Extensions/CityDoctorHealer/src/test/java/de/hft/stuttgart/citydoctor2/healing/HealMissingSolidTest.java
+++ b/CityDoctorParent/Extensions/CityDoctorHealer/src/test/java/de/hft/stuttgart/citydoctor2/healing/HealMissingSolidTest.java
@@ -29,6 +29,8 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
+import de.hft.stuttgart.citydoctor2.database.UnconnectedCache;
+import org.citygml4j.core.model.CityGMLVersion;
import org.citygml4j.core.model.core.AbstractThematicSurface;
import org.citygml4j.core.model.core.CityModel;
import org.junit.Rule;
@@ -70,7 +72,8 @@ public class HealMissingSolidTest {
@Test
public void testCreateSolid() throws CityDoctorWriteException, IOException, CityGmlParseException, InvalidGmlFileException {
ValidationConfiguration config = ValidationConfiguration.loadStandardValidationConfig();
- CityDoctorModel model = new CityDoctorModel(config.getParserConfiguration(), new File("test"));
+ CityDoctorModel model = new CityDoctorModel(config.getParserConfiguration(), new File("test"), new UnconnectedCache());
+ model.setParsedCityGMLVersion(CityGMLVersion.v3_0);
model.setCityModel(new CityModel());
Building b = new Building();
model.addBuilding(b);
diff --git a/CityDoctorParent/Extensions/CityDoctorHealer/src/test/java/de/hft/stuttgart/citydoctor2/healing/HealPlanarPolygonErrorTest.java b/CityDoctorParent/Extensions/CityDoctorHealer/src/test/java/de/hft/stuttgart/citydoctor2/healing/HealPlanarPolygonErrorTest.java
index 5359f2d6b1164dc4aff26c8f216c4e83f4706474..a0697423a241eea22cd3fb333017c2bab8ca728e 100644
--- a/CityDoctorParent/Extensions/CityDoctorHealer/src/test/java/de/hft/stuttgart/citydoctor2/healing/HealPlanarPolygonErrorTest.java
+++ b/CityDoctorParent/Extensions/CityDoctorHealer/src/test/java/de/hft/stuttgart/citydoctor2/healing/HealPlanarPolygonErrorTest.java
@@ -7,6 +7,7 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
+import de.hft.stuttgart.citydoctor2.connect.edge.CppTest;
import org.junit.Assert;
import org.junit.Test;
@@ -31,6 +32,7 @@ import de.hft.stuttgart.citydoctor2.datastructure.Geometry.Orientation;
import de.hft.stuttgart.citydoctor2.healer.Healer;
import de.hft.stuttgart.citydoctor2.parser.CityGmlParseException;
import de.hft.stuttgart.citydoctor2.parser.InvalidGmlFileException;
+import org.junit.experimental.categories.Category;
public class HealPlanarPolygonErrorTest {
@@ -47,14 +49,14 @@ public class HealPlanarPolygonErrorTest {
Assert.assertTrue(geom.containsError(CheckId.C_GE_P_NON_PLANAR));
Healer healer = new Healer(c);
- healer.setNumberOfIterations(2);
healer.healCityObject(model.getBuildings().toList().get(0));
Assert.assertFalse(geom.containsError(CheckId.C_GE_P_NON_PLANAR));
}
-
+
@Test
+ @Category(CppTest.class)
public void testNonplanarPolygon() {
CppInitializer.initCpp();
Building b = new Building();
@@ -160,6 +162,7 @@ public class HealPlanarPolygonErrorTest {
}
@Test
+ @Category(CppTest.class)
public void testNonplanarPolygon_Split() {
CppInitializer.initCpp();
Building b = new Building();
@@ -274,6 +277,7 @@ public class HealPlanarPolygonErrorTest {
}
@Test
+ @Category(CppTest.class)
public void testNonplanarPolygon_Split2() {
CppInitializer.initCpp();
Building b = new Building();
diff --git a/CityDoctorParent/Extensions/CityDoctorHealer/src/test/java/de/hft/stuttgart/citydoctor2/healing/HealSolidNotClosedErrorTest.java b/CityDoctorParent/Extensions/CityDoctorHealer/src/test/java/de/hft/stuttgart/citydoctor2/healing/HealSolidNotClosedErrorTest.java
index 06e4d9e1f09b6991bdfff09db9446ca748092181..b577700d22588dddf2e5f9defab1e9f22ee2a876 100644
--- a/CityDoctorParent/Extensions/CityDoctorHealer/src/test/java/de/hft/stuttgart/citydoctor2/healing/HealSolidNotClosedErrorTest.java
+++ b/CityDoctorParent/Extensions/CityDoctorHealer/src/test/java/de/hft/stuttgart/citydoctor2/healing/HealSolidNotClosedErrorTest.java
@@ -4,8 +4,11 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
+import java.io.File;
import java.io.IOException;
+import java.nio.file.Path;
+import de.hft.stuttgart.citydoctor2.connect.edge.CppTest;
import org.citygml4j.xml.writer.CityGMLWriteException;
import org.junit.Assert;
import org.junit.Test;
@@ -33,13 +36,16 @@ import de.hft.stuttgart.citydoctor2.datastructure.Geometry.Orientation;
import de.hft.stuttgart.citydoctor2.healer.Healer;
import de.hft.stuttgart.citydoctor2.parser.CityGmlParseException;
import de.hft.stuttgart.citydoctor2.parser.InvalidGmlFileException;
+import org.junit.experimental.categories.Category;
public class HealSolidNotClosedErrorTest {
+
/**
* One polygon is split up in 3 but has not matching edges
- */
+ */
@Test
+ @Category(CppTest.class)
public void testVertexCloseToEdge() {
CppInitializer.initCpp();
Building b = new Building(); //Angelika: als Test eingefügt
@@ -164,6 +170,7 @@ public class HealSolidNotClosedErrorTest {
}
@Test
+ @Category(CppTest.class)
public void testMissingPolygon() {
CppInitializer.initCpp();
Building b = new Building();
@@ -343,6 +350,7 @@ public class HealSolidNotClosedErrorTest {
}
@Test
+ @Category(CppTest.class)
public void test2MissingPolygonsCpp() {
CppInitializer.initCpp();
Building b = new Building();
@@ -420,7 +428,9 @@ public class HealSolidNotClosedErrorTest {
assertNotNull(cr);
assertEquals(ResultStatus.OK, cr.getResultStatus());
}
-
+
+
+
/**
* Missing Polygon has a self intersection
* @throws IOException
@@ -431,24 +441,22 @@ public class HealSolidNotClosedErrorTest {
*/
@Test
public void testMissingPolygon2() throws CityGmlParseException, IOException, InvalidGmlFileException {
- String path = "src/test/resources/SimpleSolid_SrefBS-GE-gml-SO-0002-T0002.gml"; //bei diesem Modell stürzt die VM ab
+// String path = "src/test/resources/SimpleSolid_SrefBS-GE-gml-SO-0002-T0002.gml"; //bei diesem Modell stürzt die VM ab
// String path = "src/test/resources/SimpleSolid_SrefBS-GE-gml-SO-0002-T0001.gml"; //hier nur Fehlermeldung
+ String path = "src/test/resources/SimpleSolid_SrefBS-GE-gml-LR-0004-T0005.gml";
+// String path = "src/test/resources/SimpleSolid_SrefBS.gml";
ValidationConfiguration config = ValidationConfiguration.loadStandardValidationConfig();
CityDoctorModel model = TestUtil.loadCityModel(path, config);
+
Checker c = new Checker(config, model);
c.runChecks();
Geometry geom = model.getBuildings().toList().get(0).getGeometries().get(0);
- geom.updateVertices();
- for (Vertex v : geom.getVertices()) {
- v.setX(v.getX() - 10);
- v.setY(v.getY() - 10);
- }
Assert.assertTrue(geom.containsError(CheckId.C_GE_S_NOT_CLOSED));
Healer healer = new Healer(c);
- //healer.setNumberOfIterations(2);
+ healer.setNumberOfIterations(2);
healer.healCityObject(model.getBuildings().toList().get(0));
Assert.assertFalse(geom.containsError(CheckId.C_GE_S_NOT_CLOSED));
diff --git a/CityDoctorParent/Extensions/CityDoctorHealer/src/test/java/de/hft/stuttgart/citydoctor2/healing/TestHealer.java b/CityDoctorParent/Extensions/CityDoctorHealer/src/test/java/de/hft/stuttgart/citydoctor2/healing/TestHealer.java
index 63ccbd0519033df305c12372b7eff5a7f53b3391..46910bf28f2d4a57bf23c4c5611265e41a04c6ae 100644
--- a/CityDoctorParent/Extensions/CityDoctorHealer/src/test/java/de/hft/stuttgart/citydoctor2/healing/TestHealer.java
+++ b/CityDoctorParent/Extensions/CityDoctorHealer/src/test/java/de/hft/stuttgart/citydoctor2/healing/TestHealer.java
@@ -150,15 +150,14 @@ public class TestHealer {
Checker c = new Checker(config, model);
c.runChecks();
-
- Geometry geom = model.getBuildings().toList().get(0).getGeometries().get(0);
+ Building b = model.getBuildings().toList().get(0);
+ Geometry geom = b.getGeometries().get(0);
Healer healer = new Healer(c);
- healer.setNumberOfIterations(33);
- healer.healCityObject(model.getBuildings().toList().get(0));
+ healer.healCityObject(b);
c.runChecks();
-
assertFalse(geom.containsAnyError());
+
}
@Test
@@ -193,7 +192,6 @@ public class TestHealer {
Geometry geom = model.getBuildings().toList().get(0).getGeometries().get(0);
Healer healer = new Healer(c);
- healer.setNumberOfIterations(83);
healer.healCityObject(model.getBuildings().toList().get(0));
c.runChecks();
@@ -213,7 +211,6 @@ public class TestHealer {
Geometry geom = model.getBuildings().toList().get(0).getGeometries().get(0);
Healer healer = new Healer(c);
- healer.setNumberOfIterations(165);
healer.healCityObject(model.getBuildings().toList().get(0));
c.runChecks();
@@ -264,7 +261,6 @@ public class TestHealer {
Geometry geom = model.getBuildings().toList().get(0).getGeometries().get(0);
Healer healer = new Healer(c);
- healer.setNumberOfIterations(45);
healer.healCityObject(model.getBuildings().toList().get(0));
c.runChecks();
@@ -282,7 +278,6 @@ public class TestHealer {
Healer healer = new Healer(c);
- healer.setNumberOfIterations(45);
healer.healModel(model);
}
@@ -299,7 +294,7 @@ public class TestHealer {
Geometry geom = model.getBuildings().toList().get(0).getGeometries().get(0);
Healer healer = new Healer(c);
- healer.setNumberOfIterations(100);
+
healer.healCityObject(model.getBuildings().toList().get(0));
c.runChecks();
diff --git a/CityDoctorParent/Extensions/CityDoctorHealer/src/test/java/de/hft/stuttgart/citydoctor2/healing/TestUtil.java b/CityDoctorParent/Extensions/CityDoctorHealer/src/test/java/de/hft/stuttgart/citydoctor2/healing/TestUtil.java
index 72a2450f86cbed1d2e6adc7eab79028e8d84d332..cfc8063bf326fda94b292c2864e4fc1f67dcd237 100644
--- a/CityDoctorParent/Extensions/CityDoctorHealer/src/test/java/de/hft/stuttgart/citydoctor2/healing/TestUtil.java
+++ b/CityDoctorParent/Extensions/CityDoctorHealer/src/test/java/de/hft/stuttgart/citydoctor2/healing/TestUtil.java
@@ -31,7 +31,7 @@ public class TestUtil {
}
public static CityDoctorModel loadCityModel(String path, ValidationConfiguration config) throws CityGmlParseException, IOException, InvalidGmlFileException {
- return CityGmlParser.parseCityGmlFile(path, config.getParserConfiguration());
+ return CityGmlParser.nestedCityGmlFileParse(path, config.getParserConfiguration());
}
public static Polygon getPolygonById(String gmlId, CityDoctorModel model) {
diff --git a/CityDoctorParent/Extensions/CityDoctorHealerGUI/pom.xml b/CityDoctorParent/Extensions/CityDoctorHealerGUI/pom.xml
index c75ed10f010fee109c4e530485cbe7cf75a77777..04a0807e378bcfe911e641c4befb01fcbeee7fca 100644
--- a/CityDoctorParent/Extensions/CityDoctorHealerGUI/pom.xml
+++ b/CityDoctorParent/Extensions/CityDoctorHealerGUI/pom.xml
@@ -7,7 +7,7 @@
de.hft.stuttgart
CityDoctorParent
- 3.18.1
+ 3.18.2
../../pom.xml
CityDoctorHealerGUI
diff --git a/CityDoctorParent/Extensions/CityDoctorHealerGUI/src/main/java/de/hft/stuttgart/citydoctor2/healer/gui/HealerController.java b/CityDoctorParent/Extensions/CityDoctorHealerGUI/src/main/java/de/hft/stuttgart/citydoctor2/healer/gui/HealerController.java
index f495692cf84c7d9144b7ef3f22e8856237ff8bf7..31627f7aa8863d641edb5ff6374c3f66047e0d9c 100644
--- a/CityDoctorParent/Extensions/CityDoctorHealerGUI/src/main/java/de/hft/stuttgart/citydoctor2/healer/gui/HealerController.java
+++ b/CityDoctorParent/Extensions/CityDoctorHealerGUI/src/main/java/de/hft/stuttgart/citydoctor2/healer/gui/HealerController.java
@@ -538,8 +538,7 @@ public class HealerController {
// if (model == null || currentFeature == null) {
// return;
// }
-
- for (Building b : model.getBuildings()) {
+ model.getBuildings().forEach(b -> {
// collect polygons
Map> availablePolygons = new EnumMap<>(Lod.class);
Map> existingPolygons = new EnumMap<>(Lod.class);
@@ -568,7 +567,7 @@ public class HealerController {
insertSolidGeometry(availablePolygons, part, existingPolygons, Lod.LOD4);
}
}
- }
+ });
}
diff --git a/CityDoctorParent/Extensions/CityDoctorHealerGUI/src/main/resources/log4j2.xml b/CityDoctorParent/Extensions/CityDoctorHealerGUI/src/main/resources/log4j2.xml
new file mode 100644
index 0000000000000000000000000000000000000000..1b1a09f31c1dea7e13e9f9a70aa5b80703e4a8d0
--- /dev/null
+++ b/CityDoctorParent/Extensions/CityDoctorHealerGUI/src/main/resources/log4j2.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/CityDoctorParent/Extensions/CityDoctorHealerGenetic/pom.xml b/CityDoctorParent/Extensions/CityDoctorHealerGenetic/pom.xml
index c98ae3bc2ae2f31f1eaabd16522e14276cdda809..c74e9809b66c8985bf414def704d01f8ef29c5d9 100644
--- a/CityDoctorParent/Extensions/CityDoctorHealerGenetic/pom.xml
+++ b/CityDoctorParent/Extensions/CityDoctorHealerGenetic/pom.xml
@@ -4,7 +4,7 @@
de.hft.stuttgart
CityDoctorParent
- 3.18.1
+ 3.18.2
../../pom.xml
CityDoctorHealerGenetic
diff --git a/CityDoctorParent/pom.xml b/CityDoctorParent/pom.xml
index d69e27d21659cade01303f71fd5ff43674c701f6..2b4bd20cb5d07870ee070e64f254a0f120770790 100644
--- a/CityDoctorParent/pom.xml
+++ b/CityDoctorParent/pom.xml
@@ -5,7 +5,7 @@
4.0.0
de.hft.stuttgart
CityDoctorParent
- 3.18.1
+ 3.18.2
pom
CityDoctorParent
@@ -41,6 +41,9 @@
**/SolidSelfIntCheckFalsePositiveBigMeshTest.java
+
+ de.hft.stuttgart.citydoctor2.connect.edge.CppTest
+
@@ -303,9 +306,9 @@
Extensions/CityDoctorGUI
-
+ Extensions/CityDoctorHealer
-
+ Extensions/CityDoctorHealerGUI
\ No newline at end of file
diff --git a/DBSettings.properties b/DBSettings.properties
new file mode 100644
index 0000000000000000000000000000000000000000..887cc7e78a1b6b174ea442a0698d29715ceb9a1d
--- /dev/null
+++ b/DBSettings.properties
@@ -0,0 +1,30 @@
+! Embedded database configuration
+! Remove # at the beginning of a parameter line to override the value.
+
+! Directory for the database file. DEFAULT: \\database\\
+# database.directory=\\database\\
+! Name of the database file. DEFAULT: cd_db
+# database.name=cd_db
+
+! Sets a limit for the number of pooled connections to the embedded database. DEFAULT: 10
+! If not overridden CityDoctor will use the number of available CPU cores as limit.
+# database.connectionPoolSize=10
+
+! If temp mode is enabled the database-file will be created in the System's TEMP directory. DEFAULT: false
+# database.tempMode=false
+
+! If in-memory mode is enabled the database will be created in the Systems RAM. DEFAULT: false
+! WARNING: Enabling in-memory mode can lead to out-of-memory errors when loading bigger CityGML files.
+# database.inMemoryMode=false
+
+! If fallback is enabled CityDoctor will attempt to use the in-memory mode if database-file creation fails DEFAULT: true
+# database.attemptFallback=true
+
+! If debug mode is enabled the embedded database will start in automatic mixed mode DEFAULT: false
+! NOTE: Activating this mode will start a local server with random ports. This may trigger a Firewall request, which can be safely denied.
+! NOTE: This server is only accessible locally and automatically rejects any remote connections.
+# database.debugMode=false
+
+
+
+
diff --git a/README.md b/README.md
index 703d18a609452bc5cca336a2ace7dcc7ae14b281..12e928e99924b08a61d8133873d0edb6c355580c 100644
--- a/README.md
+++ b/README.md
@@ -43,7 +43,7 @@ Use [Maven](https://maven.apache.org/) to build CityDoctor2.
```bash
cd CityDoctorParent
-mvn install
+mvn clean install -P create-binaries
```
CityDoctor2 uses the [quality ade plugin](https://transfer.hft-stuttgart.de/gitlab/betzms/qualityade). A jar is provided in a local repository for ease of use.
@@ -55,14 +55,16 @@ Once built there is a CityDoctorValidation-\.zip file in the target fo
There is a start script included in the binary releases of citydoctor. An example start command looks like this:
```bash
-java -classpath libs/*;plugins/*;CityDoctorValidation-.jar de.hft.stuttgart.citydoctor2.CityDoctorValidation -in .gml -config .yml -xmlReport .xml -pdfReport .pdf -out .gml
+java -classpath libs/*;plugins/*;CityDoctorValidation-.jar de.hft.stuttgart.citydoctor2.CityDoctorValidation -in .gml -config .yml -xmlReport .xml -pdfReport .pdf -out .gml -db_location -db_settings .properties
```
Notes:
-- -xmlReport, -pdfReport and -out are optional
-- If a ZIP file is given as input, CityDoctor2 will check all contained CityGML files. The -out parameter is required in
- this case
+- -xmlReport, -pdfReport, -out, -db_location and -db_settings are optional
+- Paths will be resolved from CityDoctor's working directory
+- See [DBSettings.properties](DBSettings.properties) for the formatting of the database-settings file
+- The -db_location parameter takes precedence over the location set in the database-settings file
+- The start scripts included in the binary releases have -db_location set to the system's temp directory
## Extension modules