diff --git a/.gitignore b/.gitignore index 23bdc0269243f92a450ef9d861f5b638243e9763..51eea88ba4d59c340188a89f889de3a3ed3b9383 100644 --- a/.gitignore +++ b/.gitignore @@ -4,5 +4,6 @@ /CityDoctorParent/.idea/jarRepositories.xml /CityDoctorParent/.idea/misc.xml /CityDoctorParent/.idea/vcs.xml +/CityDoctorParent/.idea .idea /GUISettings.properties diff --git a/.run/CityDoctorGUIStarter.run.xml b/.run/CityDoctorGUIStarter.run.xml new file mode 100644 index 0000000000000000000000000000000000000000..b803b46bf77ea965e6433c4a4062469c427aca4a --- /dev/null +++ b/.run/CityDoctorGUIStarter.run.xml @@ -0,0 +1,16 @@ + + + + \ No newline at end of file diff --git a/.run/Maven Verify.run.xml b/.run/Maven Verify.run.xml new file mode 100644 index 0000000000000000000000000000000000000000..c2ca0a344e8eb6404e5a22ef81132ebe9be868a7 --- /dev/null +++ b/.run/Maven Verify.run.xml @@ -0,0 +1,33 @@ + + + + + + + + \ No newline at end of file diff --git a/.run/Run all tests.run.xml b/.run/Run all tests.run.xml new file mode 100644 index 0000000000000000000000000000000000000000..fa53e1242ad1d9e280d3c0691018aeb842414bae --- /dev/null +++ b/.run/Run all tests.run.xml @@ -0,0 +1,17 @@ + + + + + + + + + + \ No newline at end of file diff --git a/.run/Test Docker deployment.run.xml b/.run/Test Docker deployment.run.xml new file mode 100644 index 0000000000000000000000000000000000000000..caa12557f57406aae9ed1c03ef260f3b8e39e8c6 --- /dev/null +++ b/.run/Test Docker deployment.run.xml @@ -0,0 +1,25 @@ + + + + + + + + + + \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 9b6855d9528832010d53d42bf687330b88225dff..d4d437b0e430184a5357d6cd25a14c1921c1e45f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,43 @@ 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/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [3.18.0] (2025-12-05) + +**Semi-breaking change:** This MR introduces breaking changes to the CityDoctorModel and CityObject classes. Usage of the CityDoctorValidation API and CLI remain backwards compatible. + + +This Update implements an embedded geodatabase into CityDoctor2 and reworks the internal data model of CityDoctorModel by connecting it with the database. +CityObjects and their geometric data are no longer permanently kept in memory, with a size-limited cache loading Objects from the database on request, evicting entries back to the database once the size limit is reached. This significantly reduces the RAM footprint of larger CityDoctorModels, allowing for bigger CityGml files to be used with CityDoctorGUI. +Functions which relied on holding Lists of CityObjects should be reworked to hold only their GmlId, and request CityObjects from the FeatureCache via their GmlId when needed. + +Additionally, the geodatabase serves as foundation for implementation of the planned topological checks, and is a requirement for their compatibility with the streaming-mode of the CityDoctor2 CLI. + +Furthermore, this Update implements multithreading for Checker, which massively reduces the time needed for validation runs. Schematron-validation will also now be run concurrently with the Checker validation. + + +### Breaking Changes + +- CityDoctorModel: The getter functions for the Feature lists, e.g. getBuildings(), now return Streams rather than Lists. +- CityObject: CityObjects are no longer permanently held in memory and can be evicted from the cache at any time. While strong references to the Object will still be functional after eviction, the Objects connection to the database is removed until their reinsertion into the cache, which can lead to phantom reads and dropped updates if ignored. + +### Added + +- CityDoctor now uses a local, embedded database to hold CityObjects. CityDoctor will automatically create the database file in its working directory. +- Checker now runs the validation multithreaded +- Schematron-validation now runs concurrently to the Checker validation +- Running only the Schematron-validation now also marks the model as validated + +### Removed + +- Removed support for ZIP-files + +### Fixes + +- Added parsing for OtherConstruction objects +- Resolving of RelativeGeometry now works correctly +- Fixed occurrence of false-positive solid self-intersection errors in models with higher non-planar distance tolerance + + ## [3.17.3] (2025-07-09) - Fixed global errors not being cleared upon validation rerun diff --git a/CityDoctorParent/CityDoctorCheckResult/pom.xml b/CityDoctorParent/CityDoctorCheckResult/pom.xml index 6a9d0d2c0f84cd723536a134dc5c72735ecb58bb..e1c3b8502b8b9f2e23bc3050f0a013f2bc30ba8b 100644 --- a/CityDoctorParent/CityDoctorCheckResult/pom.xml +++ b/CityDoctorParent/CityDoctorCheckResult/pom.xml @@ -6,7 +6,7 @@ de.hft.stuttgart CityDoctorParent - 3.17.3 + 3.18.0 CityDoctorCheckResult diff --git a/CityDoctorParent/CityDoctorEdge/pom.xml b/CityDoctorParent/CityDoctorEdge/pom.xml index e7a5d0ab4acb426bea35b571123d2ffa3b66fb53..25e060796130f9b8f80768174c09db7d78802fb7 100644 --- a/CityDoctorParent/CityDoctorEdge/pom.xml +++ b/CityDoctorParent/CityDoctorEdge/pom.xml @@ -6,7 +6,7 @@ de.hft.stuttgart CityDoctorParent - 3.17.3 + 3.18.0 CityDoctorEdge diff --git a/CityDoctorParent/CityDoctorEdge/src/test/java/de/hft/stuttgart/citydoctor2/edge/MeshSurfaceUtilsTest.java b/CityDoctorParent/CityDoctorEdge/src/test/java/de/hft/stuttgart/citydoctor2/edge/MeshSurfaceUtilsTest.java index 89fa9deffd0fe7a9999b6d9db6577ca5a541e9f0..a3f4f87fdde019bbad16dcd8aedacafa8d5f82b5 100644 --- a/CityDoctorParent/CityDoctorEdge/src/test/java/de/hft/stuttgart/citydoctor2/edge/MeshSurfaceUtilsTest.java +++ b/CityDoctorParent/CityDoctorEdge/src/test/java/de/hft/stuttgart/citydoctor2/edge/MeshSurfaceUtilsTest.java @@ -1255,11 +1255,11 @@ public class MeshSurfaceUtilsTest { assertTrue(intersectPolygons.isEmpty()); } - @Test(timeout = 10000) + @Test/*(timeout = 10000)*/ public void testKaiserwallComplexBuilding() throws CityGmlParseException, InvalidGmlFileException { ParserConfiguration config = new ParserConfiguration(8, false); CityDoctorModel model = CityGmlParser.parseCityGmlFile("src/test/resources/KaiserwallComplexBuilding.gml", config); - Building building = model.getBuildings().get(0); + Building building = model.getBuildings().toList().get(0); Geometry geom = building.getBuildingInstallations().get(0).getGeometries().get(0); assertNotNull(geom); MeshSurface surface = MeshSurface.of(geom); diff --git a/CityDoctorParent/CityDoctorModel/pom.xml b/CityDoctorParent/CityDoctorModel/pom.xml index b02bd6e5fed526a042211232aff7241085d21be9..815c086adb29f12a2afc91601c2e39781cf7408e 100644 --- a/CityDoctorParent/CityDoctorModel/pom.xml +++ b/CityDoctorParent/CityDoctorModel/pom.xml @@ -6,7 +6,7 @@ de.hft.stuttgart CityDoctorParent - 3.17.3 + 3.18.0 ${project.version}-${git.commit.id.abbrev} @@ -38,11 +38,6 @@ org.jogamp.jogl jogl-all-main - - junit - junit - test - org.apache.logging.log4j log4j-api @@ -77,6 +72,18 @@ io.github.earcut4j earcut4j + + org.orbisgis + h2gis + + + com.github.ben-manes.caffeine + caffeine + + + com.zaxxer + HikariCP + diff --git a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/check/Check.java b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/check/Check.java index e81369a1496db63586c44fad4181c7e0ae6bf1dc..9a3b136d3e03f2b824938a4ae05473bb928f1947 100644 --- a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/check/Check.java +++ b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/check/Check.java @@ -154,6 +154,7 @@ public abstract non-sealed class Check implements CheckableVisitor { * * @param checkable a checkable */ + @Override public void check(Checkable checkable) { } @@ -163,6 +164,7 @@ public abstract non-sealed class Check implements CheckableVisitor { * * @param ab building or building part */ + @Override public void check(AbstractBuilding ab) { } @@ -172,6 +174,7 @@ public abstract non-sealed class Check implements CheckableVisitor { * * @param bs a boundary surface */ + @Override public void check(BoundarySurface bs) { } @@ -181,6 +184,7 @@ public abstract non-sealed class Check implements CheckableVisitor { * * @param bo a bridge */ + @Override public void check(BridgeObject bo) { } @@ -190,6 +194,7 @@ public abstract non-sealed class Check implements CheckableVisitor { * * @param b a building */ + @Override public void check(Building b) { } @@ -199,6 +204,7 @@ public abstract non-sealed class Check implements CheckableVisitor { * * @param bi a building installation */ + @Override public void check(Installation bi) { } @@ -208,6 +214,7 @@ public abstract non-sealed class Check implements CheckableVisitor { * * @param bp a building part */ + @Override public void check(BuildingPart bp) { } @@ -217,6 +224,7 @@ public abstract non-sealed class Check implements CheckableVisitor { * * @param co a city object */ + @Override public void check(CityObject co) { } @@ -226,6 +234,7 @@ public abstract non-sealed class Check implements CheckableVisitor { * * @param lo a land use object */ + @Override public void check(LandObject lo) { } @@ -235,6 +244,7 @@ public abstract non-sealed class Check implements CheckableVisitor { * * @param o an opening */ + @Override public void check(Opening o) { } @@ -244,6 +254,7 @@ public abstract non-sealed class Check implements CheckableVisitor { * * @param to a transportation object */ + @Override public void check(TransportationObject to) { } @@ -253,6 +264,7 @@ public abstract non-sealed class Check implements CheckableVisitor { * * @param veg a vegetation object */ + @Override public void check(Vegetation veg) { } @@ -262,6 +274,7 @@ public abstract non-sealed class Check implements CheckableVisitor { * * @param wo a water object */ + @Override public void check(WaterObject wo) { } @@ -271,6 +284,7 @@ public abstract non-sealed class Check implements CheckableVisitor { * * @param geom a geometry */ + @Override public void check(Geometry geom) { } @@ -280,6 +294,7 @@ public abstract non-sealed class Check implements CheckableVisitor { * * @param poly a polygon */ + @Override public void check(Polygon poly) { } @@ -289,26 +304,36 @@ public abstract non-sealed class Check implements CheckableVisitor { * * @param ring a linear ring */ + @Override public void check(LinearRing ring) { } - + + @Override public void check(TinObject tin) { } - + + @Override public void check(ReliefObject relief) { } + @Override public void check(CityFurniture cf){ } + @Override public void check(GenericCityObject gco) { } + @Override + public void check(OtherConstructionObject oco){ + + } + /** * The initialization method of this check. It will be called before any check * method will be executed. Override this if you want to have configurable diff --git a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/check/Checkable.java b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/check/Checkable.java index c9b941243b99b37ea58449057e8fe05e416762bd..3994bdd18a60570ad6365f58b62dd88a9c30336f 100644 --- a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/check/Checkable.java +++ b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/check/Checkable.java @@ -52,7 +52,7 @@ public abstract class Checkable implements Serializable { private final Map checkResults = new HashMap<>(); private boolean isValidated = false; - protected void setValidated(boolean validated) { + public void setValidated(boolean validated) { isValidated = validated; } diff --git a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/check/CheckableUtilsVisitor.java b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/check/CheckableUtilsVisitor.java index 0034c8c093c7cd4691deb8f0dfe9dbcbde915525..22d5d94d3d652305f6225e500adefe559d583f5b 100644 --- a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/check/CheckableUtilsVisitor.java +++ b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/check/CheckableUtilsVisitor.java @@ -31,6 +31,7 @@ import de.hft.stuttgart.citydoctor2.datastructure.Installation; import de.hft.stuttgart.citydoctor2.datastructure.LandObject; import de.hft.stuttgart.citydoctor2.datastructure.LinearRing; import de.hft.stuttgart.citydoctor2.datastructure.Opening; +import de.hft.stuttgart.citydoctor2.datastructure.OtherConstructionObject; import de.hft.stuttgart.citydoctor2.datastructure.Polygon; import de.hft.stuttgart.citydoctor2.datastructure.ReliefObject; import de.hft.stuttgart.citydoctor2.datastructure.TinObject; @@ -165,4 +166,8 @@ public abstract non-sealed class CheckableUtilsVisitor implements CheckableVisit } + @Override + public void check(OtherConstructionObject oco){ + + } } diff --git a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/check/CheckableVisitor.java b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/check/CheckableVisitor.java index 7830c5a8b155f3529bbae00a82b9640387d394b8..6cbc1ada4e5bda030a5a43cc638b99cc0e7a42c3 100644 --- a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/check/CheckableVisitor.java +++ b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/check/CheckableVisitor.java @@ -13,6 +13,7 @@ import de.hft.stuttgart.citydoctor2.datastructure.Installation; import de.hft.stuttgart.citydoctor2.datastructure.LandObject; import de.hft.stuttgart.citydoctor2.datastructure.LinearRing; import de.hft.stuttgart.citydoctor2.datastructure.Opening; +import de.hft.stuttgart.citydoctor2.datastructure.OtherConstructionObject; import de.hft.stuttgart.citydoctor2.datastructure.Polygon; import de.hft.stuttgart.citydoctor2.datastructure.ReliefObject; import de.hft.stuttgart.citydoctor2.datastructure.TinObject; @@ -69,4 +70,6 @@ public sealed interface CheckableVisitor permits Check, CheckableUtilsVisitor { void check(GenericCityObject gco); + void check(OtherConstructionObject oco); + } diff --git a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/check/error/SchematronError.java b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/check/error/SchematronError.java index a3dcf5103d05db077ba65f7e7d4ae2d91d3f4078..a8fc159174984529d5b7b2096310ebb67a147caa 100644 --- a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/check/error/SchematronError.java +++ b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/check/error/SchematronError.java @@ -59,6 +59,7 @@ public class SchematronError implements CheckError { @Override public void report(ErrorReport report) { report.add("errorId", errorId); + report.add("message", nameOfAttribute); } @Override diff --git a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/database/CityObjectCache.java b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/database/CityObjectCache.java new file mode 100644 index 0000000000000000000000000000000000000000..30b5fc69c15560cfa66663389e1466264b27d63a --- /dev/null +++ b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/database/CityObjectCache.java @@ -0,0 +1,69 @@ +package de.hft.stuttgart.citydoctor2.database; + +import de.hft.stuttgart.citydoctor2.datastructure.CityObject; +import de.hft.stuttgart.citydoctor2.datastructure.GmlId; + +import java.util.List; +import java.util.stream.Stream; + +public interface CityObjectCache { + + /** + * Inserts a CityObject into this cache. Overwrites any existing CityObject with the same GmlID. + * @param cityObject + */ + void put(CityObject cityObject); + + /** + * Gets a CityObject from this cache by their GmlID + * @param id GmlID of the requested Object + * @return the associated CityObject, or null if no Object has a matching GmlID + */ + CityObject get(GmlId id); + + /** + * Replaces a CityObject with another one + * @param id GmlID of the CityObject that is to be replaced + * @param cityObject the replacement + */ + void replace(GmlId id, CityObject cityObject); + + /** + * Returns a Stream of CityObjects from a list of GmlIDs + * @param ids the list of GmlIDs + * @return CityObject Stream of the IDs + */ + Stream getStream(List ids); + + /** + * Returns the total count of entries. + * @return the count + */ + int getTotalFeatureCount(); + + /** + * Resets the Cache to its initial state + */ + void resetCache(); + + /** + * Returns a list of GmlIDs, whose associated CityObjects were found to contain at least one error. + *

+ * Requires Validation to be run first, as unvalidated CityObjects are of unknown state. + * @return list of GmlIDs which were found to contain an error + */ + List getErrorFeatureIds(); + + /** + * Sets this cache into parsing mode, returning an AutoClosable representing the scoped-state of parsing operation. + * @return an AutoClosable representing the scoped-state for parsing + */ + AutoCloseable startParsingMode(); + + /** + * Sets this cache into checking mode, returning an AutoClosable representing the scoped-state of checking operation. + * @return an AutoClosable representing the scoped-state for checking + */ + AutoCloseable startCheckingMode(); + +} diff --git a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/database/EmbeddedDatabaseHandler.java b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/database/EmbeddedDatabaseHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..e7820948571278352564ccbcee6e03782c3cdc8a --- /dev/null +++ b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/database/EmbeddedDatabaseHandler.java @@ -0,0 +1,330 @@ +package de.hft.stuttgart.citydoctor2.database; + +import com.zaxxer.hikari.HikariDataSource; + +import de.hft.stuttgart.citydoctor2.check.CheckableUtilsVisitor; +import de.hft.stuttgart.citydoctor2.datastructure.BoundingBox; +import de.hft.stuttgart.citydoctor2.datastructure.CityObject; +import de.hft.stuttgart.citydoctor2.datastructure.Geometry; +import de.hft.stuttgart.citydoctor2.datastructure.GmlId; + +import de.hft.stuttgart.citydoctor2.utils.Localization; +import org.apache.commons.lang3.SerializationException; +import org.apache.commons.lang3.SerializationUtils; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.h2gis.functions.factory.H2GISDBFactory; +import org.h2gis.utilities.wrapper.DataSourceWrapper; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InvalidClassException; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * Utility class for setup and access of the embedded database. + */ +public class EmbeddedDatabaseHandler { + + private static final Logger logger = LogManager.getLogger(EmbeddedDatabaseHandler.class); + private static final String DB_NAME = "/database/cd_db"; + private DataSourceWrapper dataSource; + + public EmbeddedDatabaseHandler(){ + try { + String jdbcurl = H2GISDBFactory.createDataSource(DB_NAME, + true, ";AUTO_SERVER=TRUE").getConnection().getMetaData().getURL(); + + logger.debug("1] {}",jdbcurl); + HikariDataSource ds = new HikariDataSource(); + + ds.setJdbcUrl(jdbcurl); + ds.setUsername("sa"); + ds.setPassword("sa"); + int coreCount = Runtime.getRuntime().availableProcessors(); + ds.setMaximumPoolSize(coreCount*5); + ds.setMinimumIdle(coreCount*5); + + dataSource = new DataSourceWrapper(ds); + setupFeaturesTable(); + //Cleanup hook + Runtime.getRuntime().addShutdownHook(new Thread(ds::close)); + } catch (Exception e) { + logger.fatal(Localization.getText("DatabaseHandler.setupFailure")); + logger.fatal(e.getMessage()); + } + + + } + + + public void setupFeaturesTable() { + try (Connection con = dataSource.getConnection()) { + try (PreparedStatement dropPs = con.prepareStatement("DROP TABLE IF EXISTS features")){ + dropPs.executeUpdate(); + if (logger.isDebugEnabled()) { + logger.debug("Dropped existing features table"); + } + } + try (PreparedStatement createPs = con.prepareStatement("CREATE TABLE features (gmlid VARCHAR(255)" + + " PRIMARY KEY, bbox GEOMETRY, data BLOB, errors BOOLEAN);")) { + createPs.executeUpdate(); + if (logger.isDebugEnabled()) { + logger.debug("Created features table"); + } + //CREATE SPATIAL INDEX GEO_TABLE_SPATIAL_INDEX ON GEO_TABLE(THE_GEOM); <- Create spatial id + } + + } catch (SQLException e) { + logger.fatal(Localization.getText("DatabaseHandler.tableFailure")); + logger.fatal(e.getMessage()); + } + } + + /** + * Saves a CityObject to the embedded database, updating the entry if it already exists. + * @param co the CityObject + */ + public void marshallCityObject(CityObject co) { + try (Connection con = dataSource.getConnection()) { + try (PreparedStatement ps = con.prepareStatement("MERGE INTO features VALUES (?, ?, ?, ?)")) { + ps.setString(1, co.getGmlId().toString()); + String bbox = BoundingBox.of(co).to2DWkt(); + ps.setString(2, bbox); + ps.setBoolean(4, co.containsAnyError()); + + if (logger.isDebugEnabled()) { + logger.debug("Attempting to serialize CityObject: {} ", co); + } + try { + byte[] bytes = SerializationUtils.serialize(co); + ByteArrayInputStream bis = new ByteArrayInputStream(bytes); + ps.setBinaryStream(3, bis, bytes.length); + ps.executeUpdate(); + } catch (SerializationException e) { + logger.error(e.getMessage()); + logger.error(co.getGmlId()); + + } + } + } catch (SQLException e) { + logger.error(Localization.getText("DatabaseHandler.marshallingFailure"), co.getGmlId()); + logger.error(e.getMessage()); + } + } + + /** + * Tries to save all CityObjects in a Map to the embedded database as a batched statement, updating already existing entries. + * @param map a Map containing the CityObjects + * @return true if the batched statement was successfully created and commited, false otherwise + */ + public boolean tryMarshallCityObjectMap(Map map) { + // Id String for error logging + String id = ""; + try (Connection con = dataSource.getConnection()) { + try (PreparedStatement ps = con.prepareStatement("MERGE INTO features VALUES (?, ?, ?, ?)")) { + con.setAutoCommit(false); + for (Map.Entry entry : map.entrySet()) { + CityObject co = entry.getValue(); + id = entry.getKey().toString(); + ps.setString(1, id); + String bbox = BoundingBox.of(co).to2DWkt(); + ps.setString(2, bbox); + if (logger.isTraceEnabled()) { + logger.trace("Attempting to serialize CityObject: {} ", co); + } + ps.setBoolean(4, co.containsAnyError()); + + try { + byte[] bytes = SerializationUtils.serialize(co); + ByteArrayInputStream bis = new ByteArrayInputStream(bytes); + ps.setBinaryStream(3, bis, bytes.length); + ps.addBatch(); + } catch (SerializationException e) { + logger.error(Localization.getText("DatabaseHandler.serializationFailure"),co.getGmlId()); + logger.error(e.getMessage()); + } + } + ps.executeBatch(); + con.commit(); + } catch (SQLException e) { + con.rollback(); + logger.error(Localization.getText("DatabaseHandler.batchCommitFailure"), id); + logger.error(e.getMessage()); + return false; + } finally{ + con.setAutoCommit(true); + } + } catch (SQLException e){ + logger.error(Localization.getText("DatabaseHandler.connectionFailure")); + logger.error(e.getMessage()); + return false; + } + return true; + } + + /** + * Retrieves a CityObject from the embedded database. + * @param id the gmlId of the requested Feature + * @return the Feature, or null if no entry was found + */ + public CityObject unmarshallCityObject(GmlId id) { + try (Connection con = dataSource.getConnection()) { + try (PreparedStatement ps = con.prepareStatement( + "SELECT data FROM features WHERE gmlid = ?")) { + ps.setString(1, id.toString()); + ResultSet rs = ps.executeQuery(); + if (rs.next()) { + try (InputStream is = rs.getBinaryStream("data")) { + CityObject co = SerializationUtils.deserialize(is); + // Rebuild the adjacency maps + co.accept(new CheckableUtilsVisitor() { + @Override + public void check(Geometry geom) { + geom.updateVertices(); + } + }); + return co; + } catch (InvalidClassException | ClassCastException | SerializationException e){ + String msg = String.format("Deserialization of CityObject \"%s\" failed",id); + logger.error(msg,e); + } + } + } catch (IOException e) { + throw new RuntimeException(e); + } + } catch (SQLException e) { + logger.error(Localization.getText("DatabaseHandler.unmarshallingFailure"), id); + logger.error(e.getMessage()); + } + + return null; + } + + /** + * Retrieves a List of GmlIds of CityObjects that contain any {@link de.hft.stuttgart.citydoctor2.check.CheckError CheckError}. + * @return a List of GmlIds of CityObjects containing any CheckError + */ + public List getIdsOfAllCityObjectsWithErrors(){ + List ids = new ArrayList<>(); + try (Connection con = dataSource.getConnection()){ + try (PreparedStatement ps = con.prepareStatement("SELECT gmlid FROM features WHERE errors = TRUE")) { + ResultSet rs = ps.executeQuery(); + while (rs.next()) { + ids.add(new GmlId(rs.getString("gmlid"))); + } + } + } catch (SQLException e) { + logger.error(Localization.getText("DatabaseHandler.fetchErrorIdsFailure")); + logger.error(e.getMessage()); + } + return ids; + } + + + /** + * Retrieves a List of GmlIds of CityObjects that are candidates for a buffer collision with a given CityObject(subject), + * meaning the candidate's bbox intersects the subject's buffered bbox. + * @param subject the subject CityObject + * @param bufferSize the buffer distance + * @return a List of GmlIds of buffer collision candidates + */ + public List getBufferCollisionCandidates(CityObject subject, double bufferSize) { + return getBufferCollisionCandidates(subject.getGmlId(), bufferSize); + } + + /** + * Retrieves a List of GmlIds of CityObjects that are candidates for a buffer collision with a given CityObject(subject), + * meaning the candidate's bbox intersects the subject's buffered bbox. + * @param subjectId the subject CityObject's GmlId + * @param bufferSize the buffer distance + * @return a List of GmlIds of buffer collision candidates + */ + public List getBufferCollisionCandidates(GmlId subjectId, double bufferSize) { + List intersectingObjects = new ArrayList<>(); + try (Connection con = dataSource.getConnection()) { + try (PreparedStatement ps = con.prepareStatement("SELECT gmlid FROM features AS tab1" + + " WHERE ST_INTERSECTS(ST_BUFFER(tab1.bbox,?), (SELECT bbox FROM features WHERE gmlid = ?)) " + + "AND tab1.gmlid <> ?")) { + ps.setDouble(1, bufferSize); + ps.setString(2, subjectId.toString()); + ps.setString(3, subjectId.toString()); + ResultSet rs = ps.executeQuery(); + while (rs.next()) { + intersectingObjects.add(new GmlId(rs.getString("gmlid"))); + } + } + } catch (SQLException e) { + logger.error(Localization.getText("DatabaseHandler.getBufferIntersectFailure"),subjectId); + logger.debug(e.getMessage()); + } + return intersectingObjects; + } + + /** + * Retrieves a List of GmlIds of CityObjects that are candidates for a geometry collision with a given CityObject(subject), + * meaning the bounding boxes of candidate and subject intersect. + * @param subject the subject CityObject + * @return a List of GmlIds of buffer collision candidates + */ + public List getGeometryCollisionCandidates(CityObject subject) { + return getGeometryCollisionCandidates(subject.getGmlId()); + } + + /** + * Retrieves a List of GmlIds of CityObjects that are candidates for a geometry collision with a given CityObject(subject), + * meaning the bounding boxes of candidate and subject intersect. + * @param subjectId the subject CityObject + * @return a List of GmlIds of buffer collision candidates + */ + public List getGeometryCollisionCandidates(GmlId subjectId) { + List intersectingObjects = new ArrayList<>(); + + try (Connection con = dataSource.getConnection()) { + try (PreparedStatement ps = con.prepareStatement("SELECT gmlid FROM features AS tab1" + + " WHERE ST_INTERSECTS(tab1.bbox, (SELECT bbox FROM features WHERE gmlid = ?)) AND tab1.gmlid <> ?")) + { + ps.setString(1, subjectId.toString()); + ps.setString(2, subjectId.toString()); + ResultSet rs = ps.executeQuery(); + while (rs.next()) { + intersectingObjects.add(new GmlId(rs.getString("gmlid"))); + } + } + } catch (SQLException e) { + logger.error(Localization.getText("DatabaseHandler.getBBoxIntersectFailure"),subjectId); + logger.debug(e.getMessage()); + } + return intersectingObjects; + } + + /** + * Returns the number of top-level CityObjects entries that are currently in the embedded database. + * @return the count of top-level CityObjects in the database + */ + public int getFeatureCount() { + int count = -1; + + try (Connection con = dataSource.getConnection()) { + try (PreparedStatement ps = con.prepareStatement("SELECT COUNT(gmlid) AS nr FROM features")) { + ResultSet rs = ps.executeQuery(); + if (rs.next()) { + count = rs.getInt("nr"); + } + } + } catch (SQLException e) { + logger.error(Localization.getText("DatabaseHandler.getFeatureCountFailure")); + logger.debug(e.getMessage()); + } + return count; + } + + +} diff --git a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/database/FeatureCache.java b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/database/FeatureCache.java new file mode 100644 index 0000000000000000000000000000000000000000..b797f2083565afce69e899d372b1bb9965a388fe --- /dev/null +++ b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/database/FeatureCache.java @@ -0,0 +1,329 @@ +package de.hft.stuttgart.citydoctor2.database; + +import com.github.benmanes.caffeine.cache.Caffeine; +import com.github.benmanes.caffeine.cache.LoadingCache; +import com.github.benmanes.caffeine.cache.RemovalCause; +import de.hft.stuttgart.citydoctor2.datastructure.CityObject; +import de.hft.stuttgart.citydoctor2.datastructure.GmlId; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Stream; + + +/** + * A managed cache for top-level CityObjects (Features). This cache is connected to the embedded database and will + * automatically load missing CityObjects from it. This cache is size limited and will evict entries using the + * Window Tiny LFU policy. + *

+ * While this class is not a singleton, it is advised to keep an Instance of this class for the whole lifecycle and + * reset and reuse it instead of creating new Objects, as the initialization is quite heavy and resets the embedded + * database. + *

+ *

+ * Avoid holding long-time strong references to CityObjects returned by the cache, as eviction will sever the + * connection between reference and cache, which will lead to conflicting Object states. + *

+ */ +public class FeatureCache implements CityObjectCache{ + + + private static final Logger logger = LogManager.getLogger(FeatureCache.class); + + private final LoadingCache cache; + private final EmbeddedDatabaseHandler handler; + private final AtomicInteger putsCounter = new AtomicInteger(0); + private CacheState state = CacheState.IDLE; + private final ConcurrentHashMap evictionLocks = new ConcurrentHashMap<>(); + + public FeatureCache() { + handler = new EmbeddedDatabaseHandler(); + cache = Caffeine.newBuilder().maximumSize(3000).removalListener((GmlId key, CityObject value, RemovalCause cause) -> { + if (value != null && cause.wasEvicted() && isFeatureMarshallable(value)){ + handler.marshallCityObject(value); + } + }).build(handler::unmarshallCityObject); + } + + /** + * Checks if the CityObject is currently being checked by a Checker-thread to prevent concurrent modifications by the + * Marshaller on eviction. + * @param co the CityObject + * @return true if the CityObject can be marshalled, false otherwise + */ + private boolean isFeatureMarshallable(CityObject co) { + return switch (state){ + case IDLE, PARSING -> true; + case CHECKING -> ! (evictionLocks.containsValue(co.getGmlId())); + }; + } + + @Override + public void put(CityObject cityObject) { + cache.put(cityObject.getGmlId(), cityObject); + switch (state){ + case IDLE: + break; + case PARSING: + int count = putsCounter.incrementAndGet(); + if (count >= 2500) { + batchMarshall(); + } + break; + case CHECKING: + evictionLocks.remove(Thread.currentThread()); + break; + } + } + + + private void batchMarshall(){ + logger.trace("Setting up batch Marshaller"); + Map cacheContent= new HashMap<>(cache.asMap()); + cache.invalidateAll(); + putsCounter.set(0); + + Thread batcher = new Thread(() -> { + logger.trace("Entered batch Marshaller"); + boolean success = handler.tryMarshallCityObjectMap(cacheContent); + if (!success) { + logger.trace("Batch marshalling in Thread failed, falling back to one-by-one marshalling"); + for (Map.Entry entry : cacheContent.entrySet()) { + handler.marshallCityObject(entry.getValue()); + } + } + logger.trace("Batch marshalling done"); + }); + batcher.start(); + logger.trace("Batch Marshaller started"); + } + + @Override + public CityObject get(GmlId id) { + if (state == CacheState.CHECKING){ + evictionLocks.put(Thread.currentThread(), id); + } + return cache.get(id); + } + + + + @Override + public void replace(GmlId id, CityObject cityObject) { + cache.invalidate(id); + cache.put(cityObject.getGmlId(), cityObject); + } + + @Override + public Stream getStream(List gmlIds) { + return gmlIds.stream().map(this::get); + } + + @Override + public int getTotalFeatureCount() { + return handler.getFeatureCount(); + } + + @Override + public void resetCache(){ + logger.trace("Resetting cache"); + cache.invalidateAll(); + putsCounter.set(0); + handler.setupFeaturesTable(); + } + + @Override + public List getErrorFeatureIds() { + return handler.getIdsOfAllCityObjectsWithErrors(); + + } + + /** + * Synchronizes CityObject states by updating Database with cache content. + */ + public void synchronize(){ + HashMap cacheContent= new HashMap<>(cache.asMap()); + boolean success = handler.tryMarshallCityObjectMap(cacheContent); + if (!success) { + logger.trace("Batch marshalling failed, falling back to one-by-one marshalling"); + for (Map.Entry entry : cacheContent.entrySet()) { + handler.marshallCityObject(entry.getValue()); + } + } + } + + /** + * Signals the cache that parsing is beginning. + */ + private boolean beginParsing(){ + return state.changeState(this, CacheState.PARSING); + } + + /** + * Signals the cache that parsing has finished. + */ + private void finishParsing() { + if (state == CacheState.PARSING && state.changeState(this, CacheState.IDLE)){ + return; + } + throw new IllegalStateException("Cache failed to exit parsing mode"); + } + + /** + * Signals the cache that checking is beginning. + */ + private boolean beginChecking(){ + return state.changeState(this, CacheState.CHECKING); + } + + /** + * Signals the cache that checking has finished. + */ + private void finishChecking() { + if (state == CacheState.CHECKING && state.changeState(this, CacheState.IDLE)){ + return; + } + throw new IllegalStateException("Cache failed to exit checking mode"); + } + + @Override + public AutoCloseable startParsingMode(){ + if (this.beginParsing()){ + return this::finishParsing; + } else throw new IllegalStateException("Cache is not in IDLE state, cannot start parsing mode"); + } + + @Override + public AutoCloseable startCheckingMode(){ + if (this.beginChecking()){ + return this::finishChecking; + } else throw new IllegalStateException("Cache is not in IDLE state, cannot start checking mode"); + } + + protected void setState(CacheState state) { + this.state = state; + } + + public CacheState getState() { + return state; + } + + public enum CacheState { + IDLE { + @Override + protected boolean changeState(FeatureCache cache, CacheState nextState) { + if (cache.getState() != this){ + logger.debug("FeatureCache invoked changeState() of IDLE state while cache state is {}", cache.getState()); + return false; + } + this.onExit(cache); + cache.setState(nextState); + nextState.onEntry(cache); + return true; + } + + @Override + public void onEntry(FeatureCache cache) { + logger.trace("FeatureCache: Entering IDLE state"); + // Idle state does nothing on entry + } + + @Override + protected void onExit(FeatureCache cache) { + logger.trace("FeatureCache: Leaving IDLE state"); + // Idle state does nothing on exit + } + + }, PARSING { + @Override + protected boolean changeState(FeatureCache cache, CacheState nextState) { + if (cache.getState() != this){ + logger.debug("FeatureCache invoked changeState() of PARSING state while cache state is {}", cache.getState()); + return false; + } + boolean success = false; + switch (nextState){ + case IDLE: + this.onExit(cache); + cache.setState(CacheState.IDLE); + success = true; + break; + case PARSING: + logger.debug("Tried to set cache to PARSING state while already parsing"); + break; + case CHECKING: + logger.debug("Tried to set cache to CHECKING state while parsing"); + break; + } + return success; + } + + @Override + public void onEntry(FeatureCache cache) { + logger.trace("FeatureCache: Entering PARSING state"); + cache.resetCache(); + } + + @Override + protected void onExit(FeatureCache cache) { + logger.trace("FeatureCache: Leaving PARSING state"); + cache.synchronize(); + } + + }, CHECKING { + @Override + protected boolean changeState(FeatureCache cache, CacheState nextState) { + if (cache.getState() != this){ + logger.debug("FeatureCache invoked changeState() of CHECKING state while cache state is {}", cache.getState()); + return false; + } + boolean success = false; + switch (nextState){ + case IDLE: + this.onExit(cache); + cache.setState(CacheState.IDLE); + success = true; + break; + case PARSING: + logger.debug("Tried to set cache to PARSING state while checking"); + break; + case CHECKING: + logger.debug("Tried to set cache to CHECKING state while already checking"); + break; + } + return success; + } + + @Override + public void onEntry(FeatureCache cache) { + logger.trace("FeatureCache: Entering CHECKING state"); + + } + + @Override + protected void onExit(FeatureCache cache) { + logger.trace("FeatureCache: Leaving CHECKING state"); + cache.synchronize(); + } + + + }; + + /** + * Signals the statemachine to change the state of the FeatureCache. Returns true if the state successfully + * changed, false otherwise with the FeatureCache remaining in its current state. + * @param cache the FeatureCache instance + * @param nextState the requested next state + * @return true if the cache successfully changed state, false otherwise + */ + protected abstract boolean changeState(FeatureCache cache, CacheState nextState); + protected abstract void onEntry(FeatureCache cache); + protected abstract void onExit(FeatureCache cache); + } +} + diff --git a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/database/UnconnectedCache.java b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/database/UnconnectedCache.java new file mode 100644 index 0000000000000000000000000000000000000000..8033e63461e8719c59b4946da2513db40bf9ba35 --- /dev/null +++ b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/database/UnconnectedCache.java @@ -0,0 +1,85 @@ +package de.hft.stuttgart.citydoctor2.database; + +import de.hft.stuttgart.citydoctor2.datastructure.CityDoctorModel; +import de.hft.stuttgart.citydoctor2.datastructure.CityObject; +import de.hft.stuttgart.citydoctor2.datastructure.GmlId; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Stream; + +/** + * An adapter implementation for CityObjectCache, wrapping the Interface around a simple HashMap. + *

+ * This class is intended to allow parsing or checking {@link CityDoctorModel CityDoctorModels} in specific cases where the model + * must not use the {@link FeatureCache}, like resolving of {@link de.hft.stuttgart.citydoctor2.datastructure.LibraryObject LibraryObject} + * files or mocking of the Interface in unit tests. + * + */ +public class UnconnectedCache implements CityObjectCache{ + + private final Map cache; + private boolean idle = true; + + public UnconnectedCache() { + cache = new HashMap<>(); + } + + @Override + public void put(CityObject cityObject) { + cache.put(cityObject.getGmlId(), cityObject); + } + + @Override + public CityObject get(GmlId id) { + return cache.get(id); + } + + @Override + public void replace(GmlId id, CityObject cityObject) { + cache.put(id, cityObject); + } + + @Override + public Stream getStream(List ids) { + return cache.values().stream().filter(c -> ids.contains(c.getGmlId())); + } + + @Override + public int getTotalFeatureCount() { + return cache.size(); + } + + public void resetCache(){ + cache.clear(); + } + + @Override + public List getErrorFeatureIds() { + List errorFeatureIds = new ArrayList<>(); + cache.forEach((gmlId, cityObject) ->{ + if (cityObject.containsAnyError()){ + errorFeatureIds.add(cityObject.getGmlId()); + } + }); + return errorFeatureIds; + } + + @Override + public AutoCloseable startParsingMode() { + if (idle){ + idle = false; + return ()-> idle=true; + } else throw new IllegalStateException("Cache is not idle, could not start parsing mode"); + } + + @Override + public AutoCloseable startCheckingMode() { + if (idle){ + idle = false; + return ()-> idle=true; + } else throw new IllegalStateException("Cache is not idle, could not start checking mode"); + } +} diff --git a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/BoundarySurface.java b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/BoundarySurface.java index 9fa5066c6b7917a93c983831d4a05b99df03c0c3..c3dd9d63d95482e9e1bf942bc60755c036988079 100644 --- a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/BoundarySurface.java +++ b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/BoundarySurface.java @@ -40,7 +40,7 @@ public class BoundarySurface extends CityObject { @Serial private static final long serialVersionUID = 8793865135393496408L; - private SurfaceFeatureType featureType; + private BoundarySurfaceType type; private final List openings = new ArrayList<>(2); @@ -49,18 +49,14 @@ public class BoundarySurface extends CityObject { private AbstractThematicSurface gmlObject; public BoundarySurface(AbstractThematicSurface aco) { - this(SurfaceFeatureType.BUILDING, BoundarySurfaceType.UNDEFINED, aco); + this(BoundarySurfaceType.UNDEFINED, aco); } - public BoundarySurface(SurfaceFeatureType featureType, BoundarySurfaceType type, AbstractThematicSurface aco) { - this.featureType = featureType; + public BoundarySurface(BoundarySurfaceType type, AbstractThematicSurface aco) { this.type = type; gmlObject = aco; } - public void setFeatureType(SurfaceFeatureType featureType) { - this.featureType = featureType; - } public void setType(BoundarySurfaceType type) { this.type = type; @@ -70,9 +66,6 @@ public class BoundarySurface extends CityObject { this.gmlObject = gmlObject; } - public SurfaceFeatureType getSurfaceFeatureType() { - return featureType; - } public BoundarySurfaceType getType() { return type; diff --git a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/BoundingBox.java b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/BoundingBox.java index f2d535fefc886a4b077859379718bf1a0323a35c..bf5ac32651cdd9f0f4c048e8dc5e6764feed8e04 100644 --- a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/BoundingBox.java +++ b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/BoundingBox.java @@ -20,9 +20,11 @@ package de.hft.stuttgart.citydoctor2.datastructure; import de.hft.stuttgart.citydoctor2.math.Vector3d; import de.hft.stuttgart.citydoctor2.utils.BoundingBoxCalculator; +import de.hft.stuttgart.citydoctor2.utils.visitors.MinMaxExtentVisitor; import java.util.Collection; import java.util.List; +import java.util.Locale; /** * An axis aligned bounding box represented by its two corners @@ -47,6 +49,12 @@ public class BoundingBox { return BoundingBoxCalculator.calculateBoundingBoxFromPoints(points); } + public static BoundingBox of(CityObject co) { + MinMaxExtentVisitor mima = new MinMaxExtentVisitor(); + co.accept(mima); + return BoundingBox.of(mima.getMinMaxExtent()); + } + /** * Creates an axis aligned bounding box of the whole model. * @@ -161,4 +169,45 @@ public class BoundingBox { public double getDiagonalLength() { return bbox[1].getDistance(bbox[0]); } + + /** + * Returns whether this BoundinBox is undefined, meaning that one or all corners are infinite. + * @return True if the BoundingBox is undefined, false otherwise + */ + public boolean isUndefined(){ + double x1 = bbox[0].getX(); + double y1 = bbox[0].getY(); + double x2 = bbox[1].getX(); + double y2 = bbox[1].getY(); + return (Double.isInfinite(x1) || Double.isInfinite(y1) || Double.isInfinite(x2) || Double.isInfinite(y2)); + } + + /** + * Returns an axis-aligned 2D polygon projection of this bbox as a WKT String. + *

+ * An undefined bbox will return an empty polygon. + * @return The 2D polygon WKT for this bbox + */ + public String to2DWkt() { + if (this.isUndefined()){ + return "POLYGON EMPTY"; + } + double x1 = bbox[0].getX(); + double y1 = bbox[0].getY(); + double x2 = bbox[1].getX(); + double y2 = bbox[1].getY(); + + double minX = Math.min(x1, x2); + double minY = Math.min(y1, y2); + double maxX = Math.max(x1, x2); + double maxY = Math.max(y1, y2); + + return String.format(Locale.ROOT,"POLYGON((%.3f %.3f, %.3f %.3f, %.3f %.3f, %.3f %.3f, %.3f %.3f))", + minX, minY, + maxX, minY, + maxX, maxY, + minX, maxY, + minX, minY + ); + } } diff --git a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/BridgeObject.java b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/BridgeObject.java index b87b232e05b2edcbb9c3d544dd78271b920c6ff1..f87d6feaabee26656fca23da56fe725f9a542681 100644 --- a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/BridgeObject.java +++ b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/BridgeObject.java @@ -61,15 +61,11 @@ public class BridgeObject extends CityObject { private BridgeObject parent; public BridgeObject(AbstractBridge ab) { - this.ab = ab; - this.type = BridgeType.BRIDGE; - this.parent = null; + this(BridgeType.BRIDGE, ab, null); } public BridgeObject(AbstractBridge ab, BridgeObject parent) { - this.ab = ab; - this.type = BridgeType.BRIDGE_PART; - this.parent = parent; + this(BridgeType.BRIDGE_PART, ab, parent); } private BridgeObject(BridgeType type, AbstractBridge ab, BridgeObject parent) { diff --git a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/BuildingConstructiveElement.java b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/BuildingConstructiveElement.java index 06763aeb0424a67c0874014f45468214d09a18f7..8ac60a11ac54a504deddfbe30bfe603fdcaf6af1 100644 --- a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/BuildingConstructiveElement.java +++ b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/BuildingConstructiveElement.java @@ -1,25 +1,22 @@ package de.hft.stuttgart.citydoctor2.datastructure; -import de.hft.stuttgart.citydoctor2.check.CheckableVisitor; -import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration; -import de.hft.stuttgart.citydoctor2.utils.CityGmlUtils; -import javafx.scene.paint.Color; +import java.io.Serial; +import java.util.ArrayList; +import java.util.List; + import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.citygml4j.core.model.core.AbstractSpaceBoundaryProperty; -import org.citygml4j.core.model.deprecated.bridge.DeprecatedPropertiesOfBridgeConstructiveElement; import org.citygml4j.core.util.geometry.GeometryFactory; -import org.xmlobjects.gml.model.geometry.GeometryProperty; import org.xmlobjects.gml.model.geometry.aggregates.MultiSurface; import org.xmlobjects.gml.model.geometry.aggregates.MultiSurfaceProperty; -import org.xmlobjects.gml.model.geometry.complexes.CompositeSurface; import org.xmlobjects.gml.model.geometry.primitives.Solid; import org.xmlobjects.gml.model.geometry.primitives.SolidProperty; -import org.xmlobjects.gml.model.geometry.primitives.SurfaceProperty; -import java.io.Serial; -import java.util.ArrayList; -import java.util.List; +import de.hft.stuttgart.citydoctor2.check.CheckableVisitor; +import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration; +import de.hft.stuttgart.citydoctor2.utils.CityGmlUtils; +import javafx.scene.paint.Color; public class BuildingConstructiveElement extends CityObject { diff --git a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/CityDoctorModel.java b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/CityDoctorModel.java index 41b2b003f4b2a7581b20a263405e6c2db74b3d17..ba0be98f219adfe4c55ff770fa05c6bdca1a70f9 100644 --- a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/CityDoctorModel.java +++ b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/CityDoctorModel.java @@ -20,6 +20,8 @@ package de.hft.stuttgart.citydoctor2.datastructure; import de.hft.stuttgart.citydoctor2.check.CheckableUtilsVisitor; import de.hft.stuttgart.citydoctor2.check.CheckError; +import de.hft.stuttgart.citydoctor2.check.CheckableVisitor; +import de.hft.stuttgart.citydoctor2.database.CityObjectCache; import de.hft.stuttgart.citydoctor2.exceptions.CityDoctorWriteException; import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration; import de.hft.stuttgart.citydoctor2.writer.CityGMLWriterUtils; @@ -45,15 +47,15 @@ import java.util.stream.Stream; public class CityDoctorModel { private static final String COULD_NOT_FIND_FEATURE = "Could not find feature: "; - private final List buildings; - private final List vegetation; - private final List bridges; - private final List cityfurniture; - private final List genericObjects; - private final List land; - private final List roads; - private final List tunnels; - private final List water; + private final List buildings; + private final List vegetation; + private final List bridges; + private final List cityfurniture; + private final List genericObjects; + private final List land; + private final List roads; + private final List tunnels; + private final List water; private CityModel cModel; private final ParserConfiguration config; private final String fileName; @@ -62,11 +64,15 @@ public class CityDoctorModel { private boolean isValidated = false; private ValidationPlan plan; private CityGMLVersion cityGMLVersion; + private final CityObjectCache cache; - public CityDoctorModel(ParserConfiguration config, File file) { + public CityDoctorModel(ParserConfiguration config, File file, CityObjectCache cache) { if (config == null) { throw new IllegalArgumentException("Parser configuration may not be null"); } + if( file == null ) { + throw new IllegalArgumentException("File may not be null"); + } this.fileName = file.getName(); this.config = config; this.file = file; @@ -80,6 +86,7 @@ public class CityDoctorModel { cityfurniture = new ArrayList<>(); genericObjects = new ArrayList<>(); globalErrors = new ArrayList<>(); + this.cache = cache; } public boolean isValidated() { @@ -117,8 +124,59 @@ public class CityDoctorModel { } public Stream createFeatureStream() { - return Stream.of(buildings.stream(), vegetation.stream(), bridges.stream(), land.stream(), roads.stream(), - tunnels.stream(), water.stream(), cityfurniture.stream(), genericObjects.stream()).flatMap(co -> co); + return Stream.of(getBuildings(), getVegetation(), getBridges(), getLand(), getTransportation(), + getTunnels(), getWater(), getCityFurniture(), getOtherCityObjects()).flatMap(co -> co); + } + + public List getFeatureIds() { + List featureIds = new ArrayList<>(); + featureIds.addAll(buildings); + featureIds.addAll(vegetation); + featureIds.addAll(bridges); + featureIds.addAll(land); + featureIds.addAll(roads); + featureIds.addAll(tunnels); + featureIds.addAll(water); + featureIds.addAll(cityfurniture); + featureIds.addAll(genericObjects); + return featureIds; + + } + + public boolean containsGmlId(String id) { + if (id == null) { + return false; + } + GmlId gmlId = new GmlId(id); + if (buildings.contains(gmlId)) { + return true; + } + if (vegetation.contains(gmlId)) { + return true; + } + if (bridges.contains(gmlId)) { + return true; + } + if (land.contains(gmlId)) { + return true; + } + if (roads.contains(gmlId)) { + return true; + } + if (tunnels.contains(gmlId)) { + return true; + } + if (water.contains(gmlId)) { + return true; + } + if (cityfurniture.contains(gmlId)) { + return true; + } + return genericObjects.contains(gmlId); + } + + public void accept(CheckableVisitor visitor) { + createFeatureStream().forEach(cityObject -> cityObject.accept(visitor)); } public void saveAs(String file, boolean saveQualityAde) throws CityDoctorWriteException { @@ -136,6 +194,7 @@ public class CityDoctorModel { } } + private void exportAsGML(String file) throws CityDoctorWriteException { CityGMLWriterUtils.writeCityModel(file, this); } @@ -215,106 +274,201 @@ public class CityDoctorModel { public Set collectErrors() { List errors = new ArrayList<>(); - collectErrorsFromList(errors, buildings); - collectErrorsFromList(errors, vegetation); - collectErrorsFromList(errors, bridges); - collectErrorsFromList(errors, land); - collectErrorsFromList(errors, roads); - collectErrorsFromList(errors, tunnels); - collectErrorsFromList(errors, water); - collectErrorsFromList(errors, cityfurniture); - collectErrorsFromList(errors, genericObjects); + createFeatureStream().forEach(cityObject -> cityObject.collectErrors(errors)); return new HashSet<>(errors); } - private void collectErrorsFromList(List errors, List cos) { - for (CityObject co : cos) { - co.collectContainedErrors(errors); - } - } public String getFileName() { return fileName; } - public void addBridge(BridgeObject coBridge) { - bridges.add(coBridge); - } public void addBuilding(Building coBuilding) { - buildings.add(coBuilding); + buildings.add(coBuilding.getGmlId()); + cache.put(coBuilding); } - public List getBuildings() { + public void removeFeature(GmlId id){ + buildings.remove(id); + vegetation.remove(id); + bridges.remove(id); + land.remove(id); + roads.remove(id); + tunnels.remove(id); + water.remove(id); + cityfurniture.remove(id); + genericObjects.remove(id); + } + + public Stream getBuildings() { + return buildings.stream().map(co -> (Building) cache.get(co)); + } + + public List getBuildingIds() { return buildings; } - public List getBridges() { + public int getBuildingCount(){ + return buildings.size(); + } + + public void addBridge(BridgeObject coBridge) { + bridges.add(coBridge.getGmlId()); + cache.put(coBridge); + } + + public Stream getBridges() { + return bridges.stream().map(co -> (BridgeObject) cache.get(co)); + } + + public List getBridgeIds() { return bridges; } - public List getCityFurniture() { - return cityfurniture; + public int getBridgeCount(){ + return bridges.size(); } public void addCityFurniture(CityFurniture coFurniture) { - cityfurniture.add(coFurniture); + cityfurniture.add(coFurniture.getGmlId()); + cache.put(coFurniture); + } + + public Stream getCityFurniture() { + return cityfurniture.stream().map(co -> (CityFurniture) cache.get(co)); + } + + public List getCityFurnitureIds() { + return cityfurniture; + } + + public int getCityFurnitureCount(){ + return cityfurniture.size(); + } + + public void addOtherCityObject(CityObject otherCityObject) { + genericObjects.add(otherCityObject.getGmlId()); + cache.put(otherCityObject); } - public List getGenericCityObjects() { + public Stream getOtherCityObjects() { + return genericObjects.stream().map(cache::get); + } + + public List getOtherCityObjectsIds() { return genericObjects; } - public void addGenericCityObject(GenericCityObject coGenericCityObject) { - genericObjects.add(coGenericCityObject); + public int getOtherCityObjectsCount(){ + return genericObjects.size(); } - public void setCityModel(CityModel cModel) { - this.cModel = cModel; + public void addTransportation(TransportationObject to) { + roads.add(to.getGmlId()); + cache.put(to); } - public CityModel getCityModel() { - return cModel; + public Stream getTransportation() { + return roads.stream().map(co -> (TransportationObject) cache.get(co)); } - public List getTransportation() { + public List getTransportationIds() { return roads; } - public List getTunnels() { - return tunnels; + public int getTransportationCount(){ + return roads.size(); } - public List getWater() { - return water; + public void addTunnel(Tunnel tunnel) { + tunnels.add(tunnel.getGmlId()); + cache.put(tunnel); } - public List getLand() { - return land; + public Stream getTunnels() { + return tunnels.stream().map(co -> (Tunnel) cache.get(co)); } - public List getVegetation() { - return vegetation; + public List getTunnelIds() { + return tunnels; + } + + public int getTunnelCount(){ + return tunnels.size(); } public void addWater(WaterObject wo) { - water.add(wo); + water.add(wo.getGmlId()); + cache.put(wo); + } + + public Stream getWater() { + return water.stream().map(co -> (WaterObject) cache.get(co)); + } + + public List getWaterIds() { + return water; + } + + public int getWaterCount(){ + return water.size(); } public void addLand(LandObject lo) { - land.add(lo); + land.add(lo.getGmlId()); + cache.put(lo); + } + + public void addRelief(ReliefObject relief) { + land.add(relief.getGmlId()); + cache.put(relief); + } + + public void addTin(TinObject tin) { + land.add(tin.getGmlId()); + cache.put(tin); + } + + public Stream getLand() { + return land.stream().map(cache::get); + } + + public List getLandIds() { + return land; + } + + public int getLandCount(){ + return land.size(); } public void addVegetation(Vegetation veg) { - vegetation.add(veg); + vegetation.add(veg.getGmlId()); + cache.put(veg); } - public void addTransportation(TransportationObject to) { - roads.add(to); + public Stream getVegetation() { + return vegetation.stream().map(co -> (Vegetation) cache.get(co)); } - public void addTunnel(Tunnel tunnel) { - tunnels.add(tunnel); + public List getVegetationIds() { + return vegetation; + } + + public int getVegetationCount(){ + return vegetation.size(); + } + + public void setCityModel(CityModel cModel) { + this.cModel = cModel; + } + + public CityModel getCityModel() { + return cModel; + } + + public CityObjectCache getCache(){ + return cache; } public int getNumberOfFeatures() { @@ -349,100 +503,109 @@ public class CityDoctorModel { } private void replaceWaterObject(CityObject currentFeature, CityObject nextFeature) { - int index = water.indexOf(currentFeature); + int index = water.indexOf(currentFeature.getGmlId()); if (index == -1) { throw new IllegalStateException(COULD_NOT_FIND_FEATURE + currentFeature + " in water objects"); } - water.set(index, (WaterObject) nextFeature); + cache.replace(currentFeature.getGmlId(), nextFeature); + water.set(index, nextFeature.getGmlId()); } private void replaceLandObject(CityObject currentFeature, CityObject nextFeature) { - int index = land.indexOf(currentFeature); + int index = land.indexOf(currentFeature.getGmlId()); if (index == -1) { throw new IllegalStateException(COULD_NOT_FIND_FEATURE + currentFeature + " in land objects"); } - land.set(index, nextFeature); + cache.replace(currentFeature.getGmlId(), nextFeature); + land.set(index, nextFeature.getGmlId()); } private void replaceVegetation(CityObject currentFeature, CityObject nextFeature) { - int index = vegetation.indexOf(currentFeature); + int index = vegetation.indexOf(currentFeature.getGmlId()); if (index == -1) { throw new IllegalStateException(COULD_NOT_FIND_FEATURE + currentFeature + " in vegetation"); } - vegetation.set(index, (Vegetation) nextFeature); + cache.replace(currentFeature.getGmlId(), nextFeature); + vegetation.set(index, nextFeature.getGmlId()); } private void replaceCityFurniture(CityObject currentFeature, CityObject nextFeature) { - int index = cityfurniture.indexOf(currentFeature); + int index = cityfurniture.indexOf(currentFeature.getGmlId()); if (index == -1) { throw new IllegalStateException(COULD_NOT_FIND_FEATURE + currentFeature + " in vegetation"); } - cityfurniture.set(index, (CityFurniture) nextFeature); + cache.replace(currentFeature.getGmlId(), nextFeature); + cityfurniture.set(index, nextFeature.getGmlId()); } private void replaceGenericCityObject(CityObject currentFeature, CityObject nextFeature) { - int index = genericObjects.indexOf(currentFeature); + int index = genericObjects.indexOf(currentFeature.getGmlId()); if (index == -1) { throw new IllegalStateException(COULD_NOT_FIND_FEATURE + currentFeature + " in generic city objects"); } - genericObjects.set(index, (GenericCityObject) nextFeature); + cache.replace(currentFeature.getGmlId(), nextFeature); + genericObjects.set(index, nextFeature.getGmlId()); } private void replaceTransportationObject(CityObject currentFeature, CityObject nextFeature) { - int index = roads.indexOf(currentFeature); + int index = roads.indexOf(currentFeature.getGmlId()); if (index == -1) { throw new IllegalStateException(COULD_NOT_FIND_FEATURE + currentFeature + " in transportation objects"); } - roads.set(index, (TransportationObject) nextFeature); + cache.replace(currentFeature.getGmlId(), nextFeature); + roads.set(index, nextFeature.getGmlId()); } private void replaceTunnel(CityObject currentFeature, CityObject nextFeature) { - int index = tunnels.indexOf(currentFeature); + int index = tunnels.indexOf(currentFeature.getGmlId()); if (index == -1) { throw new IllegalStateException(COULD_NOT_FIND_FEATURE + currentFeature + " in tunnels"); } - tunnels.set(index, (Tunnel) nextFeature); + cache.replace(currentFeature.getGmlId(), nextFeature); + tunnels.set(index, nextFeature.getGmlId()); } private void replaceBridge(CityObject currentFeature, CityObject nextFeature) { - int index = bridges.indexOf(currentFeature); + int index = bridges.indexOf(currentFeature.getGmlId()); if (index == -1) { throw new IllegalStateException(COULD_NOT_FIND_FEATURE + currentFeature + " in bridges"); } - bridges.set(index, (BridgeObject) nextFeature); + cache.replace(currentFeature.getGmlId(), nextFeature); + bridges.set(index, nextFeature.getGmlId()); } private void replaceBuilding(CityObject currentFeature, CityObject nextFeature) { - int index = buildings.indexOf(currentFeature); + int index = buildings.indexOf(currentFeature.getGmlId()); if (index == -1) { throw new IllegalStateException(COULD_NOT_FIND_FEATURE + currentFeature + " in buildings"); } - buildings.set(index, (Building) nextFeature); + cache.replace(currentFeature.getGmlId(), nextFeature); + buildings.set(index, nextFeature.getGmlId()); } public void addCityObject(CityObject co) { if (co instanceof Building b) { - buildings.add(b); + buildings.add(b.getGmlId()); } else if (co instanceof BridgeObject bo) { - bridges.add(bo); + bridges.add(bo.getGmlId()); } else if (co instanceof TransportationObject to) { - roads.add(to); + roads.add(to.getGmlId()); } else if (co instanceof Tunnel tu) { - tunnels.add(tu); + tunnels.add(tu.getGmlId()); } else if (co instanceof Vegetation veg) { - vegetation.add(veg); + vegetation.add(veg.getGmlId()); } else if (co instanceof LandObject lo) { - land.add(lo); + land.add(lo.getGmlId()); } else if (co instanceof WaterObject wo) { - water.add(wo); + water.add(wo.getGmlId()); } else if (co instanceof ReliefObject) { - land.add(co); + land.add(co.getGmlId()); } else if (co instanceof TinObject) { - land.add(co); + land.add(co.getGmlId()); } else if (co instanceof CityFurniture cf) { - cityfurniture.add(cf); + cityfurniture.add(cf.getGmlId()); } else if (co instanceof GenericCityObject gco) { - genericObjects.add(gco); + genericObjects.add(gco.getGmlId()); } } @@ -454,11 +617,4 @@ public class CityDoctorModel { return cityGMLVersion; } - public void addRelief(ReliefObject relief) { - addCityObject(relief); - } - - public void addTin(TinObject tin) { - addCityObject(tin); - } } diff --git a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/FeatureType.java b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/FeatureType.java index cb49e1e0be23185738391db890f127310de131c0..11a8e687b14ee8ba5a78cb68c0c2374878de7156 100644 --- a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/FeatureType.java +++ b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/FeatureType.java @@ -27,5 +27,5 @@ public enum FeatureType { BUILDING, TRANSPORTATION, VEGETATION, BRIDGE, LAND, WATER, BOUNDARY_SURFACE, INSTALLATION, OPENING, BUILDING_PART, BUILDING_SUBDIVISION, BRIDGE_CONSTRUCTION_ELEMENT, BRIDGE_INSTALLATION, ROOM, FURNITURE, CITY_FURNITURE, - GENERIC_CITY_OBJECT, TUNNEL, TUNNEL_PART, TUNNEL_CONSTRUCTION_ELEMENT, TUNNEL_INSTALLATION, + OTHER_CITY_OBJECT, TUNNEL, TUNNEL_PART, TUNNEL_CONSTRUCTION_ELEMENT, TUNNEL_INSTALLATION, } diff --git a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/GenericAttribute.java b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/GenericAttribute.java index 041c688b98d2a2f5cd3bb1dc7479967545dd5f68..835a0fd2b3f21875dfe6d8eeca34c8e6015b9f01 100644 --- a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/GenericAttribute.java +++ b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/GenericAttribute.java @@ -5,8 +5,16 @@ import org.apache.logging.log4j.Logger; import org.citygml4j.core.model.core.AbstractGenericAttributeProperty; import org.citygml4j.core.model.generics.*; +import java.io.Serial; +import java.io.Serializable; -public class GenericAttribute { +import java.util.List; + + +public class GenericAttribute implements Serializable { + + @Serial + private static final long serialVersionUID = -4101408947632132328L; private static final Logger logger = LogManager.getLogger(GenericAttribute.class); @@ -45,6 +53,22 @@ public class GenericAttribute { } else if (attributeProperty.getObject() instanceof CodeAttribute ca) { type = String.format("CodeAttribute (%s)", ca.getValue().getLanguage()); value = String.format("'''%s''' %n CodeSpace: %s", ca.getValue().getValue(), ca.getValue().getCodeSpace()); + } else if (attributeProperty.getObject() instanceof GenericAttributeSet gas) { + type = "GenericAttributeSet"; + List attributes = gas.getValue(); + StringBuilder sb = new StringBuilder(); + sb.append("{"); + for (AbstractGenericAttributeProperty attribute : attributes) { + if (attribute.getObject() != null) { + sb.append(attribute.getObject().getName()); + sb.append(" = "); + sb.append(attribute.getObject().getValue()); + sb.append("; "); + } + } + sb.replace(sb.length() - 1, sb.length(), "}"); + value = String.format("'%s'", sb); + } else { logger.warn("GenericAttribute {} is of unknown type {}", attributeProperty, attributeProperty.getObject()); value = attributeProperty.getObject().getValue().toString(); diff --git a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/GenericCityObject.java b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/GenericCityObject.java index 34a0d022d9975433061979ff8043e724dd38f5b8..a8aa7bfb1a0c89fd3b0e3780400a7d1031d09421 100644 --- a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/GenericCityObject.java +++ b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/GenericCityObject.java @@ -111,7 +111,7 @@ public class GenericCityObject extends CityObject { cgmlGos.getDeprecatedProperties().setLod4Geometry(new SolidProperty(solid)); break; default: - throw new IllegalStateException("Cannot add " + geom.getLod() + " solid to buildings"); + throw new IllegalStateException("Cannot add " + geom.getLod() + " solid to generic city object"); } } @Override @@ -121,7 +121,7 @@ public class GenericCityObject extends CityObject { @Override public FeatureType getFeatureType() { - return FeatureType.GENERIC_CITY_OBJECT; + return FeatureType.OTHER_CITY_OBJECT; } public List getBoundarySurfaces() { diff --git a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/Geometry.java b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/Geometry.java index d7c17240faa18fbbd5a789468956d4ac75983b18..f2c0d41942e725d652ad7e9567285902f0a78d9d 100644 --- a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/Geometry.java +++ b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/Geometry.java @@ -26,6 +26,8 @@ import de.hft.stuttgart.citydoctor2.utils.BoundingBoxCalculator; import de.hft.stuttgart.citydoctor2.utils.SerializablePair; import javafx.scene.paint.Color; +import java.io.IOException; +import java.io.ObjectInputStream; import java.io.Serial; import java.util.*; @@ -53,9 +55,9 @@ public class Geometry extends GmlElement { private CityObject parent; private final List polygons = new ArrayList<>(2); - private List edges; - private Map, Edge> edgeMap; - private List vertices; + private transient List edges; + private transient Map, Edge> edgeMap; + private transient List vertices; private Orientation orientation; public Geometry(GeometryType type, Lod lod, Orientation orientation) { @@ -344,6 +346,12 @@ public class Geometry extends GmlElement { return false; } + @Serial + private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { + in.defaultReadObject(); + edges = new ArrayList<>(); + edgeMap = new HashMap<>(); + } public void clearMetaData() { if (vertices != null) { diff --git a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/ImplicitGeometryHolder.java b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/ImplicitGeometryHolder.java index 872725ee41cc8342b4314d99e00aaf3ba7eeee05..8285eb93603f0dee513600bb648b20d1e0c9f80b 100644 --- a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/ImplicitGeometryHolder.java +++ b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/ImplicitGeometryHolder.java @@ -1,8 +1,14 @@ package de.hft.stuttgart.citydoctor2.datastructure; import java.io.Serial; +import java.util.HashSet; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; import de.hft.stuttgart.citydoctor2.check.CheckableVisitor; +import de.hft.stuttgart.citydoctor2.database.CityObjectCache; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import org.citygml4j.core.model.core.ImplicitGeometry; import de.hft.stuttgart.citydoctor2.math.TransformationMatrix; @@ -16,9 +22,15 @@ public class ImplicitGeometryHolder extends Geometry { @Serial private static final long serialVersionUID = -8938931081577196349L; + private static final Logger logger = LogManager.getLogger(ImplicitGeometryHolder.class); - private ImplicitGeometry cgmlImplicitGeometry = null; + public enum PrototypeGeometryType { + LIBRARY_OBJECT, RELATIVE_GEOMETRY + } + + private ImplicitGeometry cgmlImplicitGeometry = null; + private static ConcurrentHashMap deferredRelGeomObjects = new ConcurrentHashMap<>(); private final PrototypeGeometryType type; private final Geometry prototypeGeometry; @@ -38,7 +50,46 @@ public class ImplicitGeometryHolder extends Geometry { applyTransformation(); } + public static ImplicitGeometryHolder deferRelativeGeomParsing(ImplicitGeometry ig, Lod lod) { + ImplicitGeometryHolder igh = new ImplicitGeometryHolder(lod); + deferredRelGeomObjects.put(igh, ig); + return igh; + } + public static void resolveDeferredObjects(CityObjectCache cache) { + Set missingGeoms = new HashSet<>(); + if(!deferredRelGeomObjects.isEmpty()) { + logger.info("Resolving deferred relative geometries"); + } + for (ImplicitGeometryHolder key : deferredRelGeomObjects.keySet()) { + ImplicitGeometry ig = deferredRelGeomObjects.get(key); + String hrefId = ig.getRelativeGeometry().getHref(); + hrefId = hrefId.startsWith("#") ? hrefId.substring(1) : hrefId; + GmlId gmlId = new GmlId(hrefId); + RelativeGeometry relGeom = RelativeGeometry.of(gmlId); + if (relGeom != null) { + ImplicitGeometryHolder igh = new ImplicitGeometryHolder(ig, relGeom); + CityObject parent = cache.get(key.getParent().getGmlId()); + parent.removeGeometry(igh.getLod(), igh.getType()); + parent.addGeometry(igh); + } else { + missingGeoms.add(gmlId); + } + } + if (!missingGeoms.isEmpty()) { + logger.warn("RelativeGeometries of the following gmlIDs could not be resolved: {}", missingGeoms); + } + deferredRelGeomObjects.clear(); + if (logger.isDebugEnabled()) { + logger.debug("Resolving HRef geometries finished"); + } + } + + private ImplicitGeometryHolder(Lod lod) { + super(null, lod, null); + type = null; + prototypeGeometry = new Geometry(null, lod, null); + } /** * Applies the transformation matrix of the implicit geometry to a copy of the reference geometry and copies the resulting * transformed geometry into this object. @@ -54,6 +105,30 @@ public class ImplicitGeometryHolder extends Geometry { return type; } + /** + * Resets the Object maps of {@link RelativeGeometry} and {@link LibraryObject} to prevent memory and data leaks + */ + public static void resetObjectMaps() { + RelativeGeometry.resetObjectMap(); + LibraryObject.resetObjectMap(); + } + + /** + * Prepares the prototype geometries for checking and sets a lock to prevent clearing of metadata + */ + public static void preparePrototypeGeometriesForChecking(){ + RelativeGeometry.preparePrototypeGeometriesForChecking(); + LibraryObject.preparePrototypeGeometriesForChecking(); + } + + /** + * Clears metadata creating for checking of prototype geometries and releases the metadata lock + */ + public static void clearMetaDataOfPrototypeGeometries(){ + RelativeGeometry.clearMetaDataOfPrototypeGeometries(); + LibraryObject.clearMetaDataOfPrototypeGeometries(); + } + @Override public void accept(CheckableVisitor c) { prototypeGeometry.accept(c); @@ -64,8 +139,5 @@ public class ImplicitGeometryHolder extends Geometry { return prototypeGeometry.isValidated(); } - public enum PrototypeGeometryType { - LIBRARY_OBJECT, RELATIVE_GEOMETRY - } } diff --git a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/LibraryObject.java b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/LibraryObject.java index f757da769a1b138b12fed1a530cc3f0d1f3b6934..557cd3ef4fd52841d05c45c37062a0eb32778b64 100644 --- a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/LibraryObject.java +++ b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/LibraryObject.java @@ -4,7 +4,7 @@ import de.hft.stuttgart.citydoctor2.parser.CityGmlParseException; import de.hft.stuttgart.citydoctor2.parser.CityGmlParser; import de.hft.stuttgart.citydoctor2.parser.InvalidGmlFileException; import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration; -import de.hft.stuttgart.citydoctor2.zip.CityGmlZipEntry; +import de.hft.stuttgart.citydoctor2.utils.Localization; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -26,8 +26,8 @@ public class LibraryObject extends Geometry { private static final Logger logger = LogManager.getLogger(LibraryObject.class); @Serial private static final long serialVersionUID = -50293435187454911L; - - private static Map libraryObjects = new ConcurrentHashMap<>(); + private static boolean metadataLocked = false; + private static final Map libraryObjects = new ConcurrentHashMap<>(); public static LibraryObject of(Path path, ParserConfiguration config) { if (libraryObjects.containsKey(path.toString())) { @@ -44,22 +44,6 @@ public class LibraryObject extends Geometry { return libOb; } - public static LibraryObject of(CityGmlZipEntry entry, ParserConfiguration config) { - String fileName = entry.getEntrySubPath(); - if (libraryObjects.containsKey(fileName)){ - return libraryObjects.get(fileName); - } - Geometry protoGeom = parseZipEntry(entry, config); - if (protoGeom == null) { - return null; - } - LibraryObject libOb = new LibraryObject(protoGeom.getType(), protoGeom.getLod(), protoGeom.getOrientation()); - protoGeom.getPolygons().forEach(libOb::addPolygon); - libOb.updateEdgesAndVertices(); - libraryObjects.put(fileName, libOb); - return libOb; - } - private LibraryObject(GeometryType type, Lod lod, Orientation orientation) { super(type, lod, orientation); } @@ -69,31 +53,15 @@ public class LibraryObject extends Geometry { Geometry geo = null; if (Files.exists(path)) { try { - geo = getProtoGeometry(CityGmlParser.parseCityGmlFileSilently(path.toString(), config)); + geo = getProtoGeometry(CityGmlParser.nestedCityGmlFileParse(path.toString(), config)); } catch (CityGmlParseException e) { - logger.error(String.format( - "Encountered an error while parsing library object %s", path)); + logger.error(Localization.getText("LibraryObject.parsingError"), path); logger.error(e.getStackTrace()); } catch (InvalidGmlFileException e) { logger.error(e.getStackTrace()); } } else { - logger.error(String.format("Implicit geometry references non-existing library object file %s.", path)); - } - return geo; - } - - private static Geometry parseZipEntry(CityGmlZipEntry entry, ParserConfiguration config) { - Geometry geo = null; - try { - entry.loadEntry(config); - geo = getProtoGeometry(entry.getModel()); - } catch (InvalidGmlFileException e) { - logger.error(e.getStackTrace()); - } catch (CityGmlParseException e) { - logger.error(String.format( - "Encountered an error while parsing library object %s", entry.getEntrySubPath())); - logger.error(e.getStackTrace()); + logger.error(Localization.getText("LibraryObject.fileMissing"), path); } return geo; } @@ -111,4 +79,33 @@ public class LibraryObject extends Geometry { return objects.get(0).getHighestLodGeometry(); } + + public static void resetObjectMap() { + libraryObjects.clear(); + } + + public static void preparePrototypeGeometriesForChecking() { + libraryObjects.values().forEach(LibraryObject::updateEdgesAndVertices); + metadataLocked = true; + } + + public static void clearMetaDataOfPrototypeGeometries() { + metadataLocked = false; + libraryObjects.values().forEach(LibraryObject::clearMetaData); + } + + @Override + public void updateEdgesAndVertices(){ + if (!metadataLocked) { + super.updateEdgesAndVertices(); + } + } + + @Override + public void clearMetaData(){ + if (!metadataLocked) { + super.clearMetaData(); + } + } + } diff --git a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/Opening.java b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/Opening.java index b64487de6c20dc229d8e3f46debc50b5e2bc06e9..b59ab14abbeb135cf703876425eefd163381a8c5 100644 --- a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/Opening.java +++ b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/Opening.java @@ -44,17 +44,11 @@ public class Opening extends CityObject { private BoundarySurface partOf; private OpeningType type; - private SurfaceFeatureType featureType; private AbstractFillingSurface ao; - private Opening(OpeningType type) { - this.type = type; - } - - public Opening(OpeningType type, SurfaceFeatureType featureType, BoundarySurface partOf, + public Opening(OpeningType type, BoundarySurface partOf, AbstractFillingSurface ao) { - this.featureType = featureType; this.partOf = partOf; this.type = type; this.ao = ao; @@ -96,11 +90,6 @@ public class Opening extends CityObject { } } - - public SurfaceFeatureType getSurfaceFeatureType() { - return featureType; - } - public BoundarySurface getPartOf() { return partOf; } diff --git a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/OtherConstructionObject.java b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/OtherConstructionObject.java new file mode 100644 index 0000000000000000000000000000000000000000..d29145d509a607548caf34a802286ce345c4c1e0 --- /dev/null +++ b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/OtherConstructionObject.java @@ -0,0 +1,142 @@ +package de.hft.stuttgart.citydoctor2.datastructure; + +import de.hft.stuttgart.citydoctor2.check.CheckableVisitor; +import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration; +import de.hft.stuttgart.citydoctor2.utils.CityGmlUtils; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.citygml4j.core.model.construction.OtherConstruction; +import org.citygml4j.core.model.core.AbstractCityObject; +import org.citygml4j.core.model.core.AbstractSpaceBoundaryProperty; +import org.citygml4j.core.util.geometry.GeometryFactory; +import org.xmlobjects.gml.model.geometry.aggregates.MultiSurface; +import org.xmlobjects.gml.model.geometry.aggregates.MultiSurfaceProperty; +import org.xmlobjects.gml.model.geometry.primitives.Solid; +import org.xmlobjects.gml.model.geometry.primitives.SolidProperty; + +import java.io.Serial; +import java.util.ArrayList; +import java.util.List; + +public class OtherConstructionObject extends CityObject{ + + @Serial + private static final long serialVersionUID = -3885206364978761701L; + + private static final Logger logger = LogManager.getLogger(OtherConstructionObject.class); + + private final List boundarySurfaceList = new ArrayList<>(); + private OtherConstruction gmlObject; + + @Override + public void accept(CheckableVisitor c) { + super.accept(c); + if (c.canExecute(this)) { + c.check(this); + } + for (BoundarySurface bs : boundarySurfaceList) { + bs.accept(c); + } + } + + public void setGmlObject(OtherConstruction gmlObject) { + this.gmlObject = gmlObject; + } + + @Override + public void rebuildGeometries(GeometryFactory factory, ParserConfiguration config) { + for (Geometry geom : getGeometries()) { + if (geom instanceof ImplicitGeometryHolder) { + continue; + } + if (geom.getType() == GeometryType.MULTI_SURFACE) { + MultiSurface ms = CityGmlUtils.createMultiSurface(geom, factory, config); + setMultiSurfaceAccordingToLod(geom, ms); + } else { + Solid solid = CityGmlUtils.createSolid(geom, factory, config); + setSolidAccordingToLod(geom, solid); + } + } + removeEmptyBoundarySurfaces(); + } + + private void removeEmptyBoundarySurfaces() { + for (BoundarySurface bs : boundarySurfaceList) { + if (bs.getGeometries().isEmpty()) { + for (AbstractSpaceBoundaryProperty bsp : gmlObject.getBoundaries()) { + if (bsp.getObject() != null && bsp.getObject() == bs.getGmlObject()) { + logger.warn("Found empty boundary surface: {}, removing from feature", bs.getGmlId()); + gmlObject.getBoundaries().remove(bsp); + break; + } + } + } + } + } + + private void setMultiSurfaceAccordingToLod(Geometry geom, MultiSurface ms) { + switch (geom.getLod()) { + case LOD0: + gmlObject.setLod0MultiSurface(new MultiSurfaceProperty(ms)); + break; + case LOD2: + gmlObject.setLod2MultiSurface(new MultiSurfaceProperty(ms)); + break; + case LOD3: + gmlObject.setLod3MultiSurface(new MultiSurfaceProperty(ms)); + break; + default: + throw new IllegalStateException("Cannot add " + geom.getLod() + " multi surface to other construction object"); + } + } + + private void setSolidAccordingToLod(Geometry geom, Solid solid) { + switch (geom.getLod()) { + case LOD1: + gmlObject.setLod1Solid(new SolidProperty(solid)); + break; + case LOD2: + gmlObject.setLod2Solid(new SolidProperty(solid)); + break; + case LOD3: + gmlObject.setLod3Solid(new SolidProperty(solid)); + break; + default: + throw new IllegalStateException("Cannot add " + geom.getLod() + " solid to other construction object"); + } + } + + @Override + public OtherConstruction getGmlObject() { + return gmlObject; + } + + @Override + public void unsetGmlGeometries() { + gmlObject.setLod0MultiSurface(null); + gmlObject.setLod2MultiSurface(null); + gmlObject.setLod3MultiSurface(null); + gmlObject.setLod1Solid(null); + gmlObject.setLod2Solid(null); + gmlObject.setLod3Solid(null); + } + + @Override + public CityObject getTopLevelCityObject() { + return this; + } + + @Override + public FeatureType getFeatureType() { + return FeatureType.OTHER_CITY_OBJECT; + } + + public void addBoundarySurface(BoundarySurface bs) { + boundarySurfaceList.add(bs); + bs.setParent(this); + } + + public List getBoundarySurfaces() { + return boundarySurfaceList; + } +} diff --git a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/RelativeGeometry.java b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/RelativeGeometry.java index bbf61550e200a9c5311e30834649065cd55b9bf3..489fa054857e4552ca991a2499a7eec29266354b 100644 --- a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/RelativeGeometry.java +++ b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/RelativeGeometry.java @@ -14,20 +14,53 @@ public class RelativeGeometry extends Geometry { @Serial private static final long serialVersionUID = -686112245455298977L; - private static Map relativeGeometries = new ConcurrentHashMap<>(); + private static final Map relativeGeometries = new ConcurrentHashMap<>(); + private static boolean metadataLocked = false; - public static RelativeGeometry of(Geometry geom) { - if (relativeGeometries.containsKey(geom)) { - return relativeGeometries.get(geom); + public static RelativeGeometry of(GmlId gmlId, Geometry geom) { + if (relativeGeometries.containsKey(gmlId)) { + return relativeGeometries.get(gmlId); } RelativeGeometry relGeo = new RelativeGeometry(geom.getType(), geom.getLod(), geom.getOrientation()); geom.getPolygons().forEach(relGeo::addPolygon); relGeo.updateEdgesAndVertices(); - relativeGeometries.put(geom, relGeo); + relativeGeometries.put(gmlId, relGeo); return relGeo; } + public static RelativeGeometry of(GmlId gmlId) { + return relativeGeometries.getOrDefault(gmlId, null); + } + private RelativeGeometry(GeometryType type, Lod lod, Orientation orientation) { super(type, lod, orientation); } + + public static void resetObjectMap() { + relativeGeometries.clear(); + } + + public static void preparePrototypeGeometriesForChecking() { + relativeGeometries.values().forEach(RelativeGeometry::updateEdgesAndVertices); + metadataLocked = true; + } + + public static void clearMetaDataOfPrototypeGeometries() { + metadataLocked = false; + relativeGeometries.values().forEach(RelativeGeometry::clearMetaData); + } + + @Override + public void updateEdgesAndVertices(){ + if (!metadataLocked) { + super.updateEdgesAndVertices(); + } + } + + @Override + public void clearMetaData(){ + if (!metadataLocked) { + super.clearMetaData(); + } + } } diff --git a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/TunnelPart.java b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/TunnelPart.java index e6c02a9974ac22f2822472d55ce2779c3458e29c..4584a999f08ed10ce09a016e8e5fdc06b32b0831 100644 --- a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/TunnelPart.java +++ b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/TunnelPart.java @@ -9,6 +9,8 @@ public class TunnelPart extends AbstractTunnel { private Tunnel parent; + private TunnelPart() { + } public TunnelPart(Tunnel parent) { this.parent = parent; @@ -34,6 +36,4 @@ public class TunnelPart extends AbstractTunnel { return "TunnelPart [id=" + getGmlId() + "]"; } - private TunnelPart() { - } } diff --git a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/Vertex.java b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/Vertex.java index a49aec952b89baf41a61b8e29f7a340ce38ffe28..e42440072b6506f02af1d77a5001c3aa8148dd59 100644 --- a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/Vertex.java +++ b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/Vertex.java @@ -21,6 +21,8 @@ package de.hft.stuttgart.citydoctor2.datastructure; import de.hft.stuttgart.citydoctor2.math.Vector3d; import de.hft.stuttgart.citydoctor2.utils.SerializablePair; +import java.io.IOException; +import java.io.ObjectInputStream; import java.io.Serial; import java.util.ArrayList; import java.util.HashSet; @@ -37,7 +39,7 @@ public class Vertex extends Vector3d { @Serial private static final long serialVersionUID = -5525361920397934892L; - private List>> adjacentRings = new ArrayList<>(2); + private transient List>> adjacentRings = new ArrayList<>(2); public Vertex(double x, double y, double z) { super(x, y, z); @@ -91,6 +93,12 @@ public class Vertex extends Vector3d { throw new IllegalStateException("Requested adjacent polygons with Geometry not containing this vertex"); } + @Serial + private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { + in.defaultReadObject(); + clearAdjacentRings(); + } + public Set getAdjacentPolygons(Geometry geom) { return getAdjacentPolygonsWithoutNeighbor(geom); } diff --git a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/mapper/citygml3/Citygml3FeatureMapper.java b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/mapper/citygml3/Citygml3FeatureMapper.java index e5f5c5435c06b98da11fb7e5a6af8c074cbb315f..e27555ca167f86cb172b6346de9db5e3ddf46aa9 100644 --- a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/mapper/citygml3/Citygml3FeatureMapper.java +++ b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/mapper/citygml3/Citygml3FeatureMapper.java @@ -24,6 +24,9 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import de.hft.stuttgart.citydoctor2.database.FeatureCache; +import de.hft.stuttgart.citydoctor2.database.UnconnectedCache; +import de.hft.stuttgart.citydoctor2.datastructure.OtherConstructionObject; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.citygml4j.core.model.CityGMLVersion; @@ -45,6 +48,7 @@ import org.citygml4j.core.model.building.BuildingRoomProperty; import org.citygml4j.core.model.building.BuildingUnit; import org.citygml4j.core.model.building.Storey; import org.citygml4j.core.model.construction.AbstractConstruction; +import org.citygml4j.core.model.construction.OtherConstruction; import org.citygml4j.core.model.core.AbstractCityObject; import org.citygml4j.core.model.core.AbstractFeatureWithLifespan; import org.citygml4j.core.model.core.AbstractGenericAttributeProperty; @@ -157,35 +161,32 @@ import de.hft.stuttgart.citydoctor2.datastructure.WaterObject; import de.hft.stuttgart.citydoctor2.math.graph.KDTree; import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration; import de.hft.stuttgart.citydoctor2.utils.Localization; -import de.hft.stuttgart.citydoctor2.zip.CityGmlZipEntry; public class Citygml3FeatureMapper extends ObjectWalker { private static final Logger logger = LogManager.getLogger(Citygml3FeatureMapper.class); + private static FeatureCache featureCache = new FeatureCache(); private final CityDoctorModel model; private final ParserConfiguration config; private final Path directory; - private final CityGmlZipEntry zipEntry; private final double neighborDistance; private Map polygonMap = new HashMap<>(); private Map compositeMap = new HashMap<>(); private List references = new ArrayList<>(); private Map vertexMap = new HashMap<>(); - public Citygml3FeatureMapper(ParserConfiguration config, Path path) { + public Citygml3FeatureMapper(ParserConfiguration config, Path path, boolean unconnected) { this.config = config; this.directory = path.getParent(); - model = new CityDoctorModel(config, path.toFile()); - neighborDistance = 1.8d / Math.pow(10, config.getNumberOfRoundingPlaces()); - zipEntry = null; - } - public Citygml3FeatureMapper(ParserConfiguration config, CityGmlZipEntry entry) { - this.config = config; - this.directory = null; - this.zipEntry = entry; - model = new CityDoctorModel(config, Path.of(entry.getEntrySubPath()).toFile()); + if (unconnected){ + model = new CityDoctorModel(config, path.toFile(), new UnconnectedCache()); + } else { + featureCache.resetCache(); + ImplicitGeometryHolder.resetObjectMaps(); + model = new CityDoctorModel(config, path.toFile(), featureCache); + } neighborDistance = 1.8d / Math.pow(10, config.getNumberOfRoundingPlaces()); } @@ -203,6 +204,32 @@ public class Citygml3FeatureMapper extends ObjectWalker { } + @Override + public void visit(OtherConstruction gmlOc){ + OtherConstructionObject oco = new OtherConstructionObject(); + oco.setGmlObject(gmlOc); + mapAbstractOccupiedSpace(gmlOc, oco, Orientation.OUTWARD); + + SurfaceMapper surfaceMapper = new SurfaceMapper(polygonMap, references, compositeMap, vertexMap, config); + for (AbstractSpaceBoundaryProperty surfaceProp : gmlOc.getBoundaries()) { + if (!surfaceProp.isSetObject()) { + continue; + } + AbstractSpaceBoundary surface = surfaceProp.getObject(); + surface.accept(surfaceMapper); + } + for (BoundarySurface bs : surfaceMapper.getSurfaces()) { + oco.addBoundarySurface(bs); + for (Geometry geom : bs.getGeometries()) { + for (Polygon p : geom.getPolygons()) { + p.setPartOfSurface(bs); + } + } + } + finishCityObjectConstruction(oco); + model.addOtherCityObject(oco); + } + @Override public void visit(org.citygml4j.core.model.cityfurniture.CityFurniture gmlCityFurniture) { CityFurniture cf = new CityFurniture(); @@ -230,7 +257,7 @@ public class Citygml3FeatureMapper extends ObjectWalker { } mapAbstractOccupiedSpace(gos, gco, Orientation.OUTWARD); finishCityObjectConstruction(gco); - model.addGenericCityObject(gco); + model.addOtherCityObject(gco); } @Override @@ -1024,30 +1051,39 @@ public class Citygml3FeatureMapper extends ObjectWalker { if (directory != null){ Path libraryObjectPath = directory.resolve(ig.getLibraryObject()); libObj = LibraryObject.of(libraryObjectPath, config); - } else { - String libraryObjectPath = ig.getLibraryObject(); - Path loPath = zipEntry.resolveLibraryObjectPath(libraryObjectPath); - CityGmlZipEntry libEntry = zipEntry.getArchive().getEntry(loPath.toString()); - libObj = LibraryObject.of(libEntry, config); } if (libObj != null) { igh = new ImplicitGeometryHolder(ig, libObj); } } else if (ig.getRelativeGeometry() != null) { AbstractGeometry aGeom = ig.getRelativeGeometry().getObject(); - Geometry geom = null; Lod lod = Lod.values()[lodInt]; - RelativeGeometry relGeo = null; - if (aGeom instanceof MultiSurface ms) { - geom = parseMultiSurface(ms, lod); - } else if (aGeom instanceof Solid s) { - geom = parseSolid(s, lod, orientation); - } else if (aGeom instanceof CompositeSurface cs) { - geom = parseCompositeSurface(cs, lod); - } - if (geom != null) { - relGeo = RelativeGeometry.of(geom); - igh = new ImplicitGeometryHolder(ig, relGeo); + if (aGeom != null) { + Geometry geom = null; + if (aGeom instanceof MultiSurface ms) { + geom = parseMultiSurface(ms, lod); + } else if (aGeom instanceof Solid s) { + geom = parseSolid(s, lod, orientation); + } else if (aGeom instanceof CompositeSurface cs) { + geom = parseCompositeSurface(cs, lod); + } + if (geom != null) { + geom.setGmlId(new GmlId(aGeom.getId())); + RelativeGeometry relGeo = RelativeGeometry.of(geom.getGmlId(), geom); + igh = new ImplicitGeometryHolder(ig, relGeo); + } + } else if (ig.getRelativeGeometry().getHref() != null) { + String hrefId = ig.getRelativeGeometry().getHref(); + hrefId = hrefId.startsWith("#") ? hrefId.substring(1) : hrefId; + GmlId gmlId = new GmlId(hrefId); + RelativeGeometry relGeo = RelativeGeometry.of(gmlId); + if (relGeo == null) { + igh = ImplicitGeometryHolder.deferRelativeGeomParsing(ig, lod); + } else { + igh = new ImplicitGeometryHolder(ig, relGeo); + } + } else { + logger.warn("Relative geometry of GML-ID {} has neither geometry nor an href", ig.getId()); } } else { diff --git a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/mapper/citygml3/SurfaceMapper.java b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/mapper/citygml3/SurfaceMapper.java index c8e8495283789b7a046d17517687595816dda05f..6b3257ad509e783b2bed7b814bc71f77159ab0cd 100644 --- a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/mapper/citygml3/SurfaceMapper.java +++ b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/mapper/citygml3/SurfaceMapper.java @@ -54,8 +54,7 @@ public class SurfaceMapper extends ObjectWalker { @Override public void visit(WallSurface wallSurface) { - BoundarySurface surface = new BoundarySurface(SurfaceFeatureType.BUILDING, BoundarySurfaceType.WALL, - wallSurface); + BoundarySurface surface = new BoundarySurface(BoundarySurfaceType.WALL, wallSurface); handleConstructionSurface(wallSurface, surface); surfaces.add(surface); } @@ -74,11 +73,11 @@ public class SurfaceMapper extends ObjectWalker { private void readAbstractFillingSurface(AbstractFillingSurface afs, BoundarySurface cdSurface) { Opening o; if (afs instanceof DoorSurface ds) { - o = new Opening(OpeningType.DOOR, SurfaceFeatureType.BUILDING, cdSurface, ds); + o = new Opening(OpeningType.DOOR, cdSurface, ds); } else if (afs instanceof WindowSurface ws) { - o = new Opening(OpeningType.WINDOW, SurfaceFeatureType.BUILDING, cdSurface, ws); + o = new Opening(OpeningType.WINDOW, cdSurface, ws); } else { - o = new Opening(OpeningType.UNKNOWN, SurfaceFeatureType.BUILDING, cdSurface, afs); + o = new Opening(OpeningType.UNKNOWN, cdSurface, afs); } cdSurface.addOpening(o); parseAndAddMultiSurface(afs.getLod0MultiSurface(), Lod.LOD0, o); @@ -144,64 +143,56 @@ public class SurfaceMapper extends ObjectWalker { @Override public void visit(FloorSurface floorSurface) { - BoundarySurface surface = new BoundarySurface(SurfaceFeatureType.BUILDING, BoundarySurfaceType.FLOOR, - floorSurface); + BoundarySurface surface = new BoundarySurface(BoundarySurfaceType.FLOOR, floorSurface); handleConstructionSurface(floorSurface, surface); surfaces.add(surface); } @Override public void visit(CeilingSurface ceilingSurface) { - BoundarySurface surface = new BoundarySurface(SurfaceFeatureType.BUILDING, BoundarySurfaceType.CEILING, - ceilingSurface); + BoundarySurface surface = new BoundarySurface(BoundarySurfaceType.CEILING, ceilingSurface); handleConstructionSurface(ceilingSurface, surface); surfaces.add(surface); } @Override public void visit(GroundSurface groundSurface) { - BoundarySurface surface = new BoundarySurface(SurfaceFeatureType.BUILDING, BoundarySurfaceType.GROUND, - groundSurface); + BoundarySurface surface = new BoundarySurface(BoundarySurfaceType.GROUND, groundSurface); handleConstructionSurface(groundSurface, surface); surfaces.add(surface); } @Override public void visit(InteriorWallSurface interiorWallSurface) { - BoundarySurface surface = new BoundarySurface(SurfaceFeatureType.BUILDING, BoundarySurfaceType.INTERIOR_WALL, - interiorWallSurface); + BoundarySurface surface = new BoundarySurface(BoundarySurfaceType.INTERIOR_WALL, interiorWallSurface); handleConstructionSurface(interiorWallSurface, surface); surfaces.add(surface); } @Override public void visit(OuterCeilingSurface outerCeilingSurface) { - BoundarySurface surface = new BoundarySurface(SurfaceFeatureType.BUILDING, BoundarySurfaceType.OUTER_CEILING, - outerCeilingSurface); + BoundarySurface surface = new BoundarySurface(BoundarySurfaceType.OUTER_CEILING, outerCeilingSurface); handleConstructionSurface(outerCeilingSurface, surface); surfaces.add(surface); } @Override public void visit(OuterFloorSurface outerFloorSurface) { - BoundarySurface surface = new BoundarySurface(SurfaceFeatureType.BUILDING, BoundarySurfaceType.OUTER_FLOOR, - outerFloorSurface); + BoundarySurface surface = new BoundarySurface(BoundarySurfaceType.OUTER_FLOOR, outerFloorSurface); handleConstructionSurface(outerFloorSurface, surface); surfaces.add(surface); } @Override public void visit(RoofSurface roofSurface) { - BoundarySurface surface = new BoundarySurface(SurfaceFeatureType.BUILDING, BoundarySurfaceType.ROOF, - roofSurface); + BoundarySurface surface = new BoundarySurface(BoundarySurfaceType.ROOF, roofSurface); handleConstructionSurface(roofSurface, surface); surfaces.add(surface); } @Override public void visit(ClosureSurface closureSurface) { - BoundarySurface surface = new BoundarySurface(SurfaceFeatureType.BUILDING, BoundarySurfaceType.CLOSURE, - closureSurface); + BoundarySurface surface = new BoundarySurface(BoundarySurfaceType.CLOSURE, closureSurface); handleThematicSurface(closureSurface, surface); surfaces.add(surface); } diff --git a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/math/Triangle3d.java b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/math/Triangle3d.java index 96ec193dec6b4b0d350789937ec01f9991318abd..4f3c2920d38c3389b5dbc0f439f83379fdbee1c1 100644 --- a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/math/Triangle3d.java +++ b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/math/Triangle3d.java @@ -87,8 +87,13 @@ public class Triangle3d implements Serializable { Vector3d n2 = v1.cross(v2); return new Plane(n2, p1); } - + public boolean doesIntersect(Triangle3d other) { + return doesIntersect(other, EPSILON); + } + + + public boolean doesIntersect(Triangle3d other, double epsilon) { // plane of other triangle Plane planeT2 = other.getPlane(); // check if all points are on one side of the plane @@ -96,13 +101,13 @@ public class Triangle3d implements Serializable { double distanceP2T2 = planeT2.getSignedDistance(p2); double distanceP3T2 = planeT2.getSignedDistance(p3); - if (Math.abs(distanceP1T2) < EPSILON) { + if (Math.abs(distanceP1T2) < epsilon) { distanceP1T2 = 0.0; } - if (Math.abs(distanceP2T2) < EPSILON) { + if (Math.abs(distanceP2T2) < epsilon) { distanceP2T2 = 0.0; } - if (Math.abs(distanceP3T2) < EPSILON) { + if (Math.abs(distanceP3T2) < epsilon) { distanceP3T2 = 0.0; } @@ -123,13 +128,13 @@ public class Triangle3d implements Serializable { double distanceP2T1 = planeT1.getSignedDistance(other.getP2()); double distanceP3T1 = planeT1.getSignedDistance(other.getP3()); - if (Math.abs(distanceP1T1) < EPSILON) { + if (Math.abs(distanceP1T1) < epsilon) { distanceP1T1 = 0.0; } - if (Math.abs(distanceP2T1) < EPSILON) { + if (Math.abs(distanceP2T1) < epsilon) { distanceP2T1 = 0.0; } - if (Math.abs(distanceP3T1) < EPSILON) { + if (Math.abs(distanceP3T1) < epsilon) { distanceP3T1 = 0.0; } @@ -139,11 +144,15 @@ public class Triangle3d implements Serializable { return false; } - return checkTriangleLineIntersection(other, p1, p2) || checkTriangleLineIntersection(other, p1, p3) + boolean intersects = checkTriangleLineIntersection(other, p1, p2) || checkTriangleLineIntersection(other, p1, p3) || checkTriangleLineIntersection(other, p2, p3) || checkTriangleLineIntersection(this, other.p1, other.p2) || checkTriangleLineIntersection(this, other.p1, other.p3) || checkTriangleLineIntersection(this, other.p2, other.p3); + if (intersects) { + System.out.println(); + } + return intersects; } private boolean checkTriangleLineIntersection(Triangle3d other, Vector3d a, Vector3d b) { @@ -171,7 +180,11 @@ public class Triangle3d implements Serializable { private boolean doesIntersectCoplanarTriangle(Triangle3d other) { Triangle2d t1 = projectTo2d(); Triangle2d t2 = other.projectTo2d(); - return t1.intersects(t2); + boolean intersects = t1.intersects(t2); + if (intersects) { + System.out.println(); + } + return intersects; } public Triangle2d projectTo2d() { diff --git a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/parser/CityGmlParser.java b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/parser/CityGmlParser.java index 06d42a00208f77a9d5cd43bb017d77dd3c9b02e6..d94ab7eecf5a32285c7a3feee955a4d5a5dc7eab 100644 --- a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/parser/CityGmlParser.java +++ b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/parser/CityGmlParser.java @@ -19,7 +19,6 @@ package de.hft.stuttgart.citydoctor2.parser; import java.io.BufferedInputStream; -import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; @@ -44,6 +43,8 @@ import javax.xml.validation.Schema; import javax.xml.validation.SchemaFactory; import javax.xml.validation.Validator; +import de.hft.stuttgart.citydoctor2.datastructure.GmlId; +import de.hft.stuttgart.citydoctor2.datastructure.ImplicitGeometryHolder; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -78,7 +79,6 @@ import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.SAXNotRecognizedException; import org.xml.sax.SAXNotSupportedException; -import org.xml.sax.SAXParseException; import org.xmlobjects.schema.SchemaHandler; import org.xmlobjects.schema.SchemaHandlerException; import org.xmlobjects.stream.XMLReader; @@ -90,8 +90,6 @@ import de.hft.stuttgart.citydoctor2.mapper.citygml3.Citygml3FeatureMapper; import de.hft.stuttgart.citydoctor2.mapper.citygml3.GMLValidationHandler; import de.hft.stuttgart.citydoctor2.math.Vector3d; import de.hft.stuttgart.citydoctor2.utils.Localization; -import de.hft.stuttgart.citydoctor2.zip.CityGmlZipEntry; -import de.hft.stuttgart.citydoctor2.zip.CityGmlZipEntryFile; import de.hft.stuttgart.quality.QualityADEContext; import de.hft.stuttgart.quality.QualityADEModule; @@ -157,33 +155,111 @@ public class CityGmlParser { ADERegistry adeRegistry = ADERegistry.getInstance(); adeRegistry.loadADE(new QualityADEContext()); } catch (CityGMLContextException e) { - logger.fatal("Unable to create citygml4j context", e); + logger.fatal(Localization.getText("CityGmlParser.creating4jContextFailed"), e); throw new IllegalStateException("Unable to create citygml4j context"); } catch (ADEException e) { - logger.fatal("Unable to add ADE plugins to citygml4j", e); + logger.fatal(Localization.getText("CityGmlParser.creatingAdePluginsFailed"), e); throw new IllegalStateException("Unable to add ADE plugins to citygml4j"); } } return context; } - public static CityDoctorModel parseCityGmlFileSilently(String file, ParserConfiguration config) + /** + * Parses a given CityGML file and collects the contained CityObject Features in a {@link CityDoctorModel}. + *

+ * The nested parse uses an {@link de.hft.stuttgart.citydoctor2.database.UnconnectedCache UnconnectedCache}, which + * is not connected to the database. + *

+ * Nested parsing should only be used for accessing Features in auxiliary, small CityGML files, e.g. parsing of + * {@link de.hft.stuttgart.citydoctor2.datastructure.LibraryObject LibraryObject} files. + * + * @param filePath String path to the file + * @param config Configuration of the parser + * @return A {@link CityDoctorModel} object with the parsed Features + * @throws CityGmlParseException if parsing of the CityGML-file failed + * @throws InvalidGmlFileException if the GMLValidationHandler found an error + */ + public static CityDoctorModel nestedCityGmlFileParse(String filePath, ParserConfiguration config) throws CityGmlParseException, InvalidGmlFileException { - return parseCityGmlFile(file, config, null, null, false); + return parseCityGmlFile(filePath, config, null, null, false, true); } - public static CityDoctorModel parseCityGmlFile(String file, ParserConfiguration config) + /** + * Parses a given CityGML file and collects the contained CityObject Features in a {@link CityDoctorModel}. + *

+ * Features are held in a non-persistent, embedded Database with an in-memory upstream cache. Thus, strong references + * to {@link CityObject} are to be avoided, to allow for the memory management of the cache. + * + * @param filePath String path to the file + * @param config Configuration of the parser + * @return A {@link CityDoctorModel} object with the parsed Features + * @throws CityGmlParseException if parsing of the CityGML-file failed + * @throws InvalidGmlFileException if the GMLValidationHandler found an error + */ + public static CityDoctorModel parseCityGmlFile(String filePath, ParserConfiguration config) throws CityGmlParseException, InvalidGmlFileException { - return parseCityGmlFile(file, config, null, null, true); + return parseCityGmlFile(filePath, config, null, null); } - public static CityDoctorModel parseCityGmlFile(String file, ParserConfiguration config, ProgressListener l) + + /** + * Parses a given CityGML file and collects the contained CityObject Features in a {@link CityDoctorModel}. + *

+ * Features are held in a non-persistent, embedded Database with an in-memory upstream cache. Thus, strong references + * to {@link CityObject} are to be avoided, to allow for the memory management of the cache. + * + * @param filePath String path to the file + * @param config Configuration of the parser + * @param l Listener hook for tracking of parsing progress + * @return A {@link CityDoctorModel} object with the parsed Features + * @throws CityGmlParseException if parsing of the CityGML-file failed + * @throws InvalidGmlFileException if the GMLValidationHandler found an error + */ + public static CityDoctorModel parseCityGmlFile(String filePath, ParserConfiguration config, ProgressListener l) throws CityGmlParseException, InvalidGmlFileException { - return parseCityGmlFile(file, config, l, null, true); + return parseCityGmlFile(filePath, config, l, null); } + /** + * Parses a given CityGML file and collects the contained CityObject Features in a {@link CityDoctorModel}. + *

+ * Features are held in a non-persistent, embedded Database with an in-memory upstream cache. Thus, strong references + * to {@link CityObject} are to be avoided, to allow for the memory management of the cache. + * + * @param filePath String path to the file + * @param config Configuration of the parser + * @param l Listener hook for tracking of parsing progress + * @param handler Validation handler for GML-file validation + * @return A {@link CityDoctorModel} object with the parsed Features + * @throws CityGmlParseException if parsing of the CityGML-file failed + * @throws InvalidGmlFileException if the GMLValidationHandler found an error + */ public static CityDoctorModel parseCityGmlFile(String filePath, ParserConfiguration config, ProgressListener l, - GMLValidationHandler handler, boolean verbose) throws CityGmlParseException, InvalidGmlFileException { + GMLValidationHandler handler) throws CityGmlParseException, InvalidGmlFileException { + return parseCityGmlFile(filePath, config, l, handler, true, false); + } + + /** + * Parses a given CityGML file and collects the contained CityObject Features in a {@link CityDoctorModel}. + *

+ * Features are held in a non-persistent, embedded Database with an in-memory upstream cache. Thus, strong references + * to {@link CityObject} are to be avoided, to allow for the memory management of the cache. + * + * @param filePath String path to the file + * @param config Configuration of the parser + * @param l Listener hook for tracking of parsing progress + * @param handler Validation handler for GML-file validation + * @param verbose If verbosity is enabled the parser will write info logs to the logger + * @param unconnected If true the parser will use an {@link de.hft.stuttgart.citydoctor2.database.UnconnectedCache UnconnectedCache} + * to collect the parsed CityObjects + * @return A {@link CityDoctorModel} object with the parsed Features + * @throws CityGmlParseException if parsing of the CityGML-file failed + * @throws InvalidGmlFileException if the GMLValidationHandler found an error + */ + private static CityDoctorModel parseCityGmlFile(String filePath, ParserConfiguration config, ProgressListener l, + GMLValidationHandler handler, boolean verbose, boolean unconnected) + throws CityGmlParseException, InvalidGmlFileException { CityGMLContext context = getContext(); Path file = Paths.get(filePath); if (config.getValidate()) { @@ -194,14 +270,14 @@ public class CityGmlParser { } try { - parseEpsgCodeFromFile(file, config); + parseEpsgCodeFromFile(file, config, verbose); CityGMLInputFactory in = context.createCityGMLInputFactory() .withChunking(ChunkOptions.chunkByProperties(chunkProperties).skipCityModel(false)); try (ObservedInputStream ois = new ObservedInputStream(file.toFile())) { if (l != null) { ois.addListener(l::updateProgress); } - return readAndKeepFeatures(config, file, in, ois, verbose); + return readAndKeepFeatures(config, file, in, ois, verbose, unconnected); } } catch (CityGMLReadException | IOException e) { throw new CityGmlParseException("Failed to read CityGML file", e); @@ -209,118 +285,6 @@ public class CityGmlParser { } - public static CityDoctorModel parseCityGmlZipEntry(CityGmlZipEntry entry, ParserConfiguration config) - throws CityGmlParseException, InvalidGmlFileException, IOException { - return parseCityGmlZipEntry(entry, config, null); - } - - public static CityDoctorModel parseCityGmlZipEntry(CityGmlZipEntry entry, ParserConfiguration config, ProgressListener l) - throws CityGmlParseException, InvalidGmlFileException, IOException { - CityGMLContext context = getContext(); - - if (config.getValidate()) { - try (CityGmlZipEntryFile entryFile = new CityGmlZipEntryFile(entry)) { - List messages = validateStream(entryFile.getInputStream(), context); - if (!messages.isEmpty()) { - throw new InvalidGmlFileException("Invalid GML File. First error: \n" + messages.get(0)); - } - } catch (Exception e) { - throw new CityGmlParseException(e); - } - - } - return decompressAndParseCityGmlEntry(entry, config, l, context); - } - - public static CityDoctorModel decompressAndParseCityGmlEntry(CityGmlZipEntry entry, ParserConfiguration config, CityGMLContext context) - throws CityGmlParseException { - return decompressAndParseCityGmlEntry(entry, config, null, context); - } - - public static CityDoctorModel decompressAndParseCityGmlEntry(CityGmlZipEntry entry, ParserConfiguration config, ProgressListener l, CityGMLContext context) - throws CityGmlParseException { - - try (CityGmlZipEntryFile entryFile = new CityGmlZipEntryFile(entry)) { - BufferedInputStream bis = new BufferedInputStream(entryFile.getInputStream()); - readEpsgCodeFromInputStream(bis, config); - CityGMLInputFactory in = context.createCityGMLInputFactory() - .withChunking(ChunkOptions.chunkByProperties(chunkProperties).skipCityModel(false)); - try (ObservedInputStream ois = new ObservedInputStream(bis, bis.available())) { - if (l != null) { - ois.addListener(l::updateProgress); - } - return readAndKeepFeatures(config, entry, in, ois, false); - } - } catch (CityGMLReadException | IOException e) { - throw new CityGmlParseException("Failed to read CityGML file", e); - } catch (Exception e) { - throw new CityGmlParseException(e); - } - } - - private static CityDoctorModel readAndKeepFeatures(ParserConfiguration config, CityGmlZipEntry entry, - CityGMLInputFactory inputFactory, ObservedInputStream ois, boolean verbose) throws CityGMLReadException { - return readAndKeepModel(new Citygml3FeatureMapper(config, entry), inputFactory, ois, verbose); - } - - private static List validateStream(InputStream vis, CityGMLContext context) throws CityGmlParseException { - GMLValidationHandler handler = new GMLValidationHandler(); - - try { - BufferedInputStream bis = new BufferedInputStream(vis); - SchemaHandler schemaHandler = new ValidationSchemaHandler(context.getDefaultSchemaHandler()); - readAdditionalSchemaDefinitions(context, bis, schemaHandler); - Source[] schemas = schemaHandler.getSchemas(); - SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); - schemaFactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); - Schema schema = schemaFactory.newSchema(schemas); - Validator validator = schema.newValidator(); - validator.setErrorHandler(handler); - validator.validate(new StreamSource(bis)); - return handler.getMessages(); - } catch (SchemaHandlerException | SAXException | IOException e) { - throw new CityGmlParseException("Failed to validate CityGML file", e); - } - } - - private static void readAdditionalSchemaDefinitions(CityGMLContext context, BufferedInputStream bis, SchemaHandler schemaHandler) - throws CityGmlParseException { - bis.mark(Integer.MAX_VALUE); - try (XMLReader reader = XMLReaderFactory.newInstance(context.getXMLObjects()) - .withSchemaHandler(schemaHandler) - .createReader(bis)) { - reader.nextTag(); - bis.reset(); - } catch (Exception e) { - throw new CityGmlParseException("Failed to read Schema from stream.", e); - } - } - - private static void readEpsgCodeFromInputStream(BufferedInputStream bis, ParserConfiguration config) throws CityGmlParseException { - try { - // Mark start position of GML-"file" - bis.mark(Integer.MAX_VALUE); - // Buffer the first 10000 chars of the Stream, EPSG/envelope info should be found within that range - int peekingWidth = Math.min(10000, bis.available()); - byte[] buf = new byte[peekingWidth]; - bis.read(buf, 0, peekingWidth); - bis.reset(); - parseEpsgCodeFromBuffer(buf, config); - } catch (ParserConfigurationException | SAXException | IOException e) { - throw new CityGmlParseException("Failed to read CityGML file", e); - } - - } - - public static void streamCityGml(CityGmlZipEntry entry, ParserConfiguration config, CityGmlConsumer cityObjectConsumer, - String outputFile) throws CityGmlParseException, IOException { - try (CityGmlZipEntryFile entryFile = new CityGmlZipEntryFile(entry)) { - parseEpsgCodeFromStream(entryFile.getInputStream(), config); - startReadingCityGmlZipEntry(entry, config, null, cityObjectConsumer, outputFile); - } catch (ParserConfigurationException | SAXException | IOException e) { - throw new CityGmlParseException("Failed to read CityGML stream", e); - } - } public static void streamCityGml(String file, ParserConfiguration config, CityGmlConsumer cityObjectConsumer, String outputFile) throws CityGmlParseException { @@ -335,7 +299,7 @@ public class CityGmlParser { public static void streamCityGml(Path file, ParserConfiguration config, ProgressListener l, CityGmlConsumer cityObjectConsumer, String outputFile) throws CityGmlParseException { - parseEpsgCodeFromFile(file, config); + parseEpsgCodeFromFile(file, config, true); startReadingCityGmlFile(file, config, l, cityObjectConsumer, outputFile); } @@ -373,31 +337,11 @@ public class CityGmlParser { private static void readAndDiscardFeatures(Path file, ParserConfiguration config, ObservedInputStream ois, CityGmlConsumer cityObjectConsumer, String outputFile) throws CityGMLReadException { - Citygml3FeatureMapper mapper = new Citygml3FeatureMapper(config, file); + Citygml3FeatureMapper mapper = new Citygml3FeatureMapper(config, file, false); readAndDiscardModel(mapper, ois, cityObjectConsumer, outputFile); } - private static void startReadingCityGmlZipEntry(CityGmlZipEntry entry, ParserConfiguration config, ProgressListener l, - CityGmlConsumer cityObjectConsumer, String outputFile) { - try (CityGmlZipEntryFile entryFile = new CityGmlZipEntryFile(entry); - ObservedInputStream ois = new ObservedInputStream(entryFile.getInputStream(), entry.getFileSize())) { - if (l != null) { - ois.addListener(l::updateProgress); - } - streamAndDiscardFeatures(entry, config, ois, cityObjectConsumer, outputFile); - } catch (IOException | CityGMLReadException e) { - logger.error(Localization.getText("CityGmlParser.errorReadingGmlFile"), e.getMessage()); - logger.catching(Level.ERROR, e); - } - } - - private static void streamAndDiscardFeatures(CityGmlZipEntry entry, ParserConfiguration config, ObservedInputStream ois, - CityGmlConsumer cityObjectConsumer, String outputFile) throws CityGMLReadException { - Citygml3FeatureMapper mapper = new Citygml3FeatureMapper(config, entry); - readAndDiscardModel(mapper, ois, cityObjectConsumer, outputFile); - } - private static void readAndDiscardModel(Citygml3FeatureMapper mapper, ObservedInputStream ois, CityGmlConsumer cityObjectConsumer, String outputFile) throws CityGMLReadException { getContext(); @@ -484,8 +428,9 @@ public class CityGmlParser { } private static CityDoctorModel readAndKeepFeatures(ParserConfiguration config, Path file, - CityGMLInputFactory inputFactory, ObservedInputStream ois, boolean verbose) throws CityGMLReadException { - return readAndKeepModel(new Citygml3FeatureMapper(config, file), inputFactory, ois, verbose); + CityGMLInputFactory inputFactory, ObservedInputStream ois, + boolean verbose, boolean unconnected) throws CityGMLReadException { + return readAndKeepModel(new Citygml3FeatureMapper(config, file, unconnected), inputFactory, ois, verbose); } private static CityDoctorModel readAndKeepModel(Citygml3FeatureMapper mapper, CityGMLInputFactory inputFactory, @@ -496,52 +441,75 @@ public class CityGmlParser { // object members are replaced by href in model // need to remove the refs and re-add unparsed objects List acos = new ArrayList<>(); - while (reader.hasNext()) { - AbstractFeature chunk = reader.next(); - version = CityGMLModules.getCityGMLVersion(reader.getName().getNamespaceURI()); - if (chunk instanceof CityModel cModel) { - cModel.setCityObjectMembers(null); - mapper.setCityModel(cModel); - mapper.setCityGMLVersion(version); - } else if (chunk instanceof AbstractCityObject aco) { - acos.add(aco); - aco.accept(mapper); + CityModel cgmlModel = null; + CityDoctorModel cdModel = mapper.getModel(); + AutoCloseable parsingContext = cdModel.getCache().startParsingMode(); + try (parsingContext){ + List queuedObjects = new ArrayList<>(); + while (reader.hasNext()) { + AbstractFeature chunk = reader.next(); + version = CityGMLModules.getCityGMLVersion(reader.getName().getNamespaceURI()); + if (chunk instanceof CityModel cModel) { + cModel.setCityObjectMembers(null); + mapper.setCityModel(cModel); + mapper.setCityGMLVersion(version); + cgmlModel = cModel; + + if (!queuedObjects.isEmpty()) { + for (AbstractCityObject aco : queuedObjects) { + if (!cdModel.containsGmlId(aco.getId())) { + cgmlModel.getCityObjectMembers().add(new AbstractCityObjectProperty(aco)); + } + } + } + } else if (chunk instanceof AbstractCityObject aco) { + acos.add(aco); // getid + String id = aco.getId(); + aco.accept(mapper); + if (cgmlModel == null) { + // Add object to queue till the CityModel has been parsed + queuedObjects.add(aco); + }else if (!cdModel.containsGmlId(id)){ + cgmlModel.getCityObjectMembers().add(new AbstractCityObjectProperty(aco)); + } + } } - } - if (mapper.getModel().getCityModel() == null) { - // file does not contain a city model? - // create it for now - mapper.setCityModel(new CityModel()); - } - CityModel cModel = mapper.getModel().getCityModel(); - - // remove those that should have been parsed - List parsedCityObjects = mapper.getModel().createFeatureStream() - .map(CityObject::getGmlObject).toList(); - acos.removeAll(parsedCityObjects); - // re-add all not parsed objects - for (AbstractCityObject aco : acos) { - cModel.getCityObjectMembers().add(new AbstractCityObjectProperty(aco)); - } - if (logger.isInfoEnabled() && verbose) { - logger.info(Localization.getText("CityGmlParser.parsedObjects"), - mapper.getModel().getNumberOfFeatures()); + if (mapper.getModel().getCityModel() == null) { + // file does not contain a city model? + // create it for now + logger.warn(Localization.getText("CityGmlParser.missingCityModel")); + mapper.setCityModel(new CityModel()); + for (AbstractCityObject aco : queuedObjects) { + if (!cdModel.containsGmlId(aco.getId())) { + mapper.getModel().getCityModel().getCityObjectMembers().add(new AbstractCityObjectProperty(aco)); + } + } + } + + ImplicitGeometryHolder.resolveDeferredObjects(mapper.getModel().getCache()); + if (logger.isInfoEnabled() && verbose) { + logger.info(Localization.getText("CityGmlParser.parsedObjects"), + mapper.getModel().getNumberOfFeatures()); + } + mapper.setCityGMLVersion(version); + return mapper.getModel(); + } catch (Exception e) { + throw new CityGMLReadException(e); } - mapper.setCityGMLVersion(version); - return mapper.getModel(); + } } - private static void parseEpsgCodeFromFile(Path file, ParserConfiguration config) throws CityGmlParseException { + private static void parseEpsgCodeFromFile(Path file, ParserConfiguration config, boolean verbose) throws CityGmlParseException { try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file.toFile()))) { - parseEpsgCodeFromStream(bis, config); + parseEpsgCodeFromStream(bis, config, verbose); } catch (ParserConfigurationException | SAXException | IOException e) { throw new CityGmlParseException("Failed to read CityGML file", e); } } - private static void parseEpsgCodeFromStream(InputStream is, ParserConfiguration config) + private static void parseEpsgCodeFromStream(InputStream is, ParserConfiguration config, boolean verbose) throws ParserConfigurationException, SAXException { SAXParser parser = FACTORY.newSAXParser(); CityGmlHandler handler = new CityGmlHandler(); @@ -549,46 +517,19 @@ public class CityGmlParser { parser.parse(new InputSource(is), handler); } catch (EnvelopeFoundException e) { try { - parseCoordinateSystem(config, handler); + parseCoordinateSystem(config, handler, verbose); } catch (Exception e2) { logEpsgParseError(e2); } } catch (Exception e) { logEpsgParseError(e); } - if (handler.getEpsg() == null && logger.isInfoEnabled()) { + if (handler.getEpsg() == null && logger.isInfoEnabled() && verbose) { logger.info(Localization.getText("CityGmlParser.missingEPSGCode")); } } - private static void parseEpsgCodeFromBuffer(byte[] buffer, ParserConfiguration config) - throws ParserConfigurationException, SAXException { - InputStream is = new ByteArrayInputStream(buffer); - SAXParser parser = FACTORY.newSAXParser(); - CityGmlHandler handler = new CityGmlHandler(); - try { - parser.parse(new InputSource(is), handler); - } catch (EnvelopeFoundException e) { - try { - parseCoordinateSystem(config, handler); - - } catch (Exception e2) { - logEpsgParseError(e2); - } - } catch (SAXParseException spe) { - // suppress XML document structure warning - if (!spe.getMessage().matches("XML document structures must start and end within the same entity.")) { - logEpsgParseError(spe); - } - } catch (Exception e) { - logEpsgParseError(e); - } - if (handler.getEpsg() == null && logger.isInfoEnabled()) { - logger.info(Localization.getText("CityGmlParser.missingEPSGCode")); - } - } - private static void logEpsgParseError(Exception e) { logger.debug("Exception while parsing for EPSG code", e); if (logger.isWarnEnabled()) { @@ -596,7 +537,7 @@ public class CityGmlParser { } } - private static void parseCoordinateSystem(ParserConfiguration config, CityGmlHandler handler) { + private static void parseCoordinateSystem(ParserConfiguration config, CityGmlHandler handler, boolean verbose) { if (handler.getEpsg() == null) { return; } @@ -604,14 +545,14 @@ public class CityGmlParser { if (crs == null) { // could not find a coordinate system for srsName // assuming metric system - if (logger.isInfoEnabled()) { + if (logger.isInfoEnabled() && verbose) { logger.info(Localization.getText("CityGmlParser.missingEPSGCode")); } return; } if (crs.getProjection().getUnits() == Units.METRES) { // coordinate system is in meters, do not convert - if (logger.isInfoEnabled()) { + if (logger.isInfoEnabled() && verbose) { logger.info(Localization.getText("CityGmlParser.noConversionNeeded")); } return; @@ -636,11 +577,15 @@ public class CityGmlParser { CoordinateReferenceSystem utm; if (centerLat < 0) { // south - logger.info("Converting coordiante system to UTM zone {}S", zone); + if (logger.isInfoEnabled() && verbose) { + logger.info(Localization.getText("CityGmlParser.convertCrsToUtmZoneS"), zone); + } utm = CRS_FACTORY.createFromParameters("UTM", "+proj=utm +ellps=WGS84 +units=m +zone=" + zone + " +south"); } else { // north - logger.info("Converting coordiante system to UTM zone {}N", zone); + if (logger.isInfoEnabled() && verbose) { + logger.info(Localization.getText("CityGmlParser.convertCrsToUtmZoneN"), zone); + } utm = CRS_FACTORY.createFromParameters("UTM", "+proj=utm +ellps=WGS84 +units=m +zone=" + zone); } config.setCoordinateSystem(crs, utm); @@ -756,22 +701,14 @@ public class CityGmlParser { } private static void drainCityModel(CityDoctorModel model, CityGmlConsumer cityObjectConsumer) { - drainCityObjectList(model.getBuildings(), cityObjectConsumer); - drainCityObjectList(model.getBridges(), cityObjectConsumer); - drainCityObjectList(model.getVegetation(), cityObjectConsumer); - drainCityObjectList(model.getLand(), cityObjectConsumer); - drainCityObjectList(model.getTransportation(), cityObjectConsumer); - drainCityObjectList(model.getWater(), cityObjectConsumer); - drainCityObjectList(model.getTunnels(), cityObjectConsumer); - drainCityObjectList(model.getCityFurniture(), cityObjectConsumer); - drainCityObjectList(model.getGenericCityObjects(), cityObjectConsumer); - } - - private static void drainCityObjectList(List objects, CityGmlConsumer cityObjectConsumer) { - for (CityObject co : objects) { + List id = new ArrayList<>(); + model.createFeatureStream().forEach(co -> { cityObjectConsumer.accept(co); - } - objects.clear(); + id.add(co.getGmlId()); + }); + id.forEach(model::removeFeature); + } + } diff --git a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/tesselation/EarcutTesselator.java b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/tesselation/EarcutTesselator.java index acfc90f753a0b01a18f94ff71b0664389d4e5962..a3cfb759e826d2950aedf4c0913825e5d04f0e73 100644 --- a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/tesselation/EarcutTesselator.java +++ b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/tesselation/EarcutTesselator.java @@ -49,6 +49,15 @@ public class EarcutTesselator { start = addRingToArray(innerRing, vertices, start, axis); } + // center vertices? +// double[] projectedCenter = new double[2]; +// Geometry geometry = p.getParent(); +// Vector3d center = geometry.getCenter(); +// axis.writeCoordinatesOfVectorInArray(center, projectedCenter, 0); +// for (int i = 0; i < vertices.length; i++) { +// vertices[i] = vertices[i] - projectedCenter[i % 2]; +// } + // triangulation List indices = Earcut.earcut(vertices, holeStart, 2); List triangles = new ArrayList<>(); @@ -56,14 +65,15 @@ public class EarcutTesselator { throw new IllegalStateException(); } for (int i = 0; i < indices.size(); i = i + 3) { - Triangle3d t = new Triangle3d(vertexObjects.get(indices.get(i + 0)), - vertexObjects.get(indices.get(i + 1)), - vertexObjects.get(indices.get(i + 2))); + Vertex v1 = vertexObjects.get(indices.get(i + 0)); + Vertex v2 = vertexObjects.get(indices.get(i + 1)); + Vertex v3 = vertexObjects.get(indices.get(i + 2)); + Triangle3d t = new Triangle3d(v1, v2, v3); triangles.add(t); } return new TesselatedPolygon(triangles, p); } - + private static void addVerticesToList(LinearRing ring, List vertexObjects) { List vertices = ring.getVertices(); for (int i = 0; i < vertices.size() - 1; i++) { diff --git a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/utils/ArchivePacker.java b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/utils/ArchivePacker.java deleted file mode 100644 index feadacb3175f2e7e61bbf1d04f41e8c0eefbb030..0000000000000000000000000000000000000000 --- a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/utils/ArchivePacker.java +++ /dev/null @@ -1,98 +0,0 @@ -package de.hft.stuttgart.citydoctor2.utils; - -import de.hft.stuttgart.citydoctor2.datastructure.CityDoctorModel; -import de.hft.stuttgart.citydoctor2.zip.CityGmlZipArchive; -import de.hft.stuttgart.citydoctor2.zip.CityGmlZipEntry; -import org.apache.commons.io.FileUtils; -import org.apache.commons.io.FilenameUtils; -import org.apache.commons.io.IOUtils; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -import java.io.*; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.zip.ZipEntry; -import java.util.zip.ZipOutputStream; - -public class ArchivePacker { - - private static final Logger logger = LogManager.getLogger(ArchivePacker.class); - - private ArchivePacker(){} - - public static void packArchive(String targetPath, CityGmlZipArchive archive){ - Path outputPath = Path.of(targetPath); - outputPath = outputPath.getParent().resolve( - FilenameUtils.removeExtension(outputPath.getFileName().toString()) + ".zip"); - Path tmpDir = null; - try{ - tmpDir = Files.createTempDirectory("zipTmp"); - tmpDir.toFile().deleteOnExit(); - for (CityGmlZipEntry entry : archive.getEntries()) { - if (entry.getErrorType() != null || !entry.isLoaded()) { - continue; - } - CityDoctorModel model = entry.getModel(); - Path filePath = tmpDir.resolve(entry.getEntrySubPath()); - Files.createDirectories(filePath.getParent()); - model.saveAs(filePath.toString(), model.isValidated()); - } - zipFolder(tmpDir.toFile(), outputPath.toFile()); - - }catch (Exception e){ - logger.error(e); - } finally { - if (tmpDir != null) { - try { - FileUtils.deleteDirectory(tmpDir.toFile()); - } catch (IOException e) { - logger.error(e); - } - } - } - } - - - public static void zipFolder(File folder, File zipFile) throws IOException { - zipFolder(folder, new FileOutputStream(zipFile)); - } - - public static void zipFolder(File folder, OutputStream outputStream) throws IOException { - try (ZipOutputStream zipOutputStream = new ZipOutputStream(outputStream)) { - processFolder(folder, zipOutputStream, folder.getPath().length() + 1); - } - } - - private static void processFolder(File folder, ZipOutputStream zipOutputStream, int prefixLength) - throws IOException { - for (File file : folder.listFiles()) { - if (file.isFile()) { - ZipEntry zipEntry = new ZipEntry(file.getPath().substring(prefixLength)); - zipOutputStream.putNextEntry(zipEntry); - try (FileInputStream inputStream = new FileInputStream(file)) { - IOUtils.copy(inputStream, zipOutputStream); - } - zipOutputStream.closeEntry(); - } else if (file.isDirectory()) { - processFolder(file, zipOutputStream, prefixLength); - } - } - } - - public static void packAndDeleteDirectory(String directoryPath) throws IOException { - Path sourcePath = Path.of(directoryPath); - if (!Files.exists(sourcePath)) { - throw new IllegalStateException("Directory " + directoryPath + " does not exist"); - } - - if (!Files.isDirectory(sourcePath)) { - throw new IllegalStateException("Path " + directoryPath + " is not a directory"); - } - Path outputPath = sourcePath.getParent().resolve(sourcePath.getFileName() + ".zip"); - zipFolder(sourcePath.toFile(), outputPath.toFile()); - - FileUtils.deleteDirectory(sourcePath.toFile()); - } - -} diff --git a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/utils/BoundingBoxCalculator.java b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/utils/BoundingBoxCalculator.java index 94a65d45c1c497343cf56f271cdd745aef0fdbc3..1285b0c741c3abed146f215f8edb082f2e0aff8f 100644 --- a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/utils/BoundingBoxCalculator.java +++ b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/utils/BoundingBoxCalculator.java @@ -26,12 +26,10 @@ import de.hft.stuttgart.citydoctor2.datastructure.CityDoctorModel; import de.hft.stuttgart.citydoctor2.datastructure.CityObject; import de.hft.stuttgart.citydoctor2.datastructure.Geometry; import de.hft.stuttgart.citydoctor2.datastructure.Polygon; -import de.hft.stuttgart.citydoctor2.datastructure.TopLevelTransportFeature; -import de.hft.stuttgart.citydoctor2.datastructure.TrafficSpaceObject; -import de.hft.stuttgart.citydoctor2.datastructure.TransportationObject; -import de.hft.stuttgart.citydoctor2.datastructure.TransportationSpace; import de.hft.stuttgart.citydoctor2.datastructure.Vertex; import de.hft.stuttgart.citydoctor2.math.Vector3d; +import de.hft.stuttgart.citydoctor2.utils.visitors.CityObjectCollector; +import de.hft.stuttgart.citydoctor2.utils.visitors.MinMaxExtentVisitor; /** * Utility class for calculating axis aligned bounding boxes for different @@ -99,24 +97,10 @@ public class BoundingBoxCalculator { * @return the bounding box of the model */ public static BoundingBox calculateBoundingBox(CityDoctorModel model) { - Vector3d low = new Vector3d(Double.MAX_VALUE, Double.MAX_VALUE, Double.MAX_VALUE); - Vector3d high = new Vector3d(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY); + MinMaxExtentVisitor mima = new MinMaxExtentVisitor(); + model.accept(mima); - //TODO: Rework this using visitors - findMinMax(low, high, model.getBuildings()); - findMinMax(low, high, model.getBridges()); - findMinMax(low, high, model.getLand()); - findMinMaxTransport(low, high, model.getTransportation()); - findMinMax(low, high, model.getWater()); - findMinMax(low, high, model.getVegetation()); - findMinMax(low, high, model.getTunnels()); - findMinMax(low, high, model.getCityFurniture()); - findMinMax(low, high, model.getGenericCityObjects()); - - Vector3d[] result = new Vector3d[2]; - result[0] = low; - result[1] = high; - return BoundingBox.of(result); + return BoundingBox.of(mima.getMinMaxExtent()); } public static BoundingBox calculateBoundingBoxFromPoints(List points) { @@ -159,47 +143,39 @@ public class BoundingBoxCalculator { } } - //TODO: Implement this properly with visitor. Quick and dirty fix for the renderer - private static void findMinMaxTransport(Vector3d low, Vector3d high, List features) { - for (TransportationObject to : features) { - findMinMax(low, high, to); - if (to instanceof TransportationSpace ts) { - findMinMaxTransport(low, high, ts.getTrafficSpaces()); - findMinMaxTransport(low, high, ts.getAuxTrafficSpaces()); - if (to instanceof TopLevelTransportFeature top) { - findMinMaxTransport(low, high, top.getSections()); - findMinMaxTransport(low, high, top.getIntersections()); + + private static void findMinMax(Vector3d low, Vector3d high, CityObject co) { + CityObjectCollector collector = new CityObjectCollector(); + co.accept(collector); + for (CityObject object : collector.getCityObjects()) { + for (Geometry geom : object.getGeometries()) { + if (geom.getVertices() == null) { + geom.updateVertices(); } - } else if (to instanceof TrafficSpaceObject tso) { - findMinMaxTransport(low, high, tso.getTrafficAreas()); + findMinMax(low, high, geom); } } } - private static void findMinMax(Vector3d low, Vector3d high, CityObject co) { - for (Geometry geom : co.getGeometries()) { - if (geom.getVertices() == null) { - geom.updateVertices(); + private static void findMinMax(Vector3d low, Vector3d high, Geometry geom) { + for (Vertex v : geom.getVertices()) { + if (v.getX() < low.getX()) { + low.setX(v.getX()); } - for (Vertex v : geom.getVertices()) { - if (v.getX() < low.getX()) { - low.setX(v.getX()); - } - if (v.getX() > high.getX()) { - high.setX(v.getX()); - } - if (v.getY() < low.getY()) { - low.setY(v.getY()); - } - if (v.getY() > high.getY()) { - high.setY(v.getY()); - } - if (v.getZ() < low.getZ()) { - low.setZ(v.getZ()); - } - if (v.getZ() > high.getZ()) { - high.setZ(v.getZ()); - } + if (v.getX() > high.getX()) { + high.setX(v.getX()); + } + if (v.getY() < low.getY()) { + low.setY(v.getY()); + } + if (v.getY() > high.getY()) { + high.setY(v.getY()); + } + if (v.getZ() < low.getZ()) { + low.setZ(v.getZ()); + } + if (v.getZ() > high.getZ()) { + high.setZ(v.getZ()); } } } diff --git a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/utils/TimeFormatter.java b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/utils/TimeFormatter.java new file mode 100644 index 0000000000000000000000000000000000000000..509bdfaa3a81bba4831de362d7937dfd159c8f54 --- /dev/null +++ b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/utils/TimeFormatter.java @@ -0,0 +1,62 @@ +package de.hft.stuttgart.citydoctor2.utils; + +import java.text.ChoiceFormat; + +public final class TimeFormatter { + + private TimeFormatter(){} + + private static final String LESS_THAN_A_SECOND = + Localization.getText("TimeFormatter.lessThanASecond"); + + private static final ChoiceFormat SECONDS = + new ChoiceFormat( + new double[]{1, 2}, + new String[]{Localization.getText("TimeFormatter.oneSecond"), + Localization.getText("TimeFormatter.seconds")} + ); + + private static final ChoiceFormat MINUTES = + new ChoiceFormat( + new double[]{1, 2}, + new String[]{Localization.getText("TimeFormatter.oneMinute"), + Localization.getText("TimeFormatter.minutes")} + ); + + private static final ChoiceFormat HOURS = + new ChoiceFormat( + new double[] {1, 2}, + new String[]{Localization.getText("TimeFormatter.oneHour"), + Localization.getText("TimeFormatter.hours")} + ); + + /** + * Formats a time measurement in milliseconds as a localized String representation. + * + *

+ * The String representation will return the time as a rounded down integer of the biggest fitting TimeUnit + * (seconds, minutes or hours), returning "< 1 second" for times under a second. + *

+ * @param millis + * @return A localized String representation of the timespan + */ + public static String format(long millis) { + if (millis < 1000) { + return LESS_THAN_A_SECOND; + }else if (millis < 60_000) { + long seconds = millis / 1000; + String pattern = SECONDS.format(seconds); + return pattern.replace("{0}", Long.toString(seconds)); + }else if (millis < 3_600_000){ + long minutes = millis / 60_000; + String pattern = MINUTES.format(minutes); + return pattern.replace("{0}", Long.toString(minutes)); + } else { + long hours = millis / 3_600_000; + String pattern = HOURS.format(hours); + return pattern.replace("{0}", Long.toString(hours)); + } + + + } +} \ No newline at end of file diff --git a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/utils/visitors/MinMaxExtentVisitor.java b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/utils/visitors/MinMaxExtentVisitor.java new file mode 100644 index 0000000000000000000000000000000000000000..8ba58ac031dab02b572b90ec4532d5c0d6e0af6f --- /dev/null +++ b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/utils/visitors/MinMaxExtentVisitor.java @@ -0,0 +1,57 @@ +package de.hft.stuttgart.citydoctor2.utils.visitors; + +import de.hft.stuttgart.citydoctor2.check.Checkable; +import de.hft.stuttgart.citydoctor2.check.CheckableUtilsVisitor; +import de.hft.stuttgart.citydoctor2.datastructure.CityObject; +import de.hft.stuttgart.citydoctor2.datastructure.Geometry; +import de.hft.stuttgart.citydoctor2.datastructure.ImplicitGeometryHolder; +import de.hft.stuttgart.citydoctor2.datastructure.Vertex; +import de.hft.stuttgart.citydoctor2.math.Vector3d; + +public class MinMaxExtentVisitor extends CheckableUtilsVisitor { + + Vector3d low; + Vector3d high; + + public MinMaxExtentVisitor() { + low = new Vector3d(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY); + high = new Vector3d(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY); + } + + public Vector3d[] getMinMaxExtent() { + Vector3d[] result = new Vector3d[2]; + result[0] = low; + result[1] = high; + return result; + } + + @Override + public void check(CityObject co) { + for (Geometry geom : co.getGeometries()) { + if (geom.getVertices() == null) { + geom.updateVertices(); + } + for (Vertex v : geom.getVertices()) { + if (v.getX() < low.getX()) { + low.setX(v.getX()); + } + if (v.getX() > high.getX()) { + high.setX(v.getX()); + } + if (v.getY() < low.getY()) { + low.setY(v.getY()); + } + if (v.getY() > high.getY()) { + high.setY(v.getY()); + } + if (v.getZ() < low.getZ()) { + low.setZ(v.getZ()); + } + if (v.getZ() > high.getZ()) { + high.setZ(v.getZ()); + } + } + } + } + +} diff --git a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/writer/CityGMLWriterUtils.java b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/writer/CityGMLWriterUtils.java index 4069621e5d79b0386bb5f9d4885ef4243b1d482a..e3b9cbfb9cfba0e2eed6f3dbaa57e6a93cf15f71 100644 --- a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/writer/CityGMLWriterUtils.java +++ b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/writer/CityGMLWriterUtils.java @@ -22,12 +22,12 @@ import java.io.File; import java.time.ZonedDateTime; import java.util.HashMap; import java.util.Iterator; -import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.UUID; import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Stream; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -92,7 +92,7 @@ public class CityGMLWriterUtils { storeCityObjects(model.getTransportation(), gmlFactory, model, cModel, val); storeCityObjects(model.getWater(), gmlFactory, model, cModel, val); storeCityObjects(model.getCityFurniture(), gmlFactory, model, cModel, val); - storeCityObjects(model.getGenericCityObjects(), gmlFactory, model, cModel, val); + storeCityObjects(model.getOtherCityObjects(), gmlFactory, model, cModel, val); storeCityObjects(model.getTunnels(), gmlFactory, model, cModel, val); writer.write(cModel); @@ -135,12 +135,13 @@ public class CityGMLWriterUtils { de.hft.stuttgart.quality.model.enums.ErrorId adeId = QualityADEUtils.mapErrorIdToAdeId(e.getKey()); if (adeId == null) { // error that is not part of the ade standard - logger.warn("Found error {} that cannot be converted to ADE error. It will not be written", e.getKey()); + logger.warn(Localization.getText("CityGmlWriterUtils.unknownADEError"), e.getKey()); continue; } stats.setName(adeId); statistics.getErrors().add(new ErrorProperty(stats)); } + // TODO: Quality ADE update to CityGML 3.0 statistics.setNumErrorBuildings(new FeatureStatisticsProperty(countValidatedCityObjects(model.getBuildings()))); statistics.setNumErrorBridgeObjects(new FeatureStatisticsProperty(countValidatedCityObjects(model.getBridges()))); statistics.setNumErrorLandObjects(new FeatureStatisticsProperty(countValidatedCityObjects(model.getLand()))); @@ -152,29 +153,30 @@ public class CityGMLWriterUtils { return val; } - private static FeatureStatistics countValidatedCityObjects(List cos) { - int numChecked = 0; - int numError = 0; - for (CityObject co : cos) { + private static FeatureStatistics countValidatedCityObjects(Stream cos) { + AtomicInteger numChecked = new AtomicInteger(); + AtomicInteger numError = new AtomicInteger(); + cos.forEach(co -> { if (co.isValidated()) { - numChecked++; + numChecked.getAndIncrement(); if (co.containsAnyError()) { - numError++; + numError.getAndIncrement(); } } - } - return new FeatureStatistics(numChecked, numError); + }); + return new FeatureStatistics(numChecked.get(), numError.get()); } - private static void storeCityObjects(List cos, GeometryFactory gmlFactory, CityDoctorModel model, CityModel cModel, Validation val) { - for (CityObject co : cos) { + private static void storeCityObjects(Stream cos, GeometryFactory gmlFactory, CityDoctorModel model, CityModel cModel, Validation val) { + cos.forEach(co -> { if (model.isValidated() && val != null) { QualityADEUtils.writeQualityAde(co, val); } co.reCreateGeometries(gmlFactory, model.getParserConfig()); cModel.getCityObjectMembers().add(new AbstractCityObjectProperty(co.getGmlObject())); - } + }); + } } diff --git a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/zip/CityGmlZipArchive.java b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/zip/CityGmlZipArchive.java deleted file mode 100644 index be6e4cda33b7f24ea127a9f14ed48ae55fa21b27..0000000000000000000000000000000000000000 --- a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/zip/CityGmlZipArchive.java +++ /dev/null @@ -1,151 +0,0 @@ -package de.hft.stuttgart.citydoctor2.zip; - -import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration; -import de.hft.stuttgart.citydoctor2.utils.ArchivePacker; -import de.hft.stuttgart.citydoctor2.utils.Localization; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.Serial; -import java.io.Serializable; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.List; -import java.util.zip.ZipEntry; -import java.util.zip.ZipFile; -import java.util.zip.ZipInputStream; - -/** - * This class serves as a representation of a ZIP-archive containing CityGml files. The contained files are represented - * by {@link CityGmlZipEntry} objects. - */ -public class CityGmlZipArchive implements Serializable { - - private static final Logger logger = LogManager.getLogger(CityGmlZipArchive.class); - - @Serial - private static final long serialVersionUID = 2168389511043362615L; - - private List entries; - private final Path archivePath; - private final String archiveNameRE; - - /** - * Registers a ZIP-file as an archive. All contained XML and GML files will be registered as {@link CityGmlZipEntry} objects. - * - * @param zipFile path of the ZIP-file - * @return A {@link CityGmlZipArchive} object representing the archive, or null if read-access for the ZIP-file was denied - * @throws MalformedZipFileException if the ZIP-file has encoding errors - */ - public static CityGmlZipArchive register(String zipFile) throws MalformedZipFileException { - ArrayList archiveEntries = new ArrayList<>(); - CityGmlZipArchive cgmlArchive = new CityGmlZipArchive(Path.of(zipFile)); - try (ZipInputStream zis = new ZipInputStream(new FileInputStream(zipFile))) { - ZipEntry ze; - while ((ze = zis.getNextEntry()) != null) { - if (ze.isDirectory()) { - continue; - } - if (ze.getName().endsWith(".gml") || ze.getName().endsWith(".xml")) { - // Ignore report files generated by CityDoctor - if (ze.getName().endsWith("_report.xml")) { - continue; - } - archiveEntries.add(CityGmlZipEntry.register(ze, cgmlArchive)); - } - } - cgmlArchive.setEntries(archiveEntries); - return cgmlArchive; - } catch (IOException e) { - logger.error(Localization.getText("CityGmlZipArchive.ioError")); - logger.debug(e.getMessage(), e); - return null; - } catch (IllegalArgumentException e) { - logger.error(Localization.getText("CityGmlZipArchive.malformedZipFile")); - throw new MalformedZipFileException(Localization.getText("CityGmlZipArchive.malformedZipFile")); - } catch (Exception e) { - logger.error(Localization.getText("CityGmlZipArchive.generalException")); - logger.debug(e.getMessage(), e); - throw (e); - } - } - - /** - * Attempts to load all contained {@link CityGmlZipEntry} objects into memory. - * - * @param config Parser configuration for the entries - */ - public void mountArchive(ParserConfiguration config) { - try (ZipFile zip = new ZipFile(archivePath.toFile())) { - for (CityGmlZipEntry entry : entries) { - entry.loadEntry(config); - } - } catch (IOException e) { - logger.error(e); - } - } - - private CityGmlZipArchive(Path archivePath) { - this.archivePath = archivePath; - this.archiveNameRE = archivePath.getFileName().toString().replace(".zip", "") + File.separator; - } - - private void setEntries(List entries) { - this.entries = entries; - } - - /** - * Saves this archive as a ZIP-file. - * @param path target path for the export - */ - public void exportToZipFile(String path) { - ArchivePacker.packArchive(path, this); - } - - /** - * Gets an entry in this archive by its subpath. - * - * @param subpath subpath to the entry from this archive's root directory - * @return the corresponding entry, or null if entry could not be found - */ - public CityGmlZipEntry getEntry(String subpath) { - subpath = stripArchivePath(subpath); - for (CityGmlZipEntry entry : entries) { - String entryName = stripArchivePath(entry.getEntrySubPath()); - if (entryName.equals(subpath)) { - return entry; - } - } - return null; - } - - /** - * Strips the root directory name of this archive from an entry subpath. - * @param path the relative path to the entry - * @return String of the path without the root directory - */ - private String stripArchivePath(String path) { - Path systemPath = Path.of(path); - return systemPath.toString().replace(archiveNameRE, ""); - } - - /** - * Gets the path to the ZIP-file associated with this archive. - * @return path of the ZIP-file - */ - public Path getArchivePath() { - return archivePath; - } - - /** - * Gets the entry list of this archive. - * @return the entry list - */ - public List getEntries() { - return entries; - } - -} diff --git a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/zip/CityGmlZipEntry.java b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/zip/CityGmlZipEntry.java deleted file mode 100644 index d9a86770b90e4f6e5703bf1a31adfda17080d9bd..0000000000000000000000000000000000000000 --- a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/zip/CityGmlZipEntry.java +++ /dev/null @@ -1,211 +0,0 @@ -package de.hft.stuttgart.citydoctor2.zip; - -import de.hft.stuttgart.citydoctor2.datastructure.CityDoctorModel; -import de.hft.stuttgart.citydoctor2.parser.CityGmlParseException; -import de.hft.stuttgart.citydoctor2.parser.CityGmlParser; -import de.hft.stuttgart.citydoctor2.parser.InvalidGmlFileException; -import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration; -import de.hft.stuttgart.citydoctor2.parser.ProgressListener; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -import java.io.IOException; -import java.io.Serial; -import java.io.Serializable; -import java.nio.file.Path; -import java.util.zip.ZipEntry; - -/** - * This class serves as a representation of a CityGml file in a ZIP archive. - *

- * The {@link CityDoctorModel} of the associated file can only be accessed after loading the corresponding entry. - */ -public class CityGmlZipEntry implements Serializable { - - private static final Logger logger = LogManager.getLogger(CityGmlZipEntry.class); - @Serial - private static final long serialVersionUID = -5732913269959043262L; - - private final Path filePath; - private final String fileName; - private final String displayName; - private transient CityDoctorModel model; - private CityGmlZipArchive parentArchive; - private boolean inMemory; - private long fileSize = -1L; - private static final long MB = 1024 * 1024L; - private ZipEntryErrorType errorType = null; - - - /** - * Attempts to parse the CityGML model associated with this entry and loads it into memory. - *

- * In the event of a parsing error, the entry will be flagged by assigning the appropriate - * {@link ZipEntryErrorType} to the errorType field. - * - * @param config Parser configuration for this model - */ - public void loadEntry(ParserConfiguration config) { - loadEntry(config, null); - } - - /** - * Attempts to parse the CityGML model associated with this entry and loads it into memory. - *

- * In the event of a parsing error, the entry will be flagged by assigning the appropriate - * {@link ZipEntryErrorType} to the errorType field. - * - * @param config Parser configuration for this model - * @param l ProgressListener for tracking parsing progress - */ - public void loadEntry(ParserConfiguration config, ProgressListener l) { - if (inMemory) { - return; - } - if (errorType != null) { - logger.warn("Tried loading erroneous CityGmlZipEntry"); - return; - } - try { - this.model = CityGmlParser.parseCityGmlZipEntry(this, config, l); - this.inMemory = true; - } catch (CityGmlParseException | InvalidGmlFileException e) { - logger.error(e); - this.errorType = ZipEntryErrorType.INVALID_CITY_GML_FILE; - } catch (IOException e) { - logger.error(e); - this.errorType = ZipEntryErrorType.IO_ERROR; - } - } - - /** - * Registers a {@link ZipEntry ZipEntry} in a ZIP-archive as a {@link CityGmlZipEntry}. - *

- * If the filesize of the associated file exceeds the total available system memory, or read access is denied, - * the entry will be flagged by assigning the appropriate {@link ZipEntryErrorType} to the errorType field. - * - * @param entry The ZipEntry object - * @param parentArchive The parent archive for this entry - * @return A corresponding CityGmlZipEntry object - */ - public static CityGmlZipEntry register(ZipEntry entry, CityGmlZipArchive parentArchive) { - CityGmlZipEntry cgzEntry = new CityGmlZipEntry(entry, parentArchive, false); - try { - if (!cgzEntry.entrySizeWithinMemoryLimits()) { - cgzEntry.errorType = ZipEntryErrorType.EXCESSIVE_FILESIZE; - } - } catch (IOException e) { - logger.error(e); - cgzEntry.errorType = ZipEntryErrorType.IO_ERROR; - } - return cgzEntry; - } - - /** - * Checks if the filesize of this entry would exceed the system's available memory. - * - * @return true if within limits, false otherwise - * @throws IOException if read access to the ZIP-archive is denied - */ - private boolean entrySizeWithinMemoryLimits() throws IOException { - long memoryLimit = (long) Math.ceil(((double) Runtime.getRuntime().maxMemory() / MB) * 0.9); - if (fileSize == -1L) { - try (CityGmlZipEntryFile entryFile = new CityGmlZipEntryFile(this)) { - long filesize = entryFile.getFileSize(); - if (filesize != -1) { - this.fileSize = filesize; - } else { - return false; - } - } catch (Exception e) { - throw new IOException(e); - } - } - return memoryLimit > (fileSize / MB); - } - - private CityGmlZipEntry(ZipEntry entry, CityGmlZipArchive parentArchive, boolean inMemory) { - this.fileName = entry.getName(); - this.filePath = Path.of(entry.getName()); - this.displayName = filePath.getFileName().toString(); - if (entry.getSize() != -1) { - this.fileSize = entry.getSize(); - } - this.model = null; - this.inMemory = inMemory; - this.parentArchive = parentArchive; - } - - /** - * Gets the parent archive of this entry. - * @return the archive - */ - public CityGmlZipArchive getArchive() { - return parentArchive; - } - - /** - * Gets the sub-path in the archive of the file associated with this entry. - * - * @return the relative sub-path from the archive root directory - */ - public String getEntrySubPath() { - return fileName; - } - - /** - * Gets the name of the file associated with this entry. - * @return the filename - */ - public String getDisplayName() { - return displayName; - } - - /** - * Gets the {@link ZipEntryErrorType} of this entry. - * @return the error type, or null if this entry is not erroneous - */ - public ZipEntryErrorType getErrorType() { - return errorType; - } - - /** - * Gets the {@link CityDoctorModel} of this entry. - * @return The model, or null if the entry has not been loaded or is erroneous - */ - public CityDoctorModel getModel() { - return model; - } - - public void setFileSize(long size) { - fileSize = size; - } - - /** - * Resolves the reference path of a {@link de.hft.stuttgart.citydoctor2.datastructure.LibraryObject LibraryObject} - * in the {@link CityDoctorModel} of this entry. - * @param libraryObjectPath The reference path to the LibraryObject's CityGml file - * @return Relative sub-path within the archive to the CityGml file - */ - public Path resolveLibraryObjectPath(String libraryObjectPath) { - return filePath.getParent().resolve(libraryObjectPath); - } - - /** - * Checks if the {@link CityDoctorModel} of this entry has been loaded into memory. - * - * @return true if it is loaded, false otherwise - */ - public boolean isLoaded() { - return inMemory; - } - - /** - * Returns the estimated uncompressed filesize of this entry. - * - * @return filesize in bytes, -1L if filesize is unknown - */ - public long getFileSize() { - return fileSize; - } -} diff --git a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/zip/CityGmlZipEntryFile.java b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/zip/CityGmlZipEntryFile.java deleted file mode 100644 index 3bf82fe00a2490d9eef2eb715ef6edc5a4a14786..0000000000000000000000000000000000000000 --- a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/zip/CityGmlZipEntryFile.java +++ /dev/null @@ -1,79 +0,0 @@ -package de.hft.stuttgart.citydoctor2.zip; - -import java.io.BufferedInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.zip.ZipEntry; -import java.util.zip.ZipFile; - -/** - * This class serves as a resource for read-access to the file that is being represented by - * a CityGmlZipEntry object. - *

- * Does not decompress the file or the parent ZIP-archive. - */ -public class CityGmlZipEntryFile implements AutoCloseable { - - private final ZipFile zip; - private final ZipEntry zipEntry; - private final CityGmlZipEntry cgmlZipEntry; - private boolean closed = false; - - /** - * Creates a {@link CityGmlZipEntryFile} for a {@link CityGmlZipEntry} object's referenced file. - * - * @param entry the requested entry - * @throws IOException if read access to the ZIP-archive is denied. - */ - public CityGmlZipEntryFile(CityGmlZipEntry entry) throws IOException { - CityGmlZipArchive archive = entry.getArchive(); - zip = new ZipFile(archive.getArchivePath().toFile()); - zipEntry = zip.getEntry(entry.getEntrySubPath()); - this.cgmlZipEntry = entry; - } - - /** - * Gets a new InputStream of this file. - *

- * Returned streams are independent of each other, but will all be closed when the {@link CityGmlZipEntryFile} object - * is closed. - * @return an InputStream of this file. - * @throws IOException when this method is called after the file has been closed. - */ - public InputStream getInputStream() throws IOException { - if (closed){ - throw new IOException("CityGmlZipEntryFile closed"); - } - return zip.getInputStream(zipEntry); - } - - /** - * Gets an estimation of this file's filesize. - * @return filesize in bytes, -1L if unknown - * @throws IOException when this method is called after the file has been closed. - */ - public long getFileSize() throws IOException { - if (closed){ - throw new IOException("CityGmlZipEntryFile closed"); - } - if (cgmlZipEntry.getFileSize() == -1L) { - if (zipEntry.getSize() == -1) { - long bytes = 0; - InputStream is = new BufferedInputStream(this.getInputStream()); - for (int i = is.read(); i != -1; i = is.read()) { - bytes++; - } - cgmlZipEntry.setFileSize(bytes); - } else { - cgmlZipEntry.setFileSize(zipEntry.getSize()); - } - } - return cgmlZipEntry.getFileSize(); - } - - @Override - public void close() throws IOException { - zip.close(); - closed = true; - } -} diff --git a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/zip/MalformedZipFileException.java b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/zip/MalformedZipFileException.java deleted file mode 100644 index 759fbe6bffca2ee965fbbb0b84a35b6202398084..0000000000000000000000000000000000000000 --- a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/zip/MalformedZipFileException.java +++ /dev/null @@ -1,17 +0,0 @@ -package de.hft.stuttgart.citydoctor2.zip; - -import java.util.zip.ZipException; - -/** - * Signals that a ZIP-file is corrupted and couldn't be parsed. - */ -public class MalformedZipFileException extends ZipException { - - public MalformedZipFileException() { - super(); - } - - public MalformedZipFileException(String message) { - super(message); - } -} diff --git a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/zip/ZipEntryErrorType.java b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/zip/ZipEntryErrorType.java deleted file mode 100644 index 7dec72b42b00da211c994f85d05005916e9430bf..0000000000000000000000000000000000000000 --- a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/zip/ZipEntryErrorType.java +++ /dev/null @@ -1,8 +0,0 @@ -package de.hft.stuttgart.citydoctor2.zip; - -/** - * Error types for {@link CityGmlZipEntry} objects. - */ -public enum ZipEntryErrorType { - INVALID_CITY_GML_FILE, EXCESSIVE_FILESIZE, IO_ERROR -} diff --git a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/zip/ZipParser.java b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/zip/ZipParser.java deleted file mode 100644 index e65d96b82ad2b8f3d29109348ccf6bb22107de2e..0000000000000000000000000000000000000000 --- a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/zip/ZipParser.java +++ /dev/null @@ -1,12 +0,0 @@ -package de.hft.stuttgart.citydoctor2.zip; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -public class ZipParser { - - private static final Logger logger = LogManager.getLogger(ZipParser.class); - - - -} diff --git a/CityDoctorParent/CityDoctorModel/src/main/resources/CityDoctorLocalization.properties b/CityDoctorParent/CityDoctorModel/src/main/resources/CityDoctorLocalization.properties index 78349133d6520a64c71648949f2205e4c513add6..59ecf4ef6cf2cbcb46cf92569781ccb940c2ff54 100644 --- a/CityDoctorParent/CityDoctorModel/src/main/resources/CityDoctorLocalization.properties +++ b/CityDoctorParent/CityDoctorModel/src/main/resources/CityDoctorLocalization.properties @@ -1,173 +1,201 @@ -CityDoctorValidation.Version=${versionString} -DistanceError.distanceFromPlane=distance from plane -AboutDialog.developedBy=Developed by +AboutDialog.closeBtn=Close AboutDialog.contact=Contact +AboutDialog.developedBy=Developed by AboutDialog.title=CityDoctor 3 - About -AboutDialog.closeBtn=Close -CheckDialog.title=Check Configuration -CheckDialog.schematronFiles=Schematron Files -CheckDialog.schematronChooserTitle=Choose schematron file.. -CheckDialog.validationConfiguration=Validation Configuration -CheckDialog.startingChecks=Starting checks -CheckDialog.checksDone=Checks done -CheckDialog.failedChecks=Failed to execute checks -CheckDialog.schematronFileNotExisting=Schematron file does not exist, ignoring +CheckContainer.error=Unexpected exception while executing check: {} +CheckDialog.availableChecksLabel=Available Checks +CheckDialog.cancelBtn=Cancel +CheckDialog.checkBtn=Check CheckDialog.checkEnabled=Enabled CheckDialog.checkName=Name -CheckDialog.parameterValue=Value +CheckDialog.checksDone=Checks done +CheckDialog.checksReenabledAlert=Some checks have been reenabled so that other wanted checks can be executed\nSee the log for more information. +CheckDialog.checksTab=Checks +CheckDialog.failedChecks=Failed to execute checks +CheckDialog.filterTab=Filter +CheckDialog.geometricChecksLabel=Geometric Checks +CheckDialog.globalParametersLabel=Global Parameters +CheckDialog.noPathError=Output path is missing! +CheckDialog.outputPathBtn=Select +CheckDialog.outputPathLabel=Output directory (Required): CheckDialog.parameterUnit=Unit +CheckDialog.parameterValue=Value +CheckDialog.pdfReportsOption=Create PDF reports +CheckDialog.schematronChooserTitle=Choose schematron file ... +CheckDialog.schematronFileLabel=Schematron File: +CheckDialog.schematronFileNotExisting=Schematron file does not exist, Schematron will be skipped +CheckDialog.schematronFiles=Schematron Files +CheckDialog.selectBtn=Select +CheckDialog.semanticChecksLabel=Semantic Checks +CheckDialog.startingChecks=Starting checks +CheckDialog.streamCheckLabel=Citymodels are not loaded and kept in memory. Check results are saved to the QualityADE in copies of the input files. +CheckDialog.streamCheckOption=Use low memory mode +CheckDialog.title=Check Configuration +CheckDialog.validationConfiguration=Validation Configuration +CheckDialog.xmlReportsOption=Create XML reports +Checker.checkFeature=Checking feature: {} +Checker.checksFinished=Finished executing checks. Total time: {0} +Checker.dbStillUnresponsive=Checker still unable to load some CityObjects from database! +Checker.dbUnresponsive=Checker could not load some CityObjects from database! +Checker.executeCheck=Executing check: {} +Checker.failPdf=Failed to write PDF Report. +Checker.failReports=Failed to write reports. +Checker.failXml=Failed to write XML Error Report. +Checker.finishedSchematron=Finished Schematron validation +Checker.futuresCheckFailures=Encountered check failures due to the following errors: +Checker.noCheckSatisfiesRequirement=Could not find any check that satisfies requirement {}, it will not be checked +Checker.schematronCompleted=Schematron completed +Checker.schematronFileNotFound=Schematron file {} could not be found +Checker.schematronInterrupted=Main Thread was interrupted while waiting for Schematron +Checker.schematronStillRunning=Schematron is still running. Waiting for completion, this may take some time +Checker.schematronValidation=Schematron-validation thread started +Checker.shutdownInterrupted=Main Thread got interrupted during ThreadPool shutdown +Checker.validationInterrupted=Validation aborted: Checker got interrupted +Checker.waitAndRetry=Waiting a second before retrying... +Checks.missingCheck=Could not find check for id: {} +CityDoctorController.exportSuccess=Successfully exported feature CityDoctorController.noDatamodel=Datamodel is null, no checks could be done CityDoctorController.noSourceFile=Source file is null, no checks could be done CityDoctorController.noZipFile=ZIP archive is null, no checks could be done -CityDoctorController.exportSuccess=Successfully exported feature CityDoctorController.saveZipArchiveReports=Successfully exported validation reports! +CityDoctorValidation.Version=${versionString} +CityDoctorValidation.inputFileNotExisting= Input file '{}' does not exist. +CityDoctorValidation.loadingDefaultConfig=No configuration file given, loading default configuration +CityDoctorValidation.noConfig=No configuration file specified with -config [FILE] +CityDoctorValidation.noInputFile=No input file specified. (-in [FILE]) +CityDoctorValidation.noOutputFile=No output file specified. (-out [FILE]) +CityDoctorValidation.notExactlyOneConfigFile=Specify exactly one file as configuration +CityDoctorValidation.notExactlyOneInputFile=Specify exactly one file as input. +CityDoctorValidation.notExactlyOneOutputFile=Specify exactly one file as output. +CityDoctorValidation.notExactlyOnePDFOutput=Specify exactly one file as pdfReport +CityDoctorValidation.notExactlyOneXMLOutput=Specify exactly one file as xmlReport +CityDoctorValidation.wrongInputFileFormat=Input file '{}' does not end with .gml or .xml +CityGmlParser.chunkReadFailed=Failed to read GML file in chunks, falling back to reading the complete file +CityGmlParser.convertCrsToUtmZoneN=Converting coordinate system to UTM zone {}N +CityGmlParser.convertCrsToUtmZoneS=Converting coordinate system to UTM zone {}S +CityGmlParser.creating4jContextFailed=Unable to create citygml4j context +CityGmlParser.creatingAdePluginsFailed=Unable to add ADE plugins to citygml4j +CityGmlParser.errorReadingGmlFile=Error while reading city gml file\n{} +CityGmlParser.errorWritingGmlFile=Error while writing city gml file\n{} +CityGmlParser.failedEPSGParse=Could not read EPSG code, fallback to metric system +CityGmlParser.missingCityModel=File does not contain a CityModel definition! Temporary CityModel will be created. +CityGmlParser.missingEPSGCode=No EPSG code found, assuming metric system +CityGmlParser.noConversionNeeded=Coordinate system is in meters, no conversion done +CityGmlParser.notValidGmlFile=This is not a valid GML-File\n +CityGmlParser.parsedObjects=Parsed model with {} objects +CityGmlWriterUtils.unknownADEError= Found error {} that cannot be converted to ADE error. It will not be written +CityGmlZipArchive.generalException=Encountered an unexpected error while reading the ZIP archive +CityGmlZipArchive.ioError=Accessing the ZIP archive failed +CityGmlZipArchive.malformedZipFile=Parsing of ZIP archive aborted, ZIP file is malformed! +DatabaseHandler.batchCommitFailure=Batch-commit aborted: Critical failure while trying to write CityObject {} to database! +DatabaseHandler.connectionFailure=Connection to embedded database could not be opened! +DatabaseHandler.fetchErrorIdsFailure=Fetching list of GmlIDs of CityObjects with errors failed! +DatabaseHandler.getAllCityObjectsFailure=Fetching of all CityObjects failed! +DatabaseHandler.getBBoxIntersectFailure= Connection to database failed while trying to fetch bbox intersecting objects of CityObject {} +DatabaseHandler.getBufferIntersectFailure=Connection to database failed while trying to fetch buffer intersecting objects of CityObject {} +DatabaseHandler.getFeatureCountFailure=Connection to database failed while trying to get count of CityObjects! +DatabaseHandler.marshallingFailure=Writing CityObject {} to database failed! +DatabaseHandler.serializationFailure=Serialization of CityObject {} failed! +DatabaseHandler.setupFailure=FATAL ERROR: Creation of embedded database failed! +DatabaseHandler.tableFailure=FATAL ERROR: Creation of features table failed! +DatabaseHandler.unmarshallingFailure=Loading of CityObject {} from embedded database failed! +DistanceError.distanceFromPlane=distance from plane +ErrorItemVisitor.childId=Child id +ErrorItemVisitor.component=Component +ErrorItemVisitor.degeneratedRing=Degenerated ring +ErrorItemVisitor.deviation=Deviation +ErrorItemVisitor.distance=Distance +ErrorItemVisitor.intersection=Intersection +ErrorItemVisitor.nameOfAttribute=Name of attribute +ErrorItemVisitor.pointTouchesEdge=Point touches edge +ErrorItemVisitor.triangles=Triangles ExceptionDialog.stacktrace=The exception stacktrace was: -FilterPane.buildings=Buildings +FeatureMapper.polygonUnreferenced=Polygon {} is referenced but not found in feature polygons FilterPane.bridges=Bridges +FilterPane.buildings=Buildings FilterPane.landUse=Land Use FilterPane.transportation=Transportation FilterPane.vegetation=Vegetation FilterPane.water=Water -MainToolBar.wireframe=Show/Hide Wireframe +GeometryMapper.emptyPolygon=Found polygon without exterior ring, ignoring +LibraryObject.fileMissing=Implicit geometry references non-existing library object file {} +LibraryObject.parsingError=Encountered an error while parsing library object {} MainToolBar.culling=Enable/Disable Culling -MainToolBar.writeReports=Write Reports MainToolBar.executeChecks=Execute Checks -MainToolBar.showWorld=Show entire city model -MainToolBar.resetCamera=Reset view MainToolBar.hideRoof=Show/Hide roof BoundarySurfaces +MainToolBar.resetCamera=Reset view +MainToolBar.showWorld=Show entire city model +MainToolBar.wireframe=Show/Hide Wireframe +MainToolBar.writeReports=Write Reports MainToolBar.zip=Open zip-entry selection window -MainWindow.missingConfig=Could not find configuration file. -MainWindow.loadGivenFile=Loading given file, please wait -MainWindow.finishedLoading=Finished loading -MainWindow.checking=Checking, please wait -MainWindow.writeXml=Writing xml report -MainWindow.finishedXml=Finished xml report -MainWindow.writePdf=Writing pdf report -MainWindow.finishedPdf=Finished pdf report -MainWindow.loadFailed=Failed to load given gml file: {} MainWindow.all=All -MainWindow.withErrors=With errors -MainWindow.export=Export feature +MainWindow.attributeTab=Attributes +MainWindow.availableLabel=Available: +MainWindow.bridgeTab=Bridges +MainWindow.buildingsTab=Buildings +MainWindow.checking=Checking, please wait +MainWindow.cityfurnitureTab=CityFurniture +MainWindow.clearBtn=Clear MainWindow.copyId=Copy GML-ID MainWindow.delete=Delete feature -MainWindow.infoTopLevelExport=Only top-level object can be exported! +MainWindow.edgesTab=Edges +MainWindow.errorsTab=Errors +MainWindow.export=Export feature +MainWindow.finishedLoading=Finished loading +MainWindow.finishedPdf=Finished pdf report +MainWindow.finishedXml=Finished xml report +MainWindow.focusCityObject=Focus object +MainWindow.globalErrorsTab=Global Errors MainWindow.infoTopLevelCopyID=GML-ID can only be copied from top-level object! -mainWindow.warnCopyIdFailed=Could not copy GML-ID! -OpenFileDialog.select=Select CityGML file +MainWindow.infoTopLevelExport=Only top-level object can be exported! MainWindow.languageChange=For the change in language to apply, restart CityDoctor2. -MainWindow.buildingsTab=Buildings -MainWindow.vegetationTab=Vegetation -MainWindow.transportationTab=Transportation -MainWindow.tunnelTab=Tunnels -MainWindow.bridgeTab=Bridges -MainWindow.waterTab=Water -MainWindow.terrainTab=Terrain -MainWindow.cityfurnitureTab=CityFurniture +MainWindow.loadFailed=Failed to load given gml file: {} +MainWindow.loadGivenFile=Loading given file, please wait +MainWindow.logTab=Log +MainWindow.memoryLabel=Memory: +MainWindow.missingConfig=Could not find configuration file. MainWindow.otherObjectsTab=Other -MainWindow.viewLabel=View -MainWindow.showLabel=Show: -MainWindow.searchLabel=Search: -MainWindow.searchBtn=Search -MainWindow.clearBtn=Clear -MainWindow.errorsTab=Errors MainWindow.polygonsTab=Polygons -MainWindow.edgesTab=Edges +MainWindow.searchBtn=Search +MainWindow.searchLabel=Search: +MainWindow.showLabel=Show: +MainWindow.terrainTab=Terrain +MainWindow.transportationTab=Transportation +MainWindow.tunnelTab=Tunnels +MainWindow.vegetationTab=Vegetation MainWindow.verticesTab=Vertices -MainWindow.attributeTab=Attributes -MainWindow.logTab=Log -MainWindow.globalErrorsTab=Global Errors -MainWindow.focusCityObject=Focus object +MainWindow.viewLabel=View +MainWindow.warnCopyIdFailed=Could not copy GML-ID! +MainWindow.waterTab=Water +MainWindow.withErrors=With errors +MainWindow.writePdf=Writing pdf report +MainWindow.writeXml=Writing xml report +OpenFileDialog.cancelBtn=Cancel OpenFileDialog.fileLabel=File: -OpenFileDialog.selectBtn=Select OpenFileDialog.loadBtn=Load -OpenFileDialog.settingsPane=Parser Preferences +OpenFileDialog.loadFailed=Failed to load CityGML File +OpenFileDialog.lowMemoryLabel=Low Memory Consumption Mode OpenFileDialog.roundingPlacesLabel=NumberOfRoundingPlaces +OpenFileDialog.select=Select CityGML file +OpenFileDialog.selectBtn=Select +OpenFileDialog.settingsPane=Parser Preferences OpenFileDialog.xmlValidationLabel=Use XML Validation -Checker.failXml=Failed to write XML Error Report. -Checker.failPdf=Failed to write PDF Report. -Checker.checksFinished=Finished executing checks -Checker.schematronValidation=Starting Schematron validation -Checker.finishedSchematron=Finished Schematron validation -Checker.failReports=Failed to write reports. -Checker.checkFeature=Checking feature: {} -Checker.executeCheck=Executing check: {} -ValidationConfiguration.reenable={} has been disabled but {} depends on it, reenabling +TimeFormatter.hours={0} hours +TimeFormatter.lessThanASecond=< 1 second +TimeFormatter.minutes={0} minutes +TimeFormatter.oneHour=1 hour +TimeFormatter.oneMinute=1 minute +TimeFormatter.oneSecond=1 second +TimeFormatter.seconds={0} seconds +Unit.Degree=Degree +Unit.Radian=Radian ValidationConfiguration.missingSchematron={} is not an existing file, disabling schematron check -CheckContainer.error=Unexpected exception while executing check: {} -Checks.missingCheck=Could not find check for id: {} -OpenFileDialog.cancelBtn=Cancel -CheckDialog.checksTab=Checks -CheckDialog.filterTab=Filter -CheckDialog.globalParametersLabel=Global Parameters -CheckDialog.availableChecksLabel=Available Checks -CheckDialog.geometricChecksLabel=Geometric Checks -CheckDialog.semanticChecksLabel=Semantic Checks -CheckDialog.schematronFileLabel=Schematron File: -CheckDialog.selectBtn=Select -CheckDialog.checkBtn=Check -CheckDialog.cancelBtn=Cancel -CheckDialog.streamCheckOption=Use low memory mode -CheckDialog.streamCheckLabel=Citymodels are not loaded and kept in memory. Check results are saved to the QualityADE in copies of the input files. -CheckDialog.outputPathLabel=Output directory (Required): -CheckDialog.outputPathBtn=Select -CheckDialog.pdfReportsOption=Create PDF reports -CheckDialog.xmlReportsOption=Create XML reports -CheckDialog.noPathError=Output path is missing! -ZipEntryManager.title=Zip-entry manager -ZipEntryManager.entryListTitle=Zip-entries -ZipEntryManager.metadata=Metadata -ZipEntryManager.subpathLbl=Subpath: -ZipEntryManager.erroneousLbl=Erroneous: -ZipEntryManager.excessiveFileSize=Filesize exceeds memory -ZipEntryManager.invalidCityGml=Invalid CityGML file -ZipEntryManager.ioError=Unable to access file -ZipEntryManager.filesizeLbl=Filesize: -ZipEntryManager.validatedLbl=Validated: -ZipEntryManager.objectCountLbl=Object count: -ZipEntryManager.loadBtn=Load CityGML model -ZipEntryManager.decompressBtn=Unpack file -ZipEntryManager.decompressAllBtn=Unpack all files -ZipEntryManager.checkAllBtn=Check all files -ZipEntryManager.showReportBtn=Show error statistic -ZipEntryManager.saveBtn=Export validation results -ZipEntryManager.cancelBtn=Cancel -ZipEntryManager.unknownValue=N/A -ZipEntryManager.yes=Yes -ZipEntryManager.no=No -CityGmlZipArchive.ioError=Accessing the ZIP archive failed -CityGmlZipArchive.malformedZipFile=Parsing of ZIP archive aborted, ZIP file is malformed! -CityGmlZipArchive.generalException=Encountered an unexpected error while reading the ZIP archive -WriteReportDialog.writeBtn=Save +ValidationConfiguration.reenable={} has been disabled but {} depends on it, reenabling WriteReportDialog.cancelBtn=Cancel WriteReportDialog.errorStatisticsLabel=Error Statistics WriteReportDialog.saveImageBtn=Save Image... WriteReportDialog.selectPdfBtn=Select WriteReportDialog.selectXmlFile=Select +WriteReportDialog.writeBtn=Save WriteReportDialog.xAxisLabel=Error -WriteReportDialog.yAxisLabel=Count -Unit.Radian=Radian -Unit.Degree=Degree -FeatureMapper.polygonUnreferenced=Polygon {} is referenced but not found in feature polygons -GeometryMapper.emptyPolygon=Found polygon without exterior ring, ignoring -CityGmlParser.parsedObjects=Parsed model with {} objects -CityGmlParser.chunkReadFailed=Failed to read GML file in chunks, falling back to reading the complete file -CityGmlParser.notValidGmlFile=This is not a valid GML-File\n -CityGmlParser.errorReadingGmlFile=Error while reading city gml file\n{} -CityGmlParser.errorWritingGmlFile=Error while writing city gml file\n{} -CityGmlParser.noConversionNeeded=Coordinate system is in meters, no conversion done -CityGmlParser.failedEPSGParse=Could not read EPSG code, fallback to metric system -CityGmlParser.missingEPSGCode=No EPSG code found, assuming metric system -OpenFileDialog.loadFailed=Failed to load CityGML File -MainWindow.memoryLabel=Memory: -CheckDialog.checksReenabledAlert=Some checks have been reenabled so that other wanted checks can be executed\nSee the log for more information. -MainWindow.availableLabel=Available: -OpenFileDialog.lowMemoryLabel=Low Memory Consumption Mode -ErrorItemVisitor.intersection=Intersection -ErrorItemVisitor.component=Component -ErrorItemVisitor.nameOfAttribute=Name of attribute -ErrorItemVisitor.childId=Child id -ErrorItemVisitor.distance=Distance -ErrorItemVisitor.pointTouchesEdge=Point touches edge -ErrorItemVisitor.degeneratedRing=Degenerated ring -ErrorItemVisitor.deviation=Deviation -ErrorItemVisitor.triangles=Triangles \ No newline at end of file +WriteReportDialog.yAxisLabel=Count \ No newline at end of file diff --git a/CityDoctorParent/CityDoctorModel/src/main/resources/CityDoctorLocalization_de.properties b/CityDoctorParent/CityDoctorModel/src/main/resources/CityDoctorLocalization_de.properties index 864c13b7b84e9974f1bd6c2b2ab9c6d5e3b45129..e9c1f7b68d35cda5c4a329698fe8801e4d8f31ba 100644 --- a/CityDoctorParent/CityDoctorModel/src/main/resources/CityDoctorLocalization_de.properties +++ b/CityDoctorParent/CityDoctorModel/src/main/resources/CityDoctorLocalization_de.properties @@ -1,171 +1,201 @@ -DistanceError.distanceFromPlane=Abstand von der Ebene -AboutDialog.developedBy=Entwickelt von +AboutDialog.closeBtn=Schlie\u00DFen AboutDialog.contact=Kontakt +AboutDialog.developedBy=Entwickelt von AboutDialog.title=CityDoctor 3 - \u00DCber -AboutDialog.closeBtn=Schlie\u00DFen -CheckDialog.title=Pr\u00fcfungskonfiguration -CheckDialog.schematronFiles=Schematron Dateien -CheckDialog.schematronChooserTitle=W\u00e4hle Schematron Datei.. -CheckDialog.validationConfiguration=Validierungs Konfiguration -CheckDialog.startingChecks=Starte Pr\u00fcfung +CheckContainer.error=Unerwarteter Fehler bei der Ausf\u00fchrung von Pr\u00fcfung: {} +CheckDialog.availableChecksLabel=Verf\u00fcgbare Pr\u00fcfungen +CheckDialog.cancelBtn=Abbrechen +CheckDialog.checkBtn=Pr\u00fcfen +CheckDialog.checkEnabled=Aktiv +CheckDialog.checkName=Name CheckDialog.checksDone=Pr\u00fcfung abgeschlossen +CheckDialog.checksReenabledAlert=Manche Pr\u00fcfungen wurden reaktiviert damit andere gewollte Pr\u00fcfungen durchgef\u00fchrt werden k\u00f6nnen\nMehr Details sind im Log geschrieben +CheckDialog.checksTab=Pr\u00fcfungen CheckDialog.failedChecks=Konnte Pr\u00fcfungen nicht ausf\u00fchren -CheckDialog.schematronFileNotExisting=Schematron Datei existiert nicht, ignoriere -CheckDialog.checkEnabled=Aktiv -CheckDialog.parameterValue=Wert +CheckDialog.filterTab=Filter +CheckDialog.geometricChecksLabel=Geometrische Pr\u00fcfungen +CheckDialog.globalParametersLabel=Globale Parameter +CheckDialog.noPathError=Ausgabepfad wurde nicht gesetzt! +CheckDialog.outputPathBtn=Ausw\u00e4hlen +CheckDialog.outputPathLabel=Ausgabeordner (Pflichtfeld): CheckDialog.parameterUnit=Einheit -CityDoctorController.noDatamodel=Datenmodell ist null, keine Pr\u00fcfungen konnten ausgef\u00fchrt werden -CityDoctorController.noSourceFile=Quelldatei ist null, keine Pr\u00fcfungen konnten ausgef\u00fchrt werden -CityDoctorController.noZipFile=ZIP-Archiv ist null, keine Pr\u00fcfungen konnten ausgef\u00fchrt werden -CityDoctorController.exportSuccess=Feature export erfolgreich abgeschlossen +CheckDialog.parameterValue=Wert +CheckDialog.pdfReportsOption=PDF-Berichte erstellen +CheckDialog.schematronChooserTitle=W\u00e4hle Schematron Datei ... +CheckDialog.schematronFileLabel=Schematron Datei: +CheckDialog.schematronFileNotExisting=Schematron Datei existiert nicht, Schematron-Pr\u00fcfung wird \u00fcbersprungen +CheckDialog.schematronFiles=Schematron Dateien +CheckDialog.selectBtn=Ausw\u00e4hlen +CheckDialog.semanticChecksLabel=Semantische Pr\u00fcfungen +CheckDialog.startingChecks=Starte Pr\u00fcfung +CheckDialog.streamCheckLabel=Stadtmodelle werden nicht in den Arbeitsspeicher geladen. Ergebnisse werden in der QualityADE in Kopien der Eingangsdateien gespeichert. +CheckDialog.streamCheckOption=Niedrigen Arbeitsspeicherverbrauchsmodus aktivieren +CheckDialog.title=Pr\u00fcfungskonfiguration +CheckDialog.validationConfiguration=Validierungskonfiguration +CheckDialog.xmlReportsOption=XML-Berichte erstellen +Checker.checkFeature=Pr\u00fcfe Feature: {} +Checker.checksFinished=Durchf\u00fchrung der Pr\u00fcfungen abgeschlossen. Gesamtzeit: {0} +Checker.dbStillUnresponsive=Pr\u00fcfung konnte weiterhin einige CityObjects nicht aus der Datenbank laden! +Checker.dbUnresponsive=Pr\u00fcfung konnte einige CityObjects nicht aus der Datenbank laden! +Checker.executeCheck=F\u00fchre Pr\u00fcfung aus: {} +Checker.failPdf=Konnte PDF-Fehlerbericht nicht schreiben. +Checker.failReports=Konnte Pr\u00fcfberichte nicht schreiben. +Checker.failXml=Konnte XML-Fehlerbericht nicht schreiben. +Checker.finishedSchematron=Schematron-Pr\u00fcfung abgeschlossen +Checker.futuresCheckFailures=Einige Pr\u00fcfungen sind aufgrund folgender Fehler fehlgeschlagen: +Checker.noCheckSatisfiesRequirement=Keine Pr\u00fcfung erf\u00fcllt die Anforderung {}, Anforderung wird nicht gepr\u00fcft +Checker.schematronCompleted=Schematron-Pr\u00fcfung abgeschlossen +Checker.schematronFileNotFound=Schematron Datei {} konnte nicht gefunden werden +Checker.schematronInterrupted=Main Thread hat Interrupt-Befehl w\u00e4hrend dem Warten auf Schematron Abschluss erhalten! +Checker.schematronStillRunning=Schematron-Pr\u00fcfung ist noch nicht abgeschlossen. Warten auf Abschluss der Pr\u00fcfung, dies kann einiges an Zeit beanspruchen +Checker.schematronValidation=Schematron-Pr\u00fcfung gestartet +Checker.shutdownInterrupted=Main-Thread hat einen Interrupt-Befehl w\u00e4hrend dem ThreadPool shutdown erhalten +Checker.validationInterrupted=Validierung abgebrochen: Pr\u00fcfung hat Interrupt-Befehl erhalten +Checker.waitAndRetry=Wiederhole Pr\u00fcfung nach kurzer Wartezeit ... +Checks.missingCheck=Konnte keine Pr\u00fcfung f\u00fcr id {} finden +CityDoctorController.exportSuccess=Exportieren des Features erfolgreich abgeschlossen +CityDoctorController.noDatamodel=Datenmodell ist NULL, keine Pr\u00fcfungen konnten ausgef\u00fchrt werden +CityDoctorController.noSourceFile=Quelldatei ist NULL, keine Pr\u00fcfungen konnten ausgef\u00fchrt werden +CityDoctorController.noZipFile=ZIP-Archiv ist NULL, keine Pr\u00fcfungen konnten ausgef\u00fchrt werden CityDoctorController.saveZipArchiveReports=Validierungsberichte erfolgreich exportiert! +CityDoctorValidation.Version=${versionString} +CityDoctorValidation.inputFileNotExisting=Eingabedatei '{}' existiert nicht. +CityDoctorValidation.loadingDefaultConfig=Keine Konfigurationsdatei angegeben, Standardkonfiguration wird geladen. +CityDoctorValidation.noConfig=Keine Konfigurationsdatei angegeben. (-config [DATEIPFAD]) +CityDoctorValidation.noInputFile=Keine Eingabedatei angegeben. (-in [DATEIPFAD]) +CityDoctorValidation.noOutputFile=Keinen Ausgabedateipfad angegeben. (-out [DATEIPFAD]) +CityDoctorValidation.notExactlyOneConfigFile=Es muss exakt eine Konfigurationsdatei angegeben werden. +CityDoctorValidation.notExactlyOneInputFile=Es muss exakt eine Eingabedatei angegeben werden. +CityDoctorValidation.notExactlyOneOutputFile=Es muss exakt ein Ausgabedateipfad angegeben werden. +CityDoctorValidation.notExactlyOnePDFOutput=Es muss exakt ein Ausgabedateipfad f\u00fcr den PDF-Bericht angegeben werden. +CityDoctorValidation.notExactlyOneXMLOutput=Es muss exakt ein Ausgabedateipfad f\u00fcr den XML-Bericht angegeben werden. +CityDoctorValidation.wrongInputFileFormat=Eingabedatei '{}' ist keine .gml oder .xml Datei. +CityGmlParser.chunkReadFailed=Konnte Datei nicht in St\u00fccken lesen, versuche komplett zu lesen +CityGmlParser.convertCrsToUtmZoneN=Konvertiere Koordinatensystem zu UTM Zone {}N +CityGmlParser.convertCrsToUtmZoneS=Konvertiere Koordinatensystem zu UTM Zone {}S +CityGmlParser.creating4jContextFailed=Erstellen des Citygml4j Kontext fehlgeschlagen +CityGmlParser.creatingAdePluginsFailed=Erstellen des ADE Plugins f\u00fcr citygml4j fehlgeschlagen +CityGmlParser.errorReadingGmlFile=Fehler beim lesen der CityGML Datei\n{} +CityGmlParser.errorWritingGmlFile=Fehler beim schreiben der CityGML Datei\n{} +CityGmlParser.failedEPSGParse=Lesen des EPSG-Codes fehlgeschlagen, greife auf metrisches System zur\u00fcck +CityGmlParser.missingCityModel=Datei enth\u00e4lt kein CityModel! Tempor\u00e4res CityModel wird erstellt. +CityGmlParser.missingEPSGCode=Kein EPSG-Code wurde gefunden! Gehe von metrischem System aus +CityGmlParser.noConversionNeeded=Koordinatensystem in Metern, keine Konvertierung notwendig +CityGmlParser.notValidGmlFile=Dies ist keine korrekte CityGML Datei +CityGmlParser.parsedObjects=Modell mit {} Objekten gelesen +CityGmlWriterUtils.unknownADEError= Fehler {} kann nicht zu einem ADE-Fehler konvertiert werden. Fehler wird nicht ausgegeben +CityGmlZipArchive.generalException=Unerwarteter Fehler beim Einlesen des ZIP-Archivs +CityGmlZipArchive.ioError=Zugriff auf ZIP-Datei fehlgeschlagen +CityGmlZipArchive.malformedZipFile=Einlesen des ZIP-Archivs abgebrochen, ZIP-Datei ist fehlerhaft! +DatabaseHandler.batchCommitFailure=Batch-commit abgebrochen: Auftreten eines kritischen Fehlers beim Versuch CityObject {} in die Datenbank zu schreiben! +DatabaseHandler.connectionFailure=Verbindung zur eingebetteten Datenbank konnte nicht hergestellt werden! +DatabaseHandler.fetchErrorIdsFailure=Abfragen der Liste von CityObjects mit Fehlern ist fehlgeschlagen! +DatabaseHandler.getAllCityObjectsFailure=Abfragen der Liste aller CityObjects ist fehlgeschlagen! +DatabaseHandler.getBBoxIntersectFailure=Verbindung zur Datenbank konnte nicht hergestellt werden, abfragen der BoundingBox-\u00dcberschneidungen von CityObject {} fehlgeschlagen! +DatabaseHandler.getBufferIntersectFailure=Verbindung zur Datenbank konnte nicht hergestellt werden, abfragen der Buffer-\u00dcberschneidungen von CityObject {} fehlgeschlagen! +DatabaseHandler.getFeatureCountFailure=Verbindung zur Datenbank konnte nicht hergestellt werden, abfragen der Anzahl an CityObjects fehlgeschlagen! +DatabaseHandler.marshallingFailure=Schreiben des CityObject {} in die Datenbank fehlgeschlagen! +DatabaseHandler.serializationFailure=Serialisierung des CityObject {} fehlgeschlagen! +DatabaseHandler.setupFailure=KRITISCHER FEHLER: Erstellen der eingebetteten Datenbank fehlgeschlagen! +DatabaseHandler.tableFailure=KRITISCHER FEHLER: Erstellen der "features" Tabelle fehlgeschlagen! +DatabaseHandler.unmarshallingFailure=Laden des CityObject {} aus der Datenbank fehlgeschlagen! +DistanceError.distanceFromPlane=Abstand von der Ebene +ErrorItemVisitor.childId=Kind ID +ErrorItemVisitor.component=Komponente +ErrorItemVisitor.degeneratedRing=Degenerierter Ring +ErrorItemVisitor.deviation=Abweichung +ErrorItemVisitor.distance=Distanz +ErrorItemVisitor.intersection=Verschneidung +ErrorItemVisitor.nameOfAttribute=Name des Attributs +ErrorItemVisitor.pointTouchesEdge=Punkt ber\u00fchrt Kante +ErrorItemVisitor.triangles=Dreiecke ExceptionDialog.stacktrace=Der Stacktrace des Fehlers war: -FilterPane.buildings=Geb\u00e4ude +FeatureMapper.polygonUnreferenced=Polygon {} wurde referenziert, konnte aber nicht gefunden werden! FilterPane.bridges=Br\u00fccken +FilterPane.buildings=Geb\u00e4ude FilterPane.landUse=Landnutzung FilterPane.transportation=Transport FilterPane.vegetation=Vegetation FilterPane.water=Wasser -MainToolBar.wireframe=Zeige/Verstecke Gitternetz -MainToolBar.culling=Aktiviere/Deaktiviere Entfernen der R\u00fcckseiten -MainToolBar.writeReports=Schreibe Reports +GeometryMapper.emptyPolygon=Polygon ohne externen Ring gefunden. Polygon wird ignoriert +LibraryObject.fileMissing=Die ImplicitGeometry eines Features verweist auf eine nicht vorhandene LibraryObject-Datei {} +LibraryObject.parsingError=LibraryObject-Datei {} konnte aufgrund eines Fehlers nicht ausgelesen werden +MainToolBar.culling=Aktiviere/Deaktiviere Entfernen der Polygon-R\u00fcckseiten MainToolBar.executeChecks=F\u00fchre Pr\u00fcfungen aus -MainToolBar.showWorld=Gesamtes Stadtmodell anzeigen -MainToolBar.resetCamera=Ansicht zur\u00fccksetzen -MainToolBar.hideRoof=Zeige/Verstecke Dach BoundarySurfaces +MainToolBar.hideRoof=Zeige/Verstecke Dach-BoundarySurfaces +MainToolBar.resetCamera=Kamera-Ansicht zur\u00fccksetzen +MainToolBar.showWorld=Zeige gesamtes Stadtmodell an +MainToolBar.wireframe=Aktiviere/Deaktiviere Gitternetz-Modus +MainToolBar.writeReports=Schreibe Berichte MainToolBar.zip=Zip-eintrag Auswahlfenster \u00f6ffnen -MainWindow.missingConfig=Konnte Konfigurationsdatei nicht finden. -MainWindow.loadGivenFile=Lade vorhandene Datei, bitte warten -MainWindow.finishedLoading=Fertig geladen -MainWindow.checking=Pr\u00fcfe, bitte warten -MainWindow.writeXml=Schreibe Xml Report -MainWindow.finishedXml=Xml Report abgeschlossen -MainWindow.writePdf=Schreibe Pdf Report -MainWindow.finishedPdf=Pdf Report abgeschlossen -MainWindow.loadFailed=Konnte GML-Datei nicht laden: {} MainWindow.all=Alle -MainWindow.withErrors=Mit Fehlern -MainWindow.export=Feature Exportieren +MainWindow.attributeTab=Attribute +MainWindow.availableLabel=Verf\u00fcgbar: +MainWindow.bridgeTab=Br\u00fccken +MainWindow.buildingsTab=Geb\u00e4ude +MainWindow.checking=Pr\u00fcfe, bitte warten +MainWindow.cityfurnitureTab=Stadtm\u00f6bel +MainWindow.clearBtn=Leeren MainWindow.copyId=GML-ID kopieren MainWindow.delete=Feature L\u00f6schen -MainWindow.infoTopLevelExport=Export ist nur f\u00fcr Featureobjekt basis m\u00f6glich! +MainWindow.edgesTab=Kanten +MainWindow.errorsTab=Fehler +MainWindow.export=Feature Exportieren +MainWindow.finishedLoading=Fertig geladen +MainWindow.finishedPdf=Pdf-Bericht abgeschlossen +MainWindow.finishedXml=Xml-Bericht abgeschlossen +MainWindow.focusCityObject=Objekt fokussieren +MainWindow.globalErrorsTab=Globale Fehler MainWindow.infoTopLevelCopyID=GML-ID kann nur von Featureobjekt basis kopiert werden! -mainWindow.warnCopyIdFailed=Kopieren der ID fehlgeschlagen! -OpenFileDialog.select=W\u00e4hle CityGML Datei aus +MainWindow.infoTopLevelExport=Export ist nur f\u00fcr Featureobjekt basis m\u00f6glich! MainWindow.languageChange=Um die Spracheinstellung zu \u00fcbernehmen muss CityDoctor2 neugestartet werden. -MainWindow.buildingsTab=Geb\u00e4ude -MainWindow.vegetationTab=Vegetation -MainWindow.transportationTab=Verkehrsobjekte -MainWindow.tunnelTab=Tunnel -MainWindow.bridgeTab=Br\u00fccken -MainWindow.waterTab=Gew\u00e4sser -MainWindow.terrainTab=Gel\u00e4nde -MainWindow.cityfurnitureTab=Stadtm\u00f6bel +MainWindow.loadFailed=Konnte GML-Datei nicht laden: {} +MainWindow.loadGivenFile=Lade vorhandene Datei, bitte warten +MainWindow.logTab=Log +MainWindow.memoryLabel=Speicher: +MainWindow.missingConfig=Konnte Konfigurationsdatei nicht finden. MainWindow.otherObjectsTab=Andere -MainWindow.viewLabel=Ansicht -MainWindow.showLabel=Zeige: -MainWindow.searchLabel=Suche: -MainWindow.searchBtn=Suche -MainWindow.clearBtn=Leeren -MainWindow.errorsTab=Fehler MainWindow.polygonsTab=Polygone -MainWindow.edgesTab=Kanten +MainWindow.searchBtn=Suche +MainWindow.searchLabel=Suche: +MainWindow.showLabel=Zeige: +MainWindow.terrainTab=Gel\u00e4nde +MainWindow.transportationTab=Verkehrsobjekte +MainWindow.tunnelTab=Tunnel +MainWindow.vegetationTab=Vegetation MainWindow.verticesTab=Punkte -MainWindow.attributeTab=Attribute -MainWindow.logTab=Log -MainWindow.globalErrorsTab=Globale Fehler -MainWindow.focusCityObject=Objekt fokussieren +MainWindow.viewLabel=Ansicht +MainWindow.warnCopyIdFailed=Kopieren der ID fehlgeschlagen! +MainWindow.waterTab=Gew\u00e4sser +MainWindow.withErrors=Mit Fehlern +MainWindow.writePdf=Schreibe Pdf-Bericht +MainWindow.writeXml=Schreibe Xml-Bericht +OpenFileDialog.cancelBtn=Abbrechen OpenFileDialog.fileLabel=Datei: -OpenFileDialog.selectBtn=Ausw\u00e4hlen OpenFileDialog.loadBtn=Laden +OpenFileDialog.loadFailed=Konnte CityGML Datei nicht laden +OpenFileDialog.lowMemoryLabel=Reduzierter Speicherverbrauchsmodus +OpenFileDialog.roundingPlacesLabel=Anzahl der Rundungsstellen +OpenFileDialog.select=W\u00e4hle CityGML Datei aus +OpenFileDialog.selectBtn=Ausw\u00e4hlen OpenFileDialog.settingsPane=Parser Einstellungen -OpenFileDialog.roundingPlacesLabel=NumberOfRoundingPlaces OpenFileDialog.xmlValidationLabel=F\u00fchre XML-Validierung aus -Checker.failXml=Konnte XML Fehlerbericht nicht schreiben. -Checker.failPdf=Konnte PDF Fehlerbericht nicht schreiben. -Checker.checksFinished=Pr\u00fcfungen beendet -Checker.schematronValidation=Starte Schematron Pr\u00fcfung -Checker.finishedSchematron=Schematron Pr\u00fcfung abgeschlossen -Checker.failReports=Konnte Pr\u00fcfberichte nicht schreiben. -Checker.checkFeature=Pr\u00fcfe Feature: {} -Checker.executeCheck=F\u00fchre Pr\u00fcfung aus: {} -ValidationConfiguration.reenable={} ist deaktiviert wird aber von {} ben\u00f6tigt, reaktiviere +TimeFormatter.hours={0} Stunden +TimeFormatter.lessThanASecond=< 1 Sekunde +TimeFormatter.minutes={0} Minuten +TimeFormatter.oneHour=1 Stunde +TimeFormatter.oneMinute=1 Minute +TimeFormatter.oneSecond=1 Sekunde +TimeFormatter.seconds={0} Sekunden +Unit.Degree=Grad +Unit.Radian=Radiant ValidationConfiguration.missingSchematron={} existiert nicht, deaktiviere Schematron Pr\u00fcfung -CheckContainer.error=Unerwarteter Fehler bei der Ausf\u00fchrung von Pr\u00fcfung: {} -Checks.missingCheck=Konnte keine Pr\u00fcfung f\u00fcr id {} finden -OpenFileDialog.cancelBtn=Abbrechen -CheckDialog.checksTab=Pr\u00fcfungen -CheckDialog.filterTab=Filter -CheckDialog.globalParametersLabel=Globale Parameter -CheckDialog.availableChecksLabel=Verf\u00fcgbare Pr\u00fcfungen -CheckDialog.geometricChecksLabel=Geometrische Pr\u00fcfungen -CheckDialog.semanticChecksLabel=Semantische Pr\u00fcfungen -CheckDialog.schematronFileLabel=Schematron Datei -CheckDialog.selectBtn=Ausw\u00e4hlen -CheckDialog.checkBtn=Pr\u00fcfen -CheckDialog.cancelBtn=Abbrechen -CheckDialog.streamCheckOption=Niedrigen Arbeitsspeicherverbrauchsmodus aktivieren -CheckDialog.streamCheckLabel=Stadtmodelle werden nicht in den Arbeitsspeicher geladen. Ergebnisse werden in der QualityADE in Kopien der Eingangsdateien gespeichert. -CheckDialog.outputPathLabel=Ausgabeordner (Pflichtfeld): -CheckDialog.outputPathBtn=Ausw\u00e4hlen -CheckDialog.pdfReportsOption=PDF Berichte erstellen -CheckDialog.xmlReportsOption=XML Berichte erstellen -CheckDialog.noPathError=Ausgabepfad wurde nicht gesetzt! -ZipEntryManager.title=Zipeintrag Manager -ZipEntryManager.entryListTitle=Zipeintr\u00e4ge -ZipEntryManager.metadata=Metadaten -ZipEntryManager.subpathLbl=Unterpfad: -ZipEntryManager.erroneousLbl=Fehlerhaft: -ZipEntryManager.excessiveFileSize=Datei zu gro\u00DF -ZipEntryManager.invalidCityGml=Ung\u00fcltige CityGML Datei -ZipEntryManager.ioError=Dateizugriff fehlgeschlagen -ZipEntryManager.filesizeLbl=Dateigr\u00f6\u00DFe: -ZipEntryManager.validatedLbl=Validiert: -ZipEntryManager.objectCountLbl=Objektanzahl: -ZipEntryManager.loadBtn=CityGML Modell laden -ZipEntryManager.decompressBtn=Datei entpacken -ZipEntryManager.decompressAllBtn=Alle Dateien entpacken -ZipEntryManager.checkAllBtn=Alle Dateien pr\u00fcfen -ZipEntryManager.showReportBtn=Fehlerstatistik anzeigen -ZipEntryManager.saveBtn=Validierungsergebnisse exportieren -ZipEntryManager.cancelBtn=Abbruch -ZipEntryManager.unknownValue=Unbekannt -ZipEntryManager.yes=Ja -ZipEntryManager.no=Nein -CityGmlZipArchive.ioError=Zugriff auf ZIP-Datei fehlgeschlagen -CityGmlZipArchive.malformedZipFile=Einlesen des ZIP-Archivs abgebrochen, ZIP-Datei ist fehlerhaft! -CityGmlZipArchive.generalException=Unerwarteter Fehler beim Einlesen des ZIP-Archivs -WriteReportDialog.writeBtn=Speichern +ValidationConfiguration.reenable={} ist deaktiviert wird aber von {} ben\u00f6tigt, reaktiviere WriteReportDialog.cancelBtn=Abbrechen WriteReportDialog.errorStatisticsLabel=Fehler Statistik WriteReportDialog.saveImageBtn=Bild Speichern WriteReportDialog.selectPdfBtn=Ausw\u00e4hlen WriteReportDialog.selectXmlFile=Ausw\u00e4hlen +WriteReportDialog.writeBtn=Speichern WriteReportDialog.xAxisLabel=Fehler -WriteReportDialog.yAxisLabel=Anzahl -Unit.Radian=Radiant -Unit.Degree=Grad -FeatureMapper.polygonUnreferenced=Polygon {} ist referenziert, konnte aber nicht gefunden werden -GeometryMapper.emptyPolygon=Polygon ohne externen Ring gefunden, ignoriere -CityGmlParser.parsedObjects=Modell mit {} Objekten gelesen -CityGmlParser.chunkReadFailed=Konnte Datei nicht in St\u00fccken lesen, versuche komplett zu lesen -CityGmlParser.notValidGmlFile=Dies ist keine korrekte CityGML Datei\n -CityGmlParser.errorReadingGmlFile=Fehler beim lesen der CityGML Datei\n{} -CityGmlParser.errorWritingGmlFile=Fehler beim schreiben der CityGML Datei\n{} -CityGmlParser.noConversionNeeded=Koordinatensystem in Metern, keine Konvertierung notwendig -CityGmlParser.failedEPSGParse=Lesen des EPSG Codes fehlgeschlagen, greife auf metrisches System zur\u00fcck -CityGmlParser.missingEPSGCode=Kein EPSG Code gefunden, nehme metrisches System an -OpenFileDialog.loadFailed=Konnte CityGML Datei nicht laden -MainWindow.memoryLabel=Speicher: -CheckDialog.checksReenabledAlert=Manche Pr\u00fcfungen wurden reaktiviert damit andere gewollte Pr\u00fcfungen durchgef\u00fchrt werden k\u00f6nnen\nMehr Details sind im Log geschrieben -MainWindow.availableLabel=Verf\u00fcgbar: -OpenFileDialog.lowMemoryLabel=Reduzierter Speicherverbrauchsmodus -ErrorItemVisitor.intersection=Verschneidung -ErrorItemVisitor.component=Komponente -ErrorItemVisitor.nameOfAttribute=Name des Attributs -ErrorItemVisitor.childId=Kind ID -ErrorItemVisitor.distance=Distanz -ErrorItemVisitor.pointTouchesEdge=Punkt ber\u00fchrt Kante -ErrorItemVisitor.degeneratedRing=Degenerierter Ring -ErrorItemVisitor.deviation=Abweichung -ErrorItemVisitor.triangles=Dreiecke \ No newline at end of file +WriteReportDialog.yAxisLabel=Anzahl \ No newline at end of file diff --git a/CityDoctorParent/CityDoctorModel/src/main/resources/log4j2.xml b/CityDoctorParent/CityDoctorModel/src/main/resources/log4j2.xml index 4e951d6be8c184c776c0a02290cc32671d09c3de..d398aaaa8f5b4f31148c1c39d67d47b85690b9d9 100644 --- a/CityDoctorParent/CityDoctorModel/src/main/resources/log4j2.xml +++ b/CityDoctorParent/CityDoctorModel/src/main/resources/log4j2.xml @@ -14,5 +14,8 @@ + + + \ No newline at end of file diff --git a/CityDoctorParent/CityDoctorModel/src/test/java/de/hft/stuttgart/citydoctor2/database/EmbeddedDataBaseHandlerTest.java b/CityDoctorParent/CityDoctorModel/src/test/java/de/hft/stuttgart/citydoctor2/database/EmbeddedDataBaseHandlerTest.java new file mode 100644 index 0000000000000000000000000000000000000000..06c0bb6e713a27cd1593503520cc2005905d776b --- /dev/null +++ b/CityDoctorParent/CityDoctorModel/src/test/java/de/hft/stuttgart/citydoctor2/database/EmbeddedDataBaseHandlerTest.java @@ -0,0 +1,244 @@ +package de.hft.stuttgart.citydoctor2.database; + +import de.hft.stuttgart.citydoctor2.datastructure.Building; +import de.hft.stuttgart.citydoctor2.datastructure.CityDoctorModel; +import de.hft.stuttgart.citydoctor2.datastructure.CityObject; +import de.hft.stuttgart.citydoctor2.datastructure.ConcretePolygon; +import de.hft.stuttgart.citydoctor2.datastructure.Geometry; +import de.hft.stuttgart.citydoctor2.datastructure.GeometryTestUtils; +import de.hft.stuttgart.citydoctor2.datastructure.GeometryType; +import de.hft.stuttgart.citydoctor2.datastructure.GmlId; +import de.hft.stuttgart.citydoctor2.datastructure.LinearRing; +import de.hft.stuttgart.citydoctor2.datastructure.Lod; +import de.hft.stuttgart.citydoctor2.datastructure.Vertex; +import de.hft.stuttgart.citydoctor2.parser.CityGmlParseException; +import de.hft.stuttgart.citydoctor2.parser.CityGmlParser; +import de.hft.stuttgart.citydoctor2.parser.InvalidGmlFileException; +import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration; +import org.citygml4j.core.model.building.AbstractBuilding; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mockito; + +import java.util.List; + +import static de.hft.stuttgart.citydoctor2.database.SerializationTest.assertCityObjectEquality; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.fail; + +public class EmbeddedDataBaseHandlerTest { + + private EmbeddedDatabaseHandler handler; + + @Before + public void resetDatabase() { + try { + handler = new EmbeddedDatabaseHandler(); + handler.setupFeaturesTable(); + } catch (Exception e) { + fail(e.getMessage()); + } + } + + + @Test + public void testGetBboxIntersectingObjects() { + Building b = new Building(); + Building b2 = new Building(); + b2.setGmlObject(Mockito.mock(AbstractBuilding.class)); + Building b3 = new Building(); + Building b4 = new Building(); + b4.addGeometry(GeometryTestUtils.createDummyGeometry(GeometryType.SOLID, Lod.LOD0)); + + Geometry geom = new Geometry(GeometryType.SOLID, Lod.LOD0, Geometry.Orientation.OUTWARD); + ConcretePolygon polygon = new ConcretePolygon(); + geom.getPolygons().add(polygon); + polygon.setParent(geom); + LinearRing lr = new LinearRing(LinearRing.LinearRingType.EXTERIOR); + polygon.setExteriorRing(lr); + Vertex v1 = new Vertex(10, 10, 8); + lr.getVertices().add(v1); + Vertex v2 = new Vertex(14, 15, 7); + lr.getVertices().add(v2); + Vertex v3 = new Vertex(14, 15, 3); + lr.getVertices().add(v3); + Vertex v4 = new Vertex(10, 10, 3); + lr.getVertices().add(v4); + lr.getVertices().add(v1); + geom.updateEdgesAndVertices(); + b.addGeometry(geom); + + + Geometry geom2 = new Geometry(GeometryType.SOLID, Lod.LOD0, Geometry.Orientation.OUTWARD); + ConcretePolygon polygon2 = new ConcretePolygon(); + geom2.getPolygons().add(polygon2); + polygon2.setParent(geom2); + LinearRing lr2 = new LinearRing(LinearRing.LinearRingType.EXTERIOR); + polygon2.setExteriorRing(lr2); + Vertex v1b2 = new Vertex(6, 6, 8); + lr2.getVertices().add(v1b2); + Vertex v2b2 = new Vertex(11, 13, 7); + lr2.getVertices().add(v2b2); + Vertex v3b2 = new Vertex(11, 13, 3); + lr2.getVertices().add(v3b2); + Vertex v4b2 = new Vertex(6, 6, 3); + lr2.getVertices().add(v4b2); + lr2.getVertices().add(v1b2); + geom2.updateEdgesAndVertices(); + b2.addGeometry(geom2); + + Geometry geom3 = new Geometry(GeometryType.SOLID, Lod.LOD0, Geometry.Orientation.OUTWARD); + ConcretePolygon polygon3 = new ConcretePolygon(); + geom3.getPolygons().add(polygon3); + polygon3.setParent(geom3); + LinearRing lr3 = new LinearRing(LinearRing.LinearRingType.EXTERIOR); + polygon3.setExteriorRing(lr3); + Vertex v1b3 = new Vertex(6, 6, 8); + lr3.getVertices().add(v1b3); + Vertex v2b3 = new Vertex(10, 9.999, 7); + lr3.getVertices().add(v2b3); + Vertex v3b3 = new Vertex(10, 9.999, 3); + lr3.getVertices().add(v3b3); + Vertex v4b3 = new Vertex(6, 6, 3); + lr3.getVertices().add(v4b3); + lr3.getVertices().add(v1b3); + geom3.updateEdgesAndVertices(); + b3.addGeometry(geom3); + + handler.marshallCityObject(b); + handler.marshallCityObject(b2); + handler.marshallCityObject(b3); + handler.marshallCityObject(b4); + assertEquals(4, handler.getFeatureCount()); + + List objects = handler.getGeometryCollisionCandidates(b); + assertEquals(1, objects.size()); + assertEquals(4, handler.getFeatureCount()); + + CityObject co = handler.unmarshallCityObject(objects.get(0)); + assertNotNull(co); + assertCityObjectEquality(b2, co); + + } + + @Test + public void testGetBboxBufferIntersectingObjects() { + Building b = new Building(); + Building b2 = new Building(); + b2.setGmlObject(Mockito.mock(AbstractBuilding.class)); + Building b3 = new Building(); + Building b4 = new Building(); + b4.addGeometry(GeometryTestUtils.createDummyGeometry(GeometryType.SOLID, Lod.LOD0)); + + + Geometry geom = new Geometry(GeometryType.SOLID, Lod.LOD0, Geometry.Orientation.OUTWARD); + ConcretePolygon polygon = new ConcretePolygon(); + geom.getPolygons().add(polygon); + polygon.setParent(geom); + LinearRing lr = new LinearRing(LinearRing.LinearRingType.EXTERIOR); + polygon.setExteriorRing(lr); + Vertex v1 = new Vertex(10, 10, 8); + lr.getVertices().add(v1); + Vertex v2 = new Vertex(14, 15, 7); + lr.getVertices().add(v2); + Vertex v3 = new Vertex(14, 15, 3); + lr.getVertices().add(v3); + Vertex v4 = new Vertex(10, 10, 3); + lr.getVertices().add(v4); + lr.getVertices().add(v1); + geom.updateEdgesAndVertices(); + b.addGeometry(geom); + + + Geometry geom2 = new Geometry(GeometryType.SOLID, Lod.LOD0, Geometry.Orientation.OUTWARD); + ConcretePolygon polygon2 = new ConcretePolygon(); + geom2.getPolygons().add(polygon2); + polygon2.setParent(geom2); + LinearRing lr2 = new LinearRing(LinearRing.LinearRingType.EXTERIOR); + polygon2.setExteriorRing(lr2); + Vertex v1b2 = new Vertex(6, 6, 8); + lr2.getVertices().add(v1b2); + Vertex v2b2 = new Vertex(9, 9, 7); + lr2.getVertices().add(v2b2); + Vertex v3b2 = new Vertex(9, 9, 3); + lr2.getVertices().add(v3b2); + Vertex v4b2 = new Vertex(6, 6, 3); + lr2.getVertices().add(v4b2); + lr2.getVertices().add(v1b2); + geom2.updateEdgesAndVertices(); + b2.addGeometry(geom2); + + Geometry geom3 = new Geometry(GeometryType.SOLID, Lod.LOD0, Geometry.Orientation.OUTWARD); + ConcretePolygon polygon3 = new ConcretePolygon(); + geom3.getPolygons().add(polygon3); + polygon3.setParent(geom3); + LinearRing lr3 = new LinearRing(LinearRing.LinearRingType.EXTERIOR); + polygon3.setExteriorRing(lr3); + Vertex v1b3 = new Vertex(4, 4, 8); + lr3.getVertices().add(v1b3); + Vertex v2b3 = new Vertex(8.999, 8.999, 7); + lr3.getVertices().add(v2b3); + Vertex v3b3 = new Vertex(8.999, 8.999, 3); + lr3.getVertices().add(v3b3); + Vertex v4b3 = new Vertex(4, 4, 3); + lr3.getVertices().add(v4b3); + lr3.getVertices().add(v1b3); + geom3.updateEdgesAndVertices(); + b3.addGeometry(geom3); + + handler.marshallCityObject(b); + handler.marshallCityObject(b2); + handler.marshallCityObject(b3); + handler.marshallCityObject(b4); + assertEquals(4, handler.getFeatureCount()); + + List objects = handler.getBufferCollisionCandidates(b, Math.sqrt(2)); + assertEquals(1, objects.size()); + assertEquals(4, handler.getFeatureCount()); + + CityObject co = handler.unmarshallCityObject(objects.get(0)); + assertNotNull(co); + assertCityObjectEquality(b2, co); + + } + + @Test + public void testMarshallingRoundTripSimpleSolid() throws InvalidGmlFileException, CityGmlParseException { + ParserConfiguration config = new ParserConfiguration(8, false); + CityDoctorModel model = CityGmlParser.parseCityGmlFile("src/test/resources/SimpleSolid_SrefBS.gml", config); + + Building b = model.getBuildings().toList().get(0); + assertNotNull(b); + handler.marshallCityObject(b); + assertEquals(1, handler.getFeatureCount()); + + CityObject b2 = handler.unmarshallCityObject(b.getGmlId()); + assertNotNull(b2); + assertEquals(1, handler.getFeatureCount()); + + assertCityObjectEquality(b, b2); + + } + + + @Test + public void testMarshallingRoundTripFzk() throws InvalidGmlFileException, CityGmlParseException { + ParserConfiguration config = new ParserConfiguration(8, false); + CityDoctorModel model = CityGmlParser.parseCityGmlFile("src/test/resources/FZK_haus.gml", config); + + Building b = model.getBuildings().toList().get(0); + assertNotNull(b); + assertEquals(1, handler.getFeatureCount()); + handler.marshallCityObject(b); + assertEquals(1, handler.getFeatureCount()); + + CityObject b2 = handler.unmarshallCityObject(b.getGmlId()); + assertNotNull(b2); + assertEquals(1, handler.getFeatureCount()); + + assertCityObjectEquality(b, b2); + + } + +} diff --git a/CityDoctorParent/CityDoctorModel/src/test/java/de/hft/stuttgart/citydoctor2/database/FeatureCacheTest.java b/CityDoctorParent/CityDoctorModel/src/test/java/de/hft/stuttgart/citydoctor2/database/FeatureCacheTest.java new file mode 100644 index 0000000000000000000000000000000000000000..b17640f6d451cfda19f802703dba394ce570e27c --- /dev/null +++ b/CityDoctorParent/CityDoctorModel/src/test/java/de/hft/stuttgart/citydoctor2/database/FeatureCacheTest.java @@ -0,0 +1,99 @@ +package de.hft.stuttgart.citydoctor2.database; + +import de.hft.stuttgart.citydoctor2.datastructure.*; +import org.citygml4j.core.model.building.AbstractBuilding; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertThrows; +import static org.mockito.Mockito.mock; + +public class FeatureCacheTest { + + + + @Test + public void testPut(){ + FeatureCache cache = new FeatureCache(); + + Building b = new Building(); + b.setGmlObject(mock(AbstractBuilding.class)); + b.setGmlId(new GmlId("test")); + b.addGeometry(GeometryTestUtils.createDummyGeometry(GeometryType.SOLID, Lod.LOD0)); + + assertEquals(0, cache.getTotalFeatureCount()); + cache.put(b); + cache.synchronize(); + + assertEquals(1, cache.getTotalFeatureCount()); + } + + @Test + public void testGet(){ + FeatureCache cache = new FeatureCache(); + + assertNull(cache.get(new GmlId("test"))); + Building b = new Building(); + + b.setGmlObject(mock(AbstractBuilding.class)); + b.setGmlId(new GmlId("test")); + b.addGeometry(GeometryTestUtils.createDummyGeometry(GeometryType.SOLID, Lod.LOD0)); + assertEquals(0, cache.getTotalFeatureCount()); + cache.put(b); + cache.synchronize(); + + CityObject b2 = cache.get(new GmlId("test")); + assertEquals(b.getGmlId(), b2.getGmlId()); + } + + @Test + public void testStateHandlingFromIdle(){ + FeatureCache cache = new FeatureCache(); + assertEquals(FeatureCache.CacheState.IDLE, cache.getState()); + + AutoCloseable parsingContext = cache.startParsingMode(); + try(parsingContext){ + assertEquals(FeatureCache.CacheState.PARSING, cache.getState()); + } catch (Exception e){ + throw new RuntimeException(e); + } + assertEquals(FeatureCache.CacheState.IDLE, cache.getState()); + + AutoCloseable checkingContext = cache.startCheckingMode(); + try(checkingContext){ + assertEquals(FeatureCache.CacheState.CHECKING, cache.getState()); + } catch (Exception e){ + throw new RuntimeException(e); + } + assertEquals(FeatureCache.CacheState.IDLE, cache.getState()); + } + + @Test + public void testCheckingModeStateCollision(){ + FeatureCache cache = new FeatureCache(); + assertEquals(FeatureCache.CacheState.IDLE, cache.getState()); + AutoCloseable checkingContext = cache.startCheckingMode(); + try(checkingContext){ + assertEquals(FeatureCache.CacheState.CHECKING, cache.getState()); + assertThrows(IllegalStateException.class, cache::startParsingMode); + } catch (Exception e){ + throw new RuntimeException(e); + } + } + + @Test + public void testParsingModeStateCollision(){ + FeatureCache cache = new FeatureCache(); + assertEquals(FeatureCache.CacheState.IDLE, cache.getState()); + AutoCloseable parsingContext = cache.startParsingMode(); + try(parsingContext){ + assertEquals(FeatureCache.CacheState.PARSING, cache.getState()); + assertThrows(IllegalStateException.class, cache::startCheckingMode); + } catch (Exception e){ + throw new RuntimeException(e); + } + } + + +} diff --git a/CityDoctorParent/CityDoctorModel/src/test/java/de/hft/stuttgart/citydoctor2/database/SerializationTest.java b/CityDoctorParent/CityDoctorModel/src/test/java/de/hft/stuttgart/citydoctor2/database/SerializationTest.java new file mode 100644 index 0000000000000000000000000000000000000000..d664d6603d6ebd22f8290c440253a4589fb820ae --- /dev/null +++ b/CityDoctorParent/CityDoctorModel/src/test/java/de/hft/stuttgart/citydoctor2/database/SerializationTest.java @@ -0,0 +1,59 @@ +package de.hft.stuttgart.citydoctor2.database; + +import de.hft.stuttgart.citydoctor2.datastructure.Building; +import de.hft.stuttgart.citydoctor2.datastructure.CityDoctorModel; +import de.hft.stuttgart.citydoctor2.datastructure.CityObject; +import de.hft.stuttgart.citydoctor2.parser.CityGmlParseException; +import de.hft.stuttgart.citydoctor2.parser.CityGmlParser; +import de.hft.stuttgart.citydoctor2.parser.InvalidGmlFileException; +import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration; +import de.hft.stuttgart.citydoctor2.utils.visitors.CityObjectCollector; +import org.apache.commons.lang3.SerializationUtils; +import org.junit.Test; + +import java.util.Set; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +public class SerializationTest { + + static void assertCityObjectEquality(CityObject c1, CityObject c2) { + assertEquals(c1.getGmlId(), c2.getGmlId()); + assertEquals(c1.getFeatureType(), c2.getFeatureType()); + assertEquals(c1.getGmlObject().getId(), c2.getGmlObject().getId()); + + CityObjectCollector collector = new CityObjectCollector(); + c1.accept(collector); + Set coB = collector.getCityObjects(); + collector = new CityObjectCollector(); + c2.accept(collector); + Set coB2 = collector.getCityObjects(); + assertEquals(coB.size(), coB2.size()); + } + + @Test + public void testRoundtripSimpleSolid() throws CityGmlParseException, InvalidGmlFileException { + ParserConfiguration config = new ParserConfiguration(8, false); + CityDoctorModel model = CityGmlParser.parseCityGmlFile("src/test/resources/SimpleSolid_SrefBS.gml", config); + Building b = model.getBuildings().toList().get(0); + assertNotNull(b); + Building b2 = SerializationUtils.roundtrip(b); + assertNotNull(b2); + + assertCityObjectEquality(b, b2); + } + + + @Test + public void testRoundtripFzk() throws CityGmlParseException, InvalidGmlFileException { + ParserConfiguration config = new ParserConfiguration(8, false); + CityDoctorModel model = CityGmlParser.parseCityGmlFile("src/test/resources/FZK_haus.gml", config); + Building b = model.getBuildings().toList().get(0); + assertNotNull(b); + Building b2 = SerializationUtils.roundtrip(b); + + assertCityObjectEquality(b, b2); + } + +} diff --git a/CityDoctorParent/CityDoctorModel/src/test/java/de/hft/stuttgart/citydoctor2/datastructure/BoundarySurfaceTest.java b/CityDoctorParent/CityDoctorModel/src/test/java/de/hft/stuttgart/citydoctor2/datastructure/BoundarySurfaceTest.java index 1275cc857af29974dfcd4e6a959f63b7c3297f82..c08b1ad7cede13dbb1522e5bcab5081630b9564d 100644 --- a/CityDoctorParent/CityDoctorModel/src/test/java/de/hft/stuttgart/citydoctor2/datastructure/BoundarySurfaceTest.java +++ b/CityDoctorParent/CityDoctorModel/src/test/java/de/hft/stuttgart/citydoctor2/datastructure/BoundarySurfaceTest.java @@ -51,11 +51,9 @@ import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration; public class BoundarySurfaceTest { - //Todo: Check this class for rework potential with the new Visitors - @Test public void testVisitorPropagation() { - BoundarySurface bs = new BoundarySurface(SurfaceFeatureType.BUILDING, BoundarySurfaceType.WALL, null); + BoundarySurface bs = new BoundarySurface(BoundarySurfaceType.WALL, null); Opening oMock = Mockito.mock(Opening.class); bs.addOpening(oMock); @@ -68,7 +66,7 @@ public class BoundarySurfaceTest { @Test public void testAccept() { - BoundarySurface bs = new BoundarySurface(SurfaceFeatureType.BUILDING, BoundarySurfaceType.WALL, null); + BoundarySurface bs = new BoundarySurface(BoundarySurfaceType.WALL, null); Opening oMock = Mockito.mock(Opening.class); bs.addOpening(oMock); AtomicInteger bsCounter = new AtomicInteger(0); @@ -86,7 +84,7 @@ public class BoundarySurfaceTest { @Test public void testAcceptWithoutFittingCheck() { - BoundarySurface bs = new BoundarySurface(SurfaceFeatureType.BUILDING, BoundarySurfaceType.WALL, null); + BoundarySurface bs = new BoundarySurface(BoundarySurfaceType.WALL, null); Opening oMock = Mockito.mock(Opening.class); bs.addOpening(oMock); AtomicInteger bsCounter = new AtomicInteger(0); @@ -104,7 +102,7 @@ public class BoundarySurfaceTest { @Test public void testPrepareForChecking() { - BoundarySurface bs = new BoundarySurface(SurfaceFeatureType.BUILDING, BoundarySurfaceType.WALL, null); + BoundarySurface bs = new BoundarySurface(BoundarySurfaceType.WALL, null); Geometry geom = new Geometry(GeometryType.MULTI_SURFACE, Lod.LOD2, Orientation.OUTWARD); Geometry spyGeom = Mockito.spy(geom); bs.addGeometry(spyGeom); @@ -114,7 +112,7 @@ public class BoundarySurfaceTest { @Test public void testContainsError() { - BoundarySurface bs = new BoundarySurface(SurfaceFeatureType.BUILDING, BoundarySurfaceType.WALL, null); + BoundarySurface bs = new BoundarySurface(BoundarySurfaceType.WALL, null); assertFalse(bs.containsError(CheckId.C_GE_P_HOLE_OUTSIDE)); bs.addCheckResult( new CheckResult(CheckId.C_GE_P_HOLE_OUTSIDE, ResultStatus.ERROR, Mockito.mock(CheckError.class))); @@ -124,9 +122,9 @@ public class BoundarySurfaceTest { @Test public void testContainsErrorInOpening() { - BoundarySurface bs = new BoundarySurface(SurfaceFeatureType.BUILDING, BoundarySurfaceType.WALL, null); + BoundarySurface bs = new BoundarySurface(BoundarySurfaceType.WALL, null); assertFalse(bs.containsError(CheckId.C_GE_P_HOLE_OUTSIDE)); - Opening o = new Opening(OpeningType.WINDOW, SurfaceFeatureType.BUILDING, bs, null); + Opening o = new Opening(OpeningType.WINDOW, bs, null); bs.addOpening(o); o.addCheckResult( new CheckResult(CheckId.C_GE_P_HOLE_OUTSIDE, ResultStatus.ERROR, Mockito.mock(CheckError.class))); @@ -136,7 +134,7 @@ public class BoundarySurfaceTest { @Test public void testClearAllContainedCheckResults() { - BoundarySurface bs = new BoundarySurface(SurfaceFeatureType.BUILDING, BoundarySurfaceType.WALL, null); + BoundarySurface bs = new BoundarySurface(BoundarySurfaceType.WALL, null); Opening oMock = Mockito.mock(Opening.class); bs.addCheckResult( new CheckResult(CheckId.C_GE_P_HOLE_OUTSIDE, ResultStatus.ERROR, Mockito.mock(CheckError.class))); @@ -149,7 +147,7 @@ public class BoundarySurfaceTest { @Test public void testContainsAnyError() { - BoundarySurface bs = new BoundarySurface(SurfaceFeatureType.BUILDING, BoundarySurfaceType.WALL, null); + BoundarySurface bs = new BoundarySurface(BoundarySurfaceType.WALL, null); assertFalse(bs.containsAnyError()); bs.addCheckResult( new CheckResult(CheckId.C_GE_P_HOLE_OUTSIDE, ResultStatus.ERROR, Mockito.mock(CheckError.class))); @@ -159,19 +157,18 @@ public class BoundarySurfaceTest { @Test public void testCollectContainedErrors() { - BoundarySurface bs = new BoundarySurface(SurfaceFeatureType.BUILDING, BoundarySurfaceType.WALL, null); + BoundarySurface bs = new BoundarySurface(BoundarySurfaceType.WALL, null); bs.addCheckResult( new CheckResult(CheckId.C_GE_P_HOLE_OUTSIDE, ResultStatus.ERROR, Mockito.mock(CheckError.class))); List errors = new ArrayList<>(); bs.collectContainedErrors(errors); assertEquals(1, errors.size()); - ; } @Test public void testReCreateGeometriesWithoutId() { WallSurface ws = new WallSurface(); - BoundarySurface bs = new BoundarySurface(SurfaceFeatureType.BUILDING, BoundarySurfaceType.WALL, ws); + BoundarySurface bs = new BoundarySurface(BoundarySurfaceType.WALL, ws); bs.reCreateGeometries(GeometryFactory.newInstance(), new ParserConfiguration(8, false)); assertNotNull(ws.getId()); } @@ -180,7 +177,7 @@ public class BoundarySurfaceTest { public void testReCreateGeometriesWithId() { WallSurface ws = new WallSurface(); ws.setId("test"); - BoundarySurface bs = new BoundarySurface(SurfaceFeatureType.BUILDING, BoundarySurfaceType.WALL, ws); + BoundarySurface bs = new BoundarySurface(BoundarySurfaceType.WALL, ws); bs.reCreateGeometries(GeometryFactory.newInstance(), new ParserConfiguration(8, false)); // nothing has changed assertEquals("test", ws.getId()); @@ -190,89 +187,52 @@ public class BoundarySurfaceTest { } @Test - public void testReCreateGeometriesMultiSurfaceLod2() { - WallSurface ws = new WallSurface(); - BoundarySurface bs = new BoundarySurface(SurfaceFeatureType.BUILDING, BoundarySurfaceType.WALL, ws); - bs.addGeometry(GeometryTestUtils.createDummyGeometry(GeometryType.MULTI_SURFACE)); - bs.reCreateGeometries(GeometryFactory.newInstance(), new ParserConfiguration(8, false)); - assertNotNull(ws.getLod2MultiSurface()); - assertNull(ws.getLod3MultiSurface()); - assertNull(ws.getDeprecatedProperties().getLod4MultiSurface()); - } - - @Test - public void testReCreateGeometriesMultiSurfaceBridgeLod2() { - WallSurface ws = new WallSurface(); - BoundarySurface bs = new BoundarySurface(SurfaceFeatureType.BRIDGE, BoundarySurfaceType.WALL, ws); - bs.addGeometry(GeometryTestUtils.createDummyGeometry(GeometryType.MULTI_SURFACE)); - bs.reCreateGeometries(GeometryFactory.newInstance(), new ParserConfiguration(8, false)); - assertNotNull(ws.getLod2MultiSurface()); - assertNull(ws.getLod3MultiSurface()); - assertNull(ws.getDeprecatedProperties().getLod4MultiSurface()); - } - - @Test - public void testReCreateGeometriesMultiSurfaceBridgeLod3() { + public void testReCreateGeometriesMultiSurfaceLod0() { WallSurface ws = new WallSurface(); - BoundarySurface bs = new BoundarySurface(SurfaceFeatureType.BRIDGE, BoundarySurfaceType.WALL, ws); - bs.addGeometry(GeometryTestUtils.createDummyGeometry(GeometryType.MULTI_SURFACE, Lod.LOD3)); + BoundarySurface bs = new BoundarySurface(BoundarySurfaceType.WALL, ws); + bs.addGeometry(GeometryTestUtils.createDummyGeometry(GeometryType.MULTI_SURFACE, Lod.LOD0)); bs.reCreateGeometries(GeometryFactory.newInstance(), new ParserConfiguration(8, false)); + assertNotNull(ws.getLod0MultiSurface()); + assertNull(ws.getLod1MultiSurface()); assertNull(ws.getLod2MultiSurface()); - assertNotNull(ws.getLod3MultiSurface()); + assertNull(ws.getLod3MultiSurface()); assertNull(ws.getDeprecatedProperties().getLod4MultiSurface()); } @Test - public void testReCreateGeometriesMultiSurfaceBridgeLod4() { + public void testReCreateGeometriesMultiSurfaceLod1() { WallSurface ws = new WallSurface(); - BoundarySurface bs = new BoundarySurface(SurfaceFeatureType.BRIDGE, BoundarySurfaceType.WALL, ws); - bs.addGeometry(GeometryTestUtils.createDummyGeometry(GeometryType.MULTI_SURFACE, Lod.LOD4)); + BoundarySurface bs = new BoundarySurface(BoundarySurfaceType.WALL, ws); + bs.addGeometry(GeometryTestUtils.createDummyGeometry(GeometryType.MULTI_SURFACE, Lod.LOD1)); bs.reCreateGeometries(GeometryFactory.newInstance(), new ParserConfiguration(8, false)); + assertNull(ws.getLod0MultiSurface()); + assertNotNull(ws.getLod1MultiSurface()); assertNull(ws.getLod2MultiSurface()); assertNull(ws.getLod3MultiSurface()); - assertNotNull(ws.getDeprecatedProperties().getLod4MultiSurface()); + assertNull(ws.getDeprecatedProperties().getLod4MultiSurface()); } @Test - public void testReCreateGeometriesMultiSurfaceTunnelLod2() { + public void testReCreateGeometriesMultiSurfaceLod2() { WallSurface ws = new WallSurface(); - BoundarySurface bs = new BoundarySurface(SurfaceFeatureType.TUNNEL, BoundarySurfaceType.WALL, ws); + BoundarySurface bs = new BoundarySurface(BoundarySurfaceType.WALL, ws); bs.addGeometry(GeometryTestUtils.createDummyGeometry(GeometryType.MULTI_SURFACE)); bs.reCreateGeometries(GeometryFactory.newInstance(), new ParserConfiguration(8, false)); + assertNull(ws.getLod0MultiSurface()); + assertNull(ws.getLod1MultiSurface()); assertNotNull(ws.getLod2MultiSurface()); assertNull(ws.getLod3MultiSurface()); assertNull(ws.getDeprecatedProperties().getLod4MultiSurface()); } - @Test - public void testReCreateGeometriesMultiSurfaceTunnelLod3() { - WallSurface ws = new WallSurface(); - BoundarySurface bs = new BoundarySurface(SurfaceFeatureType.TUNNEL, BoundarySurfaceType.WALL, ws); - bs.addGeometry(GeometryTestUtils.createDummyGeometry(GeometryType.MULTI_SURFACE, Lod.LOD3)); - bs.reCreateGeometries(GeometryFactory.newInstance(), new ParserConfiguration(8, false)); - assertNull(ws.getLod2MultiSurface()); - assertNotNull(ws.getLod3MultiSurface()); - assertNull(ws.getDeprecatedProperties().getLod4MultiSurface()); - } - - @Test - public void testReCreateGeometriesMultiSurfaceTunnelLod4() { - WallSurface ws = new WallSurface(); - BoundarySurface bs = new BoundarySurface(SurfaceFeatureType.TUNNEL, BoundarySurfaceType.WALL, ws); - bs.addGeometry(GeometryTestUtils.createDummyGeometry(GeometryType.MULTI_SURFACE, Lod.LOD4)); - bs.reCreateGeometries(GeometryFactory.newInstance(), new ParserConfiguration(8, false)); - assertNull(ws.getLod2MultiSurface()); - assertNull(ws.getLod3MultiSurface()); - assertNotNull(ws.getDeprecatedProperties().getLod4MultiSurface()); - } - @Test public void testReCreateGeometriesMultiSurfaceLod3() { WallSurface ws = new WallSurface(); - ws.setId("test"); - BoundarySurface bs = new BoundarySurface(SurfaceFeatureType.BUILDING, BoundarySurfaceType.WALL, ws); + BoundarySurface bs = new BoundarySurface( BoundarySurfaceType.WALL, ws); bs.addGeometry(GeometryTestUtils.createDummyGeometry(GeometryType.MULTI_SURFACE, Lod.LOD3)); bs.reCreateGeometries(GeometryFactory.newInstance(), new ParserConfiguration(8, false)); + assertNull(ws.getLod0MultiSurface()); + assertNull(ws.getLod1MultiSurface()); assertNull(ws.getLod2MultiSurface()); assertNotNull(ws.getLod3MultiSurface()); assertNull(ws.getDeprecatedProperties().getLod4MultiSurface()); @@ -281,30 +241,21 @@ public class BoundarySurfaceTest { @Test public void testReCreateGeometriesMultiSurfaceLod4() { WallSurface ws = new WallSurface(); - ws.setId("test"); - BoundarySurface bs = new BoundarySurface(SurfaceFeatureType.BUILDING, BoundarySurfaceType.WALL, ws); + BoundarySurface bs = new BoundarySurface(BoundarySurfaceType.WALL, ws); bs.addGeometry(GeometryTestUtils.createDummyGeometry(GeometryType.MULTI_SURFACE, Lod.LOD4)); bs.reCreateGeometries(GeometryFactory.newInstance(), new ParserConfiguration(8, false)); + assertNull(ws.getLod0MultiSurface()); + assertNull(ws.getLod1MultiSurface()); assertNull(ws.getLod2MultiSurface()); assertNull(ws.getLod3MultiSurface()); assertNotNull(ws.getDeprecatedProperties().getLod4MultiSurface()); } - @Test - public void testReCreateGeometriesMultiSurfaceLod0() { - WallSurface ws = new WallSurface(); - ws.setId("test"); - BoundarySurface bs = new BoundarySurface(SurfaceFeatureType.BUILDING, BoundarySurfaceType.WALL, ws); - bs.addGeometry(GeometryTestUtils.createDummyGeometry(GeometryType.MULTI_SURFACE, Lod.LOD0)); - bs.reCreateGeometries(GeometryFactory.newInstance(), new ParserConfiguration(8, false)); - assertNotNull(ws.getLod0MultiSurface()); - } @Test(expected = IllegalStateException.class) public void testReCreateGeometriesSolid() { WallSurface ws = new WallSurface(); - ws.setId("test"); - BoundarySurface bs = new BoundarySurface(SurfaceFeatureType.BUILDING, BoundarySurfaceType.WALL, ws); + BoundarySurface bs = new BoundarySurface(BoundarySurfaceType.WALL, ws); bs.addGeometry(GeometryTestUtils.createDummyGeometry(GeometryType.SOLID)); bs.reCreateGeometries(GeometryFactory.newInstance(), new ParserConfiguration(8, false)); } @@ -312,8 +263,7 @@ public class BoundarySurfaceTest { @Test public void testReCreateGeometriesOpenings() { WallSurface ws = new WallSurface(); - ws.setId("test"); - BoundarySurface bs = new BoundarySurface(SurfaceFeatureType.BUILDING, BoundarySurfaceType.WALL, ws); + BoundarySurface bs = new BoundarySurface(BoundarySurfaceType.WALL, ws); Opening oMock = Mockito.mock(Opening.class); bs.addOpening(oMock); GeometryFactory factory = GeometryFactory.newInstance(); @@ -325,7 +275,7 @@ public class BoundarySurfaceTest { @Test public void testGetGmlObject() { WallSurface ws = new WallSurface(); - BoundarySurface bs = new BoundarySurface(SurfaceFeatureType.BUILDING, BoundarySurfaceType.WALL, ws); + BoundarySurface bs = new BoundarySurface(BoundarySurfaceType.WALL, ws); assertEquals(ws, bs.getGmlObject()); } @@ -338,7 +288,7 @@ public class BoundarySurfaceTest { assertNotNull(ws.getLod2MultiSurface()); assertNotNull(ws.getLod3MultiSurface()); assertNotNull(ws.getDeprecatedProperties().getLod4MultiSurface()); - BoundarySurface bs = new BoundarySurface(SurfaceFeatureType.BUILDING, BoundarySurfaceType.WALL, ws); + BoundarySurface bs = new BoundarySurface(BoundarySurfaceType.WALL, ws); Opening oMock = Mockito.mock(Opening.class); bs.addOpening(oMock); bs.accept(new UnsetGeometriesVisitor()); @@ -348,41 +298,9 @@ public class BoundarySurfaceTest { assertNull(ws.getDeprecatedProperties().getLod4MultiSurface()); } - @Test - public void testUnsetGmlGeometriesBridge() { - WallSurface ws = new WallSurface(); - ws.setLod2MultiSurface(new MultiSurfaceProperty()); - ws.setLod3MultiSurface(new MultiSurfaceProperty()); - ws.getDeprecatedProperties().setLod4MultiSurface(new MultiSurfaceProperty()); - assertNotNull(ws.getLod2MultiSurface()); - assertNotNull(ws.getLod3MultiSurface()); - assertNotNull(ws.getDeprecatedProperties().getLod4MultiSurface()); - BoundarySurface bs = new BoundarySurface(SurfaceFeatureType.BRIDGE, BoundarySurfaceType.WALL, ws); - bs.unsetGmlGeometries(); - assertNull(ws.getLod2MultiSurface()); - assertNull(ws.getLod3MultiSurface()); - assertNull(ws.getDeprecatedProperties().getLod4MultiSurface()); - } - - @Test - public void testUnsetGmlGeometriesTunnel() { - WallSurface ws = new WallSurface(); - ws.setLod2MultiSurface(new MultiSurfaceProperty()); - ws.setLod3MultiSurface(new MultiSurfaceProperty()); - ws.getDeprecatedProperties().setLod4MultiSurface(new MultiSurfaceProperty()); - assertNotNull(ws.getLod2MultiSurface()); - assertNotNull(ws.getLod3MultiSurface()); - assertNotNull(ws.getDeprecatedProperties().getLod4MultiSurface()); - BoundarySurface bs = new BoundarySurface(SurfaceFeatureType.TUNNEL, BoundarySurfaceType.WALL, ws); - bs.unsetGmlGeometries(); - assertNull(ws.getLod2MultiSurface()); - assertNull(ws.getLod3MultiSurface()); - assertNull(ws.getDeprecatedProperties().getLod4MultiSurface()); - } - @Test public void testGetFeatureType() { - BoundarySurface bs = new BoundarySurface(SurfaceFeatureType.TUNNEL, BoundarySurfaceType.WALL, null); + BoundarySurface bs = new BoundarySurface(BoundarySurfaceType.WALL, null); assertEquals(FeatureType.BOUNDARY_SURFACE, bs.getFeatureType()); } @@ -392,17 +310,11 @@ public class BoundarySurfaceTest { BoundarySurface bs = new BoundarySurface(aco); assertEquals(aco, bs.getGmlObject()); } - - @Test - public void testSetFeatureType() { - BoundarySurface bs = new BoundarySurface(SurfaceFeatureType.TUNNEL, BoundarySurfaceType.WALL, null); - bs.setFeatureType(SurfaceFeatureType.BRIDGE); - assertEquals(SurfaceFeatureType.BRIDGE, bs.getSurfaceFeatureType()); - } + @Test public void testSetType() { - BoundarySurface bs = new BoundarySurface(SurfaceFeatureType.TUNNEL, BoundarySurfaceType.WALL, null); + BoundarySurface bs = new BoundarySurface(BoundarySurfaceType.WALL, null); bs.setType(BoundarySurfaceType.ROOF); assertEquals(BoundarySurfaceType.ROOF, bs.getType()); } diff --git a/CityDoctorParent/CityDoctorModel/src/test/java/de/hft/stuttgart/citydoctor2/datastructure/BridgeObjectTest.java b/CityDoctorParent/CityDoctorModel/src/test/java/de/hft/stuttgart/citydoctor2/datastructure/BridgeObjectTest.java index d185d272673832131bfd175d24d84cb43161a643..931ce45c4daf8176200c0aa68071fbf85743c75b 100644 --- a/CityDoctorParent/CityDoctorModel/src/test/java/de/hft/stuttgart/citydoctor2/datastructure/BridgeObjectTest.java +++ b/CityDoctorParent/CityDoctorModel/src/test/java/de/hft/stuttgart/citydoctor2/datastructure/BridgeObjectTest.java @@ -51,7 +51,6 @@ import de.hft.stuttgart.citydoctor2.utils.visitors.UnsetGeometriesVisitor; public class BridgeObjectTest { - //TODO: Rework this class with the new Visitors @Test public void testAccept() { diff --git a/CityDoctorParent/CityDoctorModel/src/test/java/de/hft/stuttgart/citydoctor2/datastructure/BuildingTest.java b/CityDoctorParent/CityDoctorModel/src/test/java/de/hft/stuttgart/citydoctor2/datastructure/BuildingTest.java index a27eee4343fe5532d21b52b972e779275295417b..21d897faca604266bdf25a662d05ba0abc78a0ee 100644 --- a/CityDoctorParent/CityDoctorModel/src/test/java/de/hft/stuttgart/citydoctor2/datastructure/BuildingTest.java +++ b/CityDoctorParent/CityDoctorModel/src/test/java/de/hft/stuttgart/citydoctor2/datastructure/BuildingTest.java @@ -64,7 +64,7 @@ public class BuildingTest { b.setCityGmlBuilding(createCityGmlBuilding()); RoofSurface rs = new RoofSurface(); rs.setId("testRoof"); - BoundarySurface surface = new BoundarySurface(SurfaceFeatureType.BUILDING, BoundarySurfaceType.ROOF, rs); + BoundarySurface surface = new BoundarySurface(BoundarySurfaceType.ROOF, rs); Geometry geomSurface = new Geometry(GeometryType.MULTI_SURFACE, Lod.LOD2, Orientation.OUTWARD); geomSurface.addPolygon(new LinkedPolygon(p, geomSurface)); geomSurface.updateEdgesAndVertices(); @@ -75,7 +75,8 @@ public class BuildingTest { assertNotSame(b, copy); assertEquals(b.getGmlId(), copy.getGmlId()); - + + copy.prepareForChecking(); Geometry copyGeom = copy.getGeometries().get(0); assertNotSame(geom, copyGeom); diff --git a/CityDoctorParent/CityDoctorModel/src/test/java/de/hft/stuttgart/citydoctor2/datastructure/CityDoctorModelTest.java b/CityDoctorParent/CityDoctorModel/src/test/java/de/hft/stuttgart/citydoctor2/datastructure/CityDoctorModelTest.java index 7eeee2897303efc7f89d28f3d3431b98273c69a9..b535500a2481ebc4398d7568f6b7cb1219165ac1 100644 --- a/CityDoctorParent/CityDoctorModel/src/test/java/de/hft/stuttgart/citydoctor2/datastructure/CityDoctorModelTest.java +++ b/CityDoctorParent/CityDoctorModel/src/test/java/de/hft/stuttgart/citydoctor2/datastructure/CityDoctorModelTest.java @@ -27,11 +27,14 @@ import java.util.ArrayList; import java.util.List; import java.util.UUID; +import de.hft.stuttgart.citydoctor2.database.FeatureCache; +import de.hft.stuttgart.citydoctor2.database.UnconnectedCache; import org.citygml4j.core.ade.ADEException; import org.citygml4j.core.model.CityGMLVersion; import org.citygml4j.core.model.core.AbstractFeatureProperty; import org.citygml4j.core.model.core.CityModel; import org.citygml4j.xml.writer.CityGMLWriteException; +import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; @@ -63,28 +66,40 @@ import de.hft.stuttgart.quality.model.types.ValidationPlan; public class CityDoctorModelTest { + private File mockFile; + private ParserConfiguration config; + private CityDoctorModel model; + private final FeatureCache featureCache = new FeatureCache(); + @Before + public void setUp(){ + mockFile = Mockito.mock(File.class); + Mockito.when(mockFile.getName()).thenReturn("test"); + config = new ParserConfiguration(8, false); + featureCache.resetCache(); + model = new CityDoctorModel(config, mockFile, featureCache); + } + @Rule public TemporaryFolder folder = new TemporaryFolder(); @Test(expected = IllegalArgumentException.class) public void testCityDoctorModelNoConfig() { - new CityDoctorModel(null, null); + new CityDoctorModel(null, mockFile, new UnconnectedCache()); + } + + @Test(expected = IllegalArgumentException.class) + public void testCityDoctorModelNoFile() { + new CityDoctorModel(config, null, new UnconnectedCache()); } @Test public void testSetValidated() { - File f = Mockito.mock(File.class); - ParserConfiguration config = new ParserConfiguration(8, false); - CityDoctorModel model = new CityDoctorModel(config, f); model.setValidated(Mockito.mock(ValidationPlan.class)); assertTrue(model.isValidated()); } @Test public void testAddGlobalError() { - File f = Mockito.mock(File.class); - ParserConfiguration config = new ParserConfiguration(8, false); - CityDoctorModel model = new CityDoctorModel(config, f); CheckError err = Mockito.mock(CheckError.class); model.addGlobalError(err); assertEquals(err, model.getGlobalErrors().get(0)); @@ -92,9 +107,6 @@ public class CityDoctorModelTest { @Test public void testAddGlobalErrors() { - File f = Mockito.mock(File.class); - ParserConfiguration config = new ParserConfiguration(8, false); - CityDoctorModel model = new CityDoctorModel(config, f); CheckError err1 = Mockito.mock(CheckError.class); CheckError err2 = Mockito.mock(CheckError.class); List errors = new ArrayList<>(); @@ -107,19 +119,15 @@ public class CityDoctorModelTest { @Test public void testGetFile() { - File f = Mockito.mock(File.class); - ParserConfiguration config = new ParserConfiguration(8, false); - CityDoctorModel model = new CityDoctorModel(config, f); - assertEquals(f, model.getFile()); + assertEquals(mockFile, model.getFile()); } @Test public void testCreateFeatureStream() { - File f = Mockito.mock(File.class); - ParserConfiguration config = new ParserConfiguration(8, false); - CityDoctorModel model = new CityDoctorModel(config, f); Building b = Mockito.mock(Building.class); + Mockito.when(b.getGmlId()).thenReturn(new GmlId("b")); Vegetation v = Mockito.mock(Vegetation.class); + Mockito.when(v.getGmlId()).thenReturn(new GmlId("v")); model.addBuilding(b); model.addVegetation(v); assertTrue(model.createFeatureStream().anyMatch(c -> c == b)); @@ -129,9 +137,6 @@ public class CityDoctorModelTest { @Test public void testSaveAsWithoutValidation() throws CityGMLWriteException, ADEException, IOException, CityGmlParseException, InvalidGmlFileException, CityDoctorWriteException { - File f = Mockito.mock(File.class); - ParserConfiguration config = new ParserConfiguration(8, false); - CityDoctorModel model = new CityDoctorModel(config, f); model.setParsedCityGMLVersion(CityGMLVersion.v2_0); CityModel cModel = new CityModel(); model.setCityModel(cModel); @@ -147,7 +152,7 @@ public class CityDoctorModelTest { assertTrue(saveFile.length() > 0); CityDoctorModel parsedModel = CityGmlParser.parseCityGmlFile(saveFile.getAbsolutePath(), config); - Building parsedBuilding = parsedModel.getBuildings().get(0); + Building parsedBuilding = parsedModel.getBuildings().toList().get(0); assertEquals("testId", parsedBuilding.getGmlId().getGmlString()); assertEquals(1, parsedBuilding.getGeometries().size()); } @@ -155,9 +160,7 @@ public class CityDoctorModelTest { @Test public void testSaveAsWithValidation() throws CityGMLWriteException, ADEException, IOException, CityGmlParseException, InvalidGmlFileException, CityDoctorWriteException { - File f = Mockito.mock(File.class); - ParserConfiguration config = new ParserConfiguration(8, false); - CityDoctorModel model = new CityDoctorModel(config, f); + model.setParsedCityGMLVersion(CityGMLVersion.v2_0); CityModel cModel = new CityModel(); ValidationPlan plan = new ValidationPlan(); @@ -214,7 +217,7 @@ public class CityDoctorModelTest { assertTrue(saveFile.length() > 0); CityDoctorModel parsedModel = CityGmlParser.parseCityGmlFile(saveFile.getAbsolutePath(), config); - Building parsedBuilding = parsedModel.getBuildings().get(0); + Building parsedBuilding = parsedModel.getBuildings().toList().get(0); assertEquals("testId", parsedBuilding.getGmlId().getGmlString()); assertEquals(1, parsedBuilding.getGeometries().size()); List props = parsedBuilding.getGmlObject().getADEProperties(CityObjectProperties.class); @@ -234,9 +237,6 @@ public class CityDoctorModelTest { @Test public void testCollectErrors() { - File f = Mockito.mock(File.class); - ParserConfiguration config = new ParserConfiguration(8, false); - CityDoctorModel model = new CityDoctorModel(config, f); Building b = new Building(); model.addBuilding(b); CheckError error = Mockito.mock(CheckError.class); @@ -247,18 +247,12 @@ public class CityDoctorModelTest { @Test public void testGetFileName() { - File f = new File("test"); - ParserConfiguration config = new ParserConfiguration(8, false); - CityDoctorModel model = new CityDoctorModel(config, f); assertEquals("test", model.getFileName()); - assertEquals(f, model.getFile()); + assertEquals(mockFile, model.getFile()); } @Test public void testSetCityModel() { - File f = Mockito.mock(File.class); - ParserConfiguration config = new ParserConfiguration(8, false); - CityDoctorModel model = new CityDoctorModel(config, f); CityModel cModel = Mockito.mock(CityModel.class); model.setCityModel(cModel); assertEquals(cModel, model.getCityModel()); @@ -266,111 +260,99 @@ public class CityDoctorModelTest { @Test public void testAddBuilding() { - File f = Mockito.mock(File.class); - ParserConfiguration config = new ParserConfiguration(8, false); - CityDoctorModel model = new CityDoctorModel(config, f); Building b = Mockito.mock(Building.class); + Mockito.when(b.getGmlId()).thenReturn(new GmlId("b")); model.addBuilding(b); - assertEquals(b, model.getBuildings().get(0)); + assertEquals(b, model.getBuildings().toList().get(0)); } @Test public void testAddBridge() { - File f = Mockito.mock(File.class); - ParserConfiguration config = new ParserConfiguration(8, false); - CityDoctorModel model = new CityDoctorModel(config, f); BridgeObject b = Mockito.mock(BridgeObject.class); + Mockito.when(b.getGmlId()).thenReturn(new GmlId("b")); model.addBridge(b); - assertEquals(b, model.getBridges().get(0)); + assertEquals(b, model.getBridges().toList().get(0)); } @Test public void testAddVegetation() { - File f = Mockito.mock(File.class); - ParserConfiguration config = new ParserConfiguration(8, false); - CityDoctorModel model = new CityDoctorModel(config, f); Vegetation veg = Mockito.mock(Vegetation.class); + Mockito.when(veg.getGmlId()).thenReturn(new GmlId("v")); model.addVegetation(veg); - assertEquals(veg, model.getVegetation().get(0)); + assertEquals(veg, model.getVegetation().toList().get(0)); } @Test public void testAddTunnel() { - File f = Mockito.mock(File.class); - ParserConfiguration config = new ParserConfiguration(8, false); - CityDoctorModel model = new CityDoctorModel(config, f); Tunnel tunnel = Mockito.mock(Tunnel.class); + Mockito.when(tunnel.getGmlId()).thenReturn(new GmlId("t")); model.addTunnel(tunnel); - assertEquals(tunnel, model.getTunnels().get(0)); + assertEquals(tunnel, model.getTunnels().toList().get(0)); } @Test public void testAddTransportation() { - File f = Mockito.mock(File.class); - ParserConfiguration config = new ParserConfiguration(8, false); - CityDoctorModel model = new CityDoctorModel(config, f); TransportationObject trans = Mockito.mock(TransportationObject.class); + Mockito.when(trans.getGmlId()).thenReturn(new GmlId("t")); model.addTransportation(trans); - assertEquals(trans, model.getTransportation().get(0)); + assertEquals(trans, model.getTransportation().toList().get(0)); } @Test public void testAddLand() { - File f = Mockito.mock(File.class); - ParserConfiguration config = new ParserConfiguration(8, false); - CityDoctorModel model = new CityDoctorModel(config, f); LandObject land = Mockito.mock(LandObject.class); + Mockito.when(land.getGmlId()).thenReturn(new GmlId("l")); model.addLand(land); - assertEquals(land, model.getLand().get(0)); + assertEquals(land, model.getLand().toList().get(0)); } @Test public void testAddWater() { - File f = Mockito.mock(File.class); - ParserConfiguration config = new ParserConfiguration(8, false); - CityDoctorModel model = new CityDoctorModel(config, f); WaterObject water = Mockito.mock(WaterObject.class); + Mockito.when(water.getGmlId()).thenReturn(new GmlId("w")); model.addWater(water); - assertEquals(water, model.getWater().get(0)); + assertEquals(water, model.getWater().toList().get(0)); } @Test public void testAddCityFurniture() { - File f = Mockito.mock(File.class); - ParserConfiguration config = new ParserConfiguration(8, false); - CityDoctorModel model = new CityDoctorModel(config, f); CityFurniture cf = Mockito.mock(CityFurniture.class); + Mockito.when(cf.getGmlId()).thenReturn(new GmlId("cf")); model.addCityFurniture(cf); - assertEquals(cf, model.getCityFurniture().get(0)); + assertEquals(cf, model.getCityFurniture().toList().get(0)); } @Test - public void testAddGenericCityObject() { - File f = Mockito.mock(File.class); - ParserConfiguration config = new ParserConfiguration(8, false); - CityDoctorModel model = new CityDoctorModel(config, f); + public void testAddOtherCityObject() { GenericCityObject gen = Mockito.mock(GenericCityObject.class); - model.addGenericCityObject(gen); - assertEquals(gen, model.getGenericCityObjects().get(0)); + Mockito.when(gen.getGmlId()).thenReturn(new GmlId("g")); + model.addOtherCityObject(gen); + assertEquals(gen, model.getOtherCityObjects().toList().get(0)); } @Test public void testGetNumberOfFeatures() { - File f = Mockito.mock(File.class); - ParserConfiguration config = new ParserConfiguration(8, false); - CityDoctorModel model = new CityDoctorModel(config, f); Building b = Mockito.mock(Building.class); + Mockito.when(b.getGmlId()).thenReturn(new GmlId("b")); BridgeObject bo = Mockito.mock(BridgeObject.class); + Mockito.when(bo.getGmlId()).thenReturn(new GmlId("bo")); Vegetation veg = Mockito.mock(Vegetation.class); + Mockito.when(veg.getGmlId()).thenReturn(new GmlId("ve")); Tunnel tunnel = Mockito.mock(Tunnel.class); + Mockito.when(tunnel.getGmlId()).thenReturn(new GmlId("t")); TransportationObject trans = Mockito.mock(TransportationObject.class); + Mockito.when(trans.getGmlId()).thenReturn(new GmlId("tr")); LandObject land = Mockito.mock(LandObject.class); + Mockito.when(land.getGmlId()).thenReturn(new GmlId("l")); WaterObject water = Mockito.mock(WaterObject.class); + Mockito.when(water.getGmlId()).thenReturn(new GmlId("w")); CityFurniture cf = Mockito.mock(CityFurniture.class); + Mockito.when(cf.getGmlId()).thenReturn(new GmlId("cf")); GenericCityObject generic = Mockito.mock(GenericCityObject.class); + Mockito.when(generic.getGmlId()).thenReturn(new GmlId("g")); model.addBuilding(b); model.addBridge(bo); @@ -380,7 +362,7 @@ public class CityDoctorModelTest { model.addLand(land); model.addWater(water); model.addCityFurniture(cf); - model.addGenericCityObject(generic); + model.addOtherCityObject(generic); assertEquals(9, model.getNumberOfFeatures()); @@ -388,31 +370,25 @@ public class CityDoctorModelTest { @Test public void testGetParserConfig() { - File f = Mockito.mock(File.class); - ParserConfiguration config = new ParserConfiguration(8, false); - CityDoctorModel model = new CityDoctorModel(config, f); assertEquals(config, model.getParserConfig()); } @Test public void testReplaceBuilding() { - File f = Mockito.mock(File.class); - ParserConfiguration config = new ParserConfiguration(8, false); - CityDoctorModel model = new CityDoctorModel(config, f); Building b1 = Mockito.mock(Building.class); + Mockito.when(b1.getGmlId()).thenReturn(new GmlId("b1")); Building b2 = Mockito.mock(Building.class); + Mockito.when(b2.getGmlId()).thenReturn(new GmlId("b2")); + model.addBuilding(b1); - assertEquals(b1, model.getBuildings().get(0)); + assertEquals(b1, model.getBuildings().toList().get(0)); model.replaceFeature(b1, b2); - assertEquals(b2, model.getBuildings().get(0)); - assertEquals(1, model.getBuildings().size()); + assertEquals(b2, model.getBuildings().toList().get(0)); + assertEquals(1, model.getBuildings().toList().size()); } @Test(expected = IllegalStateException.class) public void testReplaceBuildingMissing() { - File f = Mockito.mock(File.class); - ParserConfiguration config = new ParserConfiguration(8, false); - CityDoctorModel model = new CityDoctorModel(config, f); Building b1 = Mockito.mock(Building.class); Building b2 = Mockito.mock(Building.class); model.replaceFeature(b1, b2); @@ -420,23 +396,19 @@ public class CityDoctorModelTest { @Test public void testReplaceBridge() { - File f = Mockito.mock(File.class); - ParserConfiguration config = new ParserConfiguration(8, false); - CityDoctorModel model = new CityDoctorModel(config, f); BridgeObject b1 = Mockito.mock(BridgeObject.class); + Mockito.when(b1.getGmlId()).thenReturn(new GmlId("b1")); BridgeObject b2 = Mockito.mock(BridgeObject.class); + Mockito.when(b2.getGmlId()).thenReturn(new GmlId("b2")); model.addBridge(b1); - assertEquals(b1, model.getBridges().get(0)); + assertEquals(b1, model.getBridges().toList().get(0)); model.replaceFeature(b1, b2); - assertEquals(b2, model.getBridges().get(0)); - assertEquals(1, model.getBridges().size()); + assertEquals(b2, model.getBridges().toList().get(0)); + assertEquals(1, model.getBridges().toList().size()); } @Test(expected = IllegalStateException.class) public void testReplaceBridgeMissing() { - File f = Mockito.mock(File.class); - ParserConfiguration config = new ParserConfiguration(8, false); - CityDoctorModel model = new CityDoctorModel(config, f); BridgeObject b1 = Mockito.mock(BridgeObject.class); BridgeObject b2 = Mockito.mock(BridgeObject.class); model.replaceFeature(b1, b2); @@ -444,23 +416,20 @@ public class CityDoctorModelTest { @Test public void testReplaceVegetation() { - File f = Mockito.mock(File.class); - ParserConfiguration config = new ParserConfiguration(8, false); - CityDoctorModel model = new CityDoctorModel(config, f); Vegetation v1 = Mockito.mock(Vegetation.class); + Mockito.when(v1.getGmlId()).thenReturn(new GmlId("v1")); Vegetation v2 = Mockito.mock(Vegetation.class); + Mockito.when(v2.getGmlId()).thenReturn(new GmlId("v2")); + model.addVegetation(v1); - assertEquals(v1, model.getVegetation().get(0)); + assertEquals(v1, model.getVegetation().toList().get(0)); model.replaceFeature(v1, v2); - assertEquals(v2, model.getVegetation().get(0)); - assertEquals(1, model.getVegetation().size()); + assertEquals(v2, model.getVegetation().toList().get(0)); + assertEquals(1, model.getVegetation().toList().size()); } @Test(expected = IllegalStateException.class) public void testReplaceVegetationMissing() { - File f = Mockito.mock(File.class); - ParserConfiguration config = new ParserConfiguration(8, false); - CityDoctorModel model = new CityDoctorModel(config, f); Vegetation v1 = Mockito.mock(Vegetation.class); Vegetation v2 = Mockito.mock(Vegetation.class); model.replaceFeature(v1, v2); @@ -468,23 +437,20 @@ public class CityDoctorModelTest { @Test public void testReplaceTunnel() { - File f = Mockito.mock(File.class); - ParserConfiguration config = new ParserConfiguration(8, false); - CityDoctorModel model = new CityDoctorModel(config, f); Tunnel t1 = Mockito.mock(Tunnel.class); + Mockito.when(t1.getGmlId()).thenReturn(new GmlId("t1")); Tunnel t2 = Mockito.mock(Tunnel.class); + Mockito.when(t2.getGmlId()).thenReturn(new GmlId("t2")); + model.addTunnel(t1); - assertEquals(t1, model.getTunnels().get(0)); + assertEquals(t1, model.getTunnels().toList().get(0)); model.replaceFeature(t1, t2); - assertEquals(t2, model.getTunnels().get(0)); - assertEquals(1, model.getTunnels().size()); + assertEquals(t2, model.getTunnels().toList().get(0)); + assertEquals(1, model.getTunnels().toList().size()); } @Test(expected = IllegalStateException.class) public void testReplaceTunnelMissing() { - File f = Mockito.mock(File.class); - ParserConfiguration config = new ParserConfiguration(8, false); - CityDoctorModel model = new CityDoctorModel(config, f); Tunnel t1 = Mockito.mock(Tunnel.class); Tunnel t2 = Mockito.mock(Tunnel.class); model.replaceFeature(t1, t2); @@ -492,23 +458,20 @@ public class CityDoctorModelTest { @Test public void testReplaceTransportation() { - File f = Mockito.mock(File.class); - ParserConfiguration config = new ParserConfiguration(8, false); - CityDoctorModel model = new CityDoctorModel(config, f); TransportationObject t1 = Mockito.mock(TransportationObject.class); + Mockito.when(t1.getGmlId()).thenReturn(new GmlId("t1")); TransportationObject t2 = Mockito.mock(TransportationObject.class); + Mockito.when(t2.getGmlId()).thenReturn(new GmlId("t2")); + model.addTransportation(t1); - assertEquals(t1, model.getTransportation().get(0)); + assertEquals(t1, model.getTransportation().toList().get(0)); model.replaceFeature(t1, t2); - assertEquals(t2, model.getTransportation().get(0)); - assertEquals(1, model.getTransportation().size()); + assertEquals(t2, model.getTransportation().toList().get(0)); + assertEquals(1, model.getTransportation().toList().size()); } @Test(expected = IllegalStateException.class) public void testReplaceTransportationMissing() { - File f = Mockito.mock(File.class); - ParserConfiguration config = new ParserConfiguration(8, false); - CityDoctorModel model = new CityDoctorModel(config, f); TransportationObject t1 = Mockito.mock(TransportationObject.class); TransportationObject t2 = Mockito.mock(TransportationObject.class); model.replaceFeature(t1, t2); @@ -516,23 +479,20 @@ public class CityDoctorModelTest { @Test public void testReplaceLand() { - File f = Mockito.mock(File.class); - ParserConfiguration config = new ParserConfiguration(8, false); - CityDoctorModel model = new CityDoctorModel(config, f); LandObject lo1 = Mockito.mock(LandObject.class); + Mockito.when(lo1.getGmlId()).thenReturn(new GmlId("lo1")); LandObject lo2 = Mockito.mock(LandObject.class); + Mockito.when(lo2.getGmlId()).thenReturn(new GmlId("lo2")); + model.addLand(lo1); - assertEquals(lo1, model.getLand().get(0)); + assertEquals(lo1, model.getLand().toList().get(0)); model.replaceFeature(lo1, lo2); - assertEquals(lo2, model.getLand().get(0)); - assertEquals(1, model.getLand().size()); + assertEquals(lo2, model.getLand().toList().get(0)); + assertEquals(1, model.getLand().toList().size()); } @Test(expected = IllegalStateException.class) public void testReplaceLandMissing() { - File f = Mockito.mock(File.class); - ParserConfiguration config = new ParserConfiguration(8, false); - CityDoctorModel model = new CityDoctorModel(config, f); LandObject lo1 = Mockito.mock(LandObject.class); LandObject lo2 = Mockito.mock(LandObject.class); model.replaceFeature(lo1, lo2); @@ -540,23 +500,20 @@ public class CityDoctorModelTest { @Test public void testReplaceWater() { - File f = Mockito.mock(File.class); - ParserConfiguration config = new ParserConfiguration(8, false); - CityDoctorModel model = new CityDoctorModel(config, f); WaterObject t1 = Mockito.mock(WaterObject.class); + Mockito.when(t1.getGmlId()).thenReturn(new GmlId("t1")); WaterObject t2 = Mockito.mock(WaterObject.class); + Mockito.when(t2.getGmlId()).thenReturn(new GmlId("t2")); + model.addWater(t1); - assertEquals(t1, model.getWater().get(0)); + assertEquals(t1, model.getWater().toList().get(0)); model.replaceFeature(t1, t2); - assertEquals(t2, model.getWater().get(0)); - assertEquals(1, model.getWater().size()); + assertEquals(t2, model.getWater().toList().get(0)); + assertEquals(1, model.getWater().toList().size()); } @Test(expected = IllegalStateException.class) public void testReplaceWaterMissing() { - File f = Mockito.mock(File.class); - ParserConfiguration config = new ParserConfiguration(8, false); - CityDoctorModel model = new CityDoctorModel(config, f); WaterObject t1 = Mockito.mock(WaterObject.class); WaterObject t2 = Mockito.mock(WaterObject.class); model.replaceFeature(t1, t2); @@ -564,23 +521,20 @@ public class CityDoctorModelTest { @Test public void testReplaceCityFurniture() { - File f = Mockito.mock(File.class); - ParserConfiguration config = new ParserConfiguration(8, false); - CityDoctorModel model = new CityDoctorModel(config, f); CityFurniture cf1 = Mockito.mock(CityFurniture.class); + Mockito.when(cf1.getGmlId()).thenReturn(new GmlId("cf1")); CityFurniture cf2 = Mockito.mock(CityFurniture.class); + Mockito.when(cf2.getGmlId()).thenReturn(new GmlId("cf2")); + model.addCityFurniture(cf1); - assertEquals(cf1, model.getCityFurniture().get(0)); + assertEquals(cf1, model.getCityFurniture().toList().get(0)); model.replaceFeature(cf1, cf2); - assertEquals(cf2, model.getCityFurniture().get(0)); - assertEquals(1, model.getCityFurniture().size()); + assertEquals(cf2, model.getCityFurniture().toList().get(0)); + assertEquals(1, model.getCityFurniture().toList().size()); } @Test(expected = IllegalStateException.class) public void testReplaceCityFurnitureMissing() { - File f = Mockito.mock(File.class); - ParserConfiguration config = new ParserConfiguration(8, false); - CityDoctorModel model = new CityDoctorModel(config, f); CityFurniture cf1 = Mockito.mock(CityFurniture.class); CityFurniture cf2 = Mockito.mock(CityFurniture.class); model.replaceFeature(cf1, cf2); @@ -588,23 +542,20 @@ public class CityDoctorModelTest { @Test public void testReplaceGenericCityObject() { - File f = Mockito.mock(File.class); - ParserConfiguration config = new ParserConfiguration(8, false); - CityDoctorModel model = new CityDoctorModel(config, f); GenericCityObject gco1 = Mockito.mock(GenericCityObject.class); + Mockito.when(gco1.getGmlId()).thenReturn(new GmlId("gco1")); GenericCityObject gco2 = Mockito.mock(GenericCityObject.class); - model.addGenericCityObject(gco1); - assertEquals(gco1, model.getGenericCityObjects().get(0)); + Mockito.when(gco2.getGmlId()).thenReturn(new GmlId("gco2")); + + model.addOtherCityObject(gco1); + assertEquals(gco1, model.getOtherCityObjects().toList().get(0)); model.replaceFeature(gco1, gco2); - assertEquals(gco2, model.getGenericCityObjects().get(0)); - assertEquals(1, model.getGenericCityObjects().size()); + assertEquals(gco2, model.getOtherCityObjects().toList().get(0)); + assertEquals(1, model.getOtherCityObjects().toList().size()); } @Test(expected = IllegalStateException.class) public void testReplaceGenericCityObjectMissing() { - File f = Mockito.mock(File.class); - ParserConfiguration config = new ParserConfiguration(8, false); - CityDoctorModel model = new CityDoctorModel(config, f); GenericCityObject gco1 = Mockito.mock(GenericCityObject.class); GenericCityObject gco2 = Mockito.mock(GenericCityObject.class); model.replaceFeature(gco1, gco2); diff --git a/CityDoctorParent/CityDoctorModel/src/test/java/de/hft/stuttgart/citydoctor2/datastructure/CompositePolygonTest.java b/CityDoctorParent/CityDoctorModel/src/test/java/de/hft/stuttgart/citydoctor2/datastructure/CompositePolygonTest.java index 7aa9ad7763c3c949010b4464d2567ffc94d12042..9c306ab34964f5cba514843072d70110439109d3 100644 --- a/CityDoctorParent/CityDoctorModel/src/test/java/de/hft/stuttgart/citydoctor2/datastructure/CompositePolygonTest.java +++ b/CityDoctorParent/CityDoctorModel/src/test/java/de/hft/stuttgart/citydoctor2/datastructure/CompositePolygonTest.java @@ -16,7 +16,7 @@ public class CompositePolygonTest { ParserConfiguration config = new ParserConfiguration(8, false); CityDoctorModel m = CityGmlParser.parseCityGmlFile("src/test/resources/FZK_haus.gml", config); - Building b = m.getBuildings().get(0); + Building b = m.getBuildings().toList().get(0); assertNotNull(b); assertFalse(b.getBoundarySurfaces().isEmpty()); for (BoundarySurface bs : b.getBoundarySurfaces()) { diff --git a/CityDoctorParent/CityDoctorModel/src/test/java/de/hft/stuttgart/citydoctor2/datastructure/GeometryTest.java b/CityDoctorParent/CityDoctorModel/src/test/java/de/hft/stuttgart/citydoctor2/datastructure/GeometryTest.java index a37077ae28fbca4d79961e9bb2a5141afabdbe79..5c8b97cff5c28a6c4b8b9e1308253988999b70f3 100644 --- a/CityDoctorParent/CityDoctorModel/src/test/java/de/hft/stuttgart/citydoctor2/datastructure/GeometryTest.java +++ b/CityDoctorParent/CityDoctorModel/src/test/java/de/hft/stuttgart/citydoctor2/datastructure/GeometryTest.java @@ -96,7 +96,7 @@ public class GeometryTest { public void testRemovePolygonConcreteWithLink() { ParserConfiguration config = new ParserConfiguration(4, false); AbstractConstructionSurface abs = new WallSurface(); - BoundarySurface bs = new BoundarySurface(SurfaceFeatureType.BUILDING, BoundarySurfaceType.WALL, abs); + BoundarySurface bs = new BoundarySurface(BoundarySurfaceType.WALL, abs); var gmlBi = new org.citygml4j.core.model.building.BuildingInstallation(); Installation bi = new Installation(); bi.setGmlObject(gmlBi); @@ -133,7 +133,7 @@ public class GeometryTest { public void testRemovePolygonOnlyConcrete() { ParserConfiguration config = new ParserConfiguration(4, false); AbstractConstructionSurface abs = new WallSurface(); - BoundarySurface bs = new BoundarySurface(SurfaceFeatureType.BUILDING, BoundarySurfaceType.WALL, abs); + BoundarySurface bs = new BoundarySurface(BoundarySurfaceType.WALL, abs); Geometry geom = new Geometry(GeometryType.MULTI_SURFACE, Lod.LOD2, Orientation.OUTWARD); ConcretePolygon p = new ConcretePolygon(); @@ -156,7 +156,7 @@ public class GeometryTest { public void testRemovePolygonLinked() { ParserConfiguration config = new ParserConfiguration(4, false); AbstractConstructionSurface abs = new WallSurface(); - BoundarySurface bs = new BoundarySurface(SurfaceFeatureType.BUILDING, BoundarySurfaceType.WALL, abs); + BoundarySurface bs = new BoundarySurface(BoundarySurfaceType.WALL, abs); var gmlBi = new org.citygml4j.core.model.building.BuildingInstallation(); Installation bi = new Installation(); bi.setGmlObject(gmlBi); @@ -193,7 +193,7 @@ public class GeometryTest { public void testReplacePolygon() { ParserConfiguration config = new ParserConfiguration(4, false); AbstractConstructionSurface abs = new WallSurface(); - BoundarySurface bs = new BoundarySurface(SurfaceFeatureType.BUILDING, BoundarySurfaceType.WALL, abs); + BoundarySurface bs = new BoundarySurface(BoundarySurfaceType.WALL, abs); var gmlBi = new org.citygml4j.core.model.building.BuildingInstallation(); Installation bi = new Installation(); bi.setGmlObject(gmlBi); diff --git a/CityDoctorParent/CityDoctorModel/src/test/java/de/hft/stuttgart/citydoctor2/datastructure/VegetationTest.java b/CityDoctorParent/CityDoctorModel/src/test/java/de/hft/stuttgart/citydoctor2/datastructure/VegetationTest.java index 5f9c97a3f29f5bb6dd70e7ed4cdb3df3c51dd964..4df104691c64bb4c5f1535ea058b9ac285172a50 100644 --- a/CityDoctorParent/CityDoctorModel/src/test/java/de/hft/stuttgart/citydoctor2/datastructure/VegetationTest.java +++ b/CityDoctorParent/CityDoctorModel/src/test/java/de/hft/stuttgart/citydoctor2/datastructure/VegetationTest.java @@ -26,7 +26,6 @@ import static org.mockito.Mockito.mock; public class VegetationTest { - //TODO: Recreate geometries tests @Test public void testContainsError() { diff --git a/CityDoctorParent/CityDoctorModel/src/test/java/de/hft/stuttgart/citydoctor2/mapper/FeatureMapperTest.java b/CityDoctorParent/CityDoctorModel/src/test/java/de/hft/stuttgart/citydoctor2/mapper/FeatureMapperTest.java index a4d8f261a8a6f70f685dbb5d9b64592ca5708849..456d40124bc646f364c306016fc84c5a80177a68 100644 --- a/CityDoctorParent/CityDoctorModel/src/test/java/de/hft/stuttgart/citydoctor2/mapper/FeatureMapperTest.java +++ b/CityDoctorParent/CityDoctorModel/src/test/java/de/hft/stuttgart/citydoctor2/mapper/FeatureMapperTest.java @@ -63,20 +63,20 @@ public class FeatureMapperTest { public void testVisitWaterBody() { WaterBody body = new WaterBody(); Citygml3FeatureMapper mapper = new Citygml3FeatureMapper(mock(ParserConfiguration.class), - new File("").toPath()); + new File("").toPath(), false); mapper.visit(body); - assertEquals(1, mapper.getModel().getWater().size()); + assertEquals(1, mapper.getModel().getWater().toList().size()); body.setId("test1"); mapper.visit(body); - assertEquals(2, mapper.getModel().getWater().size()); - WaterObject waterObject = mapper.getModel().getWater().get(1); + assertEquals(2, mapper.getModel().getWater().toList().size()); + WaterObject waterObject = mapper.getModel().getWater().toList().get(1); assertEquals("test1", waterObject.getGmlId().getGmlString()); body.getDeprecatedProperties().setLod1MultiSurface(createDummyMsp()); mapper.visit(body); - assertEquals(3, mapper.getModel().getWater().size()); + assertEquals(3, mapper.getModel().getWater().toList().size()); assertNull(body.getDeprecatedProperties().getLod1MultiSurface()); - Geometry geometry = mapper.getModel().getWater().get(2).getGeometries().get(0); + Geometry geometry = mapper.getModel().getWater().toList().get(2).getGeometries().get(0); assertEquals(1, geometry.getPolygons().size()); assertEquals(Lod.LOD1, geometry.getLod()); assertEquals(GeometryType.MULTI_SURFACE, geometry.getType()); @@ -86,7 +86,7 @@ public class FeatureMapperTest { public void testVisitPlantCover() { PlantCover cover = new PlantCover(); Citygml3FeatureMapper mapper = new Citygml3FeatureMapper(mock(ParserConfiguration.class), - new File("").toPath()); + new File("").toPath(), false); mapper.visit(cover); } @@ -124,12 +124,12 @@ public class FeatureMapperTest { body.getDeprecatedProperties().setLod1MultiSurface(new MultiSurfaceProperty(ms)); ParserConfiguration config = new ParserConfiguration(8, false); - Citygml3FeatureMapper mapper = new Citygml3FeatureMapper(config, folder.newFile().toPath()); + Citygml3FeatureMapper mapper = new Citygml3FeatureMapper(config, folder.newFile().toPath(), false); mapper.visit(body); CityDoctorModel model = mapper.getModel(); - assertEquals(1, model.getWater().size()); - WaterObject waterObject = model.getWater().get(0); + assertEquals(1, model.getWater().toList().size()); + WaterObject waterObject = model.getWater().toList().get(0); Geometry geometry = waterObject.getGeometries().get(0); assertEquals(1, geometry.getVertices().size()); Vertex vertex = geometry.getVertices().get(0); @@ -152,12 +152,12 @@ public class FeatureMapperTest { body.getDeprecatedProperties().setLod1MultiSurface(new MultiSurfaceProperty(ms)); ParserConfiguration config = new ParserConfiguration(8, false); - Citygml3FeatureMapper mapper = new Citygml3FeatureMapper(config, folder.newFile().toPath()); + Citygml3FeatureMapper mapper = new Citygml3FeatureMapper(config, folder.newFile().toPath(), false); mapper.visit(body); CityDoctorModel model = mapper.getModel(); - assertEquals(1, model.getWater().size()); - WaterObject waterObject = model.getWater().get(0); + assertEquals(1, model.getWater().toList().size()); + WaterObject waterObject = model.getWater().toList().get(0); Geometry geometry = waterObject.getGeometries().get(0); assertEquals(2, geometry.getVertices().size()); Vertex vertex = geometry.getVertices().get(0); @@ -199,12 +199,12 @@ public class FeatureMapperTest { body.getDeprecatedProperties().setLod1MultiSurface(new MultiSurfaceProperty(ms)); ParserConfiguration config = new ParserConfiguration(8, false); - Citygml3FeatureMapper mapper = new Citygml3FeatureMapper(config, folder.newFile().toPath()); + Citygml3FeatureMapper mapper = new Citygml3FeatureMapper(config, folder.newFile().toPath(), false); mapper.visit(body); CityDoctorModel model = mapper.getModel(); - assertEquals(1, model.getWater().size()); - WaterObject waterObject = model.getWater().get(0); + assertEquals(1, model.getWater().toList().size()); + WaterObject waterObject = model.getWater().toList().get(0); Geometry geometry = waterObject.getGeometries().get(0); assertEquals(7, geometry.getVertices().size()); assertEquals(8, geometry.getEdges().size()); diff --git a/CityDoctorParent/CityDoctorModel/src/test/java/de/hft/stuttgart/citydoctor2/parser/CityGml3ParserTest.java b/CityDoctorParent/CityDoctorModel/src/test/java/de/hft/stuttgart/citydoctor2/parser/CityGml3ParserTest.java index cbc926f156477550c15a2256c742e161ada87269..88b958f4f01ef0083bb0bb8ed262e8ca71b3e0bb 100644 --- a/CityDoctorParent/CityDoctorModel/src/test/java/de/hft/stuttgart/citydoctor2/parser/CityGml3ParserTest.java +++ b/CityDoctorParent/CityDoctorModel/src/test/java/de/hft/stuttgart/citydoctor2/parser/CityGml3ParserTest.java @@ -49,7 +49,7 @@ public class CityGml3ParserTest { ParserConfiguration config = new ParserConfiguration(8, false); CityDoctorModel model = CityGmlParser.parseCityGmlFile("src/test/resources/SimpleSolid_SrefBS.gml", config); assertNotNull(model); - List buildings = model.getBuildings(); + List buildings = model.getBuildings().toList(); assertEquals(1, buildings.size()); Building building = buildings.get(0); assertEquals("_Simple_BD.1", building.getGmlId().getGmlString()); diff --git a/CityDoctorParent/CityDoctorModel/src/test/java/de/hft/stuttgart/citydoctor2/zip/ZipTest.java b/CityDoctorParent/CityDoctorModel/src/test/java/de/hft/stuttgart/citydoctor2/zip/ZipTest.java deleted file mode 100644 index cb9b8e2b612c3f80c136da4df1962f487ba14d8c..0000000000000000000000000000000000000000 --- a/CityDoctorParent/CityDoctorModel/src/test/java/de/hft/stuttgart/citydoctor2/zip/ZipTest.java +++ /dev/null @@ -1,106 +0,0 @@ -package de.hft.stuttgart.citydoctor2.zip; - -import de.hft.stuttgart.citydoctor2.datastructure.CityDoctorModel; -import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration; -import org.apache.commons.io.FileUtils; -import org.junit.Test; - -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; - -public class ZipTest { - - ParserConfiguration config = new ParserConfiguration(8, false); - - - @Test - public void testUnzipping() throws MalformedZipFileException { - CityGmlZipArchive cgmlArch = CityGmlZipArchive.register("src/test/resources/zip/mock_archive.zip"); - assertNotNull(cgmlArch); - cgmlArch.mountArchive(config); - - checkMockArchive(cgmlArch); - } - - private void checkMockArchive(CityGmlZipArchive cgmlArch) { - assertEquals(5, cgmlArch.getEntries().size()); - for (CityGmlZipEntry entry : cgmlArch.getEntries()) { - assertNotNull(entry); - assertTrue(entry.getEntrySubPath().matches("^mock[1-5].gml$")); - assertNull(entry.getErrorType()); - assertNotNull(entry.getModel()); - assertEquals(1, entry.getModel().getNumberOfFeatures()); - } - } - - @Test - public void testZipping() throws IOException { - CityGmlZipArchive cgmlArch = CityGmlZipArchive.register("src/test/resources/zip/mock_archive.zip"); - assertNotNull(cgmlArch); - cgmlArch.mountArchive(config); - - Path tmpDir = null; - try { - tmpDir = Files.createTempDirectory("testTmp"); - tmpDir.toFile().deleteOnExit(); - String expPath = tmpDir + "/export.zip"; - - cgmlArch.exportToZipFile(expPath); - CityGmlZipArchive cgmlExport = CityGmlZipArchive.register(expPath); - assertNotNull(cgmlExport); - cgmlExport.mountArchive(config); - - checkMockArchive(cgmlExport); - } finally { - if (tmpDir != null) { - FileUtils.deleteDirectory(tmpDir.toFile()); - } - } - } - - @Test - public void testEpsgParsing() throws MalformedZipFileException { - CityGmlZipArchive cgmlArch = CityGmlZipArchive.register("src/test/resources/zip/epsg.zip"); - assertNotNull(cgmlArch); - cgmlArch.mountArchive(config); - - CityGmlZipEntry entry = cgmlArch.getEntry("epsg1.gml"); - assertNotNull(entry); - String srsName = entry.getModel().getCityModel().getBoundedBy().getEnvelope().getSrsName().split(":")[6]; - assertEquals("25832", srsName); - - entry = cgmlArch.getEntry("epsg2.gml"); - assertNotNull(entry); - srsName = entry.getModel().getCityModel().getBoundedBy().getEnvelope().getSrsName().split(":")[6]; - assertEquals("7415", srsName); - } - - @Test - public void testXMLValidation() throws MalformedZipFileException { - ParserConfiguration valConfig = new ParserConfiguration(8, true); - CityGmlZipArchive cgmlArch = CityGmlZipArchive.register("src/test/resources/zip/validate.zip"); - assertNotNull(cgmlArch); - cgmlArch.mountArchive(valConfig); - - assertNull(cgmlArch.getEntry("valCorrect.gml").getErrorType()); - assertEquals(ZipEntryErrorType.INVALID_CITY_GML_FILE, cgmlArch.getEntry("valFaulty.gml").getErrorType()); - } - - - @Test - public void testImplicitParsing() throws MalformedZipFileException { - CityGmlZipArchive cgmlArch = CityGmlZipArchive.register("src/test/resources/zip/implicit.zip"); - assertNotNull(cgmlArch); - cgmlArch.mountArchive(config); - - CityDoctorModel mainModel = cgmlArch.getEntry("Main_model.gml").getModel(); - assertEquals(18, mainModel.getGenericCityObjects().size()); - } - -} diff --git a/CityDoctorParent/CityDoctorModel/src/test/resources/04-FZK-Haus-LoD2-Tex-Storey-CG30-V01-InteriorSurface.gml b/CityDoctorParent/CityDoctorModel/src/test/resources/04-FZK-Haus-LoD2-Tex-Storey-CG30-V01-InteriorSurface.gml new file mode 100644 index 0000000000000000000000000000000000000000..da8303f785cdf9dbd703cde6d8717e64c3fafa2b --- /dev/null +++ b/CityDoctorParent/CityDoctorModel/src/test/resources/04-FZK-Haus-LoD2-Tex-Storey-CG30-V01-InteriorSurface.gml @@ -0,0 +1,1655 @@ + + + + + + + + + FZK-Haus + + + 458900.0 5438785.0 113.5 + 458912.0 5438795.0 120.017691 + + + + + KIT Test Building FZK-Haus adapted for CityGML 3.0 + KIT Test Building FZK-Haus for CityGML 3.0 + + + @cityeditor:layer + LoD2-Ausgeblendet + + + + + + + + + + + + + + + + + + + + + + projected + + + highestRoofEdge + lowestGroundPoint + measured + 6.52 + + + + + 2 + + + + + Ground Floor + + + Ground + + + + + + + 458912.0 5438785.0 + 113.5 458900.0 5438785.0 113.5 458900.0 5438795.0 + 113.5 458912.0 5438795.0 113.5 458912.0 5438785.0 + 113.5 + + + + + + + + + + + Ground Floor / Wall East + + + + + + + 458912.0 5438795.0 + 113.5 458912.0 5438795.0 116.4 458912.0 5438785.0 + 116.4 458912.0 5438785.0 113.5 458912.0 5438795.0 + 113.5 + + + + + + + + + + + Ground Floor / Wall South + + + + + + + 458912.0 5438785.0 + 113.5 458912.0 5438785.0 116.4 458900.0 5438785.0 + 116.4 458900.0 5438785.0 113.5 458912.0 5438785.0 + 113.5 + + + + + + + + + + + Ground Floor / Wall West + + + + + + + 458900.0 5438785.0 + 113.5 458900.0 5438785.0 116.4 458900.0 5438795.0 + 116.4 458900.0 5438795.0 113.5 458900.0 5438785.0 + 113.5 + + + + + + + + + + + Ground Floor / Wall North + + + + + + + 458900.0 5438795.0 + 113.5 458900.0 5438795.0 116.4 458912.0 5438795.0 + 116.4 458912.0 5438795.0 113.5 458900.0 5438795.0 + 113.5 + + + + + + + + + + + 02 Ground Floor - Kitchen + + + Ground Floor / Kitchen / Closure Surface North + + + + + + + 458904.695 + 5438789.01 116.2 458903.8 5438789.01 116.2 + 458903.8 5438789.01 113.7 458904.695 5438789.01 + 113.7 458904.695 5438789.01 116.2 + + + + + + + + + + + Ground Floor / Kitchen / Closure Surface East + + + + + + + 458904.695 + 5438789.01 116.2 458904.695 5438789.01 113.7 + 458904.695 5438785.3 113.7 458904.695 5438785.3 + 116.2 458904.695 5438789.01 116.2 + + + + + + + + + + + Ground Floor / Kitchen / Ceiling + + + + + + + 458900.3 5438785.3 + 116.2 458900.3 5438789.01 116.2 458903.8 + 5438789.01 116.2 458904.695 5438789.01 116.2 + 458904.695 5438785.3 116.2 458900.3 5438785.3 + 116.2 + + + + + + + + + + + Ground Floor / Kitchen / Interior Wall West + + + + + + + 458900.3 5438785.3 + 116.2 458900.3 5438785.3 113.7 458900.3 5438789.01 + 113.7 458900.3 5438789.01 116.2 458900.3 5438785.3 + 116.2 + + + + + + + + + + + Ground Floor / Kitchen / Interior Wall South + + + + + + + 458904.695 5438785.3 + 116.2 458904.695 5438785.3 113.7 458900.3 + 5438785.3 113.7 458900.3 5438785.3 116.2 + 458904.695 5438785.3 116.2 + + + + + + + + + + + Ground Floor / Kitchen / Interior Wall North + + + + + + + 458900.3 5438789.01 + 113.7 458903.8 5438789.01 113.7 458903.8 + 5438789.01 116.2 458900.3 5438789.01 116.2 + 458900.3 5438789.01 113.7 + + + + + + + + + + + Ground Floor / Kitchen / Floor + + + + + + + 458903.8 5438789.01 + 113.7 458900.3 5438789.01 113.7 458900.3 5438785.3 + 113.7 458904.695 5438785.3 113.7 458904.695 + 5438789.01 113.7 458903.8 5438789.01 + 113.7 + + + + + + + + + + + + + 03 Ground Floor - Corridor + + + Ground Floor / Corridor / Closure Surface South + + + + + + + 458907.41 5438789.01 + 113.7 458904.695 5438789.01 113.7 458904.695 + 5438789.01 116.2 458907.41 5438789.01 116.2 + 458907.41 5438789.01 113.7 + + + + + + + + + + + Ground Floor / Corridor / Closure Surface South + + + + + + + 458903.8 5438789.01 + 116.2 458904.695 5438789.01 116.2 458904.695 + 5438789.01 113.7 458903.8 5438789.01 113.7 + 458903.8 5438789.01 116.2 + + + + + + + + + + + Ground Floor / Corridor / Ceiling + + + + + + + 458903.8 5438789.25 + 116.2 458900.3 5438789.25 116.2 458900.3 + 5438790.75 116.2 458907.41 5438790.75 116.2 + 458907.41 5438789.01 116.2 458904.695 5438789.01 + 116.2 458903.8 5438789.01 116.2 458903.8 + 5438789.25 116.2 + + + + + + + + + + + Ground Floor / Corridor / Wall East + + + + + + + 458907.41 5438790.75 + 116.2 458907.41 5438790.75 113.7 458907.41 + 5438789.01 113.7 458907.41 5438789.01 116.2 + 458907.41 5438790.75 116.2 + + + + + + + + + + + Ground Floor / Corridor / Wall North + + + + + + + 458900.3 5438790.75 + 113.7 458907.41 5438790.75 113.7 458907.41 + 5438790.75 116.2 458900.3 5438790.75 116.2 + 458900.3 5438790.75 113.7 + + + + + + + + + + + Ground Floor / Corridor / Wall West I + + + + + + + 458900.3 5438789.25 + 113.7 458900.3 5438790.75 113.7 458900.3 + 5438790.75 116.2 458900.3 5438789.25 116.2 + 458900.3 5438789.25 113.7 + + + + + + + + + + + Ground Floor / Corridor / Wall South + + + + + + + 458903.8 5438789.25 + 113.7 458900.3 5438789.25 113.7 458900.3 + 5438789.25 116.2 458903.8 5438789.25 116.2 + 458903.8 5438789.25 113.7 + + + + + + + + + + + Ground Floor / Corridor / Wall West II + + + + + + + 458903.8 5438789.01 + 113.7 458903.8 5438789.25 113.7 458903.8 + 5438789.25 116.2 458903.8 5438789.01 116.2 + 458903.8 5438789.01 113.7 + + + + + + + + + + + Ground Floor / Corridor / Floor + + + + + + + 458903.8 5438789.01 + 113.7 458904.695 5438789.01 113.7 458907.41 + 5438789.01 113.7 458907.41 5438790.75 113.7 + 458900.3 5438790.75 113.7 458900.3 5438789.25 + 113.7 458903.8 5438789.25 113.7 458903.8 + 5438789.01 113.7 + + + + + + + + + + + + + 04 Ground Floor - Living Room + + + Ground Floor / Living Room / Closure Surface West + + + + + + + 458904.695 5438785.3 + 116.2 458904.695 5438785.3 113.7 458904.695 + 5438789.01 113.7 458904.695 5438789.01 116.2 + 458904.695 5438785.3 116.2 + + + + + + + + + + + Ground Floor / Living Room / Closure Surface North + + + + + + + 458904.695 + 5438789.01 113.7 458907.41 5438789.01 113.7 + 458907.41 5438789.01 116.2 458904.695 5438789.01 + 116.2 458904.695 5438789.01 113.7 + + + + + + + + + + + Ground Floor / Living Room / Ceiling + + + + + + + 458904.695 + 5438789.01 116.2 458907.41 5438789.01 116.2 + 458911.7 5438789.01 116.2 458911.7 5438785.3 116.2 + 458904.695 5438785.3 116.2 458904.695 5438789.01 + 116.2 + + + + + + + + + + + Ground Floor / Living Room / Interior Wall North + + + + + + + 458911.7 5438789.01 + 116.2 458907.41 5438789.01 116.2 458907.41 + 5438789.01 113.7 458911.7 5438789.01 113.7 + 458911.7 5438789.01 116.2 + + + + + + + + + + + Ground Floor / Living Room / Interior Wall South + + + + + + + 458911.7 5438785.3 + 116.2 458911.7 5438785.3 113.7 458904.695 + 5438785.3 113.7 458904.695 5438785.3 116.2 + 458911.7 5438785.3 116.2 + + + + + + + + + + + Ground Floor / Living Room / Interior Wall East + + + + + + + 458911.7 5438789.01 + 116.2 458911.7 5438789.01 113.7 458911.7 5438785.3 + 113.7 458911.7 5438785.3 116.2 458911.7 5438789.01 + 116.2 + + + + + + + + + + + Ground Floor / Living Room / Floor + + + + + + + 458904.695 5438785.3 + 113.7 458911.7 5438785.3 113.7 458911.7 5438789.01 + 113.7 458907.41 5438789.01 113.7 458904.695 + 5438789.01 113.7 458904.695 5438785.3 + 113.7 + + + + + + + + + + + + + 05 Ground Floor - Bedroom + + + Ground Floor / Bedroom / Ceiling + + + + + + + 458911.7 5438789.25 + 116.2 458907.65 5438789.25 116.2 458907.65 + 5438794.7 116.2 458911.7 5438794.7 116.2 458911.7 + 5438789.25 116.2 + + + + + + + + + + + Ground Floor / Bedroom / Interior Wall West + + + + + + + 458907.65 5438789.25 + 116.2 458907.65 5438789.25 113.7 458907.65 + 5438794.7 113.7 458907.65 5438794.7 116.2 + 458907.65 5438789.25 116.2 + + + + + + + + + + + Ground Floor / Bedroom / Interior Wall South + + + + + + + 458911.7 5438789.25 + 116.2 458911.7 5438789.25 113.7 458907.65 + 5438789.25 113.7 458907.65 5438789.25 116.2 + 458911.7 5438789.25 116.2 + + + + + + + + + + + Ground Floor / Bedroom / Interior Wall North + + + + + + + 458907.65 5438794.7 + 116.2 458907.65 5438794.7 113.7 458911.7 5438794.7 + 113.7 458911.7 5438794.7 116.2 458907.65 5438794.7 + 116.2 + + + + + + + + + + + Ground Floor / Bedroom / Interior Wall East + + + + + + + 458911.7 5438794.7 + 116.2 458911.7 5438794.7 113.7 458911.7 5438789.25 + 113.7 458911.7 5438789.25 116.2 458911.7 5438794.7 + 116.2 + + + + + + + + + + + Ground Floor / Bedroom / Floor + + + + + + + 458911.7 5438789.25 + 113.7 458911.7 5438794.7 113.7 458907.65 5438794.7 + 113.7 458907.65 5438789.25 113.7 458911.7 + 5438789.25 113.7 + + + + + + + + + + + + + 06 Ground Floor - Bathroom + + + Ground Floor / Bathroom / Ceiling + + + + + + + 458907.41 5438790.99 + 116.2 458904.04 5438790.99 116.2 458904.04 + 5438794.7 116.2 458907.41 5438794.7 116.2 + 458907.41 5438790.99 116.2 + + + + + + + + + + + Ground Floor / Bathroom / Interior Wall West + + + + + + + 458904.04 5438790.99 + 116.2 458904.04 5438790.99 113.7 458904.04 + 5438794.7 113.7 458904.04 5438794.7 116.2 + 458904.04 5438790.99 116.2 + + + + + + + + + + + Ground Floor / Bathroom / Interior Wall South + + + + + + + 458907.41 5438790.99 + 116.2 458907.41 5438790.99 113.7 458904.04 + 5438790.99 113.7 458904.04 5438790.99 116.2 + 458907.41 5438790.99 116.2 + + + + + + + + + + + Ground Floor / Bathroom / Interior Wall North + + + + + + + 458904.04 5438794.7 + 116.2 458904.04 5438794.7 113.7 458907.41 + 5438794.7 113.7 458907.41 5438794.7 116.2 + 458904.04 5438794.7 116.2 + + + + + + + + + + + Ground Floor / Bathroom / Interior Wall East + + + + + + + 458907.41 5438794.7 + 116.2 458907.41 5438794.7 113.7 458907.41 + 5438790.99 113.7 458907.41 5438790.99 116.2 + 458907.41 5438794.7 116.2 + + + + + + + + + + + Ground Floor / Bathroom / Floor + + + + + + + 458907.41 5438790.99 + 113.7 458907.41 5438794.7 113.7 458904.04 + 5438794.7 113.7 458904.04 5438790.99 113.7 + 458907.41 5438790.99 113.7 + + + + + + + + + + + + + 07 Ground Floor - Office + + + Ground Floor / Office / Ceiling + + + + + + + 458903.8 5438790.99 + 116.2 458900.3 5438790.99 116.2 458900.3 5438794.7 + 116.2 458903.8 5438794.7 116.2 458903.8 5438790.99 + 116.2 + + + + + + + + + + + Ground Floor / Office / Interior Wall West + + + + + + + 458900.3 5438790.99 + 116.2 458900.3 5438790.99 113.7 458900.3 5438794.7 + 113.7 458900.3 5438794.7 116.2 458900.3 5438790.99 + 116.2 + + + + + + + + + + + Ground Floor / Office / Interior Wall South + + + + + + + 458903.8 5438790.99 + 116.2 458903.8 5438790.99 113.7 458900.3 + 5438790.99 113.7 458900.3 5438790.99 116.2 + 458903.8 5438790.99 116.2 + + + + + + + + + + + Ground Floor / Office / Interior Wall North + + + + + + + 458900.3 5438794.7 + 116.2 458900.3 5438794.7 113.7 458903.8 5438794.7 + 113.7 458903.8 5438794.7 116.2 458900.3 5438794.7 + 116.2 + + + + + + + + + + + Ground Floor / Office / Interior Wall East + + + + + + + 458903.8 5438794.7 + 116.2 458903.8 5438794.7 113.7 458903.8 5438790.99 + 113.7 458903.8 5438790.99 116.2 458903.8 5438794.7 + 116.2 + + + + + + + + + + + Ground Floor / Office / Floor + + + + + + + 458903.8 5438790.99 + 113.7 458903.8 5438794.7 113.7 458900.3 5438794.7 + 113.7 458900.3 5438790.99 113.7 458903.8 + 5438790.99 113.7 + + + + + + + + + + + + + + + Second Floor + + + Second Floor / Roof South + + + + + + + 458912.0 5438790.0 + 120.017691 458900.0 5438790.0 120.017691 458900.0 + 5438785.0 117.13094 458912.0 5438785.0 117.13094 + 458912.0 5438790.0 120.017691 + + + + + + + + + + + Second Floor / Roof North + + + + + + + 458900.0 5438790.0 + 120.017691 458912.0 5438790.0 120.017691 458912.0 + 5438795.0 117.13094 458900.0 5438795.0 117.13094 + 458900.0 5438790.0 120.017691 + + + + + + + + + + + Second Floor / Wall South + + + + + + + 458900.0 5438785.0 + 117.13094 458900.0 5438785.0 116.4 458912.0 + 5438785.0 116.4 458912.0 5438785.0 117.13094 + 458900.0 5438785.0 117.13094 + + + + + + + + + + + Second Floor / Wall West + + + + + + + 458900.0 5438795.0 + 117.13094 458900.0 5438795.0 116.4 458900.0 + 5438785.0 116.4 458900.0 5438785.0 117.13094 + 458900.0 5438790.0 120.017691 458900.0 5438795.0 + 117.13094 + + + + + + + + + + + Second Floor / Wall East + + + + + + + 458912.0 5438785.0 + 117.13094 458912.0 5438785.0 116.4 458912.0 + 5438795.0 116.4 458912.0 5438795.0 117.13094 + 458912.0 5438790.0 120.017691 458912.0 5438785.0 + 117.13094 + + + + + + + + + + + Second Floor / Wall North + + + + + + + 458912.0 5438795.0 + 117.13094 458912.0 5438795.0 116.4 458900.0 + 5438795.0 116.4 458900.0 5438795.0 117.13094 + 458912.0 5438795.0 117.13094 + + + + + + + + + + + 01 Second Floor - Galery + + + Second Floor / Galery / Ceiling North + + + + + + + 458900.3 5438794.7 + 117.073205 458911.7 5438794.7 117.073205 458911.7 + 5438790.0 119.786751 458900.3 5438790.0 119.786751 + 458900.3 5438794.7 117.073205 + + + + + + + + + + + Second Floor / Galery / Ceiling South + + + + + + + 458900.3 5438785.3 + 117.073205 458900.3 5438790.0 119.786751 458911.7 + 5438790.0 119.786751 458911.7 5438785.3 117.073205 + 458900.3 5438785.3 117.073205 + + + + + + + + + + + Second Floor / Galery / Interior Wall North + + + + + + + 458911.7 5438794.7 + 116.4 458911.7 5438794.7 117.073205 458900.3 + 5438794.7 117.073205 458900.3 5438794.7 116.4 + 458911.7 5438794.7 116.4 + + + + + + + + + + + Second Floor / Galery / Interior Wall East + + + + + + + 458911.7 5438794.7 + 117.073205 458911.7 5438794.7 116.4 458911.7 + 5438785.3 116.4 458911.7 5438785.3 117.073205 + 458911.7 5438790.0 119.786751 458911.7 5438794.7 + 117.073205 + + + + + + + + + + + Second Floor / Galery / Interior Wall West + + + + + + + 458900.3 5438790.0 + 119.786751 458900.3 5438785.3 117.073205 458900.3 + 5438785.3 116.4 458900.3 5438794.7 116.4 458900.3 + 5438794.7 117.073205 458900.3 5438790.0 + 119.786751 + + + + + + + + + + + Second Floor / Galery / Interior Wall South + + + + + + + 458900.3 5438785.3 + 116.4 458900.3 5438785.3 117.073205 458911.7 + 5438785.3 117.073205 458911.7 5438785.3 116.4 + 458900.3 5438785.3 116.4 + + + + + + + + + + + Second Floor / Galery / Floor + + + + + + + 458911.7 5438785.3 + 116.4 458911.7 5438794.7 116.4 458900.3 5438794.7 + 116.4 458900.3 5438785.3 116.4 458911.7 5438785.3 + 116.4 + + + + + + + + + + + + + + + + + + + textures/FZK-Haus-Front.png + wrap + + + #KIT-Test-Building-01_PG.nfWbzHM5j2MqtisYAjgV + + + -6.01592849610218e-17 1.000011046207786 + -3.0079642480510886e-17 0.7987000468203478 + 1.0000000000000002 0.7987000468203478 1.0000000000000002 + 1.000011046207786 -6.01592849610218e-17 + 1.000011046207786 + #KIT-Test-Building-01_LR.l5vPQsQlvAxe0PfGrItK + + + + + + + #KIT-Test-Building-01_PG.8Oi6zRMGuUdvjDA3942O + + + 1.0000000000000002 + -4.454490602082857e-31 1.0000000000000002 0.7987000468203478 + -3.007964248051091e-17 0.7987000468203478 0.0 + -5.359579389737923e-47 1.0000000000000002 + -4.454490602082857e-31 + #KIT-Test-Building-01_LR.dQRaAbGZocTDsiXUS3Wo + + + + + + + + + textures/FZK-Haus-Right.png + wrap + + + #KIT-Test-Building-01_PG.ioJ6HX4PnhWvLSYhPA7h + + + 7.560328766851198e-17 + 0.5570891737385654 5.087501393878691e-16 0.444942234223729 + 1.0000000000000004 0.44494223422372897 1.0000000000000004 + 0.5570891737385655 0.49999999999999994 0.9999986887435715 + 7.560328766851198e-17 0.5570891737385654 + #KIT-Test-Building-01_LR.VpCnRrYqLGD4bFFZLmWC + + + + + + + #KIT-Test-Building-01_PG.WH3ZPoThoidUosBGLd28 + + + 1.0000000000000004 + -2.907494171674344e-16 1.0000000000000004 + 0.44494223422372897 5.087501393878691e-16 0.444942234223729 + 7.560328766851198e-17 -2.907494171674344e-16 + 1.0000000000000004 + -2.907494171674344e-16 + #KIT-Test-Building-01_LR.kb6UBRDjXdQhuZgyrrXF + + + + + + + + + textures/FZK-Haus-Left.png + wrap + + + #KIT-Test-Building-01_PG.VdnPNlkOAJHnTVZL5R37 + + + -1.0 0.5570891737385658 + -0.9999999999999996 0.44494223422372936 + 4.331468517193571e-16 0.44494223422372936 + 4.331468517193571e-16 0.5570891737385657 + -0.49999999999999944 0.9999986887435719 -1.0 + 0.5570891737385658 + #KIT-Test-Building-01_LR.CWPcEAowucw9pxGFPH3S + + + + + + + #KIT-Test-Building-01_PG.87LG6xx5gYYjprCeHCDY + + + 4.331468517193571e-16 + -1.1157709843049066e-47 4.331468517193571e-16 + 0.44494223422372936 -0.9999999999999996 0.44494223422372936 + -1.0 -8.368282382286802e-48 4.331468517193571e-16 + -1.1157709843049066e-47 + #KIT-Test-Building-01_LR.z42J72DCA0DG7fsjO1iJ + + + + + + + + + textures/Roofing_Shingles_GAF_Estates.jpg + wrap + + + #KIT-Test-Building-01_PG.as933cYedpVOQ8Wqm9j7 + + + 21.47458840372227 18.00558453022584 + 1.8506199769767277e-15 18.00558453022584 + -1.2918958832001822e-15 4.124469685250767 21.47458840372227 + 4.124469685250767 21.47458840372227 18.00558453022584 + #KIT-Test-Building-01_LR.FJ2G4jJFUVmWcdGG3gyw + + + + + + + #KIT-Test-Building-01_PG.CUXCVrNXAnCgCUjdXnY1 + + + -2.0055287249601352e-15 + -2.816087737236785 -21.47458840372227 -2.816087737236785 + -21.47458840372227 -16.697202582211872 + 1.8024740244805496e-15 -16.697202582211872 + -2.0055287249601352e-15 -2.816087737236785 + #KIT-Test-Building-01_LR.cYvvi9l6K4nl9jeHjt03 + + + + + + + + + textures/FZK-Haus-Back.png + wrap + + + #KIT-Test-Building-01_PG.cdHLpEJXgkf3Hq9x6PF7 + + + -1.0000000000000002 1.000011046207795 + -1.0000000000000002 0.7987000468203566 + 2.7071678232459823e-16 0.7987000468203567 + 3.007964248051091e-16 1.000011046207795 -1.0000000000000002 + 1.000011046207795 + #KIT-Test-Building-01_LR.ODQPptDGkQ9xxB6LArAA + + + + + + + #KIT-Test-Building-01_PG.Y4DuK1eWWjbSOQxjL75Z + + + 3.0079642480510913e-16 + -1.4416909618544142e-15 2.707167823245983e-16 + 0.7987000468203463 -1.0000000000000002 0.7987000468203463 + -1.0000000000000002 -1.4416909618544138e-15 + 3.0079642480510913e-16 -1.4416909618544142e-15 + #KIT-Test-Building-01_LR.CvfxHmYhr7DvEJeZnfKH + + + + + + + + + 0.2 + 0.4666666666666667 0.34509803921568627 + 0.21176470588235294 + 0.0 0.0 0.0 + 1.0 1.0 1.0 + 0.2 + 0.0 + false + #KIT-Test-Building-01_PG.B9OH2yr4U3AkPsKWbFy2 + + + + + diff --git a/CityDoctorParent/CityDoctorValidation/pom.xml b/CityDoctorParent/CityDoctorValidation/pom.xml index 48329e28a6d195e3d605b2a8052b3adceae93f8a..6cd0386295bb343dc7714a176c38058d7581c16f 100644 --- a/CityDoctorParent/CityDoctorValidation/pom.xml +++ b/CityDoctorParent/CityDoctorValidation/pom.xml @@ -4,7 +4,7 @@ de.hft.stuttgart CityDoctorParent - 3.17.3 + 3.18.0 CityDoctorValidation CityDoctorValidation diff --git a/CityDoctorParent/CityDoctorValidation/src/main/java/de/hft/stuttgart/citydoctor2/CityDoctorValidation.java b/CityDoctorParent/CityDoctorValidation/src/main/java/de/hft/stuttgart/citydoctor2/CityDoctorValidation.java index 5b73190bff2699949f020a921782e01e5d369988..ec2d0df09e0c2e858d747670c34b9df74f5b79d7 100644 --- a/CityDoctorParent/CityDoctorValidation/src/main/java/de/hft/stuttgart/citydoctor2/CityDoctorValidation.java +++ b/CityDoctorParent/CityDoctorValidation/src/main/java/de/hft/stuttgart/citydoctor2/CityDoctorValidation.java @@ -21,13 +21,11 @@ package de.hft.stuttgart.citydoctor2; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; -import java.nio.file.Path; import java.util.List; -import de.hft.stuttgart.citydoctor2.zip.CityGmlZipArchive; +import de.hft.stuttgart.citydoctor2.utils.Localization; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import org.citygml4j.core.ade.ADEException; import de.hft.stuttgart.citydoctor2.check.Checker; import de.hft.stuttgart.citydoctor2.check.ValidationConfiguration; @@ -83,12 +81,12 @@ public class CityDoctorValidation { if (optional) { return null; } - logger.error("No output file specified. (-out [FILE])"); + logger.error(Localization.getText("CityDoctorValidation.noOutputFile")); System.exit(11); } List outFiles = argParser.getValues("out"); if (outFiles.size() != 1) { - logger.error("Specify exactly one file as output."); + logger.error(Localization.getText("CityDoctorValidation.notExactlyOneOutputFile")); System.exit(12); } outputFile = outFiles.get(0); @@ -157,15 +155,13 @@ public class CityDoctorValidation { ValidationConfiguration config, String outputFile) throws CityDoctorWriteException, CityGmlParseException, IOException, InvalidGmlFileException { File inputFile = new File(input); if (!inputFile.exists()) { - logger.error("Input file '{}' does not exist.", input); + logger.error(Localization.getText("CityDoctorValidation.inputFileNotExisting"), input); System.exit(1); } if (inputFile.getName().endsWith(".gml") || inputFile.getName().endsWith(".xml")) { startFileValidation(inputFile, xmlOutput, pdfOutput, config, outputFile); - } else if (inputFile.getName().endsWith(".zip")) { - startZipValidation(input, xmlOutput, pdfOutput, config, outputFile); } else { - logger.error("Input file '{}' does not end with .gml or .xml and is not a zip archive.", input); + logger.error(Localization.getText("CityDoctorValidation.wrongInputFileFormat"), input); System.exit(1); } } @@ -179,10 +175,11 @@ public class CityDoctorValidation { * @param pdfOutput the output path for the pdf report (optional) * @param config the configuration path for the validation plan * @param outputFile storing the validated gml file with quality ade - * @throws CityDoctorWriteException if something goes wrong while writing the gml - * file - * @throws CityGMLBuilderException - * @throws ADEException + * + * @throws IOException When an exception while writing the report files happens. + * @throws CityGmlParseException When an error while parsing the cityGML file happens. + * @throws InvalidGmlFileException If the cityGML file is not valid according to the cityGML schema. + * @throws CityDoctorWriteException If something goes wrong while writing the output gml file */ public static void startFileValidation(File inputFile, String xmlOutput, String pdfOutput, ValidationConfiguration config, String outputFile) throws IOException, CityGmlParseException, @@ -201,34 +198,11 @@ public class CityDoctorValidation { } } - public static void startZipValidation(String inputZipFile, String xmlOutput, String pdfOutput, - ValidationConfiguration config, String outputFile) throws CityGmlParseException, IOException { - xmlOutput = toDirectoryPath(xmlOutput); - pdfOutput = toDirectoryPath(pdfOutput); - outputFile = toDirectoryPath(outputFile); - if (xmlOutput == null && pdfOutput == null && outputFile == null) { - logger.warn("No output locations specified, results of validation will not be saved"); - } - CityGmlZipArchive archive = CityGmlZipArchive.register(inputZipFile); - Checker.streamCheck(archive, xmlOutput, pdfOutput, config, outputFile); - } - - public static String toDirectoryPath(String input) { - if (input == null) { - return null; - } - String parentDirectory = Path.of(input).getParent().toString() + File.separator; - String name = Path.of(input).getFileName().toString().replaceFirst("\\..+", "") + File.separator; - File f = new File(parentDirectory + name); - f.mkdir(); - return f.getPath() + File.separator; - } - public static String getPdfOutput(ArgumentParser argParser) { if (argParser.containsOption("pdfreport")) { List reportFiles = argParser.getValues("pdfreport"); if (reportFiles.size() != 1) { - logger.error("Specify exactly one file as pdfReport"); + logger.error(Localization.getText("CityDoctorValidation.notExactlyOnePDFOutput")); System.exit(6); } return reportFiles.get(0); @@ -240,7 +214,7 @@ public class CityDoctorValidation { if (argParser.containsOption("xmlreport")) { List reportFiles = argParser.getValues("xmlreport"); if (reportFiles.size() != 1) { - logger.error("Specify exactly one file as xmlReport"); + logger.error(Localization.getText("CityDoctorValidation.notExactlyOneXMLOutput")); System.exit(5); } return reportFiles.get(0); @@ -257,16 +231,16 @@ public class CityDoctorValidation { if (argParser.containsOption("config")) { List configFiles = argParser.getValues("config"); if (configFiles.size() != 1) { - logger.error("Specify exactly one file as configuration"); + logger.error(Localization.getText("CityDoctorValidation.notExactlyOneConfigFile")); System.exit(4); } return ValidationConfiguration.loadValidationConfig(configFiles.get(0)); } else { if (optional) { - logger.warn("No configuration file given, loading default configuration"); + logger.warn(Localization.getText("CityDoctorValidation.loadingDefaultConfig")); return ValidationConfiguration.loadStandardValidationConfig(); } else { - logger.error("No configuration file specified with -config [FILE]"); + logger.error(Localization.getText("CityDoctorValidation.noConfig")); System.exit(7); return null; } @@ -278,7 +252,7 @@ public class CityDoctorValidation { if (argParser.containsOption("out")) { List outFiles = argParser.getValues("out"); if (outFiles.size() != 1) { - logger.error("Specify exactly one file as output."); + logger.error(Localization.getText("CityDoctorValidation.multipleOutputFiles")); System.exit(3); } return outFiles.get(0); @@ -297,12 +271,12 @@ public class CityDoctorValidation { if (optional) { return null; } - logger.error("No input file specified. (-in [FILE])"); + logger.error(Localization.getText("CityDoctorValidation.noInputFile")); System.exit(1); } List inFiles = argParser.getValues("in"); if (inFiles.size() != 1) { - logger.error("Specify exactly one file as input."); + logger.error(Localization.getText("CityDoctorValidation.notExactlyOneInputFile")); System.exit(2); } inputFile = inFiles.get(0); diff --git a/CityDoctorParent/CityDoctorValidation/src/main/java/de/hft/stuttgart/citydoctor2/CityDoctorValidationCLI.java b/CityDoctorParent/CityDoctorValidation/src/main/java/de/hft/stuttgart/citydoctor2/CityDoctorValidationCLI.java index 505c5eb54a7d32e60cee219350bb1795a859868f..9003eb7b97bcfeb67cafb5f0ae002312cfa46af8 100644 --- a/CityDoctorParent/CityDoctorValidation/src/main/java/de/hft/stuttgart/citydoctor2/CityDoctorValidationCLI.java +++ b/CityDoctorParent/CityDoctorValidation/src/main/java/de/hft/stuttgart/citydoctor2/CityDoctorValidationCLI.java @@ -1,12 +1,19 @@ package de.hft.stuttgart.citydoctor2; -import java.util.concurrent.Callable; +import de.hft.stuttgart.citydoctor2.check.ValidationConfiguration; +import de.hft.stuttgart.citydoctor2.exceptions.CityDoctorWriteException; +import de.hft.stuttgart.citydoctor2.parser.CityGmlParseException; +import de.hft.stuttgart.citydoctor2.parser.InvalidGmlFileException; +import picocli.CommandLine; import picocli.CommandLine.Command; import picocli.CommandLine.Option; +import java.io.File; +import java.io.IOException; + @Command(name = "citydoctor2", mixinStandardHelpOptions = true, description = "Validates CityGML files according to a provided validation-plan.") -public class CityDoctorValidationCLI implements Callable { +public class CityDoctorValidationCLI implements Runnable { @Option(names = {"-i" , "--in" , "--input"}, description = "Filepath of the CityGML file.", @@ -15,23 +22,41 @@ public class CityDoctorValidationCLI implements Callable { @Option(names = {"-c" , "--config" , "--configuration", "--plan"}, description = "Filepath of the validation configuration .yml", - required = true) - private String config; + defaultValue = Option.NULL_VALUE) + private File config; @Option(names = {"-x" , "--xml" , "--xmlReport"}, - description = "Create a XML validation report at target location") + description = "Create a XML validation report at target location", + defaultValue = Option.NULL_VALUE) private String xmlReport; @Option(names = {"-p" , "--pdf" , "--pdfReport"}, - description = "Create a PDF validation report at target location") + description = "Create a PDF validation report at target location", + defaultValue = Option.NULL_VALUE) private String pdfReport; @Option(names = {"-o" , "--out" , "--output"}, - description = "Create a validated copy of the CityGML input with QualityADE at target location.") + description = "Create a validated copy of the CityGML input with QualityADE at target location.", + defaultValue = Option.NULL_VALUE) private String output; @Override - public Integer call() throws Exception { - return 0; + public void run(){ + try { + ValidationConfiguration valConfig; + if(config == null){ + valConfig=ValidationConfiguration.loadStandardValidationConfig(); + } else{ + valConfig=ValidationConfiguration.loadValidationConfig(config.getAbsolutePath()); + } + CityDoctorValidation.startValidationProcess(input, xmlReport, pdfReport, valConfig,output); + } catch (CityDoctorWriteException | CityGmlParseException | IOException | InvalidGmlFileException e) { + throw new RuntimeException(e); + } + } + + public static void main(String[] args) { + int exitCode = new CommandLine(new CityDoctorValidationCLI()).execute(args); + System.exit(exitCode); } } diff --git a/CityDoctorParent/CityDoctorValidation/src/main/java/de/hft/stuttgart/citydoctor2/check/Checker.java b/CityDoctorParent/CityDoctorValidation/src/main/java/de/hft/stuttgart/citydoctor2/check/Checker.java index 061e4184ca9c36eb99b6e61d5fe35c81c9b30e56..c863720e40b70668737309eaa2148ce5cc42e9f4 100644 --- a/CityDoctorParent/CityDoctorValidation/src/main/java/de/hft/stuttgart/citydoctor2/check/Checker.java +++ b/CityDoctorParent/CityDoctorValidation/src/main/java/de/hft/stuttgart/citydoctor2/check/Checker.java @@ -28,9 +28,14 @@ import de.hft.stuttgart.citydoctor2.checks.CheckPrototype; import de.hft.stuttgart.citydoctor2.checks.Checks; import de.hft.stuttgart.citydoctor2.checks.SvrlContentHandler; import de.hft.stuttgart.citydoctor2.checks.util.FeatureCheckedListener; +import de.hft.stuttgart.citydoctor2.database.CityObjectCache; +import de.hft.stuttgart.citydoctor2.database.CityObjectCache; import de.hft.stuttgart.citydoctor2.datastructure.CityDoctorModel; import de.hft.stuttgart.citydoctor2.datastructure.CityObject; import de.hft.stuttgart.citydoctor2.datastructure.FeatureType; +import de.hft.stuttgart.citydoctor2.datastructure.GmlId; +import de.hft.stuttgart.citydoctor2.datastructure.ImplicitGeometryHolder; +import de.hft.stuttgart.citydoctor2.datastructure.GmlId; import de.hft.stuttgart.citydoctor2.parser.CityGmlConsumer; import de.hft.stuttgart.citydoctor2.parser.CityGmlParseException; import de.hft.stuttgart.citydoctor2.parser.CityGmlParser; @@ -42,11 +47,8 @@ import de.hft.stuttgart.citydoctor2.reporting.XmlStreamReporter; import de.hft.stuttgart.citydoctor2.reporting.XmlValidationReporter; import de.hft.stuttgart.citydoctor2.reporting.pdf.PdfReporter; import de.hft.stuttgart.citydoctor2.reporting.pdf.PdfStreamReporter; -import de.hft.stuttgart.citydoctor2.utils.ArchivePacker; import de.hft.stuttgart.citydoctor2.utils.Localization; -import de.hft.stuttgart.citydoctor2.zip.CityGmlZipArchive; -import de.hft.stuttgart.citydoctor2.zip.CityGmlZipEntry; -import de.hft.stuttgart.citydoctor2.zip.CityGmlZipEntryFile; +import de.hft.stuttgart.citydoctor2.utils.TimeFormatter; import de.hft.stuttgart.quality.model.enums.RequirementId; import de.hft.stuttgart.quality.model.enums.TopLevelFeatureType; import de.hft.stuttgart.quality.model.properties.CheckingProperty; @@ -57,7 +59,6 @@ import de.hft.stuttgart.quality.model.properties.RequirementProperty; import de.hft.stuttgart.quality.model.types.Checking; import de.hft.stuttgart.quality.model.types.Parameter; import de.hft.stuttgart.quality.model.types.ValidationPlan; -import org.apache.commons.io.FilenameUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -79,6 +80,7 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.UncheckedIOException; +import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; import java.util.Collections; @@ -89,7 +91,8 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; -import java.util.stream.Stream; +import java.util.concurrent.*; +import java.util.concurrent.atomic.AtomicInteger; /** * The main container class for checking. It contains the logic for validation, @@ -191,38 +194,93 @@ public class Checker { if (config == null) { config = ValidationConfiguration.loadStandardValidationConfig(); } - checkCityModel(model, l); - if (logger.isInfoEnabled()) { - logger.info(Localization.getText("Checker.checksFinished")); + AutoCloseable checkingContext = model.getCache().startCheckingMode(); + try(checkingContext){ + Callable schematronThread = () -> executeSchematronValidationIfAvailable(config, model.getFile()); + ExecutorService executor = Executors.newSingleThreadExecutor(); + Future handlerFuture = executor.submit(schematronThread); + executor.shutdown(); + + checkCityModel(model, l); + getSchematronResults(handlerFuture, l); + + model.setValidated(createValidationPlan()); + } catch (Exception e){ + logger.error("Validation failed due to encountering error", e); + } + } + + private void getSchematronResults(Future handlerFuture, ProgressListener l) { + if (!handlerFuture.isDone()) { + if (logger.isInfoEnabled()) { + logger.info(Localization.getText("Checker.schematronStillRunning")); + } + if(l !=null){ + l.updateProgress(-0.5f); + } } - SvrlContentHandler handler = executeSchematronValidationIfAvailable(config, model.getFile()); - if (handler != null) { - handleSchematronResults(handler); + try { + SvrlContentHandler handler = handlerFuture.get(); + if (handler != null) { + handleSchematronResults(handler); + } + } catch (ExecutionException e) { + logger.error(e); + } catch (InterruptedException e) { + logger.error(Localization.getText("Checker.schematronInterrupted"), e); + Thread.currentThread().interrupt(); } - model.setValidated(createValidationPlan()); } private void handleSchematronResults(SvrlContentHandler handler) { - model.addGlobalErrors(handler.getGeneralErrors()); + CityObjectCache cache = model.getCache(); + handleSchematronErrorsGlobal(handler.getGeneralErrors()); Map featureMap = new HashMap<>(); - model.createFeatureStream().forEach(f -> featureMap.put(f.getGmlId().getGmlString(), f)); + boolean onlySchematron = execLayers.isEmpty(); + if (onlySchematron) { + CheckableUtilsVisitor visitor = new CheckableUtilsVisitor() { + @Override + public void check(Checkable checkable) { + checkable.setValidated(true); + } + }; + model.createFeatureStream().forEach(f -> { + featureMap.put(f.getGmlId().getGmlString(), f); + f.accept(visitor); + }); + } else { + model.createFeatureStream().forEach(f -> featureMap.put(f.getGmlId().getGmlString(), f)); + } handler.getFeatureErrors().forEach((k, v) -> { - if (k.trim().isEmpty()) { - // missing gml id, ignore? - return; - } - CityObject co = featureMap.get(k); + String trimmedId = k.trim(); + CityObject co = cache.get(new GmlId(k)); if (co == null) { // gml id reported by schematron was not found, add to general errors - for (SchematronError se : v) { - model.addGlobalError(se); - } + handleSchematronErrorsGlobal(v); } else { handleSchematronErrorsForCityObject(v, co); + co.setValidated(true); } }); } + private void handleSchematronErrorsGlobal(List v) { + for (SchematronError se : v) { + CheckError err; + if (AttributeMissingError.ID.getIdString().equals(se.getErrorIdString())) { + err = new AttributeMissingError(null, se.getChildId(), se.getNameOfAttribute()); + } else if (AttributeValueWrongError.ID.getIdString().equals(se.getErrorIdString())) { + err = new AttributeValueWrongError(null, se.getChildId(), se.getNameOfAttribute()); + } else if (AttributeInvalidError.ID.getIdString().equals(se.getErrorIdString())) { + err = new AttributeInvalidError(null, se.getChildId(), se.getNameOfAttribute()); + } else { + throw new IllegalStateException( + "Unknown error ID was given in schematron file: " + se.getErrorIdString()); + } + model.addGlobalError(err); + } + } + public static void handleSchematronErrorsForCityObject(List v, CityObject co) { int count = 0; for (SchematronError se : v) { @@ -435,13 +493,16 @@ public class Checker { } } - @SuppressWarnings("resource") public static SvrlContentHandler executeSchematronValidationIfAvailable(ValidationConfiguration config, InputStream in) { if (config.getSchematronFilePath() != null && !config.getSchematronFilePath().isEmpty()) { if (logger.isInfoEnabled()) { logger.info(Localization.getText("Checker.schematronValidation")); } + if (!Files.exists(Path.of(config.getSchematronFilePath()))) { + logger.warn(Localization.getText("Checker.schematronFileNotFound"), config.getSchematronFilePath()); + return null; + } try { TransformerFactory transformerFactory = TransformerFactory.newInstance("net.sf.saxon.TransformerFactoryImpl", Checker.class.getClassLoader()); @@ -559,7 +620,7 @@ public class Checker { for (Entry e : config.getRequirements().entrySet()) { de.hft.stuttgart.citydoctor2.check.Requirement req = Checks.getAvailableRequirements().get(e.getKey()); if (req == null) { - logger.warn("Could not find any check that satisfies requirement {}, it will not be checked", + logger.warn(Localization.getText("Checker.noCheckSatisfiesRequirement"), e.getKey()); } else { if (e.getValue().isEnabled()) { @@ -626,31 +687,110 @@ public class Checker { } } - private void checkCityModel(CityDoctorModel model, ProgressListener l) { - Stream features = model.createFeatureStream(); - float featureSum = model.getNumberOfFeatures(); + private void checkCityModel(CityDoctorModel model, ProgressListener l){ + List features = model.getFeatureIds(); + + AtomicInteger checkedCount = new AtomicInteger(0); // clear global errors model.getGlobalErrors().clear(); - - // stupid lamda with final variable restrictions - int[] currentFeature = new int[1]; - features.forEach(co -> { - if (config.getParserConfiguration().useLowMemoryConsumption()) { - // no edges have been created yet, create them - co.prepareForChecking(); + CityObjectCache cache = model.getCache(); + logger.trace("Setting up ThreadPool"); + int threadCount = Runtime.getRuntime().availableProcessors() * 5; + ExecutorService exec = new ThreadPoolExecutor + (threadCount, threadCount, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<>()); + try{ + long startTime = System.nanoTime(); + ImplicitGeometryHolder.preparePrototypeGeometriesForChecking(); + + List> futures = runChecksOnFeatures(exec, cache, features, checkedCount, l); + List missedFeatures = getMissedFeatures(futures); + + ImplicitGeometryHolder.clearMetaDataOfPrototypeGeometries(); + if (!missedFeatures.isEmpty()){ + logger.error(Localization.getText("Checker.dbUnresponsive")); + if (logger.isDebugEnabled()){ + logger.debug(missedFeatures.toString()); + } } - // check every feature - executeChecksForCityObject(co); + long endTime = System.nanoTime(); + if (logger.isInfoEnabled()){ + long totalTime = (endTime - startTime) / 1_000_000; // Convert ns to ms + String messageString = Localization.getText("Checker.checksFinished"); + String timeString = TimeFormatter.format(totalTime); + messageString = messageString.replace("{0}", timeString); + logger.info(messageString); + } + } catch (InterruptedException e){ + // No interrupts implemented, so this block should actually never be entered + logger.error(Localization.getText("Checker.validationInterrupted"), e); + Thread.currentThread().interrupt(); + + } finally { + exec.shutdown(); + try { + if(!exec.awaitTermination(1, TimeUnit.MINUTES)){ + exec.shutdownNow(); + } - if (config.getParserConfiguration().useLowMemoryConsumption()) { - // low memory consumption, remove edges again - co.clearMetaInformation(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + logger.error(Localization.getText("Checker.shutdownInterrupted")); } - if (l != null) { - currentFeature[0]++; - l.updateProgress(currentFeature[0] / featureSum); + } + } + + private List> runChecksOnFeatures(ExecutorService exec, CityObjectCache cache, List ids, AtomicInteger checkedCount, + ProgressListener l) + throws InterruptedException { + float featureSum = ids.size() + (float) checkedCount.get(); + + logger.trace("Queueing up Checker tasks"); + List> tasks = new ArrayList<>(); + for (GmlId id : ids) { + tasks.add(()->{ + CityObject co = cache.get(id); + if (co == null) { + return id; + } + if(Thread.interrupted()){ + Thread.currentThread().interrupt(); + return null; + } + co.prepareForChecking(); + executeChecksForCityObject(co); + co.clearMetaInformation(); + cache.put(co); + checkedCount.incrementAndGet(); + if (l!=null){ + l.updateProgress((checkedCount.get()) / featureSum); + } + return null; + }); + } + logger.trace("Queueing up finished, invoking all tasks"); + return exec.invokeAll(tasks); + } + + private List getMissedFeatures(List> futures) throws InterruptedException{ + List missedList = new ArrayList<>(); + Set errors = new HashSet<>(); + for (Future future : futures) { + try{ + GmlId gmlId = future.get(); + if (gmlId != null) { + missedList.add(gmlId); + } + } catch (ExecutionException e){ + logger.debug("A Task failed due to an unexpected exception", e); + logger.debug(e.getCause()); + errors.add(e); } - }); + } + if (!errors.isEmpty()) { + logger.error(Localization.getText("Checker.futuresCheckFailures")); + logger.error(errors.toString()); + } + return missedList; } private boolean filterObject(CityObject co) { @@ -756,73 +896,6 @@ public class Checker { return hasUnusedDependency; } - public static void streamCheck(CityGmlZipArchive archive, String xmlDirectory, String pdfDirectory, ValidationConfiguration config, - String outputDirectory) throws IOException, CityGmlParseException { - streamCheck(archive, xmlDirectory, pdfDirectory, config, null, outputDirectory); - } - - public static void streamCheck(CityGmlZipArchive archive, String xmlDirectory, String pdfDirectory, ValidationConfiguration config, - FeatureCheckedListener l, String outputDirectory) throws IOException, CityGmlParseException { - - - for (CityGmlZipEntry entry : archive.getEntries()) { - String entryName = FilenameUtils.removeExtension(entry.getDisplayName()); - String xmlOutput = null; - String pdfOutput = null; - String outputFile = null; - if (xmlDirectory != null) { - xmlOutput = Path.of(xmlDirectory).resolve(entryName + "_report.xml").toString(); - } - if (pdfDirectory != null) { - pdfOutput = Path.of(pdfDirectory).resolve(entryName + "_report.pdf").toString(); - } - if (outputDirectory != null) { - outputFile = Path.of(outputDirectory).resolve(entryName + "_validated.gml").toString(); - } - - streamCheck(entry, xmlOutput, pdfOutput, config, l, outputFile); - - - } - if (outputDirectory != null) { - ArchivePacker.packAndDeleteDirectory(outputDirectory); - } - } - - - public static void streamCheck(CityGmlZipEntry entry, String xmlOutput, String pdfOutput, ValidationConfiguration config, - String outputFile) throws IOException, CityGmlParseException { - streamCheck(entry, xmlOutput, pdfOutput, config, null, outputFile); - } - - public static void streamCheck(CityGmlZipEntry entry, String xmlOutput, String pdfOutput, ValidationConfiguration config, - FeatureCheckedListener l, String outputFile) throws IOException, CityGmlParseException { - try (BufferedOutputStream xmlBos = getXmlOutputMaybe(xmlOutput); - BufferedOutputStream pdfBos = getPdfOutputMaybe(pdfOutput)) { - Checker c = new Checker(config, null); - String fileName = entry.getEntrySubPath(); - - // create reporter if available - XmlStreamReporter xmlReporter = getXmlReporter(config, xmlBos, fileName); - PdfStreamReporter pdfReporter = getPdfReporter(config, pdfBos, fileName); - - // execute schematron first - try (CityGmlZipEntryFile entryFile = new CityGmlZipEntryFile(entry)) { - SvrlContentHandler handler = executeSchematronValidationIfAvailable(config, entryFile.getInputStream()); - - CityGmlConsumer con = new StreamCityGmlConsumer(c, xmlReporter, pdfReporter, handler, config, l); - // parse and validate - CityGmlParser.streamCityGml(entry, config.getParserConfiguration(), con, outputFile); - - // write reports if available - writeReport(xmlReporter); - writeReport(pdfReporter); - } - } catch (CheckReportWriteException e) { - logger.error(Localization.getText("Checker.failReports"), e); - } - } - public static void streamCheck(File inputFile, String xmlOutput, String pdfOutput, ValidationConfiguration config, String outputFile) throws IOException, CityGmlParseException { streamCheck(inputFile, xmlOutput, pdfOutput, config, null, outputFile); diff --git a/CityDoctorParent/CityDoctorValidation/src/main/java/de/hft/stuttgart/citydoctor2/check/StreamCityGmlConsumer.java b/CityDoctorParent/CityDoctorValidation/src/main/java/de/hft/stuttgart/citydoctor2/check/StreamCityGmlConsumer.java index c3ff365c3980e47e729bb0d2d940938cd3dcb7f0..1c542e653354490735d652f30f8ecf3f81f39d64 100644 --- a/CityDoctorParent/CityDoctorValidation/src/main/java/de/hft/stuttgart/citydoctor2/check/StreamCityGmlConsumer.java +++ b/CityDoctorParent/CityDoctorValidation/src/main/java/de/hft/stuttgart/citydoctor2/check/StreamCityGmlConsumer.java @@ -134,7 +134,7 @@ public class StreamCityGmlConsumer implements CityGmlConsumer { pdfReporter.report(co); } - // TODO: Update QualityADE to be compatible with CityGML 3.0 or deprecate it, unhandled top-level feature types are just skipped for now + // TODO: Update QualityADE to be compatible with CityGML 3.0, unhandled top-level feature types are just skipped for now if (!(co instanceof AbstractTunnel || co instanceof CityFurniture || co instanceof GenericCityObject)) { // store quality ade datastructures in cityobject QualityADEUtils.writeQualityAde(co, val); diff --git a/CityDoctorParent/CityDoctorValidation/src/main/java/de/hft/stuttgart/citydoctor2/checks/CheckContainer.java b/CityDoctorParent/CityDoctorValidation/src/main/java/de/hft/stuttgart/citydoctor2/checks/CheckContainer.java index 8b6f2943b8f19e88a65a52fe5c41eca1cdf9ea00..7e628940ea3053a8e1dc3ff0d15d9586bde08e4c 100644 --- a/CityDoctorParent/CityDoctorValidation/src/main/java/de/hft/stuttgart/citydoctor2/checks/CheckContainer.java +++ b/CityDoctorParent/CityDoctorValidation/src/main/java/de/hft/stuttgart/citydoctor2/checks/CheckContainer.java @@ -230,6 +230,24 @@ public class CheckContainer extends Check { } } + @Override + public void check(TinObject to) { + try { + check.check(to); + }catch (Exception e) { + handleException(e, to); + } + } + + @Override + public void check(ReliefObject ro) { + try { + check.check(ro); + }catch (Exception e) { + handleException(e, ro); + } + } + @Override public void check(CityFurniture cf){ try { @@ -248,6 +266,15 @@ public class CheckContainer extends Check { } } + @Override + public void check(OtherConstructionObject oco) { + try { + check.check(oco); + }catch (Exception e) { + handleException(e, oco); + } + } + @Override public RequirementType getType() { return check.getType(); diff --git a/CityDoctorParent/CityDoctorValidation/src/main/java/de/hft/stuttgart/citydoctor2/checks/SvrlContentHandler.java b/CityDoctorParent/CityDoctorValidation/src/main/java/de/hft/stuttgart/citydoctor2/checks/SvrlContentHandler.java index 78189eb9d156cec92beec11ffed6d5d9552f967b..07c583dc48ea7dfe27e73738b5c079dd828c272d 100644 --- a/CityDoctorParent/CityDoctorValidation/src/main/java/de/hft/stuttgart/citydoctor2/checks/SvrlContentHandler.java +++ b/CityDoctorParent/CityDoctorValidation/src/main/java/de/hft/stuttgart/citydoctor2/checks/SvrlContentHandler.java @@ -106,12 +106,12 @@ public class SvrlContentHandler implements ContentHandler { throw new IllegalStateException( "Schematron File is not formed according to specification for CityDoctor."); } - String gmlId = split[0]; + String gmlId = split[0].strip(); String childId = split[1]; String errorId = split[2]; String nameOfAttribute = split[3]; SchematronError err = new SchematronError(errorId, gmlId, childId, nameOfAttribute); - if (gmlId == null || gmlId.isEmpty()) { + if (gmlId == null || gmlId.isBlank()) { // general error generalErrors.add(err); } else { diff --git a/CityDoctorParent/CityDoctorValidation/src/main/java/de/hft/stuttgart/citydoctor2/checks/geometry/PlanarCheck.java b/CityDoctorParent/CityDoctorValidation/src/main/java/de/hft/stuttgart/citydoctor2/checks/geometry/PlanarCheck.java index 560f78b5d65876a42ae9a41932f0050e342c19dd..af6dd4cc83280a9a4b454c5807339138ec15dbcf 100644 --- a/CityDoctorParent/CityDoctorValidation/src/main/java/de/hft/stuttgart/citydoctor2/checks/geometry/PlanarCheck.java +++ b/CityDoctorParent/CityDoctorValidation/src/main/java/de/hft/stuttgart/citydoctor2/checks/geometry/PlanarCheck.java @@ -57,10 +57,12 @@ import de.hft.stuttgart.citydoctor2.tesselation.TesselatedPolygon; */ public class PlanarCheck extends Check { - private static final String DISTANCE = "distance"; - private static final String DISTANCE_TOLERANCE = "distanceTolerance"; + public static final String ANGLE = "angle"; + public static final String DISTANCE = "distance"; + public static final String BOTH = "both"; + public static final String DISTANCE_TOLERANCE = "distanceTolerance"; private static final String ANGLE_TOLERANCE = "angleTolerance"; - private static final String TYPE = "type"; + public static final String TYPE = "type"; private static final List dependencies; @@ -97,7 +99,7 @@ public class PlanarCheck extends Check { public void check(Polygon p) { if (DISTANCE.equals(planarCheckType)) { planarDistance(p); - } else if ("angle".equals(planarCheckType)) { + } else if (ANGLE.equals(planarCheckType)) { planarNormalDeviation(p); } else if ("both".equals(planarCheckType)) { planarDistance(p); diff --git a/CityDoctorParent/CityDoctorValidation/src/main/java/de/hft/stuttgart/citydoctor2/checks/geometry/SolidSelfIntCheck.java b/CityDoctorParent/CityDoctorValidation/src/main/java/de/hft/stuttgart/citydoctor2/checks/geometry/SolidSelfIntCheck.java index 0eefd3498e4f95f4b290be5e3c193252e5eee90e..c911a1d7e525c8a613ff2199e8d432b52e1c17c5 100644 --- a/CityDoctorParent/CityDoctorValidation/src/main/java/de/hft/stuttgart/citydoctor2/checks/geometry/SolidSelfIntCheck.java +++ b/CityDoctorParent/CityDoctorValidation/src/main/java/de/hft/stuttgart/citydoctor2/checks/geometry/SolidSelfIntCheck.java @@ -21,13 +21,13 @@ package de.hft.stuttgart.citydoctor2.checks.geometry; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Map; import java.util.Set; import de.hft.stuttgart.citydoctor2.check.Check; import de.hft.stuttgart.citydoctor2.check.CheckError; import de.hft.stuttgart.citydoctor2.check.CheckId; import de.hft.stuttgart.citydoctor2.check.CheckResult; -import de.hft.stuttgart.citydoctor2.check.GeometrySelfIntersection; import de.hft.stuttgart.citydoctor2.check.Requirement; import de.hft.stuttgart.citydoctor2.check.RequirementType; import de.hft.stuttgart.citydoctor2.check.ResultStatus; @@ -36,6 +36,7 @@ import de.hft.stuttgart.citydoctor2.checks.util.CollectionUtils; import de.hft.stuttgart.citydoctor2.checks.util.SelfIntersectionUtil; import de.hft.stuttgart.citydoctor2.datastructure.Geometry; import de.hft.stuttgart.citydoctor2.datastructure.GeometryType; +import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration; import de.hft.stuttgart.citydoctor2.utils.PolygonIntersection; /** @@ -47,7 +48,9 @@ import de.hft.stuttgart.citydoctor2.utils.PolygonIntersection; public class SolidSelfIntCheck extends Check { private static final List dependencies; - + + private double delta = 0.01; + static { ArrayList deps = new ArrayList<>(); dependencies = Collections.unmodifiableList(deps); @@ -68,6 +71,13 @@ public class SolidSelfIntCheck extends Check { deps.add(CheckId.C_GE_S_NON_MANIFOLD_VERTEX); deps.add(CheckId.C_GE_S_POLYGON_WRONG_ORIENTATION); } + + @Override + public void init(Map parameters, ParserConfiguration config) { + if (parameters.containsKey(PlanarCheck.DISTANCE_TOLERANCE)) { + delta = Double.parseDouble(parameters.get(PlanarCheck.DISTANCE_TOLERANCE)); + } + } @Override public void check(Geometry g) { @@ -75,7 +85,7 @@ public class SolidSelfIntCheck extends Check { return; } CheckResult cr; - List intersections = SelfIntersectionUtil.calculateSolidSelfIntersection(g); + List intersections = SelfIntersectionUtil.calculateSolidSelfIntersection(g, delta); if (intersections.isEmpty()) { cr = new CheckResult(this, ResultStatus.OK, null); } else { @@ -85,18 +95,6 @@ public class SolidSelfIntCheck extends Check { g.addCheckResult(cr); } - @SuppressWarnings("unused") - private CheckResult oldIntersectionAlgorithm(Geometry g) { - CheckResult cr; - GeometrySelfIntersection intersect = SelfIntersectionUtil.doesSolidSelfIntersect(g); - if (intersect != null) { - cr = new CheckResult(this, ResultStatus.ERROR, null); - } else { - cr = new CheckResult(this, ResultStatus.OK, null); - } - return cr; - } - @Override public List getDependencies() { return dependencies; diff --git a/CityDoctorParent/CityDoctorValidation/src/main/java/de/hft/stuttgart/citydoctor2/checks/util/SelfIntersectionUtil.java b/CityDoctorParent/CityDoctorValidation/src/main/java/de/hft/stuttgart/citydoctor2/checks/util/SelfIntersectionUtil.java index 602eb04545a19a7052a10e30eda1f7f72d45a1ca..30c5787867fc6aab977b7f2e702c9e6ac877bb72 100644 --- a/CityDoctorParent/CityDoctorValidation/src/main/java/de/hft/stuttgart/citydoctor2/checks/util/SelfIntersectionUtil.java +++ b/CityDoctorParent/CityDoctorValidation/src/main/java/de/hft/stuttgart/citydoctor2/checks/util/SelfIntersectionUtil.java @@ -21,6 +21,7 @@ package de.hft.stuttgart.citydoctor2.checks.util; import java.util.ArrayList; import java.util.Collections; import java.util.IdentityHashMap; +import java.util.Iterator; import java.util.List; import java.util.Map; @@ -39,6 +40,8 @@ import org.locationtech.jts.geom.impl.CoordinateArraySequence; import org.locationtech.jts.operation.overlay.OverlayOp; import org.locationtech.jts.operation.overlay.snap.SnapIfNeededOverlayOp; +import Jama.EigenvalueDecomposition; +import Jama.Matrix; import de.hft.stuttgart.citydoctor2.check.GeometrySelfIntersection; import de.hft.stuttgart.citydoctor2.datastructure.ConcretePolygon; import de.hft.stuttgart.citydoctor2.datastructure.Geometry; @@ -50,8 +53,10 @@ import de.hft.stuttgart.citydoctor2.edge.EdgePolygon; import de.hft.stuttgart.citydoctor2.edge.IntersectPlanarPolygons; import de.hft.stuttgart.citydoctor2.edge.MeshSurface; import de.hft.stuttgart.citydoctor2.edge.PolygonPolygonIntersection; +import de.hft.stuttgart.citydoctor2.math.CovarianceMatrix; import de.hft.stuttgart.citydoctor2.math.MovedPolygon; import de.hft.stuttgart.citydoctor2.math.MovedRing; +import de.hft.stuttgart.citydoctor2.math.OrthogonalRegressionPlane; import de.hft.stuttgart.citydoctor2.math.Plane; import de.hft.stuttgart.citydoctor2.math.PlaneSegmentIntersection; import de.hft.stuttgart.citydoctor2.math.PlaneSegmentIntersection.Type; @@ -83,18 +88,37 @@ public class SelfIntersectionUtil { private SelfIntersectionUtil() { } - - public static List calculateSolidSelfIntersection(Geometry g) { + + public static List calculateSolidSelfIntersection(Geometry g, double delta) { List tesselatedPolygons = new ArrayList<>(); for (Polygon p : g.getPolygons()) { - tesselatedPolygons.add(EarcutTesselator.tesselatePolygon(p)); + TesselatedPolygon tessPolygon = EarcutTesselator.tesselatePolygon(p); + for (Iterator iterator = tessPolygon.getTriangles().iterator(); iterator.hasNext();) { + Triangle3d t = iterator.next(); + List vertices = new ArrayList<>(3); + vertices.add(t.getP1()); + vertices.add(t.getP2()); + vertices.add(t.getP3()); + Vector3d centroid = CovarianceMatrix.getCentroid(vertices); + EigenvalueDecomposition ed = OrthogonalRegressionPlane.decompose(vertices, centroid); + Matrix eigenValues = ed.getD(); + double[] eigenValuesArray = new double[3]; + eigenValuesArray[0] = eigenValues.get(0, 0); + eigenValuesArray[1] = eigenValues.get(1, 1); + eigenValuesArray[2] = eigenValues.get(2, 2); + if (eigenValuesArray[1] < delta) { + iterator.remove(); + } + } + tesselatedPolygons.add(tessPolygon); } + List intersections = new ArrayList<>(); for (int i = 0; i < tesselatedPolygons.size() - 1; i++) { TesselatedPolygon p1 = tesselatedPolygons.get(i); for (int j = i + 1; j < tesselatedPolygons.size(); j++) { TesselatedPolygon p2 = tesselatedPolygons.get(j); - GeometrySelfIntersection intersection = doPolygonsIntersect(p1, p2); + GeometrySelfIntersection intersection = doPolygonsIntersect(p1, p2, delta); if (intersection != null) { intersections.add(PolygonIntersection.triangles(intersection.t1(), intersection.t2())); } @@ -103,8 +127,8 @@ public class SelfIntersectionUtil { return intersections; } - public static GeometrySelfIntersection doesSolidSelfIntersect(Geometry g) { - return selfIntersectionJava(g); + public static GeometrySelfIntersection doesSolidSelfIntersect(Geometry g, double epsilon) { + return selfIntersectionJava(g, epsilon); } public static List doesSolidSelfIntersect2(Geometry g) { @@ -404,7 +428,7 @@ public class SelfIntersectionUtil { return sign != 0; } - private static GeometrySelfIntersection selfIntersectionJava(Geometry g) { + private static GeometrySelfIntersection selfIntersectionJava(Geometry g, double epsilon) { List tessPolys = new ArrayList<>(); for (Polygon p : g.getPolygons()) { tessPolys.add(JoglTesselator.tesselatePolygon(p)); @@ -413,7 +437,7 @@ public class SelfIntersectionUtil { TesselatedPolygon p1 = tessPolys.get(i); for (int j = i + 1; j < tessPolys.size(); j++) { TesselatedPolygon p2 = tessPolys.get(j); - GeometrySelfIntersection intersection = doPolygonsIntersect(p1, p2); + GeometrySelfIntersection intersection = doPolygonsIntersect(p1, p2, epsilon); if (intersection != null) { return intersection; } @@ -422,12 +446,12 @@ public class SelfIntersectionUtil { return null; } - private static GeometrySelfIntersection doPolygonsIntersect(TesselatedPolygon p1, TesselatedPolygon p2) { + private static GeometrySelfIntersection doPolygonsIntersect(TesselatedPolygon p1, TesselatedPolygon p2, double epsilon) { for (int p1Index = 0; p1Index < p1.getTriangles().size(); p1Index++) { for (int p2Index = 0; p2Index < p2.getTriangles().size(); p2Index++) { Triangle3d t1 = p1.getTriangles().get(p1Index); Triangle3d t2 = p2.getTriangles().get(p2Index); - if (t1.doesIntersect(t2)) { + if (t1.doesIntersect(t2, epsilon)) { logger.trace("{} intersects {}", t1, t2); logger.trace("GML-ID: {} intersects {}", t1.getPartOf().getOriginal().getGmlId(), t2.getPartOf().getOriginal().getGmlId()); diff --git a/CityDoctorParent/CityDoctorValidation/src/main/java/de/hft/stuttgart/citydoctor2/reporting/XmlValidationReporter.java b/CityDoctorParent/CityDoctorValidation/src/main/java/de/hft/stuttgart/citydoctor2/reporting/XmlValidationReporter.java index 5bf19ad3c957cb2495c1e5c27316175d1dac80f0..3c5503835fda1730e561ff6d7e6d8668c6933dcc 100644 --- a/CityDoctorParent/CityDoctorValidation/src/main/java/de/hft/stuttgart/citydoctor2/reporting/XmlValidationReporter.java +++ b/CityDoctorParent/CityDoctorValidation/src/main/java/de/hft/stuttgart/citydoctor2/reporting/XmlValidationReporter.java @@ -45,33 +45,8 @@ public class XmlValidationReporter implements Reporter { @Override public void writeReport(Checks checks, OutputStream filePath, CityDoctorModel model, ValidationConfiguration config) throws CheckReportWriteException { StreamReporter streamReporter = new XmlStreamReporter(filePath, model.getFileName(), config); - for (BridgeObject bo : model.getBridges()) { - streamReporter.report(bo); - } - for (Building b : model.getBuildings()) { - streamReporter.report(b); - } - for (TransportationObject to : model.getTransportation()) { - streamReporter.report(to); - } - for (CityObject lo : model.getLand()) { - streamReporter.report(lo); - } - for (Vegetation v : model.getVegetation()) { - streamReporter.report(v); - } - for (WaterObject wo : model.getWater()) { - streamReporter.report(wo); - } - for (Tunnel tunnel : model.getTunnels()) { - streamReporter.report(tunnel); - } - for (CityFurniture cf : model.getCityFurniture()) { - streamReporter.report(cf); - } - for (GenericCityObject gco : model.getGenericCityObjects()) { - streamReporter.report(gco); - } + model.createFeatureStream().forEach(streamReporter::report); + for (CheckError err : model.getGlobalErrors()) { streamReporter.reportGlobalError(err); } diff --git a/CityDoctorParent/CityDoctorValidation/src/main/resources/log4j2.xml b/CityDoctorParent/CityDoctorValidation/src/main/resources/log4j2.xml new file mode 100644 index 0000000000000000000000000000000000000000..1b1a09f31c1dea7e13e9f9a70aa5b80703e4a8d0 --- /dev/null +++ b/CityDoctorParent/CityDoctorValidation/src/main/resources/log4j2.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/check/CheckerTest.java b/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/check/CheckerTest.java index 799b27307361491671017a36ef2a3b328ef713dd..cbc489abf908279d7d8e193f47b2db258495141b 100644 --- a/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/check/CheckerTest.java +++ b/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/check/CheckerTest.java @@ -24,7 +24,6 @@ import de.hft.stuttgart.citydoctor2.checkresult.GlobalErrorStatistics; import de.hft.stuttgart.citydoctor2.checkresult.GlobalStatistics; import de.hft.stuttgart.citydoctor2.checkresult.ModelStatistics; import de.hft.stuttgart.citydoctor2.checkresult.utility.CheckReportParseException; -import de.hft.stuttgart.citydoctor2.checks.util.FeatureCheckedListener; import de.hft.stuttgart.citydoctor2.datastructure.Building; import de.hft.stuttgart.citydoctor2.datastructure.CityDoctorModel; import de.hft.stuttgart.citydoctor2.exceptions.CityDoctorWriteException; @@ -32,8 +31,6 @@ import de.hft.stuttgart.citydoctor2.parser.CityGmlParseException; import de.hft.stuttgart.citydoctor2.parser.CityGmlParser; import de.hft.stuttgart.citydoctor2.parser.InvalidGmlFileException; import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration; -import de.hft.stuttgart.citydoctor2.zip.CityGmlZipArchive; -import de.hft.stuttgart.citydoctor2.zip.CityGmlZipEntry; import org.apache.commons.io.FileUtils; import org.junit.Rule; import org.junit.Test; @@ -68,7 +65,7 @@ public class CheckerTest { "src/test/resources/SimpleSolid_SrefBS_SchematronTest.gml", config.getParserConfiguration()); Checker checker = new Checker(config, model); checker.runChecks(); - for (Building b : model.getBuildings()) { + for (Building b : model.getBuildings().toList()) { if (b.getGmlId().getGmlString().equals("_Simple_BD.1")) { assertTrue(b.containsAnyError()); } else { @@ -128,76 +125,6 @@ public class CheckerTest { } } - @Test - public void testCliZipChecking() throws IOException, CityDoctorWriteException, CityGmlParseException, InvalidGmlFileException { - String output = folder.getRoot().toPath() + File.separator + "test"; - String pdfOutput = folder.getRoot().toPath() + File.separator + "pdf" + File.separator; - String xmlOutput = folder.getRoot().toPath() + File.separator + "xml" + File.separator; - try { - String[] args = new String[10]; - args[0] = "-in"; - args[1] = "src/test/resources/zipArchive.zip"; - args[2] = "-config"; - args[3] = "src/test/resources/testConfigWithStreaming.yml"; - args[4] = "-pdfReport"; - args[5] = pdfOutput; - args[6] = "-xmlReport"; - args[7] = xmlOutput; - args[8] = "-out"; - args[9] = output + File.separator; - CityDoctorValidation.main(args); - File zipFile = new File(output + ".zip"); - File pdfDir = new File(pdfOutput); - File xmlDir = new File(xmlOutput); - assertTrue(zipFile.exists()); - assertTrue(pdfDir.exists()); - assertTrue(xmlDir.exists()); - - assertTrue(pdfDir.isDirectory()); - assertTrue(xmlDir.isDirectory()); - assertEquals(5, pdfDir.listFiles().length); - assertEquals(5, xmlDir.listFiles().length); - - CityGmlZipArchive cgmlArch = CityGmlZipArchive.register(output + ".zip"); - assertNotNull(cgmlArch); - cgmlArch.mountArchive(new ParserConfiguration(8, true)); - assertEquals(5, cgmlArch.getEntries().size()); - for (CityGmlZipEntry entry : cgmlArch.getEntries()) { - assertNotNull(entry); - assertNull(entry.getErrorType()); - } - - } catch (CityGmlParseException | IOException | InvalidGmlFileException | CityDoctorWriteException e) { - throw e; - } - } - - @Test - public void testZipEntryChecking() throws CityGmlParseException, IOException { - CityGmlZipArchive cgmlArch = CityGmlZipArchive.register("src/test/resources/zipArchive.zip"); - assertNotNull(cgmlArch); - cgmlArch.mountArchive(new ParserConfiguration(8, false)); - ValidationConfiguration config = ValidationConfiguration.loadStandardValidationConfig(); - FeatureCheckedListener l = co -> { - assertTrue("CityObject should be validated", co.isValidated()); - }; - for (CityGmlZipEntry entry : cgmlArch.getEntries()) { - Checker.streamCheck(entry, null, null, config, l, null); - } - } - - @Test - public void testZipArchiveChecking() throws CityGmlParseException, IOException { - CityGmlZipArchive cgmlArch = CityGmlZipArchive.register("src/test/resources/zipArchive.zip"); - assertNotNull(cgmlArch); - cgmlArch.mountArchive(new ParserConfiguration(8, false)); - ValidationConfiguration config = ValidationConfiguration.loadStandardValidationConfig(); - FeatureCheckedListener l = co -> { - assertTrue(co.isValidated()); - }; - Checker.streamCheck(cgmlArch, null, null, config, l, null); - } - @Test public void testReportCreation() throws IOException, CityGmlParseException, InvalidGmlFileException { Path tmpDir = null; @@ -207,7 +134,7 @@ public class CheckerTest { Path xmlPath = tmpDir.resolve("report.xml"); Path pdfPath = tmpDir.resolve("report.pdf"); File features = new File("src/test/resources/feature_types.gml"); - CityDoctorModel model = CityGmlParser.parseCityGmlFileSilently( + CityDoctorModel model = CityGmlParser.nestedCityGmlFileParse( features.toString(), new ParserConfiguration(8, false)); assertNotNull(model); Checker checker = new Checker(model); diff --git a/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/check/FilterTest.java b/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/check/FilterTest.java index f3c096f0b3cb08f021f194840600b68a3ebb98bf..b8c2d3674a44ca8bef7df547432184510de971bd 100644 --- a/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/check/FilterTest.java +++ b/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/check/FilterTest.java @@ -45,12 +45,12 @@ public class FilterTest { Checker c = new Checker(config, model); c.runChecks(); - Building b = model.getBuildings().get(0); + Building b = model.getBuildings().toList().get(0); Geometry geom = b.getGeometries().get(0); assertFalse(geom.hasCheckResults()); - TransportationObject to = model.getTransportation().get(0); + TransportationObject to = model.getTransportation().toList().get(0); Geometry geom2 = to.getGeometries().get(0); assertTrue(geom2.getPolygons().get(0).hasCheckResults()); @@ -65,12 +65,12 @@ public class FilterTest { Checker c = new Checker(config, model); c.runChecks(); - Building b = model.getBuildings().get(0); + Building b = model.getBuildings().toList().get(0); Geometry geom = b.getGeometries().get(0); assertFalse(geom.hasCheckResults()); - TransportationObject to = model.getTransportation().get(0); + TransportationObject to = model.getTransportation().toList().get(0); Geometry geom2 = to.getGeometries().get(0); assertTrue(geom2.getPolygons().get(0).hasCheckResults()); diff --git a/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/checks/geometry/DegeneratedPolygonCheckTest.java b/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/checks/geometry/DegeneratedPolygonCheckTest.java index 98669c4056f985bc14c0f1e834afb584f6182bb3..7859eb72d23b80b5b4586048b7297afc1b6ce733 100644 --- a/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/checks/geometry/DegeneratedPolygonCheckTest.java +++ b/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/checks/geometry/DegeneratedPolygonCheckTest.java @@ -26,6 +26,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import de.hft.stuttgart.citydoctor2.database.UnconnectedCache; import org.junit.Test; import de.hft.stuttgart.citydoctor2.check.CheckError; @@ -44,6 +45,7 @@ import de.hft.stuttgart.citydoctor2.datastructure.Vertex; import de.hft.stuttgart.citydoctor2.datastructure.Geometry.Orientation; import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration; import de.hft.stuttgart.quality.model.enums.RequirementId; +import org.mockito.Mockito; public class DegeneratedPolygonCheckTest { @@ -68,9 +70,10 @@ public class DegeneratedPolygonCheckTest { Building b = new Building(); b.addGeometry(geom); - + File file = Mockito.mock(File.class); + Mockito.when(file.getName()).thenReturn("building"); ParserConfiguration config = new ParserConfiguration(8, false); - CityDoctorModel model = new CityDoctorModel(config, new File("")); + CityDoctorModel model = new CityDoctorModel(config, file, new UnconnectedCache()); model.addBuilding(b); ValidationConfiguration valConfig = ValidationConfiguration.loadStandardValidationConfig(); diff --git a/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/checks/geometry/SolidSelfIntCheckFalsePositiveBigMeshTest.java b/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/checks/geometry/SolidSelfIntCheckFalsePositiveBigMeshTest.java index d79fed452bec668bfba03968c8bb20f24ddfde8a..20ad29a1dc48c0afc2920fb491255a60f414d072 100644 --- a/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/checks/geometry/SolidSelfIntCheckFalsePositiveBigMeshTest.java +++ b/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/checks/geometry/SolidSelfIntCheckFalsePositiveBigMeshTest.java @@ -35,7 +35,7 @@ public class SolidSelfIntCheckFalsePositiveBigMeshTest { CityDoctorModel m = CityGmlParser.parseCityGmlFile(gml_filepath, config.getParserConfiguration()); Checker c = new Checker(config, m); c.runChecks(); - Building building = m.getBuildings().get(0); + Building building = m.getBuildings().toList().get(0); /* * The examples have no actual self-intersections, but can contain other actual model defects. * If an error is detected, it is thus required to check if the diff --git a/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/checks/geometry/SolidSelfIntCheckTest.java b/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/checks/geometry/SolidSelfIntCheckTest.java index 847de23fb231a38b6160cf06f45a707edbc3a475..7531268e16c20e9ad90704c0258859877af339ac 100644 --- a/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/checks/geometry/SolidSelfIntCheckTest.java +++ b/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/checks/geometry/SolidSelfIntCheckTest.java @@ -25,14 +25,18 @@ import static org.junit.Assert.assertNotNull; import org.junit.Assert; import org.junit.Test; +import de.hft.stuttgart.citydoctor2.check.CheckId; import de.hft.stuttgart.citydoctor2.check.CheckResult; import de.hft.stuttgart.citydoctor2.check.Checker; import de.hft.stuttgart.citydoctor2.check.ResultStatus; import de.hft.stuttgart.citydoctor2.check.ValidationConfiguration; +import de.hft.stuttgart.citydoctor2.check.error.NonPlanarPolygonDistancePlaneError; import de.hft.stuttgart.citydoctor2.checks.util.GeometryTestUtils; import de.hft.stuttgart.citydoctor2.datastructure.Building; import de.hft.stuttgart.citydoctor2.datastructure.CityDoctorModel; +import de.hft.stuttgart.citydoctor2.datastructure.ConcretePolygon; import de.hft.stuttgart.citydoctor2.datastructure.Geometry; +import de.hft.stuttgart.citydoctor2.datastructure.Geometry.Orientation; import de.hft.stuttgart.citydoctor2.datastructure.GeometryType; import de.hft.stuttgart.citydoctor2.datastructure.Lod; import de.hft.stuttgart.citydoctor2.parser.CityGmlParseException; @@ -45,6 +49,22 @@ import de.hft.stuttgart.citydoctor2.parser.InvalidGmlFileException; * */ public class SolidSelfIntCheckTest { + + @Test + public void testDependencyChecking() { + Geometry geom = new Geometry(GeometryType.SOLID, Lod.LOD2, Orientation.OUTWARD); + + ConcretePolygon p = new ConcretePolygon(); + geom.addPolygon(p); + NonPlanarPolygonDistancePlaneError err = new NonPlanarPolygonDistancePlaneError(p, 2, null, null); + CheckResult cr = new CheckResult(CheckId.C_GE_P_NON_PLANAR, ResultStatus.ERROR, err); + p.addCheckResult(cr); + + SolidSelfIntCheck selfIntCheck = new SolidSelfIntCheck(); + + boolean canExecute = selfIntCheck.canExecute(geom); + assertFalse(canExecute); + } @Test public void testGoodGeometry() { @@ -75,7 +95,7 @@ public class SolidSelfIntCheckTest { CityDoctorModel m = CityGmlParser.parseCityGmlFile("src/test/resources/SolidSelfIntTest1.gml", config.getParserConfiguration()); Checker c = new Checker(config, m); c.runChecks(); - assertFalse(m.getBuildings().get(0).containsAnyError()); + assertFalse(m.getBuildings().toList().get(0).containsAnyError()); } @@ -85,7 +105,7 @@ public class SolidSelfIntCheckTest { CityDoctorModel m = CityGmlParser.parseCityGmlFile(gml_filepath, config.getParserConfiguration()); Checker c = new Checker(config, m); c.runChecks(); - Building building = m.getBuildings().get(0); + Building building = m.getBuildings().toList().get(0); /* * The examples have no actual self-intersections, but can contain other actual model defects. * If an error is detected, it is thus required to check if the diff --git a/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/systemtest/AllPolygonWrongOrientedTest.java b/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/systemtest/AllPolygonWrongOrientedTest.java index e941df1946461dc80fc2d51912529b4e535f4cf5..e96b4e45f807843d4c9e921572e605cc9184e136 100644 --- a/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/systemtest/AllPolygonWrongOrientedTest.java +++ b/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/systemtest/AllPolygonWrongOrientedTest.java @@ -48,7 +48,7 @@ public class AllPolygonWrongOrientedTest { Checker c = new Checker(config, model); c.runChecks(); - Building b = model.getBuildings().get(0); + Building b = model.getBuildings().toList().get(0); assertFalse(b.containsError(CheckId.C_GE_S_ALL_POLYGONS_WRONG_ORIENTATION)); } diff --git a/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/systemtest/ConCompCheckTest.java b/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/systemtest/ConCompCheckTest.java index 2a8c1317fd1397912446ca11abac4c2e899376f1..b9a508095bc3da244bc2e932b787c30a976fc877 100644 --- a/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/systemtest/ConCompCheckTest.java +++ b/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/systemtest/ConCompCheckTest.java @@ -51,7 +51,7 @@ public class ConCompCheckTest extends TestCleanUp { Checker c = new Checker(m); c.runChecks(); - Geometry geom = m.getBuildings().get(0).getGeometries().get(0); + Geometry geom = m.getBuildings().toList().get(0).getGeometries().get(0); CheckResult cr = geom.getCheckResult(CheckId.C_GE_S_MULTIPLE_CONNECTED_COMPONENTS); assertNotNull(cr); assertEquals(ResultStatus.ERROR, cr.getResultStatus()); @@ -65,7 +65,7 @@ public class ConCompCheckTest extends TestCleanUp { Checker c = new Checker(m); c.runChecks(); - Geometry geom = m.getBuildings().get(0).getGeometries().get(0); + Geometry geom = m.getBuildings().toList().get(0).getGeometries().get(0); CheckResult cr = geom.getCheckResult(CheckId.C_GE_S_MULTIPLE_CONNECTED_COMPONENTS); assertNotNull(cr); assertEquals(ResultStatus.ERROR, cr.getResultStatus()); diff --git a/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/systemtest/DupPointsCheckTest.java b/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/systemtest/DupPointsCheckTest.java index 924c651ee8c38889a9f2887df4176de0c6475883..2720b0114a11b59726ebc232f82d8d92b3261b53 100644 --- a/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/systemtest/DupPointsCheckTest.java +++ b/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/systemtest/DupPointsCheckTest.java @@ -79,7 +79,7 @@ public class DupPointsCheckTest { @Test public void testDupPoints3() throws CityGmlParseException, IOException, InvalidGmlFileException { CityDoctorModel m = TestUtil.loadAndCheckCityModel("src/test/resources/SimpleSolid_SrefBS.gml"); - for (Polygon p : m.getBuildings().get(0).getGeometries().get(0).getPolygons()) { + for (Polygon p : m.getBuildings().toList().get(0).getGeometries().get(0).getPolygons()) { LinearRing r = p.getExteriorRing(); CheckResult cr = r.getCheckResult(CheckId.C_GE_R_DUPLICATE_POINT); assertEquals(ResultStatus.OK, cr.getResultStatus()); diff --git a/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/systemtest/HoleOutsideSystemTest.java b/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/systemtest/HoleOutsideSystemTest.java index 89072edcdf00906f4b6635788ae09b49ad4b85dc..dd603053ca7d71ec338650570a4989b8e03442c5 100644 --- a/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/systemtest/HoleOutsideSystemTest.java +++ b/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/systemtest/HoleOutsideSystemTest.java @@ -43,7 +43,7 @@ public class HoleOutsideSystemTest { @Test public void testHoleOutside1() throws CityGmlParseException, IOException, InvalidGmlFileException { CityDoctorModel c = TestUtil.loadAndCheckCityModel("src/test/resources/SimpleSolid_SrefBS-GE-gml-PO-0001-T0002.gml"); - for (Polygon p : c.getBuildings().get(0).getGeometries().get(0).getPolygons()) { + for (Polygon p : c.getBuildings().toList().get(0).getGeometries().get(0).getPolygons()) { CheckResult cr = p.getCheckResult(CheckId.C_GE_P_HOLE_OUTSIDE); assertEquals(ResultStatus.OK, cr.getResultStatus()); } diff --git a/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/systemtest/InnerRingsNestedSystemTest.java b/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/systemtest/InnerRingsNestedSystemTest.java index 6ae1d4784e4694fca61c2728298ab73ecfaae070..ca2982e97cb2eb608b6d5d647e73d5e8adf88178 100644 --- a/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/systemtest/InnerRingsNestedSystemTest.java +++ b/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/systemtest/InnerRingsNestedSystemTest.java @@ -43,7 +43,7 @@ public class InnerRingsNestedSystemTest { @Test public void innerRingsNested1() throws CityGmlParseException, IOException, InvalidGmlFileException { CityDoctorModel c = TestUtil.loadAndCheckCityModel("src/test/resources/SimpleSolid_SrefBS-GE-gml-PO-0001-T0002.gml"); - for (Polygon p : c.getBuildings().get(0).getGeometries().get(0).getPolygons()) { + for (Polygon p : c.getBuildings().toList().get(0).getGeometries().get(0).getPolygons()) { CheckResult cr = p.getCheckResult(CheckId.C_GE_P_INNER_RINGS_NESTED); assertEquals(ResultStatus.OK, cr.getResultStatus()); } diff --git a/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/systemtest/InteriorDisconnectedSystemTest.java b/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/systemtest/InteriorDisconnectedSystemTest.java index 4ddd49c4c80c84e52affbea83eb11ee17edffe3e..9d7ac4466eebb596fd1b1613417469896156535c 100644 --- a/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/systemtest/InteriorDisconnectedSystemTest.java +++ b/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/systemtest/InteriorDisconnectedSystemTest.java @@ -43,7 +43,7 @@ public class InteriorDisconnectedSystemTest { @Test public void testInteriorDisconnected1() throws CityGmlParseException, IOException, InvalidGmlFileException { CityDoctorModel c = TestUtil.loadAndCheckCityModel("src/test/resources/SimpleSolid_SrefBS-GE-gml-PO-0001-T0002.gml"); - for (Polygon p : c.getBuildings().get(0).getGeometries().get(0).getPolygons()) { + for (Polygon p : c.getBuildings().toList().get(0).getGeometries().get(0).getPolygons()) { CheckResult cr = p.getCheckResult(CheckId.C_GE_P_INTERIOR_DISCONNECTED); assertEquals(ResultStatus.OK, cr.getResultStatus()); } diff --git a/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/systemtest/MultipleComponentTest.java b/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/systemtest/MultipleComponentTest.java index 33aaafbd829182bd8152eb799c73c212f783bdaf..f958a9e023b454ea27fa45704913fc418fa23919 100644 --- a/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/systemtest/MultipleComponentTest.java +++ b/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/systemtest/MultipleComponentTest.java @@ -43,7 +43,7 @@ public class MultipleComponentTest { @Test public void testNoMultipleComponents() throws CityGmlParseException, IOException, InvalidGmlFileException { CityDoctorModel c = TestUtil.loadAndCheckCityModel("src/test/resources/SimpleSolid_SrefBS.gml"); - Geometry g = c.getBuildings().get(0).getGeometries().get(0); + Geometry g = c.getBuildings().toList().get(0).getGeometries().get(0); CheckResult cr = g.getCheckResult(CheckId.C_GE_S_MULTIPLE_CONNECTED_COMPONENTS); assertEquals(ResultStatus.OK, cr.getResultStatus()); } @@ -51,7 +51,7 @@ public class MultipleComponentTest { @Test public void testMultipleComponents() throws CityGmlParseException, IOException, InvalidGmlFileException { CityDoctorModel c = TestUtil.loadAndCheckCityModel("src/test/resources/SimpleSolid_SrefBS-GE-gml-SO-0005-T0001.gml"); - Geometry g = c.getBuildings().get(0).getGeometries().get(0); + Geometry g = c.getBuildings().toList().get(0).getGeometries().get(0); CheckResult cr = g.getCheckResult(CheckId.C_GE_S_MULTIPLE_CONNECTED_COMPONENTS); assertEquals(ResultStatus.ERROR, cr.getResultStatus()); assertEquals(ErrorId.GE_S_MULTIPLE_CONNECTED_COMPONENTS, cr.getError().getErrorId()); diff --git a/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/systemtest/NonManifoldEdgeSystemTest.java b/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/systemtest/NonManifoldEdgeSystemTest.java index 66e121b26da26a57fe8ad9d8026d41cbfcefa56e..597bd46268887d78054d80c6a751f5e2d2bc3221 100644 --- a/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/systemtest/NonManifoldEdgeSystemTest.java +++ b/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/systemtest/NonManifoldEdgeSystemTest.java @@ -46,7 +46,7 @@ public class NonManifoldEdgeSystemTest { @Test public void testNonManifoldEdge1() throws CityGmlParseException, IOException, InvalidGmlFileException { CityDoctorModel c = TestUtil.loadAndCheckCityModel("src/test/resources/SimpleSolid_SrefBS.gml"); - Geometry g = c.getBuildings().get(0).getGeometries().get(0); + Geometry g = c.getBuildings().toList().get(0).getGeometries().get(0); CheckResult cr = g.getCheckResult(CheckId.C_GE_S_NON_MANIFOLD_EDGE); assertEquals(ResultStatus.OK, cr.getResultStatus()); } @@ -59,7 +59,7 @@ public class NonManifoldEdgeSystemTest { paramMap.put(RequirementId.R_GE_P_NON_PLANAR.toString(), parameter); CityDoctorModel c = TestUtil.loadAndCheckCityModel("src/test/resources/SimpleSolid_SrefBS-GE-gml-SO-0004-T0001.gml", paramMap); - Geometry g = c.getBuildings().get(0).getGeometries().get(0); + Geometry g = c.getBuildings().toList().get(0).getGeometries().get(0); CheckResult cr = g.getCheckResult(CheckId.C_GE_S_NON_MANIFOLD_EDGE); assertEquals(ResultStatus.ERROR, cr.getResultStatus()); assertEquals(ErrorId.GE_S_NON_MANIFOLD_EDGE, cr.getError().getErrorId()); diff --git a/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/systemtest/NonManifoldVertexSystemTest.java b/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/systemtest/NonManifoldVertexSystemTest.java index 127745410d707602a3238b97d3f377516ed9bb0e..9ab2e229831157a09dd6652d0163384f88169fcd 100644 --- a/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/systemtest/NonManifoldVertexSystemTest.java +++ b/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/systemtest/NonManifoldVertexSystemTest.java @@ -43,7 +43,7 @@ public class NonManifoldVertexSystemTest { @Test public void testNonManifoldVertex1() throws CityGmlParseException, IOException, InvalidGmlFileException { CityDoctorModel c = TestUtil.loadAndCheckCityModel("src/test/resources/SimpleSolid_SrefBS.gml"); - Geometry g = c.getBuildings().get(0).getGeometries().get(0); + Geometry g = c.getBuildings().toList().get(0).getGeometries().get(0); CheckResult cr = g.getCheckResult(CheckId.C_GE_S_NON_MANIFOLD_VERTEX); assertEquals(ResultStatus.OK, cr.getResultStatus()); } @@ -51,7 +51,7 @@ public class NonManifoldVertexSystemTest { @Test public void testNonManifoldVertex2() throws CityGmlParseException, IOException, InvalidGmlFileException { CityDoctorModel c = TestUtil.loadAndCheckCityModel("src/test/resources/SimpleSolid_SrefBS-GE-gml-SO-0003-T0001.gml"); - Geometry g = c.getBuildings().get(0).getGeometries().get(0); + Geometry g = c.getBuildings().toList().get(0).getGeometries().get(0); CheckResult cr = g.getCheckResult(CheckId.C_GE_S_NON_MANIFOLD_VERTEX); assertEquals(ResultStatus.ERROR, cr.getResultStatus()); assertEquals(ErrorId.GE_S_NON_MANIFOLD_VERTEX, cr.getError().getErrorId()); diff --git a/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/systemtest/NumPointsCheckTest.java b/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/systemtest/NumPointsCheckTest.java index 2a1a6b37d2d32728b0de55f5583988365cbc5225..22c2c426a3a148e5380d8b36992e0086f6e1904d 100644 --- a/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/systemtest/NumPointsCheckTest.java +++ b/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/systemtest/NumPointsCheckTest.java @@ -80,7 +80,7 @@ public class NumPointsCheckTest { public void testNumPoints3() throws CityGmlParseException, IOException, InvalidGmlFileException { CityDoctorModel c = TestUtil.loadAndCheckCityModel("src/test/resources/SimpleSolid_SrefBS.gml"); - for (Polygon p : c.getBuildings().get(0).getGeometries().get(0).getPolygons()) { + for (Polygon p : c.getBuildings().toList().get(0).getGeometries().get(0).getPolygons()) { LinearRing r = p.getExteriorRing(); assertEquals(ResultStatus.OK, r.getCheckResult(CheckId.C_GE_R_TOO_FEW_POINTS).getResultStatus()); } diff --git a/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/systemtest/OrientationSameSystemTest.java b/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/systemtest/OrientationSameSystemTest.java index 687871312622bfb2d9e62a02b078ccb39272e1ce..1e3b3a5654224f008766778db5619aafc79af121 100644 --- a/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/systemtest/OrientationSameSystemTest.java +++ b/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/systemtest/OrientationSameSystemTest.java @@ -43,7 +43,7 @@ public class OrientationSameSystemTest { @Test public void testOrientationSame1() throws CityGmlParseException, IOException, InvalidGmlFileException { CityDoctorModel c = TestUtil.loadAndCheckCityModel("src/test/resources/SimpleSolid_SrefBS-GE-gml-PO-0001-T0002.gml"); - for (Polygon p : c.getBuildings().get(0).getGeometries().get(0).getPolygons()) { + for (Polygon p : c.getBuildings().toList().get(0).getGeometries().get(0).getPolygons()) { CheckResult cr = p.getCheckResult(CheckId.C_GE_P_ORIENTATION_RINGS_SAME); assertEquals(ResultStatus.OK, cr.getResultStatus()); } diff --git a/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/systemtest/OuterEdgeCheckTest.java b/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/systemtest/OuterEdgeCheckTest.java index 2b6af2fbd2a172f34a39a5514fc09cdc49535a99..08e88d65c4dcfaff34f514a871c7ec49b683a84c 100644 --- a/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/systemtest/OuterEdgeCheckTest.java +++ b/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/systemtest/OuterEdgeCheckTest.java @@ -71,7 +71,7 @@ public class OuterEdgeCheckTest { expectedErrorEdges.add(new Vertex(1.0, 0.0, 3.5)); expectedErrorEdges.add(new Vertex(2.0, 0.0, 3.0)); - Geometry geom = m.getBuildings().get(0).getGeometries().get(0); + Geometry geom = m.getBuildings().toList().get(0).getGeometries().get(0); CheckResult cr = geom.getCheckResult(CheckId.C_GE_S_NOT_CLOSED); Assert.assertEquals(ResultStatus.ERROR, cr.getResultStatus()); } diff --git a/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/systemtest/PlanarTest.java b/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/systemtest/PlanarTest.java index f15f12899d9e5fe4fa7de10e8c0bfbb2cc1e8927..34d69e7adf6cab6e945571b2308cb9a1d1ecbea9 100644 --- a/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/systemtest/PlanarTest.java +++ b/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/systemtest/PlanarTest.java @@ -31,6 +31,7 @@ import de.hft.stuttgart.citydoctor2.check.CheckResult; import de.hft.stuttgart.citydoctor2.check.Checker; import de.hft.stuttgart.citydoctor2.check.ErrorId; import de.hft.stuttgart.citydoctor2.check.ResultStatus; +import de.hft.stuttgart.citydoctor2.checks.geometry.PlanarCheck; import de.hft.stuttgart.citydoctor2.datastructure.CityDoctorModel; import de.hft.stuttgart.citydoctor2.datastructure.Polygon; import de.hft.stuttgart.citydoctor2.parser.CityGmlParseException; @@ -106,7 +107,7 @@ public class PlanarTest { @Test public void testPlanarPolygon3() throws CityGmlParseException, IOException, InvalidGmlFileException { CityDoctorModel c = TestUtil.loadAndCheckCityModel("src/test/resources/SimpleSolid_SrefBS-GE-gml-PO-0001-T0002.gml"); - for (Polygon p : c.getBuildings().get(0).getGeometries().get(0).getPolygons()) { + for (Polygon p : c.getBuildings().toList().get(0).getGeometries().get(0).getPolygons()) { CheckResult cr = p.getCheckResult(CheckId.C_GE_P_NON_PLANAR); assertEquals(ResultStatus.OK, cr.getResultStatus()); } @@ -142,7 +143,7 @@ public class PlanarTest { public void testPlanarPolygon6() throws CityGmlParseException, IOException, InvalidGmlFileException { Map> paramMap = new HashMap<>(); Map parameter = new HashMap<>(); - parameter.put("type", "both"); + parameter.put(PlanarCheck.TYPE, PlanarCheck.BOTH); parameter.put("distanceTolerance", "0.5"); paramMap.put(RequirementId.R_GE_P_NON_PLANAR.toString(), parameter); CityDoctorModel c = TestUtil.loadAndCheckCityModel("src/test/resources/SimpleSolid_SrefBS-GE-gml-PO-0002-T0002.gml", paramMap); diff --git a/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/systemtest/PolygonIntersectingRingsTest.java b/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/systemtest/PolygonIntersectingRingsTest.java index a4dadfb38a6e97e1c956ef6cd60103e5860eb76c..a18ed09e06bc2c145e9dec3f36f4a0a7db8d5e8c 100644 --- a/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/systemtest/PolygonIntersectingRingsTest.java +++ b/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/systemtest/PolygonIntersectingRingsTest.java @@ -43,7 +43,7 @@ public class PolygonIntersectingRingsTest { @Test public void testSelfIntPolygon1() throws CityGmlParseException, IOException, InvalidGmlFileException { CityDoctorModel c = TestUtil.loadAndCheckCityModel("src/test/resources/SimpleSolid_SrefBS.gml"); - for (Polygon p : c.getBuildings().get(0).getGeometries().get(0).getPolygons()) { + for (Polygon p : c.getBuildings().toList().get(0).getGeometries().get(0).getPolygons()) { CheckResult cr = p.getCheckResult(CheckId.C_GE_P_INTERSECTING_RINGS); assertEquals(ResultStatus.OK, cr.getResultStatus()); } @@ -52,7 +52,7 @@ public class PolygonIntersectingRingsTest { @Test public void testSelfIntPolygon2() throws CityGmlParseException, IOException, InvalidGmlFileException { CityDoctorModel c = TestUtil.loadAndCheckCityModel("src/test/resources/SimpleSolid_SrefBS-GE-gml-PO-0001-T0002.gml"); - for (Polygon p : c.getBuildings().get(0).getGeometries().get(0).getPolygons()) { + for (Polygon p : c.getBuildings().toList().get(0).getGeometries().get(0).getPolygons()) { CheckResult cr = p.getCheckResult(CheckId.C_GE_P_INTERSECTING_RINGS); assertEquals(ResultStatus.OK, cr.getResultStatus()); } diff --git a/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/systemtest/RingClosedCheckTest.java b/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/systemtest/RingClosedCheckTest.java index 7cdf629c77a367b0710818316998cda025922d23..9be6709e7073afe043ecd108f50b45cdb5cb11da 100644 --- a/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/systemtest/RingClosedCheckTest.java +++ b/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/systemtest/RingClosedCheckTest.java @@ -91,7 +91,7 @@ public class RingClosedCheckTest extends TestCleanUp { @Test public void testClosedRing3() throws CityGmlParseException, IOException, InvalidGmlFileException { CityDoctorModel c = TestUtil.loadAndCheckCityModel("src/test/resources/SimpleSolid_SrefBS.gml"); - for (Polygon p : c.getBuildings().get(0).getGeometries().get(0).getPolygons()) { + for (Polygon p : c.getBuildings().toList().get(0).getGeometries().get(0).getPolygons()) { LinearRing r = p.getExteriorRing(); CheckResult cr = r.getCheckResult(CheckId.C_GE_R_NOT_CLOSED); assertEquals(ResultStatus.OK, cr.getResultStatus()); @@ -111,7 +111,7 @@ public class RingClosedCheckTest extends TestCleanUp { @Test public void testClosedRing5() throws CityGmlParseException, IOException, InvalidGmlFileException { CityDoctorModel c = TestUtil.loadAndCheckCityModel("src/test/resources/SimpleSolid_SrefBS-GE-gml-LR-0003-T0002.gml", 1); - for (Polygon p : c.getBuildings().get(0).getGeometries().get(0).getPolygons()) { + for (Polygon p : c.getBuildings().toList().get(0).getGeometries().get(0).getPolygons()) { LinearRing r = p.getExteriorRing(); CheckResult cr = r.getCheckResult(CheckId.C_GE_R_NOT_CLOSED); assertEquals(ResultStatus.OK, cr.getResultStatus()); diff --git a/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/systemtest/RingSelfIntersectionTest.java b/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/systemtest/RingSelfIntersectionTest.java index 9b9da948f78a732cdc34a8845c9eff50d0a0b7b0..76e04e9678c57217d1498bab03555ff071a4a200 100644 --- a/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/systemtest/RingSelfIntersectionTest.java +++ b/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/systemtest/RingSelfIntersectionTest.java @@ -101,7 +101,7 @@ public class RingSelfIntersectionTest { @Test public void testSelfIntPoints4() throws CityGmlParseException, IOException, InvalidGmlFileException { CityDoctorModel c = TestUtil.loadAndCheckCityModel("src/test/resources/SimpleSolid_SrefBS.gml"); - for (Polygon p : c.getBuildings().get(0).getGeometries().get(0).getPolygons()) { + for (Polygon p : c.getBuildings().toList().get(0).getGeometries().get(0).getPolygons()) { LinearRing r = p.getExteriorRing(); CheckResult cr = r.getCheckResult(CheckId.C_GE_R_SELF_INTERSECTION); assertEquals(ResultStatus.OK, cr.getResultStatus()); @@ -131,7 +131,7 @@ public class RingSelfIntersectionTest { @Test public void testSelfIntPoints7() throws CityGmlParseException, IOException, InvalidGmlFileException { CityDoctorModel c = TestUtil.loadAndCheckCityModel("src/test/resources/SimpleSolid_SrefBS-GE-gml-LR-0004-T0005.gml", 2); - for (Polygon p : c.getBuildings().get(0).getGeometries().get(0).getPolygons()) { + for (Polygon p : c.getBuildings().toList().get(0).getGeometries().get(0).getPolygons()) { LinearRing r = p.getExteriorRing(); CheckResult cr = r.getCheckResult(CheckId.C_GE_R_SELF_INTERSECTION); assertEquals(ResultStatus.OK, cr.getResultStatus()); diff --git a/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/systemtest/ShellNotClosedSystemTest.java b/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/systemtest/ShellNotClosedSystemTest.java index e26695bc98e1efd20b3b4a24e5bc4ca679621f65..f51002491191f94c40fc8c6c78075c8b9c45fa94 100644 --- a/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/systemtest/ShellNotClosedSystemTest.java +++ b/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/systemtest/ShellNotClosedSystemTest.java @@ -43,7 +43,7 @@ public class ShellNotClosedSystemTest { @Test public void testShellNotClosed1() throws CityGmlParseException, IOException, InvalidGmlFileException { CityDoctorModel c = TestUtil.loadAndCheckCityModel("src/test/resources/SimpleSolid_SrefBS.gml"); - Geometry g = c.getBuildings().get(0).getGeometries().get(0); + Geometry g = c.getBuildings().toList().get(0).getGeometries().get(0); CheckResult cr = g.getCheckResult(CheckId.C_GE_S_NOT_CLOSED); assertEquals(ResultStatus.OK, cr.getResultStatus()); } @@ -51,7 +51,7 @@ public class ShellNotClosedSystemTest { @Test public void testShellNotClosed2() throws CityGmlParseException, IOException, InvalidGmlFileException { CityDoctorModel c = TestUtil.loadAndCheckCityModel("src/test/resources/SimpleSolid_SrefBS-GE-gml-SO-0002-T0001.gml"); - Geometry g = c.getBuildings().get(0).getGeometries().get(0); + Geometry g = c.getBuildings().toList().get(0).getGeometries().get(0); CheckResult cr = g.getCheckResult(CheckId.C_GE_S_NOT_CLOSED); assertEquals(ResultStatus.ERROR, cr.getResultStatus()); assertEquals(ErrorId.GE_S_NOT_CLOSED, cr.getError().getErrorId()); diff --git a/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/systemtest/TestUtil.java b/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/systemtest/TestUtil.java index f1dd8d201d058926dd928d853bb6ebd597ed94aa..48e82e8da7de8706294bfe7d1a34c7d14c7ddb5a 100644 --- a/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/systemtest/TestUtil.java +++ b/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/systemtest/TestUtil.java @@ -22,6 +22,7 @@ import java.io.IOException; import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.Optional; import de.hft.stuttgart.citydoctor2.check.Checker; import de.hft.stuttgart.citydoctor2.check.ValidationConfiguration; @@ -89,15 +90,16 @@ public class TestUtil { if (gmlId == null) { return null; } - Polygon result = getPolygonById(gmlId, model.getBuildings()); + Polygon result = getPolygonById(gmlId, model.getBuildings().toList()); + if (result != null) { return result; } - result = getPolygonById(gmlId, model.getVegetation()); + result = getPolygonById(gmlId, model.getVegetation().toList()); if (result != null) { return result; } - return getPolygonById(gmlId, model.getTransportation()); + return getPolygonById(gmlId, model.getTransportation().toList()); } private static Polygon getPolygonById(String gmlId, List features) { @@ -136,22 +138,17 @@ public class TestUtil { if (featureId == null) { return null; } - for (CityObject co : model.getBuildings()) { - if (featureId.equals(co.getGmlId().getGmlString())) { - return co; - } + Optional result = null; + result = model.getBuildings().filter(b -> featureId.equals(b.getGmlId().toString())).findFirst(); + if (result.isPresent()){ + return result.get(); } - for (CityObject co : model.getTransportation()) { - if (featureId.equals(co.getGmlId().getGmlString())) { - return co; - } + result = model.getTransportation().filter(t-> featureId.equals(t.getGmlId().toString())).findFirst(); + if (result.isPresent()){ + return result.get(); } - for (CityObject co : model.getVegetation()) { - if (featureId.equals(co.getGmlId().getGmlString())) { - return co; - } - } - return null; - } + result = model.getVegetation().filter(t-> featureId.equals(t.getGmlId().toString())).findFirst(); + return result.orElse(null); + } } diff --git a/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/systemtest/TooFewPolygonsSystemTest.java b/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/systemtest/TooFewPolygonsSystemTest.java index 4cf0caa6bbcaf7691a942e00a674f678f9c19ca9..0bf43727b8b99291d8df8a2d6c16e25f758fa486 100644 --- a/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/systemtest/TooFewPolygonsSystemTest.java +++ b/CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/systemtest/TooFewPolygonsSystemTest.java @@ -43,7 +43,7 @@ public class TooFewPolygonsSystemTest { @Test public void testTooFewPolygons1() throws CityGmlParseException, IOException, InvalidGmlFileException { CityDoctorModel c = TestUtil.loadAndCheckCityModel("src/test/resources/SimpleSolid_SrefBS.gml"); - Geometry g = c.getBuildings().get(0).getGeometries().get(0); + Geometry g = c.getBuildings().toList().get(0).getGeometries().get(0); CheckResult cr = g.getCheckResult(CheckId.C_GE_S_TOO_FEW_POLYGONS); assertEquals(ResultStatus.OK, cr.getResultStatus()); } @@ -51,7 +51,7 @@ public class TooFewPolygonsSystemTest { @Test public void testTooFewPolygons2() throws CityGmlParseException, IOException, InvalidGmlFileException { CityDoctorModel c = TestUtil.loadAndCheckCityModel("src/test/resources/SimpleSolid_SrefBS-GE-gml-SO-0001-T0001.gml"); - Geometry g = c.getBuildings().get(0).getGeometries().get(0); + Geometry g = c.getBuildings().toList().get(0).getGeometries().get(0); CheckResult cr = g.getCheckResult(CheckId.C_GE_S_TOO_FEW_POLYGONS); assertEquals(ResultStatus.ERROR, cr.getResultStatus()); assertEquals(ErrorId.GE_S_TOO_FEW_POLYGONS, cr.getError().getErrorId()); diff --git a/CityDoctorParent/Extensions/CityDoctorAutoPro/pom.xml b/CityDoctorParent/Extensions/CityDoctorAutoPro/pom.xml index 52eb30300a1e7c9c0e4598c22aad858328aedfee..ec1f300cee9974e688d6e4f4f7c4f9b11953cd7a 100644 --- a/CityDoctorParent/Extensions/CityDoctorAutoPro/pom.xml +++ b/CityDoctorParent/Extensions/CityDoctorAutoPro/pom.xml @@ -6,7 +6,7 @@ de.hft.stuttgart CityDoctorParent - 3.17.3 + 3.18.0 ../../pom.xml CityDoctorAutoPro diff --git a/CityDoctorParent/Extensions/CityDoctorGUI/pom.xml b/CityDoctorParent/Extensions/CityDoctorGUI/pom.xml index 2b07c026a5b412210ccdb584563acf42de815420..01e74c250d42360399c1b8c6ba2c73ee5ed30856 100644 --- a/CityDoctorParent/Extensions/CityDoctorGUI/pom.xml +++ b/CityDoctorParent/Extensions/CityDoctorGUI/pom.xml @@ -6,7 +6,7 @@ de.hft.stuttgart CityDoctorParent - 3.17.3 + 3.18.0 ../../pom.xml CityDoctorGUI diff --git a/CityDoctorParent/Extensions/CityDoctorGUI/src/assembly/lin/start.sh b/CityDoctorParent/Extensions/CityDoctorGUI/src/assembly/lin/start.sh index 7066c344eb2e03374306ed7d4516f62581120c98..90ce022066ddab661b7acb4f12e3bc86ec60930c 100644 --- a/CityDoctorParent/Extensions/CityDoctorGUI/src/assembly/lin/start.sh +++ b/CityDoctorParent/Extensions/CityDoctorGUI/src/assembly/lin/start.sh @@ -1,2 +1,2 @@ -#!/bin/sh -./runtime/bin/java -classpath app/*:plugin/* de.hft.stuttgart.citydoctor2.gui.CityDoctorGUIStarter \ No newline at end of file +#! /usr/bin/env sh +java -classpath "app/*:plugin/*" de.hft.stuttgart.citydoctor2.gui.CityDoctorGUIStarter 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 23ae6271bcbd5cd62f8fde072e25fd3ad19ac852..fdfd46aa8bd4cf48fccf75346bf64936d7bd1a9d 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 @@ -11,6 +11,7 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; +import de.hft.stuttgart.citydoctor2.parser.ProgressListener; import javafx.beans.value.ChangeListener; import javafx.beans.value.ObservableValue; import javafx.scene.control.Alert; @@ -139,8 +140,6 @@ public class CheckDialog { @FXML private Label schematronFileLabel; - @FXML - private VBox zipArchiveOptionsVBox; @FXML private CheckBox streamCheckOption; @FXML @@ -161,7 +160,6 @@ public class CheckDialog { private CityDoctorController controller; private FilterPane filterPane; private MainWindow window; - private boolean zipArchiveMode; public CheckDialog(MainWindow window, Window parent, CityDoctorController controller) throws IOException { this.window = window; @@ -181,7 +179,6 @@ public class CheckDialog { } public void initialize() { - setupZipArchiveOptions(); createEnableColumn(geometricTable); createNameColumn(geometricTable); @@ -286,46 +283,6 @@ public class CheckDialog { }); } - private void setupZipArchiveOptions() { - streamCheckOption.selectedProperty().addListener(new ChangeListener() { - @Override - public void changed(ObservableValue observable, Boolean oldValue, Boolean newValue) { - streamCheckParametersVBox.setDisable(!streamCheckOption.isSelected()); - } - }); - - outputPathBtn.setOnAction(e -> { - DirectoryChooser directoryChooser = new DirectoryChooser(); - directoryChooser.setInitialDirectory(Path.of(Settings.get(Settings.LAST_OPEN_FOLDER)).getParent().toFile()); - File f = directoryChooser.showDialog(stage.getOwner()); - if (f != null) { - outputPathTextField.setText(f.getAbsolutePath()); - Settings.set(Settings.LAST_OPEN_FOLDER, f.getAbsolutePath()); - } - - - }); - - streamCheckOption.setText(Localization.getText("CheckDialog.streamCheckOption")); - streamCheckLabel.setTooltip(new Tooltip(Localization.getText("CheckDialog.streamCheckLabel"))); - outputPathLabel.setText(Localization.getText("CheckDialog.outputPathLabel")); - outputPathBtn.setText(Localization.getText("CheckDialog.outputPathBtn")); - pdfReportsOption.setText(Localization.getText("CheckDialog.pdfReportsOption")); - xmlReportsOption.setText(Localization.getText("CheckDialog.xmlReportsOption")); - - showZipArchiveOptions(false); - } - - /** - * Shows the option panel for ZIP-Archive checking and enables the ZIP-Archive checking mode for this dialog. - * - * @param enabled - */ - public void showZipArchiveOptions(boolean enabled) { - zipArchiveOptionsVBox.setDisable(!enabled); - zipArchiveOptionsVBox.setVisible(enabled); - zipArchiveMode = enabled; - } private void setupSelectButton() { selectBtn.setOnAction(ae -> { @@ -494,25 +451,13 @@ public class CheckDialog { String startingChecks = Localization.getText("CheckDialog.startingChecks"); logger.info(startingChecks); } - if (zipArchiveMode) { - Path outputPath = null; - if (streamCheckOption.isSelected()) { - if (outputPathTextField.getText().isEmpty()) { - Alert warning = new Alert(Alert.AlertType.ERROR); - warning.setTitle("Error"); - warning.setContentText(Localization.getText("CheckDialog.noPathError")); - warning.showAndWait(); - return; - } - outputPath = Path.of(outputPathTextField.getText()); - Platform.runLater(() -> progress.setProgress(ProgressIndicator.INDETERMINATE_PROGRESS)); + ProgressListener l = new ProgressListener() { + @Override + public void updateProgress(float state) { + Platform.runLater(() -> progress.setProgress(state)); } - controller.startZipFileChecks(config, progress::setProgress, streamCheckOption.isSelected(), - outputPath, pdfReportsOption.isSelected(), - xmlReportsOption.isSelected()); - } else { - controller.startChecks(config, progress::setProgress); - } + }; + controller.startChecks(config, l); if (logger.isInfoEnabled()) { String checksDone = Localization.getText("CheckDialog.checksDone"); 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 fd4320d151d592a80b308899e5d09ac3a3d691fe..3d68b2fc379bdc485c302cccebcafe16ae69f9b1 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 @@ -5,6 +5,7 @@ import de.hft.stuttgart.citydoctor2.check.Checker; import de.hft.stuttgart.citydoctor2.check.ErrorId; import de.hft.stuttgart.citydoctor2.check.ValidationConfiguration; import de.hft.stuttgart.citydoctor2.check.error.SchematronError; +import de.hft.stuttgart.citydoctor2.database.UnconnectedCache; import de.hft.stuttgart.citydoctor2.datastructure.*; import de.hft.stuttgart.citydoctor2.exceptions.CityDoctorWriteException; import de.hft.stuttgart.citydoctor2.gui.table.ErrorStat; @@ -16,15 +17,11 @@ import de.hft.stuttgart.citydoctor2.gui.tree.node.OpeningNode; import de.hft.stuttgart.citydoctor2.gui.tree.node.TopLevelCityObjectNode; import de.hft.stuttgart.citydoctor2.mapper.citygml3.GMLValidationHandler; import de.hft.stuttgart.citydoctor2.parser.*; -import de.hft.stuttgart.citydoctor2.utils.ArchivePacker; import de.hft.stuttgart.citydoctor2.utils.Localization; -import de.hft.stuttgart.citydoctor2.zip.CityGmlZipArchive; -import de.hft.stuttgart.citydoctor2.zip.CityGmlZipEntry; -import de.hft.stuttgart.citydoctor2.zip.MalformedZipFileException; +import de.hft.stuttgart.quality.adapter.types.ErrorAdapter; import javafx.application.Platform; import javafx.scene.chart.XYChart.Data; import javafx.scene.chart.XYChart.Series; -import javafx.scene.control.Alert; import javafx.scene.control.ButtonType; import javafx.scene.control.Dialog; import javafx.scene.control.TreeItem; @@ -32,22 +29,18 @@ import javafx.scene.control.TreeView; import javafx.scene.paint.Color; import javafx.stage.FileChooser; import javafx.stage.FileChooser.ExtensionFilter; -import org.apache.commons.io.FileUtils; -import org.apache.commons.io.FilenameUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.citygml4j.core.model.core.CityModel; import org.xml.sax.SAXParseException; -import java.awt.*; import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; import java.util.*; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Function; +import java.util.function.Supplier; +import java.util.stream.Stream; public class CityDoctorController { @@ -60,9 +53,7 @@ public class CityDoctorController { private CityDoctorModel model; private ParserConfiguration currentConfig; private String sourceFile; - private CityGmlZipArchive zipArchive; - private ZipEntryManager currentZipEntryManager; - private HashMap previousCheckers = null; + private Checker currentChecker; private HighlightController highlightController; @@ -77,7 +68,9 @@ public class CityDoctorController { private AtomicInteger waterChunkNr = new AtomicInteger(0); private AtomicInteger landChunkNr = new AtomicInteger(0); private AtomicInteger cityFurnitureChunkNr = new AtomicInteger(0); - private AtomicInteger genericCityObjectsChunkNr = new AtomicInteger(0); + private AtomicInteger otherCityObjectsChunkNr = new AtomicInteger(0); + + public CityDoctorController(MainWindow mainWindow, HighlightController highlightController, Renderer renderer) { this.mainWindow = mainWindow; @@ -95,7 +88,7 @@ public class CityDoctorController { try { Platform.runLater(() -> { mainWindow.getOpenBtn().setDisable(true); - mainWindow.getZipManagerBtn().setDisable(true); + mainWindow.getWriteReportButton().setDisable(true); mainWindow.getMeshGroup().getChildren().clear(); @@ -103,12 +96,6 @@ public class CityDoctorController { mainWindow.resetSearchBar(); mainWindow.resetFilterComboBox(); }); - if (path.endsWith(".zip")) { - loadCityGmlZipFile(path, numberOfRoundingPlaces, useValidation, lowMemory); - return; - } - currentZipEntryManager = null; - previousCheckers = null; currentChecker = null; currentConfig = new ParserConfiguration(numberOfRoundingPlaces, useValidation, lowMemory); GMLValidationHandler handler = null; @@ -135,7 +122,7 @@ public class CityDoctorController { } }; } - model = CityGmlParser.parseCityGmlFile(path, currentConfig, l, handler, true); + model = CityGmlParser.parseCityGmlFile(path, currentConfig, l, handler); if (!validationIssues.isEmpty()) { StringJoiner sj = new StringJoiner("\n"); validationIssues.stream().forEach(sj::add); @@ -155,120 +142,30 @@ public class CityDoctorController { mainWindow.getSaveBtn().setDisable(false); mainWindow.getResetCameraBtn().setDisable(false); mainWindow.getHideRoofBtn().setDisable(false); - mainWindow.getZipManagerBtn().setDisable(true); - mainWindow.getNorthArrow().setVisible(true); - mainWindow.alignNorthArrow(); - setupFeatureTabs(); - buildTrees(); - }); - } finally { - Platform.runLater(() -> mainWindow.getOpenBtn().setDisable(false)); - } - } - - private void loadCityGmlZipFile(String path, int numberOfRoundingPlaces, boolean useValidation, - boolean lowMemory) { - - currentConfig = new ParserConfiguration(numberOfRoundingPlaces, useValidation, lowMemory); - try { - zipArchive = CityGmlZipArchive.register(path); - } catch (MalformedZipFileException e) { - Platform.runLater(() -> { - Alert alert = new Alert(Alert.AlertType.ERROR, e.getMessage()); - alert.showAndWait(); - }); - } catch (Exception e) { - Platform.runLater(() -> { - ExceptionDialog exDialog = new ExceptionDialog(); - exDialog.show(e); - }); - } - - if (zipArchive != null) { - previousCheckers = new HashMap<>(); - Platform.runLater(() -> { - try { - currentZipEntryManager = new ZipEntryManager(mainWindow.getMainStage(), this); - currentZipEntryManager.show(); - } catch (IOException e) { - throw new RuntimeException(e); - } - }); - } - } - - public void decompressZipEntry(CityGmlZipEntry entry, ProgressListener l) { - entry.loadEntry(currentConfig, l); - } - - public CityGmlZipArchive getZipArchive() { - return zipArchive; - } - - public void loadZipEntry(CityGmlZipEntry entry) { - if (!entry.isLoaded()) { - entry.loadEntry(currentConfig); - } - if (entry.getErrorType() != null) { - throw new IllegalArgumentException("Attempted to load erroneous zip entry"); - } - try { - Platform.runLater(() -> { - mainWindow.getOpenBtn().setDisable(true); - mainWindow.getZipManagerBtn().setDisable(true); - mainWindow.getWriteReportButton().setDisable(true); - mainWindow.getMeshGroup().getChildren().clear(); - clearTrees(); - mainWindow.resetSearchBar(); - mainWindow.resetFilterComboBox(); - }); - - - model = entry.getModel(); - currentChecker = previousCheckers.getOrDefault(model, null); - mainWindow.getClickHandler().setConfig(currentConfig); - sourceFile = entry.getArchive().getArchivePath().toString(); - renderer.reset(); - - Platform.runLater(() -> { - mainWindow.addFileNameToTitle(entry.getArchive().getArchivePath().toString()); - mainWindow.getCheckButton().setDisable(false); - mainWindow.getLod1Btn().setDisable(false); - mainWindow.getLod2Btn().setDisable(false); - mainWindow.getLod3Btn().setDisable(false); - mainWindow.getLod4Btn().setDisable(false); - mainWindow.getWorldBtn().setDisable(false); - mainWindow.getSaveBtn().setDisable(false); - mainWindow.getResetCameraBtn().setDisable(false); - mainWindow.getHideRoofBtn().setDisable(false); - mainWindow.getZipManagerBtn().setDisable(false); mainWindow.getNorthArrow().setVisible(true); mainWindow.alignNorthArrow(); setupFeatureTabs(); buildTrees(); - updateFeatureTrees(); - mainWindow.getWriteReportButton().setDisable(currentChecker == null); }); } finally { Platform.runLater(() -> mainWindow.getOpenBtn().setDisable(false)); } - } - public void showZipManager() { - Platform.runLater(() -> currentZipEntryManager.show()); + public static int getMaxFeaturesPerChunk(){ + return MAX_FEATURES_PER_CHUNK; } private void setupFeatureTabs() { - mainWindow.setDisableOfFeatureTab(FeatureType.BUILDING, model.getBuildings().isEmpty()); - mainWindow.setDisableOfFeatureTab(FeatureType.VEGETATION, model.getVegetation().isEmpty()); - mainWindow.setDisableOfFeatureTab(FeatureType.TRANSPORTATION, model.getTransportation().isEmpty()); - mainWindow.setDisableOfFeatureTab(FeatureType.TUNNEL, model.getTunnels().isEmpty()); - mainWindow.setDisableOfFeatureTab(FeatureType.BRIDGE, model.getBridges().isEmpty()); - mainWindow.setDisableOfFeatureTab(FeatureType.WATER, model.getWater().isEmpty()); - mainWindow.setDisableOfFeatureTab(FeatureType.LAND, model.getLand().isEmpty()); - mainWindow.setDisableOfFeatureTab(FeatureType.CITY_FURNITURE, model.getCityFurniture().isEmpty()); - mainWindow.setDisableOfFeatureTab(FeatureType.GENERIC_CITY_OBJECT, model.getGenericCityObjects().isEmpty()); + mainWindow.setDisableOfFeatureTab(FeatureType.BUILDING, model.getBuildingCount() == 0); + mainWindow.setDisableOfFeatureTab(FeatureType.VEGETATION, model.getVegetationCount() == 0); + mainWindow.setDisableOfFeatureTab(FeatureType.TRANSPORTATION, model.getTransportationCount() == 0); + mainWindow.setDisableOfFeatureTab(FeatureType.TUNNEL, model.getTunnelCount() == 0); + mainWindow.setDisableOfFeatureTab(FeatureType.BRIDGE, model.getBridgeCount() == 0); + mainWindow.setDisableOfFeatureTab(FeatureType.WATER, model.getWaterCount() == 0); + mainWindow.setDisableOfFeatureTab(FeatureType.LAND, model.getLandCount() == 0); + mainWindow.setDisableOfFeatureTab(FeatureType.CITY_FURNITURE, model.getCityFurnitureCount() == 0); + mainWindow.setDisableOfFeatureTab(FeatureType.OTHER_CITY_OBJECT, model.getOtherCityObjectsCount() == 0); } public void buildTrees() { @@ -281,7 +178,7 @@ public class CityDoctorController { buildWater(model); buildLand(model); buildCityFurniture(model); - buildOtherCityObjects(model); + buildGenericCityObjects(model); buildTunnel(model); } @@ -294,126 +191,134 @@ public class CityDoctorController { waterChunkNr.set(0); landChunkNr.set(0); cityFurnitureChunkNr.set(0); - genericCityObjectsChunkNr.set(0); + otherCityObjectsChunkNr.set(0); } private void buildLand(CityDoctorModel model) { - if (model.getLand().isEmpty()) { + if (model.getLandCount() == 0) { return; } TreeView landView = mainWindow.getTerrainView(); - TreeItem landRoot = new TreeItem<>(new CityObjectGroupNode(model.getLand(), "Land", + TreeItem landRoot = new TreeItem<>(new CityObjectGroupNode(Collections.emptyList(), "Land", Color.BROWN)); landRoot.setExpanded(true); landView.setRoot(landRoot); - buildLandFromList(model.getLand(), landView.getRoot()); - addMoreButtonIfNecessary(model.getLand(), landView, landRoot, landChunkNr); + Supplier> supply = model::getLand; + buildLandTreeFromList(supply, landView.getRoot()); + addMoreButtonForLand(landView, landRoot, landChunkNr, supply, model.getLandCount()); } - private void buildLandFromList(List list, TreeItem root) { + private void buildLandTreeFromList(Supplier> supply, TreeItem root) { int landChunk = landChunkNr.get(); - for (int i = landChunk * MAX_FEATURES_PER_CHUNK; i < (landChunk + 1) * MAX_FEATURES_PER_CHUNK - && i < list.size(); i++) { - CityObject land = list.get(i); + supply.get().skip((long) landChunk * MAX_FEATURES_PER_CHUNK).limit(MAX_FEATURES_PER_CHUNK).forEach(land ->{ CityObjectNode node = new CityObjectNode(land); TreeItem item = new TreeItem<>(node); item.setExpanded(true); root.getChildren().add(item); createGeometryNodes(land, item); - - } + }); } private void buildCityFurniture(CityDoctorModel model) { - if (model.getCityFurniture().isEmpty()) { + if (model.getCityFurnitureCount() == 0) { return; } TreeView cityFurnitureView = mainWindow.getCityFurnitureView(); - TreeItem cityFurnitureRoot = new TreeItem<>(new CityObjectGroupNode(model.getCityFurniture(), + TreeItem cityFurnitureRoot = new TreeItem<>(new CityObjectGroupNode(Collections.emptyList(), "City Furniture", Color.BLUEVIOLET)); cityFurnitureRoot.setExpanded(true); cityFurnitureView.setRoot(cityFurnitureRoot); - buildCityFurnitureTreeFromList(model.getCityFurniture(), cityFurnitureView.getRoot()); - addMoreButtonIfNecessary(model.getCityFurniture(), cityFurnitureView, cityFurnitureRoot, cityFurnitureChunkNr); + Supplier> supply = model::getCityFurniture; + buildCityFurnitureTreeFromList(supply, cityFurnitureView.getRoot()); + addMoreButtonForCityFurniture(cityFurnitureView, cityFurnitureRoot, cityFurnitureChunkNr, supply, + model.getCityFurnitureCount()); } - private void buildOtherCityObjects(CityDoctorModel model) { - if (model.getGenericCityObjects().isEmpty()) { + private void buildGenericCityObjects(CityDoctorModel model) { + if (model.getOtherCityObjectsCount() == 0) { return; } - TreeView otherObjectsView = mainWindow.getGenericCityObjectView(); - TreeItem otherObjectsRoot = new TreeItem<>(new CityObjectGroupNode(model.getGenericCityObjects(), + TreeView otherObjectsView = mainWindow.getOtherCityObjectView(); + TreeItem otherObjectsRoot = new TreeItem<>(new CityObjectGroupNode(Collections.emptyList(), "Generic CityObjects", Color.DARKGRAY)); otherObjectsRoot.setExpanded(true); otherObjectsView.setRoot(otherObjectsRoot); - buildGenericCityObjectTreeFromList(model.getGenericCityObjects(), otherObjectsView.getRoot()); - addMoreButtonIfNecessary(model.getGenericCityObjects(), otherObjectsView, otherObjectsRoot, genericCityObjectsChunkNr); + Supplier> supply = model::getOtherCityObjects; + buildOtherCityObjectsTreeFromList(supply, otherObjectsView.getRoot()); + addMoreButtonForOtherCityObjects( otherObjectsView, otherObjectsRoot, otherCityObjectsChunkNr, supply, + model.getOtherCityObjectsCount()); } private void buildWater(CityDoctorModel model) { - if (model.getWater().isEmpty()) { + if (model.getWaterCount() == 0) { return; } TreeView waterView = mainWindow.getWaterView(); - TreeItem waterRoot = new TreeItem<>(new CityObjectGroupNode(model.getWater(), "Water", + TreeItem waterRoot = new TreeItem<>(new CityObjectGroupNode(Collections.emptyList(), "Water", Color.LIGHTSKYBLUE)); waterRoot.setExpanded(true); waterView.setRoot(waterRoot); - buildWaterTreeFromList(model.getWater(), waterRoot); - addMoreButtonIfNecessary(model.getWater(), waterView, waterRoot, waterChunkNr); + Supplier> supply = model::getWater; + buildWaterTreeFromList(supply, waterRoot); + addMoreButtonForWater(waterView, waterRoot, waterChunkNr, supply, model.getWaterCount()); } private void buildBridges(CityDoctorModel model) { - if (model.getBridges().isEmpty()) { + if (model.getBridgeCount() == 0) { return; } TreeView bridgeView = mainWindow.getBridgeView(); - TreeItem bridgeRoot = new TreeItem<>(new CityObjectGroupNode(model.getBridges(), "Bridges", + TreeItem bridgeRoot = new TreeItem<>(new CityObjectGroupNode(Collections.emptyList(), "Bridges", Color.CORAL)); bridgeRoot.setExpanded(true); bridgeView.setRoot(bridgeRoot); - buildBridgeTreeFromList(model.getBridges(), bridgeView.getRoot()); - addMoreButtonIfNecessary(model.getBridges(), bridgeView, bridgeRoot, bridgeChunkNr); + Supplier> supply = model::getBridges; + buildBridgeTreeFromList(supply, bridgeView.getRoot()); + addMoreButtonForBridges(bridgeView, bridgeRoot, bridgeChunkNr, supply, model.getBridgeCount()); } private void buildTransportation(CityDoctorModel model) { - if (model.getTransportation().isEmpty()) { + if (model.getTransportationCount() == 0) { return; } TreeView transView = mainWindow.getTransportationView(); - TreeItem transRoot = new TreeItem<>(new CityObjectGroupNode(model.getTransportation(), + TreeItem transRoot = new TreeItem<>(new CityObjectGroupNode(Collections.emptyList(), "Transportation", Color.YELLOW)); transRoot.setExpanded(true); transView.setRoot(transRoot); - buildTransportationTreeFromList(model.getTransportation(), transView.getRoot()); - addMoreButtonIfNecessary(model.getTransportation(), transView, transRoot, transportationChunkNr); + Supplier> supply = model::getTransportation; + buildTransportationTreeFromList(supply, transView.getRoot()); + addMoreButtonForTransportation(transView, transRoot, transportationChunkNr, supply, + model.getTransportationCount()); } private void buildTunnel(CityDoctorModel model) { - if (model.getTunnels().isEmpty()) { + if (model.getTunnelCount() == 0) { return; } TreeView tunnelView = mainWindow.getTunnelView(); - TreeItem tunnelRoot = new TreeItem<>(new CityObjectGroupNode(model.getTunnels(), "Tunnel", + TreeItem tunnelRoot = new TreeItem<>(new CityObjectGroupNode(Collections.emptyList(), "Tunnel", Color.SLATEGRAY)); tunnelRoot.setExpanded(true); tunnelView.setRoot(tunnelRoot); - buildTunnelTreeFromList(model.getTunnels(), tunnelRoot); - addMoreButtonIfNecessary(model.getTunnels(), tunnelView, tunnelRoot, tunnelChunkNr); + Supplier> supply = model::getTunnels; + buildTunnelTreeFromList(supply, tunnelRoot); + addMoreButtonForTunnel(tunnelView, tunnelRoot, tunnelChunkNr, supply, model.getTunnelCount()); } private void buildVegetation(CityDoctorModel model) { - if (model.getVegetation().isEmpty()) { + if (model.getVegetationCount() == 0) { return; } TreeView vegetationsView = mainWindow.getVegetationView(); - TreeItem vegRoot = new TreeItem<>(new CityObjectGroupNode(model.getVegetation(), + TreeItem vegRoot = new TreeItem<>(new CityObjectGroupNode(Collections.emptyList(), "Vegetation", Color.LIGHTGREEN)); vegRoot.setExpanded(true); vegetationsView.setRoot(vegRoot); - buildVegetationTreeFromList(model.getVegetation(), vegRoot); - addMoreButtonIfNecessary(model.getVegetation(), vegetationsView, vegRoot, vegetationChunkNr); + Supplier> supply = model::getVegetation; + buildVegetationTreeFromList(supply, vegRoot); + addMoreButtonForVegetation(vegetationsView, vegRoot, vegetationChunkNr, supply, model.getVegetationCount()); } private void addMoreButtonIfNecessary(List list, TreeView view, @@ -429,7 +334,7 @@ public class CityDoctorController { chunkCounter.incrementAndGet(); int visibleFeatures = countVisibleNodes(view); - buildTreeFromList(list, root, chunkCounter); +// buildTreeFromList(list, root, chunkCounter); updateTree(root); if (selectedIndex >= 0) { view.getSelectionModel().select(selectedIndex); @@ -445,17 +350,34 @@ public class CityDoctorController { } } + private void moreButton(CityDoctorModel model, TreeView view, TreeItem root, + AtomicInteger chunkCounter, Supplier> streamSupplier){ + int featureCount = model.getBuildingCount(); + if ((chunkCounter.get() + 1) * MAX_FEATURES_PER_CHUNK < featureCount) { + AddMoreButtonRunnable run = new AddMoreButtonRunnable(featureCount, view, root, chunkCounter) { + @Override + public void buildNodeTreeCall() { + buildTreeFromList(streamSupplier, root, chunkCounter); + updateTree(root); + } + }; + //add button + root.getChildren().add(new TreeItem<>(new ButtonRenderable(run))); + } + } + private void buildBuildings(CityDoctorModel model) { - if (model.getBuildings().isEmpty()) { + if (model.getBuildingCount() == 0) { return; } TreeView buildingsView = mainWindow.getBuildingsView(); - TreeItem root = new TreeItem<>(new CityObjectGroupNode(model.getBuildings(), "Buildings", + TreeItem root = new TreeItem<>(new CityObjectGroupNode(Collections.emptyList(), "Buildings", Color.WHITE)); root.setExpanded(true); buildingsView.setRoot(root); - buildBuildingTreeFromList(model.getBuildings(), root); - addMoreButtonToBuildingsIfNecessary(model.getBuildings(), buildingsView, root, buildingChunkNr); + Supplier> supply = model::getBuildings; + buildBuildingTreeFromList(supply, root); + addMoreButtonForBuildings(buildingsView, root, buildingChunkNr, supply, model.getBuildingCount()); } @@ -471,7 +393,7 @@ public class CityDoctorController { root.getChildren().remove(root.getChildren().size() - 1); chunkCounter.getAndIncrement(); int visibleFeatures = countVisibleNodes(view); - buildBuildingTreeFromList(list, root); +// buildBuildingTreeFromList(list, root); updateTree(root); if (selectedIndex >= 0) { view.getSelectionModel().select(selectedIndex); @@ -487,6 +409,141 @@ public class CityDoctorController { } } + private void addMoreButtonForBuildings(TreeView view, TreeItem root, + AtomicInteger chunkCounter, Supplier> supply, int featureCount) { + if ((chunkCounter.get() + 1) * MAX_FEATURES_PER_CHUNK < featureCount) { + AddMoreButtonRunnable run = new AddMoreButtonRunnable(featureCount, view, root, chunkCounter) { + @Override + public void buildNodeTreeCall() { + buildBuildingTreeFromList(supply, root); + updateTree(root); + } + }; + //add button + root.getChildren().add(new TreeItem<>(new ButtonRenderable(run))); + } + } + + private void addMoreButtonForBridges(TreeView view, TreeItem root, + AtomicInteger chunkCounter, Supplier> supply, int featureCount){ + if ((chunkCounter.get() + 1) * MAX_FEATURES_PER_CHUNK < featureCount) { + AddMoreButtonRunnable run = new AddMoreButtonRunnable(featureCount, view, root, chunkCounter) { + @Override + public void buildNodeTreeCall() { + buildBridgeTreeFromList(supply, root); + updateTree(root); + } + }; + //add button + root.getChildren().add(new TreeItem<>(new ButtonRenderable(run))); + } + } + + private void addMoreButtonForVegetation(TreeView view, TreeItem root, + AtomicInteger chunkCounter, Supplier> supply, int featureCount){ + if ((chunkCounter.get() + 1) * MAX_FEATURES_PER_CHUNK < featureCount) { + AddMoreButtonRunnable run = new AddMoreButtonRunnable(featureCount, view, root, chunkCounter) { + @Override + public void buildNodeTreeCall() { + buildVegetationTreeFromList(supply, root); + updateTree(root); + } + }; + //add button + root.getChildren().add(new TreeItem<>(new ButtonRenderable(run))); + } + } + + private void addMoreButtonForTunnel(TreeView view, TreeItem root, + AtomicInteger chunkCounter, Supplier> supply, int featureCount){ + if ((chunkCounter.get() + 1) * MAX_FEATURES_PER_CHUNK < featureCount) { + AddMoreButtonRunnable run = new AddMoreButtonRunnable(featureCount, view, root, chunkCounter) { + @Override + public void buildNodeTreeCall() { + buildTunnelTreeFromList(supply, root); + updateTree(root); + } + }; + //add button + root.getChildren().add(new TreeItem<>(new ButtonRenderable(run))); + } + } + + private void addMoreButtonForTransportation(TreeView view, TreeItem root, + AtomicInteger chunkCounter, Supplier> supply, int featureCount){ + if ((chunkCounter.get() + 1) * MAX_FEATURES_PER_CHUNK < featureCount) { + AddMoreButtonRunnable run = new AddMoreButtonRunnable(featureCount, view, root, chunkCounter) { + @Override + public void buildNodeTreeCall() { + buildTransportationTreeFromList(supply, root); + updateTree(root); + } + }; + //add button + root.getChildren().add(new TreeItem<>(new ButtonRenderable(run))); + } + } + + private void addMoreButtonForLand(TreeView view, TreeItem root, + AtomicInteger chunkCounter, Supplier> supply, int featureCount){ + if ((chunkCounter.get() + 1) * MAX_FEATURES_PER_CHUNK < featureCount) { + AddMoreButtonRunnable run = new AddMoreButtonRunnable(featureCount, view, root, chunkCounter) { + @Override + public void buildNodeTreeCall() { + buildLandTreeFromList(supply, root); + updateTree(root); + } + }; + //add button + root.getChildren().add(new TreeItem<>(new ButtonRenderable(run))); + } + } + + private void addMoreButtonForWater(TreeView view, TreeItem root, + AtomicInteger chunkCounter, Supplier> supply, int featureCount){ + if ((chunkCounter.get() + 1) * MAX_FEATURES_PER_CHUNK < featureCount) { + AddMoreButtonRunnable run = new AddMoreButtonRunnable(featureCount, view, root, chunkCounter) { + @Override + public void buildNodeTreeCall() { + buildWaterTreeFromList(supply, root); + updateTree(root); + } + }; + //add button + root.getChildren().add(new TreeItem<>(new ButtonRenderable(run))); + } + } + + private void addMoreButtonForCityFurniture(TreeView view, TreeItem root, + AtomicInteger chunkCounter, Supplier> supply, int featureCount){ + if ((chunkCounter.get() + 1) * MAX_FEATURES_PER_CHUNK < featureCount) { + AddMoreButtonRunnable run = new AddMoreButtonRunnable(featureCount, view, root, chunkCounter) { + @Override + public void buildNodeTreeCall() { + buildCityFurnitureTreeFromList(supply, root); + updateTree(root); + } + }; + //add button + root.getChildren().add(new TreeItem<>(new ButtonRenderable(run))); + } + } + + private void addMoreButtonForOtherCityObjects(TreeView view, TreeItem root, + AtomicInteger chunkCounter, Supplier> supply, int featureCount){ + if ((chunkCounter.get() + 1) * MAX_FEATURES_PER_CHUNK < featureCount) { + AddMoreButtonRunnable run = new AddMoreButtonRunnable(featureCount, view, root, chunkCounter) { + @Override + public void buildNodeTreeCall() { + buildOtherCityObjectsTreeFromList(supply, root); + updateTree(root); + } + }; + //add button + root.getChildren().add(new TreeItem<>(new ButtonRenderable(run))); + } + } + private static int countVisibleNodes(TreeView view) { return countVisibleNodes(view.getRoot()) + 1; } @@ -501,17 +558,16 @@ public class CityDoctorController { return visibleFeatures; } - private void buildTreeFromList(List cos, TreeItem root, + private void buildTreeFromList(Supplier> supply, TreeItem root, AtomicInteger chunkCounter) { - int chunk = chunkCounter.get(); - for (int i = chunk * MAX_FEATURES_PER_CHUNK; i < (chunk + 1) * MAX_FEATURES_PER_CHUNK && i < cos.size(); i++) { - CityObject co = cos.get(i); + int buildingChunk = buildingChunkNr.get(); + supply.get().skip((long) buildingChunk * MAX_FEATURES_PER_CHUNK).limit(MAX_FEATURES_PER_CHUNK).forEach(co ->{ CityObjectNode node = new CityObjectNode(co); TreeItem nodeItem = new TreeItem<>(node); nodeItem.setExpanded(true); root.getChildren().add(nodeItem); createGeometryNodes(co, nodeItem); - } + }); } private void buildTreeFromListWithProducer(List cos, TreeItem root, @@ -535,7 +591,7 @@ public class CityDoctorController { mainWindow.getWaterView().setRoot(null); mainWindow.getTerrainView().setRoot(null); mainWindow.getCityFurnitureView().setRoot(null); - mainWindow.getGenericCityObjectView().setRoot(null); + mainWindow.getOtherCityObjectView().setRoot(null); mainWindow.getErrorTree().getRoot().getChildren().clear(); mainWindow.getAttributeView().getRoot().getChildren().clear(); mainWindow.getGlobalErrorsView().getItems().clear(); @@ -582,11 +638,9 @@ public class CityDoctorController { return nodeItem; } - private void buildBuildingTreeFromList(List list, TreeItem root) { + private void buildBuildingTreeFromList(Supplier> supply, TreeItem root) { int buildingChunk = buildingChunkNr.get(); - for (int i = buildingChunk * MAX_FEATURES_PER_CHUNK; i < (buildingChunk + 1) * MAX_FEATURES_PER_CHUNK - && i < list.size(); i++) { - Building b = list.get(i); + supply.get().skip((long) buildingChunk * MAX_FEATURES_PER_CHUNK).limit(MAX_FEATURES_PER_CHUNK).forEach(b ->{ TreeItem item = buildTopLevelCityObjectNode(b, root, b.getBoundarySurfaces()); createBuildingInstallationNodes(b, item); @@ -596,14 +650,12 @@ public class CityDoctorController { createBuildingStoreyNodes(b, item); createBuildingUnitNodes(b, item); createBuildingPartNodes(b, item); - } + }); } - private void buildBridgeTreeFromList(List list, TreeItem root) { + private void buildBridgeTreeFromList(Supplier> supply, TreeItem root) { int bridgeChunk = bridgeChunkNr.get(); - for (int i = bridgeChunk * MAX_FEATURES_PER_CHUNK; i < (bridgeChunk + 1) * MAX_FEATURES_PER_CHUNK - && i < list.size(); i++) { - BridgeObject bridge = list.get(i); + supply.get().skip((long) bridgeChunk * MAX_FEATURES_PER_CHUNK).limit(MAX_FEATURES_PER_CHUNK).forEach(bridge ->{ TreeItem item = buildTopLevelCityObjectNode(bridge, root, bridge.getBoundarySurfaces()); createBridgeRoomNodes(bridge, item); @@ -611,55 +663,46 @@ public class CityDoctorController { createBridgeFurnitureNodes(bridge, item); createBridgeConstructiveElementsNodes(bridge, item); createBridgePartNodes(bridge, item); - } + }); } - private void buildTransportationTreeFromList(List list, TreeItem root) { + private void buildTransportationTreeFromList(Supplier> supply, TreeItem root) { int transportChunk = transportationChunkNr.get(); - for (int i = transportChunk * MAX_FEATURES_PER_CHUNK; i < (transportChunk + 1) * MAX_FEATURES_PER_CHUNK - && i < list.size(); i++) { - TransportationObject t = list.get(i); - TreeItem item = buildTopLevelCityObjectNode(t, root); - createTransportSectionNodes(t, item); - createTrafficSpacesNodes(t, item); - } + supply.get().skip((long) transportChunk * MAX_FEATURES_PER_CHUNK).limit(MAX_FEATURES_PER_CHUNK).forEach(trans ->{ + TreeItem item = buildTopLevelCityObjectNode(trans, root); + createTransportSectionNodes(trans, item); + createTrafficSpacesNodes(trans, item); + }); } - private void buildVegetationTreeFromList(List list, TreeItem root) { + private void buildVegetationTreeFromList(Supplier> supply, TreeItem root) { int vegetationChunk = vegetationChunkNr.get(); - for (int i = vegetationChunk * MAX_FEATURES_PER_CHUNK; i < (vegetationChunk + 1) * MAX_FEATURES_PER_CHUNK - && i < list.size(); i++) { - Vegetation v = list.get(i); - buildTopLevelCityObjectNode(v, root); - } + supply.get().skip((long) vegetationChunk * MAX_FEATURES_PER_CHUNK).limit(MAX_FEATURES_PER_CHUNK).forEach(veg ->{ + buildTopLevelCityObjectNode(veg, root); + }); + } - private void buildWaterTreeFromList(List list, TreeItem root) { + private void buildWaterTreeFromList(Supplier> supply, TreeItem root) { int waterChunk = waterChunkNr.get(); - for (int i = waterChunk * MAX_FEATURES_PER_CHUNK; i < (waterChunk + 1) * MAX_FEATURES_PER_CHUNK - && i < list.size(); i++) { - WaterObject w = list.get(i); - buildTopLevelCityObjectNode(w, root); - } + supply.get().skip((long) waterChunk * MAX_FEATURES_PER_CHUNK).limit(MAX_FEATURES_PER_CHUNK).forEach(wat ->{ + buildTopLevelCityObjectNode(wat, root); + }); } - private void buildCityFurnitureTreeFromList(List list, TreeItem root) { + private void buildCityFurnitureTreeFromList(Supplier> supply, TreeItem root) { int cityFurnChunk = cityFurnitureChunkNr.get(); - for (int i = cityFurnChunk * MAX_FEATURES_PER_CHUNK; i < (cityFurnChunk + 1) * MAX_FEATURES_PER_CHUNK - && i < list.size(); i++) { - CityFurniture cf = list.get(i); + supply.get().skip((long) cityFurnChunk * MAX_FEATURES_PER_CHUNK).limit(MAX_FEATURES_PER_CHUNK).forEach(cf ->{ buildTopLevelCityObjectNode(cf, root); - } + }); } - private void buildGenericCityObjectTreeFromList(List list, TreeItem root) { - int genericObjectChunk = genericCityObjectsChunkNr.get(); - for (int i = genericObjectChunk * MAX_FEATURES_PER_CHUNK; i < (genericObjectChunk + 1) * MAX_FEATURES_PER_CHUNK - && i < list.size(); i++) { - GenericCityObject goc = list.get(i); - buildTopLevelCityObjectNode(goc, root); - } + private void buildOtherCityObjectsTreeFromList(Supplier> supply, TreeItem root) { + int genericObjectChunk = otherCityObjectsChunkNr.get(); + supply.get().skip((long) genericObjectChunk * MAX_FEATURES_PER_CHUNK).limit(MAX_FEATURES_PER_CHUNK).forEach(gen ->{ + buildTopLevelCityObjectNode(gen, root); + }); } private void createTransportSectionNodes(TransportationObject t, TreeItem root) { @@ -733,10 +776,9 @@ public class CityDoctorController { } - private void buildTunnelTreeFromList(List list, TreeItem root) { + private void buildTunnelTreeFromList(Supplier> supply, TreeItem root) { int tunnelChunk = tunnelChunkNr.get(); - for (int i = tunnelChunk * MAX_FEATURES_PER_CHUNK; i < (tunnelChunk + 1) * MAX_FEATURES_PER_CHUNK && i < list.size(); i++) { - Tunnel tunnel = list.get(i); + supply.get().skip((long) tunnelChunk * MAX_FEATURES_PER_CHUNK).limit(MAX_FEATURES_PER_CHUNK).forEach(tunnel ->{ TreeItem item = buildTopLevelCityObjectNode(tunnel, root); createTunnelHollowNodes(tunnel, item); @@ -744,7 +786,8 @@ public class CityDoctorController { createTunnelFurnitureNodes(tunnel, item); createTunnelConstructiveElementsNodes(tunnel, item); createTunnelPartNodes(tunnel, item); - } + }); + } private void createTunnelInstallationNodes(Tunnel tunnel, TreeItem root) { @@ -1035,20 +1078,14 @@ public class CityDoctorController { config.setNumberOfRoundingPlacesInGlobalParameters(currentConfig.getNumberOfRoundingPlaces()); config.setParserConfig(currentConfig); currentChecker = new Checker(config, model); - if (previousCheckers != null) { - previousCheckers.put(model, currentChecker); - } currentChecker.runChecks(l); Platform.runLater(() -> { // apply check results to tree views + buildTrees(); updateFeatureTrees(); updateTree(mainWindow.getPolygonsView().getRoot()); - for (CheckError e : model.getGlobalErrors()) { - if (e instanceof SchematronError se) { - mainWindow.getGlobalErrorsView().getItems().add(se.getErrorIdString() + " - " + se.getNameOfAttribute()); - } - } + updateGlobalErrors(); renderer.refresh(); mainWindow.getWriteReportButton().setDisable(false); }); @@ -1057,134 +1094,10 @@ public class CityDoctorController { } } - public void startZipFileChecks(ValidationConfiguration config, ProgressListener l, boolean lowMemoryMode, - Path outputPath, boolean pdfReports, boolean xmlReports) { - if (zipArchive == null && logger.isWarnEnabled()) { - logger.warn(Localization.getText("CityDoctorController.noZipFile")); - } - - if (lowMemoryMode) { - startZipFileCheckStream(config, outputPath, pdfReports, xmlReports); - return; - } - try { - Platform.runLater(() -> { - mainWindow.getCheckButton().setDisable(true); - mainWindow.getErrorTree().getRoot().getChildren().clear(); - mainWindow.getGlobalErrorsView().getItems().clear(); - }); - previousCheckers = new HashMap<>(); - zipArchive.mountArchive(currentConfig); - config.setNumberOfRoundingPlacesInGlobalParameters(currentConfig.getNumberOfRoundingPlaces()); - config.setParserConfig(currentConfig); - int totalEntries = zipArchive.getEntries().size(); - int checkedEntries = 0; - for (CityGmlZipEntry entry : zipArchive.getEntries()) { - if (entry.getErrorType() != null && entry.getModel() == null) { - continue; - } - model = entry.getModel(); - currentChecker = new Checker(config, model); - currentChecker.runChecks(); - previousCheckers.put(model, currentChecker); - checkedEntries++; - if (l != null) { - l.updateProgress((float) checkedEntries / totalEntries); - } - - } - Platform.runLater(() -> { - // apply check results to tree views - updateFeatureTrees(); - updateTree(mainWindow.getPolygonsView().getRoot()); - for (CheckError e : model.getGlobalErrors()) { - if (e instanceof SchematronError se) { - mainWindow.getGlobalErrorsView().getItems().add(se.getErrorIdString() + " - " + se.getNameOfAttribute()); - } - } - renderer.refresh(); - mainWindow.getWriteReportButton().setDisable(false); - currentZipEntryManager.refresh(); - }); - } finally { - Platform.runLater(() -> mainWindow.getCheckButton().setDisable(false)); - } - - } - - private void startZipFileCheckStream(ValidationConfiguration valConfig, Path outputPath, boolean pdfReports, - boolean xmlReports) { - try { - Path outputZipDirectory = null; - if (outputPath.toFile().isDirectory()) { - - String filename = FilenameUtils.removeExtension(zipArchive.getArchivePath().getFileName().toString()); - filename = filename + "_validated"; - outputZipDirectory = outputPath.resolve(filename); - Files.createDirectories(outputZipDirectory); - } else { - String filename = FilenameUtils.removeExtension(outputPath.toAbsolutePath().getFileName().toString()); - outputZipDirectory = Path.of(filename); - } - - String xmlReportsDirectory = null; - String pdfReportsDirectory = null; - if (xmlReports) { - xmlReportsDirectory = Files.createDirectories( - outputZipDirectory.resolve("xml_reports/")).toAbsolutePath().toString(); - } - if (pdfReports) { - pdfReportsDirectory = Files.createDirectories( - outputZipDirectory.resolve("pdf_reports/")).toAbsolutePath().toString(); - } - Checker.streamCheck(zipArchive, xmlReportsDirectory, pdfReportsDirectory, valConfig, outputZipDirectory.toString()); - Desktop desktop = Desktop.getDesktop(); - desktop.open(outputPath.toFile()); - } catch (CityGmlParseException e) { - throw new RuntimeException(e); - } catch (IOException e) { - throw new RuntimeException(e); - } - - } - - public void saveZipArchiveReports(File outputZipDirectory) { - if (zipArchive == null) { - return; - } - String directoryName = FilenameUtils.removeExtension(outputZipDirectory.getAbsolutePath()); - Path tempOutput = Path.of(directoryName + File.separator); - File temp = null; - try { - temp = tempOutput.toFile(); - for (CityGmlZipEntry entry : zipArchive.getEntries()) { - if (entry.getErrorType() != null || entry.getModel() == null) { - continue; - } - model = entry.getModel(); - if (model.isValidated()) { - Checker checker = previousCheckers.get(model); - Files.createDirectories(tempOutput.resolve(entry.getEntrySubPath()).getParent()); - checker.writeXmlReport(tempOutput.resolve(entry.getDisplayName() + "_report.xml").toString()); - checker.writePdfReport(tempOutput.resolve(entry.getDisplayName() + "_report.pdf").toString()); - } - } - ArchivePacker.packAndDeleteDirectory(tempOutput.toString()); - temp = null; - Alert alert = new Alert(Alert.AlertType.INFORMATION); - alert.setTitle("Export Report"); - alert.setContentText(Localization.getText("CityDoctorController.saveZipArchiveReports")); - alert.showAndWait(); - } catch (IOException e) { - logger.error(e); - } finally { - try { - if (temp != null) { - FileUtils.deleteDirectory(temp); - } - } catch (IOException e) { - logger.error(e); - } + private void updateGlobalErrors() { + GlobalErrorVisitor globErrVisitor = new GlobalErrorVisitor(mainWindow); + for (CheckError e : model.getGlobalErrors()) { + e.accept(globErrVisitor); } } @@ -1196,7 +1109,7 @@ public class CityDoctorController { updateTree(mainWindow.getCityFurnitureView().getRoot()); updateTree(mainWindow.getTransportationView().getRoot()); updateTree(mainWindow.getWaterView().getRoot()); - updateTree(mainWindow.getGenericCityObjectView().getRoot()); + updateTree(mainWindow.getOtherCityObjectView().getRoot()); updateTree(mainWindow.getTunnelView().getRoot()); renderer.updateErrors(); } @@ -1236,15 +1149,13 @@ public class CityDoctorController { private Map getErrorStats() { Map stats = new HashMap<>(); - addErrorStats(stats, model.getBridges()); - addErrorStats(stats, model.getBuildings()); - addErrorStats(stats, model.getLand()); - addErrorStats(stats, model.getTunnels()); - addErrorStats(stats, model.getTransportation()); - addErrorStats(stats, model.getVegetation()); - addErrorStats(stats, model.getWater()); - addErrorStats(stats, model.getCityFurniture()); - addErrorStats(stats, model.getGenericCityObjects()); + List errors = new ArrayList<>(); + model.createFeatureStream().forEach(co -> co.collectContainedErrors(errors)); + Set filteredErrors = new HashSet<>(errors); + for (CheckError error : filteredErrors) { + ErrorStat stat = stats.computeIfAbsent(error.getErrorId(), ErrorStat::new); + stat.incrementCount(); + } return stats; } @@ -1258,13 +1169,15 @@ public class CityDoctorController { ErrorStat stat = stats.computeIfAbsent(error.getErrorId(), ErrorStat::new); stat.incrementCount(); } + + } public void export(CityObject co) { if (model == null) { return; } - CityDoctorModel newModel = new CityDoctorModel(model.getParserConfig(), model.getFile()); + CityDoctorModel newModel = new CityDoctorModel(model.getParserConfig(), model.getFile(), new UnconnectedCache()); newModel.setCityModel(new CityModel()); newModel.addCityObject(co); newModel.setParsedCityGMLVersion(model.getCityGMLVersion()); @@ -1319,96 +1232,113 @@ public class CityDoctorController { case WATER -> filterWaterTree(searchString); case LAND -> filterLandTree(searchString); case CITY_FURNITURE -> filterCityFurnitureTree(searchString); - case GENERIC_CITY_OBJECT -> filterGenericCityObjectTree(searchString); + case OTHER_CITY_OBJECT -> filterOtherCityObjectsTree(searchString); } } private void filterBuildingTree(String searchString) { - List foundBuildings = filterFeatures(searchString, model.getBuildings()); + Supplier> foundBuildings = () -> model.getBuildings(). + filter(co -> featureFilter(co, searchString)); + int featureCount = (int) foundBuildings.get().count(); TreeView buildingsView = mainWindow.getBuildingsView(); TreeItem root = buildingsView.getRoot(); root.getChildren().clear(); buildBuildingTreeFromList(foundBuildings, root); updateTree(root); - addMoreButtonToBuildingsIfNecessary(foundBuildings, buildingsView, root, buildingChunkNr); + addMoreButtonForBuildings(buildingsView, root, buildingChunkNr, foundBuildings, featureCount); } private void filterBridgeTree(String searchString) { - List foundBridges = filterFeatures(searchString, model.getBridges()); + Supplier> foundBridges = () -> model.getBridges(). + filter(co -> featureFilter(co, searchString)); + int featureCount = (int) foundBridges.get().count(); TreeView bridgeView = mainWindow.getBridgeView(); TreeItem root = bridgeView.getRoot(); root.getChildren().clear(); buildBridgeTreeFromList(foundBridges, root); updateTree(root); - addMoreButtonIfNecessary(foundBridges, bridgeView, root, bridgeChunkNr); + addMoreButtonForBridges(bridgeView, root, bridgeChunkNr, foundBridges, featureCount); } private void filterTunnelTree(String searchString) { - List foundTunnel = filterFeatures(searchString, model.getTunnels()); + Supplier> foundTunnel = () -> model.getTunnels().filter(co -> featureFilter(co, searchString)); + int featureCount = (int) foundTunnel.get().count(); TreeView tunnelView = mainWindow.getTunnelView(); TreeItem root = tunnelView.getRoot(); root.getChildren().clear(); buildTunnelTreeFromList(foundTunnel, root); updateTree(root); - addMoreButtonIfNecessary(foundTunnel, tunnelView, root, tunnelChunkNr); + addMoreButtonForTunnel(tunnelView, root, tunnelChunkNr, foundTunnel, featureCount); } private void filterVegetationTree(String searchString) { - List foundVegetation = filterFeatures(searchString, model.getVegetation()); + Supplier> foundVegetation = () -> model.getVegetation(). + filter(co -> featureFilter(co, searchString)); + int featureCount = (int) foundVegetation.get().count(); TreeView vegetationView = mainWindow.getVegetationView(); TreeItem root = vegetationView.getRoot(); root.getChildren().clear(); buildVegetationTreeFromList(foundVegetation, root); updateTree(root); - addMoreButtonIfNecessary(foundVegetation, vegetationView, root, vegetationChunkNr); + addMoreButtonForVegetation(vegetationView, root, vegetationChunkNr, foundVegetation, featureCount); } private void filterTransportationTree(String searchString) { - List foundTransportation = filterFeatures(searchString, model.getTransportation()); + Supplier> foundTransportation = () -> model.getTransportation(). + filter(co -> featureFilter(co, searchString)); + int featureCount = (int) foundTransportation.get().count(); TreeView transportationView = mainWindow.getTransportationView(); TreeItem root = transportationView.getRoot(); root.getChildren().clear(); buildTransportationTreeFromList(foundTransportation, root); updateTree(root); - addMoreButtonIfNecessary(foundTransportation, transportationView, root, transportationChunkNr); + addMoreButtonForTransportation(transportationView, root, transportationChunkNr, + foundTransportation, featureCount); } private void filterWaterTree(String searchString) { - List foundWater = filterFeatures(searchString, model.getWater()); + Supplier> foundWater = () -> model.getWater().filter(co -> featureFilter(co, searchString)); + int featureCount = (int) foundWater.get().count(); TreeView waterView = mainWindow.getWaterView(); TreeItem root = waterView.getRoot(); root.getChildren().clear(); buildWaterTreeFromList(foundWater, root); - addMoreButtonIfNecessary(foundWater, waterView, root, waterChunkNr); + addMoreButtonForWater(waterView, root, waterChunkNr, foundWater, featureCount); } private void filterLandTree(String searchString) { - List foundLand = filterFeatures(searchString, model.getLand()); + Supplier> foundLand = () -> model.getLand().filter(co -> featureFilter(co, searchString)); + int featureCount = (int) foundLand.get().count(); TreeView landView = mainWindow.getTerrainView(); TreeItem root = landView.getRoot(); root.getChildren().clear(); - buildLandFromList(foundLand, root); - addMoreButtonIfNecessary(foundLand, landView, root, landChunkNr); + buildLandTreeFromList(foundLand, root); + addMoreButtonForLand(landView, root, landChunkNr, foundLand, featureCount); } private void filterCityFurnitureTree(String searchString) { - List foundCityFurniture = filterFeatures(searchString, model.getCityFurniture()); + Supplier> foundCityFurniture = () -> model.getCityFurniture(). + filter(co -> featureFilter(co, searchString)); + int featureCount = (int) foundCityFurniture.get().count(); TreeView cityFurnitureView = mainWindow.getCityFurnitureView(); TreeItem root = cityFurnitureView.getRoot(); root.getChildren().clear(); buildCityFurnitureTreeFromList(foundCityFurniture, root); - addMoreButtonIfNecessary(foundCityFurniture, cityFurnitureView, root, cityFurnitureChunkNr); + addMoreButtonForCityFurniture(cityFurnitureView, root, cityFurnitureChunkNr, foundCityFurniture, featureCount); } - private void filterGenericCityObjectTree(String searchString) { - List foundGenericCityObject = filterFeatures(searchString, model.getGenericCityObjects()); - TreeView genericCityObjectView = mainWindow.getGenericCityObjectView(); + private void filterOtherCityObjectsTree(String searchString) { + Supplier> foundGenericCityObject = () -> model.getOtherCityObjects(). + filter(co ->featureFilter(co, searchString)); + int featureCount = (int) foundGenericCityObject.get().count(); + TreeView genericCityObjectView = mainWindow.getOtherCityObjectView(); TreeItem root = genericCityObjectView.getRoot(); root.getChildren().clear(); - buildGenericCityObjectTreeFromList(foundGenericCityObject, root); - addMoreButtonIfNecessary(foundGenericCityObject, genericCityObjectView, root, genericCityObjectsChunkNr); + buildOtherCityObjectsTreeFromList(foundGenericCityObject, root); + addMoreButtonForOtherCityObjects(genericCityObjectView, root, otherCityObjectsChunkNr, + foundGenericCityObject, featureCount); } private List filterFeatures(String searchString, List features) { @@ -1421,6 +1351,10 @@ public class CityDoctorController { return foundFeatures; } + private boolean featureFilter(CityObject co, String searchString) { + return co.getGmlId().getGmlString().contains(searchString); + } + public void resetSearch(FeatureType selectedTab) { if (model == null) { return; @@ -1455,141 +1389,192 @@ public class CityDoctorController { } mainWindow.resetSearchBar(); root.getChildren().clear(); - List errorBuildings = new ArrayList<>(); - for (Building b : model.getBuildings()) { - if (b.containsAnyError()) { - errorBuildings.add(b); - } - } resetFeatureChunks(); - buildBuildingTreeFromList(errorBuildings, root); + List foundBuildings = model.getCache().getErrorFeatureIds(); + List idList = model.getBuildingIds(); + foundBuildings.removeIf(gmlId -> (!idList.contains(gmlId))); + + Supplier> supply = () -> model.getCache().getStream(foundBuildings).map(co -> (Building) co); + buildBuildingTreeFromList(supply, root); updateTree(root); - addMoreButtonToBuildingsIfNecessary(errorBuildings, buildingsView, root, buildingChunkNr); + addMoreButtonForBuildings(buildingsView, root, buildingChunkNr, supply, foundBuildings.size()); } public void fillTreeViewWithErrorVegetation() { + TreeView vegetationView = mainWindow.getVegetationView(); + TreeItem root = vegetationView.getRoot(); if (model == null) { return; } - fillTreeViewWithErrorCityObjects(mainWindow.getVegetationView(), model.getVegetation(), vegetationChunkNr); + if (root == null) { + return; + } + mainWindow.resetSearchBar(); + root.getChildren().clear(); + resetFeatureChunks(); + List foundVegetation = model.getCache().getErrorFeatureIds(); + List idList = model.getVegetationIds(); + foundVegetation.removeIf(gmlId -> (!idList.contains(gmlId))); + + Supplier> supply = () -> model.getCache().getStream(foundVegetation).map(co -> (Vegetation) co); + buildVegetationTreeFromList(supply, root); + updateTree(root); + addMoreButtonForVegetation(vegetationView, root, vegetationChunkNr, supply, foundVegetation.size()); } public void fillTreeViewWithErrorBridges() { + TreeView bridgeView = mainWindow.getBridgeView(); + TreeItem root = bridgeView.getRoot(); if (model == null) { return; } - fillTreeViewWithErrorCityObjects(mainWindow.getBridgeView(), model.getBridges(), bridgeChunkNr); + if (root == null) { + return; + } + mainWindow.resetSearchBar(); + root.getChildren().clear(); + resetFeatureChunks(); + List foundBridge = model.getCache().getErrorFeatureIds(); + List idList = model.getBridgeIds(); + foundBridge.removeIf(gmlId -> (!idList.contains(gmlId))); + + Supplier> supply = () -> model.getCache().getStream(foundBridge).map(co -> (BridgeObject) co); + buildBridgeTreeFromList(supply, root); + updateTree(root); + addMoreButtonForBridges(bridgeView, root, bridgeChunkNr, supply, foundBridge.size()); } public void fillTreeViewWithErrorLand() { + TreeView landView = mainWindow.getTerrainView(); + TreeItem root = landView.getRoot(); if (model == null) { return; } - fillTreeViewWithErrorCityObjects(mainWindow.getTerrainView(), model.getLand(), landChunkNr); + if (root == null) { + return; + } + mainWindow.resetSearchBar(); + root.getChildren().clear(); + resetFeatureChunks(); + List foundLand = model.getCache().getErrorFeatureIds(); + List idList = model.getLandIds(); + foundLand.removeIf(gmlId -> (!idList.contains(gmlId))); + + Supplier> supply = () -> model.getCache().getStream(foundLand).map(co -> (CityObject) co); + buildLandTreeFromList(supply, root); + updateTree(root); + addMoreButtonForLand(landView, root, landChunkNr, supply, foundLand.size()); } public void fillTreeViewWithErrorCityFurniture() { + TreeView cityFurnitureView = mainWindow.getCityFurnitureView(); + TreeItem root = cityFurnitureView.getRoot(); if (model == null) { return; } - fillTreeViewWithErrorCityObjects(mainWindow.getCityFurnitureView(), - model.getCityFurniture(), cityFurnitureChunkNr); + if (root == null) { + return; + } + mainWindow.resetSearchBar(); + root.getChildren().clear(); + resetFeatureChunks(); + List foundCityFurniture = model.getCache().getErrorFeatureIds(); + List idList = model.getCityFurnitureIds(); + foundCityFurniture.removeIf(gmlId -> (!idList.contains(gmlId))); + + Supplier> supply = () -> model.getCache().getStream(foundCityFurniture).map(co -> (CityFurniture) co); + buildCityFurnitureTreeFromList(supply, root); + updateTree(root); + addMoreButtonForCityFurniture(cityFurnitureView, root, cityFurnitureChunkNr, supply, foundCityFurniture.size()); } - public void fillTreeViewWithErrorGenericCityObjects() { + public void fillTreeViewWithErrorOtherCityObjects() { + TreeView genericCityObjectsView = mainWindow.getOtherCityObjectView(); + TreeItem root = genericCityObjectsView.getRoot(); if (model == null) { return; } - fillTreeViewWithErrorCityObjects(mainWindow.getGenericCityObjectView(), - model.getGenericCityObjects(), genericCityObjectsChunkNr); + if (root == null) { + return; + } + mainWindow.resetSearchBar(); + root.getChildren().clear(); + resetFeatureChunks(); + List foundOtherCityObjects = model.getCache().getErrorFeatureIds(); + List idList = model.getOtherCityObjectsIds(); + foundOtherCityObjects.removeIf(gmlId -> (!idList.contains(gmlId))); + + Supplier> supply = () -> model.getCache().getStream(foundOtherCityObjects).map(co -> (GenericCityObject) co); + buildOtherCityObjectsTreeFromList(supply, root); + updateTree(root); + addMoreButtonForOtherCityObjects(genericCityObjectsView, root, otherCityObjectsChunkNr, supply, foundOtherCityObjects.size()); } public void fillTreeViewWithErrorTransportation() { + TreeView transportationView = mainWindow.getTransportationView(); + TreeItem root = transportationView.getRoot(); if (model == null) { return; } - fillTreeViewWithErrorCityObjects(mainWindow.getTransportationView(), model.getTransportation(), - transportationChunkNr); - } - - public void fillTreeViewWithErrorTunnel() { - if (model == null) { + if (root == null) { return; } - fillTreeViewWithErrorCityObjects(mainWindow.getTunnelView(), model.getTunnels(), tunnelChunkNr); + mainWindow.resetSearchBar(); + root.getChildren().clear(); + resetFeatureChunks(); + List foundTransportation = model.getCache().getErrorFeatureIds(); + List idList = model.getTransportationIds(); + foundTransportation.removeIf(gmlId -> (!idList.contains(gmlId))); + + Supplier> supply = () -> model.getCache().getStream(foundTransportation).map(co -> (TransportationObject) co); + buildTransportationTreeFromList(supply, root); + updateTree(root); + addMoreButtonForTransportation(transportationView, root, transportationChunkNr, supply, foundTransportation.size()); } - public void fillTreeViewWithErrorWater() { + public void fillTreeViewWithErrorTunnel() { + TreeView tunnelView = mainWindow.getTunnelView(); + TreeItem root = tunnelView.getRoot(); if (model == null) { return; } - fillTreeViewWithErrorCityObjects(mainWindow.getWaterView(), model.getWater(), waterChunkNr); - } - - private void fillTreeViewWithErrorCityObjects(TreeView treeView, List objects, - AtomicInteger chunkCounter) { - TreeItem root = treeView.getRoot(); if (root == null) { return; } mainWindow.resetSearchBar(); root.getChildren().clear(); - List errorObjects = new ArrayList<>(); - for (CityObject co : objects) { - if (co.containsAnyError()) { - errorObjects.add(co); - } - } - buildTreeFromList(errorObjects, root, chunkCounter); + resetFeatureChunks(); + List foundTunnel = model.getCache().getErrorFeatureIds(); + List idList = model.getTunnelIds(); + foundTunnel.removeIf(gmlId -> (!idList.contains(gmlId))); + + Supplier> supply = () -> model.getCache().getStream(foundTunnel).map(co -> (Tunnel) co); + buildTunnelTreeFromList(supply, root); updateTree(root); - addMoreButtonIfNecessary(errorObjects, treeView, root, chunkCounter); + addMoreButtonForTunnel(tunnelView, root, tunnelChunkNr, supply, foundTunnel.size()); + } - public void fillTreeViewFromFeatures(FeatureType selectedTab) { + public void fillTreeViewWithErrorWater() { + TreeView waterView = mainWindow.getWaterView(); + TreeItem root = waterView.getRoot(); if (model == null) { return; } - mainWindow.resetSearchBar(); - switch (selectedTab) { - case BUILDING: - buildBuildings(model); - updateTree(mainWindow.getBuildingsView().getRoot()); - break; - case VEGETATION: - buildVegetation(model); - updateTree(mainWindow.getVegetationView().getRoot()); - break; - case BRIDGE: - buildBridges(model); - updateTree(mainWindow.getBridgeView().getRoot()); - break; - case LAND: - buildLand(model); - updateTree(mainWindow.getTerrainView().getRoot()); - break; - case TRANSPORTATION: - buildTransportation(model); - updateTree(mainWindow.getTransportationView().getRoot()); - break; - case TUNNEL: - buildTunnel(model); - updateTree(mainWindow.getTunnelView().getRoot()); - break; - case WATER: - buildWater(model); - updateTree(mainWindow.getWaterView().getRoot()); - break; - case CITY_FURNITURE: - buildCityFurniture(model); - updateTree(mainWindow.getCityFurnitureView().getRoot()); - break; - case GENERIC_CITY_OBJECT: - buildOtherCityObjects(model); - updateTree(mainWindow.getGenericCityObjectView().getRoot()); - break; - default: - throw new IllegalStateException(); + if (root == null) { + return; } + mainWindow.resetSearchBar(); + root.getChildren().clear(); + resetFeatureChunks(); + List foundWater = model.getCache().getErrorFeatureIds(); + List idList = model.getWaterIds(); + foundWater.removeIf(gmlId -> (!idList.contains(gmlId))); + + Supplier> supply = () -> model.getCache().getStream(foundWater).map(co -> (WaterObject) co); + buildWaterTreeFromList(supply, root); + updateTree(root); + addMoreButtonForWater(waterView, root, tunnelChunkNr, supply, foundWater.size()); } public CityDoctorModel getModel() { @@ -1641,7 +1626,7 @@ public class CityDoctorController { public void delete(TreeItem selectedItem) { if (model == null) { return; - }/* TODO: Rework this properly via Renderable implementation + }/* Old debug function, would first need a refactor due to the RenderNode and GeoDB reworks Renderable render = selectedItem.getValue(); if (render instanceof BuildingNode node) { model.getBuildings().remove(node.getBuilding()); @@ -1654,37 +1639,19 @@ public class CityDoctorController { public void errorFilterIndexChanged(Number newV) { mainWindow.getMeshGroup().getChildren().clear(); mainWindow.unselectEverything(); - if (newV.intValue() == 0) { - fillTreeViewFromFeatures(mainWindow.getSelectedTab()); - } else if (newV.intValue() == 1) { - switch (mainWindow.getSelectedTab()) { - case BUILDING: - fillTreeViewWithErrorBuildings(); - break; - case VEGETATION: - fillTreeViewWithErrorVegetation(); - break; - case BRIDGE: - fillTreeViewWithErrorBridges(); - break; - case LAND: - fillTreeViewWithErrorLand(); - break; - case TRANSPORTATION: - fillTreeViewWithErrorTransportation(); - break; - case WATER: - fillTreeViewWithErrorWater(); - break; - case CITY_FURNITURE: - fillTreeViewWithErrorCityFurniture(); - break; - case GENERIC_CITY_OBJECT: - fillTreeViewWithErrorGenericCityObjects(); - break; - default: - throw new IllegalStateException("Unknown selected feature tab: " + mainWindow.getSelectedTab()); - } + if (newV.intValue() == 0) { // Error filter was set to "All" + buildTrees(); + updateFeatureTrees(); + } else if (newV.intValue() == 1) { // Error filter was set to "With errors" + fillTreeViewWithErrorBuildings(); + fillTreeViewWithErrorVegetation(); + fillTreeViewWithErrorBridges(); + fillTreeViewWithErrorLand(); + fillTreeViewWithErrorTransportation(); + fillTreeViewWithErrorTunnel(); + fillTreeViewWithErrorWater(); + fillTreeViewWithErrorCityFurniture(); + fillTreeViewWithErrorOtherCityObjects(); } else { throw new IllegalStateException("Unknown filter index selected: " + newV); } diff --git a/CityDoctorParent/Extensions/CityDoctorGUI/src/main/java/de/hft/stuttgart/citydoctor2/gui/GlobalErrorVisitor.java b/CityDoctorParent/Extensions/CityDoctorGUI/src/main/java/de/hft/stuttgart/citydoctor2/gui/GlobalErrorVisitor.java new file mode 100644 index 0000000000000000000000000000000000000000..287ea14dc3f234af31c5543459542eccb02ba7a2 --- /dev/null +++ b/CityDoctorParent/Extensions/CityDoctorGUI/src/main/java/de/hft/stuttgart/citydoctor2/gui/GlobalErrorVisitor.java @@ -0,0 +1,225 @@ +package de.hft.stuttgart.citydoctor2.gui; + +import de.hft.stuttgart.citydoctor2.check.CheckError; +import de.hft.stuttgart.citydoctor2.check.ErrorVisitor; +import de.hft.stuttgart.citydoctor2.check.error.AllPolygonsWrongOrientationError; +import de.hft.stuttgart.citydoctor2.check.error.AttributeInvalidError; +import de.hft.stuttgart.citydoctor2.check.error.AttributeMissingError; +import de.hft.stuttgart.citydoctor2.check.error.AttributeValueWrongError; +import de.hft.stuttgart.citydoctor2.check.error.ConsecutivePointSameError; +import de.hft.stuttgart.citydoctor2.check.error.DegeneratedRingError; +import de.hft.stuttgart.citydoctor2.check.error.DependenciesNotMetError; +import de.hft.stuttgart.citydoctor2.check.error.MultipleConnectedComponentsError; +import de.hft.stuttgart.citydoctor2.check.error.NestedRingError; +import de.hft.stuttgart.citydoctor2.check.error.NonManifoldEdgeError; +import de.hft.stuttgart.citydoctor2.check.error.NonManifoldVertexError; +import de.hft.stuttgart.citydoctor2.check.error.NonPlanarPolygonDistancePlaneError; +import de.hft.stuttgart.citydoctor2.check.error.NonPlanarPolygonNormalsDeviation; +import de.hft.stuttgart.citydoctor2.check.error.NotCeilingError; +import de.hft.stuttgart.citydoctor2.check.error.NotFloorError; +import de.hft.stuttgart.citydoctor2.check.error.NotGroundError; +import de.hft.stuttgart.citydoctor2.check.error.NotWallError; +import de.hft.stuttgart.citydoctor2.check.error.NullAreaError; +import de.hft.stuttgart.citydoctor2.check.error.PlanarityError; +import de.hft.stuttgart.citydoctor2.check.error.PointTouchesEdgeError; +import de.hft.stuttgart.citydoctor2.check.error.PolygonError; +import de.hft.stuttgart.citydoctor2.check.error.PolygonHoleOutsideError; +import de.hft.stuttgart.citydoctor2.check.error.PolygonInteriorDisconnectedError; +import de.hft.stuttgart.citydoctor2.check.error.PolygonIntersectingRingsError; +import de.hft.stuttgart.citydoctor2.check.error.PolygonSameOrientationError; +import de.hft.stuttgart.citydoctor2.check.error.PolygonWithoutSurfaceError; +import de.hft.stuttgart.citydoctor2.check.error.PolygonWrongOrientationError; +import de.hft.stuttgart.citydoctor2.check.error.RingDuplicatePointError; +import de.hft.stuttgart.citydoctor2.check.error.RingEdgeIntersectionError; +import de.hft.stuttgart.citydoctor2.check.error.RingError; +import de.hft.stuttgart.citydoctor2.check.error.RingNotClosedError; +import de.hft.stuttgart.citydoctor2.check.error.RingSelfIntersectionError; +import de.hft.stuttgart.citydoctor2.check.error.RingTooFewPointsError; +import de.hft.stuttgart.citydoctor2.check.error.SchematronError; +import de.hft.stuttgart.citydoctor2.check.error.SolidError; +import de.hft.stuttgart.citydoctor2.check.error.SolidNotClosedError; +import de.hft.stuttgart.citydoctor2.check.error.SolidSelfIntError; +import de.hft.stuttgart.citydoctor2.check.error.SurfaceUnfragmentedError; +import de.hft.stuttgart.citydoctor2.check.error.TooFewPolygonsError; +import de.hft.stuttgart.citydoctor2.check.error.UnknownCheckError; + +public class GlobalErrorVisitor implements ErrorVisitor { + + private MainWindow mainWindow; + + public GlobalErrorVisitor(MainWindow mainWindow) { + this.mainWindow = mainWindow; + } + + @Override + public void visit(RingError err) { + } + + @Override + public void visit(PolygonError err) { + } + + @Override + public void visit(RingSelfIntersectionError err) { + } + + @Override + public void visit(PlanarityError err) { + } + + @Override + public void visit(PolygonHoleOutsideError err) { + } + + @Override + public void visit(NonManifoldEdgeError err) { + } + + @Override + public void visit(MultipleConnectedComponentsError err) { + } + + @Override + public void visit(NestedRingError err) { + } + + @Override + public void visit(NonManifoldVertexError err) { + } + + @Override + public void visit(PolygonWrongOrientationError err) { + } + + @Override + public void visit(PolygonSameOrientationError err) { + } + + @Override + public void visit(SolidNotClosedError err) { + } + + @Override + public void visit(DependenciesNotMetError err) { + } + + @Override + public void visit(UnknownCheckError err) { + } + + @Override + public void visit(RingNotClosedError err) { + } + + @Override + public void visit(ConsecutivePointSameError err) { + } + + @Override + public void visit(AllPolygonsWrongOrientationError err) { + } + + @Override + public void visit(PolygonInteriorDisconnectedError err) { + } + + @Override + public void visit(NullAreaError err) { + } + + @Override + public void visit(RingTooFewPointsError err) { + } + + @Override + public void visit(NonPlanarPolygonNormalsDeviation err) { + } + + @Override + public void visit(NonPlanarPolygonDistancePlaneError err) { + } + + @Override + public void visit(PolygonIntersectingRingsError err) { + } + + @Override + public void visit(SolidSelfIntError err) { + } + + @Override + public void visit(TooFewPolygonsError err) { + } + + @Override + public void visit(RingDuplicatePointError err) { + } + + @Override + public void visit(RingEdgeIntersectionError err) { + } + + @Override + public void visit(PointTouchesEdgeError err) { + } + + @Override + public void visit(NotCeilingError err) { + } + + @Override + public void visit(NotFloorError err) { + } + + @Override + public void visit(NotWallError err) { + } + + @Override + public void visit(NotGroundError err) { + } + + @Override + public void visit(SchematronError se) { + mainWindow.getGlobalErrorsView().getItems().add(se.getErrorIdString() + " - " + se.getNameOfAttribute()); + } + + @Override + public void visit(SurfaceUnfragmentedError err) { + } + + @Override + public void visit(DegeneratedRingError err) { + } + + @Override + public void visit(AttributeMissingError err) { + mainWindow.getGlobalErrorsView().getItems().add(err.getErrorId().getIdString() + + " - " + err.getNameOfAttribute()); + } + + @Override + public void visit(AttributeValueWrongError err) { + mainWindow.getGlobalErrorsView().getItems().add(err.getErrorId().getIdString() + + " - " + err.getNameOfAttribute()); + } + + @Override + public void visit(AttributeInvalidError err) { + mainWindow.getGlobalErrorsView().getItems().add(err.getErrorId().getIdString() + + " - " + err.getNameOfAttribute()); + } + + @Override + public void visit(PolygonWithoutSurfaceError err) { + } + + @Override + public void visit(CheckError err) { + } + + @Override + public void visit(SolidError err) { + } + +} diff --git a/CityDoctorParent/Extensions/CityDoctorGUI/src/main/java/de/hft/stuttgart/citydoctor2/gui/MainToolBar.java b/CityDoctorParent/Extensions/CityDoctorGUI/src/main/java/de/hft/stuttgart/citydoctor2/gui/MainToolBar.java index 78fc80737b913aff0c5a3c462489488ca58d3c3e..3993c617c0e08aec82f750255bf86c18e9c6dc1b 100644 --- a/CityDoctorParent/Extensions/CityDoctorGUI/src/main/java/de/hft/stuttgart/citydoctor2/gui/MainToolBar.java +++ b/CityDoctorParent/Extensions/CityDoctorGUI/src/main/java/de/hft/stuttgart/citydoctor2/gui/MainToolBar.java @@ -85,12 +85,6 @@ public class MainToolBar { @FXML private ImageView lod4View; - @FXML - private Button zipManagerBtn; - - @FXML - private ImageView zipManagerView; - @FXML private Button aboutBtn; @@ -153,7 +147,6 @@ public class MainToolBar { setupReportButton(); setupResetCameraButton(); setupHideRoofButton(); - setupZipManagerButton(); loadImages(); gridButton.setOnAction(ae -> renderer.showWireFrame(gridButton.isSelected())); @@ -232,10 +225,6 @@ public class MainToolBar { Image img = new Image(inStream); hideRoofView.setImage(img); } - try (InputStream inStream = MainWindow.class.getResourceAsStream("icons/zip.png")) { - Image img = new Image(inStream); - zipManagerView.setImage(img); - } } catch (IOException e) { // ignore close exception } @@ -347,14 +336,6 @@ public class MainToolBar { } - private void setupZipManagerButton() { - zipManagerBtn.setDisable(true); - zipManagerBtn.setTooltip(new Tooltip(Localization.getText("MainToolBar.zip"))); - zipManagerBtn.setOnAction(ae -> { - mainWindow.showZipManager(); - }); - } - public Button getCheckButton() { return checkBtn; } @@ -407,10 +388,6 @@ public class MainToolBar { return resetCameraBtn; } - public Button getZipManagerBtn() { - return zipManagerBtn; - } - public HBox getToolBar() { return toolBar; } 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 58810fd551a0c33520250578d8666b0b816ce481..5fb958e150dd53d1dc3f89edef65421a51ab4d26 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 @@ -453,6 +453,7 @@ public class MainWindow extends Application { }); } + @SuppressWarnings("java:S2629") private void checkForStartupLoading() { if (loadFileAtStartup) { logger.info(Localization.getText("MainWindow.loadGivenFile")); @@ -638,7 +639,7 @@ public class MainWindow extends Application { selectedTab = FeatureType.CITY_FURNITURE; break; case 8: - selectedTab = FeatureType.GENERIC_CITY_OBJECT; + selectedTab = FeatureType.OTHER_CITY_OBJECT; break; default: throw new IllegalStateException("Unknown tab index: " + index); @@ -672,7 +673,7 @@ public class MainWindow extends Application { case CITY_FURNITURE: cityFurnitureTab.setDisable(value); break; - case GENERIC_CITY_OBJECT: + case OTHER_CITY_OBJECT: otherObjectsTab.setDisable(value); break; default: @@ -801,10 +802,13 @@ public class MainWindow extends Application { }); menu.getItems().add(copyToClipboardOption); + /* Was used for debugging the repair module, functionless since the RenderNode rework. + * Commented out for now, might be needed later on again MenuItem deleteOption = new MenuItem(Localization.getText("MainWindow.delete")); deleteOption.setOnAction(ae -> controller.delete(featureView.getSelectionModel().getSelectedItem())); menu.getItems().add(deleteOption); featureView.setContextMenu(menu); + */ } public void fetchCopyAction(Renderable node) { @@ -1011,7 +1015,7 @@ public class MainWindow extends Application { return attributeView; } - public TreeView getGenericCityObjectView() { + public TreeView getOtherCityObjectView() { return otherObjectsView; } @@ -1157,7 +1161,7 @@ public class MainWindow extends Application { case WATER -> new Pair<>(waterTab, waterView); case LAND -> new Pair<>(terrainTab, terrainView); case CITY_FURNITURE -> new Pair<>(cityFurnitureTab, cityFurnitureView); - case GENERIC_CITY_OBJECT -> new Pair<>(otherObjectsTab, otherObjectsView); + case OTHER_CITY_OBJECT -> new Pair<>(otherObjectsTab, otherObjectsView); default -> throw new IllegalArgumentException("unknown feature type: " + coType); }; } @@ -1178,13 +1182,6 @@ public class MainWindow extends Application { return mainToolBar.getOpenBtn(); } - public void showZipManager() { - controller.showZipManager(); - } - - public Button getZipManagerBtn() { - return mainToolBar.getZipManagerBtn(); - } public VertexClickHandler getClickHandler() { return clickHandler; diff --git a/CityDoctorParent/Extensions/CityDoctorGUI/src/main/java/de/hft/stuttgart/citydoctor2/gui/OpenFileDialog.java b/CityDoctorParent/Extensions/CityDoctorGUI/src/main/java/de/hft/stuttgart/citydoctor2/gui/OpenFileDialog.java index 8e3b6c556dc69007e30d996871032108124c7c0c..d5857b2187938e82b0ff993e95bd687c8e26a48e 100644 --- a/CityDoctorParent/Extensions/CityDoctorGUI/src/main/java/de/hft/stuttgart/citydoctor2/gui/OpenFileDialog.java +++ b/CityDoctorParent/Extensions/CityDoctorGUI/src/main/java/de/hft/stuttgart/citydoctor2/gui/OpenFileDialog.java @@ -120,7 +120,7 @@ public class OpenFileDialog { if (fc == null) { fc = new FileChooser(); fc.setTitle(Localization.getText("OpenFileDialog.select")); - fc.getExtensionFilters().add(new ExtensionFilter("GML/XML/ZIP", "*.gml", "*.xml", "*.zip")); + fc.getExtensionFilters().add(new ExtensionFilter("GML/XML", "*.gml", "*.xml")); fc.getExtensionFilters().add(new ExtensionFilter(Localization.getText("MainWindow.all"), "*.*")); } File dir = new File(Settings.get(Settings.LAST_OPEN_FOLDER, "")); @@ -153,9 +153,6 @@ public class OpenFileDialog { Thread t = new Thread(() -> { try { - if (path.endsWith(".zip")) { - Platform.runLater(() -> progress.setProgress(-1)); - } controller.loadCityGml(path, numberOfRoundingPlaces, progress::setProgress, useValidation, lowMemory); Platform.runLater(() -> stage.close()); diff --git a/CityDoctorParent/Extensions/CityDoctorGUI/src/main/java/de/hft/stuttgart/citydoctor2/gui/TriangulatedGeometry.java b/CityDoctorParent/Extensions/CityDoctorGUI/src/main/java/de/hft/stuttgart/citydoctor2/gui/TriangulatedGeometry.java index 9709b35373ee30f37f06bb958ee6a1934286e125..83a556d32f0189588d14008983c994b0d8ec565f 100644 --- a/CityDoctorParent/Extensions/CityDoctorGUI/src/main/java/de/hft/stuttgart/citydoctor2/gui/TriangulatedGeometry.java +++ b/CityDoctorParent/Extensions/CityDoctorGUI/src/main/java/de/hft/stuttgart/citydoctor2/gui/TriangulatedGeometry.java @@ -13,6 +13,7 @@ import javafx.scene.paint.PhongMaterial; import javafx.scene.shape.*; import java.util.*; +import java.util.stream.Stream; public class TriangulatedGeometry { @@ -91,15 +92,15 @@ public class TriangulatedGeometry { addPolygonDataFromCityObjects(model.getVegetation(), triGeom, Color.LIGHTGREEN, filters); addPolygonDataFromCityObjects(model.getWater(), triGeom, Color.LIGHTSKYBLUE, filters); addPolygonDataFromCityObjects(model.getCityFurniture(), triGeom, Color.BLUEVIOLET, filters); - addPolygonDataFromCityObjects(model.getGenericCityObjects(), triGeom, Color.BLACK, filters); + addPolygonDataFromCityObjects(model.getOtherCityObjects(), triGeom, Color.BLACK, filters); return triGeom; } - private static void addPolygonDataFromCityObjects(List cos, - TriangulatedGeometry triGeom, Color color, List filters) { + private static void addPolygonDataFromCityObjects(Stream cos, + TriangulatedGeometry triGeom, Color color, List filters) { CityObjectCollector collector = new CityObjectCollector(); cos.forEach(cityObject -> cityObject.accept(collector)); collector.getCityObjects().forEach(cityObject -> addPolygonData(cityObject, triGeom, color, filters)); diff --git a/CityDoctorParent/Extensions/CityDoctorGUI/src/main/java/de/hft/stuttgart/citydoctor2/gui/ZipEntryManager.java b/CityDoctorParent/Extensions/CityDoctorGUI/src/main/java/de/hft/stuttgart/citydoctor2/gui/ZipEntryManager.java deleted file mode 100644 index b27a3f37a5a164cd6271907e671fbe280963a32f..0000000000000000000000000000000000000000 --- a/CityDoctorParent/Extensions/CityDoctorGUI/src/main/java/de/hft/stuttgart/citydoctor2/gui/ZipEntryManager.java +++ /dev/null @@ -1,439 +0,0 @@ -package de.hft.stuttgart.citydoctor2.gui; - -import de.hft.stuttgart.citydoctor2.gui.tree.ZipEntryListCell; -import de.hft.stuttgart.citydoctor2.gui.tree.node.ZipEntryNode; -import de.hft.stuttgart.citydoctor2.utils.Localization; -import de.hft.stuttgart.citydoctor2.zip.CityGmlZipArchive; -import de.hft.stuttgart.citydoctor2.zip.CityGmlZipEntry; -import de.hft.stuttgart.citydoctor2.zip.ZipEntryErrorType; -import javafx.application.Platform; -import javafx.fxml.FXML; -import javafx.fxml.FXMLLoader; -import javafx.scene.Scene; -import javafx.scene.control.Button; -import javafx.scene.control.Label; -import javafx.scene.control.ListView; -import javafx.scene.control.ProgressBar; -import javafx.scene.control.TextField; -import javafx.scene.control.TitledPane; -import javafx.scene.control.Tooltip; -import javafx.scene.image.Image; -import javafx.scene.image.ImageView; -import javafx.scene.input.KeyCode; -import javafx.scene.input.KeyEvent; -import javafx.scene.layout.VBox; -import javafx.stage.FileChooser; -import javafx.stage.Modality; -import javafx.stage.Stage; -import javafx.stage.Window; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.util.function.Predicate; - -/** - * This class implements a GUI for managing a loaded {@link CityGmlZipArchive} in CityDoctor. - */ -public class ZipEntryManager { - - private static final Logger logger = LogManager.getLogger(ZipEntryManager.class); - - private Stage stage; - private CityGmlZipArchive archive; - - @FXML - private TitledPane entriesPane; - @FXML - private TitledPane metadataPane; - - @FXML - private Label subpathLbl; - @FXML - private TextField subpathValueTxt; - - @FXML - private Label erroneousLbl; - @FXML - private Label erroneousValue; - - @FXML - private Label filesizeLbl; - @FXML - private Label filesizeValue; - - @FXML - private Label validatedLbl; - @FXML - private Label validatedValue; - - @FXML - private Label objectCountLbl; - @FXML - private Label objectCountValue; - - @FXML - private Button cancelBtn; - - @FXML - private Button loadBtn; - @FXML - private ImageView loadImageView; - - @FXML - private Button decompressBtn; - @FXML - private ImageView decompressImageView; - - @FXML - private Button decompressAllBtn; - @FXML - private ImageView decompressAllImageView; - - @FXML - private Button checkAllBtn; - @FXML - private ImageView checkAllImageView; - - @FXML - private Button showReportBtn; - @FXML - private ImageView showReportImageView; - - @FXML - private Button saveBtn; - @FXML - private ImageView saveImageView; - - @FXML - private ListView entryList; - @FXML - private ProgressBar progress; - @FXML - private ProgressBar subProgress; - - private CityDoctorController controller; - private int currentlyLoadedEntry = -1; - private CheckDialog dialog; - - private final String unknownValueText = Localization.getText("ZipEntryManager.unknownValue"); - - private static final Predicate entryDecompressed = node -> - (node.getEntry().isLoaded() || node.getEntry().getErrorType() != null); - private static final Predicate entryValidated = entryDecompressed.and(node -> - (node.getEntry().getModel() != null && node.getEntry().getModel().isValidated())); - - public ZipEntryManager(Window parent, CityDoctorController controller) throws IOException { - FXMLLoader loader = new FXMLLoader(ZipEntryManager.class.getResource("ZipEntryManager.fxml")); - loader.setController(this); - this.controller = controller; - archive = controller.getZipArchive(); - VBox box = loader.load(); - stage = new Stage(); - stage.getIcons().add(new Image(MainWindow.class.getResourceAsStream("icons/CityDoctor-Logo-rot_klein.jpg"))); - stage.setScene(new Scene(box)); - stage.initOwner(parent); - stage.initModality(Modality.APPLICATION_MODAL); - stage.setTitle(Localization.getText("ZipEntryManager.title")); - stage.getScene().addEventFilter(KeyEvent.KEY_PRESSED, (KeyEvent event) -> { - if (event.getCode() == KeyCode.ESCAPE) { - stage.close(); - } - }); - dialog = new CheckDialog(null, parent, controller); - dialog.showZipArchiveOptions(true); - } - - public void initialize() { - subProgress.setVisible(false); - entryList.getSelectionModel().selectedItemProperty().addListener((obs, oldI, newI) -> { - if (newI != null) { - showMetadata(newI.getEntry()); - } - }); - entryList.setCellFactory(param -> new ZipEntryListCell()); - setupButtons(); - applyLocalization(); - populateZipEntryList(); - } - - private void setupButtons() { - try { - try (InputStream inStream = MainWindow.class.getResourceAsStream("icons/decompress_zipEntry.png")) { - Image img = new Image(inStream); - decompressImageView.setImage(img); - } - try (InputStream inStream = MainWindow.class.getResourceAsStream("icons/view_model.png")) { - Image img = new Image(inStream); - loadImageView.setImage(img); - } - try (InputStream inStream = MainWindow.class.getResourceAsStream("icons/decompress_all_zipEntries.png")) { - Image img = new Image(inStream); - decompressAllImageView.setImage(img); - } - try (InputStream inStream = MainWindow.class.getResourceAsStream("icons/check_all_zipEntries.png")) { - Image img = new Image(inStream); - checkAllImageView.setImage(img); - } - try (InputStream inStream = MainWindow.class.getResourceAsStream("icons/error_stat32x32.png")) { - Image img = new Image(inStream); - showReportImageView.setImage(img); - } - try (InputStream inStream = MainWindow.class.getResourceAsStream("icons/save.png")) { - Image img = new Image(inStream); - saveImageView.setImage(img); - } - } catch (IOException ignored) { - //ignore exceptions - } - - decompressBtn.setOnAction(e -> { - disableTaskButtons(); - setEntryListLocked(true); - Thread t = new Thread(() -> { - CityGmlZipEntry entry = entryList.getSelectionModel().getSelectedItem().getEntry(); - logger.info("Decompressing entry \"{}\"", entry.getDisplayName()); - controller.decompressZipEntry(entry, progressValue -> - Platform.runLater(() -> progress.setProgress(progressValue)) - ); - Platform.runLater(() -> { - refresh(); - progress.setProgress(0); - setEntryListLocked(false); - }); - }); - t.setDaemon(true); - t.start(); - - }); - - loadBtn.setOnAction(e -> { - disableTaskButtons(); - setEntryListLocked(true); - try { - int selectedIndex = entryList.getSelectionModel().getSelectedIndex(); - if (selectedIndex == currentlyLoadedEntry) { - stage.hide(); - return; - } - CityGmlZipEntry entry = entryList.getSelectionModel().getSelectedItem().getEntry(); - if (entry.getErrorType() != null) { - logger.debug("IllegalState: loadBtn was pressed while an erroneous entry was selected"); - populateZipEntryList(selectedIndex); - return; - } - controller.loadZipEntry(entry); - currentlyLoadedEntry = selectedIndex; - stage.hide(); - } finally { - setEntryListLocked(false); - } - - }); - - decompressAllBtn.setOnAction(e -> { - disableTaskButtons(); - setEntryListLocked(true); - subProgress.setVisible(true); - subProgress.setProgress(0); - Thread t = new Thread(() -> { - progress.setProgress(0); - int count = 0; - int total = entryList.getItems().size(); - for (ZipEntryNode node : entryList.getItems()) { - logger.info("Decompressing entry \"{}\"", node.getEntry().getDisplayName()); - controller.decompressZipEntry(node.getEntry(), progressValue -> - Platform.runLater(() -> subProgress.setProgress(progressValue)) - ); - count++; - double progressValue = count * 1.0 / total; - Platform.runLater(() -> progress.setProgress(progressValue)); - } - Platform.runLater(() -> { - subProgress.setVisible(false); - refresh(); - progress.setProgress(0); - setEntryListLocked(false); - }); - }); - t.setDaemon(true); - t.start(); - }); - - checkAllBtn.setOnAction(e -> { - disableTaskButtons(); - dialog.show(); - refresh(); - }); - - showReportBtn.setOnAction(e -> { - disableTaskButtons(); - setEntryListLocked(true); - - try { - controller.loadZipEntry(entryList.getSelectionModel().getSelectedItem().getEntry()); - if (currentlyLoadedEntry == -1) { - currentlyLoadedEntry = entryList.getSelectionModel().getSelectedIndex(); - } - WriteReportDialog writeDialog = new WriteReportDialog(stage, controller, null); - writeDialog.show(); - } catch (IOException ex) { - throw new RuntimeException(ex); - } finally { - controller.loadZipEntry(entryList.getItems().get(currentlyLoadedEntry).getEntry()); - setEntryListLocked(false); - refresh(); - } - }); - showReportBtn.setDisable(true); - - saveBtn.setOnAction(e -> { - disableTaskButtons(); - setEntryListLocked(true); - try { - FileChooser fileChooser = new FileChooser(); - fileChooser.setTitle("Export Zip file"); - FileChooser.ExtensionFilter zipFilter = new FileChooser.ExtensionFilter("Zip File", "*.zip"); - fileChooser.getExtensionFilters().add(zipFilter); - File f = fileChooser.showSaveDialog(stage.getOwner()); - if (f != null) { - controller.saveZipArchiveReports(f); - } - } finally { - setEntryListLocked(false); - refresh(); - } - }); - saveBtn.setDisable(true); - - cancelBtn.setOnAction(e -> stage.close()); - } - - private void applyLocalization() { - entriesPane.setText(Localization.getText("ZipEntryManager.entryListTitle")); - metadataPane.setText(Localization.getText("ZipEntryManager.metadata")); - subpathLbl.setText(Localization.getText("ZipEntryManager.subpathLbl")); - erroneousLbl.setText(Localization.getText("ZipEntryManager.erroneousLbl")); - filesizeLbl.setText(Localization.getText("ZipEntryManager.filesizeLbl")); - validatedLbl.setText(Localization.getText("ZipEntryManager.validatedLbl")); - objectCountLbl.setText(Localization.getText("ZipEntryManager.objectCountLbl")); - - subpathValueTxt.setText(unknownValueText); - erroneousValue.setText(unknownValueText); - filesizeValue.setText(unknownValueText); - validatedValue.setText(unknownValueText); - objectCountValue.setText(unknownValueText); - - loadBtn.setTooltip(new Tooltip(Localization.getText("ZipEntryManager.loadBtn"))); - decompressBtn.setTooltip(new Tooltip(Localization.getText("ZipEntryManager.decompressBtn"))); - decompressAllBtn.setTooltip(new Tooltip(Localization.getText("ZipEntryManager.decompressAllBtn"))); - checkAllBtn.setTooltip(new Tooltip(Localization.getText("ZipEntryManager.checkAllBtn"))); - showReportBtn.setTooltip(new Tooltip(Localization.getText("ZipEntryManager.showReportBtn"))); - saveBtn.setTooltip(new Tooltip(Localization.getText("ZipEntryManager.saveBtn"))); - cancelBtn.setText(Localization.getText("ZipEntryManager.cancelBtn")); - } - - private void populateZipEntryList() { - populateZipEntryList(0); - } - - private void populateZipEntryList(int selectionIndex) { - entryList.getItems().clear(); - for (CityGmlZipEntry entry : archive.getEntries()) { - entryList.getItems().add(new ZipEntryNode(entry)); - } - entryList.getSelectionModel().clearSelection(); - entryList.getSelectionModel().select(selectionIndex); - showMetadata(entryList.getSelectionModel().getSelectedItem().getEntry()); - decompressAllBtn.setDisable(entryList.getItems().stream().allMatch(entryDecompressed)); - saveBtn.setDisable(entryList.getItems().stream().noneMatch(entryValidated)); - } - - private void showMetadata(CityGmlZipEntry entry) { - subpathValueTxt.setText(entry.getEntrySubPath()); - if (entry.getFileSize() != -1L) { - long fileSize = entry.getFileSize(); - long kb = 1024L; - long mb = kb * kb; - long gb = mb * kb; - - if (fileSize < kb) { - filesizeValue.setText("< 1 KB"); - } else if (fileSize < mb) { - filesizeValue.setText(String.format("%s KB", fileSize / kb)); - } else if (fileSize < gb) { - filesizeValue.setText(String.format("%s MB", fileSize / mb)); - } else { - double gigabytes = (double) fileSize / gb; - filesizeValue.setText(String.format("%.2f GB", gigabytes)); - } - } else { - filesizeValue.setText(unknownValueText); - } - if (entry.getErrorType() != null) { - erroneousValue.setText(getErrorText(entry.getErrorType())); - validatedValue.setText(unknownValueText); - objectCountValue.setText(unknownValueText); - loadBtn.setDisable(true); - decompressBtn.setDisable(true); - showReportBtn.setDisable(true); - } else { - erroneousValue.setText(Localization.getText("ZipEntryManager.no")); - - loadBtn.setDisable(!entry.isLoaded()); - decompressBtn.setDisable(entry.isLoaded()); - if (entry.getModel() == null) { - validatedValue.setText(unknownValueText); - objectCountValue.setText(unknownValueText); - return; - } - if (entry.getModel().isValidated()) { - validatedValue.setText(Localization.getText("ZipEntryManager.yes")); - showReportBtn.setDisable(false); - } else { - validatedValue.setText(Localization.getText("ZipEntryManager.no")); - showReportBtn.setDisable(true); - } - objectCountValue.setText(String.valueOf(entry.getModel().getNumberOfFeatures())); - } - - } - - private void disableTaskButtons() { - decompressBtn.setDisable(true); - loadBtn.setDisable(true); - decompressAllBtn.setDisable(true); - showReportBtn.setDisable(true); - saveBtn.setDisable(true); - } - - public void refresh() { - populateZipEntryList(entryList.getSelectionModel().getSelectedIndex()); - } - - private String getErrorText(ZipEntryErrorType error) { - switch (error) { - case EXCESSIVE_FILESIZE -> { - return Localization.getText("ZipEntryManager.excessiveFileSize"); - } - case INVALID_CITY_GML_FILE -> { - return Localization.getText("ZipEntryManager.invalidCityGml"); - } - default -> { - return Localization.getText("ZipEntryManager.ioError"); - } - } - } - - private void setEntryListLocked(boolean locked) { - entryList.setMouseTransparent(locked); - entryList.setFocusTraversable(!locked); - } - - public void show() { - Platform.runLater(() -> stage.showAndWait()); - refresh(); - } -} diff --git a/CityDoctorParent/Extensions/CityDoctorGUI/src/main/java/de/hft/stuttgart/citydoctor2/gui/tree/AddMoreButtonRunnable.java b/CityDoctorParent/Extensions/CityDoctorGUI/src/main/java/de/hft/stuttgart/citydoctor2/gui/tree/AddMoreButtonRunnable.java new file mode 100644 index 0000000000000000000000000000000000000000..262b309028d56a561bedba099dbc6feaad6e05ae --- /dev/null +++ b/CityDoctorParent/Extensions/CityDoctorGUI/src/main/java/de/hft/stuttgart/citydoctor2/gui/tree/AddMoreButtonRunnable.java @@ -0,0 +1,68 @@ +package de.hft.stuttgart.citydoctor2.gui.tree; + +import de.hft.stuttgart.citydoctor2.datastructure.CityDoctorModel; +import de.hft.stuttgart.citydoctor2.gui.CityDoctorController; +import javafx.scene.control.TreeItem; +import javafx.scene.control.TreeView; + +import java.util.concurrent.atomic.AtomicInteger; + + +public abstract class AddMoreButtonRunnable implements Runnable{ + + private int featureCount; + private final TreeView view; + private final TreeItem root; + private final AtomicInteger chunkCounter; + private static final int MAX_FEATURES_PER_CHUNK = CityDoctorController.getMaxFeaturesPerChunk(); + + + protected AddMoreButtonRunnable(int featureCount, TreeView view, + TreeItem root, AtomicInteger chunkCounter){ + this.featureCount = featureCount; + this.view = view; + this.root = root; + this.chunkCounter = chunkCounter; + } + + @Override + public void run() { + // 29 is the height of one item + int numberOfDisplayedItems = (int) (view.getHeight() / 29); + int selectedIndex = view.getSelectionModel().getSelectedIndex(); + // remove button node + root.getChildren().remove(root.getChildren().size() - 1); + chunkCounter.getAndIncrement(); + int visibleFeatures = countVisibleNodes(view); + buildNodeTreeCall(); + if (selectedIndex >= 0) { + view.getSelectionModel().select(selectedIndex); + } + if ((chunkCounter.get() + 1) * MAX_FEATURES_PER_CHUNK < featureCount) { + root.getChildren().add(new TreeItem<>(new ButtonRenderable(this))); + } + view.scrollTo(visibleFeatures - numberOfDisplayedItems + 1); + + } + + /** + * Function hook for the buildTree call of the view + */ + public abstract void buildNodeTreeCall(); + + + private static int countVisibleNodes(TreeView view) { + return countVisibleNodes(view.getRoot()) + 1; + } + + private static int countVisibleNodes(TreeItem root) { + int visibleFeatures = root.getChildren().size(); + for (TreeItem child : root.getChildren()) { + if (!child.getChildren().isEmpty() && child.isExpanded()) { + visibleFeatures += countVisibleNodes(child); + } + } + return visibleFeatures; + } + +} diff --git a/CityDoctorParent/Extensions/CityDoctorGUI/src/main/java/de/hft/stuttgart/citydoctor2/gui/tree/ZipEntryListCell.java b/CityDoctorParent/Extensions/CityDoctorGUI/src/main/java/de/hft/stuttgart/citydoctor2/gui/tree/ZipEntryListCell.java deleted file mode 100644 index 745471880256b7eff20a9b6d7e44c0e54c8e297f..0000000000000000000000000000000000000000 --- a/CityDoctorParent/Extensions/CityDoctorGUI/src/main/java/de/hft/stuttgart/citydoctor2/gui/tree/ZipEntryListCell.java +++ /dev/null @@ -1,22 +0,0 @@ -package de.hft.stuttgart.citydoctor2.gui.tree; - -import de.hft.stuttgart.citydoctor2.gui.tree.node.ZipEntryNode; -import javafx.scene.control.ListCell; - -public class ZipEntryListCell extends ListCell { - - @Override - protected void updateItem(ZipEntryNode item, boolean empty) { - super.updateItem(item, empty); - if (!empty || item != null) { - setText(item.getText()); - updateColor(); - } else { - setText(null); - } - } - - public void updateColor() { - setTextFill(getItem().getTextColor()); - } -} diff --git a/CityDoctorParent/Extensions/CityDoctorGUI/src/main/java/de/hft/stuttgart/citydoctor2/gui/tree/node/CityObjectNode.java b/CityDoctorParent/Extensions/CityDoctorGUI/src/main/java/de/hft/stuttgart/citydoctor2/gui/tree/node/CityObjectNode.java index 170891fe8ce6d6e1d87a63c232300e133bcd8df3..7d3fae37a369ab3d03ba906f7734e42bd11c9406 100644 --- a/CityDoctorParent/Extensions/CityDoctorGUI/src/main/java/de/hft/stuttgart/citydoctor2/gui/tree/node/CityObjectNode.java +++ b/CityDoctorParent/Extensions/CityDoctorGUI/src/main/java/de/hft/stuttgart/citydoctor2/gui/tree/node/CityObjectNode.java @@ -12,9 +12,11 @@ public class CityObjectNode extends Renderable { private static final Logger logger = LogManager.getLogger(CityObjectNode.class); private final CityObject co; + private String text; public CityObjectNode(CityObject co) { this.co = co; + this.text = co.getDisplayText(); } @Override @@ -30,7 +32,7 @@ public class CityObjectNode extends Renderable { @Override public String getText() { - return co.getDisplayText(); + return text; } @Override diff --git a/CityDoctorParent/Extensions/CityDoctorGUI/src/main/java/de/hft/stuttgart/citydoctor2/gui/tree/node/ZipEntryNode.java b/CityDoctorParent/Extensions/CityDoctorGUI/src/main/java/de/hft/stuttgart/citydoctor2/gui/tree/node/ZipEntryNode.java deleted file mode 100644 index f4ba0875daaa35c29e0052f392d29a54b2aeecbc..0000000000000000000000000000000000000000 --- a/CityDoctorParent/Extensions/CityDoctorGUI/src/main/java/de/hft/stuttgart/citydoctor2/gui/tree/node/ZipEntryNode.java +++ /dev/null @@ -1,43 +0,0 @@ -package de.hft.stuttgart.citydoctor2.gui.tree.node; - -import de.hft.stuttgart.citydoctor2.zip.CityGmlZipEntry; -import javafx.scene.paint.Color; - -public class ZipEntryNode { - - private final CityGmlZipEntry entry; - - public ZipEntryNode(CityGmlZipEntry entry) { - this.entry = entry; - } - - public Color getTextColor() { - if (entry.getErrorType() != null) { - return Color.DARKRED; - } else if (entry.getModel() != null) { - if (entry.getModel().getNumberOfFeatures() == 0) { - return Color.GRAY; - } - if (entry.getModel().isValidated()) { - if (entry.getModel().collectErrors().isEmpty()) { - return Color.GREEN; - } - return Color.RED; - } - return Color.BLUE; - } else if (entry.isLoaded()) { - return Color.BLUE; - } else { - return Color.BLACK; - } - } - - public String getText() { - return entry.getDisplayName(); - } - - public CityGmlZipEntry getEntry() { - return entry; - } - -} 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 5261641c5b6ca6e3f143e4d0e754e1802438ea45..e0924a244fe035c2460abb84e1d48a4a7ba8c0d5 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,7 +2,6 @@ - @@ -52,78 +51,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/CityDoctorParent/Extensions/CityDoctorGUI/src/main/resources/de/hft/stuttgart/citydoctor2/gui/MainToolBar.fxml b/CityDoctorParent/Extensions/CityDoctorGUI/src/main/resources/de/hft/stuttgart/citydoctor2/gui/MainToolBar.fxml index 4cf90fff910acf63b9d70da64a989c2e594d990f..17d20351a150a2394aa96ad0e35cdd21fd9fe9f6 100644 --- a/CityDoctorParent/Extensions/CityDoctorGUI/src/main/resources/de/hft/stuttgart/citydoctor2/gui/MainToolBar.fxml +++ b/CityDoctorParent/Extensions/CityDoctorGUI/src/main/resources/de/hft/stuttgart/citydoctor2/gui/MainToolBar.fxml @@ -16,13 +16,7 @@ - - + - + @@ -86,7 +80,7 @@ - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/CityDoctorParent/Extensions/CityDoctorGUI/src/main/resources/log4j2.xml b/CityDoctorParent/Extensions/CityDoctorGUI/src/main/resources/log4j2.xml index 52b82fc21d441190f17422840d0be52cdfaf3de2..e2d7657f5300c5534ab487bf3a3e1cc3b7645a18 100644 --- a/CityDoctorParent/Extensions/CityDoctorGUI/src/main/resources/log4j2.xml +++ b/CityDoctorParent/Extensions/CityDoctorGUI/src/main/resources/log4j2.xml @@ -19,5 +19,8 @@ + + + \ No newline at end of file diff --git a/CityDoctorParent/Extensions/CityDoctorHealer/pom.xml b/CityDoctorParent/Extensions/CityDoctorHealer/pom.xml index 1d031a02f9edca6ee6beb9876ef77c4bdcc21f1c..f31ce66ad603025f32918033b6dc47651b9f1ed1 100644 --- a/CityDoctorParent/Extensions/CityDoctorHealer/pom.xml +++ b/CityDoctorParent/Extensions/CityDoctorHealer/pom.xml @@ -6,7 +6,7 @@ de.hft.stuttgart CityDoctorParent - 3.17.3 + 3.18.0 ../../pom.xml CityDoctorHealer diff --git a/CityDoctorParent/Extensions/CityDoctorHealer/src/test/java/de/hft/stuttgart/citydoctor2/healing/HealAllPolygonsWrongOrientationErrorTest.java b/CityDoctorParent/Extensions/CityDoctorHealer/src/test/java/de/hft/stuttgart/citydoctor2/healing/HealAllPolygonsWrongOrientationErrorTest.java index 58b52a5f4533588824f6e0e552f356f6da6669af..18146a77cb84ef36988543e8406d43c4f7ee1fdd 100644 --- a/CityDoctorParent/Extensions/CityDoctorHealer/src/test/java/de/hft/stuttgart/citydoctor2/healing/HealAllPolygonsWrongOrientationErrorTest.java +++ b/CityDoctorParent/Extensions/CityDoctorHealer/src/test/java/de/hft/stuttgart/citydoctor2/healing/HealAllPolygonsWrongOrientationErrorTest.java @@ -24,11 +24,11 @@ public class HealAllPolygonsWrongOrientationErrorTest { CityDoctorModel model = TestUtil.loadCityModel(path, config); Checker c = new Checker(config, model); c.runChecks(); - Geometry geom = model.getBuildings().get(0).getGeometries().get(0); + Geometry geom = model.getBuildings().toList().get(0).getGeometries().get(0); Assert.assertTrue(geom.containsError(CheckId.C_GE_S_ALL_POLYGONS_WRONG_ORIENTATION)); Healer healer = new Healer(c); - healer.healCityObject(model.getBuildings().get(0)); + healer.healCityObject(model.getBuildings().toList().get(0)); Assert.assertFalse(geom.containsError(CheckId.C_GE_S_ALL_POLYGONS_WRONG_ORIENTATION)); } diff --git a/CityDoctorParent/Extensions/CityDoctorHealer/src/test/java/de/hft/stuttgart/citydoctor2/healing/HealConsecutivePointsSameErrorTest.java b/CityDoctorParent/Extensions/CityDoctorHealer/src/test/java/de/hft/stuttgart/citydoctor2/healing/HealConsecutivePointsSameErrorTest.java index 0e530923d65b4df25d5b53650a9f486ce3a49c61..efd83d4805520fcfa054826c4ac143f2e407102e 100644 --- a/CityDoctorParent/Extensions/CityDoctorHealer/src/test/java/de/hft/stuttgart/citydoctor2/healing/HealConsecutivePointsSameErrorTest.java +++ b/CityDoctorParent/Extensions/CityDoctorHealer/src/test/java/de/hft/stuttgart/citydoctor2/healing/HealConsecutivePointsSameErrorTest.java @@ -26,11 +26,11 @@ public class HealConsecutivePointsSameErrorTest { Checker c = new Checker(config, model); c.runChecks(); - Geometry geom = model.getBuildings().get(0).getGeometries().get(0); + Geometry geom = model.getBuildings().toList().get(0).getGeometries().get(0); Assert.assertTrue(geom.containsError(CheckId.C_GE_R_DUPLICATE_POINT)); Healer healer = new Healer(c); - healer.healCityObject(model.getBuildings().get(0)); + healer.healCityObject(model.getBuildings().toList().get(0)); Assert.assertFalse(geom.containsError(CheckId.C_GE_R_DUPLICATE_POINT)); } diff --git a/CityDoctorParent/Extensions/CityDoctorHealer/src/test/java/de/hft/stuttgart/citydoctor2/healing/HealHoleOutsideErrorTest.java b/CityDoctorParent/Extensions/CityDoctorHealer/src/test/java/de/hft/stuttgart/citydoctor2/healing/HealHoleOutsideErrorTest.java index 50ca0b4724383000d63d397cba99c30eeadc0b8b..909bd46c1cf59af53afacf6de12040ca3a85bca6 100644 --- a/CityDoctorParent/Extensions/CityDoctorHealer/src/test/java/de/hft/stuttgart/citydoctor2/healing/HealHoleOutsideErrorTest.java +++ b/CityDoctorParent/Extensions/CityDoctorHealer/src/test/java/de/hft/stuttgart/citydoctor2/healing/HealHoleOutsideErrorTest.java @@ -25,11 +25,11 @@ public class HealHoleOutsideErrorTest { Checker c = new Checker(config, model); c.runChecks(); - Building building = model.getBuildings().get(0); + Building building = model.getBuildings().toList().get(0); Assert.assertTrue(building.containsError(CheckId.C_GE_P_HOLE_OUTSIDE)); Healer healer = new Healer(c); - healer.healCityObject(model.getBuildings().get(0)); + healer.healCityObject(model.getBuildings().toList().get(0)); Assert.assertFalse(building.containsError(CheckId.C_GE_P_HOLE_OUTSIDE)); } 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 0b064845520f1581bb84717742cdb6b60c523d1d..07adf8c1e520aaaa8d5595768de7217957f5a7c1 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 @@ -138,7 +138,7 @@ public class HealMissingSolidTest { model.saveAs(createSolidFile.toString(), false); CityDoctorModel parsedModel = CityGmlParser.parseCityGmlFile(createSolidFile.toString(), config.getParserConfiguration()); - Building building = parsedModel.getBuildings().get(0); + Building building = parsedModel.getBuildings().toList().get(0); assertEquals(1, building.getGeometries().size()); Geometry geometry2 = building.getGeometries().get(0); assertEquals(GeometryType.SOLID, geometry2.getType()); @@ -162,7 +162,7 @@ public class HealMissingSolidTest { new RequirementConfiguration(false)); CityDoctorModel model = CityGmlParser.parseCityGmlFile("src/test/resources/SimpleSolid_SrefBS_withoutSolid.gml", config.getParserConfiguration()); - Building b = model.getBuildings().get(0); + Building b = model.getBuildings().toList().get(0); assertTrue(b.getGeometries().isEmpty()); Checker c = new Checker(config, model); c.runChecks(); diff --git a/CityDoctorParent/Extensions/CityDoctorHealer/src/test/java/de/hft/stuttgart/citydoctor2/healing/HealNonManifoldEdgeErrorTest.java b/CityDoctorParent/Extensions/CityDoctorHealer/src/test/java/de/hft/stuttgart/citydoctor2/healing/HealNonManifoldEdgeErrorTest.java index 110254116dab3ee0e896f89a21555acb72e9f3ad..2bfca2e739f0002a9b23ffc5284d1ea9f1240715 100644 --- a/CityDoctorParent/Extensions/CityDoctorHealer/src/test/java/de/hft/stuttgart/citydoctor2/healing/HealNonManifoldEdgeErrorTest.java +++ b/CityDoctorParent/Extensions/CityDoctorHealer/src/test/java/de/hft/stuttgart/citydoctor2/healing/HealNonManifoldEdgeErrorTest.java @@ -25,11 +25,11 @@ public class HealNonManifoldEdgeErrorTest { Checker c = new Checker(config, model); c.runChecks(); - Geometry geom = model.getBuildings().get(0).getGeometries().get(0); + Geometry geom = model.getBuildings().toList().get(0).getGeometries().get(0); Assert.assertTrue(geom.containsError(CheckId.C_GE_S_NON_MANIFOLD_EDGE)); Healer healer = new Healer(c); - healer.healCityObject(model.getBuildings().get(0)); + healer.healCityObject(model.getBuildings().toList().get(0)); Assert.assertFalse(geom.containsError(CheckId.C_GE_S_NON_MANIFOLD_EDGE)); } 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 7b5576bdf330e218e813c323b28ada149660d73e..5359f2d6b1164dc4aff26c8f216c4e83f4706474 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 @@ -43,12 +43,12 @@ public class HealPlanarPolygonErrorTest { Checker c = new Checker(config, model); c.runChecks(); - Geometry geom = model.getBuildings().get(0).getGeometries().get(0); + Geometry geom = model.getBuildings().toList().get(0).getGeometries().get(0); Assert.assertTrue(geom.containsError(CheckId.C_GE_P_NON_PLANAR)); Healer healer = new Healer(c); healer.setNumberOfIterations(2); - healer.healCityObject(model.getBuildings().get(0)); + healer.healCityObject(model.getBuildings().toList().get(0)); Assert.assertFalse(geom.containsError(CheckId.C_GE_P_NON_PLANAR)); diff --git a/CityDoctorParent/Extensions/CityDoctorHealer/src/test/java/de/hft/stuttgart/citydoctor2/healing/HealPolygonWithoutSurfaceTest.java b/CityDoctorParent/Extensions/CityDoctorHealer/src/test/java/de/hft/stuttgart/citydoctor2/healing/HealPolygonWithoutSurfaceTest.java index 28e6832c7b5b721f47d7a40d844f4c0c4b295603..0ccc24f0ccb65a362dbdfe7f88f65e87e747a8c6 100644 --- a/CityDoctorParent/Extensions/CityDoctorHealer/src/test/java/de/hft/stuttgart/citydoctor2/healing/HealPolygonWithoutSurfaceTest.java +++ b/CityDoctorParent/Extensions/CityDoctorHealer/src/test/java/de/hft/stuttgart/citydoctor2/healing/HealPolygonWithoutSurfaceTest.java @@ -35,11 +35,11 @@ public class HealPolygonWithoutSurfaceTest { Checker c = new Checker(config, model); c.runChecks(); - Building building = model.getBuildings().get(0); + Building building = model.getBuildings().toList().get(0); Assert.assertTrue(building.containsError(CheckId.C_SE_POLYGON_WITHOUT_SURFACE)); Healer healer = new Healer(c); - healer.healCityObject(model.getBuildings().get(0)); + healer.healCityObject(model.getBuildings().toList().get(0)); Assert.assertFalse(building.containsError(CheckId.C_SE_POLYGON_WITHOUT_SURFACE)); @@ -49,7 +49,7 @@ public class HealPolygonWithoutSurfaceTest { CityDoctorModel loadedModel = TestUtil.loadCityModel(outputFile.toString(), config); c = new Checker(config, loadedModel); c.runChecks(); - building = loadedModel.getBuildings().get(0); + building = loadedModel.getBuildings().toList().get(0); Assert.assertFalse(building.containsError(CheckId.C_SE_POLYGON_WITHOUT_SURFACE)); } diff --git a/CityDoctorParent/Extensions/CityDoctorHealer/src/test/java/de/hft/stuttgart/citydoctor2/healing/HealPolygonWrongOrientationErrorTest.java b/CityDoctorParent/Extensions/CityDoctorHealer/src/test/java/de/hft/stuttgart/citydoctor2/healing/HealPolygonWrongOrientationErrorTest.java index 7f640b9690246f4089a6ae2fb335916c8a00b087..9d8e1b8da5bc8f06a1bb9ae630cedc4415516ae7 100644 --- a/CityDoctorParent/Extensions/CityDoctorHealer/src/test/java/de/hft/stuttgart/citydoctor2/healing/HealPolygonWrongOrientationErrorTest.java +++ b/CityDoctorParent/Extensions/CityDoctorHealer/src/test/java/de/hft/stuttgart/citydoctor2/healing/HealPolygonWrongOrientationErrorTest.java @@ -41,11 +41,11 @@ public class HealPolygonWrongOrientationErrorTest { Checker c = new Checker(config, model); c.runChecks(); - Geometry geom = model.getBuildings().get(0).getGeometries().get(0); + Geometry geom = model.getBuildings().toList().get(0).getGeometries().get(0); Assert.assertTrue(geom.containsError(CheckId.C_GE_S_POLYGON_WRONG_ORIENTATION)); Healer healer = new Healer(c); - healer.healCityObject(model.getBuildings().get(0)); + healer.healCityObject(model.getBuildings().toList().get(0)); Assert.assertFalse(geom.containsError(CheckId.C_GE_S_POLYGON_WRONG_ORIENTATION)); } diff --git a/CityDoctorParent/Extensions/CityDoctorHealer/src/test/java/de/hft/stuttgart/citydoctor2/healing/HealRingNotClosedErrorTest.java b/CityDoctorParent/Extensions/CityDoctorHealer/src/test/java/de/hft/stuttgart/citydoctor2/healing/HealRingNotClosedErrorTest.java index 6622e3554e2d7b51c9cae1acc9c4e5b1c1727ce0..e8f03e12491b30431cd1fa96029b36e8efc63faf 100644 --- a/CityDoctorParent/Extensions/CityDoctorHealer/src/test/java/de/hft/stuttgart/citydoctor2/healing/HealRingNotClosedErrorTest.java +++ b/CityDoctorParent/Extensions/CityDoctorHealer/src/test/java/de/hft/stuttgart/citydoctor2/healing/HealRingNotClosedErrorTest.java @@ -25,11 +25,11 @@ public class HealRingNotClosedErrorTest { Checker c = new Checker(config, model); c.runChecks(); - Geometry geom = model.getBuildings().get(0).getGeometries().get(0); + Geometry geom = model.getBuildings().toList().get(0).getGeometries().get(0); Assert.assertTrue(geom.containsError(CheckId.C_GE_R_NOT_CLOSED)); Healer healer = new Healer(c); - healer.healCityObject(model.getBuildings().get(0)); + healer.healCityObject(model.getBuildings().toList().get(0)); Assert.assertFalse(geom.containsError(CheckId.C_GE_R_NOT_CLOSED)); } diff --git a/CityDoctorParent/Extensions/CityDoctorHealer/src/test/java/de/hft/stuttgart/citydoctor2/healing/HealRingSelfIntErrorTest.java b/CityDoctorParent/Extensions/CityDoctorHealer/src/test/java/de/hft/stuttgart/citydoctor2/healing/HealRingSelfIntErrorTest.java index 8a33573b70cbd02ac734d900e0fbf0321d0724da..4408e1226c9b235ba9a2bbc78be96c71ef15155b 100644 --- a/CityDoctorParent/Extensions/CityDoctorHealer/src/test/java/de/hft/stuttgart/citydoctor2/healing/HealRingSelfIntErrorTest.java +++ b/CityDoctorParent/Extensions/CityDoctorHealer/src/test/java/de/hft/stuttgart/citydoctor2/healing/HealRingSelfIntErrorTest.java @@ -190,11 +190,11 @@ public class HealRingSelfIntErrorTest { Checker c = new Checker(config, model); c.runChecks(); - Geometry geom = model.getBuildings().get(0).getGeometries().get(0); + Geometry geom = model.getBuildings().toList().get(0).getGeometries().get(0); Assert.assertTrue(geom.containsError(CheckId.C_GE_R_SELF_INTERSECTION)); Healer healer = new Healer(c); - healer.healCityObject(model.getBuildings().get(0)); + healer.healCityObject(model.getBuildings().toList().get(0)); Assert.assertFalse(geom.containsError(CheckId.C_GE_R_SELF_INTERSECTION)); } @@ -208,11 +208,11 @@ public class HealRingSelfIntErrorTest { Checker c = new Checker(config, model); c.runChecks(); - Geometry geom = model.getBuildings().get(0).getGeometries().get(0); + Geometry geom = model.getBuildings().toList().get(0).getGeometries().get(0); Assert.assertTrue(geom.containsError(CheckId.C_GE_R_SELF_INTERSECTION)); Healer healer = new Healer(c); - healer.healCityObject(model.getBuildings().get(0)); + healer.healCityObject(model.getBuildings().toList().get(0)); Assert.assertFalse(geom.containsError(CheckId.C_GE_R_SELF_INTERSECTION)); } @@ -228,11 +228,11 @@ public class HealRingSelfIntErrorTest { Checker c = new Checker(config, model); c.runChecks(); - Geometry geom = model.getBuildings().get(0).getGeometries().get(0); + Geometry geom = model.getBuildings().toList().get(0).getGeometries().get(0); Assert.assertTrue(geom.containsError(CheckId.C_GE_R_SELF_INTERSECTION)); Healer healer = new Healer(c); - healer.healCityObject(model.getBuildings().get(0)); + healer.healCityObject(model.getBuildings().toList().get(0)); Assert.assertFalse(geom.containsError(CheckId.C_GE_R_SELF_INTERSECTION)); } diff --git a/CityDoctorParent/Extensions/CityDoctorHealer/src/test/java/de/hft/stuttgart/citydoctor2/healing/HealSameOrientationErrorTest.java b/CityDoctorParent/Extensions/CityDoctorHealer/src/test/java/de/hft/stuttgart/citydoctor2/healing/HealSameOrientationErrorTest.java index e5b64193dd4c2664e32cbd33b65a3e02bb169bbd..f0802787cf00831c6d04c58ad165b4e83e330f43 100644 --- a/CityDoctorParent/Extensions/CityDoctorHealer/src/test/java/de/hft/stuttgart/citydoctor2/healing/HealSameOrientationErrorTest.java +++ b/CityDoctorParent/Extensions/CityDoctorHealer/src/test/java/de/hft/stuttgart/citydoctor2/healing/HealSameOrientationErrorTest.java @@ -26,11 +26,11 @@ public class HealSameOrientationErrorTest { Checker c = new Checker(config, model); c.runChecks(); - Geometry geom = model.getBuildings().get(0).getGeometries().get(0); + Geometry geom = model.getBuildings().toList().get(0).getGeometries().get(0); Assert.assertTrue(geom.containsError(CheckId.C_GE_P_ORIENTATION_RINGS_SAME)); Healer healer = new Healer(c); - healer.healCityObject(model.getBuildings().get(0)); + healer.healCityObject(model.getBuildings().toList().get(0)); Assert.assertFalse(geom.containsError(CheckId.C_GE_P_ORIENTATION_RINGS_SAME)); } 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 5a8713a8664a8429f9b8550f9aaad5abe6d99f65..06e4d9e1f09b6991bdfff09db9446ca748092181 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 @@ -439,7 +439,7 @@ public class HealSolidNotClosedErrorTest { Checker c = new Checker(config, model); c.runChecks(); - Geometry geom = model.getBuildings().get(0).getGeometries().get(0); + Geometry geom = model.getBuildings().toList().get(0).getGeometries().get(0); geom.updateVertices(); for (Vertex v : geom.getVertices()) { v.setX(v.getX() - 10); @@ -449,7 +449,7 @@ public class HealSolidNotClosedErrorTest { Healer healer = new Healer(c); //healer.setNumberOfIterations(2); - healer.healCityObject(model.getBuildings().get(0)); + 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/HealTooFewPointsTest.java b/CityDoctorParent/Extensions/CityDoctorHealer/src/test/java/de/hft/stuttgart/citydoctor2/healing/HealTooFewPointsTest.java index eac3472b3097e9314a33bb5022dbbd62e0334519..8d22d6e6d71bb106ea2912b6af0dcb82921a84f7 100644 --- a/CityDoctorParent/Extensions/CityDoctorHealer/src/test/java/de/hft/stuttgart/citydoctor2/healing/HealTooFewPointsTest.java +++ b/CityDoctorParent/Extensions/CityDoctorHealer/src/test/java/de/hft/stuttgart/citydoctor2/healing/HealTooFewPointsTest.java @@ -27,11 +27,11 @@ public class HealTooFewPointsTest { Checker c = new Checker(config, model); c.runChecks(); - Geometry geom = model.getBuildings().get(0).getGeometries().get(0); + Geometry geom = model.getBuildings().toList().get(0).getGeometries().get(0); assertTrue(geom.containsError(CheckId.C_GE_R_TOO_FEW_POINTS)); Healer healer = new Healer(c); - healer.healCityObject(model.getBuildings().get(0)); + healer.healCityObject(model.getBuildings().toList().get(0)); assertFalse(geom.containsError(CheckId.C_GE_R_TOO_FEW_POINTS)); } 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 a36ce00d1f8fd5dc57c7e4f01fc46000ef87fd62..63ccbd0519033df305c12372b7eff5a7f53b3391 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 @@ -45,7 +45,7 @@ public class TestHealer { c.runChecks(); Building b = null; - for (Building building : model.getBuildings()) { + for (Building building : model.getBuildings().toList()) { if (building.getGmlId().getGmlString().equals("DEBE08YYF0004KZs")) { b = building; break; @@ -125,8 +125,8 @@ public class TestHealer { c.runChecks(); Healer healer = new Healer(c); - Geometry geom = model.getBuildings().get(0).getGeometries().get(0); - healer.healCityObject(model.getBuildings().get(0)); + Geometry geom = model.getBuildings().toList().get(0).getGeometries().get(0); + healer.healCityObject(model.getBuildings().toList().get(0)); c.runChecks(); assertFalse(geom.containsAnyError()); @@ -151,11 +151,11 @@ public class TestHealer { Checker c = new Checker(config, model); c.runChecks(); - Geometry geom = model.getBuildings().get(0).getGeometries().get(0); + Geometry geom = model.getBuildings().toList().get(0).getGeometries().get(0); Healer healer = new Healer(c); healer.setNumberOfIterations(33); - healer.healCityObject(model.getBuildings().get(0)); + healer.healCityObject(model.getBuildings().toList().get(0)); c.runChecks(); assertFalse(geom.containsAnyError()); @@ -171,10 +171,10 @@ public class TestHealer { Checker c = new Checker(config, model); c.runChecks(); - Geometry geom = model.getBuildings().get(0).getGeometries().get(0); + Geometry geom = model.getBuildings().toList().get(0).getGeometries().get(0); Healer healer = new Healer(c); - healer.healCityObject(model.getBuildings().get(0)); + healer.healCityObject(model.getBuildings().toList().get(0)); c.runChecks(); assertFalse(geom.containsAnyError()); @@ -190,11 +190,11 @@ public class TestHealer { Checker c = new Checker(config, model); c.runChecks(); - Geometry geom = model.getBuildings().get(0).getGeometries().get(0); + Geometry geom = model.getBuildings().toList().get(0).getGeometries().get(0); Healer healer = new Healer(c); healer.setNumberOfIterations(83); - healer.healCityObject(model.getBuildings().get(0)); + healer.healCityObject(model.getBuildings().toList().get(0)); c.runChecks(); assertFalse(geom.containsAnyError()); @@ -210,11 +210,11 @@ public class TestHealer { Checker c = new Checker(config, model); c.runChecks(); - Geometry geom = model.getBuildings().get(0).getGeometries().get(0); + Geometry geom = model.getBuildings().toList().get(0).getGeometries().get(0); Healer healer = new Healer(c); healer.setNumberOfIterations(165); - healer.healCityObject(model.getBuildings().get(0)); + healer.healCityObject(model.getBuildings().toList().get(0)); c.runChecks(); assertFalse(geom.containsAnyError()); @@ -241,7 +241,7 @@ public class TestHealer { Checker c = new Checker(config, model); c.runChecks(); - Building b = model.getBuildings().get(0); + Building b = model.getBuildings().toList().get(0); Healer healer = new Healer(c); healer.healCityObject(b); c.runChecks(); @@ -261,11 +261,11 @@ public class TestHealer { Checker c = new Checker(config, model); c.runChecks(); - Geometry geom = model.getBuildings().get(0).getGeometries().get(0); + Geometry geom = model.getBuildings().toList().get(0).getGeometries().get(0); Healer healer = new Healer(c); healer.setNumberOfIterations(45); - healer.healCityObject(model.getBuildings().get(0)); + healer.healCityObject(model.getBuildings().toList().get(0)); c.runChecks(); assertFalse(geom.containsAnyError()); @@ -297,10 +297,10 @@ public class TestHealer { Checker c = new Checker(config, model); c.runChecks(); - Geometry geom = model.getBuildings().get(0).getGeometries().get(0); + Geometry geom = model.getBuildings().toList().get(0).getGeometries().get(0); Healer healer = new Healer(c); healer.setNumberOfIterations(100); - healer.healCityObject(model.getBuildings().get(0)); + healer.healCityObject(model.getBuildings().toList().get(0)); c.runChecks(); assertFalse(geom.containsAnyError()); 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 ca21944ccbe7f6ad47383cbf987d7b0a719e44fd..72a2450f86cbed1d2e6adc7eab79028e8d84d332 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 @@ -38,15 +38,15 @@ public class TestUtil { if (gmlId == null) { return null; } - Polygon result = getPolygonById(gmlId, model.getBuildings()); + Polygon result = getPolygonById(gmlId, model.getBuildings().toList()); if (result != null) { return result; } - result = getPolygonById(gmlId, model.getVegetation()); + result = getPolygonById(gmlId, model.getVegetation().toList()); if (result != null) { return result; } - return getPolygonById(gmlId, model.getTransportation()); + return getPolygonById(gmlId, model.getTransportation().toList()); } private static Polygon getPolygonById(String gmlId, List features) { @@ -85,17 +85,17 @@ public class TestUtil { if (featureId == null) { return null; } - for (CityObject co : model.getBuildings()) { + for (CityObject co : model.getBuildings().toList()) { if (featureId.equals(co.getGmlId().getGmlString())) { return co; } } - for (CityObject co : model.getTransportation()) { + for (CityObject co : model.getTransportation().toList()) { if (featureId.equals(co.getGmlId().getGmlString())) { return co; } } - for (CityObject co : model.getVegetation()) { + for (CityObject co : model.getVegetation().toList()) { if (featureId.equals(co.getGmlId().getGmlString())) { return co; } diff --git a/CityDoctorParent/Extensions/CityDoctorHealerGUI/pom.xml b/CityDoctorParent/Extensions/CityDoctorHealerGUI/pom.xml index 8eb1cfeeaf651e273121b1da6c586d02b89e23aa..7368ea56d9515f15c9c4287e2b2598aa00767e9b 100644 --- a/CityDoctorParent/Extensions/CityDoctorHealerGUI/pom.xml +++ b/CityDoctorParent/Extensions/CityDoctorHealerGUI/pom.xml @@ -7,7 +7,7 @@ de.hft.stuttgart CityDoctorParent - 3.17.3 + 3.18.0 ../../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 4cb6311c9c39331b6edb3e83e54295e99c94239a..5668a4570069b12de7daba80d2ebf29eeaf91e92 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,60 +538,45 @@ public class HealerController { } public void injectSolid(boolean useBs, boolean useBi, boolean useLod2, boolean useLod3, boolean useLod4) { - if (model == null || currentFeature == null) { - return; - } - CityObject oldFeature = currentFeature; - currentFeature.prepareForChecking(); - if (currentFeature instanceof BoundarySurface) { - BoundarySurface surface = (BoundarySurface) currentFeature; - currentFeature = surface.getParent(); - } - if (!(currentFeature instanceof Building)) { - return; - } - // collect polygons - Map> availablePolygons = new EnumMap<>(Lod.class); - Map> existingPolygons = new EnumMap<>(Lod.class); - Building b = (Building) currentFeature; - collectPolygons(useBs, useBi, availablePolygons, existingPolygons, b); - if (useLod2) { - insertSolidGeometry(availablePolygons, b, existingPolygons, Lod.LOD2); - } - if (useLod3) { - insertSolidGeometry(availablePolygons, b, existingPolygons, Lod.LOD3); - } - if (useLod4) { - insertSolidGeometry(availablePolygons, b, existingPolygons, Lod.LOD4); +// if (model == null || currentFeature == null) { +// return; +// } + + for (Building b : model.getBuildings()) { + // collect polygons + Map> availablePolygons = new EnumMap<>(Lod.class); + Map> existingPolygons = new EnumMap<>(Lod.class); + collectPolygons(useBs, useBi, availablePolygons, existingPolygons, b); + if (useLod2) { + insertSolidGeometry(availablePolygons, b, existingPolygons, Lod.LOD2); + } + if (useLod3) { + insertSolidGeometry(availablePolygons, b, existingPolygons, Lod.LOD3); + } + if (useLod4) { + insertSolidGeometry(availablePolygons, b, existingPolygons, Lod.LOD4); + } + for (BuildingPart part : b.getBuildingParts()) { + // collect polygons + availablePolygons = new EnumMap<>(Lod.class); + existingPolygons = new EnumMap<>(Lod.class); + collectPolygons(useBs, useBi, availablePolygons, existingPolygons, part); + if (useLod2) { + insertSolidGeometry(availablePolygons, part, existingPolygons, Lod.LOD2); + } + if (useLod3) { + insertSolidGeometry(availablePolygons, part, existingPolygons, Lod.LOD3); + } + if (useLod4) { + insertSolidGeometry(availablePolygons, part, existingPolygons, Lod.LOD4); + } + } } - nextFeature = null; - nextGeometry = null; - Lod lod = currentGeometry.getLod(); - GeometryType type = GeometryType.SOLID; - currentGeometry = Objects.requireNonNull(currentFeature.getGeometry(type, lod)); - checker.executeChecksForCheckable(currentFeature); - healerView.getNextErrorList().getItems().clear(); - healerView.getNextMeshGroup().getChildren().clear(); - updateCurrentErrors(); - currentTriangulatedGeometry = TriangulatedGeometry.of(currentGeometry); - currentErrorVisitor.setGeometry(currentTriangulatedGeometry); - currentTriangulatedGeometry.setCullFace(culling); - currentTriangulatedGeometry.setDrawMode(drawMode); - healerView.zoomOutForBoundingBox(currentGeometry.calculateBoundingBox()); - - healerView.getCurrentMeshGroup().getChildren().clear(); - healerView.getCurrentMeshGroup().getChildren().addAll(currentTriangulatedGeometry.getMeshes()); - healerView.getNextStepBtn().setDisable(false); - healerView.getHealCompleteBtn().setDisable(false); - healerView.getAcceptBtn().setDisable(true); - healerView.getCancelBtn().setDisable(true); - healerView.getSolidInjectorBtn().setDisable(true); - currentFeature = oldFeature; } private void collectPolygons(boolean useBs, boolean useBi, Map> availablePolygons, - Map> existingPolygons, Building b) { + Map> existingPolygons, AbstractBuilding b) { if (useBs) { collectPolygons(availablePolygons, b.getBoundarySurfaces()); } @@ -604,13 +589,13 @@ public class HealerController { collectPolygons(availablePolygons, bi.getBoundarySurfaces()); } } - for (Geometry geom : b.getGeometries()) { - Set polygons = existingPolygons.computeIfAbsent(geom.getLod(), l -> new HashSet<>()); - polygons.addAll(geom.getPolygons()); - } +// for (Geometry geom : b.getGeometries()) { +// Set polygons = existingPolygons.computeIfAbsent(geom.getLod(), l -> new HashSet<>()); +// polygons.addAll(geom.getPolygons()); +// } } - private void insertSolidGeometry(Map> availablePolygons, Building b, + private void insertSolidGeometry(Map> availablePolygons, AbstractBuilding b, Map> existingPolygons, Lod lod) { List newPolygons = availablePolygons.get(lod); if (newPolygons != null) { @@ -689,9 +674,7 @@ public class HealerController { // triangle area is too small, ignore return; } - for (Building b : model.getBuildings()) { - MeshGenerator.replaceGeometryWithMeshedGeometry(b, area); - } + model.getBuildings().forEach(building -> MeshGenerator.replaceGeometryWithMeshedGeometry(building, area)); } catch (NumberFormatException e) { // no real number was inserted, do nothing } diff --git a/CityDoctorParent/Extensions/CityDoctorHealerGenetic/pom.xml b/CityDoctorParent/Extensions/CityDoctorHealerGenetic/pom.xml index 352b8af31ec441acd47ac26c80fe0a1b5d885110..280bad626a5cc32576f63953edd9bfc249e18914 100644 --- a/CityDoctorParent/Extensions/CityDoctorHealerGenetic/pom.xml +++ b/CityDoctorParent/Extensions/CityDoctorHealerGenetic/pom.xml @@ -4,7 +4,7 @@ de.hft.stuttgart CityDoctorParent - 3.17.3 + 3.18.0 ../../pom.xml CityDoctorHealerGenetic diff --git a/CityDoctorParent/Extensions/CityDoctorHealerGenetic/src/main/java/de/hft/stuttgart/citydoctor2/healer/genetic/gui/GeneticsGUI.java b/CityDoctorParent/Extensions/CityDoctorHealerGenetic/src/main/java/de/hft/stuttgart/citydoctor2/healer/genetic/gui/GeneticsGUI.java index 894e4c7b02589a59a27fb14fd04339e3250c9ba0..c9a65976c3bfb2a0db457e9e3b06ebc87837da74 100644 --- a/CityDoctorParent/Extensions/CityDoctorHealerGenetic/src/main/java/de/hft/stuttgart/citydoctor2/healer/genetic/gui/GeneticsGUI.java +++ b/CityDoctorParent/Extensions/CityDoctorHealerGenetic/src/main/java/de/hft/stuttgart/citydoctor2/healer/genetic/gui/GeneticsGUI.java @@ -329,7 +329,7 @@ public class GeneticsGUI extends View { parserConfig); currentChecker = new Checker(model1); currentChecker.runChecks(); - Building building = model1.getBuildings().get(0); + Building building = model1.getBuildings().toList().getFirst(); currentGeometry = building.getGeometries().get(0); currentFeature = building; showCurrentGeometry(); diff --git a/CityDoctorParent/pom.xml b/CityDoctorParent/pom.xml index 84bc1df25c5d4d94f4944e7658f82a353383d70b..b5198f83b37d839a77d49dd77d9d5806dcd0f2cc 100644 --- a/CityDoctorParent/pom.xml +++ b/CityDoctorParent/pom.xml @@ -5,7 +5,7 @@ 4.0.0 de.hft.stuttgart CityDoctorParent - 3.17.3 + 3.18.0 pom CityDoctorParent @@ -242,6 +242,21 @@ earcut4j 2.2.2 + + org.orbisgis + h2gis + 2.2.3 + + + com.github.ben-manes.caffeine + caffeine + 3.2.2 + + + com.zaxxer + HikariCP + 7.0.2 + @@ -267,6 +282,17 @@ info.picocli picocli + + org.apache.logging.log4j + log4j-slf4j18-impl + 2.18.0 + test + + + junit + junit + test + @@ -277,10 +303,10 @@ Extensions/CityDoctorGUI - Extensions/CityDoctorAutoPro - Extensions/CityDoctorHealer - Extensions/CityDoctorHealerGenetic - Extensions/CityDoctorHealerGUI + + + + \ No newline at end of file