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

reworked handling of neighbor vertices, now replaced by the other vertex

parent d12c7d39
Pipeline #2448 passed with stage
in 3 minutes and 28 seconds
......@@ -67,18 +67,18 @@ public class Edge implements Serializable {
numberOfOppositeHalfEdges++;
return;
}
throw new IllegalStateException("The given vertices do not from this edge");
throw new IllegalStateException("The given vertices do not form this edge\n v0=" + v0 + ", v1=" + v1 + ", edge" + this);
}
private boolean isPointOfEdge(Vertex v0, Vertex edgePoint) {
if (v0.equals(edgePoint)) {
return true;
}
for (Vertex v : v0.getNeighbors()) {
if (v.equals(edgePoint)) {
return true;
}
}
// for (Vertex v : v0.getNeighbors()) {
// if (v.equals(edgePoint)) {
// return true;
// }
// }
return false;
}
......
......@@ -145,24 +145,24 @@ public class Geometry extends GmlElement {
Edge oppositeEdge = new Edge(v1, v0);
duplicacyMap.put(tempEdge, tempEdge);
duplicacyMap.put(oppositeEdge, tempEdge);
for (Vertex v0Neighbor : v0.getNeighbors()) {
Edge alternativeEdge = new Edge(v0Neighbor, v1);
Edge oppositeAlternativeEdge = new Edge(v1, v0Neighbor);
duplicacyMap.put(alternativeEdge, tempEdge);
duplicacyMap.put(oppositeAlternativeEdge, tempEdge);
for (Vertex v1Neighbor : v1.getNeighbors()) {
alternativeEdge = new Edge(v0Neighbor, v1Neighbor);
oppositeAlternativeEdge = new Edge(v1Neighbor, v0Neighbor);
duplicacyMap.put(alternativeEdge, tempEdge);
duplicacyMap.put(oppositeAlternativeEdge, tempEdge);
}
}
for (Vertex v : v1.getNeighbors()) {
Edge alternativeEdge = new Edge(v0, v);
Edge oppositeAlternativeEdge = new Edge(v, v0);
duplicacyMap.put(alternativeEdge, tempEdge);
duplicacyMap.put(oppositeAlternativeEdge, tempEdge);
}
// for (Vertex v0Neighbor : v0.getNeighbors()) {
// Edge alternativeEdge = new Edge(v0Neighbor, v1);
// Edge oppositeAlternativeEdge = new Edge(v1, v0Neighbor);
// duplicacyMap.put(alternativeEdge, tempEdge);
// duplicacyMap.put(oppositeAlternativeEdge, tempEdge);
// for (Vertex v1Neighbor : v1.getNeighbors()) {
// alternativeEdge = new Edge(v0Neighbor, v1Neighbor);
// oppositeAlternativeEdge = new Edge(v1Neighbor, v0Neighbor);
// duplicacyMap.put(alternativeEdge, tempEdge);
// duplicacyMap.put(oppositeAlternativeEdge, tempEdge);
// }
// }
// for (Vertex v : v1.getNeighbors()) {
// Edge alternativeEdge = new Edge(v0, v);
// Edge oppositeAlternativeEdge = new Edge(v, v0);
// duplicacyMap.put(alternativeEdge, tempEdge);
// duplicacyMap.put(oppositeAlternativeEdge, tempEdge);
// }
e = tempEdge;
edges.add(e);
edgeMap.put(new SerializablePair<>(v0, v1), e);
......@@ -277,10 +277,6 @@ public class Geometry extends GmlElement {
return vertices;
}
public void setVertices(List<Vertex> vertices) {
this.vertices = vertices;
}
public List<Edge> getEdges() {
return edges;
}
......@@ -300,24 +296,24 @@ public class Geometry extends GmlElement {
if (edge != null) {
return edge;
}
for (Vertex neighborV1 : v1.getNeighbors()) {
edge = edgeMap.get(new SerializablePair<>(neighborV1, v2));
if (edge != null) {
return edge;
}
for (Vertex neighborV2 : v2.getNeighbors()) {
edge = edgeMap.get(new SerializablePair<>(neighborV1, neighborV2));
if (edge != null) {
return edge;
}
}
}
for (Vertex neighborV2 : v2.getNeighbors()) {
edge = edgeMap.get(new SerializablePair<>(neighborV2, v1));
if (edge != null) {
return edge;
}
}
// for (Vertex neighborV1 : v1.getNeighbors()) {
// edge = edgeMap.get(new SerializablePair<>(neighborV1, v2));
// if (edge != null) {
// return edge;
// }
// for (Vertex neighborV2 : v2.getNeighbors()) {
// edge = edgeMap.get(new SerializablePair<>(neighborV1, neighborV2));
// if (edge != null) {
// return edge;
// }
// }
// }
// for (Vertex neighborV2 : v2.getNeighbors()) {
// edge = edgeMap.get(new SerializablePair<>(neighborV2, v1));
// if (edge != null) {
// return edge;
// }
// }
return null;
}
......
......@@ -216,6 +216,14 @@ public class LinearRing extends GmlElement {
}
v.addAdjacentRing(this, parent.getParent());
}
public void setVertex(int i, Vertex v) {
vertices.set(i, v);
if (parent.isLinkedTo()) {
v.addAdjacentRing(this, parent.getLinkedFromPolygon().getParent());
}
v.addAdjacentRing(this, parent.getParent());
}
@Override
public String toString() {
......
......@@ -19,7 +19,6 @@
package de.hft.stuttgart.citydoctor2.datastructure;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
......@@ -39,8 +38,6 @@ public class Vertex extends Vector3d {
private List<SerializablePair<Geometry, HashSet<LinearRing>>> adjacentRings = new ArrayList<>(2);
private List<Vertex> neighbors;
public Vertex(double x, double y, double z) {
super(x, y, z);
}
......@@ -49,21 +46,7 @@ public class Vertex extends Vector3d {
super(vec);
}
public void addNeighbor(Vertex vec) {
if (neighbors == null) {
neighbors = new ArrayList<>(1);
}
neighbors.add(vec);
}
public List<Vertex> getNeighbors() {
if (neighbors == null) {
return Collections.emptyList();
}
return neighbors;
}
private Set<LinearRing> getAdjacentRingsWithoutNeightbor(Geometry geom) {
private Set<LinearRing> getAdjacentRingsWithoutNeighbor(Geometry geom) {
for (SerializablePair<Geometry, HashSet<LinearRing>> adjacency : adjacentRings) {
if (adjacency.getValue0() == geom) {
return adjacency.getValue1();
......@@ -73,24 +56,7 @@ public class Vertex extends Vector3d {
}
public Set<LinearRing> getAdjacentRings(Geometry geom) {
if (adjacentRings == null) {
return Collections.emptySet();
}
for (SerializablePair<Geometry, HashSet<LinearRing>> adjacency : adjacentRings) {
if (adjacency.getValue0() == geom) {
if (neighbors == null || neighbors.isEmpty()) {
return adjacency.getValue1();
} else {
Set<LinearRing> linearRings = new HashSet<>();
linearRings.addAll(adjacency.getValue1());
for (Vertex neighbor : neighbors) {
linearRings.addAll(neighbor.getAdjacentRingsWithoutNeightbor(geom));
}
return linearRings;
}
}
}
throw new IllegalStateException("Requested adjacent rings with Geometry not containing this vertex");
return getAdjacentRingsWithoutNeighbor(geom);
}
void addAdjacentRing(LinearRing ring, Geometry geom) {
......@@ -128,24 +94,7 @@ public class Vertex extends Vector3d {
}
public Set<Polygon> getAdjacentPolygons(Geometry geom) {
if (adjacentRings == null) {
return Collections.emptySet();
}
for (SerializablePair<Geometry, HashSet<LinearRing>> adjecency : adjacentRings) {
if (adjecency.getValue0() == geom) {
Set<Polygon> polygons = new HashSet<>();
for (LinearRing lr : adjecency.getValue1()) {
polygons.add(lr.getParent());
}
if (neighbors != null && !neighbors.isEmpty()) {
for (Vertex neighbor : neighbors) {
polygons.addAll(neighbor.getAdjacentPolygonsWithoutNeighbor(geom));
}
}
return polygons;
}
}
throw new IllegalStateException("Requested adjacent polygons with Geometry not containing this vertex");
return getAdjacentPolygonsWithoutNeighbor(geom);
}
@Override
......@@ -182,34 +131,6 @@ public class Vertex extends Vector3d {
findAdjacentRingsForGeometry(geom).remove(lr);
}
public boolean equalsWithNeighbors(Vertex other) {
if (this.equals(other)) {
return true;
}
for (Vertex v : other.getNeighbors()) {
if (this.equals(v)) {
return true;
}
}
return checkNeighbors(other);
}
private boolean checkNeighbors(Vertex other) {
if (neighbors != null) {
for (Vertex v : neighbors) {
if (v.equals(other)) {
return true;
}
for (Vertex otherNeighbor : other.getNeighbors()) {
if (otherNeighbor.equals(v)) {
return true;
}
}
}
}
return false;
}
/**
* Remove all adjacent rings from this vertex, ignoring geometry association
*/
......
......@@ -67,10 +67,12 @@ import de.hft.stuttgart.citydoctor2.datastructure.Geometry;
import de.hft.stuttgart.citydoctor2.datastructure.GeometryType;
import de.hft.stuttgart.citydoctor2.datastructure.GmlId;
import de.hft.stuttgart.citydoctor2.datastructure.LandObject;
import de.hft.stuttgart.citydoctor2.datastructure.LinearRing;
import de.hft.stuttgart.citydoctor2.datastructure.LinkedPolygon;
import de.hft.stuttgart.citydoctor2.datastructure.Lod;
import de.hft.stuttgart.citydoctor2.datastructure.Opening;
import de.hft.stuttgart.citydoctor2.datastructure.OpeningType;
import de.hft.stuttgart.citydoctor2.datastructure.Polygon;
import de.hft.stuttgart.citydoctor2.datastructure.SurfaceFeatureType;
import de.hft.stuttgart.citydoctor2.datastructure.TransportationObject;
import de.hft.stuttgart.citydoctor2.datastructure.TransportationObject.TransportationType;
......@@ -154,30 +156,38 @@ public class FeatureMapper extends FeatureWalker {
}
private void updateEdgesAndVertices(CityObject co) {
// searching for neighboring vertices, replacing them with one single vertex to
// avoid later problems with edges and manifold problems
for (Geometry geom : co.getGeometries()) {
geom.updateVertices();
KDTree tree = new KDTree();
for (Vertex v : geom.getVertices()) {
tree.add(v);
}
for (Vertex v : geom.getVertices()) {
List<Vertex> nodesInRange = tree.getNodesInRange(v, neighborDistance);
for (Vertex neighbor : nodesInRange) {
if (neighbor == v) {
continue;
}
v.addNeighbor(neighbor);
for (Polygon poly : geom.getPolygons()) {
LinearRing lr = poly.getExteriorRing();
updateRing(tree, lr);
for (LinearRing innerRing : poly.getInnerRings()) {
updateRing(tree, innerRing);
}
}
if (config.useLowMemoryConsumption()) {
// do not create edges and vertices
// vertices were already created because they were needed for the kd tree
// remove them again
geom.clearMetaInformation();
if (!config.useLowMemoryConsumption()) {
// no low memory consumption mode meaning create all meta information in geometry
geom.updateEdgesAndVertices();
}
}
}
private void updateRing(KDTree tree, LinearRing lr) {
for (int i = 0; i < lr.getVertices().size(); i++) {
Vertex v = lr.getVertices().get(i);
List<Vertex> nodesInRange = tree.getNodesInRange(v, neighborDistance);
if (nodesInRange.isEmpty()) {
tree.add(v);
} else {
// create edges
geom.updateEdges();
if (nodesInRange.size() != 1) {
throw new IllegalStateException(
"Found more than one vertex in range of " + v + " this should never happen here");
}
// replace other vertex with neighboring one
Vertex original = nodesInRange.get(0);
lr.setVertex(i, original);
}
}
}
......
......@@ -23,13 +23,26 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.util.ArrayList;
import java.util.List;
import org.citygml4j.factory.GMLGeometryFactory;
import org.citygml4j.model.citygml.building.AbstractBoundarySurface;
import org.citygml4j.model.citygml.building.WallSurface;
import org.junit.Test;
import de.hft.stuttgart.citydoctor2.check.Check;
import de.hft.stuttgart.citydoctor2.check.CheckError;
import de.hft.stuttgart.citydoctor2.check.CheckId;
import de.hft.stuttgart.citydoctor2.check.CheckResult;
import de.hft.stuttgart.citydoctor2.check.ResultStatus;
import de.hft.stuttgart.citydoctor2.datastructure.LinearRing.LinearRingType;
import de.hft.stuttgart.citydoctor2.math.Vector3d;
import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration;
/**
......@@ -42,24 +55,24 @@ public class GeometryTest {
@Test
public void testCreate() {
Geometry geom = new Geometry(GeometryType.SOLID, Lod.LOD0);
assertNotNull(geom);
assertSame(GeometryType.SOLID, geom.getType());
assertSame(Lod.LOD0, geom.getLod());
}
@Test
public void testAddPolygon() {
Geometry geom = new Geometry(GeometryType.SOLID, Lod.LOD0);
Polygon p = new ConcretePolygon();
geom.addPolygon(p);
assertEquals(1, geom.getPolygons().size());
assertSame(geom, p.getParent());
assertSame(geom.getPolygons().get(0), p);
}
@Test
public void testRemovePolygon() {
ParserConfiguration config = new ParserConfiguration(4, false);
......@@ -74,22 +87,22 @@ public class GeometryTest {
LinearRing lr = new LinearRing(LinearRingType.EXTERIOR);
p.setExteriorRing(lr);
lr.addVertex(new Vertex(0, 0, 0));
geom.addPolygon(p);
p.setPartOfSurface(bs);
p.setPartOfInstallation(bi);
geom.removePolygon(p);
assertEquals(0, geom.getPolygons().size());
bs.reCreateGeometries(new GMLGeometryFactory(), config);
assertNull(abs.getLod2MultiSurface());
bi.reCreateGeometries(new GMLGeometryFactory(), config);
assertNull(gmlBi.getLod2Geometry());
}
@Test
public void testReplacePolygon() {
ParserConfiguration config = new ParserConfiguration(4, false);
......@@ -108,28 +121,27 @@ public class GeometryTest {
p.setPartOfSurface(bs);
p.setPartOfInstallation(bi);
bs.addGeometry(geom2);
Geometry geom = new Geometry(GeometryType.SOLID, Lod.LOD2);
Polygon linkedPoly = new LinkedPolygon(p, geom);
geom.addPolygon(linkedPoly);
ConcretePolygon p2 = new ConcretePolygon();
p2.setExteriorRing(lr);
ConcretePolygon p3 = new ConcretePolygon();
p3.setExteriorRing(lr);
geom.replacePolygon(linkedPoly, p2, p3);
assertEquals(2, geom.getPolygons().size());
assertEquals(2, geom2.getPolygons().size());
bi.reCreateGeometries(new GMLGeometryFactory(), config);
assertNull(gmlBi.getLod2Geometry());
assertNull(gmlBi.getLod3Geometry());
assertNull(gmlBi.getLod4Geometry());
bs.reCreateGeometries(new GMLGeometryFactory(), config);
assertNotNull(abs.getLod2MultiSurface());
assertNotNull(abs.getLod2MultiSurface().getMultiSurface());
......@@ -139,4 +151,133 @@ public class GeometryTest {
assertNull(gmlBi.getLod2Geometry());
}
@Test
public void testSetParent() {
Geometry geom = new Geometry(GeometryType.MULTI_SURFACE, Lod.LOD2);
CityObject co = mock(CityObject.class);
geom.setParent(co);
assertEquals(co, geom.getParent());
}
@Test
public void testUpdateEdges() {
Geometry geom = GeometryTestUtils.createDummyGeometryWithInnerRingWithNeighboringPolygon(GeometryType.SOLID,
Lod.LOD2);
geom.clearMetaInformation();
assertNull(geom.getEdges());
geom.updateEdges();
List<Edge> edges = geom.getEdges();
assertNotNull(edges);
assertFalse(edges.isEmpty());
assertEquals(10, edges.size());
}
@Test
public void testSetType() {
Geometry geom = new Geometry(GeometryType.MULTI_SURFACE, Lod.LOD2);
geom.setType(GeometryType.SOLID);
assertEquals(GeometryType.SOLID, geom.getType());
}
@Test
public void testGetCenter() {
Geometry geom = GeometryTestUtils.createDummyGeometry(GeometryType.SOLID);
Vector3d center = geom.getCenter();
assertEquals(427583.3025, center.getX(), 0.000001);
assertEquals(6003502.5725, center.getY(), 0.000001);
assertEquals(6.905, center.getZ(), 0.000001);
}
@Test
public void testContainsError() {
Geometry geom = new Geometry(GeometryType.SOLID, Lod.LOD1);
assertFalse(geom.containsError(CheckId.C_GE_P_HOLE_OUTSIDE));
geom.addCheckResult(
new CheckResult(CheckId.C_GE_P_HOLE_OUTSIDE, ResultStatus.ERROR, mock(CheckError.class)));
assertTrue(geom.containsError(CheckId.C_GE_P_HOLE_OUTSIDE));
ConcretePolygon p = new ConcretePolygon();
p.setExteriorRing(mock(LinearRing.class));
geom.addPolygon(p);
assertFalse(geom.containsError(CheckId.C_GE_P_INNER_RINGS_NESTED));
p.addCheckResult(
new CheckResult(CheckId.C_GE_P_INNER_RINGS_NESTED, ResultStatus.ERROR, mock(CheckError.class)));
assertTrue(geom.containsError(CheckId.C_GE_P_INNER_RINGS_NESTED));
}
@Test
public void testClearAllContainedCheckResults() {
Geometry geom = new Geometry(GeometryType.SOLID, Lod.LOD1);
assertFalse(geom.containsError(CheckId.C_GE_P_HOLE_OUTSIDE));
geom.addCheckResult(
new CheckResult(CheckId.C_GE_P_HOLE_OUTSIDE, ResultStatus.ERROR, mock(CheckError.class)));
assertTrue(geom.containsError(CheckId.C_GE_P_HOLE_OUTSIDE));
Polygon p = mock(Polygon.class);
geom.addPolygon(p);
geom.clearAllContainedCheckResults();
verify(p).clearAllContainedCheckResults();
assertFalse(geom.containsError(CheckId.C_GE_P_HOLE_OUTSIDE));
}
@Test
public void testCollectContainedErrors() {
Geometry geom = new Geometry(GeometryType.SOLID, Lod.LOD1);
assertFalse(geom.containsError(CheckId.C_GE_P_HOLE_OUTSIDE));
geom.addCheckResult(
new CheckResult(CheckId.C_GE_P_HOLE_OUTSIDE, ResultStatus.ERROR, mock(CheckError.class)));
assertTrue(geom.containsError(CheckId.C_GE_P_HOLE_OUTSIDE));
Polygon p = mock(Polygon.class);
geom.addPolygon(p);
List<CheckError> errors = new ArrayList<>();
geom.collectContainedErrors(errors);
verify(p).collectContainedErrors(errors);
assertEquals(1, errors.size());
}
@Test
public void testContainsAnyError() {
Geometry geom = new Geometry(GeometryType.SOLID, Lod.LOD1);
assertFalse(geom.containsAnyError());
geom.addCheckResult(
new CheckResult(CheckId.C_GE_P_HOLE_OUTSIDE, ResultStatus.ERROR, mock(CheckError.class)));
assertTrue(geom.containsAnyError());
Polygon p = mock(Polygon.class);
geom.addPolygon(p);
geom.clearAllContainedCheckResults();