Commit e53df320 authored by Luna Riegel's avatar Luna Riegel
Browse files

Feat: Implement feature collision check

parent aeb56f2e
......@@ -294,6 +294,15 @@ public class LinearRing extends GmlElement {
return false;
}
public List<Ray> getEdgeRays(){
List<Ray> rays = new ArrayList<>();
//First and last vertice are the same point
for(int i=0; i < vertices.size() - 1; i++){
rays.add(new Ray(vertices.get(i), new Vector3d(vertices.get(i+1)).minus(vertices.get(i))));
}
return rays;
}
public boolean hasPointAsCorner(Vertex v) {
return vertices.contains(v);
}
......
......@@ -2,18 +2,36 @@ package de.hft.stuttgart.citydoctor2.checks.topology;
import de.hft.stuttgart.citydoctor2.check.Check;
import de.hft.stuttgart.citydoctor2.check.CheckId;
import de.hft.stuttgart.citydoctor2.check.CheckResult;
import de.hft.stuttgart.citydoctor2.check.Checkable;
import de.hft.stuttgart.citydoctor2.check.CheckableUtilsVisitor;
import de.hft.stuttgart.citydoctor2.check.GlobalParameters;
import de.hft.stuttgart.citydoctor2.check.Requirement;
import de.hft.stuttgart.citydoctor2.check.RequirementType;
import de.hft.stuttgart.citydoctor2.check.ResultStatus;
import de.hft.stuttgart.citydoctor2.check.error.FeatureCollisionError;
import de.hft.stuttgart.citydoctor2.checks.Checks;
import de.hft.stuttgart.citydoctor2.checks.util.GeometryCollisionUtil;
import de.hft.stuttgart.citydoctor2.database.CityObjectCache;
import de.hft.stuttgart.citydoctor2.datastructure.BridgeObject;
import de.hft.stuttgart.citydoctor2.datastructure.Building;
import de.hft.stuttgart.citydoctor2.datastructure.CityFurniture;
import de.hft.stuttgart.citydoctor2.datastructure.CityObject;
import de.hft.stuttgart.citydoctor2.datastructure.GenericCityObject;
import de.hft.stuttgart.citydoctor2.datastructure.Geometry;
import de.hft.stuttgart.citydoctor2.datastructure.GmlId;
import de.hft.stuttgart.citydoctor2.datastructure.LinearRing;
import de.hft.stuttgart.citydoctor2.datastructure.OtherConstructionObject;
import de.hft.stuttgart.citydoctor2.datastructure.Polygon;
import de.hft.stuttgart.citydoctor2.datastructure.TopLevelTransportFeature;
import de.hft.stuttgart.citydoctor2.datastructure.Vegetation;
import de.hft.stuttgart.citydoctor2.edge.PolygonPolygonIntersection;
import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
......@@ -40,7 +58,6 @@ public class FeatureCollisionCheck extends Check{
}
@Override
public Set<Requirement> appliesToRequirements() {
return Set.of(Requirement.R_TO_FEATURE_COLLISION);
......@@ -71,11 +88,125 @@ public class FeatureCollisionCheck extends Check{
}
@Override
public void check(CityObject co){
public void check(BridgeObject bo) {
checkForFeatureCollisions(bo);
}
@Override
public void check(Building b) {
checkForFeatureCollisions(b);
}
@Override
public void check(TopLevelTransportFeature top) {
checkForFeatureCollisions(top);
}
@Override
public void check(Vegetation veg) {
checkForFeatureCollisions(veg);
}
@Override
public void check(CityFurniture cf) {
checkForFeatureCollisions(cf);
}
@Override
public void check(GenericCityObject gco) {
checkForFeatureCollisions(gco);
}
@Override
public void check(OtherConstructionObject oco) {
checkForFeatureCollisions(oco);
}
private void checkForFeatureCollisions(CityObject subject){
Collection<CityObject> candidates = cache.getCandidates(subject, epsilon);
List<Geometry> subjGeoms = new ArrayList<>();
subject.accept(new CheckableUtilsVisitor() {
@Override
public void check(Geometry geom) {
subjGeoms.add(geom);
}
});
List<CollisionRecord> collisions = new ArrayList<>();
subjGeoms.forEach(sGeo ->{
candidates.forEach(candidate ->{
candidate.accept(new CheckableUtilsVisitor() {
@Override
public void check(Geometry geom) {
List<PolygonPolygonIntersection> intersections =
GeometryCollisionUtil.getGeometryIntersections(sGeo, geom, epsilon);
if(!intersections.isEmpty()){
CollisionRecord collRec = new CollisionRecord(sGeo, geom, candidate);
intersections.forEach(ppi ->
collRec.addCollision(ppi.getPolygon1().getOriginal(), ppi.getPolygon2().getOriginal()));
collisions.add(collRec);
}
}
});
});
});
if(collisions.isEmpty()){
subject.addCheckResult(new CheckResult(this, ResultStatus.OK,null));
} else {
for(CollisionRecord collRec : collisions){
subject.addCheckResult(new CheckResult(this, ResultStatus.ERROR,
new FeatureCollisionError(
subject, collRec.getSubjectGeom(), collRec.getCollidingFeatureId(), collRec.getCollidingGeom(),
collRec.getCollisionMap())
));
}
}
}
private static class CollisionRecord{
private final Geometry subjectGeom;
private final Geometry collidingGeom;
private final GmlId collidingFeatureId;
private final Map<Polygon, List<Polygon>> collisionMap;
public CollisionRecord(Geometry subjectGeom, Geometry collidingGeom, CityObject collidingFeature){
this.subjectGeom = subjectGeom;
this.collidingGeom = collidingGeom;
this.collidingFeatureId = collidingFeature.getGmlId();
this.collisionMap = new HashMap<>();
}
public void addCollision(Polygon subjectPoly, Polygon collidingPoly){
List<Polygon> polyList = collisionMap.computeIfAbsent(subjectPoly, k -> new ArrayList<>());
polyList.add(collidingPoly);
}
public Map<Polygon, List<Polygon>> getCollisionMap() {
return collisionMap;
}
public Geometry getSubjectGeom() {
return subjectGeom;
}
public Geometry getCollidingGeom() {
return collidingGeom;
}
public GmlId getCollidingFeatureId() {
return collidingFeatureId;
}
}
@Override
public Check createNewInstance() {
return new FeatureCollisionCheck();
......
package de.hft.stuttgart.citydoctor2.checks.util;
import de.hft.stuttgart.citydoctor2.datastructure.ConcretePolygon;
import de.hft.stuttgart.citydoctor2.datastructure.Geometry;
import de.hft.stuttgart.citydoctor2.datastructure.Polygon;
import de.hft.stuttgart.citydoctor2.datastructure.Vertex;
import de.hft.stuttgart.citydoctor2.edge.CDPolygonNs;
import de.hft.stuttgart.citydoctor2.edge.IntersectPlanarPolygons;
import de.hft.stuttgart.citydoctor2.edge.MeshSurface;
import de.hft.stuttgart.citydoctor2.edge.PolygonPolygonIntersection;
import de.hft.stuttgart.citydoctor2.math.Ray;
import de.hft.stuttgart.citydoctor2.math.Vector3d;
import java.util.ArrayList;
import java.util.List;
public class GeometryCollisionUtil {
public static boolean doPolygonsCollide(Polygon subjectPoly, Polygon candidatePoly, double samePointTolerance){
ConcretePolygon subject = subjectPoly.getOriginal();
ConcretePolygon candidate = candidatePoly.getOriginal();
for (Ray ray : subject.getExteriorRing().getEdgeRays()){
Vector3d intersection = ray.intersectsPolygon(candidate);
if (intersection != null){
Vertex nearestVertex = findClosestVertexToIntersection(intersection, candidate);
if(nearestVertex.getDistance(intersection) < samePointTolerance){
continue;
}
return true;
}
}
return false;
}
public static List<PolygonPolygonIntersection> getGeometryIntersections(Geometry subject, Geometry candidate, double samePointTolerance){
MeshSurface subjectMesh = MeshSurface.of(subject);
MeshSurface candidateMesh = MeshSurface.of(candidate);
List<PolygonPolygonIntersection> intersections = new ArrayList<>();
for (CDPolygonNs subjPoly: subjectMesh.polygons()){
for (CDPolygonNs candPoly: candidateMesh.polygons()){
intersections = IntersectPlanarPolygons.intersectPolygons(subjPoly,candPoly, samePointTolerance, 0.001);
intersections = intersections.stream()
.filter(ppi ->
!ppi.getPolyLine().isNullLine(samePointTolerance))
.toList();
}
}
return intersections;
}
public static Vertex findClosestVertexToIntersection(Vector3d intersection, ConcretePolygon poly){
List<Vertex> vertices = poly.getExteriorRing().getVertices();
double min = Double.MAX_VALUE;
Vertex closestVertex = null;
for(Vertex vertex : vertices){
if(vertex.getDistance(intersection) < min){
closestVertex = vertex;
min = vertex.getDistance(intersection);
}
}
return closestVertex;
}
}
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