Commit 5d40c7b6 authored by Matthias Betz's avatar Matthias Betz
Browse files

CityDoctor2 validation open source release

parents
/*-
* Copyright 2020 Beuth Hochschule für Technik Berlin, Hochschule für Technik Stuttgart
*
* This file is part of CityDoctor2.
*
* CityDoctor2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* CityDoctor2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with CityDoctor2. If not, see <https://www.gnu.org/licenses/>.
*/
package de.hft.stuttgart.citydoctor2.parser;
import java.util.EventListener;
/**
* Implementations of this listener will be informed about the (file) loading progress of ObservedInputStream
* instances. You have to register your implementation of this interface at the ObservedInputStream instance.
*
* @author Marcel Bruse
*/
public interface InputStreamListener extends EventListener {
/**
* This method will be called by the observed input stream when a new chunk of bytes has been read.
*
* @param progress Should be a value between 0 and 1. 0 means no progress and 1 means loading finished.
*/
public void updateProgress(float progress);
}
/*-
* Copyright 2020 Beuth Hochschule für Technik Berlin, Hochschule für Technik Stuttgart
*
* This file is part of CityDoctor2.
*
* CityDoctor2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* CityDoctor2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with CityDoctor2. If not, see <https://www.gnu.org/licenses/>.
*/
package de.hft.stuttgart.citydoctor2.parser;
/**
* Used when an invalid CityGML file is found.
*
* @author Matthias Betz
*
*/
public class InvalidGmlFileException extends Exception {
private static final long serialVersionUID = 5490585939707730933L;
public InvalidGmlFileException() {
super();
}
public InvalidGmlFileException(String message, Throwable cause, boolean enableSuppression,
boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
public InvalidGmlFileException(String message, Throwable cause) {
super(message, cause);
}
public InvalidGmlFileException(String message) {
super(message);
}
public InvalidGmlFileException(Throwable cause) {
super(cause);
}
}
/*-
* Copyright 2020 Beuth Hochschule für Technik Berlin, Hochschule für Technik Stuttgart
*
* This file is part of CityDoctor2.
*
* CityDoctor2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* CityDoctor2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with CityDoctor2. If not, see <https://www.gnu.org/licenses/>.
*/
package de.hft.stuttgart.citydoctor2.parser;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
/**
* This ObservedInputStream will update its registered listeners about the reading process of the underlying file.
* Every time when the underlying input stream is read the registered listeners will be informed and updated with the
* new progress.
*
* @author Marcel Bruse
*/
public class ObservedInputStream extends FilterInputStream {
/** List of registered progress listeners. */
private ArrayList<InputStreamListener> listeners = new ArrayList<>();
/** The number of bytes of the file to be read. */
private long fileLength;
/** The number of bytes read so far. */
private long location;
/**
* Instantiates the ObservedInputStream with a given file handle.
*
* @param file The file that should be loaded.
* @throws FileNotFoundException If there is on file, you will get some of this.
*/
public ObservedInputStream(File file) throws FileNotFoundException {
super(new BufferedInputStream(new FileInputStream(file)));
fileLength = file.length();
}
public ObservedInputStream(String fileName) throws FileNotFoundException {
this(new File(fileName));
}
public ObservedInputStream(InputStream in, long fileLength) {
super(new BufferedInputStream(in));
this.fileLength = fileLength;
}
/**
* Calls all the registered listeners if the file loading process makes any progress.
* It calculates and passes the progress in percent.
*/
private void updateProgress() {
for (InputStreamListener l : listeners) {
l.updateProgress((float) location / fileLength);
}
}
/**
* Calls super and counts the number of read bytes.
*
* @see FilterInputStream
*/
@Override
public int read() throws IOException {
final int data = super.read();
if (data != -1) {
location++;
updateProgress();
}
return data;
}
/**
* Calls super and counts the number of read bytes.
*
* @see FilterInputStream
*/
@Override
public int read(byte[] b, int off, int len) throws IOException {
final int byteCount = super.read(b, off, len);
if (byteCount != -1) {
location += byteCount;
updateProgress();
}
return byteCount;
}
/**
* Registers listeners. Every registered listener will get informed if the file loading process makes any
* progress.
*
* @param ps The progress listener to be registered.
*/
public void addListener(InputStreamListener ps) {
listeners.add(ps);
}
}
/*-
* Copyright 2020 Beuth Hochschule für Technik Berlin, Hochschule für Technik Stuttgart
*
* This file is part of CityDoctor2.
*
* CityDoctor2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* CityDoctor2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with CityDoctor2. If not, see <https://www.gnu.org/licenses/>.
*/
package de.hft.stuttgart.citydoctor2.parser;
import java.io.Serializable;
import org.osgeo.proj4j.BasicCoordinateTransform;
import org.osgeo.proj4j.CRSFactory;
import org.osgeo.proj4j.CoordinateReferenceSystem;
/**
* Container class to store the configuration needed to parse a file. Also
* contains information on transformation of vertices.
*
* @author Matthias Betz
*
*/
public class ParserConfiguration implements Serializable {
private static final long serialVersionUID = 6209047092991074661L;
private static final CRSFactory CRS_FACTORY = new CRSFactory();
private int roundingPlaces = 8;
private boolean validate = false;
private transient BasicCoordinateTransform targetTransform = null;
private transient BasicCoordinateTransform originalTransform = null;
private String targetTransformString;
private String originalTransformString;
private boolean hasTransformation = false;
private transient double fromMetres = 1.0;
public ParserConfiguration(int numberOfRoundingPlaces, boolean validate) {
if (numberOfRoundingPlaces < 0) {
throw new IllegalArgumentException("Number of rounding places must be a positive value");
}
roundingPlaces = numberOfRoundingPlaces;
this.validate = validate;
}
public boolean getValidate() {
return validate;
}
public int getNumberOfRoundingPlaces() {
return roundingPlaces;
}
public void setCoordinateSystem(CoordinateReferenceSystem crs, CoordinateReferenceSystem tgtCrs) {
if (crs != null && tgtCrs != null) {
hasTransformation = true;
targetTransformString = tgtCrs.getParameterString();
originalTransformString = crs.getParameterString();
targetTransform = new BasicCoordinateTransform(crs, tgtCrs);
originalTransform = new BasicCoordinateTransform(tgtCrs, crs);
}
}
public BasicCoordinateTransform getTargetTransform() {
if (hasTransformation && targetTransform == null) {
createCoordinateTransforms();
}
return targetTransform;
}
private void createCoordinateTransforms() {
CoordinateReferenceSystem tgtCrs = null;
CoordinateReferenceSystem crs = null;
synchronized (CRS_FACTORY) {
tgtCrs = CRS_FACTORY.createFromParameters("Target", targetTransformString);
crs = CRS_FACTORY.createFromParameters("Original", originalTransformString);
}
targetTransform = new BasicCoordinateTransform(crs, tgtCrs);
originalTransform = new BasicCoordinateTransform(tgtCrs, crs);
}
public BasicCoordinateTransform getOriginalTransform() {
if (hasTransformation && originalTransform == null) {
createCoordinateTransforms();
}
return originalTransform;
}
public void setFromMetres(double d) {
fromMetres = d;
}
public double getFromMetres() {
return fromMetres;
}
}
/*-
* Copyright 2020 Beuth Hochschule für Technik Berlin, Hochschule für Technik Stuttgart
*
* This file is part of CityDoctor2.
*
* CityDoctor2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* CityDoctor2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with CityDoctor2. If not, see <https://www.gnu.org/licenses/>.
*/
package de.hft.stuttgart.citydoctor2.parser;
/**
* ProgressListeners can be registered at CityGMLParsers in order to get updates about file loading and
* file parsing processes. Every update tells the ProgressListener the processing progress in percent, normalized
* to values between 0 and 1.
*
* @author Marcel Bruse
*/
public interface ProgressListener {
/**
* This is a callback that will be called if a file loading process progresses. The file loading process will
* be performed by a CityGMLParser.
*
* @param progress The progress of the current file loading process. The argument will be a value between 0 and 1.
* 0 means that no byte has been read by the CityGMLParser so far and 1 means, that the reading and parsing process
* is finished.
*/
public void updateProgress(float progress);
}
\ No newline at end of file
/*-
* Copyright 2020 Beuth Hochschule für Technik Berlin, Hochschule für Technik Stuttgart
*
* This file is part of CityDoctor2.
*
* CityDoctor2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* CityDoctor2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with CityDoctor2. If not, see <https://www.gnu.org/licenses/>.
*/
package de.hft.stuttgart.citydoctor2.parser;
import java.lang.reflect.Field;
import org.osgeo.proj4j.proj.Projection;
import org.osgeo.proj4j.units.Unit;
/**
* To extract the unit of the coordinate system. Workaround as the library
* proj4j has no getter to access the unit value
*
* @author Matthias Betz
*
*/
public class ProjectionUnitExtractor {
private Unit unit;
public ProjectionUnitExtractor(Projection proj) {
try {
Field f = Projection.class.getDeclaredField("unit");
f.setAccessible(true);
unit = (Unit) f.get(proj);
} catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
throw new IllegalArgumentException(e);
}
}
public Unit getUnit() {
return unit;
}
}
/*-
* Copyright 2020 Beuth Hochschule für Technik Berlin, Hochschule für Technik Stuttgart
*
* This file is part of CityDoctor2.
*
* CityDoctor2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* CityDoctor2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with CityDoctor2. If not, see <https://www.gnu.org/licenses/>.
*/
package de.hft.stuttgart.citydoctor2.tesselation;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import com.jogamp.opengl.GL;
import com.jogamp.opengl.glu.GLU;
import com.jogamp.opengl.glu.GLUtessellator;
import com.jogamp.opengl.glu.GLUtessellatorCallbackAdapter;
import de.hft.stuttgart.citydoctor2.datastructure.LinearRing;
import de.hft.stuttgart.citydoctor2.datastructure.Polygon;
import de.hft.stuttgart.citydoctor2.datastructure.Vertex;
import de.hft.stuttgart.citydoctor2.math.Vector3d;
/**
* Tesselator to create triangles out of polygons.
*
* @author Matthias Betz
*
*/
public class JoglTesselator {
private static final String DATA_WAS_NOT_A_LIST = "data was not a list";
private static final GLU glu = new GLU();
private static final GLUtessellator tess = GLU.gluNewTess();
private static final GLUtessellatorCallbackAdapter callback;
private static final ArrayList<Primitive> primitives = new ArrayList<>();
static {
callback = new GLUtessellatorCallbackAdapter() {
private Primitive lastPrimitive;
@Override
public void beginData(int type, Object data) {
if (!(data instanceof ArrayList<?>)) {
throw new IllegalStateException(DATA_WAS_NOT_A_LIST);
}
@SuppressWarnings("unchecked")
ArrayList<Vector3d> vertices = (ArrayList<Vector3d>) data;
lastPrimitive = new Primitive(type, vertices);
primitives.add(lastPrimitive);
}
@Override
public void vertexData(Object vertex, Object data) {
if (!(data instanceof ArrayList)) {
throw new IllegalStateException(DATA_WAS_NOT_A_LIST);
}
if (!(vertex instanceof Integer)) {
throw new IllegalStateException("vertex has to be an Integer");
}
lastPrimitive.addIndex((Integer) vertex);
}
@Override
public void combineData(double[] coords, Object[] vertexIndices, float[] weights, Object[] outgoingData,
Object data) {
if (!(data instanceof ArrayList<?>)) {
throw new IllegalStateException(DATA_WAS_NOT_A_LIST);
}
@SuppressWarnings("unchecked")
ArrayList<Vector3d> vertices = (ArrayList<Vector3d>) data;
// to ensure the coordinates are valid
double[] myCoords = Arrays.copyOf(coords, 3);
Vector3d newVertex = new Vector3d(myCoords);
outgoingData[0] = vertices.size();
vertices.add(newVertex);
}
@Override
public void errorData(int errnum, Object data) {
throw new TesselationException("GLU Error " + glu.gluErrorString(errnum));
}
};
GLU.gluTessCallback(tess, GLU.GLU_TESS_BEGIN_DATA, callback);
GLU.gluTessCallback(tess, GLU.GLU_TESS_VERTEX_DATA, callback);
GLU.gluTessCallback(tess, GLU.GLU_TESS_ERROR_DATA, callback);
GLU.gluTessCallback(tess, GLU.GLU_TESS_COMBINE_DATA, callback);
GLU.gluTessCallback(tess, GLU.GLU_TESS_END_DATA, callback);
}
public static TesselatedPolygon tesselatePolygon(Polygon p) {
ArrayList<Vector3d> vertices = new ArrayList<>();
Vector3d normal = p.calculateNormal();
synchronized (tess) {
GLU.gluTessProperty(tess, GLU.GLU_TESS_BOUNDARY_ONLY, GL.GL_FALSE);
GLU.gluTessBeginPolygon(tess, vertices);
GLU.gluTessNormal(tess, normal.getX(), normal.getY(), normal.getZ());
// exterior ring
LinearRing ext = p.getExteriorRing();
createContour(vertices, ext);
// interior rings
for (LinearRing lr : p.getInnerRings()) {
createContour(vertices, lr);
}
GLU.gluTessEndPolygon(tess);
ArrayList<Integer> indices = new ArrayList<>();
for (Primitive primitive : primitives) {
primitive.fillListWithIndices(indices);
}
primitives.clear();
return new TesselatedPolygon(vertices, indices, p);
}
}
private static void createContour(List<Vector3d> vertices, LinearRing lr) {
GLU.gluTessBeginContour(tess);
for (Vertex v : lr.getVertices()) {
vertices.add(v);
GLU.gluTessVertex(tess, v.getCoordinates(), 0, vertices.size() - 1);
}
GLU.gluTessEndContour(tess);
}
public static TesselatedRing tesselateRing(LinearRing r) {
ArrayList<Vector3d> vertices = new ArrayList<>();
Vector3d normal = r.calculateNormal();
synchronized (tess) {
GLU.gluTessBeginPolygon(tess, vertices);
GLU.gluTessNormal(tess, normal.getX(), normal.getY(), normal.getZ());
createContour(vertices, r);
GLU.gluTessEndPolygon(tess);
ArrayList<Integer> indices = new ArrayList<>();
for (Primitive primitive : primitives) {
primitive.fillListWithIndices(indices);
}
primitives.clear();
return new TesselatedRing(vertices, indices, r);
}
}
private JoglTesselator() {
// only static useage
}
}
/*-
* Copyright 2020 Beuth Hochschule für Technik Berlin, Hochschule für Technik Stuttgart
*
* This file is part of CityDoctor2.
*
* CityDoctor2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* CityDoctor2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with CityDoctor2. If not, see <https://www.gnu.org/licenses/>.
*/
package de.hft.stuttgart.citydoctor2.tesselation;
import java.util.ArrayList;
import java.util.List;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import com.jogamp.opengl.GL;
import de.hft.stuttgart.citydoctor2.math.Vector3d;
/**
* Result of the tesselation process. Primitives can be converted to triangles.
*
* @author Matthias Betz
*
*/
public class Primitive {
private static Logger logger = LogManager.getLogger(Primitive.class);
private static final double AREA_EPSILON = 0.00001;
private final int type;
private final List<Integer> pIndices = new ArrayList<>();
private final List<Vector3d> vertices;
public Primitive(int type, List<Vector3d> vertices) {
this.vertices = vertices;
this.type = type;
}
public void fillListWithIndices(List<Integer> indices) {
switch (type) {
case GL.GL_TRIANGLES:
for (int i = 0; i < pIndices.size(); i += 3) {
addToListIfAreaNonNull(pIndices.get(i), pIndices.get(i + 1), pIndices.get(i + 2), indices);
}
break;
case GL.GL_TRIANGLE_STRIP:
for (int i = 0; i < pIndices.size() - 2; i++) {
if (i % 2 == 0) {
addToListIfAreaNonNull(pIndices.get(i), pIndices.get(i + 1), pIndices.get(i + 2), indices);
} else {
addToListIfAreaNonNull(pIndices.get(i), pIndices.get(i + 2), pIndices.get(i + 1), indices);
}
}
break;
case GL.GL_TRIANGLE_FAN:
Integer first = pIndices.get(0);
for (int i = 0; i < pIndices.size() - 2; i++) {
addToListIfAreaNonNull(first, pIndices.get(i + 1), pIndices.get(i + 2), indices);
}
break;
default:
throw new IllegalStateException("unknown type found: " + type);
}
}
public void addIndex(Integer i) {
pIndices.add(i);
}
private void addToListIfAreaNonNull(Integer i1, Integer i2, Integer i3, List<Integer> indices) {
Vector3d v1 = vertices.get(i1);
Vector3d v2 = vertices.get(i2);
Vector3d v3 = vertices.get(i3);
double area = Math.abs(calculateAreaOfTriangle(v1, v2, v3));
if (area > AREA_EPSILON) {
indices.add(i1);
indices.add(i2);
indices.add(i3);
} else {
logger.trace("Tesselator created degenerated triangle, ignoring");
}
}
/**
* Calculates the area of a triangle given by the 3 points
*
* @param v1 the first point of the triangle
* @param v2 the second point of the triangle
* @param v3 the last point of the triangle
* @return the area of the triangle
*/
private static double calculateAreaOfTriangle(Vector3d v1, Vector3d v2, Vector3d v3) {
double a = v1.getDistance(v2);
double b = v2.getDistance(v3);
double c = v1.getDistance(v3);
double s = 0.5d * (a + b + c);
return Math.sqrt(s * (s - a) * (s - b) * (s - c));
}
}
/*-
* Copyright 2020 Beuth Hochschule für Technik Berlin, Hochschule für Technik Stuttgart
*
* This file is part of CityDoctor2.
*
* CityDoctor2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* CityDoctor2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with CityDoctor2. If not, see <https://www.gnu.org/licenses/>.
*/
package de.hft.stuttgart.citydoctor2.tesselation;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import de.hft.stuttgart.citydoctor2.datastructure.Polygon;
import de.hft.stuttgart.citydoctor2.math.Triangle3d;
import de.hft.stuttgart.citydoctor2.math.Vector3d;
/**
* Tesselated polygon containing a list of triangles as well as reference to the
* original polygon.
*
* @author Matthias Betz
*
*/
public class TesselatedPolygon implements Serializable {
private static final long serialVersionUID = 3117655580899570369L;
private List<Triangle3d> triangles;
private Polygon original;
public TesselatedPolygon(List<Triangle3d> triangles, Polygon original) {
this.triangles = triangles;
for (Triangle3d t : triangles) {
t.setPartOf(this);
}
this.original = original;
}
public TesselatedPolygon(List<Vector3d> vertices, List<Integer> indices, Polygon original) {
if (indices.size() % 3 != 0) {
throw new IllegalArgumentException("Number of indices is not a multiple of 3");
}
triangles = new ArrayList<>();
for (int i = 0; i < indices.size(); i = i + 3) {
Vector3d v1 = vertices.get(indices.get(i + 0));
Vector3d v2 = vertices.get(indices.get(i + 1));
Vector3d v3 = vertices.get(indices.get(i + 2));
triangles.add(new Triangle3d(v1, v2, v3, this));
}
this.original = original;
}
public List<Triangle3d> getTriangles() {
return triangles;
}
public Polygon getOriginal() {
return original;
}
}
/*-
* Copyright 2020 Beuth Hochschule für Technik Berlin, Hochschule für Technik Stuttgart
*
* This file is part of CityDoctor2.
*
* CityDoctor2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* CityDoctor2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with CityDoctor2. If not, see <https://www.gnu.org/licenses/>.
*/
package de.hft.stuttgart.citydoctor2.tesselation;
import java.util.ArrayList;
import java.util.List;
import de.hft.stuttgart.citydoctor2.datastructure.LinearRing;
import de.hft.stuttgart.citydoctor2.math.Triangle3d;
import de.hft.stuttgart.citydoctor2.math.Vector3d;
/**
* A tesselated ring containing a list of triangles and a reference to the
* original ring.
*
* @author Matthias Betz
*
*/
public class TesselatedRing {
private List<Triangle3d> triangles;
private LinearRing ring;
public TesselatedRing(List<Triangle3d> triangles, LinearRing ring) {
this.ring = ring;
this.triangles = triangles;
}
public TesselatedRing(List<Vector3d> vertices, List<Integer> indices, LinearRing r) {
if (indices.size() % 3 != 0) {
throw new IllegalArgumentException("Number of indices is not a multiple of 3");
}
triangles = new ArrayList<>();
for (int i = 0; i < indices.size(); i = i + 3) {
Vector3d v1 = vertices.get(indices.get(i + 0));
Vector3d v2 = vertices.get(indices.get(i + 1));
Vector3d v3 = vertices.get(indices.get(i + 2));
triangles.add(new Triangle3d(v1, v2, v3));
}
this.ring = r;
}
public List<Triangle3d> getTriangles() {
return triangles;
}
/**
* Getter method for ring
*
* @return the ring
*/
public LinearRing getRing() {
return ring;
}
}
/*-
* Copyright 2020 Beuth Hochschule für Technik Berlin, Hochschule für Technik Stuttgart
*
* This file is part of CityDoctor2.
*
* CityDoctor2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* CityDoctor2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with CityDoctor2. If not, see <https://www.gnu.org/licenses/>.
*/
package de.hft.stuttgart.citydoctor2.tesselation;
/**
* Thrown when something went wrong with the tesselation process.
*
* @author Matthias Betz
*
*/
public class TesselationException extends RuntimeException {
public TesselationException() {
super();
}
public TesselationException(String message, Throwable cause, boolean enableSuppression,
boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
public TesselationException(String message, Throwable cause) {
super(message, cause);
}
public TesselationException(Throwable cause) {
super(cause);
}
private static final long serialVersionUID = -2010522579830781136L;
public TesselationException(String message) {
super(message);
}
}
/*-
* Copyright 2020 Beuth Hochschule für Technik Berlin, Hochschule für Technik Stuttgart
*
* This file is part of CityDoctor2.
*
* CityDoctor2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* CityDoctor2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with CityDoctor2. If not, see <https://www.gnu.org/licenses/>.
*/
package de.hft.stuttgart.citydoctor2.utils;
import java.util.List;
import de.hft.stuttgart.citydoctor2.datastructure.BoundingBox;
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.Vertex;
import de.hft.stuttgart.citydoctor2.math.Vector3d;
/**
* Utility class for calculating axis aligned bounding boxes for different
* inputs.
*
* @author Matthias Betz
*
*/
public class BoundingBoxCalculator {
private BoundingBoxCalculator() {
// only static use
}
/**
* This will calculate two points where every other point in the geometry is
* between those two. If the geometry does not contain points or is null, an
* empty array is returned. This is considered an axis aligned bounding box.
* Only the exterior rings of the polygons is used as inner rings should be
* within the exterior or they are faulty.
*
* @param a list of polygons containing the vertices
* @return an BoundingBox containing the two end points of the bounding box.
*/
public static BoundingBox calculateBoundingBox(List<Polygon> polygons) {
double lowX = Double.MAX_VALUE;
double highX = Double.NEGATIVE_INFINITY;
double lowY = Double.MAX_VALUE;
double highY = Double.NEGATIVE_INFINITY;
double lowZ = Double.MAX_VALUE;
double highZ = Double.NEGATIVE_INFINITY;
for (Polygon p : polygons) {
// only need to check exterior rings
for (Vertex v : p.getExteriorRing().getVertices()) {
if (v.getX() < lowX) {
lowX = v.getX();
} else if (v.getX() > highX) {
highX = v.getX();
}
if (v.getY() < lowY) {
lowY = v.getY();
} else if (v.getY() > highY) {
highY = v.getY();
}
if (v.getZ() < lowZ) {
lowZ = v.getZ();
} else if (v.getZ() > highZ) {
highZ = v.getZ();
}
}
}
Vector3d[] result = new Vector3d[2];
result[0] = new Vector3d(lowX, lowY, lowZ);
result[1] = new Vector3d(highX, highY, highZ);
return BoundingBox.of(result);
}
/**
* This will calculate an axis aligned bounding box for the complete GML model.
*
* @param model the model
* @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.MIN_VALUE, Double.MIN_VALUE, Double.MIN_VALUE);
findMinMax(low, high, model.getBuildings());
findMinMax(low, high, model.getBridges());
findMinMax(low, high, model.getLand());
findMinMax(low, high, model.getTransportation());
findMinMax(low, high, model.getWater());
findMinMax(low, high, model.getVegetation());
Vector3d[] result = new Vector3d[2];
result[0] = low;
result[1] = high;
return BoundingBox.of(result);
}
private static void findMinMax(Vector3d low, Vector3d high, List<? extends CityObject> features) {
for (CityObject co : features) {
findMinMax(low, high, co);
}
}
private static void findMinMax(Vector3d low, Vector3d high, CityObject co) {
for (Geometry geom : co.getGeometries()) {
for (Vertex v : geom.getVertices()) {
if (v.getX() < low.getX()) {
low.setX(v.getX());
} else if (v.getX() > high.getX()) {
high.setX(v.getX());
}
if (v.getY() < low.getY()) {
low.setY(v.getY());
} else if (v.getY() > high.getY()) {
high.setY(v.getY());
}
if (v.getZ() < low.getZ()) {
low.setZ(v.getZ());
} else if (v.getZ() > high.getZ()) {
high.setZ(v.getZ());
}
}
}
}
}
/*-
* Copyright 2020 Beuth Hochschule für Technik Berlin, Hochschule für Technik Stuttgart
*
* This file is part of CityDoctor2.
*
* CityDoctor2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* CityDoctor2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with CityDoctor2. If not, see <https://www.gnu.org/licenses/>.
*/
package de.hft.stuttgart.citydoctor2.utils;
import java.util.ArrayList;
import java.util.List;
import org.citygml4j.factory.DimensionMismatchException;
import org.citygml4j.factory.GMLGeometryFactory;
import org.citygml4j.model.gml.geometry.aggregates.MultiSurface;
import org.citygml4j.model.gml.geometry.complexes.CompositeSurface;
import org.citygml4j.model.gml.geometry.primitives.AbstractSurface;
import org.citygml4j.model.gml.geometry.primitives.Exterior;
import org.citygml4j.model.gml.geometry.primitives.Interior;
import org.citygml4j.model.gml.geometry.primitives.Solid;
import org.citygml4j.model.gml.geometry.primitives.SurfaceProperty;
import org.osgeo.proj4j.BasicCoordinateTransform;
import org.osgeo.proj4j.ProjCoordinate;
import de.hft.stuttgart.citydoctor2.datastructure.Geometry;
import de.hft.stuttgart.citydoctor2.datastructure.GeometryType;
import de.hft.stuttgart.citydoctor2.datastructure.LinearRing;
import de.hft.stuttgart.citydoctor2.datastructure.Polygon;
import de.hft.stuttgart.citydoctor2.datastructure.Vertex;
import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration;
/**
* Utility class dedicated to create CityGML4j datastructures.
*
* @author Matthias Betz
*
*/
public final class CityGmlUtils {
private CityGmlUtils() {
// util class
}
public static org.citygml4j.model.gml.geometry.primitives.Polygon createGmlPolygon(GMLGeometryFactory factory,
Polygon cdPoly, ParserConfiguration config) {
if (cdPoly.getExteriorRing() == null) {
return null;
}
org.citygml4j.model.gml.geometry.primitives.Polygon gmlPoly = new org.citygml4j.model.gml.geometry.primitives.Polygon();
try {
// exterior ring
LinearRing extLr = cdPoly.getExteriorRing();
org.citygml4j.model.gml.geometry.primitives.LinearRing gmlLr = createGmlRing(factory, config, extLr);
gmlPoly.setExterior(new Exterior(gmlLr));
// interior rings
for (LinearRing lr : cdPoly.getInnerRings()) {
gmlLr = createGmlRing(factory, config, lr);
gmlPoly.addInterior(new Interior(gmlLr));
}
gmlPoly.setId(cdPoly.getGmlId().getGmlString());
return gmlPoly;
} catch (DimensionMismatchException e) {
// cannot happen as every vertex has 3 coordinates
return null;
}
}
private static org.citygml4j.model.gml.geometry.primitives.LinearRing createGmlRing(GMLGeometryFactory factory,
ParserConfiguration config, LinearRing lr) throws DimensionMismatchException {
ProjCoordinate p1 = new ProjCoordinate();
ProjCoordinate p2 = new ProjCoordinate();
List<Double> ringValues = new ArrayList<>();
BasicCoordinateTransform trans = config.getOriginalTransform();
for (Vertex v : lr.getVertices()) {
double x = v.getX();
double y = v.getY();
double z = v.getZ();
if (trans != null) {
p1.x = x;
p1.y = y;
trans.transform(p1, p2);
x = p2.x;
y = p2.y;
z = z * config.getFromMetres();
}
ringValues.add(x);
ringValues.add(y);
ringValues.add(z);
}
org.citygml4j.model.gml.geometry.primitives.LinearRing gmlLr = factory.createLinearRing(ringValues, 3);
gmlLr.setId(lr.getGmlId().getGmlString());
return gmlLr;
}
public static Solid createSolid(Geometry geom, GMLGeometryFactory factory, ParserConfiguration config) {
if (geom.getType() != GeometryType.SOLID) {
throw new IllegalArgumentException("Only solids are allowed");
}
List<SurfaceProperty> surfaceMember = new ArrayList<>();
for (Polygon cdPoly : geom.getPolygons()) {
if (!cdPoly.isLink()) {
org.citygml4j.model.gml.geometry.primitives.Polygon gmlPoly = createGmlPolygon(factory, cdPoly, config);
if (gmlPoly != null) {
surfaceMember.add(new SurfaceProperty(gmlPoly));
}
} else {
// add reference to polygon
surfaceMember.add(new SurfaceProperty("#" + cdPoly.getGmlId().getGmlString()));
}
}
if (surfaceMember.isEmpty()) {
return null;
}
CompositeSurface comp = new CompositeSurface();
comp.setSurfaceMember(surfaceMember);
Solid solid = new Solid();
solid.setExterior(new SurfaceProperty(comp));
solid.setId(geom.getGmlId().getGmlString());
return solid;
}
public static MultiSurface createMultiSurface(Geometry geom, GMLGeometryFactory factory,
ParserConfiguration config) {
if (geom.getType() != GeometryType.MULTI_SURFACE) {
throw new IllegalArgumentException("This can only handle MultiSurfaces");
}
List<AbstractSurface> surfaces = new ArrayList<>();
for (Polygon cdPoly : geom.getPolygons()) {
if (!cdPoly.isLink()) {
// is not part of a boundary surface
org.citygml4j.model.gml.geometry.primitives.Polygon gmlPoly = createGmlPolygon(factory, cdPoly, config);
if (gmlPoly != null) {
surfaces.add(gmlPoly);
}
} else {
// add reference to polygon
CompositeSurface cs = new CompositeSurface();
cs.addSurfaceMember(new SurfaceProperty("#" + cdPoly.getGmlId().getGmlString()));
surfaces.add(cs);
}
}
if (surfaces.isEmpty()) {
return null;
}
MultiSurface ms = new MultiSurface(surfaces);
ms.setId(geom.getGmlId().getGmlString());
return ms;
}
public static MultiSurface createMultiSurface(List<Polygon> polygons, GMLGeometryFactory factory,
ParserConfiguration config) {
List<AbstractSurface> surfaces = new ArrayList<>();
for (Polygon cdPoly : polygons) {
org.citygml4j.model.gml.geometry.primitives.Polygon gmlPoly = createGmlPolygon(factory, cdPoly, config);
if (gmlPoly != null) {
surfaces.add(gmlPoly);
}
}
if (surfaces.isEmpty()) {
return null;
}
return new MultiSurface(surfaces);
}
}
/*-
* Copyright 2020 Beuth Hochschule für Technik Berlin, Hochschule für Technik Stuttgart
*
* This file is part of CityDoctor2.
*
* CityDoctor2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* CityDoctor2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with CityDoctor2. If not, see <https://www.gnu.org/licenses/>.
*/
package de.hft.stuttgart.citydoctor2.utils;
import java.util.ResourceBundle;
/**
* Used to get localized text values
*
* @author Matthias Betz
*
*/
public class Localization {
private static ResourceBundle bundle;
static {
bundle = ResourceBundle.getBundle("CityDoctorLocalization");
}
private Localization() {
}
public static String getText(String key) {
return bundle.getString(key);
}
}
/*-
* Copyright 2020 Beuth Hochschule für Technik Berlin, Hochschule für Technik Stuttgart
*
* This file is part of CityDoctor2.
*
* CityDoctor2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* CityDoctor2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with CityDoctor2. If not, see <https://www.gnu.org/licenses/>.
*/
package de.hft.stuttgart.citydoctor2.utils;
/**
* Used for return values if more than one object should be returned.
*
* @author Matthias Betz
*
* @param <A> Type of value 1
* @param <B> Type of value 2
*/
public class Pair<A, B> {
private A a;
private B b;
public Pair(A a, B b) {
this.a = a;
this.b = b;
}
public Pair(Pair<? extends A, ? extends B> other) {
this.a = other.a;
this.b = other.b;
}
public A getValue0() {
return a;
}
public B getValue1() {
return b;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((a == null) ? 0 : a.hashCode());
result = prime * result + ((b == null) ? 0 : b.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
Pair<?, ?> other = (Pair<?, ?>) obj;
if (a == null) {
if (other.a != null) {
return false;
}
} else if (!a.equals(other.a)) {
return false;
}
if (b == null) {
if (other.b != null) {
return false;
}
} else if (!b.equals(other.b)) {
return false;
}
return true;
}
@Override
public String toString() {
return "Pair [a=" + a + ", b=" + b + "]";
}
}
/*-
* Copyright 2020 Beuth Hochschule für Technik Berlin, Hochschule für Technik Stuttgart
*
* This file is part of CityDoctor2.
*
* CityDoctor2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* CityDoctor2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with CityDoctor2. If not, see <https://www.gnu.org/licenses/>.
*/
package de.hft.stuttgart.citydoctor2.utils;
import java.util.List;
import de.hft.stuttgart.citydoctor2.datastructure.ConcretePolygon;
import de.hft.stuttgart.citydoctor2.datastructure.Polygon;
import de.hft.stuttgart.citydoctor2.math.Segment3d;
/**
* Result of a polygon polygon intersection.
*
* @author Matthias Betz
*
*/
public class PolygonIntersection {
public enum IntersectionType {
NONE, LINE, POLYGON
}
private IntersectionType type;
private List<Segment3d> lines;
private ConcretePolygon polygon;
private Polygon p1;
private Polygon p2;
public static PolygonIntersection none() {
return new PolygonIntersection(IntersectionType.NONE);
}
public static PolygonIntersection lines(List<Segment3d> lines, Polygon p1, Polygon p2) {
PolygonIntersection poly = new PolygonIntersection(IntersectionType.LINE);
poly.lines = lines;
poly.p1 = p1;
poly.p2 = p2;
return poly;
}
public static PolygonIntersection polygon(ConcretePolygon polygon, Polygon p1, Polygon p2) {
PolygonIntersection poly = new PolygonIntersection(IntersectionType.POLYGON);
poly.polygon = polygon;
poly.p1 = p1;
poly.p2 = p2;
return poly;
}
public Polygon getP1() {
return p1;
}
public Polygon getP2() {
return p2;
}
private PolygonIntersection(IntersectionType type) {
this.type = type;
}
public IntersectionType getType() {
return type;
}
public List<Segment3d> getLines() {
return lines;
}
public ConcretePolygon getIntersectionPolygon() {
return polygon;
}
@Override
public String toString() {
return "PolygonIntersection [type=" + type + ", lines=" + lines + ", polygon=" + polygon + ", p1=" + p1
+ ", p2=" + p2 + "]";
}
}
/*-
* Copyright 2020 Beuth Hochschule für Technik Berlin, Hochschule für Technik Stuttgart
*
* This file is part of CityDoctor2.
*
* CityDoctor2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* CityDoctor2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with CityDoctor2. If not, see <https://www.gnu.org/licenses/>.
*/
package de.hft.stuttgart.citydoctor2.utils;
import java.io.Serializable;
/**
* When a pair of values is needed that need to be serialized.
*
* @author Matthias Betz
*
* @param <A> Type of value 1, needs to implement Serializable
* @param <B> Type of value 2, needs to implement Serializable
*/
public class SerializablePair<A extends Serializable, B extends Serializable> implements Serializable {
private static final long serialVersionUID = -5307944001963352647L;
private A a;
private B b;
public SerializablePair(A a, B b) {
this.a = a;
this.b = b;
}
public SerializablePair(SerializablePair<? extends A, ? extends B> other) {
this.a = other.a;
this.b = other.b;
}
public A getValue0() {
return a;
}
public B getValue1() {
return b;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((a == null) ? 0 : a.hashCode());
result = prime * result + ((b == null) ? 0 : b.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
SerializablePair<?, ?> other = (SerializablePair<?, ?>) obj;
if (a == null) {
if (other.a != null) {
return false;
}
} else if (!a.equals(other.a)) {
return false;
}
if (b == null) {
if (other.b != null) {
return false;
}
} else if (!b.equals(other.b)) {
return false;
}
return true;
}
@Override
public String toString() {
return "SerializablePair [a=" + a + ", b=" + b + "]";
}
}
DistanceError.distanceFromPlane=distance from plane
AboutDialog.developedBy=Developed by
AboutDialog.contact=Contact
AboutDialog.title=CityDoctor 3 - About
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
CheckDialog.checkEnabled=Enabled
CheckDialog.checkName=Name
CheckDialog.parameterValue=Value
CheckDialog.parameterUnit=Unit
CityDoctorController.noDatamodel=Datamodel is null, no checks could be done
CityDoctorController.noSourceFile=Source file is null, no checks could be done
ExceptionDialog.stacktrace=The exception stacktrace was:
FilterPane.buildings=Buildings
FilterPane.bridges=Bridges
FilterPane.landUse=Land Use
FilterPane.transportation=Transportation
FilterPane.vegetation=Vegetation
FilterPane.water=Water
MainToolBar.wireframe=Show/Hide Wireframe
MainToolBar.culling=Enable/Disable Culling
MainToolBar.writeReports=Write Reports
MainToolBar.executeChecks=Execute Checks
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
OpenFileDialog.select=Select CityGML file
MainWindow.languageChange=For the change in language to apply, restart CityDoctor2.
MainWindow.buildingsTab=Buildings
MainWindow.vegetationTab=Vegetation
MainWindow.transportationTab=Transportation
MainWindow.bridgeTab=Bridges
MainWindow.waterTab=Water
MainWindow.terrainTab=Terrain
MainWindow.viewLabel=View
MainWindow.showLabel=Show:
MainWindow.searchLabel=Search:
MainWindow.searchBtn=Search
MainWindow.clearBtn=Clear
OpenFileDialog.fileLabel=File:
OpenFileDialog.selectBtn=Select
\ No newline at end of file
DistanceError.distanceFromPlane=Abstand von der Ebene
AboutDialog.developedBy=Entwickelt von
AboutDialog.contact=Kontakt
AboutDialog.title=CityDoctor 3 - ber
CheckDialog.title=Prfungskonfiguration
CheckDialog.schematronFiles=Schematron Dateien
CheckDialog.schematronChooserTitle=Whle Schematron Datei..
CheckDialog.validationConfiguration=Validierungs Konfiguration
CheckDialog.startingChecks=Starte Prfung
CheckDialog.checksDone=Prfung abgeschlossen
CheckDialog.failedChecks=Konnte Prfungen nicht ausfhren
CheckDialog.schematronFileNotExisting=Schematron Datei existiert nicht, ignoriere
CheckDialog.checkEnabled=Aktiv
CheckDialog.parameterValue=Wert
CheckDialog.parameterUnit=Einheit
CityDoctorController.noDatamodel=Datenmodell ist null, keine Prfungen konnten ausgefhrt werden
CityDoctorController.noSourceFile=Quelldatei ist null, keine Prfungen konnten ausgefhrt werden
ExceptionDialog.stacktrace=Der Stacktrace des Fehlers war:
FilterPane.buildings=Gebude
FilterPane.bridges=Brcken
FilterPane.landUse=Landnutzung
FilterPane.transportation=Transport
FilterPane.vegetation=Vegetation
FilterPane.water=Wasser
MainToolBar.wireframe=Zeige/Verstecke Gitternetz
MainToolBar.culling=Aktiviere/Deaktiviere Entfernen der Rckseiten
MainToolBar.writeReports=Schreibe Reports
MainToolBar.executeChecks=Fhre Prfungen aus
MainWindow.missingConfig=Konnte Konfigurationsdatei nicht finden.
MainWindow.loadGivenFile=Lade vorhandene Datei, bitte warten
MainWindow.finishedLoading=Fertig geladen
MainWindow.checking=Prfe, 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=Exportieren
OpenFileDialog.select=Whle CityGML Datei aus
MainWindow.languageChange=Um die Spracheinstellung zu bernehmen muss CityDoctor2 neugestartet werden.
MainWindow.buildingsTab=Gebude
MainWindow.vegetationTab=Vegetation
MainWindow.transportationTab=Verkehrsobjekte
MainWindow.bridgeTab=Brcken
MainWindow.waterTab=Gewsser
MainWindow.terrainTab=Gelnde
MainWindow.viewLabel=Ansicht
MainWindow.showLabel=Zeige:
MainWindow.searchLabel=Suche:
MainWindow.searchBtn=Suche
MainWindow.clearBtn=Leeren
OpenFileDialog.fileLabel=Datei:
OpenFileDialog.selectBtn=Auswhlen
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Configuration>
<Configuration status="INFO">
<Appenders>
<Console name="console" target="SYSTEM_OUT">
<PatternLayout
pattern="[%-5level] %d{HH:mm:ss.SSS} %c{1} - %msg%n" />
</Console>
</Appenders>
<Loggers>
<Root level="debug" additivity="false">
<AppenderRef ref="console" />
</Root>
</Loggers>
</Configuration>
\ No newline at end of file
Markdown is supported
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