Commit 0c03ab39 authored by Numanoglu's avatar Numanoglu
Browse files

Orienation corrected, simplified and getter added

parent 82126347
Pipeline #12428 failed with stage
in 88 minutes and 25 seconds
......@@ -6,21 +6,11 @@ import de.hft.stuttgart.citydoctor2.math.Plane;
import de.hft.stuttgart.citydoctor2.math.UnitVector3d;
import de.hft.stuttgart.citydoctor2.math.Vector3d;
enum SweepIntersectionPosition {
ON_EDGE,
BEFORE_SWEEP_VERTEX,
BEYOND_OUTGOING_EDGE_TARGET,
UNKNOWN
}
public class SweepEdge {
private Edge outgoingEdge;
private Vertex sweepVertex;
private Vertex outgoingEdgeTarget;
private Vector3d referencePoint;
private UnitVector3d direction;
private double outgoingEdgeLength;
private boolean valid = false;
public SweepEdge(Edge outgoingEdge, Vertex sweepVertex, double minSweepEdgeLength) {
......@@ -29,22 +19,19 @@ public class SweepEdge {
return;
}
Vertex outgoingEdgeTarget = outgoingEdge.getOppositeVertex(sweepVertex);
if (outgoingEdgeTarget == null) {
Vertex referencePoint = outgoingEdge.getOppositeVertex(sweepVertex);
if (referencePoint == null) {
return;
}
Vector3d edgeVector = outgoingEdgeTarget.minus(sweepVertex);
Vector3d edgeVector = sweepVertex.minus(referencePoint);
if (edgeVector.getLength() < minSweepEdgeLength) {
return;
}
this.outgoingEdge = outgoingEdge;
this.sweepVertex = sweepVertex;
this.outgoingEdgeTarget = outgoingEdgeTarget;
this.referencePoint = sweepVertex;
this.referencePoint = referencePoint;
this.direction = edgeVector.normalize();
this.outgoingEdgeLength = edgeVector.getLength();
this.valid = true;
}
......@@ -91,30 +78,25 @@ public class SweepEdge {
return true;
}
//------------------------------------------------------------------------------------------------------
// Nicht mehr notwendig wegen Position- Flags- -nur noch Konfort
public boolean isOnEdge (Vector3d intersectionPoint, double eps) {
return classifyIntersectionPosition(intersectionPoint, eps) == SweepIntersectionPosition.ON_EDGE;
}
//-------------------------------------------------------------------------------------------------------
public SweepIntersectionPosition classifyIntersectionPosition(Vector3d intersectionPoint, double eps) {
public boolean isSweepableEdge(Vector3d intersectionPoint, double eps) {
if (!valid || intersectionPoint == null) {
return SweepIntersectionPosition.UNKNOWN;
return false;
}
Vector3d sweepToIntersection = intersectionPoint.minus(sweepVertex);
double lineParameter = sweepToIntersection.dot(direction);
Vector3d referenceToIntersection = intersectionPoint.minus(referencePoint);
double lineParameter = referenceToIntersection.dot(direction);
if (lineParameter < -eps) {
return SweepIntersectionPosition.BEFORE_SWEEP_VERTEX;
}
if (lineParameter > outgoingEdgeLength + eps) {
return SweepIntersectionPosition.BEYOND_OUTGOING_EDGE_TARGET;
}
return SweepIntersectionPosition.ON_EDGE;
/*
* Die Kante ist aus Sicht des festen Bezugspunkts zur urspruenglichen
* Position des Sweep-Punktes gerichtet.
*
* lineParameter zwischen 0 und der urspruenglichen Kantenlaenge bedeutet
* Verkuerzen. Ein groesserer lineParameter bedeutet Verlaengern.
* lineParameter kleiner eps liegt vor oder zu nah am Bezugspunkt und wird
* nicht als regulaerer Fall-2-Sweep behandelt.
*/
return lineParameter >= eps;
}
Edge getOutgoingEdge() {
......
......@@ -2,55 +2,31 @@ package de.hft.stuttgart.citydoctor2.healing;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.Collections;
import java.util.HashSet;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import de.hft.stuttgart.citydoctor2.check.ModificationListener;
import de.hft.stuttgart.citydoctor2.check.error.NonPlanarPolygonDistancePlaneError;
import de.hft.stuttgart.citydoctor2.datastructure.LinearRing;
import de.hft.stuttgart.citydoctor2.datastructure.Polygon;
import de.hft.stuttgart.citydoctor2.datastructure.Vertex;
import de.hft.stuttgart.citydoctor2.math.Plane;
import de.hft.stuttgart.citydoctor2.math.Vector3d;
/* todo: in HealPlanarPolygonSweep visit-Methode austauschen
public boolean visit(NonPlanarPolygonDistancePlaneError err, ModificationListener l) {
logger.debug("Executing Repair for NonPlanarPolygonDistancePlaneError");
SweepUtilities utils = new SweepUtilities(err);
todo: Epsilon-Werte setzen
utils.initialize();
if ( utils.calculate() ) {
utils.doHeal();
return true;
}
else {
logger.debug("Repair by Sweep not possible");
return false;
}
}
*/
public class SweepUtilities {
private static final Logger logger = LogManager.getLogger(SweepUtilities.class);
private Plane targetPlane;
private Polygon pol;
//todo: weitere Attribute hinzufuegen (fuer collectOutgoingEdges, ...)
private Polygon errorPolygon;
// todo: Toleranzen passend initialisieren
private double minSweepEdgeLength = 0.001; // Mindestlaenge einer Kante
private double maxPointPlaneDistance = 0.001; // Maximalabstand zur Ebene
// TODO Transformiere mit arcsin() um dem Nenner den kompl.Winkel zuzuordnen
private double minLinePlaneAngleRatio = 0.001; // MindestNeigung: vgl. <EbenenenNormale,GeradenRichtVektor>
private List<SweepVertex> verts;
private List<SweepVertex> sweepVertices;
public SweepUtilities(NonPlanarPolygonDistancePlaneError err) {
......@@ -59,25 +35,25 @@ public class SweepUtilities {
}
targetPlane = err.getPlane();
pol = err.getPolygon();
errorPolygon = err.getPolygon();
}
public void initialize() {
if (pol == null || targetPlane == null) {
if (errorPolygon == null || targetPlane == null) {
logger.error("Cannot initialize sweep: polygon or target plane is null");
verts = null;
sweepVertices = null;
return;
}
int nVerts = countSweepVertices(pol);
verts = new ArrayList<>(nVerts);// <Vertex>??
int nVerts = countSweepVertices(errorPolygon);
sweepVertices = new ArrayList<>(nVerts);// <Vertex>??
collectSweepVertices(pol);
collectSweepVertices(errorPolygon);
for (SweepVertex v : verts) {
v.collectOutgoingEdges(pol, minSweepEdgeLength);
for (SweepVertex v : sweepVertices) {
v.collectOutgoingEdges(errorPolygon, minSweepEdgeLength);
v.initStatus(targetPlane, maxPointPlaneDistance);
}
......@@ -85,7 +61,7 @@ public class SweepUtilities {
public boolean calculate() {
if (verts == null || targetPlane == null) {
if (sweepVertices == null || targetPlane == null) {
return false;
}
......@@ -106,8 +82,8 @@ public class SweepUtilities {
}
*/
for (SweepVertex v : verts) {
v.calculateNewPoint(targetPlane, pol, minSweepEdgeLength, minLinePlaneAngleRatio);
for (SweepVertex v : sweepVertices) {
v.calculateNewPoint(targetPlane, errorPolygon, minSweepEdgeLength, minLinePlaneAngleRatio);
}
return canHeal();
......@@ -120,14 +96,14 @@ public class SweepUtilities {
return;
}
for (SweepVertex v : verts) {
for (SweepVertex v : sweepVertices) {
v.doHeal();
}
}
private boolean canHeal() {
for (SweepVertex v : verts) {
for (SweepVertex v : sweepVertices) {
SweepVertexStatus status = v.getStatus();
switch (status) {
case ON_PLANE:
......@@ -148,7 +124,7 @@ public class SweepUtilities {
private boolean hasErrorStatus() {
for (SweepVertex v : verts) {
for (SweepVertex v : sweepVertices) {
SweepVertexStatus status = v.getStatus();
if (status == SweepVertexStatus.ERROR || status == SweepVertexStatus.NONE) {
return true;
......@@ -173,7 +149,7 @@ public class SweepUtilities {
if (ring == null) {
return 0;
}
return Math.max(0, ring.getVertices().size() - 1); //redundande übervorsicht
return Math.max(0, ring.getVertices().size() - 1); //redundante übervorsicht
}
private void collectSweepVertices(Polygon p) {
......@@ -191,9 +167,12 @@ public class SweepUtilities {
}
List<Vertex> vertices = ring.getVertices();
for (int i = 0; i < vertices.size() - 1; i++) {
verts.add(new SweepVertex(vertices.get(i)));
sweepVertices.add(new SweepVertex(vertices.get(i)));
}
}
public List<SweepVertex> getSweepVertices(){
return sweepVertices;
}
}
......@@ -27,25 +27,25 @@ public class SweepVertex {
private SweepVertexStatus status = SweepVertexStatus.NONE;
private Vertex vert;
private Vertex sweepVertex;
private Vector3d newPoint;
private List<Edge> outgoingEdges = new LinkedList<>();
private List<Edge> outgoingEdges = new LinkedList<>();// TODO ?ist diese Zuweisung stabil?
public SweepVertex(Vertex v) {
vert = v;
sweepVertex = v;
}
public void collectOutgoingEdges(Polygon pol, double minSweepEdgeLength) {
public void collectOutgoingEdges(Polygon errorPoly, double minSweepEdgeLength) {
outgoingEdges.clear();
if (pol == null || vert == null) {
if (errorPoly == null || sweepVertex == null) {
logger.error("Cannot collect outgoing edges: polygon or vertex is null");
status = SweepVertexStatus.ERROR;
return;
}
Geometry geometry = pol.getParent();
Geometry geometry = errorPoly.getParent();
if (geometry == null) {
logger.error("Cannot collect outgoing edges: polygon has no parent geometry");
status = SweepVertexStatus.ERROR;
......@@ -55,8 +55,8 @@ public class SweepVertex {
geometry.updateEdgesAndVertices();
}
for (Edge edge : geometry.getEdgesAdjacentTo(vert)) {
if (edge.getAdjacentPolygons().contains(pol)) {
for (Edge edge : geometry.getEdgesAdjacentTo(sweepVertex)) {
if (edge.getAdjacentPolygons().contains(errorPoly)) {
continue;
}
if (edge.getFrom().getDistance(edge.getTo()) < minSweepEdgeLength) {
......@@ -70,15 +70,15 @@ public class SweepVertex {
public void initStatus (Plane targetPlane, double maxPointPlaneDistance) {
if (targetPlane == null || vert == null) {
if (targetPlane == null || sweepVertex == null) {
status = SweepVertexStatus.ERROR;
return;
}
if ( targetPlane.getDistance(vert) < maxPointPlaneDistance ) {
if ( targetPlane.getDistance(sweepVertex) < maxPointPlaneDistance ) {
status = SweepVertexStatus.ON_PLANE;
}
else if ( outgoingEdges.size() < 1 ) {
else if ( outgoingEdges.size() == 0 ) {
status = SweepVertexStatus.PROJECT;
}
/*
......@@ -119,7 +119,7 @@ public class SweepVertex {
newPoint = null;
if (targetPlane == null || vert == null) {
if (targetPlane == null || sweepVertex == null) {
status = SweepVertexStatus.ERROR;
return;
}
......@@ -129,7 +129,7 @@ public class SweepVertex {
return;
case PROJECT:
newPoint = targetPlane.projectPointToPlane(vert);
newPoint = targetPlane.projectPointToPlane(sweepVertex);
if (newPoint == null) {
status = SweepVertexStatus.ERROR;
}
......@@ -147,7 +147,7 @@ public class SweepVertex {
return;
}
SweepEdge sweepEdge = new SweepEdge(outgoingEdge, vert, minSweepEdgeLength);
SweepEdge sweepEdge = new SweepEdge(outgoingEdge, sweepVertex, minSweepEdgeLength);
if (!sweepEdge.valid()) {
status = SweepVertexStatus.ERROR;
return;
......@@ -159,26 +159,14 @@ public class SweepVertex {
return;
}
SweepIntersectionPosition position = sweepEdge.classifyIntersectionPosition(intersectionPoint, minSweepEdgeLength);
switch (position) {
case ON_EDGE:
case BEYOND_OUTGOING_EDGE_TARGET:
/*
* Fall 2 nach Piepereit:
* Auf der Kante bedeutet Verkuerzen, hinter dem Kantenziel bedeutet
* Verlaengern. In beiden Faellen ist der Schnittpunkt die neue Position
* des Sweep-Punktes.
*/
newPoint = intersectionPoint;
return;
case BEFORE_SWEEP_VERTEX:
case UNKNOWN:
default:
if (!sweepEdge.isSweepableEdge(intersectionPoint, minSweepEdgeLength)) {
status = SweepVertexStatus.ERROR;
return;
}
newPoint = intersectionPoint;
return;
case NONE:
case ERROR:
default:
......@@ -193,14 +181,14 @@ public class SweepVertex {
return;
}
if (vert == null || newPoint == null) {
if (sweepVertex == null || newPoint == null) {
status = SweepVertexStatus.ERROR;
return;
}
vert.setX(newPoint.getX());
vert.setY(newPoint.getY());
vert.setZ(newPoint.getZ());
sweepVertex.setX(newPoint.getX());
sweepVertex.setY(newPoint.getY());
sweepVertex.setZ(newPoint.getZ());
}
public SweepVertexStatus getStatus () {
......@@ -208,7 +196,19 @@ public class SweepVertex {
return status;
}
public int getNoOutgoingEdges () {
public Vector3d getNewPoint() {
return newPoint;
}
public List<Edge> getOutgoingEdges(){
return outgoingEdges;
}
public Vertex getSweepVertex() {
return sweepVertex;
}
public int countOutgoingEdges () {
return outgoingEdges.size();
}
......
......@@ -18,10 +18,15 @@ public class SweepUtilitiesSyntheticTest {
private static final double EPS = 0.000001;
/**
* Fall 1: Ein Punkt eines Fenster-Innenrings steht aus der Wandebene x = 0
* heraus. Da keine abführende Kante , muss er orthogonal auf die
* Zielebene projiziert werden.
*/
@Test
public void repairsCase1ByOrthogonalProjection() {
Building building = SyntheticSweepPlanarityModelFactory.createWallWithProtrudingWindowInnerRingPoint();
Polygon sweepPolygon = getPolygon(building, 0);
Polygon sweepPolygon = getPolygonAtIndex(building, 0);
Vertex protrudingPoint = sweepPolygon.getInnerRings().get(0).getVertices().get(2);
Plane targetPlane = wallPlaneX0();
......@@ -33,10 +38,15 @@ public class SweepUtilitiesSyntheticTest {
assertEquals(0, targetPlane.getDistance(protrudingPoint), EPS);
}
/**
* Fall 2, Verkürzen: Der Schnitt mit x = 0 liegt zwischen referencePoint und
* ursprünglichem Sweep-Punkt. Der Sweep-Punkt bewegt sich also auf der
* bestehenden abführenden Kante zurück.
*/
@Test
public void repairsCase2WhenOutgoingEdgeIsShortened() {
Building building = SyntheticSweepPlanarityModelFactory.createSweepCase2ShorteningEdge();
Polygon sweepPolygon = getPolygon(building, 0);
Polygon sweepPolygon = getPolygonAtIndex(building, 0);
Vertex sweepPoint = sweepPolygon.getExteriorRing().getVertices().get(1);
Plane targetPlane = wallPlaneX0();
......@@ -48,10 +58,14 @@ public class SweepUtilitiesSyntheticTest {
assertEquals(0, targetPlane.getDistance(sweepPoint), EPS);
}
/**
* Fall 2, Verlängern: Der Schnitt mit x = 0 liegt hinter dem ursprünglichen
* Sweep-Punkt. Die abführende Kante wird dadurch in Sweep-Richtung verlängert.
*/
@Test
public void repairsCase2WhenOutgoingEdgeIsExtended() {
Building building = SyntheticSweepPlanarityModelFactory.createSweepCase2ExtendingEdge();
Polygon sweepPolygon = getPolygon(building, 0);
Polygon sweepPolygon = getPolygonAtIndex(building, 0);
Vertex sweepPoint = sweepPolygon.getExteriorRing().getVertices().get(1);
Plane targetPlane = wallPlaneX0();
......@@ -63,10 +77,15 @@ public class SweepUtilitiesSyntheticTest {
assertEquals(0, targetPlane.getDistance(sweepPoint), EPS);
}
/**
* Fehlerfall: Der Schnitt mit x = 0 liegt vor oder zu nah am referencePoint.
* Vgl. rote Bereich aus der Skizze vom Margitta ist (vorerst?) nicht
* sweepbar.
*/
@Test
public void rejectsCase2WhenIntersectionIsBeforeSweepVertex() {
Building building = SyntheticSweepPlanarityModelFactory.createSweepCase2IntersectionBeforeSweepVertex();
Polygon sweepPolygon = getPolygon(building, 0);
public void rejectsCase2WhenIntersectionIsBeforeReferencePoint() {
Building building = SyntheticSweepPlanarityModelFactory.createSweepCase2IntersectionBeforeReferencePoint();
Polygon sweepPolygon = getPolygonAtIndex(building, 0);
Vertex sweepPoint = sweepPolygon.getExteriorRing().getVertices().get(1);
assertFalse(runSweep(sweepPolygon, wallPlaneX0()));
......@@ -74,10 +93,14 @@ public class SweepUtilitiesSyntheticTest {
assertEquals(1, sweepPoint.getX(), EPS);
}
/**
* Fehlerfall: Die abführende Kante verläuft parallel zur Zielebene x = 0.
* Dann gibt es keinen stabilen eindeutigen Schnittpunkt für Fall 2.
*/
@Test
public void rejectsCase2WhenOutgoingEdgeIsParallelToTargetPlane() {
Building building = SyntheticSweepPlanarityModelFactory.createSweepCase2ParallelOutgoingEdge();
Polygon sweepPolygon = getPolygon(building, 0);
Polygon sweepPolygon = getPolygonAtIndex(building, 0);
Vertex sweepPoint = sweepPolygon.getExteriorRing().getVertices().get(1);
assertFalse(runSweep(sweepPolygon, wallPlaneX0()));
......@@ -97,7 +120,7 @@ public class SweepUtilitiesSyntheticTest {
return true;
}
private Polygon getPolygon(Building building, int index) {
private Polygon getPolygonAtIndex(Building building, int index) {
Geometry geometry = building.getGeometries().get(0);
return geometry.getPolygons().get(index);
}
......
......@@ -220,18 +220,19 @@ public class SyntheticSweepPlanarityModelFactory {
/**
* Fall 2 model: the faulty sweep point has exactly one outgoing edge. The target
* plane x = 0 lies behind the outgoing edge target, so the edge is extended.
* plane x = 0 lies behind the original sweep point, so the edge is extended.
*/
static Building createSweepCase2ExtendingEdge() {
return createSweepCase2SingleOutgoingEdge(new Vertex(0.5, 1, 0));
return createSweepCase2SingleOutgoingEdge(new Vertex(2, 1, 0));
}
/**
* Fall 2 error model: the line through the outgoing edge hits the target plane
* before the sweep point. The current sweep implementation rejects this case.
* before or too close to the reference point. The current sweep implementation
* rejects this case.
*/
static Building createSweepCase2IntersectionBeforeSweepVertex() {
return createSweepCase2SingleOutgoingEdge(new Vertex(2, 1, 0));
static Building createSweepCase2IntersectionBeforeReferencePoint() {
return createSweepCase2SingleOutgoingEdge(new Vertex(0.5, 1, 0));
}
/**
......
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