Commit 3dac795e authored by Riegel's avatar Riegel
Browse files

Merge branch 'dev' into 'master'

Version 3.17.0 Release

See merge request !28
1 merge request!28Version 3.17.0 Release
Pipeline #11012 passed with stage
in 1 minute and 10 seconds
Showing with 1310 additions and 190 deletions
+1310 -190
...@@ -33,7 +33,7 @@ import de.hft.stuttgart.citydoctor2.datastructure.Vertex; ...@@ -33,7 +33,7 @@ import de.hft.stuttgart.citydoctor2.datastructure.Vertex;
import de.hft.stuttgart.citydoctor2.math.Vector3d; import de.hft.stuttgart.citydoctor2.math.Vector3d;
/** /**
* Tesselator to create triangles out of polygons. * Tesselator to create triangles out of polygons. Uses JOGL implementation.
* *
* @author Matthias Betz * @author Matthias Betz
* *
...@@ -102,6 +102,10 @@ public class JoglTesselator { ...@@ -102,6 +102,10 @@ public class JoglTesselator {
} }
public static TesselatedPolygon tesselatePolygon(Polygon p) { public static TesselatedPolygon tesselatePolygon(Polygon p) {
return tesselatePolygon(p, true);
}
public static TesselatedPolygon tesselatePolygon(Polygon p, boolean discardDegeneratedTriangles) {
ArrayList<Vector3d> vertices = new ArrayList<>(); ArrayList<Vector3d> vertices = new ArrayList<>();
Vector3d normal = p.calculateNormalNormalized(); Vector3d normal = p.calculateNormalNormalized();
synchronized (tess) { synchronized (tess) {
...@@ -121,7 +125,7 @@ public class JoglTesselator { ...@@ -121,7 +125,7 @@ public class JoglTesselator {
GLU.gluTessEndPolygon(tess); GLU.gluTessEndPolygon(tess);
ArrayList<Integer> indices = new ArrayList<>(); ArrayList<Integer> indices = new ArrayList<>();
for (Primitive primitive : primitives) { for (Primitive primitive : primitives) {
primitive.fillListWithIndices(indices); primitive.fillListWithIndices(indices, discardDegeneratedTriangles);
} }
primitives.clear(); primitives.clear();
return new TesselatedPolygon(vertices, indices, p); return new TesselatedPolygon(vertices, indices, p);
...@@ -137,7 +141,7 @@ public class JoglTesselator { ...@@ -137,7 +141,7 @@ public class JoglTesselator {
GLU.gluTessEndContour(tess); GLU.gluTessEndContour(tess);
} }
public static TesselatedRing tesselateRing(LinearRing r) { public static TesselatedRing tesselateRing(LinearRing r, boolean discardDegeneratedTriangles) {
ArrayList<Vector3d> vertices = new ArrayList<>(); ArrayList<Vector3d> vertices = new ArrayList<>();
Vector3d normal = r.calculateNormal(); Vector3d normal = r.calculateNormal();
synchronized (tess) { synchronized (tess) {
...@@ -147,13 +151,17 @@ public class JoglTesselator { ...@@ -147,13 +151,17 @@ public class JoglTesselator {
GLU.gluTessEndPolygon(tess); GLU.gluTessEndPolygon(tess);
ArrayList<Integer> indices = new ArrayList<>(); ArrayList<Integer> indices = new ArrayList<>();
for (Primitive primitive : primitives) { for (Primitive primitive : primitives) {
primitive.fillListWithIndices(indices); primitive.fillListWithIndices(indices, discardDegeneratedTriangles);
} }
primitives.clear(); primitives.clear();
return new TesselatedRing(vertices, indices, r); return new TesselatedRing(vertices, indices, r);
} }
} }
public static TesselatedRing tesselateRing(LinearRing r) {
return tesselateRing(r, true);
}
private JoglTesselator() { private JoglTesselator() {
// only static useage // only static useage
} }
......
...@@ -49,30 +49,34 @@ public class Primitive { ...@@ -49,30 +49,34 @@ public class Primitive {
this.type = type; this.type = type;
} }
public void fillListWithIndices(List<Integer> indices) { public void fillListWithIndices(List<Integer> indices, boolean discardDegeneratedTriangles) {
switch (type) { switch (type) {
case GL.GL_TRIANGLES: case GL.GL_TRIANGLES:
for (int i = 0; i < pIndices.size(); i += 3) { for (int i = 0; i < pIndices.size(); i += 3) {
addToListIfAreaNonNull(pIndices.get(i), pIndices.get(i + 1), pIndices.get(i + 2), indices); addToListIfAreaNonNull(pIndices.get(i), pIndices.get(i + 1), pIndices.get(i + 2), indices,
discardDegeneratedTriangles);
} }
break; break;
case GL.GL_TRIANGLE_STRIP: case GL.GL_TRIANGLE_STRIP:
for (int i = 0; i < pIndices.size() - 2; i++) { for (int i = 0; i < pIndices.size() - 2; i++) {
if (i % 2 == 0) { if (i % 2 == 0) {
addToListIfAreaNonNull(pIndices.get(i), pIndices.get(i + 1), pIndices.get(i + 2), indices); addToListIfAreaNonNull(pIndices.get(i), pIndices.get(i + 1), pIndices.get(i + 2), indices,
discardDegeneratedTriangles);
} else { } else {
addToListIfAreaNonNull(pIndices.get(i), pIndices.get(i + 2), pIndices.get(i + 1), indices); addToListIfAreaNonNull(pIndices.get(i), pIndices.get(i + 2), pIndices.get(i + 1), indices,
discardDegeneratedTriangles);
} }
} }
break; break;
case GL.GL_TRIANGLE_FAN: case GL.GL_TRIANGLE_FAN:
Integer first = pIndices.get(0); Integer first = pIndices.get(0);
for (int i = 0; i < pIndices.size() - 2; i++) { for (int i = 0; i < pIndices.size() - 2; i++) {
addToListIfAreaNonNull(first, pIndices.get(i + 1), pIndices.get(i + 2), indices); addToListIfAreaNonNull(first, pIndices.get(i + 1), pIndices.get(i + 2), indices,
discardDegeneratedTriangles);
} }
break; break;
default: default:
throw new IllegalStateException("unknown type found: " + type); throw new IllegalStateException("unknown triangle type found: " + type);
} }
} }
...@@ -80,17 +84,18 @@ public class Primitive { ...@@ -80,17 +84,18 @@ public class Primitive {
pIndices.add(i); pIndices.add(i);
} }
private void addToListIfAreaNonNull(Integer i1, Integer i2, Integer i3, List<Integer> indices) { private void addToListIfAreaNonNull(Integer i1, Integer i2, Integer i3, List<Integer> indices,
boolean discardDegeneratedTriangles) {
Vector3d v1 = vertices.get(i1); Vector3d v1 = vertices.get(i1);
Vector3d v2 = vertices.get(i2); Vector3d v2 = vertices.get(i2);
Vector3d v3 = vertices.get(i3); Vector3d v3 = vertices.get(i3);
double area = Math.abs(calculateAreaOfTriangle(v1, v2, v3)); if (discardDegeneratedTriangles && Math.abs(calculateAreaOfTriangle(v1, v2, v3)) <= AREA_EPSILON) {
if (area > AREA_EPSILON) { // switch to discard degenerated triangles is enabled and triangle has nearly no area
logger.trace("Tesselator created degenerated triangle, ignoring");
} else {
indices.add(i1); indices.add(i1);
indices.add(i2); indices.add(i2);
indices.add(i3); indices.add(i3);
} else {
logger.trace("Tesselator created degenerated triangle, ignoring");
} }
} }
......
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());
}
}
...@@ -26,6 +26,10 @@ import de.hft.stuttgart.citydoctor2.datastructure.CityDoctorModel; ...@@ -26,6 +26,10 @@ import de.hft.stuttgart.citydoctor2.datastructure.CityDoctorModel;
import de.hft.stuttgart.citydoctor2.datastructure.CityObject; import de.hft.stuttgart.citydoctor2.datastructure.CityObject;
import de.hft.stuttgart.citydoctor2.datastructure.Geometry; import de.hft.stuttgart.citydoctor2.datastructure.Geometry;
import de.hft.stuttgart.citydoctor2.datastructure.Polygon; 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.datastructure.Vertex;
import de.hft.stuttgart.citydoctor2.math.Vector3d; import de.hft.stuttgart.citydoctor2.math.Vector3d;
...@@ -49,7 +53,7 @@ public class BoundingBoxCalculator { ...@@ -49,7 +53,7 @@ public class BoundingBoxCalculator {
* Only the exterior rings of the polygons is used as inner rings should be * Only the exterior rings of the polygons is used as inner rings should be
* within the exterior or they are faulty. * within the exterior or they are faulty.
* *
* @param a list of polygons containing the vertices * @param polygons a list of polygons containing the vertices
* @return an BoundingBox containing the two end points of the bounding box. * @return an BoundingBox containing the two end points of the bounding box.
*/ */
public static BoundingBox calculateBoundingBox(Collection<? extends Polygon> polygons) { public static BoundingBox calculateBoundingBox(Collection<? extends Polygon> polygons) {
...@@ -98,12 +102,16 @@ public class BoundingBoxCalculator { ...@@ -98,12 +102,16 @@ public class BoundingBoxCalculator {
Vector3d low = new Vector3d(Double.MAX_VALUE, Double.MAX_VALUE, Double.MAX_VALUE); 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); Vector3d high = new Vector3d(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY);
//TODO: Rework this using visitors
findMinMax(low, high, model.getBuildings()); findMinMax(low, high, model.getBuildings());
findMinMax(low, high, model.getBridges()); findMinMax(low, high, model.getBridges());
findMinMax(low, high, model.getLand()); findMinMax(low, high, model.getLand());
findMinMax(low, high, model.getTransportation()); findMinMaxTransport(low, high, model.getTransportation());
findMinMax(low, high, model.getWater()); findMinMax(low, high, model.getWater());
findMinMax(low, high, model.getVegetation()); 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]; Vector3d[] result = new Vector3d[2];
result[0] = low; result[0] = low;
...@@ -151,6 +159,23 @@ public class BoundingBoxCalculator { ...@@ -151,6 +159,23 @@ 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<? extends TransportationObject> 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());
}
} else if (to instanceof TrafficSpaceObject tso) {
findMinMaxTransport(low, high, tso.getTrafficAreas());
}
}
}
private static void findMinMax(Vector3d low, Vector3d high, CityObject co) { private static void findMinMax(Vector3d low, Vector3d high, CityObject co) {
for (Geometry geom : co.getGeometries()) { for (Geometry geom : co.getGeometries()) {
if (geom.getVertices() == null) { if (geom.getVertices() == null) {
......
...@@ -25,6 +25,7 @@ import java.util.List; ...@@ -25,6 +25,7 @@ import java.util.List;
import de.hft.stuttgart.citydoctor2.datastructure.ConcretePolygon; import de.hft.stuttgart.citydoctor2.datastructure.ConcretePolygon;
import de.hft.stuttgart.citydoctor2.datastructure.Polygon; import de.hft.stuttgart.citydoctor2.datastructure.Polygon;
import de.hft.stuttgart.citydoctor2.math.Segment3d; import de.hft.stuttgart.citydoctor2.math.Segment3d;
import de.hft.stuttgart.citydoctor2.math.Triangle3d;
/** /**
* Result of a polygon polygon intersection. * Result of a polygon polygon intersection.
...@@ -38,7 +39,7 @@ public class PolygonIntersection implements Serializable { ...@@ -38,7 +39,7 @@ public class PolygonIntersection implements Serializable {
private static final long serialVersionUID = -6301963226688351725L; private static final long serialVersionUID = -6301963226688351725L;
public enum IntersectionType { public enum IntersectionType {
NONE, LINE, POLYGON NONE, LINE, POLYGON, TRIANGLES
} }
private final IntersectionType type; private final IntersectionType type;
...@@ -48,10 +49,30 @@ public class PolygonIntersection implements Serializable { ...@@ -48,10 +49,30 @@ public class PolygonIntersection implements Serializable {
private Polygon p1; private Polygon p1;
private Polygon p2; private Polygon p2;
private Triangle3d t1;
private Triangle3d t2;
public static PolygonIntersection none() { public static PolygonIntersection none() {
return new PolygonIntersection(IntersectionType.NONE); return new PolygonIntersection(IntersectionType.NONE);
} }
public static PolygonIntersection triangles(Triangle3d t1, Triangle3d t2) {
PolygonIntersection poly = new PolygonIntersection(IntersectionType.TRIANGLES);
poly.p1 = t1.getPartOf().getOriginal();
poly.p2 = t2.getPartOf().getOriginal();
poly.t1 = t1;
poly.t2 = t2;
return poly;
}
public static PolygonIntersection any(Polygon p1, Polygon p2) {
PolygonIntersection poly = new PolygonIntersection(IntersectionType.POLYGON);
poly.p1 = p1;
poly.p2 = p2;
return poly;
}
public static PolygonIntersection lines(List<Segment3d> lines, Polygon p1, Polygon p2) { public static PolygonIntersection lines(List<Segment3d> lines, Polygon p1, Polygon p2) {
PolygonIntersection poly = new PolygonIntersection(IntersectionType.LINE); PolygonIntersection poly = new PolygonIntersection(IntersectionType.LINE);
poly.lines = lines; poly.lines = lines;
...@@ -76,6 +97,14 @@ public class PolygonIntersection implements Serializable { ...@@ -76,6 +97,14 @@ public class PolygonIntersection implements Serializable {
return p2; return p2;
} }
public Triangle3d getT1() {
return t1;
}
public Triangle3d getT2() {
return t2;
}
private PolygonIntersection(IntersectionType type) { private PolygonIntersection(IntersectionType type) {
this.type = type; this.type = type;
} }
......
...@@ -31,7 +31,6 @@ import java.util.concurrent.atomic.AtomicInteger; ...@@ -31,7 +31,6 @@ import java.util.concurrent.atomic.AtomicInteger;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.citygml4j.core.model.CityGMLVersion;
import org.citygml4j.core.model.core.AbstractCityObjectProperty; import org.citygml4j.core.model.core.AbstractCityObjectProperty;
import org.citygml4j.core.model.core.AbstractFeatureProperty; import org.citygml4j.core.model.core.AbstractFeatureProperty;
import org.citygml4j.core.model.core.CityModel; import org.citygml4j.core.model.core.CityModel;
......
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<CityGmlZipEntry> 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<CityGmlZipEntry> 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<CityGmlZipEntry> 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<CityGmlZipEntry> getEntries() {
return entries;
}
}
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.
* <p/>
* 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.
* <p/>
* 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.
* <p/>
* 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}.
* <p/>
* 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;
}
}
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.
* <p/>
* 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.
* <p/>
* 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;
}
}
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);
}
}
package de.hft.stuttgart.citydoctor2.zip;
/**
* Error types for {@link CityGmlZipEntry} objects.
*/
public enum ZipEntryErrorType {
INVALID_CITY_GML_FILE, EXCESSIVE_FILESIZE, IO_ERROR
}
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);
}
...@@ -18,6 +18,9 @@ CheckDialog.parameterValue=Value ...@@ -18,6 +18,9 @@ CheckDialog.parameterValue=Value
CheckDialog.parameterUnit=Unit CheckDialog.parameterUnit=Unit
CityDoctorController.noDatamodel=Datamodel is null, no checks could be done CityDoctorController.noDatamodel=Datamodel is null, no checks could be done
CityDoctorController.noSourceFile=Source file 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!
ExceptionDialog.stacktrace=The exception stacktrace was: ExceptionDialog.stacktrace=The exception stacktrace was:
FilterPane.buildings=Buildings FilterPane.buildings=Buildings
FilterPane.bridges=Bridges FilterPane.bridges=Bridges
...@@ -32,6 +35,7 @@ MainToolBar.executeChecks=Execute Checks ...@@ -32,6 +35,7 @@ MainToolBar.executeChecks=Execute Checks
MainToolBar.showWorld=Show entire city model MainToolBar.showWorld=Show entire city model
MainToolBar.resetCamera=Reset view MainToolBar.resetCamera=Reset view
MainToolBar.hideRoof=Show/Hide roof BoundarySurfaces MainToolBar.hideRoof=Show/Hide roof BoundarySurfaces
MainToolBar.zip=Open zip-entry selection window
MainWindow.missingConfig=Could not find configuration file. MainWindow.missingConfig=Could not find configuration file.
MainWindow.loadGivenFile=Loading given file, please wait MainWindow.loadGivenFile=Loading given file, please wait
MainWindow.finishedLoading=Finished loading MainWindow.finishedLoading=Finished loading
...@@ -43,7 +47,12 @@ MainWindow.finishedPdf=Finished pdf report ...@@ -43,7 +47,12 @@ MainWindow.finishedPdf=Finished pdf report
MainWindow.loadFailed=Failed to load given gml file: {} MainWindow.loadFailed=Failed to load given gml file: {}
MainWindow.all=All MainWindow.all=All
MainWindow.withErrors=With errors MainWindow.withErrors=With errors
MainWindow.export=Export MainWindow.export=Export feature
MainWindow.copyId=Copy GML-ID
MainWindow.delete=Delete feature
MainWindow.infoTopLevelExport=Only top-level object can be exported!
MainWindow.infoTopLevelCopyID=GML-ID can only be copied from top-level object!
mainWindow.warnCopyIdFailed=Could not copy GML-ID!
OpenFileDialog.select=Select CityGML file OpenFileDialog.select=Select CityGML file
MainWindow.languageChange=For the change in language to apply, restart CityDoctor2. MainWindow.languageChange=For the change in language to apply, restart CityDoctor2.
MainWindow.buildingsTab=Buildings MainWindow.buildingsTab=Buildings
...@@ -67,6 +76,7 @@ MainWindow.verticesTab=Vertices ...@@ -67,6 +76,7 @@ MainWindow.verticesTab=Vertices
MainWindow.attributeTab=Attributes MainWindow.attributeTab=Attributes
MainWindow.logTab=Log MainWindow.logTab=Log
MainWindow.globalErrorsTab=Global Errors MainWindow.globalErrorsTab=Global Errors
MainWindow.focusCityObject=Focus object
OpenFileDialog.fileLabel=File: OpenFileDialog.fileLabel=File:
OpenFileDialog.selectBtn=Select OpenFileDialog.selectBtn=Select
OpenFileDialog.loadBtn=Load OpenFileDialog.loadBtn=Load
...@@ -96,6 +106,37 @@ CheckDialog.schematronFileLabel=Schematron File: ...@@ -96,6 +106,37 @@ CheckDialog.schematronFileLabel=Schematron File:
CheckDialog.selectBtn=Select CheckDialog.selectBtn=Select
CheckDialog.checkBtn=Check CheckDialog.checkBtn=Check
CheckDialog.cancelBtn=Cancel 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 WriteReportDialog.writeBtn=Save
WriteReportDialog.cancelBtn=Cancel WriteReportDialog.cancelBtn=Cancel
WriteReportDialog.errorStatisticsLabel=Error Statistics WriteReportDialog.errorStatisticsLabel=Error Statistics
...@@ -114,9 +155,19 @@ CityGmlParser.notValidGmlFile=This is not a valid GML-File\n ...@@ -114,9 +155,19 @@ CityGmlParser.notValidGmlFile=This is not a valid GML-File\n
CityGmlParser.errorReadingGmlFile=Error while reading city gml file\n{} CityGmlParser.errorReadingGmlFile=Error while reading city gml file\n{}
CityGmlParser.errorWritingGmlFile=Error while writing city gml file\n{} CityGmlParser.errorWritingGmlFile=Error while writing city gml file\n{}
CityGmlParser.noConversionNeeded=Coordinate system is in meters, no conversion done CityGmlParser.noConversionNeeded=Coordinate system is in meters, no conversion done
CityGmlParser.noEPSG=Could not read EPSG code, assuming metric system 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 OpenFileDialog.loadFailed=Failed to load CityGML File
MainWindow.memoryLabel=Memory: MainWindow.memoryLabel=Memory:
CheckDialog.checksReenabledAlert=Some checks have been reenabled so that other wanted checks can be executed\nSee the log for more information. CheckDialog.checksReenabledAlert=Some checks have been reenabled so that other wanted checks can be executed\nSee the log for more information.
MainWindow.availableLabel=Available: MainWindow.availableLabel=Available:
OpenFileDialog.lowMemoryLabel=Low Memory Consumption Mode 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
...@@ -16,6 +16,9 @@ CheckDialog.parameterValue=Wert ...@@ -16,6 +16,9 @@ CheckDialog.parameterValue=Wert
CheckDialog.parameterUnit=Einheit CheckDialog.parameterUnit=Einheit
CityDoctorController.noDatamodel=Datenmodell ist null, keine Pr\u00fcfungen konnten ausgef\u00fchrt werden 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.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
CityDoctorController.saveZipArchiveReports=Validierungsberichte erfolgreich exportiert!
ExceptionDialog.stacktrace=Der Stacktrace des Fehlers war: ExceptionDialog.stacktrace=Der Stacktrace des Fehlers war:
FilterPane.buildings=Geb\u00e4ude FilterPane.buildings=Geb\u00e4ude
FilterPane.bridges=Br\u00fccken FilterPane.bridges=Br\u00fccken
...@@ -30,6 +33,7 @@ MainToolBar.executeChecks=F\u00fchre Pr\u00fcfungen aus ...@@ -30,6 +33,7 @@ MainToolBar.executeChecks=F\u00fchre Pr\u00fcfungen aus
MainToolBar.showWorld=Gesamtes Stadtmodell anzeigen MainToolBar.showWorld=Gesamtes Stadtmodell anzeigen
MainToolBar.resetCamera=Ansicht zur\u00fccksetzen MainToolBar.resetCamera=Ansicht zur\u00fccksetzen
MainToolBar.hideRoof=Zeige/Verstecke Dach BoundarySurfaces MainToolBar.hideRoof=Zeige/Verstecke Dach BoundarySurfaces
MainToolBar.zip=Zip-eintrag Auswahlfenster \u00f6ffnen
MainWindow.missingConfig=Konnte Konfigurationsdatei nicht finden. MainWindow.missingConfig=Konnte Konfigurationsdatei nicht finden.
MainWindow.loadGivenFile=Lade vorhandene Datei, bitte warten MainWindow.loadGivenFile=Lade vorhandene Datei, bitte warten
MainWindow.finishedLoading=Fertig geladen MainWindow.finishedLoading=Fertig geladen
...@@ -41,7 +45,12 @@ MainWindow.finishedPdf=Pdf Report abgeschlossen ...@@ -41,7 +45,12 @@ MainWindow.finishedPdf=Pdf Report abgeschlossen
MainWindow.loadFailed=Konnte GML-Datei nicht laden: {} MainWindow.loadFailed=Konnte GML-Datei nicht laden: {}
MainWindow.all=Alle MainWindow.all=Alle
MainWindow.withErrors=Mit Fehlern MainWindow.withErrors=Mit Fehlern
MainWindow.export=Exportieren MainWindow.export=Feature Exportieren
MainWindow.copyId=GML-ID kopieren
MainWindow.delete=Feature L\u00f6schen
MainWindow.infoTopLevelExport=Export ist nur f\u00fcr Featureobjekt basis m\u00f6glich!
MainWindow.infoTopLevelCopyID=GML-ID kann nur von Featureobjekt basis kopiert werden!
mainWindow.warnCopyIdFailed=Kopieren der ID fehlgeschlagen!
OpenFileDialog.select=W\u00e4hle CityGML Datei aus OpenFileDialog.select=W\u00e4hle CityGML Datei aus
MainWindow.languageChange=Um die Spracheinstellung zu \u00fcbernehmen muss CityDoctor2 neugestartet werden. MainWindow.languageChange=Um die Spracheinstellung zu \u00fcbernehmen muss CityDoctor2 neugestartet werden.
MainWindow.buildingsTab=Geb\u00e4ude MainWindow.buildingsTab=Geb\u00e4ude
...@@ -65,6 +74,7 @@ MainWindow.verticesTab=Punkte ...@@ -65,6 +74,7 @@ MainWindow.verticesTab=Punkte
MainWindow.attributeTab=Attribute MainWindow.attributeTab=Attribute
MainWindow.logTab=Log MainWindow.logTab=Log
MainWindow.globalErrorsTab=Globale Fehler MainWindow.globalErrorsTab=Globale Fehler
MainWindow.focusCityObject=Objekt fokussieren
OpenFileDialog.fileLabel=Datei: OpenFileDialog.fileLabel=Datei:
OpenFileDialog.selectBtn=Ausw\u00e4hlen OpenFileDialog.selectBtn=Ausw\u00e4hlen
OpenFileDialog.loadBtn=Laden OpenFileDialog.loadBtn=Laden
...@@ -94,6 +104,37 @@ CheckDialog.schematronFileLabel=Schematron Datei ...@@ -94,6 +104,37 @@ CheckDialog.schematronFileLabel=Schematron Datei
CheckDialog.selectBtn=Ausw\u00e4hlen CheckDialog.selectBtn=Ausw\u00e4hlen
CheckDialog.checkBtn=Pr\u00fcfen CheckDialog.checkBtn=Pr\u00fcfen
CheckDialog.cancelBtn=Abbrechen 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 WriteReportDialog.writeBtn=Speichern
WriteReportDialog.cancelBtn=Abbrechen WriteReportDialog.cancelBtn=Abbrechen
WriteReportDialog.errorStatisticsLabel=Fehler Statistik WriteReportDialog.errorStatisticsLabel=Fehler Statistik
...@@ -104,7 +145,7 @@ WriteReportDialog.xAxisLabel=Fehler ...@@ -104,7 +145,7 @@ WriteReportDialog.xAxisLabel=Fehler
WriteReportDialog.yAxisLabel=Anzahl WriteReportDialog.yAxisLabel=Anzahl
Unit.Radian=Radiant Unit.Radian=Radiant
Unit.Degree=Grad Unit.Degree=Grad
FeatureMapper.polygonUnreferenced=Polygon {} ist referenziert wurde aber nicht gefunden FeatureMapper.polygonUnreferenced=Polygon {} ist referenziert, konnte aber nicht gefunden werden
GeometryMapper.emptyPolygon=Polygon ohne externen Ring gefunden, ignoriere GeometryMapper.emptyPolygon=Polygon ohne externen Ring gefunden, ignoriere
CityGmlParser.parsedObjects=Modell mit {} Objekten gelesen CityGmlParser.parsedObjects=Modell mit {} Objekten gelesen
CityGmlParser.chunkReadFailed=Konnte Datei nicht in St\u00fccken lesen, versuche komplett zu lesen CityGmlParser.chunkReadFailed=Konnte Datei nicht in St\u00fccken lesen, versuche komplett zu lesen
...@@ -112,9 +153,19 @@ CityGmlParser.notValidGmlFile=Dies ist keine korrekte CityGML Datei\n ...@@ -112,9 +153,19 @@ CityGmlParser.notValidGmlFile=Dies ist keine korrekte CityGML Datei\n
CityGmlParser.errorReadingGmlFile=Fehler beim lesen der CityGML Datei\n{} CityGmlParser.errorReadingGmlFile=Fehler beim lesen der CityGML Datei\n{}
CityGmlParser.errorWritingGmlFile=Fehler beim schreiben der CityGML Datei\n{} CityGmlParser.errorWritingGmlFile=Fehler beim schreiben der CityGML Datei\n{}
CityGmlParser.noConversionNeeded=Koordinatensystem in Metern, keine Konvertierung notwendig CityGmlParser.noConversionNeeded=Koordinatensystem in Metern, keine Konvertierung notwendig
CityGmlParser.noEPSG=Konnte EPSG Code nicht lesen, nehme metrisches System an 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 OpenFileDialog.loadFailed=Konnte CityGML Datei nicht laden
MainWindow.memoryLabel=Speicher: 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 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: MainWindow.availableLabel=Verf\u00fcgbar:
OpenFileDialog.lowMemoryLabel=Reduzierter Speicherverbrauchsmodus 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
...@@ -348,6 +348,11 @@ public class AbstractBuildingTest { ...@@ -348,6 +348,11 @@ public class AbstractBuildingTest {
return null; return null;
} }
@Override
public CityObject getTopLevelCityObject(){
return null;
}
}; };
return ab; return ab;
} }
......
...@@ -47,7 +47,7 @@ public class BridgeObjectTest { ...@@ -47,7 +47,7 @@ public class BridgeObjectTest {
@Test @Test
public void testAccept() { public void testAccept() {
BridgeObject bo = new BridgeObject(BridgeType.BRIDGE, mock(AbstractBridge.class)); BridgeObject bo = new BridgeObject(mock(AbstractBridge.class));
bo.addBoundarySurface(new BoundarySurface(null)); bo.addBoundarySurface(new BoundarySurface(null));
AtomicInteger boCounter = new AtomicInteger(0); AtomicInteger boCounter = new AtomicInteger(0);
AtomicInteger bsCounter = new AtomicInteger(0); AtomicInteger bsCounter = new AtomicInteger(0);
...@@ -75,7 +75,7 @@ public class BridgeObjectTest { ...@@ -75,7 +75,7 @@ public class BridgeObjectTest {
@Test @Test
public void testPrepareForChecking() { public void testPrepareForChecking() {
BridgeObject bo = new BridgeObject(BridgeType.BRIDGE, mock(AbstractBridge.class)); BridgeObject bo = new BridgeObject(mock(AbstractBridge.class));
BoundarySurface bsMock = mock(BoundarySurface.class); BoundarySurface bsMock = mock(BoundarySurface.class);
bo.addBoundarySurface(bsMock); bo.addBoundarySurface(bsMock);
bo.prepareForChecking(); bo.prepareForChecking();
...@@ -84,7 +84,7 @@ public class BridgeObjectTest { ...@@ -84,7 +84,7 @@ public class BridgeObjectTest {
@Test @Test
public void testClearMetaInformation() { public void testClearMetaInformation() {
BridgeObject bo = new BridgeObject(BridgeType.BRIDGE, mock(AbstractBridge.class)); BridgeObject bo = new BridgeObject(mock(AbstractBridge.class));
BoundarySurface bsMock = mock(BoundarySurface.class); BoundarySurface bsMock = mock(BoundarySurface.class);
bo.addBoundarySurface(bsMock); bo.addBoundarySurface(bsMock);
bo.clearMetaInformation(); bo.clearMetaInformation();
...@@ -93,7 +93,7 @@ public class BridgeObjectTest { ...@@ -93,7 +93,7 @@ public class BridgeObjectTest {
@Test @Test
public void testContainsError() { public void testContainsError() {
BridgeObject bo = new BridgeObject(BridgeType.BRIDGE, mock(AbstractBridge.class)); BridgeObject bo = new BridgeObject(mock(AbstractBridge.class));
assertFalse(bo.containsError(CheckId.C_GE_P_HOLE_OUTSIDE)); assertFalse(bo.containsError(CheckId.C_GE_P_HOLE_OUTSIDE));
bo.addCheckResult(new CheckResult(CheckId.C_GE_P_HOLE_OUTSIDE, ResultStatus.ERROR, mock(CheckError.class))); bo.addCheckResult(new CheckResult(CheckId.C_GE_P_HOLE_OUTSIDE, ResultStatus.ERROR, mock(CheckError.class)));
assertTrue(bo.containsError(CheckId.C_GE_P_HOLE_OUTSIDE)); assertTrue(bo.containsError(CheckId.C_GE_P_HOLE_OUTSIDE));
...@@ -101,7 +101,7 @@ public class BridgeObjectTest { ...@@ -101,7 +101,7 @@ public class BridgeObjectTest {
@Test @Test
public void testContainsError2() { public void testContainsError2() {
BridgeObject bo = new BridgeObject(BridgeType.BRIDGE, mock(AbstractBridge.class)); BridgeObject bo = new BridgeObject(mock(AbstractBridge.class));
BoundarySurface bsMock = mock(BoundarySurface.class); BoundarySurface bsMock = mock(BoundarySurface.class);
bo.addBoundarySurface(bsMock); bo.addBoundarySurface(bsMock);
assertFalse(bo.containsError(CheckId.C_GE_P_HOLE_OUTSIDE)); assertFalse(bo.containsError(CheckId.C_GE_P_HOLE_OUTSIDE));
...@@ -111,7 +111,7 @@ public class BridgeObjectTest { ...@@ -111,7 +111,7 @@ public class BridgeObjectTest {
@Test @Test
public void testClearAllContainedCheckResults() { public void testClearAllContainedCheckResults() {
BridgeObject bo = new BridgeObject(BridgeType.BRIDGE, mock(AbstractBridge.class)); BridgeObject bo = new BridgeObject(mock(AbstractBridge.class));
BoundarySurface bsMock = mock(BoundarySurface.class); BoundarySurface bsMock = mock(BoundarySurface.class);
bo.addBoundarySurface(bsMock); bo.addBoundarySurface(bsMock);
bo.clearAllContainedCheckResults(); bo.clearAllContainedCheckResults();
...@@ -120,7 +120,7 @@ public class BridgeObjectTest { ...@@ -120,7 +120,7 @@ public class BridgeObjectTest {
@Test @Test
public void testContainsAnyError() { public void testContainsAnyError() {
BridgeObject bo = new BridgeObject(BridgeType.BRIDGE, mock(AbstractBridge.class)); BridgeObject bo = new BridgeObject(mock(AbstractBridge.class));
BoundarySurface bsMock = mock(BoundarySurface.class); BoundarySurface bsMock = mock(BoundarySurface.class);
bo.addBoundarySurface(bsMock); bo.addBoundarySurface(bsMock);
bo.containsAnyError(); bo.containsAnyError();
...@@ -129,14 +129,14 @@ public class BridgeObjectTest { ...@@ -129,14 +129,14 @@ public class BridgeObjectTest {
when(bsMock.containsAnyError()).thenReturn(true); when(bsMock.containsAnyError()).thenReturn(true);
assertTrue(bo.containsAnyError()); assertTrue(bo.containsAnyError());
BridgeObject bo2 = new BridgeObject(BridgeType.BRIDGE, mock(AbstractBridge.class)); BridgeObject bo2 = new BridgeObject(mock(AbstractBridge.class));
bo2.addCheckResult(new CheckResult(CheckId.C_GE_P_HOLE_OUTSIDE, ResultStatus.ERROR, mock(CheckError.class))); bo2.addCheckResult(new CheckResult(CheckId.C_GE_P_HOLE_OUTSIDE, ResultStatus.ERROR, mock(CheckError.class)));
assertTrue(bo2.containsAnyError()); assertTrue(bo2.containsAnyError());
} }
@Test @Test
public void testCollectContainedErrors() { public void testCollectContainedErrors() {
BridgeObject bo = new BridgeObject(BridgeType.BRIDGE, mock(AbstractBridge.class)); BridgeObject bo = new BridgeObject(mock(AbstractBridge.class));
BoundarySurface bsMock = mock(BoundarySurface.class); BoundarySurface bsMock = mock(BoundarySurface.class);
bo.addBoundarySurface(bsMock); bo.addBoundarySurface(bsMock);
ArrayList<CheckError> errors = new ArrayList<>(); ArrayList<CheckError> errors = new ArrayList<>();
...@@ -146,7 +146,7 @@ public class BridgeObjectTest { ...@@ -146,7 +146,7 @@ public class BridgeObjectTest {
@Test @Test
public void testReCreateGeometries() { public void testReCreateGeometries() {
BridgeObject bo = new BridgeObject(BridgeType.BRIDGE, mock(AbstractBridge.class)); BridgeObject bo = new BridgeObject(mock(AbstractBridge.class));
BoundarySurface bsMock = mock(BoundarySurface.class); BoundarySurface bsMock = mock(BoundarySurface.class);
bo.addBoundarySurface(bsMock); bo.addBoundarySurface(bsMock);
GeometryFactory factoryMock = mock(GeometryFactory.class); GeometryFactory factoryMock = mock(GeometryFactory.class);
...@@ -157,7 +157,7 @@ public class BridgeObjectTest { ...@@ -157,7 +157,7 @@ public class BridgeObjectTest {
@Test @Test
public void testReCreateGeometriesMultiSurfaceLod1() { public void testReCreateGeometriesMultiSurfaceLod1() {
BridgeObject bo = new BridgeObject(BridgeType.BRIDGE, mock(AbstractBridge.class)); BridgeObject bo = new BridgeObject(mock(AbstractBridge.class));
Geometry geom = GeometryTestUtils.createDummyGeometry(GeometryType.MULTI_SURFACE, Lod.LOD1); Geometry geom = GeometryTestUtils.createDummyGeometry(GeometryType.MULTI_SURFACE, Lod.LOD1);
AbstractBridge ab = new Bridge(); AbstractBridge ab = new Bridge();
bo.setGmlObject(ab); bo.setGmlObject(ab);
...@@ -172,7 +172,7 @@ public class BridgeObjectTest { ...@@ -172,7 +172,7 @@ public class BridgeObjectTest {
@Test @Test
public void testReCreateGeometriesMultiSurfaceLod2() { public void testReCreateGeometriesMultiSurfaceLod2() {
BridgeObject bo = new BridgeObject(BridgeType.BRIDGE, mock(AbstractBridge.class)); BridgeObject bo = new BridgeObject(mock(AbstractBridge.class));
Geometry geom = GeometryTestUtils.createDummyGeometry(GeometryType.MULTI_SURFACE, Lod.LOD2); Geometry geom = GeometryTestUtils.createDummyGeometry(GeometryType.MULTI_SURFACE, Lod.LOD2);
AbstractBridge ab = new Bridge(); AbstractBridge ab = new Bridge();
bo.setGmlObject(ab); bo.setGmlObject(ab);
...@@ -186,7 +186,7 @@ public class BridgeObjectTest { ...@@ -186,7 +186,7 @@ public class BridgeObjectTest {
@Test @Test
public void testReCreateGeometriesMultiSurfaceLod3() { public void testReCreateGeometriesMultiSurfaceLod3() {
BridgeObject bo = new BridgeObject(BridgeType.BRIDGE, mock(AbstractBridge.class)); BridgeObject bo = new BridgeObject(mock(AbstractBridge.class));
Geometry geom = GeometryTestUtils.createDummyGeometry(GeometryType.MULTI_SURFACE, Lod.LOD3); Geometry geom = GeometryTestUtils.createDummyGeometry(GeometryType.MULTI_SURFACE, Lod.LOD3);
AbstractBridge ab = new Bridge(); AbstractBridge ab = new Bridge();
bo.setGmlObject(ab); bo.setGmlObject(ab);
...@@ -200,7 +200,7 @@ public class BridgeObjectTest { ...@@ -200,7 +200,7 @@ public class BridgeObjectTest {
@Test @Test
public void testReCreateGeometriesMultiSurfaceLod4() { public void testReCreateGeometriesMultiSurfaceLod4() {
BridgeObject bo = new BridgeObject(BridgeType.BRIDGE, mock(AbstractBridge.class)); BridgeObject bo = new BridgeObject(mock(AbstractBridge.class));
Geometry geom = GeometryTestUtils.createDummyGeometry(GeometryType.MULTI_SURFACE, Lod.LOD4); Geometry geom = GeometryTestUtils.createDummyGeometry(GeometryType.MULTI_SURFACE, Lod.LOD4);
AbstractBridge ab = new Bridge(); AbstractBridge ab = new Bridge();
bo.setGmlObject(ab); bo.setGmlObject(ab);
...@@ -214,7 +214,7 @@ public class BridgeObjectTest { ...@@ -214,7 +214,7 @@ public class BridgeObjectTest {
@Test @Test
public void testReCreateGeometriesSolidLod1() { public void testReCreateGeometriesSolidLod1() {
BridgeObject bo = new BridgeObject(BridgeType.BRIDGE, mock(AbstractBridge.class)); BridgeObject bo = new BridgeObject(mock(AbstractBridge.class));
Geometry geom = GeometryTestUtils.createDummyGeometry(GeometryType.SOLID, Lod.LOD1); Geometry geom = GeometryTestUtils.createDummyGeometry(GeometryType.SOLID, Lod.LOD1);
AbstractBridge ab = new Bridge(); AbstractBridge ab = new Bridge();
bo.setGmlObject(ab); bo.setGmlObject(ab);
...@@ -228,7 +228,7 @@ public class BridgeObjectTest { ...@@ -228,7 +228,7 @@ public class BridgeObjectTest {
@Test @Test
public void testReCreateGeometriesSolidLod2() { public void testReCreateGeometriesSolidLod2() {
BridgeObject bo = new BridgeObject(BridgeType.BRIDGE, mock(AbstractBridge.class)); BridgeObject bo = new BridgeObject(mock(AbstractBridge.class));
Geometry geom = GeometryTestUtils.createDummyGeometry(GeometryType.SOLID, Lod.LOD2); Geometry geom = GeometryTestUtils.createDummyGeometry(GeometryType.SOLID, Lod.LOD2);
AbstractBridge ab = new Bridge(); AbstractBridge ab = new Bridge();
bo.setGmlObject(ab); bo.setGmlObject(ab);
...@@ -242,7 +242,7 @@ public class BridgeObjectTest { ...@@ -242,7 +242,7 @@ public class BridgeObjectTest {
@Test @Test
public void testReCreateGeometriesSolidLod3() { public void testReCreateGeometriesSolidLod3() {
BridgeObject bo = new BridgeObject(BridgeType.BRIDGE, mock(AbstractBridge.class)); BridgeObject bo = new BridgeObject(mock(AbstractBridge.class));
Geometry geom = GeometryTestUtils.createDummyGeometry(GeometryType.SOLID, Lod.LOD3); Geometry geom = GeometryTestUtils.createDummyGeometry(GeometryType.SOLID, Lod.LOD3);
AbstractBridge ab = new Bridge(); AbstractBridge ab = new Bridge();
bo.setGmlObject(ab); bo.setGmlObject(ab);
...@@ -256,7 +256,7 @@ public class BridgeObjectTest { ...@@ -256,7 +256,7 @@ public class BridgeObjectTest {
@Test @Test
public void testReCreateGeometriesSolidLod4() { public void testReCreateGeometriesSolidLod4() {
BridgeObject bo = new BridgeObject(BridgeType.BRIDGE, mock(AbstractBridge.class)); BridgeObject bo = new BridgeObject(mock(AbstractBridge.class));
Geometry geom = GeometryTestUtils.createDummyGeometry(GeometryType.SOLID, Lod.LOD4); Geometry geom = GeometryTestUtils.createDummyGeometry(GeometryType.SOLID, Lod.LOD4);
AbstractBridge ab = new Bridge(); AbstractBridge ab = new Bridge();
bo.setGmlObject(ab); bo.setGmlObject(ab);
...@@ -273,7 +273,7 @@ public class BridgeObjectTest { ...@@ -273,7 +273,7 @@ public class BridgeObjectTest {
AbstractBridge abMock = mock(AbstractBridge.class); AbstractBridge abMock = mock(AbstractBridge.class);
DeprecatedPropertiesOfAbstractBridge propsMock = mock(DeprecatedPropertiesOfAbstractBridge.class); DeprecatedPropertiesOfAbstractBridge propsMock = mock(DeprecatedPropertiesOfAbstractBridge.class);
when(abMock.getDeprecatedProperties()).thenReturn(propsMock); when(abMock.getDeprecatedProperties()).thenReturn(propsMock);
BridgeObject bo = new BridgeObject(BridgeType.BRIDGE, abMock); BridgeObject bo = new BridgeObject(abMock);
BoundarySurface bsMock = mock(BoundarySurface.class); BoundarySurface bsMock = mock(BoundarySurface.class);
bo.addBoundarySurface(bsMock); bo.addBoundarySurface(bsMock);
...@@ -293,14 +293,14 @@ public class BridgeObjectTest { ...@@ -293,14 +293,14 @@ public class BridgeObjectTest {
@Test @Test
public void testGetFeatureType() { public void testGetFeatureType() {
AbstractBridge abMock = mock(AbstractBridge.class); AbstractBridge abMock = mock(AbstractBridge.class);
BridgeObject bo = new BridgeObject(BridgeType.BRIDGE, abMock); BridgeObject bo = new BridgeObject(abMock);
assertEquals(FeatureType.BRIDGE, bo.getFeatureType()); assertEquals(FeatureType.BRIDGE, bo.getFeatureType());
} }
@Test @Test
public void testGetType() { public void testGetType() {
AbstractBridge abMock = mock(AbstractBridge.class); AbstractBridge abMock = mock(AbstractBridge.class);
BridgeObject bo = new BridgeObject(BridgeType.BRIDGE, abMock); BridgeObject bo = new BridgeObject( abMock);
assertEquals(BridgeType.BRIDGE, bo.getType()); assertEquals(BridgeType.BRIDGE, bo.getType());
bo.setType(BridgeType.BRIDGE_PART); bo.setType(BridgeType.BRIDGE_PART);
assertEquals(BridgeType.BRIDGE_PART, bo.getType()); assertEquals(BridgeType.BRIDGE_PART, bo.getType());
...@@ -309,7 +309,7 @@ public class BridgeObjectTest { ...@@ -309,7 +309,7 @@ public class BridgeObjectTest {
@Test @Test
public void testGetGmlObject() { public void testGetGmlObject() {
AbstractBridge abMock = mock(AbstractBridge.class); AbstractBridge abMock = mock(AbstractBridge.class);
BridgeObject bo = new BridgeObject(BridgeType.BRIDGE, abMock); BridgeObject bo = new BridgeObject(abMock);
assertEquals(abMock, bo.getGmlObject()); assertEquals(abMock, bo.getGmlObject());
AbstractBridge abMock2 = mock(AbstractBridge.class); AbstractBridge abMock2 = mock(AbstractBridge.class);
bo.setGmlObject(abMock2); bo.setGmlObject(abMock2);
......
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());
}
}
File added
<?xml version="1.0" encoding="utf-8"?>
<core:CityModel xmlns:core="http://www.opengis.net/citygml/2.0" xmlns:gen="http://www.opengis.net/citygml/generics/2.0" xmlns:bldg="http://www.opengis.net/citygml/building/2.0" xmlns:app="http://www.opengis.net/citygml/appearance/2.0" xmlns:dem="http://www.opengis.net/citygml/relief/2.0" xmlns:gml="http://www.opengis.net/gml" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.opengis.net/citygml/building/2.0 http://schemas.opengis.net/citygml/building/2.0/building.xsd http://www.opengis.net/citygml/appearance/2.0 http://schemas.opengis.net/citygml/appearance/2.0/appearance.xsd http://www.opengis.net/citygml/relief/2.0 http://schemas.opengis.net/citygml/relief/2.0/relief.xsd http://www.opengis.net/citygml/2.0 http://schemas.opengis.net/citygml/2.0/cityGMLBase.xsd http://www.opengis.net/citygml/generics/2.0 http://schemas.opengis.net/citygml/generics/2.0/generics.xsd">
<gml:boundedBy>
<gml:Envelope srsDimension="3" srsName="urn:ogc:def:crs:EPSG::25832">
<gml:lowerCorner>357978.09 5654873.32 0.00</gml:lowerCorner>
<gml:upperCorner>359213.91 5656013.49 0.00</gml:upperCorner>
</gml:Envelope>
</gml:boundedBy>
</core:CityModel>
\ No newline at end of file
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment