Commit 97a65114 authored by Riegel's avatar Riegel
Browse files

Merge branch 'dev' into 'master'

Version 3.15.0

See merge request !8
parents 99c8f6a8 5950ea5f
Pipeline #10106 passed with stage
in 3 minutes and 15 seconds
package de.hft.stuttgart.citydoctor2.healing;
import java.util.Collections;
import java.util.List;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import de.hft.stuttgart.citydoctor2.check.HealingID;
import de.hft.stuttgart.citydoctor2.check.HealingMethod;
import de.hft.stuttgart.citydoctor2.check.ModificationListener;
import de.hft.stuttgart.citydoctor2.check.error.PolygonSameOrientationError;
import de.hft.stuttgart.citydoctor2.datastructure.Vertex;
public class HealSameOrientationError implements HealingMethod {
private static final Logger logger = LogManager.getLogger(HealSameOrientationError.class);
@Override
public boolean visit(PolygonSameOrientationError err, ModificationListener l) {
logger.debug("Executing Repair for PolygonSameOrientationError");
List<Vertex> vertices = err.getInnerRing().getVertices();
Collections.reverse(vertices);
return true;
}
@Override
public HealSameOrientationError createNew() {
return new HealSameOrientationError();
}
@Override
public HealingID getID() {
return HealingID.P_SAME_ORIENTATION;
}
}
package de.hft.stuttgart.citydoctor2.healing;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import de.hft.stuttgart.citydoctor2.check.HealingID;
import de.hft.stuttgart.citydoctor2.check.HealingMethod;
import de.hft.stuttgart.citydoctor2.check.ModificationListener;
import de.hft.stuttgart.citydoctor2.check.error.SolidNotClosedError;
import de.hft.stuttgart.citydoctor2.connect.edge.CppFeature;
import de.hft.stuttgart.citydoctor2.connect.edge.CppHealResult;
import de.hft.stuttgart.citydoctor2.connect.edge.CppPolygonHealing;
import de.hft.stuttgart.citydoctor2.datastructure.Geometry;
public class HealSolidNotClosedCpp implements HealingMethod {
private static final Logger logger = LogManager.getLogger(HealSolidNotClosedCpp.class);
@Override
public HealingMethod createNew() {
return new HealSolidNotClosedCpp();
}
@Override
public boolean visit(SolidNotClosedError err, ModificationListener l) {
logger.debug("Executing Repair for PolygonSameOrientationError");
// Wenn auf CPP Seite implementiert dann das hier entfernen:
if (HealSolidNotClosedError.fixVerticesCloseToEdges(err)) {
// maybe errors are fixed don't try other fixes until next iteration
return true;
}
// Bis hier
// ----------------------------------------------
// get Geometry and Geometry informations
// ----------------------------------------------
Geometry geometry = err.getGeometry();
String gmlId_string = geometry.getParent().getGmlId().toString();
// ----------------------------------------------
// create feature and fill feature with geometry
// ----------------------------------------------
CppFeature feature = new CppFeature( gmlId_string);
// MeshSurface surface = MeshSurface.of(geometry);
// DebugUtils.printPolygon3d(surface.getPolygons().toArray(new CDPolygonNs[0]));
// DebugUtils.printGeoknechtPolygon(surface.getPolygons().toArray(new CDPolygonNs[0]));
feature.setGeometry( geometry );
feature.setLoD(geometry.getLod());
// ----------------------------------------------
// start healing method
// ----------------------------------------------
CppPolygonHealing cppPolygonHealing = new CppPolygonHealing(feature);
cppPolygonHealing.createCppObject();
CppHealResult healResult = cppPolygonHealing.healSolidNotClosed();
if(healResult.isEmpty())
return false;
healResult.mergeIntoGeometry(geometry);
// ----------------------------------------------
// dispose cpp Objects
// ----------------------------------------------
cppPolygonHealing.disposeCppObject();
feature.disposeCppObject();
return true;
}
@Override
public HealingID getID() {
return HealingID.S_NOT_CLOSED_CPP;
}
}
package de.hft.stuttgart.citydoctor2.healing;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import de.hft.stuttgart.citydoctor2.check.HealingID;
import de.hft.stuttgart.citydoctor2.check.HealingMethod;
import de.hft.stuttgart.citydoctor2.check.ModificationListener;
import de.hft.stuttgart.citydoctor2.check.error.SolidNotClosedError;
import de.hft.stuttgart.citydoctor2.datastructure.ConcretePolygon;
import de.hft.stuttgart.citydoctor2.datastructure.Edge;
import de.hft.stuttgart.citydoctor2.datastructure.Geometry;
import de.hft.stuttgart.citydoctor2.datastructure.LinearRing;
import de.hft.stuttgart.citydoctor2.datastructure.LinearRing.LinearRingType;
import de.hft.stuttgart.citydoctor2.datastructure.Polygon;
import de.hft.stuttgart.citydoctor2.datastructure.Vertex;
import de.hft.stuttgart.citydoctor2.healing.math.EdgeGraph;
import de.hft.stuttgart.citydoctor2.math.Plane;
import de.hft.stuttgart.citydoctor2.math.Segment3d;
import de.hft.stuttgart.citydoctor2.math.Vector3d;
public class HealSolidNotClosedError implements HealingMethod {
private static final Logger logger = LogManager.getLogger(HealSolidNotClosedError.class);
private static double epsilon = 0.1;
@Override
public boolean visit(SolidNotClosedError err, ModificationListener l) {
logger.debug("Executing Repair for SolidNotClosedError");
if (fixVerticesCloseToEdges(err)) {
// maybe errors are fixed don't try other fixes until next iteration
return true;
}
return fixMissingPolygons(err);
}
private boolean fixMissingPolygons(SolidNotClosedError err) {
if (err.getErrorEdges().size() <= 1) {
// what to do with only one edge? Impossible?
logger.error("{} only has one error edge, cannot fix", err.getGeometry());
return false;
}
List<LinkedList<Edge>> candidatesForPolygon = new ArrayList<>();
for (Edge e0 : err.getErrorEdges()) {
for (Edge e1 : err.getErrorEdges()) {
if (e1 == e0) {
// don't check same edge
continue;
}
Vertex v0 = e0.getConnectionPoint(e1);
if (v0 != null) {
// connected edges
Vector3d ab = getVectorFromPoint(e0, v0);
Vector3d ac = getVectorFromPoint(e1, v0);
Vector3d norm = ab.cross(ac);
Plane plane = new Plane(norm, v0);
LinkedList<Edge> connectedEdges = new LinkedList<>();
connectedEdges.add(e0);
connectedEdges.add(e1);
// collect all other edges which are in the same plane and connected
collectEdgesConnectedAndInPlane(err, e0, e1, plane, connectedEdges);
candidatesForPolygon.add(connectedEdges);
}
}
}
// build a polygon for the side where the most edges are available
if (candidatesForPolygon.isEmpty()) {
return false;
}
Collections.sort(candidatesForPolygon, (o1, o2) -> o2.size() - o1.size());
LinkedList<Edge> candidate = candidatesForPolygon.get(0);
// build a new polygon out of the connected edges
buildPolygonFromEdges(err.getGeometry(), candidate);
// have added a polygon, don't try to add more in this iteration
return true;
}
private void buildPolygonFromEdges(Geometry geom, LinkedList<Edge> connectedEdges) {
Polygon p = new ConcretePolygon();
geom.addPolygon(p);
LinearRing ext = new LinearRing(LinearRingType.EXTERIOR);
p.setExteriorRing(ext);
// edges form a loop?
EdgeGraph graph = new EdgeGraph();
for (Edge e : connectedEdges) {
graph.addEdge(e, connectedEdges);
}
List<List<Edge>> cycles = graph.getCycles();
// edges form a loop when nr edges >= nr vertices
if (!cycles.isEmpty()) {
// loop
createRingFromLoop(cycles.get(0), ext);
} else {
// no cycle means open ring
createRingFromNotClosedEdges(connectedEdges, ext);
}
}
private void createRingFromNotClosedEdges(List<Edge> connectedEdges, LinearRing ext) {
Edge firstEdge = connectedEdges.get(0);
connectedEdges.remove(0);
ext.addVertex(firstEdge.getFrom());
ext.addVertex(firstEdge.getTo());
Vertex currentVertex = firstEdge.getTo();
boolean insertAtEnd = true;
while (!connectedEdges.isEmpty()) {
boolean addedEdge = false;
for (Edge e : connectedEdges) {
Vertex oppositeV = e.getOppositeVertex(currentVertex);
if (oppositeV != null) {
// found a connected edge
// insert point depending where the edge is connected
insertPointIntoRing(ext, insertAtEnd, oppositeV);
currentVertex = oppositeV;
connectedEdges.remove(e);
addedEdge = true;
break;
}
}
if (!addedEdge) {
if (!insertAtEnd) {
// could not add more edges to lr, stop here
// close ring
ext.addVertex(ext.getVertices().get(0));
return;
}
// no more edges in this direction, go the other direction
insertAtEnd = false;
currentVertex = firstEdge.getFrom();
}
}
// close ring
ext.addVertex(ext.getVertices().get(0));
}
private void insertPointIntoRing(LinearRing ext, boolean insertAtEnd, Vertex oppositeV) {
if (insertAtEnd) {
ext.addVertex(oppositeV);
} else {
// insert at the beginning
ext.addVertex(0, oppositeV);
}
}
private void createRingFromLoop(List<Edge> connectedEdges, LinearRing ext) {
Edge firstEdge = connectedEdges.get(0);
connectedEdges.remove(0);
ext.addVertex(firstEdge.getFrom());
ext.addVertex(firstEdge.getTo());
Vertex currentVertex = firstEdge.getTo();
while (!connectedEdges.isEmpty()) {
boolean addedEdge = false;
for (Edge e : connectedEdges) {
Vertex oppositeV = e.getOppositeVertex(currentVertex);
if (oppositeV != null) {
ext.addVertex(oppositeV);
currentVertex = oppositeV;
connectedEdges.remove(e);
addedEdge = true;
break;
}
}
if (!addedEdge) {
return;
}
}
}
private void collectEdgesConnectedAndInPlane(SolidNotClosedError err, Edge e0, Edge e1, Plane plane,
LinkedList<Edge> connectedEdges) {
for (Edge e2 : err.getErrorEdges()) {
if (e2 == e0 || e2 == e1) {
// don't check the starting edges
continue;
}
boolean connected = isConnectedToEdges(connectedEdges, e2);
if (connected && plane.getDistance(e2.getTo()) < epsilon
&& plane.getDistance(e2.getFrom()) < epsilon) {
// edge is in plane and connected
connectedEdges.add(e2);
}
}
}
private boolean isConnectedToEdges(List<Edge> connectedEdges, Edge e2) {
for (Edge planeEdge : connectedEdges) {
if (planeEdge.getConnectionPoint(e2) != null) {
return true;
}
}
return false;
}
private Vector3d getVectorFromPoint(Edge e0, Vertex v0) {
Vector3d ab;
if (v0 == e0.getTo()) {
ab = e0.getFrom().minus(v0);
} else {
ab = e0.getTo().minus(v0);
}
return ab;
}
public static boolean fixVerticesCloseToEdges(SolidNotClosedError err) {
boolean changed = false;
Geometry geom = err.getGeometry();
for (Edge e : err.getErrorEdges()) {
Segment3d seg = new Segment3d(e.getFrom(), e.getTo());
for (Vertex v : geom.getVertices()) {
if (v == e.getFrom() || v == e.getTo()) {
continue;
}
// check if there is an edge adjacent to the vertex that goes in the same
// direction
if (seg.getDistance(v) < epsilon && doParallelEdgesExist(geom, seg, v)) {
addVertexToEdge(e, v);
changed = true;
}
}
}
return changed;
}
private static boolean doParallelEdgesExist(Geometry geom, Segment3d seg, Vertex v) {
Vector3d dir = seg.getPointB().minus(seg.getPointA());
dir = dir.normalize();
for (Edge e2 : geom.getEdgesAdjacentTo(v)) {
Vector3d dir2 = e2.getTo().minus(e2.getFrom());
dir2 = dir2.normalize();
if (Math.abs(dir2.dot(dir)) > 0.99) {
// at least one edge is parallel
return true;
}
}
return false;
}
private static void addVertexToEdge(Edge e, Vertex v) {
for (LinearRing lr : e.getAdjacentRings()) {
for (int i = 0; i < lr.getVertices().size() - 1; i++) {
Vertex v1 = lr.getVertices().get(i);
Vertex v2 = lr.getVertices().get(i + 1);
if (e.formedByIgnoreDirection(v1, v2)) {
lr.addVertex(i + 1, v);
break;
}
}
}
}
@Override
public HealSolidNotClosedError createNew() {
return new HealSolidNotClosedError();
}
@Override
public HealingID getID() {
return HealingID.S_NOT_CLOSED;
}
}
package de.hft.stuttgart.citydoctor2.healing;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import de.hft.stuttgart.citydoctor2.check.HealingID;
import de.hft.stuttgart.citydoctor2.check.HealingMethod;
import de.hft.stuttgart.citydoctor2.check.ModificationListener;
import de.hft.stuttgart.citydoctor2.check.error.RingTooFewPointsError;
import de.hft.stuttgart.citydoctor2.datastructure.LinearRing;
import de.hft.stuttgart.citydoctor2.datastructure.LinearRing.LinearRingType;
public class HealTooFewPoints implements HealingMethod {
private static final Logger logger = LogManager.getLogger(HealTooFewPoints.class);
@Override
public boolean visit(RingTooFewPointsError err, ModificationListener l) {
logger.debug("Executing Repair for RingTooFewPointsError");
LinearRing ring = err.getRing();
// ring is only a line, remove ring
if (ring.getType() == LinearRingType.INTERIOR) {
ring.getParent().removeInnerRing(ring);
} else {
// remove whole polygon
ring.getParent().remove();
}
return true;
}
@Override
public HealTooFewPoints createNew() {
return new HealTooFewPoints();
}
@Override
public HealingID getID() {
return HealingID.R_TOO_FEW_POINTS;
}
}
package de.hft.stuttgart.citydoctor2.healing;
import java.util.List;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import de.hft.stuttgart.citydoctor2.check.HealingID;
import de.hft.stuttgart.citydoctor2.check.HealingMethod;
import de.hft.stuttgart.citydoctor2.check.ModificationListener;
import de.hft.stuttgart.citydoctor2.check.error.MultipleConnectedComponentsError;
import de.hft.stuttgart.citydoctor2.datastructure.LinearRing;
import de.hft.stuttgart.citydoctor2.datastructure.LinearRing.LinearRingType;
import de.hft.stuttgart.citydoctor2.datastructure.Polygon;
import de.hft.stuttgart.citydoctor2.datastructure.Vertex;
import de.hft.stuttgart.citydoctor2.math.Plane;
import de.hft.stuttgart.citydoctor2.math.Vector3d;
public class HealWrongDormers implements HealingMethod {
private static final Logger logger = LogManager.getLogger(HealWrongDormers.class);
private static final double EPSILON = 0.2;
@Override
public boolean visit(MultipleConnectedComponentsError err, ModificationListener l) {
logger.debug("Executing Repair for MultipleConnectedComponentsError");
for (int i = 0; i < err.getComponents().size() - 1; i++) {
List<Polygon> component1 = err.getComponents().get(i);
for (int j = i + 1; j < err.getComponents().size(); j++) {
List<Polygon> component2 = err.getComponents().get(j);
if (checkForOverlappingPolygons(component1, component2)) {
return true;
}
}
}
return false;
}
private boolean checkForOverlappingPolygons(List<Polygon> component1,
List<Polygon> component2) {
for (Polygon p1 : component1) {
for (Polygon p2 : component2) {
if (isPolygonInOtherPolygon(p1, p2)) {
// p1 is in p2
createInnerRing(p1, p2);
return true;
}
if (isPolygonInOtherPolygon(p2, p1)) {
// p2 is in p1
createInnerRing(p2, p1);
return true;
}
}
}
return false;
}
private void createInnerRing(Polygon poly1, Polygon poly2) {
LinearRing innerRing = new LinearRing(LinearRingType.INTERIOR);
poly2.addInteriorRing(innerRing);
for (Vertex v : poly1.getExteriorRing().getVertices()) {
innerRing.addVertex(v);
}
poly1.remove();
}
private boolean isPolygonInOtherPolygon(Polygon poly1, Polygon poly2) {
Plane plane = calculatePlane(poly2);
for (Vertex v : poly1.getExteriorRing().getVertices()) {
if (plane.getDistance(v) > EPSILON || !poly2.isPointInsideExteriorRing(v)) {
return false;
}
}
return true;
}
private Plane calculatePlane(Polygon p) {
Vector3d normal = p.calculateNormalNormalized();
return new Plane(normal, p.getExteriorRing().getVertices().get(0));
}
@Override
public HealWrongDormers createNew() {
return new HealWrongDormers();
}
@Override
public HealingID getID() {
return HealingID.S_WRONG_DORMERS;
}
}
package de.hft.stuttgart.citydoctor2.healing.math;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import de.hft.stuttgart.citydoctor2.datastructure.Edge;
public class EdgeGraph {
private Map<Edge, EdgeNode> nodes = new HashMap<>();
public void addEdge(Edge e, List<Edge> edges) {
if (nodes.containsKey(e)) {
return;
}
EdgeNode node = new EdgeNode(e);
nodes.put(e, node);
for (Edge childEdge : getEdgesConnected(e, edges)) {
EdgeNode childNode = nodes.get(childEdge);
if (childNode != null && childNode != node) {
node.addChild(childNode);
childNode.addChild(node);
}
}
}
private List<Edge> getEdgesConnected(Edge e, List<Edge> edges) {
List<Edge> result = new ArrayList<>();
for (Edge potentialEdge : edges) {
if (potentialEdge.getConnectionPoint(e) != null) {
result.add(potentialEdge);
}
}
return result;
}
public List<List<Edge>> getCycles() {
List<List<Edge>> cycles = new ArrayList<>();
for (EdgeNode n : nodes.values()) {
List<Edge> edges = new ArrayList<>();
n.collectConnectedEdges(edges, null);
if (edges.size() > 2) {
cycles.add(edges);
}
}
return cycles;
}
}
package de.hft.stuttgart.citydoctor2.healing.math;
import java.util.ArrayList;
import java.util.List;
import de.hft.stuttgart.citydoctor2.datastructure.Edge;
public class EdgeNode {
private Edge e;
private boolean visited = false;
public boolean finished = false;
private List<EdgeNode> children = new ArrayList<>();
public EdgeNode(Edge e) {
this.e = e;
}
public void resetVisit() {
visited = false;
}
public Edge getEdge() {
return e;
}
public void addChild(EdgeNode childNode) {
children.add(childNode);
}
public List<EdgeNode> getChildren() {
return children;
}
public boolean collectConnectedEdges(List<Edge> edges, EdgeNode parent) {
if (finished) {
return false;
}
if (visited) {
createCycle(edges);
return true;
}
visited = true;
edges.add(e);
for (EdgeNode n : children) {
if (n != parent && n.collectConnectedEdges(edges, this)) {
// found cycle
return true;
}
}
edges.remove(edges.size() - 1);
finished = true;
return false;
}
private void createCycle(List<Edge> edges) {
for (int i = 0; i < edges.size(); i++) {
Edge compare = edges.get(i);
if (compare == e) {
for (int j = 0; j < i; j++) {
edges.remove(0);
}
}
}
}
}
/*-
* 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.optimization;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import de.hft.stuttgart.citydoctor2.datastructure.BoundarySurface;
import de.hft.stuttgart.citydoctor2.datastructure.Building;
import de.hft.stuttgart.citydoctor2.datastructure.Installation;
import de.hft.stuttgart.citydoctor2.datastructure.CityObject;
import de.hft.stuttgart.citydoctor2.datastructure.ConcretePolygon;
import de.hft.stuttgart.citydoctor2.datastructure.Geometry;
import de.hft.stuttgart.citydoctor2.datastructure.LinearRing;
import de.hft.stuttgart.citydoctor2.datastructure.LinearRing.LinearRingType;
import de.hft.stuttgart.citydoctor2.datastructure.Polygon;
import de.hft.stuttgart.citydoctor2.datastructure.Vertex;
import de.hft.stuttgart.citydoctor2.math.Triangle3d;
import de.hft.stuttgart.citydoctor2.math.Vector3d;
import de.hft.stuttgart.citydoctor2.tesselation.TesselatedPolygon;
public class MeshGenerator {
private static final double EPSILON = 0.0001;
private MeshGenerator() {
}
public static void replaceGeometryWithMeshedGeometry(Building b, double maxArea) {
replacePolygonsInGeometry(b, maxArea);
for (BoundarySurface bs : b.getBoundarySurfaces()) {
replacePolygonsInGeometry(bs, maxArea);
}
for (Installation bi : b.getBuildingInstallations()) {
replacePolygonsInGeometry(bi, maxArea);
for (BoundarySurface bs : bi.getBoundarySurfaces()) {
replacePolygonsInGeometry(bs, maxArea);
}
}
}
private static void replacePolygonsInGeometry(CityObject co, double maxArea) {
for (Geometry geom : co.getGeometries()) {
Map<Polygon, List<ConcretePolygon>> replacementPolys = new HashMap<>();
for (Polygon p : geom.getPolygons()) {
if (!p.isLink() && (p.getExteriorRing().getVertices().size() > 4 || !p.getInnerRings().isEmpty())) {
TesselatedPolygon tesselate = p.tesselate();
List<ConcretePolygon> newPolys = new ArrayList<>();
for (Triangle3d t : tesselate.getTriangles()) {
addTriangles(t, maxArea, newPolys);
}
replacementPolys.put(p, newPolys);
}
}
for (Entry<Polygon, List<ConcretePolygon>> r : replacementPolys.entrySet()) {
geom.replacePolygon(r.getKey(), r.getValue().toArray(new ConcretePolygon[r.getValue().size()]));
}
}
}
private static void addTriangles(Triangle3d t, double precision, List<ConcretePolygon> newPolys) {
double area = t.getArea();
if (area > precision) {
double dis1 = t.getP1().getDistance(t.getP2());
double dis2 = t.getP2().getDistance(t.getP3());
double dis3 = t.getP1().getDistance(t.getP3());
if (dis1 >= dis2 && dis1 >= dis3) {
splitTriangles(t.getP1(), t.getP2(), t.getP3(), precision, newPolys);
return;
}
if (dis2 >= dis1 && dis2 >= dis3) {
splitTriangles(t.getP2(), t.getP3(), t.getP1(), precision, newPolys);
return;
}
splitTriangles(t.getP3(), t.getP1(), t.getP2(), precision, newPolys);
} else if (area > EPSILON) {
ConcretePolygon newPoly = new ConcretePolygon();
LinearRing ext = new LinearRing(LinearRingType.EXTERIOR);
newPoly.setExteriorRing(ext);
Vertex v1 = new Vertex(t.getP1());
ext.addVertex(v1);
ext.addVertex(new Vertex(t.getP2()));
ext.addVertex(new Vertex(t.getP3()));
ext.addVertex(v1);
newPolys.add(newPoly);
}
}
private static void splitTriangles(Vector3d v0, Vector3d v1, Vector3d v2, double precision,
List<ConcretePolygon> newPolys) {
double x = 0.5 * (v0.getX() + v1.getX());
double y = 0.5 * (v0.getY() + v1.getY());
double z = 0.5 * (v0.getZ() + v1.getZ());
Vector3d vNeu = new Vector3d(x, y, z);
Triangle3d tNeu1 = new Triangle3d(v0, vNeu, v2);
Triangle3d tNeu2 = new Triangle3d(v2, vNeu, v1);
addTriangles(tNeu1, precision, newPolys);
addTriangles(tNeu2, precision, newPolys);
}
}
package de.hft.stuttgart.citydoctor2.healer;
import java.io.IOException;
import de.hft.stuttgart.citydoctor2.datastructure.CityDoctorModel;
import de.hft.stuttgart.citydoctor2.parser.CityGmlParseException;
import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration;
import de.hft.stuttgart.citydoctor2.parser.CityGmlParser;
import de.hft.stuttgart.citydoctor2.parser.InvalidGmlFileException;
public class HealingTestUtil {
private HealingTestUtil() {
// only static access
}
public static CityDoctorModel loadCityModel(String path) throws CityGmlParseException, IOException, InvalidGmlFileException {
ParserConfiguration config = new ParserConfiguration(8, false);
CityDoctorModel m = CityGmlParser.parseCityGmlFile(path, config);
return m;
}
}
package de.hft.stuttgart.citydoctor2.healing;
import java.io.IOException;
import org.junit.Assert;
import org.junit.Test;
import de.hft.stuttgart.citydoctor2.check.CheckId;
import de.hft.stuttgart.citydoctor2.check.Checker;
import de.hft.stuttgart.citydoctor2.check.ValidationConfiguration;
import de.hft.stuttgart.citydoctor2.datastructure.CityDoctorModel;
import de.hft.stuttgart.citydoctor2.datastructure.Geometry;
import de.hft.stuttgart.citydoctor2.healer.Healer;
import de.hft.stuttgart.citydoctor2.parser.CityGmlParseException;
import de.hft.stuttgart.citydoctor2.parser.InvalidGmlFileException;
public class HealAllPolygonsWrongOrientationErrorTest {
@Test
public void testAllPolygonsWrongOrientation() throws CityGmlParseException, IOException, InvalidGmlFileException {
String path = "src/test/resources/SimpleSolid_SrefBS-GE-gml-SO-0008-T0001.gml";
ValidationConfiguration config = ValidationConfiguration.loadStandardValidationConfig();
CityDoctorModel model = TestUtil.loadCityModel(path, config);
Checker c = new Checker(config, model);
c.runChecks();
Geometry geom = model.getBuildings().get(0).getGeometries().get(0);
Assert.assertTrue(geom.containsError(CheckId.C_GE_S_ALL_POLYGONS_WRONG_ORIENTATION));
Healer healer = new Healer(c);
healer.healCityObject(model.getBuildings().get(0));
Assert.assertFalse(geom.containsError(CheckId.C_GE_S_ALL_POLYGONS_WRONG_ORIENTATION));
}
}
package de.hft.stuttgart.citydoctor2.healing;
import java.io.IOException;
import org.junit.Assert;
import org.junit.Test;
import de.hft.stuttgart.citydoctor2.check.CheckId;
import de.hft.stuttgart.citydoctor2.check.Checker;
import de.hft.stuttgart.citydoctor2.check.ValidationConfiguration;
import de.hft.stuttgart.citydoctor2.datastructure.CityDoctorModel;
import de.hft.stuttgart.citydoctor2.datastructure.Geometry;
import de.hft.stuttgart.citydoctor2.healer.Healer;
import de.hft.stuttgart.citydoctor2.parser.CityGmlParseException;
import de.hft.stuttgart.citydoctor2.parser.InvalidGmlFileException;
public class HealConsecutivePointsSameErrorTest {
@Test
public void test() throws CityGmlParseException, IOException, InvalidGmlFileException {
String path = "src/test/resources/SimpleSolid_SrefBS-GE-gml-LR-0002-T0001.gml";
ValidationConfiguration config = ValidationConfiguration.loadStandardValidationConfig();
// disable schematron testing
config.setSchematronFilePathInGlobalParameters(null);
CityDoctorModel model = TestUtil.loadCityModel(path, config);
Checker c = new Checker(config, model);
c.runChecks();
Geometry geom = model.getBuildings().get(0).getGeometries().get(0);
Assert.assertTrue(geom.containsError(CheckId.C_GE_R_DUPLICATE_POINT));
Healer healer = new Healer(c);
healer.healCityObject(model.getBuildings().get(0));
Assert.assertFalse(geom.containsError(CheckId.C_GE_R_DUPLICATE_POINT));
}
}
package de.hft.stuttgart.citydoctor2.healing;
import java.io.IOException;
import org.junit.Assert;
import org.junit.Test;
import de.hft.stuttgart.citydoctor2.check.CheckId;
import de.hft.stuttgart.citydoctor2.check.Checker;
import de.hft.stuttgart.citydoctor2.check.ValidationConfiguration;
import de.hft.stuttgart.citydoctor2.datastructure.CityDoctorModel;
import de.hft.stuttgart.citydoctor2.datastructure.Geometry;
import de.hft.stuttgart.citydoctor2.healer.Healer;
import de.hft.stuttgart.citydoctor2.parser.CityGmlParseException;
import de.hft.stuttgart.citydoctor2.parser.InvalidGmlFileException;
public class HealHoleOutsideErrorTest {
@Test
public void testHealHoleOutside() throws CityGmlParseException, IOException, InvalidGmlFileException {
String path = "src/test/resources/SimpleSolid_SrefBS-GE-gml-PO-0004-T0001.gml";
ValidationConfiguration config = ValidationConfiguration.loadStandardValidationConfig();
CityDoctorModel model = TestUtil.loadCityModel(path, config);
Checker c = new Checker(config, model);
c.runChecks();
Geometry geom = model.getBuildings().get(0).getGeometries().get(0);
Assert.assertTrue(geom.containsError(CheckId.C_GE_P_HOLE_OUTSIDE));
Healer healer = new Healer(c);
healer.healCityObject(model.getBuildings().get(0));
Assert.assertFalse(geom.containsError(CheckId.C_GE_P_HOLE_OUTSIDE));
}
}
/*-
* 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.healing;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.citygml4j.core.model.core.AbstractThematicSurface;
import org.citygml4j.core.model.core.CityModel;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import de.hft.stuttgart.citydoctor2.check.CheckError;
import de.hft.stuttgart.citydoctor2.check.Checker;
import de.hft.stuttgart.citydoctor2.check.ModificationListener;
import de.hft.stuttgart.citydoctor2.check.Requirement;
import de.hft.stuttgart.citydoctor2.check.RequirementConfiguration;
import de.hft.stuttgart.citydoctor2.check.ValidationConfiguration;
import de.hft.stuttgart.citydoctor2.check.error.AttributeMissingError;
import de.hft.stuttgart.citydoctor2.datastructure.BoundarySurface;
import de.hft.stuttgart.citydoctor2.datastructure.Building;
import de.hft.stuttgart.citydoctor2.datastructure.CityDoctorModel;
import de.hft.stuttgart.citydoctor2.datastructure.ConcretePolygon;
import de.hft.stuttgart.citydoctor2.datastructure.Geometry;
import de.hft.stuttgart.citydoctor2.datastructure.GeometryType;
import de.hft.stuttgart.citydoctor2.datastructure.Installation;
import de.hft.stuttgart.citydoctor2.datastructure.LinearRing;
import de.hft.stuttgart.citydoctor2.datastructure.LinearRing.LinearRingType;
import de.hft.stuttgart.citydoctor2.datastructure.LinkedPolygon;
import de.hft.stuttgart.citydoctor2.datastructure.Lod;
import de.hft.stuttgart.citydoctor2.datastructure.Polygon;
import de.hft.stuttgart.citydoctor2.datastructure.Vertex;
import de.hft.stuttgart.citydoctor2.exceptions.CityDoctorWriteException;
import de.hft.stuttgart.citydoctor2.healer.Healer;
import de.hft.stuttgart.citydoctor2.parser.CityGmlParseException;
import de.hft.stuttgart.citydoctor2.parser.CityGmlParser;
import de.hft.stuttgart.citydoctor2.parser.InvalidGmlFileException;
public class HealMissingSolidTest {
@Rule
public TemporaryFolder folder = new TemporaryFolder();
@Test
public void testCreateSolid() throws CityDoctorWriteException, IOException, CityGmlParseException, InvalidGmlFileException {
ValidationConfiguration config = ValidationConfiguration.loadStandardValidationConfig();
CityDoctorModel model = new CityDoctorModel(config.getParserConfiguration(), new File("test"));
model.setCityModel(new CityModel());
Building b = new Building();
model.addBuilding(b);
b.setGmlObject(new org.citygml4j.core.model.building.Building());
Geometry geom = new Geometry(GeometryType.MULTI_SURFACE, Lod.LOD2);
b.addGeometry(geom);
ConcretePolygon p1 = new ConcretePolygon();
LinearRing ext1 = createTestRing();
p1.setExteriorRing(ext1);
geom.addPolygon(p1);
BoundarySurface bs1 = new BoundarySurface(mock(AbstractThematicSurface.class));
b.addBoundarySurface(bs1);
Geometry geom2 = new Geometry(GeometryType.MULTI_SURFACE, Lod.LOD2);
bs1.addGeometry(geom2);
ConcretePolygon p2 = new ConcretePolygon();
LinearRing ext2 = createTestRing();
p2.setExteriorRing(ext2);
geom2.addPolygon(p2);
LinkedPolygon p5 = new LinkedPolygon(p2, geom);
geom.addPolygon(p5);
Installation bi = new Installation();
b.addBuildingInstallation(bi);
Geometry geom3 = new Geometry(GeometryType.MULTI_SURFACE, Lod.LOD2);
bi.addGeometry(geom3);
ConcretePolygon p3 = new ConcretePolygon();
LinearRing ext3 = createTestRing();
p3.setExteriorRing(ext3);
geom3.addPolygon(p3);
BoundarySurface bs2 = new BoundarySurface(mock(AbstractThematicSurface.class));
bi.addBoundarySurface(bs2);
Geometry geom4 = new Geometry(GeometryType.MULTI_SURFACE, Lod.LOD2);
bs2.addGeometry(geom4);
ConcretePolygon p4 = new ConcretePolygon();
LinearRing ext4 = createTestRing();
p4.setExteriorRing(ext4);
geom4.addPolygon(p4);
AttributeMissingError err = new AttributeMissingError(b, "", "lod2solid");
HealMissingSolid lodHealer = new HealMissingSolid();
lodHealer.visit(err, mock(ModificationListener.class));
assertEquals(1, b.getGeometries().size());
Geometry geometry = b.getGeometries().get(0);
assertEquals(4, geometry.getPolygons().size());
assertEquals(Lod.LOD2, geometry.getLod());
assertEquals(GeometryType.SOLID, geometry.getType());
int nrOfConcrete = 0;
int nrOfLinks = 0;
for (Polygon p : geometry.getPolygons()) {
if (p.isLink()) {
nrOfLinks++;
} else {
nrOfConcrete++;
}
}
assertEquals(1, nrOfConcrete);
assertEquals(3, nrOfLinks);
File createSolidFile = folder.newFile("createdSolid.gml");
model.saveAs(createSolidFile.toString(), false);
CityDoctorModel parsedModel = CityGmlParser.parseCityGmlFile(createSolidFile.toString(), config.getParserConfiguration());
Building building = parsedModel.getBuildings().get(0);
assertEquals(1, building.getGeometries().size());
Geometry geometry2 = building.getGeometries().get(0);
assertEquals(GeometryType.SOLID, geometry2.getType());
}
private LinearRing createTestRing() {
LinearRing ext = new LinearRing(LinearRingType.EXTERIOR);
ext.addVertex(new Vertex(1, 0, 0));
ext.addVertex(new Vertex(2, 2, 0));
ext.addVertex(new Vertex(3, 4, 0));
ext.addVertex(new Vertex(1, 0, 0));
return ext;
}
@Test
public void testFixingFile() throws CityGmlParseException, InvalidGmlFileException {
ValidationConfiguration config = ValidationConfiguration.loadStandardValidationConfig();
config.setSchematronFilePathInGlobalParameters("src/test/resources/schematronTestForMissingSolid.xml");
config.getRequirements().put(Requirement.R_SE_BS_ROOF_UNFRAGMENTED.getId(),
new RequirementConfiguration(false));
CityDoctorModel model = CityGmlParser.parseCityGmlFile("src/test/resources/SimpleSolid_SrefBS_withoutSolid.gml",
config.getParserConfiguration());
Building b = model.getBuildings().get(0);
assertTrue(b.getGeometries().isEmpty());
Checker c = new Checker(config, model);
c.runChecks();
assertTrue(b.containsAnyError());
List<CheckError> errors = new ArrayList<>();
b.collectContainedErrors(errors);
assertEquals(1, errors.size());
CheckError err = errors.get(0);
assertTrue(err instanceof AttributeMissingError);
Healer healer = new Healer(c);
healer.healModel(model);
assertFalse(b.containsAnyError());
Geometry geom = b.getGeometry(GeometryType.SOLID, Lod.LOD2);
assertNotNull(geom);
assertEquals(7, geom.getPolygons().size());
}
}
package de.hft.stuttgart.citydoctor2.healing;
import java.io.IOException;
import org.junit.Assert;
import org.junit.Test;
import de.hft.stuttgart.citydoctor2.check.CheckId;
import de.hft.stuttgart.citydoctor2.check.Checker;
import de.hft.stuttgart.citydoctor2.check.ValidationConfiguration;
import de.hft.stuttgart.citydoctor2.datastructure.CityDoctorModel;
import de.hft.stuttgart.citydoctor2.datastructure.Geometry;
import de.hft.stuttgart.citydoctor2.healer.Healer;
import de.hft.stuttgart.citydoctor2.parser.CityGmlParseException;
import de.hft.stuttgart.citydoctor2.parser.InvalidGmlFileException;
public class HealNonManifoldEdgeErrorTest {
@Test
public void test() throws CityGmlParseException, IOException, InvalidGmlFileException {
String path = "src/test/resources/SimpleSolid_SrefBS-GE-gml-SO-0004-T0001.gml";
ValidationConfiguration config = ValidationConfiguration.loadStandardValidationConfig();
CityDoctorModel model = TestUtil.loadCityModel(path, config);
Checker c = new Checker(config, model);
c.runChecks();
Geometry geom = model.getBuildings().get(0).getGeometries().get(0);
Assert.assertTrue(geom.containsError(CheckId.C_GE_S_NON_MANIFOLD_EDGE));
Healer healer = new Healer(c);
healer.healCityObject(model.getBuildings().get(0));
Assert.assertFalse(geom.containsError(CheckId.C_GE_S_NON_MANIFOLD_EDGE));
}
}
package de.hft.stuttgart.citydoctor2.healing;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.fail;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.junit.Assert;
import org.junit.Test;
import de.hft.stuttgart.citydoctor2.CppInitializer;
import de.hft.stuttgart.citydoctor2.check.CheckError;
import de.hft.stuttgart.citydoctor2.check.CheckId;
import de.hft.stuttgart.citydoctor2.check.Checker;
import de.hft.stuttgart.citydoctor2.check.ErrorId;
import de.hft.stuttgart.citydoctor2.check.ValidationConfiguration;
import de.hft.stuttgart.citydoctor2.checks.geometry.PlanarCheck;
import de.hft.stuttgart.citydoctor2.datastructure.Building;
import de.hft.stuttgart.citydoctor2.datastructure.CityDoctorModel;
import de.hft.stuttgart.citydoctor2.datastructure.ConcretePolygon;
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.LinearRing.LinearRingType;
import de.hft.stuttgart.citydoctor2.datastructure.Lod;
import de.hft.stuttgart.citydoctor2.datastructure.Polygon;
import de.hft.stuttgart.citydoctor2.datastructure.Vertex;
import de.hft.stuttgart.citydoctor2.healer.Healer;
import de.hft.stuttgart.citydoctor2.parser.CityGmlParseException;
import de.hft.stuttgart.citydoctor2.parser.InvalidGmlFileException;
public class HealPlanarPolygonErrorTest {
@Test
public void testPlanarPlaneDistance() throws CityGmlParseException, IOException, InvalidGmlFileException {
String path = "src/test/resources/SimpleSolid_SrefBS-GE-gml-PO-0002-T0001.gml";
ValidationConfiguration config = ValidationConfiguration.loadStandardValidationConfig();
CityDoctorModel model = TestUtil.loadCityModel(path, config);
Checker c = new Checker(config, model);
c.runChecks();
Geometry geom = model.getBuildings().get(0).getGeometries().get(0);
Assert.assertTrue(geom.containsError(CheckId.C_GE_P_NON_PLANAR));
Healer healer = new Healer(c);
healer.setNumberOfIterations(2);
healer.healCityObject(model.getBuildings().get(0));
Assert.assertFalse(geom.containsError(CheckId.C_GE_P_NON_PLANAR));
}
@Test
public void testNonplanarPolygon() {
CppInitializer.initCpp();
Building b = new Building();
Geometry geom = new Geometry(GeometryType.SOLID, Lod.LOD2);
b.addGeometry(geom);
Vertex v0 = new Vertex(0, 0, 0);
Vertex v1 = new Vertex(4, 0, 0);
Vertex v4 = new Vertex(4, 4, 1);
Vertex v6 = new Vertex(0, 4, 0);
Vertex v8 = new Vertex(4, 0, 4);
Vertex v9 = new Vertex(4, 4, 4);
Vertex v10 = new Vertex(0, 4, 4);
Vertex v11 = new Vertex(0, 0, 5);
Polygon p3 = new ConcretePolygon();
geom.addPolygon(p3);
LinearRing r3 = new LinearRing(LinearRingType.EXTERIOR);
p3.setExteriorRing(r3); // z = 0
r3.addVertex(v0);
r3.addVertex(v1);
r3.addVertex(v4);
r3.addVertex(v6);
r3.addVertex(v0);
Polygon p4 = new ConcretePolygon();
geom.addPolygon(p4);
LinearRing r4 = new LinearRing(LinearRingType.EXTERIOR);
p4.setExteriorRing(r4); // x = 4
r4.addVertex(v1);
r4.addVertex(v8);
r4.addVertex(v9);
r4.addVertex(v4);
r4.addVertex(v1);
Polygon p5 = new ConcretePolygon();
geom.addPolygon(p5);
LinearRing r5 = new LinearRing(LinearRingType.EXTERIOR);
p5.setExteriorRing(r5); // z = 4
r5.addVertex(v8);
r5.addVertex(v11);
r5.addVertex(v10);
r5.addVertex(v9);
r5.addVertex(v8);
Polygon p6 = new ConcretePolygon();
geom.addPolygon(p6);
LinearRing r6 = new LinearRing(LinearRingType.EXTERIOR);
p6.setExteriorRing(r6); // x = 0
r6.addVertex(v0);
r6.addVertex(v6);
r6.addVertex(v10);
r6.addVertex(v11);
r6.addVertex(v0);
Polygon p7 = new ConcretePolygon();
geom.addPolygon(p7);
LinearRing r7 = new LinearRing(LinearRingType.EXTERIOR);
p7.setExteriorRing(r7); // y = 4
r7.addVertex(v4);
r7.addVertex(v9);
r7.addVertex(v10);
r7.addVertex(v6);
r7.addVertex(v4);
Polygon p8 = new ConcretePolygon();
geom.addPolygon(p8);
LinearRing r8 = new LinearRing(LinearRingType.EXTERIOR);
p8.setExteriorRing(r8); // y = 0
r8.addVertex(v0);
r8.addVertex(v11);
r8.addVertex(v8);
r8.addVertex(v1);
r8.addVertex(v0);
geom.updateEdgesAndVertices();
PlanarCheck check = new PlanarCheck();
geom.accept(check);
check.check(geom);
List<CheckError> errors = new ArrayList<>();
geom.collectContainedErrors(errors);
List<CheckError> planarErrors = new ArrayList<>();
for (CheckError e : errors) {
if (e.getErrorId() == ErrorId.GE_P_NON_PLANAR_POLYGON_DISTANCE_PLANE) {
planarErrors.add(e);
}
}
if (!planarErrors.isEmpty()) {
CheckError e = planarErrors.get(0);
HealPlanarPolygonCpp healer = new HealPlanarPolygonCpp();
e.accept(healer, TestUtil.createDummyModificationListener());
geom.updateEdgesAndVertices();
geom.clearAllContainedCheckResults();
geom.accept(check);
assertFalse(geom.containsError(CheckId.C_GE_P_NON_PLANAR));
} else {
fail();
}
}
@Test
public void testNonplanarPolygon_Split() {
CppInitializer.initCpp();
Building b = new Building();
Geometry geom = new Geometry(GeometryType.SOLID, Lod.LOD2);
b.addGeometry(geom);
Vertex v0 = new Vertex(0, 0, 0);
Vertex v1 = new Vertex(4, -1, 0);
Vertex v4 = new Vertex(4, 4, 0);
Vertex v6 = new Vertex(0, 4, 0);
Vertex v8 = new Vertex(4, 0, 4);
Vertex v9 = new Vertex(4, 4, 4);
Vertex v10 = new Vertex(0, 4, 4);
Vertex v11 = new Vertex(0, 0, 5);
Polygon p3 = new ConcretePolygon();
geom.addPolygon(p3);
LinearRing r3 = new LinearRing(LinearRingType.EXTERIOR);
p3.setExteriorRing(r3); // z = 0
r3.addVertex(v0);
r3.addVertex(v1);
r3.addVertex(v4);
r3.addVertex(v6);
r3.addVertex(v0);
Polygon p4 = new ConcretePolygon();
geom.addPolygon(p4);
LinearRing r4 = new LinearRing(LinearRingType.EXTERIOR);
p4.setExteriorRing(r4); // x = 4
r4.addVertex(v1);
r4.addVertex(v8);
r4.addVertex(v9);
r4.addVertex(v4);
r4.addVertex(v1);
Polygon p5 = new ConcretePolygon();
geom.addPolygon(p5);
LinearRing r5 = new LinearRing(LinearRingType.EXTERIOR);
p5.setExteriorRing(r5); // z = 4
r5.addVertex(v8);
r5.addVertex(v11);
r5.addVertex(v10);
r5.addVertex(v9);
r5.addVertex(v8);
Polygon p6 = new ConcretePolygon();
geom.addPolygon(p6);
LinearRing r6 = new LinearRing(LinearRingType.EXTERIOR);
p6.setExteriorRing(r6); // x = 0
r6.addVertex(v0);
r6.addVertex(v6);
r6.addVertex(v10);
r6.addVertex(v11);
r6.addVertex(v0);
Polygon p7 = new ConcretePolygon();
geom.addPolygon(p7);
LinearRing r7 = new LinearRing(LinearRingType.EXTERIOR);
p7.setExteriorRing(r7); // y = 4
r7.addVertex(v4);
r7.addVertex(v9);
r7.addVertex(v10);
r7.addVertex(v6);
r7.addVertex(v4);
Polygon p8 = new ConcretePolygon();
geom.addPolygon(p8);
LinearRing r8 = new LinearRing(LinearRingType.EXTERIOR);
p8.setExteriorRing(r8); // y = 0
r8.addVertex(v11);
r8.addVertex(v8);
r8.addVertex(v1);
r8.addVertex(v11);
Polygon p8_2 = new ConcretePolygon();
geom.addPolygon(p8_2);
LinearRing r8_2 = new LinearRing(LinearRingType.EXTERIOR);
p8_2.setExteriorRing(r8_2); // y = 0
r8_2.addVertex(v0);
r8_2.addVertex(v11);
r8_2.addVertex(v1);
r8_2.addVertex(v0);
geom.updateEdgesAndVertices();
PlanarCheck check = new PlanarCheck();
geom.accept(check);
check.check(geom);
List<CheckError> errors = new ArrayList<>();
geom.collectContainedErrors(errors);
List<CheckError> planarErrors = new ArrayList<>();
for (CheckError e : errors) {
if (e.getErrorId() == ErrorId.GE_P_NON_PLANAR_POLYGON_DISTANCE_PLANE) {
planarErrors.add(e);
}
}
if (!planarErrors.isEmpty()) {
CheckError e = planarErrors.get(0);
HealPlanarPolygonCpp healer = new HealPlanarPolygonCpp();
e.accept(healer, TestUtil.createDummyModificationListener());
geom.updateEdgesAndVertices();
geom.clearAllContainedCheckResults();
geom.accept(check);
assertFalse(geom.containsError(CheckId.C_GE_P_NON_PLANAR));
} else {
fail();
}
}
@Test
public void testNonplanarPolygon_Split2() {
CppInitializer.initCpp();
Building b = new Building();
Geometry geom = new Geometry(GeometryType.SOLID, Lod.LOD2);
b.addGeometry(geom);
Vertex v0 = new Vertex(0, 0, 0);
Vertex v1 = new Vertex(4, 0, 0);
Vertex v4 = new Vertex(4, 5, 0);
Vertex v6 = new Vertex(0, 4, 0);
Vertex v8 = new Vertex(4, 0, 4);
Vertex v9 = new Vertex(4, 4, 4);
Vertex v10 = new Vertex(0, 4, 4);
Vertex v11 = new Vertex(0, 0, 5);
Polygon p3 = new ConcretePolygon();
geom.addPolygon(p3);
LinearRing r3 = new LinearRing(LinearRingType.EXTERIOR);
p3.setExteriorRing(r3); // z = 0
r3.addVertex(v0);
r3.addVertex(v1);
r3.addVertex(v4);
r3.addVertex(v6);
r3.addVertex(v0);
Polygon p4 = new ConcretePolygon();
geom.addPolygon(p4);
LinearRing r4 = new LinearRing(LinearRingType.EXTERIOR);
p4.setExteriorRing(r4); // x = 4
r4.addVertex(v1);
r4.addVertex(v8);
r4.addVertex(v9);
r4.addVertex(v4);
r4.addVertex(v1);
Polygon p5 = new ConcretePolygon();
geom.addPolygon(p5);
LinearRing r5 = new LinearRing(LinearRingType.EXTERIOR);
p5.setExteriorRing(r5); // z = 4
r5.addVertex(v8);
r5.addVertex(v11);
r5.addVertex(v10);
r5.addVertex(v9);
r5.addVertex(v8);
Polygon p6 = new ConcretePolygon();
geom.addPolygon(p6);
LinearRing r6 = new LinearRing(LinearRingType.EXTERIOR);
p6.setExteriorRing(r6); // x = 0
r6.addVertex(v0);
r6.addVertex(v6);
r6.addVertex(v10);
r6.addVertex(v11);
r6.addVertex(v0);
Polygon p7 = new ConcretePolygon();
geom.addPolygon(p7);
LinearRing r7 = new LinearRing(LinearRingType.EXTERIOR);
p7.setExteriorRing(r7); // y = 4
r7.addVertex(v4);
r7.addVertex(v9);
r7.addVertex(v10);
r7.addVertex(v4);
Polygon p7_2 = new ConcretePolygon();
geom.addPolygon(p7_2);
LinearRing r7_2 = new LinearRing(LinearRingType.EXTERIOR);
p7_2.setExteriorRing(r7_2); // y = 4
r7_2.addVertex(v4);
r7_2.addVertex(v10);
r7_2.addVertex(v6);
r7_2.addVertex(v4);
Polygon p8 = new ConcretePolygon();
geom.addPolygon(p8);
LinearRing r8 = new LinearRing(LinearRingType.EXTERIOR);
p8.setExteriorRing(r8); // y = 0
r8.addVertex(v0);
r8.addVertex(v11);
r8.addVertex(v8);
r8.addVertex(v1);
r8.addVertex(v0);
geom.updateEdgesAndVertices();
PlanarCheck check = new PlanarCheck();
geom.accept(check);
check.check(geom);
List<CheckError> errors = new ArrayList<>();
geom.collectContainedErrors(errors);
List<CheckError> planarErrors = new ArrayList<>();
for (CheckError e : errors) {
if (e.getErrorId() == ErrorId.GE_P_NON_PLANAR_POLYGON_DISTANCE_PLANE) {
planarErrors.add(e);
}
}
if (!planarErrors.isEmpty()) {
CheckError e = planarErrors.get(0);
HealPlanarPolygonCpp healer = new HealPlanarPolygonCpp();
e.accept(healer, TestUtil.createDummyModificationListener());
geom.updateEdgesAndVertices();
geom.clearAllContainedCheckResults();
geom.accept(check);
assertFalse(geom.containsError(CheckId.C_GE_P_NON_PLANAR));
} else {
fail();
}
}
}
package de.hft.stuttgart.citydoctor2.healing;
import java.io.File;
import java.io.IOException;
import org.junit.Assert;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import de.hft.stuttgart.citydoctor2.check.CheckId;
import de.hft.stuttgart.citydoctor2.check.Checker;
import de.hft.stuttgart.citydoctor2.check.Requirement;
import de.hft.stuttgart.citydoctor2.check.RequirementConfiguration;
import de.hft.stuttgart.citydoctor2.check.ValidationConfiguration;
import de.hft.stuttgart.citydoctor2.datastructure.Building;
import de.hft.stuttgart.citydoctor2.datastructure.CityDoctorModel;
import de.hft.stuttgart.citydoctor2.exceptions.CityDoctorWriteException;
import de.hft.stuttgart.citydoctor2.healer.Healer;
import de.hft.stuttgart.citydoctor2.parser.CityGmlParseException;
import de.hft.stuttgart.citydoctor2.parser.InvalidGmlFileException;
public class HealPolygonWithoutSurfaceTest {
@Rule
public TemporaryFolder folder = new TemporaryFolder();
@Test
public void testHealPolygonWithoutSurface() throws CityGmlParseException, IOException, InvalidGmlFileException, CityDoctorWriteException {
ValidationConfiguration config = ValidationConfiguration.loadStandardValidationConfig();
config.getRequirements().put(Requirement.R_SE_POLYGON_WITHOUT_SURFACE.getId(), new RequirementConfiguration(true));
String path = "src/test/resources/MissingGroundSurface.gml";
CityDoctorModel model = TestUtil.loadCityModel(path, config);
Checker c = new Checker(config, model);
c.runChecks();
Building building = model.getBuildings().get(0);
Assert.assertTrue(building.containsError(CheckId.C_SE_POLYGON_WITHOUT_SURFACE));
Healer healer = new Healer(c);
healer.healCityObject(model.getBuildings().get(0));
Assert.assertFalse(building.containsError(CheckId.C_SE_POLYGON_WITHOUT_SURFACE));
File outputFile = folder.newFile();
model.saveAs(outputFile.toString(), false);
CityDoctorModel loadedModel = TestUtil.loadCityModel(outputFile.toString(), config);
c = new Checker(config, loadedModel);
c.runChecks();
building = loadedModel.getBuildings().get(0);
Assert.assertFalse(building.containsError(CheckId.C_SE_POLYGON_WITHOUT_SURFACE));
}
}
package de.hft.stuttgart.citydoctor2.healing;
import java.io.IOException;
import org.junit.Assert;
import org.junit.Test;
import de.hft.stuttgart.citydoctor2.check.CheckId;
import de.hft.stuttgart.citydoctor2.check.Checker;
import de.hft.stuttgart.citydoctor2.check.ValidationConfiguration;
import de.hft.stuttgart.citydoctor2.datastructure.CityDoctorModel;
import de.hft.stuttgart.citydoctor2.datastructure.Geometry;
import de.hft.stuttgart.citydoctor2.healer.Healer;
import de.hft.stuttgart.citydoctor2.parser.CityGmlParseException;
import de.hft.stuttgart.citydoctor2.parser.InvalidGmlFileException;
public class HealPolygonWrongOrientationErrorTest {
@Test
public void testPolygonWrongOrientation1() throws CityGmlParseException, IOException, InvalidGmlFileException {
String path = "src/test/resources/SimpleSolid_SrefBS-GE-gml-SO-0007-T0001.gml";
checkAndRepairFile(path);
}
@Test
public void testPolygonWrongOrientation2() throws CityGmlParseException, IOException, InvalidGmlFileException {
String path = "src/test/resources/SimpleSolid_SrefBS-GE-gml-SO-0007-T0002.gml";
checkAndRepairFile(path);
}
@Test
public void testPolygonWrongOrientation3() throws CityGmlParseException, IOException, InvalidGmlFileException {
String path = "src/test/resources/SimpleSolid_SrefBS-GE-gml-SO-0007-T0003.gml";
checkAndRepairFile(path);
}
private void checkAndRepairFile(String path) throws CityGmlParseException, IOException, InvalidGmlFileException {
ValidationConfiguration config = ValidationConfiguration.loadStandardValidationConfig();
CityDoctorModel model = TestUtil.loadCityModel(path, config);
Checker c = new Checker(config, model);
c.runChecks();
Geometry geom = model.getBuildings().get(0).getGeometries().get(0);
Assert.assertTrue(geom.containsError(CheckId.C_GE_S_POLYGON_WRONG_ORIENTATION));
Healer healer = new Healer(c);
healer.healCityObject(model.getBuildings().get(0));
Assert.assertFalse(geom.containsError(CheckId.C_GE_S_POLYGON_WRONG_ORIENTATION));
}
}
package de.hft.stuttgart.citydoctor2.healing;
import java.io.IOException;
import org.junit.Assert;
import org.junit.Test;
import de.hft.stuttgart.citydoctor2.check.CheckId;
import de.hft.stuttgart.citydoctor2.check.Checker;
import de.hft.stuttgart.citydoctor2.check.ValidationConfiguration;
import de.hft.stuttgart.citydoctor2.datastructure.CityDoctorModel;
import de.hft.stuttgart.citydoctor2.datastructure.Geometry;
import de.hft.stuttgart.citydoctor2.healer.Healer;
import de.hft.stuttgart.citydoctor2.parser.CityGmlParseException;
import de.hft.stuttgart.citydoctor2.parser.InvalidGmlFileException;
public class HealRingNotClosedErrorTest {
@Test
public void testRingNotClosed() throws CityGmlParseException, IOException, InvalidGmlFileException {
String path = "src/test/resources/SimpleSolid_SrefBS-GE-gml-LR-0003-T0001.gml";
ValidationConfiguration config = ValidationConfiguration.loadStandardValidationConfig();
CityDoctorModel model = TestUtil.loadCityModel(path, config);
Checker c = new Checker(config, model);
c.runChecks();
Geometry geom = model.getBuildings().get(0).getGeometries().get(0);
Assert.assertTrue(geom.containsError(CheckId.C_GE_R_NOT_CLOSED));
Healer healer = new Healer(c);
healer.healCityObject(model.getBuildings().get(0));
Assert.assertFalse(geom.containsError(CheckId.C_GE_R_NOT_CLOSED));
}
}
package de.hft.stuttgart.citydoctor2.healing;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.io.IOException;
import org.junit.Assert;
import org.junit.Test;
import de.hft.stuttgart.citydoctor2.check.CheckId;
import de.hft.stuttgart.citydoctor2.check.CheckResult;
import de.hft.stuttgart.citydoctor2.check.Checker;
import de.hft.stuttgart.citydoctor2.check.ErrorId;
import de.hft.stuttgart.citydoctor2.check.ResultStatus;
import de.hft.stuttgart.citydoctor2.check.ValidationConfiguration;
import de.hft.stuttgart.citydoctor2.check.error.RingEdgeIntersectionError;
import de.hft.stuttgart.citydoctor2.checks.geometry.DuplicatePointsCheck;
import de.hft.stuttgart.citydoctor2.checks.geometry.RingSelfIntCheck;
import de.hft.stuttgart.citydoctor2.datastructure.CityDoctorModel;
import de.hft.stuttgart.citydoctor2.datastructure.ConcretePolygon;
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.LinearRing.LinearRingType;
import de.hft.stuttgart.citydoctor2.datastructure.Lod;
import de.hft.stuttgart.citydoctor2.datastructure.Polygon;
import de.hft.stuttgart.citydoctor2.datastructure.Vertex;
import de.hft.stuttgart.citydoctor2.healer.Healer;
import de.hft.stuttgart.citydoctor2.parser.CityGmlParseException;
import de.hft.stuttgart.citydoctor2.parser.InvalidGmlFileException;
public class HealRingSelfIntErrorTest {
@Test
public void testIntersectingEdges1() {
Geometry geom = new Geometry(GeometryType.SOLID, Lod.LOD1);
Polygon p = new ConcretePolygon();
geom.addPolygon(p);
Vertex v0 = new Vertex(0, 4, 0);
Vertex v1 = new Vertex(0, 0, 0);
Vertex v2 = new Vertex(4, 4, 0);
Vertex v3 = new Vertex(6, 2, 0);
Vertex v4 = new Vertex(4, 0, 0);
LinearRing r = new LinearRing(LinearRingType.EXTERIOR);
p.setExteriorRing(r);
r.addVertex(v0);
r.addVertex(v1);
r.addVertex(v2);
r.addVertex(v3);
r.addVertex(v4);
r.addVertex(v0);
geom.updateEdgesAndVertices();
RingSelfIntCheck check = new RingSelfIntCheck();
check.check(r);
CheckResult cr = r.getCheckResult(check);
assertNotNull(cr);
assertEquals(ResultStatus.ERROR, cr.getResultStatus());
assertEquals(ErrorId.GE_R_SELF_INTERSECTION, cr.getError().getErrorId());
assertTrue(cr.getError() instanceof RingEdgeIntersectionError);
HealRingSelfIntError healer = new HealRingSelfIntError();
cr.getError().accept(healer, TestUtil.createDummyModificationListener());
geom.updateEdgesAndVertices();
assertEquals(2, geom.getPolygons().size());
Polygon p1 = geom.getPolygons().get(0);
Polygon p2 = geom.getPolygons().get(1);
if (p1.getExteriorRing().getVertices().size() == 4) {
assertEquals(5, p2.getExteriorRing().getVertices().size());
} else {
assertEquals(5, p1.getExteriorRing().getVertices().size());
assertEquals(4, p2.getExteriorRing().getVertices().size());
}
check.check(p1.getExteriorRing());
check.check(p2.getExteriorRing());
cr = p1.getExteriorRing().getCheckResult(check);
assertNotNull(cr);
assertEquals(ResultStatus.OK, cr.getResultStatus());
cr = p2.getExteriorRing().getCheckResult(check);
assertNotNull(cr);
assertEquals(ResultStatus.OK, cr.getResultStatus());
}
@Test
public void testDuplicatePoint1() {
Geometry geom = new Geometry(GeometryType.SOLID, Lod.LOD1);
Polygon p = new ConcretePolygon();
geom.addPolygon(p);
Vertex v0 = new Vertex(0, 0, 0);
Vertex v1 = new Vertex(4, 0, 0);
Vertex v2 = new Vertex(4, 4, 0);
Vertex v3 = new Vertex(2, 4, 0);
Vertex v4 = new Vertex(0, 4, 0);
LinearRing r = new LinearRing(LinearRingType.EXTERIOR);
p.setExteriorRing(r);
r.addVertex(v0);
r.addVertex(v1);
r.addVertex(v2);
r.addVertex(v0);
r.addVertex(v3);
r.addVertex(v4);
r.addVertex(v0);
DuplicatePointsCheck check = new DuplicatePointsCheck();
check.check(r);
CheckResult cr = r.getCheckResult(check);
assertNotNull(cr);
assertEquals(ResultStatus.ERROR, cr.getResultStatus());
assertEquals(ErrorId.GE_R_SELF_INTERSECTION, cr.getError().getErrorId());
HealRingSelfIntError healer = new HealRingSelfIntError();
cr.getError().accept(healer, TestUtil.createDummyModificationListener());
geom.updateEdgesAndVertices();
assertEquals(2, geom.getPolygons().size());
Polygon p1 = geom.getPolygons().get(0);
Polygon p2 = geom.getPolygons().get(1);
assertEquals(4, p1.getExteriorRing().getVertices().size());
assertEquals(4, p2.getExteriorRing().getVertices().size());
assertEquals(2, v0.getAdjacentRings(geom).size());
}
@Test
public void testDuplicatePoint2() {
Geometry geom = new Geometry(GeometryType.SOLID, Lod.LOD1);
Polygon p = new ConcretePolygon();
geom.addPolygon(p);
Vertex v0 = new Vertex(0, 0, 0);
Vertex v1 = new Vertex(4, 0, 0);
Vertex v2 = new Vertex(4, 4, 0);
Vertex v3 = new Vertex(2, 4, 0);
Vertex v4 = new Vertex(0, 4, 0);
LinearRing r = new LinearRing(LinearRingType.EXTERIOR);
p.setExteriorRing(r);
r.addVertex(v4);
r.addVertex(v0);
r.addVertex(v1);
r.addVertex(v2);
r.addVertex(v0);
r.addVertex(v3);
r.addVertex(v4);
DuplicatePointsCheck check = new DuplicatePointsCheck();
check.check(r);
CheckResult cr = r.getCheckResult(check);
assertNotNull(cr);
assertEquals(ResultStatus.ERROR, cr.getResultStatus());
assertEquals(ErrorId.GE_R_SELF_INTERSECTION, cr.getError().getErrorId());
HealRingSelfIntError healer = new HealRingSelfIntError();
cr.getError().accept(healer, TestUtil.createDummyModificationListener());
geom.updateEdgesAndVertices();
assertEquals(2, geom.getPolygons().size());
Polygon p1 = geom.getPolygons().get(0);
Polygon p2 = geom.getPolygons().get(1);
assertEquals(4, p1.getExteriorRing().getVertices().size());
assertEquals(4, p2.getExteriorRing().getVertices().size());
assertEquals(2, v0.getAdjacentRings(geom).size());
}
@Test
public void testDuplicatePoint3() throws CityGmlParseException, IOException, InvalidGmlFileException {
String path = "src/test/resources/SimpleSolid_SrefBS-GE-gml-LR-0002-T0002.gml";
ValidationConfiguration config = ValidationConfiguration.loadStandardValidationConfig();
CityDoctorModel model = TestUtil.loadCityModel(path, config);
Checker c = new Checker(config, model);
c.runChecks();
Geometry geom = model.getBuildings().get(0).getGeometries().get(0);
Assert.assertTrue(geom.containsError(CheckId.C_GE_R_SELF_INTERSECTION));
Healer healer = new Healer(c);
healer.healCityObject(model.getBuildings().get(0));
Assert.assertFalse(geom.containsError(CheckId.C_GE_R_SELF_INTERSECTION));
}
@Test
public void testIntersectingEdges2() throws CityGmlParseException, IOException, InvalidGmlFileException {
String path = "src/test/resources/SimpleSolid_SrefBS-GE-gml-LR-0004-T0004.gml";
ValidationConfiguration config = ValidationConfiguration.loadStandardValidationConfig();
CityDoctorModel model = TestUtil.loadCityModel(path, config);
Checker c = new Checker(config, model);
c.runChecks();
Geometry geom = model.getBuildings().get(0).getGeometries().get(0);
Assert.assertTrue(geom.containsError(CheckId.C_GE_R_SELF_INTERSECTION));
Healer healer = new Healer(c);
healer.healCityObject(model.getBuildings().get(0));
Assert.assertFalse(geom.containsError(CheckId.C_GE_R_SELF_INTERSECTION));
}
@Test
public void testTouchingVertex() throws CityGmlParseException, IOException, InvalidGmlFileException {
String path = "src/test/resources/SimpleSolid_SrefBS-GE-gml-LR-0004-T0005.gml";
ValidationConfiguration config = ValidationConfiguration.loadStandardValidationConfig();
config.setMinVertexDistanceInGlobalParameters(0.1);
config.setNumberOfRoundingPlacesInGlobalParameters(8);
CityDoctorModel model = TestUtil.loadCityModel(path, config);
Checker c = new Checker(config, model);
c.runChecks();
Geometry geom = model.getBuildings().get(0).getGeometries().get(0);
Assert.assertTrue(geom.containsError(CheckId.C_GE_R_SELF_INTERSECTION));
Healer healer = new Healer(c);
healer.healCityObject(model.getBuildings().get(0));
Assert.assertFalse(geom.containsError(CheckId.C_GE_R_SELF_INTERSECTION));
}
}
package de.hft.stuttgart.citydoctor2.healing;
import java.io.IOException;
import org.junit.Assert;
import org.junit.Test;
import de.hft.stuttgart.citydoctor2.check.CheckId;
import de.hft.stuttgart.citydoctor2.check.Checker;
import de.hft.stuttgart.citydoctor2.check.ValidationConfiguration;
import de.hft.stuttgart.citydoctor2.datastructure.CityDoctorModel;
import de.hft.stuttgart.citydoctor2.datastructure.Geometry;
import de.hft.stuttgart.citydoctor2.healer.Healer;
import de.hft.stuttgart.citydoctor2.parser.CityGmlParseException;
import de.hft.stuttgart.citydoctor2.parser.InvalidGmlFileException;
public class HealSameOrientationErrorTest {
@Test
public void testHealSameOrientationError1()
throws CityGmlParseException, IOException, InvalidGmlFileException {
String path = "src/test/resources/SimpleSolid_SrefBS-GE-gml-PO-0006-T0001.gml";
ValidationConfiguration config = ValidationConfiguration.loadStandardValidationConfig();
CityDoctorModel model = TestUtil.loadCityModel(path, config);
Checker c = new Checker(config, model);
c.runChecks();
Geometry geom = model.getBuildings().get(0).getGeometries().get(0);
Assert.assertTrue(geom.containsError(CheckId.C_GE_P_ORIENTATION_RINGS_SAME));
Healer healer = new Healer(c);
healer.healCityObject(model.getBuildings().get(0));
Assert.assertFalse(geom.containsError(CheckId.C_GE_P_ORIENTATION_RINGS_SAME));
}
}
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