Commit 9add63da authored by Matthias Betz's avatar Matthias Betz
Browse files

fixing various code maintenance issues

2 merge requests!28Version 3.17.0 Release,!24cleanup code
Pipeline #10970 passed with stage
in 1 minute and 11 seconds
Showing with 272 additions and 49 deletions
+272 -49
<?xml version="1.0" encoding="utf-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0">
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>de.hft.stuttgart</groupId>
......
<?xml version="1.0" encoding="utf-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0">
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>de.hft.stuttgart</groupId>
......
......@@ -29,7 +29,6 @@ public class Vector2d {
this.y = y;
}
@SuppressWarnings("SuspiciousNameCombination")
public Vector2d getPerpendicularVector() {
return new Vector2d(y, -x);
}
......
<?xml version="1.0" encoding="utf-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0">
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>de.hft.stuttgart</groupId>
......@@ -58,6 +60,14 @@
<groupId>org.locationtech.proj4j</groupId>
<artifactId>proj4j</artifactId>
</dependency>
<dependency>
<groupId>org.locationtech.jts</groupId>
<artifactId>jts-core</artifactId>
</dependency>
<dependency>
<groupId>io.github.earcut4j</groupId>
<artifactId>earcut4j</artifactId>
</dependency>
</dependencies>
<build>
<resources>
......@@ -84,7 +94,8 @@
<prefix>git</prefix>
<verbose>false</verbose>
<generateGitPropertiesFile>true</generateGitPropertiesFile>
<generateGitPropertiesFilename>${project.build.outputDirectory}/git.properties</generateGitPropertiesFilename>
<generateGitPropertiesFilename>
${project.build.outputDirectory}/git.properties</generateGitPropertiesFilename>
<gitDescribe>
<skip>false</skip>
<always>false</always>
......
......@@ -60,10 +60,8 @@ import de.hft.stuttgart.citydoctor2.check.error.UnknownCheckError;
* @author Matthias Betz
*
*/
@SuppressWarnings("unused")
public interface HealingMethod {
public HealingID getID();
default boolean visit(CheckError e, ModificationListener l) {
......
......@@ -804,19 +804,6 @@ public class Citygml3FeatureMapper extends ObjectWalker {
}
}
// private void parseAndAddCompositeSurface(MultiSurfaceProperty ms, Lod lod, CityObject co) {
// if (ms == null || ms.getObject() == null) {
// return;
// }
// List<SurfaceProperty> surfaces = ms.getObject().getSurfaceMember();
// for (SurfaceProperty surface : surfaces) {
// if (surface.getObject() instanceof CompositeSurface cs) {
// Geometry geom = parseCompositeSurface(cs, lod);
// co.addGeometry(geom);
// }
// }
// }
private void parseImplicitGeometry(AbstractOccupiedSpace aos, CityObject co) {
for (int i = 1; i <= 3; i++) {
if (aos.getImplicitRepresentation(i) == null) {
......
......@@ -39,6 +39,25 @@ public class MovedPolygon {
private MovedRing exteriorRing;
private List<MovedRing> innerRings;
/**
* Moves the polygon by the first exterior vertex. The center of the polygon
* will not me the origin, the polygon will just be near the origin. This can
* eliviate numeric issues in large calculations.
*
* @param p the polygon that is moved to the center.
* @return the moved polygon.
*/
public static MovedPolygon ofPolygon(Polygon p) {
Vector3d movedBy = p.getExteriorRing().getVertices().get(0);
MovedPolygon indPoly = new MovedPolygon();
indPoly.original = p;
indPoly.exteriorRing = MovedRing.ofRing(p.getExteriorRing(), movedBy);
for (LinearRing inner : p.getInnerRings()) {
indPoly.addInnerRing(MovedRing.ofRing(inner, movedBy));
}
return indPoly;
}
public static MovedPolygon ofPolygon(Polygon p, Vector3d movedBy) {
MovedPolygon indPoly = new MovedPolygon();
indPoly.original = p;
......
......@@ -41,6 +41,11 @@ public class Polygon2d {
return projectTo2D(poly, axis);
}
public static Polygon2d withProjection(MovedPolygon poly) {
ProjectionAxis axis = ProjectionAxis.of(poly.getOriginal());
return projectTo2D(poly, axis);
}
public static Polygon2d withProjection(MovedPolygon poly, ProjectionAxis projectionAxis) {
return projectTo2D(poly, projectionAxis);
}
......
......@@ -87,12 +87,27 @@ public class ProjectionAxis {
this.axis = axis;
}
/**
* This will write the two coordinates determined in this projection axis into a
* given array at the startIndex location. The array has to have at least a
* length of startIndex + 1.
*
* @param v the vector from which the coordinates are taken.
* @param array the array that is written to.
* @param startIndex the start location in the array.
*/
public void writeCoordinatesOfVectorInArray(Vector3d v, double[] array, int startIndex) {
array[startIndex] = v.getCoordinate(axis[0]);
array[startIndex + 1] = v.getCoordinate(axis[1]);
}
public Vector2d project(Vector3d v) {
return new Vector2d(v.getCoordinate(axis[0]), v.getCoordinate(axis[1]));
}
/**
* calculates the missing coordinate for 3d vector from the plane and this axis.
*
* @return the projected 3d point.
*/
public Vector3d projectToPlane(Plane plane, Vector2d v) {
......@@ -101,6 +116,7 @@ public class ProjectionAxis {
/**
* calculates the missing coordinate for 3d vector from the plane and this axis.
*
* @return the projected 3d point.
*/
public Vector3d projectToPlane(Plane plane, double vectorX, double vectorY) {
......
......@@ -22,6 +22,8 @@ import java.io.Serial;
import java.io.Serializable;
import java.util.Arrays;
import org.locationtech.jts.geom.Coordinate;
/**
* A three dimensional vector
*
......@@ -45,6 +47,17 @@ public class Vector3d implements Serializable {
this(0d, 0d, 0d);
}
/**
* Convert JTS Coordinate class to Vector3d.
* @param coord JTS Coordinate
*/
public Vector3d(Coordinate coord) {
coords = new double[3];
coords[0] = coord.getX();
coords[1] = coord.getY();
coords[2] = coord.getZ();
}
public Vector3d(double x, double y, double z) {
coords = new double[3];
coords[0] = x;
......
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.datastructure.Polygon;
import de.hft.stuttgart.citydoctor2.datastructure.Vertex;
import de.hft.stuttgart.citydoctor2.math.ProjectionAxis;
import de.hft.stuttgart.citydoctor2.math.Triangle3d;
import earcut4j.Earcut;
/**
* Tesselator to create triangles out of polygons. Uses earcut4j implementation.
*
* @author Matthias Betz
*
*/
public class EarcutTesselator {
public static TesselatedPolygon tesselatePolygon(Polygon p) {
// sum number of vertices, don't use duplicate last point
// assume polygons are closed
int nrOfVertices = p.getExteriorRing().getVertices().size() - 1;
int[] holeStart = null;
if (!p.getInnerRings().isEmpty()) {
holeStart = new int[p.getInnerRings().size()];
List<LinearRing> innerRings = p.getInnerRings();
for (int i = 0; i < innerRings.size(); i++) {
LinearRing r = innerRings.get(i);
holeStart[i] = nrOfVertices;
nrOfVertices += r.getVertices().size() - 1;
}
}
// collect vertices
// find most dominant projection axis for 2d projection
ProjectionAxis axis = ProjectionAxis.of(p);
double[] vertices = new double[nrOfVertices * 2];
List<Vertex> vertexObjects = new ArrayList<>();
addVerticesToList(p.getExteriorRing(), vertexObjects);
for (LinearRing innerRing : p.getInnerRings()) {
addVerticesToList(innerRing, vertexObjects);
}
// write the vector data according to the projection axis into the array
int start = addRingToArray(p.getExteriorRing(), vertices, 0, axis);
for (LinearRing innerRing : p.getInnerRings()) {
start = addRingToArray(innerRing, vertices, start, axis);
}
// triangulation
List<Integer> indices = Earcut.earcut(vertices, holeStart, 2);
List<Triangle3d> triangles = new ArrayList<>();
if (indices.size() % 3 != 0) {
throw new IllegalStateException();
}
for (int i = 0; i < indices.size(); i = i + 3) {
Triangle3d t = new Triangle3d(vertexObjects.get(indices.get(i + 0)),
vertexObjects.get(indices.get(i + 1)),
vertexObjects.get(indices.get(i + 2)));
triangles.add(t);
}
return new TesselatedPolygon(triangles, p);
}
private static void addVerticesToList(LinearRing ring, List<Vertex> vertexObjects) {
List<Vertex> vertices = ring.getVertices();
for (int i = 0; i < vertices.size() - 1; i++) {
Vertex v = vertices.get(i);
vertexObjects.add(v);
}
}
private static int addRingToArray(LinearRing ring, double[] vertices, int start, ProjectionAxis axis) {
List<Vertex> ringVertices = ring.getVertices();
for (int i = 0; i < ringVertices.size() - 1; i++) {
Vertex v = ringVertices.get(i);
axis.writeCoordinatesOfVectorInArray(v, vertices, start);
start = start + 2;
}
return start;
}
private EarcutTesselator() {
}
}
......@@ -33,7 +33,7 @@ import de.hft.stuttgart.citydoctor2.datastructure.Vertex;
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
*
......@@ -102,6 +102,10 @@ public class JoglTesselator {
}
public static TesselatedPolygon tesselatePolygon(Polygon p) {
return tesselatePolygon(p, true);
}
public static TesselatedPolygon tesselatePolygon(Polygon p, boolean discardDegeneratedTriangles) {
ArrayList<Vector3d> vertices = new ArrayList<>();
Vector3d normal = p.calculateNormalNormalized();
synchronized (tess) {
......@@ -121,7 +125,7 @@ public class JoglTesselator {
GLU.gluTessEndPolygon(tess);
ArrayList<Integer> indices = new ArrayList<>();
for (Primitive primitive : primitives) {
primitive.fillListWithIndices(indices);
primitive.fillListWithIndices(indices, discardDegeneratedTriangles);
}
primitives.clear();
return new TesselatedPolygon(vertices, indices, p);
......@@ -137,7 +141,7 @@ public class JoglTesselator {
GLU.gluTessEndContour(tess);
}
public static TesselatedRing tesselateRing(LinearRing r) {
public static TesselatedRing tesselateRing(LinearRing r, boolean discardDegeneratedTriangles) {
ArrayList<Vector3d> vertices = new ArrayList<>();
Vector3d normal = r.calculateNormal();
synchronized (tess) {
......@@ -147,13 +151,17 @@ public class JoglTesselator {
GLU.gluTessEndPolygon(tess);
ArrayList<Integer> indices = new ArrayList<>();
for (Primitive primitive : primitives) {
primitive.fillListWithIndices(indices);
primitive.fillListWithIndices(indices, discardDegeneratedTriangles);
}
primitives.clear();
return new TesselatedRing(vertices, indices, r);
}
}
public static TesselatedRing tesselateRing(LinearRing r) {
return tesselateRing(r, true);
}
private JoglTesselator() {
// only static useage
}
......
......@@ -49,30 +49,34 @@ public class Primitive {
this.type = type;
}
public void fillListWithIndices(List<Integer> indices) {
public void fillListWithIndices(List<Integer> indices, boolean discardDegeneratedTriangles) {
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);
addToListIfAreaNonNull(pIndices.get(i), pIndices.get(i + 1), pIndices.get(i + 2), indices,
discardDegeneratedTriangles);
}
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);
addToListIfAreaNonNull(pIndices.get(i), pIndices.get(i + 1), pIndices.get(i + 2), indices,
discardDegeneratedTriangles);
} 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;
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);
addToListIfAreaNonNull(first, pIndices.get(i + 1), pIndices.get(i + 2), indices,
discardDegeneratedTriangles);
}
break;
default:
throw new IllegalStateException("unknown type found: " + type);
throw new IllegalStateException("unknown triangle type found: " + type);
}
}
......@@ -80,17 +84,18 @@ public class Primitive {
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 v2 = vertices.get(i2);
Vector3d v3 = vertices.get(i3);
double area = Math.abs(calculateAreaOfTriangle(v1, v2, v3));
if (area > AREA_EPSILON) {
if (discardDegeneratedTriangles && Math.abs(calculateAreaOfTriangle(v1, v2, v3)) <= 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(i2);
indices.add(i3);
} else {
logger.trace("Tesselator created degenerated triangle, ignoring");
}
}
......
......@@ -25,6 +25,7 @@ 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;
import de.hft.stuttgart.citydoctor2.math.Triangle3d;
/**
* Result of a polygon polygon intersection.
......@@ -38,7 +39,7 @@ public class PolygonIntersection implements Serializable {
private static final long serialVersionUID = -6301963226688351725L;
public enum IntersectionType {
NONE, LINE, POLYGON
NONE, LINE, POLYGON, TRIANGLES
}
private final IntersectionType type;
......@@ -48,10 +49,30 @@ public class PolygonIntersection implements Serializable {
private Polygon p1;
private Polygon p2;
private Triangle3d t1;
private Triangle3d t2;
public static PolygonIntersection 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) {
PolygonIntersection poly = new PolygonIntersection(IntersectionType.LINE);
poly.lines = lines;
......@@ -76,6 +97,14 @@ public class PolygonIntersection implements Serializable {
return p2;
}
public Triangle3d getT1() {
return t1;
}
public Triangle3d getT2() {
return t2;
}
private PolygonIntersection(IntersectionType type) {
this.type = type;
}
......
......@@ -120,3 +120,12 @@ MainWindow.memoryLabel=Memory:
CheckDialog.checksReenabledAlert=Some checks have been reenabled so that other wanted checks can be executed\nSee the log for more information.
MainWindow.availableLabel=Available:
OpenFileDialog.lowMemoryLabel=Low Memory Consumption Mode
ErrorItemVisitor.intersection=Intersection
ErrorItemVisitor.component=Component
ErrorItemVisitor.nameOfAttribute=Name of attribute
ErrorItemVisitor.childId=Child id
ErrorItemVisitor.distance=Distance
ErrorItemVisitor.pointTouchesEdge=Point touches edge
ErrorItemVisitor.degeneratedRing=Degenerated ring
ErrorItemVisitor.deviation=Deviation
ErrorItemVisitor.triangles=Triangles
\ No newline at end of file
......@@ -118,3 +118,12 @@ MainWindow.memoryLabel=Speicher:
CheckDialog.checksReenabledAlert=Manche Pr\u00fcfungen wurden reaktiviert damit andere gewollte Pr\u00fcfungen durchgef\u00fchrt werden k\u00f6nnen\nMehr Details sind im Log geschrieben
MainWindow.availableLabel=Verf\u00fcgbar:
OpenFileDialog.lowMemoryLabel=Reduzierter Speicherverbrauchsmodus
ErrorItemVisitor.intersection=Verschneidung
ErrorItemVisitor.component=Komponente
ErrorItemVisitor.nameOfAttribute=Name des Attributs
ErrorItemVisitor.childId=Kind ID
ErrorItemVisitor.distance=Distanz
ErrorItemVisitor.pointTouchesEdge=Punkt ber\u00fchrt Kante
ErrorItemVisitor.degeneratedRing=Degenerierter Ring
ErrorItemVisitor.deviation=Abweichung
ErrorItemVisitor.triangles=Dreiecke
\ No newline at end of file
......@@ -423,6 +423,7 @@ public class Checker {
}
}
@SuppressWarnings("resource")
public static SvrlContentHandler executeSchematronValidationIfAvailable(ValidationConfiguration config,
InputStream in) {
if (config.getSchematronFilePath() != null && !config.getSchematronFilePath().isEmpty()) {
......
......@@ -75,7 +75,7 @@ public class SolidSelfIntCheck extends Check {
return;
}
CheckResult cr;
List<PolygonIntersection> intersections = SelfIntersectionUtil.doesSolidSelfIntersect2(g);
List<PolygonIntersection> intersections = SelfIntersectionUtil.calculateSolidSelfIntersection(g);
if (intersections.isEmpty()) {
cr = new CheckResult(this, ResultStatus.OK, null);
} else {
......
......@@ -62,6 +62,7 @@ import de.hft.stuttgart.citydoctor2.math.Segment3d;
import de.hft.stuttgart.citydoctor2.math.Triangle3d;
import de.hft.stuttgart.citydoctor2.math.Vector2d;
import de.hft.stuttgart.citydoctor2.math.Vector3d;
import de.hft.stuttgart.citydoctor2.tesselation.EarcutTesselator;
import de.hft.stuttgart.citydoctor2.tesselation.JoglTesselator;
import de.hft.stuttgart.citydoctor2.tesselation.TesselatedPolygon;
import de.hft.stuttgart.citydoctor2.utils.PolygonIntersection;
......@@ -75,7 +76,6 @@ import de.hft.stuttgart.citydoctor2.utils.PolygonIntersection.IntersectionType;
*/
public class SelfIntersectionUtil {
private static final Logger logger = LogManager.getLogger(SelfIntersectionUtil.class);
private static final GeometryFactory factory = new GeometryFactory(new PrecisionModel(PrecisionModel.FLOATING));
......@@ -84,6 +84,25 @@ public class SelfIntersectionUtil {
}
public static List<PolygonIntersection> calculateSolidSelfIntersection(Geometry g) {
List<TesselatedPolygon> tesselatedPolygons = new ArrayList<>();
for (Polygon p : g.getPolygons()) {
tesselatedPolygons.add(EarcutTesselator.tesselatePolygon(p));
}
List<PolygonIntersection> intersections = new ArrayList<>();
for (int i = 0; i < tesselatedPolygons.size() - 1; i++) {
TesselatedPolygon p1 = tesselatedPolygons.get(i);
for (int j = i + 1; j < tesselatedPolygons.size(); j++) {
TesselatedPolygon p2 = tesselatedPolygons.get(j);
GeometrySelfIntersection intersection = doPolygonsIntersect(p1, p2);
if (intersection != null) {
intersections.add(PolygonIntersection.triangles(intersection.t1(), intersection.t2()));
}
}
}
return intersections;
}
public static GeometrySelfIntersection doesSolidSelfIntersect(Geometry g) {
return selfIntersectionJava(g);
}
......@@ -114,14 +133,15 @@ public class SelfIntersectionUtil {
return intersections;
}
private static void performEdgeSelfIntersection(List<PolygonIntersection> intersections, Map<Polygon, EdgePolygon> edgePolyMap,
Polygon p1, Polygon p2) {
private static void performEdgeSelfIntersection(List<PolygonIntersection> intersections,
Map<Polygon, EdgePolygon> edgePolyMap, Polygon p1, Polygon p2) {
EdgePolygon edgeP1 = edgePolyMap.get(p1);
EdgePolygon edgeP2 = edgePolyMap.get(p2);
List<PolygonPolygonIntersection> results = IntersectPlanarPolygons.intersectPolygons(edgeP1, edgeP2, 0.000001, 0.001);
List<PolygonPolygonIntersection> results = IntersectPlanarPolygons.intersectPolygons(edgeP1, edgeP2, 0.000001,
0.001);
if (!results.isEmpty()) {
// at least one intersection happened
for (PolygonPolygonIntersection result: results) {
for (PolygonPolygonIntersection result : results) {
// Ensure that Intersection-Edge is not a Null-Line.
// If it is a Null-Line, detected Intersection is a False-Positive.
if (!result.getPolyLine().isNullLine()) {
......
<?xml version="1.0" encoding="utf-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0">
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>de.hft.stuttgart</groupId>
......
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