Commit 5c91d943 authored by Luna Riegel's avatar Luna Riegel
Browse files

Merge branch 'refs/heads/dev' into dev_topo_checks

parents c24b7869 bd40b396
...@@ -5,6 +5,30 @@ All notable changes to this project will be documented in this file. ...@@ -5,6 +5,30 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [3.18.3] (2026-04-16)
### Fixes
- Fixed FragmentedSurface errors reporting roof BoundarySurfaces as ground BoundarySurfaces
- Fixed degenerated triangles causing false-positive detection of AllPolygonsWrongOrientation errors
- Fixed -db_location and -db_settings arguments not being parsed when starting the GUI from the CLI
## [3.18.2] (2026-02-24)
### Added
- CLI parameter "-db_location" for changing the location of the database-file of the embedded database. This parameter will
override the location settings of the DB-settings file.
- CLI parameter "-db_settings" for giving a path to a DB-settings .properties file.
- Added -db_location pointing to the system's temp directory to the start scripts for the binaries
- Added buttons for (un)checking all Geometric or Semantic requirements
- Added a Hyperlink to CityDoctor's homepage with detailed explanations for each requirement
- The GUI will now show a loading spinner while waiting for Schematron to finish.
### Fixes
- Connected CityDoctorHealer to the embedded database
- Various small fixes and improvements to performance
## [3.18.1] (2025-12-10) ## [3.18.1] (2025-12-10)
### Hotfix ### Hotfix
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
<parent> <parent>
<groupId>de.hft.stuttgart</groupId> <groupId>de.hft.stuttgart</groupId>
<artifactId>CityDoctorParent</artifactId> <artifactId>CityDoctorParent</artifactId>
<version>3.18.1</version> <version>3.18.3</version>
</parent> </parent>
<artifactId>CityDoctorCheckResult</artifactId> <artifactId>CityDoctorCheckResult</artifactId>
<dependencies> <dependencies>
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
<parent> <parent>
<groupId>de.hft.stuttgart</groupId> <groupId>de.hft.stuttgart</groupId>
<artifactId>CityDoctorParent</artifactId> <artifactId>CityDoctorParent</artifactId>
<version>3.18.1</version> <version>3.18.3</version>
</parent> </parent>
<artifactId>CityDoctorEdge</artifactId> <artifactId>CityDoctorEdge</artifactId>
<dependencies> <dependencies>
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
<parent> <parent>
<groupId>de.hft.stuttgart</groupId> <groupId>de.hft.stuttgart</groupId>
<artifactId>CityDoctorParent</artifactId> <artifactId>CityDoctorParent</artifactId>
<version>3.18.1</version> <version>3.18.3</version>
</parent> </parent>
<properties> <properties>
<versionString>${project.version}-${git.commit.id.abbrev}</versionString> <versionString>${project.version}-${git.commit.id.abbrev}</versionString>
......
...@@ -38,7 +38,7 @@ import de.hft.stuttgart.citydoctor2.check.error.SchematronError; ...@@ -38,7 +38,7 @@ import de.hft.stuttgart.citydoctor2.check.error.SchematronError;
import de.hft.stuttgart.citydoctor2.check.error.SolidError; import de.hft.stuttgart.citydoctor2.check.error.SolidError;
import de.hft.stuttgart.citydoctor2.check.error.SolidNotClosedError; import de.hft.stuttgart.citydoctor2.check.error.SolidNotClosedError;
import de.hft.stuttgart.citydoctor2.check.error.SolidSelfIntError; import de.hft.stuttgart.citydoctor2.check.error.SolidSelfIntError;
import de.hft.stuttgart.citydoctor2.check.error.SurfaceUnfragmentedError; import de.hft.stuttgart.citydoctor2.check.error.SurfaceFragmentedError;
import de.hft.stuttgart.citydoctor2.check.error.TooFewPolygonsError; import de.hft.stuttgart.citydoctor2.check.error.TooFewPolygonsError;
import de.hft.stuttgart.citydoctor2.check.error.UnknownCheckError; import de.hft.stuttgart.citydoctor2.check.error.UnknownCheckError;
import de.hft.stuttgart.citydoctor2.check.error.XMLValidationError; import de.hft.stuttgart.citydoctor2.check.error.XMLValidationError;
...@@ -182,7 +182,7 @@ public abstract class AbstractErrorVisitor implements ErrorVisitor { ...@@ -182,7 +182,7 @@ public abstract class AbstractErrorVisitor implements ErrorVisitor {
} }
@Override @Override
public void visit(SurfaceUnfragmentedError err) { public void visit(SurfaceFragmentedError err) {
} }
@Override @Override
......
...@@ -56,7 +56,7 @@ import de.hft.stuttgart.citydoctor2.check.error.SchematronError; ...@@ -56,7 +56,7 @@ import de.hft.stuttgart.citydoctor2.check.error.SchematronError;
import de.hft.stuttgart.citydoctor2.check.error.SolidError; import de.hft.stuttgart.citydoctor2.check.error.SolidError;
import de.hft.stuttgart.citydoctor2.check.error.SolidNotClosedError; import de.hft.stuttgart.citydoctor2.check.error.SolidNotClosedError;
import de.hft.stuttgart.citydoctor2.check.error.SolidSelfIntError; import de.hft.stuttgart.citydoctor2.check.error.SolidSelfIntError;
import de.hft.stuttgart.citydoctor2.check.error.SurfaceUnfragmentedError; import de.hft.stuttgart.citydoctor2.check.error.SurfaceFragmentedError;
import de.hft.stuttgart.citydoctor2.check.error.TooFewPolygonsError; import de.hft.stuttgart.citydoctor2.check.error.TooFewPolygonsError;
import de.hft.stuttgart.citydoctor2.check.error.UnknownCheckError; import de.hft.stuttgart.citydoctor2.check.error.UnknownCheckError;
import de.hft.stuttgart.citydoctor2.check.error.XMLValidationError; import de.hft.stuttgart.citydoctor2.check.error.XMLValidationError;
...@@ -136,7 +136,7 @@ public interface ErrorVisitor { ...@@ -136,7 +136,7 @@ public interface ErrorVisitor {
public void visit(SchematronError err); public void visit(SchematronError err);
public void visit(SurfaceUnfragmentedError err); public void visit(SurfaceFragmentedError err);
public void visit(DegeneratedRingError err); public void visit(DegeneratedRingError err);
......
...@@ -48,7 +48,7 @@ import de.hft.stuttgart.citydoctor2.check.error.RingTooFewPointsError; ...@@ -48,7 +48,7 @@ import de.hft.stuttgart.citydoctor2.check.error.RingTooFewPointsError;
import de.hft.stuttgart.citydoctor2.check.error.SchematronError; import de.hft.stuttgart.citydoctor2.check.error.SchematronError;
import de.hft.stuttgart.citydoctor2.check.error.SolidNotClosedError; import de.hft.stuttgart.citydoctor2.check.error.SolidNotClosedError;
import de.hft.stuttgart.citydoctor2.check.error.SolidSelfIntError; import de.hft.stuttgart.citydoctor2.check.error.SolidSelfIntError;
import de.hft.stuttgart.citydoctor2.check.error.SurfaceUnfragmentedError; import de.hft.stuttgart.citydoctor2.check.error.SurfaceFragmentedError;
import de.hft.stuttgart.citydoctor2.check.error.TooFewPolygonsError; import de.hft.stuttgart.citydoctor2.check.error.TooFewPolygonsError;
import de.hft.stuttgart.citydoctor2.check.error.UnknownCheckError; import de.hft.stuttgart.citydoctor2.check.error.UnknownCheckError;
import de.hft.stuttgart.citydoctor2.check.error.XMLValidationError; import de.hft.stuttgart.citydoctor2.check.error.XMLValidationError;
...@@ -189,7 +189,7 @@ public interface HealingMethod { ...@@ -189,7 +189,7 @@ public interface HealingMethod {
return false; return false;
} }
default boolean visit(SurfaceUnfragmentedError err, ModificationListener l) { default boolean visit(SurfaceFragmentedError err, ModificationListener l) {
return false; return false;
} }
......
...@@ -57,7 +57,7 @@ import de.hft.stuttgart.citydoctor2.check.error.RingTooFewPointsError; ...@@ -57,7 +57,7 @@ import de.hft.stuttgart.citydoctor2.check.error.RingTooFewPointsError;
import de.hft.stuttgart.citydoctor2.check.error.SchematronError; import de.hft.stuttgart.citydoctor2.check.error.SchematronError;
import de.hft.stuttgart.citydoctor2.check.error.SolidNotClosedError; import de.hft.stuttgart.citydoctor2.check.error.SolidNotClosedError;
import de.hft.stuttgart.citydoctor2.check.error.SolidSelfIntError; import de.hft.stuttgart.citydoctor2.check.error.SolidSelfIntError;
import de.hft.stuttgart.citydoctor2.check.error.SurfaceUnfragmentedError; import de.hft.stuttgart.citydoctor2.check.error.SurfaceFragmentedError;
import de.hft.stuttgart.citydoctor2.check.error.TooFewPolygonsError; import de.hft.stuttgart.citydoctor2.check.error.TooFewPolygonsError;
import de.hft.stuttgart.citydoctor2.check.error.UnknownCheckError; import de.hft.stuttgart.citydoctor2.check.error.UnknownCheckError;
import de.hft.stuttgart.citydoctor2.check.error.XMLValidationError; import de.hft.stuttgart.citydoctor2.check.error.XMLValidationError;
...@@ -369,7 +369,7 @@ public class QualityAdeErrorVisitor extends AbstractErrorVisitor { ...@@ -369,7 +369,7 @@ public class QualityAdeErrorVisitor extends AbstractErrorVisitor {
} }
@Override @Override
public void visit(SurfaceUnfragmentedError err) { public void visit(SurfaceFragmentedError err) {
// not translated // not translated
} }
......
...@@ -63,7 +63,7 @@ public class Requirement implements Serializable { ...@@ -63,7 +63,7 @@ public class Requirement implements Serializable {
public static final Requirement R_GE_R_NULL_AREA = new Requirement("R_GE_R_NULL_AREA", RequirementType.GEOMETRY); public static final Requirement R_GE_R_NULL_AREA = new Requirement("R_GE_R_NULL_AREA", RequirementType.GEOMETRY);
public static final Requirement R_SE_BS_GROUND_UNFRAGMENTED = new Requirement("R_SE_BS_GROUND_UNFRAGMENTED", RequirementType.SEMANTIC); public static final Requirement R_SE_BS_GROUND_UNFRAGMENTED = new Requirement("R_SE_BS_GROUND_UNFRAGMENTED", RequirementType.SEMANTIC);
public static final Requirement R_SE_BS_ROOF_UNFRAGMENTED = new Requirement("R_SE_BS_GROUND_UNFRAGMENTED", RequirementType.SEMANTIC); public static final Requirement R_SE_BS_ROOF_UNFRAGMENTED = new Requirement("R_SE_BS_ROOF_UNFRAGMENTED", RequirementType.SEMANTIC);
public static final Requirement R_SE_BS_IS_CEILING = new Requirement("R_SE_BS_IS_CEILING", RequirementType.SEMANTIC); public static final Requirement R_SE_BS_IS_CEILING = new Requirement("R_SE_BS_IS_CEILING", RequirementType.SEMANTIC);
public static final Requirement R_SE_BS_IS_FLOOR = new Requirement("R_SE_BS_IS_FLOOR", RequirementType.SEMANTIC); public static final Requirement R_SE_BS_IS_FLOOR = new Requirement("R_SE_BS_IS_FLOOR", RequirementType.SEMANTIC);
public static final Requirement R_SE_BS_IS_WALL = new Requirement("R_SE_BS_IS_WALL", RequirementType.SEMANTIC); public static final Requirement R_SE_BS_IS_WALL = new Requirement("R_SE_BS_IS_WALL", RequirementType.SEMANTIC);
...@@ -84,6 +84,7 @@ public class Requirement implements Serializable { ...@@ -84,6 +84,7 @@ public class Requirement implements Serializable {
defaultParameters.add(new DefaultParameter(UPPER_ANGLE_NAME, "135", Unit.DEGREE)); defaultParameters.add(new DefaultParameter(UPPER_ANGLE_NAME, "135", Unit.DEGREE));
R_SE_BS_IS_WALL.parameters = Collections.unmodifiableList(defaultParameters); R_SE_BS_IS_WALL.parameters = Collections.unmodifiableList(defaultParameters);
defaultParameters = new ArrayList<>();
defaultParameters.add(new DefaultParameter(MAX_ANGLE_DEVIATION, "1", Unit.DEGREE)); defaultParameters.add(new DefaultParameter(MAX_ANGLE_DEVIATION, "1", Unit.DEGREE));
R_SE_BS_ROOF_UNFRAGMENTED.parameters = Collections.unmodifiableList(defaultParameters); R_SE_BS_ROOF_UNFRAGMENTED.parameters = Collections.unmodifiableList(defaultParameters);
......
...@@ -36,7 +36,7 @@ import java.io.Serial; ...@@ -36,7 +36,7 @@ import java.io.Serial;
* @author Matthias Betz * @author Matthias Betz
* *
*/ */
public class SurfaceUnfragmentedError implements CheckError { public class SurfaceFragmentedError implements CheckError {
@Serial @Serial
private static final long serialVersionUID = 3146243879393474196L; private static final long serialVersionUID = 3146243879393474196L;
...@@ -44,7 +44,7 @@ public class SurfaceUnfragmentedError implements CheckError { ...@@ -44,7 +44,7 @@ public class SurfaceUnfragmentedError implements CheckError {
private final BoundarySurface bs; private final BoundarySurface bs;
private final double angleDeviation; private final double angleDeviation;
public SurfaceUnfragmentedError(BoundarySurface bs, double angleDerivation) { public SurfaceFragmentedError(BoundarySurface bs, double angleDerivation) {
this.bs = bs; this.bs = bs;
this.angleDeviation = angleDerivation; this.angleDeviation = angleDerivation;
} }
......
package de.hft.stuttgart.citydoctor2.database; package de.hft.stuttgart.citydoctor2.database;
import de.hft.stuttgart.citydoctor2.exceptions.EmbeddedDatabaseHandlerException;
import de.hft.stuttgart.citydoctor2.utils.Localization; 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;
...@@ -9,6 +10,7 @@ import java.io.File; ...@@ -9,6 +10,7 @@ import java.io.File;
import java.io.FileReader; import java.io.FileReader;
import java.io.IOException; import java.io.IOException;
import java.nio.file.InvalidPathException; import java.nio.file.InvalidPathException;
import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.Properties; import java.util.Properties;
...@@ -16,27 +18,47 @@ public final class DatabaseSettings { ...@@ -16,27 +18,47 @@ public final class DatabaseSettings {
private static final Logger logger = LogManager.getLogger(DatabaseSettings.class); private static final Logger logger = LogManager.getLogger(DatabaseSettings.class);
private static final Properties props; private static final Properties props = new Properties();
private DatabaseSettings() {} private DatabaseSettings() {}
static { static {
props = new Properties();
File propFile = new File("DBSettings.properties"); File propFile = new File("DBSettings.properties");
if (propFile.exists()) { if (propFile.exists()) {
try (BufferedReader bis = new BufferedReader(new FileReader(propFile))) { loadPropertiesFromFile(propFile);
props.load(bis); }
} catch (IOException e) { }
logger.error("Failed to load database settings", e);
} public static void loadPropertiesFromFile(File file) throws EmbeddedDatabaseHandlerException {
try (BufferedReader bis = new BufferedReader(new FileReader(file))) {
props.load(bis);
} catch (IOException e) {
throw new EmbeddedDatabaseHandlerException(e);
}
}
public static void setDBLocation(String dbLocation) throws EmbeddedDatabaseHandlerException{
Path dbPath = Paths.get(dbLocation).toAbsolutePath();
File dbLocationFile = dbPath.toFile();
if (!dbLocationFile.isFile()) {
dbPath = dbPath.resolve("cd_db");
}
Path dbParentDirectoryPath = dbPath.getParent();
if (dbParentDirectoryPath.toFile().mkdirs()){
logger.trace("Created parent directories for database location");
}
if (!dbParentDirectoryPath.toFile().canWrite()) {
throw new EmbeddedDatabaseHandlerException("Missing write permissions for database location:" + dbLocation);
} }
props.setProperty("database.name", dbPath.getFileName().toString());
props.setProperty("database.directory", dbParentDirectoryPath.toAbsolutePath().toString());
} }
public static EmbeddedDatabaseConfiguration getConfig() { public static EmbeddedDatabaseConfiguration getConfig() {
EmbeddedDatabaseConfiguration defaultConfig = new EmbeddedDatabaseConfiguration(); EmbeddedDatabaseConfiguration defaultConfig = new EmbeddedDatabaseConfiguration();
if (props.isEmpty()) { if (props.isEmpty()) {
logger.debug("No database settings found or specified, using default config"); logger.trace("No database settings found or specified, using default config");
return defaultConfig; return defaultConfig;
} }
String name = props.getProperty("database.name"); String name = props.getProperty("database.name");
......
package de.hft.stuttgart.citydoctor2.database; package de.hft.stuttgart.citydoctor2.database;
import java.io.File; import java.io.File;
import java.nio.file.Paths;
import java.util.StringJoiner; import java.util.StringJoiner;
/** /**
...@@ -51,7 +52,7 @@ public record EmbeddedDatabaseConfiguration(String databaseName, String database ...@@ -51,7 +52,7 @@ public record EmbeddedDatabaseConfiguration(String databaseName, String database
} }
public String getH2FileUrl(){ public String getH2FileUrl(){
return wrapUrlWithH2JdbcDriver(databaseDirectory + databaseName); return wrapUrlWithH2JdbcDriver(Paths.get(databaseDirectory).resolve(databaseName).toString());
} }
public String getH2ParametersSuffix(){ public String getH2ParametersSuffix(){
......
...@@ -6,7 +6,7 @@ CheckContainer.error=Unexpected exception while executing check: {} ...@@ -6,7 +6,7 @@ CheckContainer.error=Unexpected exception while executing check: {}
CheckDialog.availableChecksLabel=Available Checks CheckDialog.availableChecksLabel=Available Checks
CheckDialog.cancelBtn=Cancel CheckDialog.cancelBtn=Cancel
CheckDialog.checkBtn=Check CheckDialog.checkBtn=Check
CheckDialog.checkDescriptionsLabel=Documentations are available on CityDoctor's homepage CheckDialog.checkDescriptionsLabel=Explanations for the requirements are available on CityDoctor's homepage
CheckDialog.checkEnabled=Enabled CheckDialog.checkEnabled=Enabled
CheckDialog.checkName=Name CheckDialog.checkName=Name
CheckDialog.checksDone=Checks done CheckDialog.checksDone=Checks done
......
...@@ -6,7 +6,7 @@ CheckContainer.error=Unerwarteter Fehler bei der Ausf\u00fchrung von Pr\u00fcfun ...@@ -6,7 +6,7 @@ CheckContainer.error=Unerwarteter Fehler bei der Ausf\u00fchrung von Pr\u00fcfun
CheckDialog.availableChecksLabel=Verf\u00fcgbare Pr\u00fcfungen CheckDialog.availableChecksLabel=Verf\u00fcgbare Pr\u00fcfungen
CheckDialog.cancelBtn=Abbrechen CheckDialog.cancelBtn=Abbrechen
CheckDialog.checkBtn=Pr\u00fcfen CheckDialog.checkBtn=Pr\u00fcfen
CheckDialog.checkDescriptionsLabel=Erkl\u00e4rungen hierzu auf der CityDoctor Homepage CheckDialog.checkDescriptionsLabel=Beschreibungen der Pr\u00fcfungen sind auf der CityDoctor Homepage verf\u00fcgbar
CheckDialog.checkEnabled=Aktiv CheckDialog.checkEnabled=Aktiv
CheckDialog.checkName=Name CheckDialog.checkName=Name
CheckDialog.checksDone=Pr\u00fcfung abgeschlossen CheckDialog.checksDone=Pr\u00fcfung abgeschlossen
......
package de.hft.stuttgart.citydoctor2.database;
import org.junit.jupiter.api.Test;
public class DatabaseSettingsTest {
public void testSetLocation(){
String tempdirectory = System.getProperty("java.io.tmpdir");
DatabaseSettings.setDBLocation(tempdirectory + "/citydoctor");
}
}
...@@ -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.18.1</version> <version>3.18.3</version>
</parent> </parent>
<artifactId>CityDoctorValidation</artifactId> <artifactId>CityDoctorValidation</artifactId>
<name>CityDoctorValidation</name> <name>CityDoctorValidation</name>
......
#!/bin/sh #!/bin/sh
./runtime/bin/java -classpath app/*:plugin/* de.hft.stuttgart.citydoctor2.CityDoctorValidation -in REKaiserwall.gml -config testConfigWithStreaming.yml -xmlReport output.xml ./runtime/bin/java -classpath app/*:plugin/* de.hft.stuttgart.citydoctor2.CityDoctorValidation -in REKaiserwall.gml -config testConfigWithStreaming.yml -xmlReport output.xml -db_location "${TMPDIR:-/tmp}"
\ No newline at end of file \ No newline at end of file
java -classpath app/*;plugin/* de.hft.stuttgart.citydoctor2.CityDoctorValidation -in REKaiserwall.gml -config testConfigWithStreaming.yml -xmlReport output.xml java -classpath app/*;plugin/* de.hft.stuttgart.citydoctor2.CityDoctorValidation -in REKaiserwall.gml -config testConfigWithStreaming.yml -xmlReport output.xml -db_location %TEMP%/citydoctor/
pause pause
\ No newline at end of file
#!/bin/sh #!/bin/sh
java -classpath app/*:plugin/* de.hft.stuttgart.citydoctor2.CityDoctorValidation -in REKaiserwall.gml -config testConfigWithStreaming.yml -xmlReport output.xml java -classpath app/*:plugin/* de.hft.stuttgart.citydoctor2.CityDoctorValidation -in REKaiserwall.gml -config testConfigWithStreaming.yml -xmlReport output.xml -db_location #!/bin/sh
\ No newline at end of file ./runtime/bin/java -classpath app/*:plugin/* de.hft.stuttgart.citydoctor2.CityDoctorValidation -in REKaiserwall.gml -config testConfigWithStreaming.yml -xmlReport output.xml -db_location "${TMPDIR:-/tmp}"
\ No newline at end of file
"runtime/bin/java.exe" -classpath app/*;plugin/* de.hft.stuttgart.citydoctor2.CityDoctorValidation -in REKaiserwall.gml -config testConfigWithStreaming.yml -xmlReport output.xml "runtime/bin/java.exe" -classpath app/*;plugin/* de.hft.stuttgart.citydoctor2.CityDoctorValidation -in REKaiserwall.gml -config testConfigWithStreaming.yml -xmlReport output.xml -db_location %TEMP%/citydoctor/
pause pause
\ 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