Commit a138df4b authored by Matthias Betz's avatar Matthias Betz
Browse files

changing math api to be more robust

parent f74c2f52
Pipeline #4354 passed with stage
in 2 minutes and 21 seconds
...@@ -22,6 +22,9 @@ import java.util.ArrayList; ...@@ -22,6 +22,9 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import de.hft.stuttgart.citydoctor2.check.Check; import de.hft.stuttgart.citydoctor2.check.Check;
import de.hft.stuttgart.citydoctor2.math.ProjectionAxis;
import de.hft.stuttgart.citydoctor2.math.Ring2d;
import de.hft.stuttgart.citydoctor2.math.UnitVector3d;
import de.hft.stuttgart.citydoctor2.math.Vector2d; import de.hft.stuttgart.citydoctor2.math.Vector2d;
import de.hft.stuttgart.citydoctor2.math.Vector3d; import de.hft.stuttgart.citydoctor2.math.Vector3d;
...@@ -57,37 +60,13 @@ public class LinearRing extends GmlElement { ...@@ -57,37 +60,13 @@ public class LinearRing extends GmlElement {
*/ */
public boolean isPointInside(Vector3d v) { public boolean isPointInside(Vector3d v) {
// project to 2d ring // project to 2d ring
List<Vector2d> projectedRing = new ArrayList<>(); ProjectionAxis axis = ProjectionAxis.of(this);
Vector2d point; Vector2d point = axis.project(v);
Vector3d normal = calculateNormalNormalized(); Ring2d ring = Ring2d.of(this, axis);
double x = Math.abs(normal.getX());
double y = Math.abs(normal.getY());
double z = Math.abs(normal.getZ());
if (x > y && x > z) {
for (Vertex vert : vertices) {
Vector2d projCoords = new Vector2d(vert.getY(), vert.getZ());
projectedRing.add(projCoords);
}
point = new Vector2d(v.getY(), v.getZ());
} else if (y > x && y > z) {
for (Vertex vert : vertices) {
Vector2d projCoords = new Vector2d(vert.getX(), vert.getZ());
projectedRing.add(projCoords);
}
point = new Vector2d(v.getX(), v.getZ());
} else {
for (Vertex vert : vertices) {
Vector2d projCoords = new Vector2d(vert.getX(), vert.getY());
projectedRing.add(projCoords);
}
point = new Vector2d(v.getX(), v.getY());
}
int t = -1; int t = -1;
for (int i = 0; i < projectedRing.size() - 1; i++) { for (int i = 0; i < ring.getVertices().size() - 1; i++) {
t = t * crossProdTest(point, projectedRing.get(i), projectedRing.get(i + 1)); t = t * crossProdTest(point, ring.getVertices().get(i), ring.getVertices().get(i + 1));
if (t == 0) { if (t == 0) {
return true; return true;
} }
...@@ -135,31 +114,8 @@ public class LinearRing extends GmlElement { ...@@ -135,31 +114,8 @@ public class LinearRing extends GmlElement {
* *
* @return the normal as a normalized vector * @return the normal as a normalized vector
*/ */
public Vector3d calculateNormalNormalized() { public UnitVector3d calculateNormalNormalized() {
double[] coords = new double[3]; return calculateNormal().normalize();
for (int i = 0; i < vertices.size() - 1; i++) {
Vertex current = vertices.get(i + 0);
Vertex next = vertices.get(i + 1);
coords[0] += (current.getZ() + next.getZ()) * (current.getY() - next.getY());
coords[1] += (current.getX() + next.getX()) * (current.getZ() - next.getZ());
coords[2] += (current.getY() + next.getY()) * (current.getX() - next.getX());
}
if (coords[0] == 0 && coords[1] == 0 && coords[2] == 0) {
// no valid normal vector found
if (vertices.size() < 3) {
// no three points, return x-axis
return new Vector3d(1, 0, 0);
}
Vertex v1 = vertices.get(0);
Vertex v2 = vertices.get(1);
Vertex v3 = vertices.get(2);
return calculateNormalWithCross(v1, v2, v3);
}
Vector3d v = new Vector3d(coords);
v.normalize();
return v;
} }
/** /**
...@@ -183,7 +139,7 @@ public class LinearRing extends GmlElement { ...@@ -183,7 +139,7 @@ public class LinearRing extends GmlElement {
// no valid normal vector found // no valid normal vector found
if (vertices.size() < 3) { if (vertices.size() < 3) {
// no three points, return x-axis // no three points, return x-axis
return new Vector3d(1, 0, 0); return UnitVector3d.X_AXIS;
} }
Vertex v1 = vertices.get(0); Vertex v1 = vertices.get(0);
...@@ -194,7 +150,7 @@ public class LinearRing extends GmlElement { ...@@ -194,7 +150,7 @@ public class LinearRing extends GmlElement {
return new Vector3d(coords); return new Vector3d(coords);
} }
private Vector3d calculateNormalWithCross(Vertex v1, Vertex v2, Vertex v3) { private UnitVector3d calculateNormalWithCross(Vertex v1, Vertex v2, Vertex v3) {
Vector3d dir1 = v2.minus(v1); Vector3d dir1 = v2.minus(v1);
Vector3d dir2 = v3.minus(v1); Vector3d dir2 = v3.minus(v1);
Vector3d cross = dir1.cross(dir2); Vector3d cross = dir1.cross(dir2);
......
...@@ -33,22 +33,18 @@ public class CovarianceMatrix { ...@@ -33,22 +33,18 @@ public class CovarianceMatrix {
} }
/** /**
* Calculates the covariance matrix of the given points, with the given expected * see {@link CovarianceMatrix#calculateCovarianceMatrix(List, double[])}
* values.
* *
* @param vertices the vertices for which the matrix is calculated * @param vertices the vertices for which the matrix is calculated
* @param expected the expected values * @param expected the expected values as a vector
* @return the covariance 3 x 3 matrix * @return the covariance 3 x 3 matrix
*/ */
public static double[][] calculateCovarianceMatrix(List<? extends Vector3d> vertices, double[] expected) { public static double[][] calculateCovarianceMatrix(List<? extends Vector3d> vertices, Vector3d expected) {
if (expected.length != 3) {
throw new IllegalArgumentException("for 3D points 3 expected values have to be provided");
}
double[][] covValues = new double[3][3]; double[][] covValues = new double[3][3];
for (Vector3d v : vertices) { for (Vector3d v : vertices) {
double xdiff = v.getX() - expected[0]; double xdiff = v.getX() - expected.getX();
double ydiff = v.getY() - expected[1]; double ydiff = v.getY() - expected.getY();
double zdiff = v.getZ() - expected[2]; double zdiff = v.getZ() - expected.getZ();
covValues[0][0] += xdiff * xdiff; covValues[0][0] += xdiff * xdiff;
covValues[0][1] += xdiff * ydiff; covValues[0][1] += xdiff * ydiff;
covValues[0][2] += xdiff * zdiff; covValues[0][2] += xdiff * zdiff;
...@@ -69,17 +65,6 @@ public class CovarianceMatrix { ...@@ -69,17 +65,6 @@ public class CovarianceMatrix {
return covValues; return covValues;
} }
/**
* see {@link CovarianceMatrix#calculateCovarianceMatrix(List, double[])}
*
* @param vertices the vertices for which the matrix is calculated
* @param expected the expected values as a vector
* @return the covariance 3 x 3 matrix
*/
public static double[][] calculateCovarianceMatrix(List<? extends Vector3d> vertices, Vector3d expected) {
return calculateCovarianceMatrix(vertices, expected.getCoordinates());
}
public static Vector3d getCentroid(List<? extends Vector3d> vertices) { public static Vector3d getCentroid(List<? extends Vector3d> vertices) {
if (vertices.isEmpty()) { if (vertices.isEmpty()) {
throw new IllegalArgumentException("Vertices may not be empty to calculate centroid"); throw new IllegalArgumentException("Vertices may not be empty to calculate centroid");
......
...@@ -45,16 +45,16 @@ public class MovedRing { ...@@ -45,16 +45,16 @@ public class MovedRing {
} }
return indRing; return indRing;
} }
private MovedRing() {
vertices = new ArrayList<>();
}
public LinearRing getOriginal() { public LinearRing getOriginal() {
return original; return original;
} }
public MovedRing() { private void addVertex(Vector3d v) {
vertices = new ArrayList<>();
}
public void addVertex(Vector3d v) {
vertices.add(v); vertices.add(v);
} }
...@@ -71,75 +71,10 @@ public class MovedRing { ...@@ -71,75 +71,10 @@ public class MovedRing {
*/ */
public boolean isPointInside(Vector3d v) { public boolean isPointInside(Vector3d v) {
// project to 2d ring // project to 2d ring
List<Vector2d> projectedRing = new ArrayList<>(); ProjectionAxis axis = ProjectionAxis.of(this);
Vector2d point; Ring2d projectedRing = Ring2d.of(this, axis);
Vector3d normal = calculateNormal(); Vector2d point = axis.project(v);
return projectedRing.containsPoint(point);
double x = Math.abs(normal.getX());
double y = Math.abs(normal.getY());
double z = Math.abs(normal.getZ());
if (x >= y && x >= z) {
for (Vector3d vert : vertices) {
Vector2d projCoords = new Vector2d(vert.getY(), vert.getZ());
projectedRing.add(projCoords);
}
point = new Vector2d(v.getY(), v.getZ());
} else if (y >= x && y >= z) {
for (Vector3d vert : vertices) {
Vector2d projCoords = new Vector2d(vert.getX(), vert.getZ());
projectedRing.add(projCoords);
}
point = new Vector2d(v.getX(), v.getZ());
} else {
for (Vector3d vert : vertices) {
Vector2d projCoords = new Vector2d(vert.getX(), vert.getY());
projectedRing.add(projCoords);
}
point = new Vector2d(v.getX(), v.getY());
}
int t = -1;
for (int i = 0; i < projectedRing.size() - 1; i++) {
t = t * crossProdTest(point, projectedRing.get(i), projectedRing.get(i + 1));
if (t == 0) {
return true;
}
}
return t >= 0;
}
private int crossProdTest(Vector2d a, Vector2d b, Vector2d c) {
if (a.getY() == b.getY() && a.getY() == c.getY()) {
if ((b.getX() <= a.getX() && a.getX() <= c.getX()) || (c.getX() <= a.getX() && a.getX() <= b.getX())) {
return 0;
} else {
return 1;
}
}
if (a.getY() == b.getY() && a.getX() == b.getX()) {
return 0;
}
if (b.getY() > c.getY()) {
Vector2d temp = b;
b = c;
c = temp;
}
if (a.getY() <= b.getY() || a.getY() > c.getY()) {
return 1;
}
return calculateDelta(a, b, c);
}
private int calculateDelta(Vector2d a, Vector2d b, Vector2d c) {
double delta = (b.getX() - a.getX()) * (c.getY() - a.getY()) - (b.getY() - a.getY()) * (c.getX() - a.getX());
if (delta > 0) {
return -1;
} else if (delta < 0) {
return 1;
} else {
return 0;
}
} }
/** /**
...@@ -149,37 +84,7 @@ public class MovedRing { ...@@ -149,37 +84,7 @@ public class MovedRing {
* *
* @return the normal as a normalized vector * @return the normal as a normalized vector
*/ */
public Vector3d calculateNormal() { public UnitVector3d calculateNormalNormalized() {
double[] coords = new double[3]; return original.calculateNormalNormalized();
for (int i = 0; i < vertices.size() - 1; i++) {
Vector3d current = vertices.get(i + 0);
Vector3d next = vertices.get(i + 1);
coords[0] += (current.getZ() + next.getZ()) * (current.getY() - next.getY());
coords[1] += (current.getX() + next.getX()) * (current.getZ() - next.getZ());
coords[2] += (current.getY() + next.getY()) * (current.getX() - next.getX());
}
if (coords[0] == 0 && coords[1] == 0 && coords[2] == 0) {
// no valid normal vector found
if (vertices.size() < 3) {
// no three points, return x-axis
return new Vector3d(1, 0, 0);
}
Vector3d v1 = vertices.get(0);
Vector3d v2 = vertices.get(1);
Vector3d v3 = vertices.get(2);
return calculateNormalWithCross(v1, v2, v3);
}
Vector3d v = new Vector3d(coords);
v.normalize();
return v;
}
private Vector3d calculateNormalWithCross(Vector3d v1, Vector3d v2, Vector3d v3) {
Vector3d dir1 = v2.minus(v1);
Vector3d dir2 = v3.minus(v1);
Vector3d cross = dir1.cross(dir2);
return cross.normalize();
} }
} }
...@@ -39,7 +39,7 @@ public class Plane implements Serializable { ...@@ -39,7 +39,7 @@ public class Plane implements Serializable {
private static final double EPSILON = 0.0001; private static final double EPSILON = 0.0001;
private Vector3d normal; private UnitVector3d normal;
private Vector3d point; private Vector3d point;
private double d; private double d;
...@@ -51,11 +51,10 @@ public class Plane implements Serializable { ...@@ -51,11 +51,10 @@ public class Plane implements Serializable {
*/ */
public Plane(Vector3d normal, Vector3d p) { public Plane(Vector3d normal, Vector3d p) {
point = p; point = p;
this.normal = normal.copy(); this.normal = normal.normalize();
this.normal.normalize();
d = this.normal.dot(point); d = this.normal.dot(point);
if (d < 0) { if (d < 0) {
this.normal = this.normal.mult(-1); this.normal = this.normal.invert();
d = -d; d = -d;
} }
} }
...@@ -138,7 +137,7 @@ public class Plane implements Serializable { ...@@ -138,7 +137,7 @@ public class Plane implements Serializable {
* *
* @return the normal vector of the plane * @return the normal vector of the plane
*/ */
public Vector3d getNormal() { public UnitVector3d getNormal() {
return normal; return normal;
} }
......
...@@ -24,7 +24,6 @@ import java.util.List; ...@@ -24,7 +24,6 @@ import java.util.List;
import de.hft.stuttgart.citydoctor2.datastructure.LinearRing; import de.hft.stuttgart.citydoctor2.datastructure.LinearRing;
import de.hft.stuttgart.citydoctor2.datastructure.Polygon; import de.hft.stuttgart.citydoctor2.datastructure.Polygon;
import de.hft.stuttgart.citydoctor2.datastructure.Vertex;
/** /**
* A two dimensional polygon. Has an 2d exterior ring and interior rings * A two dimensional polygon. Has an 2d exterior ring and interior rings
...@@ -38,81 +37,36 @@ public class Polygon2d { ...@@ -38,81 +37,36 @@ public class Polygon2d {
private List<Ring2d> innerRings; private List<Ring2d> innerRings;
public static Polygon2d withProjection(Polygon poly) { public static Polygon2d withProjection(Polygon poly) {
Vector3d normal = poly.calculateNormalNormalized(); ProjectionAxis axis = ProjectionAxis.of(poly);
int[] axis = getProjectionAxis(normal);
return projectTo2D(poly, axis); return projectTo2D(poly, axis);
} }
public static Polygon2d withProjection(MovedPolygon poly, int[] projectionAxis) { public static Polygon2d withProjection(MovedPolygon poly, ProjectionAxis projectionAxis) {
return projectTo2D(poly, projectionAxis); return projectTo2D(poly, projectionAxis);
} }
public static Polygon2d withProjection(Polygon poly, int[] projectionAxis) { public static Polygon2d withProjection(Polygon poly, ProjectionAxis projectionAxis) {
return projectTo2D(poly, projectionAxis); return projectTo2D(poly, projectionAxis);
} }
private static Polygon2d projectTo2D(Polygon p, int[] axis) { private static Polygon2d projectTo2D(Polygon p, ProjectionAxis axis) {
List<Ring2d> interior = new ArrayList<>(); List<Ring2d> interior = new ArrayList<>();
Ring2d exterior = projectRing(p.getExteriorRing(), axis); Ring2d exterior = Ring2d.of(p.getExteriorRing(), axis);
for (LinearRing innerRing : p.getInnerRings()) { for (LinearRing innerRing : p.getInnerRings()) {
interior.add(projectRing(innerRing, axis)); interior.add(Ring2d.of(innerRing, axis));
} }
return new Polygon2d(exterior, interior); return new Polygon2d(exterior, interior);
} }
private static Polygon2d projectTo2D(MovedPolygon p, int[] axis) { private static Polygon2d projectTo2D(MovedPolygon p, ProjectionAxis axis) {
List<Ring2d> interior = new ArrayList<>(); List<Ring2d> interior = new ArrayList<>();
Ring2d exterior = projectRing(p.getExteriorRing(), axis); Ring2d exterior = Ring2d.of(p.getExteriorRing(), axis);
for (MovedRing innerRing : p.getInnerRings()) { for (MovedRing innerRing : p.getInnerRings()) {
interior.add(projectRing(innerRing, axis)); interior.add(Ring2d.of(innerRing, axis));
} }
return new Polygon2d(exterior, interior); return new Polygon2d(exterior, interior);
} }
public static int[] getProjectionAxis(Vector3d normal) {
double nx = Math.abs(normal.getX());
double ny = Math.abs(normal.getY());
double nz = Math.abs(normal.getZ());
int[] axis;
if (nx >= ny && nx >= nz) {
axis = new int[] { 1, 2 };
} else if (ny >= nx && ny >= nz) {
axis = new int[] { 0, 2 };
} else {
axis = new int[] { 0, 1 };
}
return axis;
}
private static Ring2d projectRing(LinearRing r, int[] axis) {
List<Vector2d> projectedVertices = new ArrayList<>();
for (Vertex v : r.getVertices()) {
projectedVertices.add(new Vector2d(v.getCoordinate(axis[0]), v.getCoordinate(axis[1])));
}
return new Ring2d(projectedVertices, r);
}
private static Ring2d projectRing(MovedRing r, int[] axis) {
List<Vector2d> projectedVertices = new ArrayList<>();
for (Vector3d v : r.getVertices()) {
projectedVertices.add(new Vector2d(v.getCoordinate(axis[0]), v.getCoordinate(axis[1])));
}
return new Ring2d(projectedVertices, r.getOriginal());
}
public static Polygon2d withRotationMatrix(Polygon poly) {
Matrix3x3d rotMatrix = PolygonUtils.calculateRotationMatrix(poly);
LinearRing lr = poly.getExteriorRing();
Ring2d exterior = createRing2d(rotMatrix, lr);
List<Ring2d> innerRings = new ArrayList<>();
for (LinearRing innerRing : poly.getInnerRings()) {
innerRings.add(createRing2d(rotMatrix, innerRing));
}
return new Polygon2d(exterior, innerRings);
}
/** /**
* Converts a Polygon to a 2d polygon. This will change the area of the polygon. * Converts a Polygon to a 2d polygon. This will change the area of the polygon.
* *
...@@ -126,16 +80,6 @@ public class Polygon2d { ...@@ -126,16 +80,6 @@ public class Polygon2d {
this.innerRings = interior; this.innerRings = interior;
} }
private static Ring2d createRing2d(Matrix3x3d rotMatrix, LinearRing lr) {
List<Vector2d> ringVertices = new ArrayList<>();
for (Vertex v : lr.getVertices()) {
Vector3d rotated = rotMatrix.mult(v);
Vector2d v2d = new Vector2d(rotated.getX(), rotated.getY());
ringVertices.add(v2d);
}
return new Ring2d(ringVertices, lr);
}
public Ring2d getExterior() { public Ring2d getExterior() {
return exterior; return exterior;
} }
......
/*-
* Copyright 2020 Beuth Hochschule für Technik Berlin, Hochschule für Technik Stuttgart