Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
CityDoctor
CityDoctor2
Commits
5a5d8118
Commit
5a5d8118
authored
Aug 03, 2026
by
Numanoglu
Browse files
WIP preserve sweep branch work
parent
a0a195e2
Changes
6
Show whitespace changes
Inline
Side-by-side
CityDoctorParent/Extensions/CityDoctorHealer/src/main/java/de/hft/stuttgart/citydoctor2/healing/HealPlanarPolygonSweep.java
View file @
5a5d8118
...
@@ -7,23 +7,58 @@ import de.hft.stuttgart.citydoctor2.check.HealingID;
...
@@ -7,23 +7,58 @@ import de.hft.stuttgart.citydoctor2.check.HealingID;
import
de.hft.stuttgart.citydoctor2.check.HealingMethod
;
import
de.hft.stuttgart.citydoctor2.check.HealingMethod
;
import
de.hft.stuttgart.citydoctor2.check.ModificationListener
;
import
de.hft.stuttgart.citydoctor2.check.ModificationListener
;
import
de.hft.stuttgart.citydoctor2.check.error.NonPlanarPolygonDistancePlaneError
;
import
de.hft.stuttgart.citydoctor2.check.error.NonPlanarPolygonDistancePlaneError
;
import
de.hft.stuttgart.citydoctor2.math.Plane
;
import
de.hft.stuttgart.citydoctor2.math.Vector3d
;
public
class
HealPlanarPolygonSweep
implements
HealingMethod
{
public
class
HealPlanarPolygonSweep
implements
HealingMethod
{
private
static
final
Logger
logger
=
LogManager
.
getLogger
(
HealPlanarPolygonSweep
.
class
);
private
static
final
Logger
logger
=
LogManager
.
getLogger
(
HealPlanarPolygonSweep
.
class
);
/* 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;
}
}
*/
// todo : dann entferne Dummy
@Override
@Override
public
boolean
visit
(
NonPlanarPolygonDistancePlaneError
err
,
ModificationListener
l
)
{
public
boolean
visit
(
NonPlanarPolygonDistancePlaneError
err
,
ModificationListener
l
)
{
logger
.
debug
(
"Executing Repair for NonPlanarPolygonDistancePlaneError"
);
logger
.
debug
(
"Executing Repair for NonPlanarPolygonDistancePlaneError"
);
Plane
plane
=
Plane
.
of
(
err
.
getPolygon
());
if
(
err
==
null
)
{
plane
.
getDistance
(
new
Vector3d
(
5
,
5
,
5
));
logger
.
error
(
"Cannot execute sweep repair: error is null"
);
return
false
;
}
if
(
err
.
getPlane
()
==
null
)
{
logger
.
error
(
"Cannot execute sweep repair: target plane is null"
);
return
false
;
}
if
(
err
.
getPolygon
()
==
null
)
{
logger
.
error
(
"Cannot execute sweep repair: polygon is null"
);
return
false
;
}
SweepUtilities
utils
=
new
SweepUtilities
(
err
);
utils
.
initialize
();
if
(
utils
.
calculate
())
{
utils
.
doHeal
();
return
true
;
return
true
;
}
}
logger
.
debug
(
"Repair by Sweep not possible"
);
return
false
;
}
@Override
@Override
public
HealPlanarPolygonSweep
createNew
()
{
public
HealPlanarPolygonSweep
createNew
()
{
return
new
HealPlanarPolygonSweep
();
return
new
HealPlanarPolygonSweep
();
...
...
CityDoctorParent/Extensions/CityDoctorHealer/src/main/java/de/hft/stuttgart/citydoctor2/healing/SweepEdge.java
View file @
5a5d8118
package
de.hft.stuttgart.citydoctor2.healing
;
package
de.hft.stuttgart.citydoctor2.healing
;
import
de.hft.stuttgart.citydoctor2.datastructure.Edge
;
import
de.hft.stuttgart.citydoctor2.datastructure.Edge
;
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.Plane
;
import
de.hft.stuttgart.citydoctor2.math.UnitVector3d
;
import
de.hft.stuttgart.citydoctor2.math.Vector3d
;
import
de.hft.stuttgart.citydoctor2.math.Vector3d
;
enum
SweepIntersectionPosition
{
ON_EDGE
,
BEFORE_SWEEP_VERTEX
,
BEYOND_OUTGOING_EDGE_TARGET
,
UNKNOWN
}
public
class
SweepEdge
{
public
class
SweepEdge
{
private
Edge
edge
;
private
Edge
outgoingEdge
;
private
Vector3d
refPt
;
private
Vertex
sweepVertex
;
private
Vector3d
dir
;
//todo: falls es eine extra Klasse für einheitsvektoren gibt, diese Klasse benutzen
private
Vertex
outgoingEdgeTarget
;
boolean
bValid
=
false
;
private
Vector3d
referencePoint
;
private
UnitVector3d
direction
;
private
double
outgoingEdgeLength
;
private
boolean
valid
=
false
;
public
SweepEdge
(
Edge
outgoingEdge
,
Vertex
sweepVertex
,
double
minSweepEdgeLength
)
{
public
SweepEdge
(
Edge
e
,
Polygon
p
,
double
epsPointDist
)
{
if
(
outgoingEdge
==
null
||
sweepVertex
==
null
)
{
return
;
}
edge
=
e
;
Vertex
outgoingEdgeTarget
=
outgoingEdge
.
getOppositeVertex
(
sweepVertex
);
//todo: falls geschickter --> Ring statt Polygon uebergeben
if
(
outgoingEdgeTarget
==
null
)
{
return
;
}
//todo: Wenn die Kante nicht zu kurz ist (epsPointDist)
Vector3d
edgeVector
=
outgoingEdgeTarget
.
minus
(
sweepVertex
);
// --> Anfangs- oder Endpunkt als Referenzpunkt, je nachdem welcher Punkt zum Polygon gehoert
if
(
edgeVector
.
getLength
()
<
minSweepEdgeLength
)
{
// --> Richtungsvektor dir als Einheitsvektor berechnen
return
;
// --> valid = true;
}
this
.
outgoingEdge
=
outgoingEdge
;
this
.
sweepVertex
=
sweepVertex
;
this
.
outgoingEdgeTarget
=
outgoingEdgeTarget
;
this
.
referencePoint
=
sweepVertex
;
this
.
direction
=
edgeVector
.
normalize
();
this
.
outgoingEdgeLength
=
edgeVector
.
getLength
();
this
.
valid
=
true
;
}
}
public
boolean
valid
()
{
public
boolean
valid
()
{
return
bValid
;
return
valid
;
}
public
Vector3d
intersection
(
Plane
plane
,
double
minLinePlaneAngleRatio
)
{
if
(!
hasIntersectionPoint
(
plane
,
minLinePlaneAngleRatio
))
{
return
null
;
}
}
public
boolean
intersection
(
Plane
plane
,
Vector3d
ipt
,
double
eps
)
{
double
denominator
=
plane
.
getNormal
().
dot
(
direction
);
//todo: Schnittpunkt berechnen
double
lineParameter
=
(
plane
.
getD
()
-
plane
.
getNormal
().
dot
(
referencePoint
))
/
denominator
;
return
referencePoint
.
plus
(
direction
.
mult
(
lineParameter
));
}
public
boolean
hasIntersectionPoint
(
Plane
plane
,
double
minLinePlaneAngleRatio
)
{
if
(!
valid
||
plane
==
null
)
{
return
false
;
return
false
;
}
}
public
boolean
isOnEdge
(
Vector3d
pt
)
{
double
denominator
=
plane
.
getNormal
().
dot
(
direction
);
return
Math
.
abs
(
denominator
)
>=
minLinePlaneAngleRatio
;
}
public
boolean
intersection
(
Plane
plane
,
Vector3d
intersectionPoint
,
double
minLinePlaneAngleRatio
)
{
//todo: pruefen ob pt zwischen Anfangs- und Endpunkt liegt
if
(
intersectionPoint
==
null
)
{
return
false
;
return
false
;
}
}
Vector3d
point
=
intersection
(
plane
,
minLinePlaneAngleRatio
);
if
(
point
==
null
)
{
return
false
;
}
intersectionPoint
.
setX
(
point
.
getX
());
intersectionPoint
.
setY
(
point
.
getY
());
intersectionPoint
.
setZ
(
point
.
getZ
());
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
)
{
if
(!
valid
||
intersectionPoint
==
null
)
{
return
SweepIntersectionPosition
.
UNKNOWN
;
}
Vector3d
sweepToIntersection
=
intersectionPoint
.
minus
(
sweepVertex
);
double
lineParameter
=
sweepToIntersection
.
dot
(
direction
);
if
(
lineParameter
<
-
eps
)
{
return
SweepIntersectionPosition
.
BEFORE_SWEEP_VERTEX
;
}
if
(
lineParameter
>
outgoingEdgeLength
+
eps
)
{
return
SweepIntersectionPosition
.
BEYOND_OUTGOING_EDGE_TARGET
;
}
return
SweepIntersectionPosition
.
ON_EDGE
;
}
Edge
getOutgoingEdge
()
{
return
outgoingEdge
;
}
Vector3d
getReferencePoint
()
{
return
referencePoint
;
}
UnitVector3d
getDirection
()
{
return
direction
;
}
}
}
CityDoctorParent/Extensions/CityDoctorHealer/src/main/java/de/hft/stuttgart/citydoctor2/healing/SweepUtilities.java
View file @
5a5d8118
...
@@ -6,6 +6,9 @@ import java.util.Set;
...
@@ -6,6 +6,9 @@ import java.util.Set;
import
java.util.Collections
;
import
java.util.Collections
;
import
java.util.HashSet
;
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.ModificationListener
;
import
de.hft.stuttgart.citydoctor2.check.error.NonPlanarPolygonDistancePlaneError
;
import
de.hft.stuttgart.citydoctor2.check.error.NonPlanarPolygonDistancePlaneError
;
import
de.hft.stuttgart.citydoctor2.datastructure.LinearRing
;
import
de.hft.stuttgart.citydoctor2.datastructure.LinearRing
;
...
@@ -35,20 +38,26 @@ import de.hft.stuttgart.citydoctor2.math.Vector3d;
...
@@ -35,20 +38,26 @@ import de.hft.stuttgart.citydoctor2.math.Vector3d;
public
class
SweepUtilities
{
public
class
SweepUtilities
{
private
static
final
Logger
logger
=
LogManager
.
getLogger
(
SweepUtilities
.
class
);
private
Plane
targetPlane
;
private
Plane
targetPlane
;
private
Polygon
pol
;
private
Polygon
pol
;
//todo: weitere Attribute hinzufuegen (fuer collectOutgoingEdges, ...)
//todo: weitere Attribute hinzufuegen (fuer collectOutgoingEdges, ...)
// todo:
Epsilons
passend initialisieren
// todo:
Toleranzen
passend initialisieren
private
double
epsPointDist
=
0.001
;
//Mindestlaenge einer Kante
private
double
minSweepEdgeLength
=
0.001
;
//
Mindestlaenge einer Kante
private
double
eps
PlaneDist
=
0.001
;
//Maximalabstand zur Ebene
private
double
maxPoint
PlaneDist
ance
=
0.001
;
//
Maximalabstand zur Ebene
private
double
epsIntersec
tio
n
=
0.001
;
//Epsilon fuer Winkel zwischen Kante und Ebene
private
double
minLinePlaneAngleRa
tio
=
0.001
;
// MindestNeigung: vgl. <EbenenenNormale,GeradenRichtVektor>
private
List
<
SweepVertex
>
verts
;
private
List
<
SweepVertex
>
verts
;
public
SweepUtilities
(
NonPlanarPolygonDistancePlaneError
err
)
{
public
SweepUtilities
(
NonPlanarPolygonDistancePlaneError
err
)
{
if
(
err
==
null
)
{
return
;
}
targetPlane
=
err
.
getPlane
();
targetPlane
=
err
.
getPlane
();
pol
=
err
.
getPolygon
();
pol
=
err
.
getPolygon
();
...
@@ -56,46 +65,49 @@ public class SweepUtilities {
...
@@ -56,46 +65,49 @@ public class SweepUtilities {
public
void
initialize
()
{
public
void
initialize
()
{
if
(
pol
==
null
||
targetPlane
==
null
)
{
logger
.
error
(
"Cannot initialize sweep: polygon or target plane is null"
);
verts
=
null
;
return
;
}
int
nVerts
=
countSweepVertices
(
pol
);
int
nVerts
=
countSweepVertices
(
pol
);
verts
=
new
ArrayList
<>(
nVerts
);
verts
=
new
ArrayList
<>(
nVerts
);
// <Vertex>??
collectSweepVertices
(
pol
);
collectSweepVertices
(
pol
);
for
(
SweepVertex
v
:
verts
)
{
for
(
SweepVertex
v
:
verts
)
{
v
.
collectOutgoingEdges
(
pol
/* todo: weitere Uebergabeparameter hinzufuegen */
,
epsPointDist
);
v
.
collectOutgoingEdges
(
pol
,
minSweepEdgeLength
);
v
.
initStatus
(
targetPlane
,
eps
PlaneDist
);
v
.
initStatus
(
targetPlane
,
maxPoint
PlaneDist
ance
);
}
}
}
}
public
boolean
calculate
()
{
public
boolean
calculate
()
{
// if there are no vertices --> no calculations
if
(
verts
==
null
||
targetPlane
==
null
)
{
if
(
null
==
verts
)
return
false
;
return
false
;
}
//if there is already an error vertex --> no calculations
if
(
hasErrorStatus
())
{
if
(
!
canHeal
()
)
return
false
;
return
false
;
}
boolean
bError
=
false
;
//todo spaeter: Anzahl der Ecken mit mehr als einer outging Edge zaehlen
//todo spaeter: Anzahl der Ecken mit mehr als einer outging Edge zaehlen
// Wenn es alle diese Ecken auf der Zielebene liegen --> weiter
// Wenn es alle diese Ecken auf der Zielebene liegen --> weiter
// Wenn es maximal drei solche Ecken gibt: Zielebene neu berechnen
// Wenn es maximal drei solche Ecken gibt: Zielebene neu berechnen
// Wenn es mehr als drei solche Ecken gibt: diese Ecken bekommen den ERROR-Status,
// Wenn es mehr als drei solche Ecken gibt: diese Ecken bekommen den ERROR-Status,
//
b
Error
= true;
//
has
Error
Status() verhindert danach das Heilen.
/*
/*
// If there is a new target plane, new initialization of status is necessary:
// If there is a new target plane, new initialization of status is necessary:
for (SweepVertex v : verts) {
for (SweepVertex v : verts) {
v.initStatus(targetPlane,
eps
PlaneDist);
v.initStatus(targetPlane,
maxPoint
PlaneDist
ance
);
}
}
*/
*/
if
(
!
bError
)
{
for
(
SweepVertex
v
:
verts
)
{
for
(
SweepVertex
v
:
verts
)
{
v
.
calculateNewPoint
(
targetPlane
,
pol
,
epsPointDist
);
v
.
calculateNewPoint
(
targetPlane
,
pol
,
minSweepEdgeLength
,
minLinePlaneAngleRatio
);
}
}
}
return
canHeal
();
return
canHeal
();
...
@@ -103,6 +115,11 @@ public class SweepUtilities {
...
@@ -103,6 +115,11 @@ public class SweepUtilities {
public
void
doHeal
()
{
public
void
doHeal
()
{
if
(!
canHeal
())
{
logger
.
error
(
"Cannot execute sweep heal: calculated sweep vertices are not healable"
);
return
;
}
for
(
SweepVertex
v
:
verts
)
{
for
(
SweepVertex
v
:
verts
)
{
v
.
doHeal
();
v
.
doHeal
();
}
}
...
@@ -112,23 +129,53 @@ public class SweepUtilities {
...
@@ -112,23 +129,53 @@ public class SweepUtilities {
for
(
SweepVertex
v
:
verts
)
{
for
(
SweepVertex
v
:
verts
)
{
SweepVertexStatus
status
=
v
.
getStatus
();
SweepVertexStatus
status
=
v
.
getStatus
();
if
(
SweepVertexStatus
.
ERROR
==
status
||
SweepVertexStatus
.
NONE
==
status
)
switch
(
status
)
{
case
ON_PLANE:
break
;
case
PROJECT:
case
SWEEP:
if
(!
v
.
hasNewPoint
())
return
false
;
return
false
;
break
;
case
NONE:
case
ERROR:
return
false
;
}
}
return
true
;
}
}
private
boolean
hasErrorStatus
()
{
for
(
SweepVertex
v
:
verts
)
{
SweepVertexStatus
status
=
v
.
getStatus
();
if
(
status
==
SweepVertexStatus
.
ERROR
||
status
==
SweepVertexStatus
.
NONE
)
{
return
true
;
return
true
;
}
}
}
return
false
;
}
private
int
countSweepVertices
(
Polygon
p
)
{
private
int
countSweepVertices
(
Polygon
p
)
{
int
nVerts
=
p
.
getExteriorRing
()
.
getVertices
().
size
(
);
int
nVerts
=
countSweepVertices
(
p
.
getExteriorRing
());
for
(
LinearRing
lr
:
p
.
getInnerRings
())
{
for
(
LinearRing
lr
:
p
.
getInnerRings
())
{
nVerts
+=
lr
.
get
Vertices
(
).
size
(
);
nVerts
+=
countSweep
Vertices
(
lr
);
}
}
return
nVerts
;
return
nVerts
;
}
}
private
int
countSweepVertices
(
LinearRing
ring
)
{
if
(
ring
==
null
)
{
return
0
;
}
return
Math
.
max
(
0
,
ring
.
getVertices
().
size
()
-
1
);
//redundande übervorsicht
}
private
void
collectSweepVertices
(
Polygon
p
)
{
private
void
collectSweepVertices
(
Polygon
p
)
{
collectSweepVertices
(
p
.
getExteriorRing
());
collectSweepVertices
(
p
.
getExteriorRing
());
...
@@ -139,8 +186,12 @@ public class SweepUtilities {
...
@@ -139,8 +186,12 @@ public class SweepUtilities {
private
void
collectSweepVertices
(
LinearRing
ring
)
{
private
void
collectSweepVertices
(
LinearRing
ring
)
{
for
(
Vertex
v
:
ring
.
getVertices
())
{
if
(
ring
==
null
)
{
verts
.
add
(
new
SweepVertex
(
v
));
return
;
}
List
<
Vertex
>
vertices
=
ring
.
getVertices
();
for
(
int
i
=
0
;
i
<
vertices
.
size
()
-
1
;
i
++)
{
verts
.
add
(
new
SweepVertex
(
vertices
.
get
(
i
)));
}
}
}
}
...
...
CityDoctorParent/Extensions/CityDoctorHealer/src/main/java/de/hft/stuttgart/citydoctor2/healing/SweepVertex.java
View file @
5a5d8118
...
@@ -3,8 +3,12 @@ package de.hft.stuttgart.citydoctor2.healing;
...
@@ -3,8 +3,12 @@ package de.hft.stuttgart.citydoctor2.healing;
import
java.util.LinkedList
;
import
java.util.LinkedList
;
import
java.util.List
;
import
java.util.List
;
import
org.apache.logging.log4j.LogManager
;
import
org.apache.logging.log4j.Logger
;
import
de.hft.stuttgart.citydoctor2.datastructure.Vertex
;
import
de.hft.stuttgart.citydoctor2.datastructure.Vertex
;
import
de.hft.stuttgart.citydoctor2.datastructure.Edge
;
import
de.hft.stuttgart.citydoctor2.datastructure.Edge
;
import
de.hft.stuttgart.citydoctor2.datastructure.Geometry
;
import
de.hft.stuttgart.citydoctor2.datastructure.Polygon
;
import
de.hft.stuttgart.citydoctor2.datastructure.Polygon
;
import
de.hft.stuttgart.citydoctor2.math.Plane
;
import
de.hft.stuttgart.citydoctor2.math.Plane
;
import
de.hft.stuttgart.citydoctor2.math.Vector3d
;
import
de.hft.stuttgart.citydoctor2.math.Vector3d
;
...
@@ -19,6 +23,8 @@ enum SweepVertexStatus {
...
@@ -19,6 +23,8 @@ enum SweepVertexStatus {
public
class
SweepVertex
{
public
class
SweepVertex
{
private
static
final
Logger
logger
=
LogManager
.
getLogger
(
SweepVertex
.
class
);
private
SweepVertexStatus
status
=
SweepVertexStatus
.
NONE
;
private
SweepVertexStatus
status
=
SweepVertexStatus
.
NONE
;
private
Vertex
vert
;
private
Vertex
vert
;
...
@@ -30,16 +36,46 @@ public class SweepVertex {
...
@@ -30,16 +36,46 @@ public class SweepVertex {
vert
=
v
;
vert
=
v
;
}
}
//todo: weitere Uebergabeparameter hinzufuegen
public
void
collectOutgoingEdges
(
Polygon
pol
,
double
minSweepEdgeLength
)
{
public
void
collectOutgoingEdges
(
Polygon
pol
/* todo: weitere Uebergabeparameter hinzufuegen */
,
double
epsPointDist
)
{
//todo: Liste outgoingEdges fuellen
outgoingEdges
.
clear
();
if
(
pol
==
null
||
vert
==
null
)
{
logger
.
error
(
"Cannot collect outgoing edges: polygon or vertex is null"
);
status
=
SweepVertexStatus
.
ERROR
;
return
;
}
Geometry
geometry
=
pol
.
getParent
();
if
(
geometry
==
null
)
{
logger
.
error
(
"Cannot collect outgoing edges: polygon has no parent geometry"
);
status
=
SweepVertexStatus
.
ERROR
;
return
;
}
if
(
geometry
.
getEdges
()
==
null
)
{
geometry
.
updateEdgesAndVertices
();
}
for
(
Edge
edge
:
geometry
.
getEdgesAdjacentTo
(
vert
))
{
if
(
edge
.
getAdjacentPolygons
().
contains
(
pol
))
{
continue
;
}
if
(
edge
.
getFrom
().
getDistance
(
edge
.
getTo
())
<
minSweepEdgeLength
)
{
logger
.
error
(
"Cannot collect outgoing edges: outgoing edge is shorter than minSweepEdgeLength"
);
status
=
SweepVertexStatus
.
ERROR
;
return
;
}
outgoingEdges
.
add
(
edge
);
}
}
}
public
void
initStatus
(
Plane
targetPlane
,
double
distPlaneEps
)
{
public
void
initStatus
(
Plane
targetPlane
,
double
maxPointPlaneDistance
)
{
if
(
targetPlane
.
getDistance
(
vert
)
<
distPlaneEps
)
{
if
(
targetPlane
==
null
||
vert
==
null
)
{
status
=
SweepVertexStatus
.
ERROR
;
return
;
}
if
(
targetPlane
.
getDistance
(
vert
)
<
maxPointPlaneDistance
)
{
status
=
SweepVertexStatus
.
ON_PLANE
;
status
=
SweepVertexStatus
.
ON_PLANE
;
}
}
else
if
(
outgoingEdges
.
size
()
<
1
)
{
else
if
(
outgoingEdges
.
size
()
<
1
)
{
...
@@ -55,38 +91,117 @@ public class SweepVertex {
...
@@ -55,38 +91,117 @@ public class SweepVertex {
*/
*/
else
if
(
outgoingEdges
.
size
()
==
1
)
else
if
(
outgoingEdges
.
size
()
==
1
)
status
=
SweepVertexStatus
.
SWEEP
;
status
=
SweepVertexStatus
.
SWEEP
;
else
else
{
/*
* Fall 3 nach Piepereit:
* Mehr als eine abführende Kante darf später nicht pauschal fehlschlagen.
* Zuerst müssen die abführenden Kanten nach Sweep-Richtung klassifiziert
* werden: negativ bedeutet, die Kante würde verkürzt; positiv bedeutet, die
* Kante würde verlängert.
*
* Geplante Aufteilung:
* - nur negative Kanten: Split-Cut, Vertex vervielfältigen und Kanten auf
* die Kopien verteilen.
* - nur positive Kanten: Split-Pull, Vertex duplizieren und eine neue Kante
* entlang der Schnittgeraden zweier Nachbarflächen einfügen.
* - gemischt: positive und negative Kanten auf Original/Duplikat trennen und
* danach erneut als Fall 2, Fall 3.1 oder Fall 3.2 behandeln.
*
* Bis diese Topologieoperationen implementiert sind, bleibt Fall 3 bewusst
* ERROR.
*/
status
=
SweepVertexStatus
.
ERROR
;
status
=
SweepVertexStatus
.
ERROR
;
}
}
}
public
void
calculateNewPoint
(
Plane
targetPlane
,
Polygon
p
,
double
epsPointDist
)
{
public
void
calculateNewPoint
(
Plane
targetPlane
,
Polygon
p
,
double
minSweepEdgeLength
,
double
minLinePlaneAngleRatio
)
{
if
(
SweepVertexStatus
.
PROJECT
==
status
)
{
newPoint
=
null
;
if
(
targetPlane
==
null
||
vert
==
null
)
{
status
=
SweepVertexStatus
.
ERROR
;
return
;
}
switch
(
status
)
{
case
ON_PLANE:
return
;
case
PROJECT:
newPoint
=
targetPlane
.
projectPointToPlane
(
vert
);
newPoint
=
targetPlane
.
projectPointToPlane
(
vert
);
if
(
newPoint
==
null
)
{
status
=
SweepVertexStatus
.
ERROR
;
}
}
else
if
(
SweepVertexStatus
.
SWEEP
==
status
)
{
return
;
if
(
1
!=
getNoOutgoingEdges
()
)
{
case
SWEEP:
if
(
outgoingEdges
==
null
||
outgoingEdges
.
size
()
!=
1
)
{
status
=
SweepVertexStatus
.
ERROR
;
status
=
SweepVertexStatus
.
ERROR
;
return
;
}
}
else
{
SweepEdge
e
=
new
SweepEdge
(
outgoingEdges
.
getFirst
(),
p
,
epsPointDist
);
Edge
outgoingEdge
=
outgoingEdges
.
getFirst
();
//todo: Schnittpunkt der outgoing Edge mit der targePlane berechnen
if
(
outgoingEdge
==
null
)
{
//todo: dafuer Hilfsklasse SweepEdge fuer Parameterdarstellung usw. nutzen
status
=
SweepVertexStatus
.
ERROR
;
//todo: Parameter des Schnittpunkts auf der Edge berechnen
return
;
// --> wenn die Edge "umkippt" oder zum Punkt degeneriert (epsPointDist): status = SweepVertexStatus.ERROR
}
SweepEdge
sweepEdge
=
new
SweepEdge
(
outgoingEdge
,
vert
,
minSweepEdgeLength
);
if
(!
sweepEdge
.
valid
())
{
status
=
SweepVertexStatus
.
ERROR
;
return
;
}
}
Vector3d
intersectionPoint
=
sweepEdge
.
intersection
(
targetPlane
,
minLinePlaneAngleRatio
);
if
(
intersectionPoint
==
null
)
{
status
=
SweepVertexStatus
.
ERROR
;
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
:
status
=
SweepVertexStatus
.
ERROR
;
return
;
}
case
NONE:
case
ERROR:
default
:
status
=
SweepVertexStatus
.
ERROR
;
return
;
}
}
}
}
public
void
doHeal
()
{
public
void
doHeal
()
{
if
(
SweepVertexStatus
.
SWEEP
==
status
||
SweepVertexStatus
.
PROJECT
==
status
)
{
if
(
status
!=
SweepVertexStatus
.
SWEEP
&&
status
!=
SweepVertexStatus
.
PROJECT
)
{
return
;
}
if
(
vert
==
null
||
newPoint
==
null
)
{
status
=
SweepVertexStatus
.
ERROR
;
return
;
}
vert
.
setX
(
newPoint
.
getX
());
vert
.
setX
(
newPoint
.
getX
());
vert
.
setY
(
newPoint
.
getY
());
vert
.
setY
(
newPoint
.
getY
());
vert
.
setZ
(
newPoint
.
getZ
());
vert
.
setZ
(
newPoint
.
getZ
());
}
}
}
public
SweepVertexStatus
getStatus
()
{
public
SweepVertexStatus
getStatus
()
{
...
@@ -97,4 +212,9 @@ public class SweepVertex {
...
@@ -97,4 +212,9 @@ public class SweepVertex {
return
outgoingEdges
.
size
();
return
outgoingEdges
.
size
();
}
}
public
boolean
hasNewPoint
()
{
return
newPoint
!=
null
;
}
}
}
CityDoctorParent/Extensions/CityDoctorHealer/src/test/java/de/hft/stuttgart/citydoctor2/healing/SweepUtilitiesSyntheticTest.java
0 → 100644
View file @
5a5d8118
package
de.hft.stuttgart.citydoctor2.healing
;
import
static
org
.
junit
.
Assert
.
assertEquals
;
import
static
org
.
junit
.
Assert
.
assertFalse
;
import
static
org
.
junit
.
Assert
.
assertTrue
;
import
org.junit.Test
;
import
de.hft.stuttgart.citydoctor2.check.error.NonPlanarPolygonDistancePlaneError
;
import
de.hft.stuttgart.citydoctor2.datastructure.Building
;
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.math.Plane
;
import
de.hft.stuttgart.citydoctor2.math.Vector3d
;
public
class
SweepUtilitiesSyntheticTest
{
private
static
final
double
EPS
=
0.000001
;
@Test
public
void
repairsCase1ByOrthogonalProjection
()
{
Building
building
=
SyntheticSweepPlanarityModelFactory
.
createWallWithProtrudingWindowInnerRingPoint
();
Polygon
sweepPolygon
=
getPolygon
(
building
,
0
);
Vertex
protrudingPoint
=
sweepPolygon
.
getInnerRings
().
get
(
0
).
getVertices
().
get
(
2
);
Plane
targetPlane
=
wallPlaneX0
();
assertEquals
(
0.3
,
protrudingPoint
.
getX
(),
EPS
);
assertTrue
(
runSweep
(
sweepPolygon
,
targetPlane
));
assertEquals
(
0
,
protrudingPoint
.
getX
(),
EPS
);
assertEquals
(
0
,
targetPlane
.
getDistance
(
protrudingPoint
),
EPS
);
}
@Test
public
void
repairsCase2WhenOutgoingEdgeIsShortened
()
{
Building
building
=
SyntheticSweepPlanarityModelFactory
.
createSweepCase2ShorteningEdge
();
Polygon
sweepPolygon
=
getPolygon
(
building
,
0
);
Vertex
sweepPoint
=
sweepPolygon
.
getExteriorRing
().
getVertices
().
get
(
1
);
Plane
targetPlane
=
wallPlaneX0
();
assertEquals
(
1
,
sweepPoint
.
getX
(),
EPS
);
assertTrue
(
runSweep
(
sweepPolygon
,
targetPlane
));
assertEquals
(
0
,
sweepPoint
.
getX
(),
EPS
);
assertEquals
(
0
,
targetPlane
.
getDistance
(
sweepPoint
),
EPS
);
}
@Test
public
void
repairsCase2WhenOutgoingEdgeIsExtended
()
{
Building
building
=
SyntheticSweepPlanarityModelFactory
.
createSweepCase2ExtendingEdge
();
Polygon
sweepPolygon
=
getPolygon
(
building
,
0
);
Vertex
sweepPoint
=
sweepPolygon
.
getExteriorRing
().
getVertices
().
get
(
1
);
Plane
targetPlane
=
wallPlaneX0
();
assertEquals
(
1
,
sweepPoint
.
getX
(),
EPS
);
assertTrue
(
runSweep
(
sweepPolygon
,
targetPlane
));
assertEquals
(
0
,
sweepPoint
.
getX
(),
EPS
);
assertEquals
(
0
,
targetPlane
.
getDistance
(
sweepPoint
),
EPS
);
}
@Test
public
void
rejectsCase2WhenIntersectionIsBeforeSweepVertex
()
{
Building
building
=
SyntheticSweepPlanarityModelFactory
.
createSweepCase2IntersectionBeforeSweepVertex
();
Polygon
sweepPolygon
=
getPolygon
(
building
,
0
);
Vertex
sweepPoint
=
sweepPolygon
.
getExteriorRing
().
getVertices
().
get
(
1
);
assertFalse
(
runSweep
(
sweepPolygon
,
wallPlaneX0
()));
assertEquals
(
1
,
sweepPoint
.
getX
(),
EPS
);
}
@Test
public
void
rejectsCase2WhenOutgoingEdgeIsParallelToTargetPlane
()
{
Building
building
=
SyntheticSweepPlanarityModelFactory
.
createSweepCase2ParallelOutgoingEdge
();
Polygon
sweepPolygon
=
getPolygon
(
building
,
0
);
Vertex
sweepPoint
=
sweepPolygon
.
getExteriorRing
().
getVertices
().
get
(
1
);
assertFalse
(
runSweep
(
sweepPolygon
,
wallPlaneX0
()));
assertEquals
(
1
,
sweepPoint
.
getX
(),
EPS
);
}
private
boolean
runSweep
(
Polygon
sweepPolygon
,
Plane
targetPlane
)
{
NonPlanarPolygonDistancePlaneError
error
=
new
NonPlanarPolygonDistancePlaneError
(
sweepPolygon
,
0
,
null
,
targetPlane
);
SweepUtilities
utilities
=
new
SweepUtilities
(
error
);
utilities
.
initialize
();
if
(!
utilities
.
calculate
())
{
return
false
;
}
utilities
.
doHeal
();
return
true
;
}
private
Polygon
getPolygon
(
Building
building
,
int
index
)
{
Geometry
geometry
=
building
.
getGeometries
().
get
(
0
);
return
geometry
.
getPolygons
().
get
(
index
);
}
private
Plane
wallPlaneX0
()
{
return
new
Plane
(
new
Vector3d
(
1
,
0
,
0
),
new
Vector3d
(
0
,
0
,
0
));
}
}
CityDoctorParent/Extensions/CityDoctorHealer/src/test/java/de/hft/stuttgart/citydoctor2/healing/SyntheticSweepPlanarityModelFactory.java
View file @
5a5d8118
...
@@ -47,6 +47,16 @@ public class SyntheticSweepPlanarityModelFactory {
...
@@ -47,6 +47,16 @@ public class SyntheticSweepPlanarityModelFactory {
createSlopedRoofWithProtrudingOpeningRingPoint
(),
createSlopedRoofWithProtrudingOpeningRingPoint
(),
new
File
(
"sweep-case1-sloped-roof-opening-ring-point.gml"
),
new
File
(
"sweep-case1-sloped-roof-opening-ring-point.gml"
),
"SweepCase1SlopedRoofOpeningRingPoint"
);
"SweepCase1SlopedRoofOpeningRingPoint"
);
exportForGui
(
createSweepCase2ShorteningEdge
(),
new
File
(
"sweep-case2-shortening-edge.gml"
),
"SweepCase2ShorteningEdge"
);
exportForGui
(
createSweepCase2ExtendingEdge
(),
new
File
(
"sweep-case2-extending-edge.gml"
),
"SweepCase2ExtendingEdge"
);
}
}
static
Building
createNonPlanarCube
(
double
boxsize
,
double
bottomerr
,
double
topLift
)
{
static
Building
createNonPlanarCube
(
double
boxsize
,
double
bottomerr
,
double
topLift
)
{
...
@@ -200,6 +210,55 @@ public class SyntheticSweepPlanarityModelFactory {
...
@@ -200,6 +210,55 @@ public class SyntheticSweepPlanarityModelFactory {
return
building
;
return
building
;
}
}
/**
* Fall 2 model: the faulty sweep point has exactly one outgoing edge. The target
* plane x = 0 cuts the finite outgoing edge, so the edge is shortened.
*/
static
Building
createSweepCase2ShorteningEdge
()
{
return
createSweepCase2SingleOutgoingEdge
(
new
Vertex
(-
1
,
1
,
0
));
}
/**
* 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.
*/
static
Building
createSweepCase2ExtendingEdge
()
{
return
createSweepCase2SingleOutgoingEdge
(
new
Vertex
(
0.5
,
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.
*/
static
Building
createSweepCase2IntersectionBeforeSweepVertex
()
{
return
createSweepCase2SingleOutgoingEdge
(
new
Vertex
(
2
,
1
,
0
));
}
/**
* Fall 2 error model: the outgoing edge is parallel to the target plane x = 0.
* The current sweep implementation cannot calculate a stable line-plane cut.
*/
static
Building
createSweepCase2ParallelOutgoingEdge
()
{
return
createSweepCase2SingleOutgoingEdge
(
new
Vertex
(
1
,
2
,
0
));
}
private
static
Building
createSweepCase2SingleOutgoingEdge
(
Vertex
outgoingTarget
)
{
Building
building
=
new
Building
();
Geometry
geom
=
new
Geometry
(
GeometryType
.
MULTI_SURFACE
,
Lod
.
LOD2
,
Orientation
.
OUTWARD
);
building
.
addGeometry
(
geom
);
Vertex
sharedAnchor
=
new
Vertex
(
0
,
0
,
0
);
Vertex
sweepPoint
=
new
Vertex
(
1
,
1
,
0
);
Vertex
upperRight
=
new
Vertex
(
0
,
2
,
0
);
Vertex
upperLeft
=
new
Vertex
(
0
,
2
,
2
);
addPolygon
(
geom
,
sharedAnchor
,
sweepPoint
,
upperRight
,
upperLeft
);
addPolygon
(
geom
,
sweepPoint
,
outgoingTarget
,
sharedAnchor
);
geom
.
updateEdgesAndVertices
();
return
building
;
}
private
static
void
exportForGui
(
Building
building
,
File
output
,
String
gmlId
)
throws
CityDoctorWriteException
{
private
static
void
exportForGui
(
Building
building
,
File
output
,
String
gmlId
)
throws
CityDoctorWriteException
{
CityDoctorModel
model
=
createCityDoctorModel
(
building
,
output
,
gmlId
);
CityDoctorModel
model
=
createCityDoctorModel
(
building
,
output
,
gmlId
);
model
.
saveAs
(
output
.
getAbsolutePath
(),
false
);
model
.
saveAs
(
output
.
getAbsolutePath
(),
false
);
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment