Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
9.2.2023: Due to updates GitLab will be unavailable for some minutes between 9:00 and 11:00.
Open sidebar
vadere
vadere
Commits
43e77c48
Commit
43e77c48
authored
Feb 28, 2017
by
Benedikt Zoennchen
Browse files
implementation of a very generic half-edge data structure
parent
0fb76bd7
Changes
31
Expand all
Hide whitespace changes
Inline
Side-by-side
VadereUtils/src/org/vadere/util/geometry/mesh/DAGElement.java
View file @
43e77c48
package
org.vadere.util.geometry.mesh
;
import
org.apache.commons.lang3.tuple.Triple
;
import
org.vadere.util.geometry.mesh.inter.IFace
;
import
org.vadere.util.geometry.shapes.IPoint
;
import
org.vadere.util.geometry.shapes.VPoint
;
import
org.vadere.util.geometry.shapes.VTriangle
;
public
class
DAGElement
<
P
extends
IPoint
>
{
private
Face
<
P
>
face
;
import
java.util.List
;
public
class
DAGElement
<
P
extends
IPoint
,
F
extends
IFace
<
P
>>
{
private
F
face
;
private
Triple
<
P
,
P
,
P
>
vertices
;
private
VTriangle
triangle
;
public
DAGElement
(
final
Face
<
P
>
face
,
final
Triple
<
P
,
P
,
P
>
vertices
)
{
public
DAGElement
(
final
F
face
,
List
<
P
>
points
)
{
P
p1
=
points
.
get
(
0
);
P
p2
=
points
.
get
(
1
);
P
p3
=
points
.
get
(
2
);
this
.
face
=
face
;
this
.
vertices
=
Triple
.
of
(
p1
,
p2
,
p3
);
this
.
triangle
=
new
VTriangle
(
new
VPoint
(
p1
),
new
VPoint
(
p2
),
new
VPoint
(
p3
));
}
public
DAGElement
(
final
F
face
,
final
Triple
<
P
,
P
,
P
>
vertices
)
{
this
.
face
=
face
;
this
.
vertices
=
vertices
;
VPoint
p1
=
new
VPoint
(
vertices
.
getLeft
()
.
getX
(),
vertices
.
getLeft
().
getY
()
);
VPoint
p2
=
new
VPoint
(
vertices
.
getMiddle
()
.
getX
(),
vertices
.
getMiddle
().
getY
()
);
VPoint
p3
=
new
VPoint
(
vertices
.
getRight
()
.
getX
(),
vertices
.
getRight
().
getY
()
);
VPoint
p1
=
new
VPoint
(
vertices
.
getLeft
());
VPoint
p2
=
new
VPoint
(
vertices
.
getMiddle
());
VPoint
p3
=
new
VPoint
(
vertices
.
getRight
());
this
.
triangle
=
new
VTriangle
(
p1
,
p2
,
p3
);
}
public
F
ace
<
P
>
getFace
()
{
public
F
getFace
()
{
return
face
;
}
...
...
VadereUtils/src/org/vadere/util/geometry/mesh/Face.java
deleted
100644 → 0
View file @
0fb76bd7
package
org.vadere.util.geometry.mesh
;
import
org.jetbrains.annotations.NotNull
;
import
org.vadere.util.geometry.GeometryUtils
;
import
org.vadere.util.geometry.shapes.IPoint
;
import
org.vadere.util.geometry.shapes.MLine
;
import
org.vadere.util.geometry.shapes.VPoint
;
import
org.vadere.util.geometry.shapes.VPolygon
;
import
org.vadere.util.geometry.shapes.VTriangle
;
import
java.awt.geom.Path2D
;
import
java.util.Iterator
;
import
java.util.List
;
import
java.util.stream.Collectors
;
import
java.util.stream.Stream
;
import
java.util.stream.StreamSupport
;
/**
* A Face is a region of a planar separation of the 2-D space, e.g. the region of a Polygon/Triangle and so on.
*
* @author Benedikt Zoennchen
* @param <P> the type of the coordinates the face uses.
*/
public
class
Face
<
P
extends
IPoint
>
implements
Iterable
<
PHalfEdge
<
P
>>,
IFace
<
P
>
{
public
static
<
P
extends
IPoint
>
Face
<
P
>
of
(
P
x
,
P
y
,
P
z
)
{
Face
superTriangle
=
new
Face
();
Face
borderFace
=
new
Face
(
true
);
PHalfEdge
xy
=
new
PHalfEdge
(
y
,
superTriangle
);
PHalfEdge
yz
=
new
PHalfEdge
(
z
,
superTriangle
);
PHalfEdge
zx
=
new
PHalfEdge
(
x
,
superTriangle
);
xy
.
setNext
(
yz
);
yz
.
setNext
(
zx
);
zx
.
setNext
(
xy
);
PHalfEdge
yx
=
new
PHalfEdge
(
x
,
borderFace
);
PHalfEdge
zy
=
new
PHalfEdge
(
y
,
borderFace
);
PHalfEdge
xz
=
new
PHalfEdge
(
z
,
borderFace
);
yx
.
setNext
(
xz
);
xz
.
setNext
(
zy
);
zy
.
setNext
(
yx
);
xy
.
setTwin
(
yx
);
yz
.
setTwin
(
zy
);
zx
.
setTwin
(
xz
);
superTriangle
.
setEdge
(
xy
);
borderFace
.
setEdge
(
yx
);
return
superTriangle
;
}
public
static
<
P
extends
IPoint
>
Face
<
P
>
getBorder
(
Class
<
P
>
p
)
{
return
new
Face
<>(
true
);
}
/**
* One of the half-edges bordering this face.
*/
private
PHalfEdge
<
P
>
edge
;
private
boolean
border
;
private
boolean
destroyed
=
false
;
/**
* Default constructor. To construct a face where you have already some half-edges
* bordering this face.
*
* @param edge one of the half-edges bordering this face.
*/
public
Face
(
@NotNull
final
PHalfEdge
<
P
>
edge
)
{
this
(
edge
,
false
);
}
public
Face
(
@NotNull
final
PHalfEdge
<
P
>
edge
,
boolean
border
)
{
this
.
border
=
border
;
this
.
edge
=
edge
;
}
/**
* This constructor can be used for constructing a new face without having
* constructed the bordering half-edges jet.
*/
public
Face
(
boolean
border
)
{
this
.
border
=
border
;
}
public
Face
()
{
this
.
border
=
false
;
}
public
boolean
isBorder
()
{
return
border
;
}
public
void
destroy
()
{
setEdge
(
null
);
destroyed
=
true
;
}
public
void
toBorder
()
{
border
=
true
;
}
/**
* Sets one of the half-edges bordering this face.
*
* @param edge half-edge bordering this face
*/
public
void
setEdge
(
final
PHalfEdge
<
P
>
edge
)
{
this
.
edge
=
edge
;
}
public
PHalfEdge
<
P
>
getEdge
()
{
return
edge
;
}
public
boolean
isDestroyed
()
{
return
destroyed
;
}
/**
* Computes the area of this face.
*
* @return the area of this face
*/
public
double
getArea
()
{
return
GeometryUtils
.
areaOfPolygon
(
getPoints
());
}
/**
*
* @return
*/
public
List
<
P
>
getPoints
()
{
return
streamPoints
().
collect
(
Collectors
.
toList
());
}
/**
* Returns true if and only if the point contained in this face.
*
* @param point the point which might be contained
* @return true if and only if the point contained in this face.
*/
public
boolean
contains
(
final
P
point
)
{
return
toPolygon
().
contains
(
point
);
}
/**
* Transforms this face into a Polygon object.
*
* @return the Polygon object defined by this face
*/
public
VPolygon
toPolygon
()
{
Path2D
path2D
=
new
Path2D
.
Double
();
path2D
.
moveTo
(
edge
.
getPrevious
().
getEnd
().
getX
(),
edge
.
getPrevious
().
getEnd
().
getY
());
for
(
PHalfEdge
edge
:
this
)
{
path2D
.
lineTo
(
edge
.
getEnd
().
getX
(),
edge
.
getEnd
().
getY
());
}
return
new
VPolygon
(
path2D
);
}
/**
* Transforms this face into a triangle. Assumption: The face is a valid triangle.
*
* @throws IllegalArgumentException if the face does not define a valid triangle
* @return a triangle which is defined by this face
*/
public
VTriangle
toTriangle
()
{
List
<
PHalfEdge
<
P
>>
edges
=
getEdges
();
if
(
edges
.
size
()
!=
3
)
{
throw
new
IllegalArgumentException
(
"this face is not a feasible triangle."
);
}
else
{
VPoint
p1
=
new
VPoint
(
edges
.
get
(
0
).
getEnd
().
getX
(),
edges
.
get
(
0
).
getEnd
().
getY
());
VPoint
p2
=
new
VPoint
(
edges
.
get
(
1
).
getEnd
().
getX
(),
edges
.
get
(
1
).
getEnd
().
getY
());
VPoint
p3
=
new
VPoint
(
edges
.
get
(
2
).
getEnd
().
getX
(),
edges
.
get
(
2
).
getEnd
().
getY
());
return
new
VTriangle
(
p1
,
p2
,
p3
);
}
}
@Override
public
Iterator
<
PHalfEdge
<
P
>>
iterator
()
{
return
new
HalfEdgeIterator
();
}
public
Stream
<
PHalfEdge
<
P
>>
stream
()
{
Iterable
<
PHalfEdge
<
P
>>
iterable
=
()
->
iterator
();
return
StreamSupport
.
stream
(
iterable
.
spliterator
(),
false
);
}
public
List
<
PHalfEdge
<
P
>>
getEdges
()
{
return
stream
().
collect
(
Collectors
.
toList
());
}
public
Stream
<
MLine
<
P
>>
streamLines
()
{
return
stream
().
map
(
halfEdge
->
new
MLine
(
halfEdge
.
getPrevious
().
getEnd
(),
halfEdge
.
getEnd
()));
}
public
Stream
<
P
>
streamPoints
()
{
return
stream
().
map
(
edge
->
edge
.
getEnd
());
}
@Override
public
String
toString
()
{
return
stream
().
map
(
edge
->
edge
.
getEnd
().
toString
()).
reduce
(
""
,
(
s1
,
s2
)
->
s1
+
" "
+
s2
);
}
private
class
HalfEdgeIterator
implements
Iterator
<
PHalfEdge
<
P
>>
{
private
PHalfEdge
<
P
>
currentHalfEdge
;
private
boolean
started
=
false
;
private
HalfEdgeIterator
(){
this
.
currentHalfEdge
=
edge
;
}
@Override
public
boolean
hasNext
()
{
return
currentHalfEdge
!=
null
&&
(!
started
||
!
currentHalfEdge
.
equals
(
edge
));
}
@Override
public
PHalfEdge
<
P
>
next
()
{
started
=
true
;
PHalfEdge
result
=
currentHalfEdge
;
currentHalfEdge
=
currentHalfEdge
.
getNext
();
return
result
;
}
}
}
VadereUtils/src/org/vadere/util/geometry/mesh/IMesh.java
deleted
100644 → 0
View file @
0fb76bd7
package
org.vadere.util.geometry.mesh
;
import
org.apache.commons.collections.IteratorUtils
;
import
org.jetbrains.annotations.NotNull
;
import
org.vadere.util.geometry.shapes.IPoint
;
import
org.vadere.util.geometry.shapes.VPoint
;
import
org.vadere.util.geometry.shapes.VPolygon
;
import
java.awt.geom.Path2D
;
import
java.util.Iterator
;
import
java.util.List
;
import
java.util.Optional
;
/**
* @author Benedikt Zoennchen
* @param <P>
*/
public
interface
IMesh
<
P
extends
IPoint
,
E
extends
IHalfEdge
<
P
>,
F
extends
IFace
<
P
>>
extends
Iterable
<
F
>
{
E
getNext
(
@NotNull
E
halfEdge
);
E
getPrev
(
@NotNull
E
halfEdge
);
E
getTwin
(
@NotNull
E
halfEdge
);
F
getFace
(
@NotNull
E
halfEdge
);
E
getEdge
(
@NotNull
P
vertex
);
E
getEdge
(
@NotNull
F
face
);
P
getVertex
(
@NotNull
E
halfEdge
);
default
F
getTwinFace
(
@NotNull
E
halfEdge
)
{
return
getFace
(
getTwin
(
halfEdge
));
}
boolean
isBoundary
(
@NotNull
F
face
);
boolean
isBoundary
(
@NotNull
E
halfEdge
);
boolean
isDestroyed
(
@NotNull
F
face
);
void
setTwin
(
@NotNull
E
halfEdge
,
@NotNull
E
twin
);
void
setNext
(
@NotNull
E
halfEdge
,
@NotNull
E
next
);
void
setPrev
(
@NotNull
E
halfEdge
,
@NotNull
E
prev
);
void
setFace
(
@NotNull
E
halfEdge
,
@NotNull
F
face
);
void
setEdge
(
@NotNull
F
face
,
@NotNull
E
edge
);
void
setEdge
(
@NotNull
P
vertex
,
@NotNull
E
edge
);
void
setVertex
(
@NotNull
E
halfEdge
,
@NotNull
P
vertex
);
List
<
E
>
getEdges
(
@NotNull
P
vertex
);
default
List
<
E
>
getEdges
(
@NotNull
F
face
)
{
return
IteratorUtils
.
toList
(
new
EdgeIterator
(
this
,
face
));
}
default
List
<
F
>
getFaces
(
@NotNull
E
edge
)
{
return
IteratorUtils
.
toList
(
new
NeighbourFaceIterator
(
this
,
edge
));
}
default
List
<
E
>
getNeighbours
(
@NotNull
E
edge
)
{
return
IteratorUtils
.
toList
(
new
NeighbourIterator
(
this
,
edge
));
}
default
Iterable
<
E
>
getNeighbourIt
(
E
edge
)
{
return
()
->
new
NeighbourIterator
(
this
,
edge
);
}
default
Iterable
<
E
>
getEdgeIt
(
F
face
)
{
return
()
->
new
EdgeIterator
(
this
,
face
);
}
default
Iterable
<
F
>
getIncidentFacesIt
(
@NotNull
E
edge
)
{
return
()
->
new
NeighbourFaceIterator
<>(
this
,
edge
);
}
E
createEdge
(
@NotNull
P
vertex
);
E
createEdge
(
@NotNull
P
vertex
,
@NotNull
F
face
);
F
createFace
();
void
destroyFace
(
@NotNull
F
face
);
void
destroyEdge
(
@NotNull
E
edge
);
List
<
F
>
getFaces
();
@Override
default
Iterator
<
F
>
iterator
()
{
return
getFaces
().
iterator
();
}
default
VPolygon
toPolygon
(
F
face
)
{
Path2D
path2D
=
new
Path2D
.
Double
();
E
edge
=
getEdge
(
face
);
E
prev
=
getPrev
(
edge
);
path2D
.
moveTo
(
getVertex
(
prev
).
getX
(),
getVertex
(
prev
).
getY
());
path2D
.
lineTo
(
getVertex
(
edge
).
getX
(),
getVertex
(
edge
).
getY
());
while
(!
edge
.
equals
(
prev
))
{
edge
=
getNext
(
edge
);
P
p
=
getVertex
(
edge
);
path2D
.
lineTo
(
p
.
getX
(),
p
.
getY
());
}
return
new
VPolygon
(
path2D
);
}
default
Optional
<
F
>
locate
(
final
double
x
,
final
double
y
)
{
for
(
F
face
:
getFaces
())
{
VPolygon
polygon
=
toPolygon
(
face
);
if
(
polygon
.
contains
(
new
VPoint
(
x
,
y
)))
{
return
Optional
.
of
(
face
);
}
}
return
Optional
.
empty
();
}
}
VadereUtils/src/org/vadere/util/geometry/mesh/IPolyConnectivity.java
View file @
43e77c48
package
org.vadere.util.geometry.mesh
;
import
org.jetbrains.annotations.NotNull
;
import
org.vadere.util.geometry.mesh.inter.IFace
;
import
org.vadere.util.geometry.mesh.inter.IHalfEdge
;
import
org.vadere.util.geometry.mesh.inter.IMesh
;
import
org.vadere.util.geometry.shapes.IPoint
;
import
org.vadere.util.geometry.shapes.VPoint
;
import
org.vadere.util.geometry.shapes.VPolygon
;
import
java.util.ArrayList
;
import
java.util.HashSet
;
import
java.util.List
;
import
java.util.Optional
;
...
...
@@ -31,7 +36,7 @@ public interface IPolyConnectivity<P extends IPoint, E extends IHalfEdge<P>, F e
return
Optional
.
empty
();
}
default
Optional
<
F
>
locate
(
final
P
point
)
{
default
Optional
<
F
>
locate
(
final
IPoint
point
)
{
return
locate
(
point
.
getX
(),
point
.
getY
());
}
...
...
@@ -46,7 +51,7 @@ public interface IPolyConnectivity<P extends IPoint, E extends IHalfEdge<P>, F e
default
Optional
<
E
>
findEdge
(
P
begin
,
P
end
)
{
IMesh
<
P
,
E
,
F
>
mesh
=
getMesh
();
return
mesh
.
get
Neighbour
s
(
mesh
.
getEdge
(
begin
)).
stream
().
filter
(
edge
->
mesh
.
getPrev
(
edge
).
equals
(
end
)).
map
(
edge
->
mesh
.
getTwin
(
edge
)).
findAny
();
return
mesh
.
get
IncidentEdge
s
(
mesh
.
getEdge
(
begin
)).
stream
().
filter
(
edge
->
mesh
.
getPrev
(
edge
).
equals
(
end
)).
map
(
edge
->
mesh
.
getTwin
(
edge
)).
findAny
();
}
default
boolean
isSimpleLink
(
E
halfEdge
)
{
...
...
@@ -120,4 +125,127 @@ public interface IPolyConnectivity<P extends IPoint, E extends IHalfEdge<P>, F e
getMesh
().
setFace
(
hold
,
face
);
}
/**
* Removes a simple link.
*
* @param edge
* @return
*/
default
F
removeEdge
(
E
edge
)
{
assert
isSimpleLink
(
edge
)
&&
!
getMesh
().
isDestroyed
(
edge
);
E
twin
=
getMesh
().
getTwin
(
edge
);
F
delFace
=
getMesh
().
getFace
(
edge
);
F
remFace
=
getMesh
().
getFace
(
twin
);
if
(
getMesh
().
isBoundary
(
delFace
))
{
F
tmp
=
delFace
;
delFace
=
remFace
;
remFace
=
tmp
;
}
assert
!
getMesh
().
isDestroyed
(
delFace
);
E
prevEdge
=
getMesh
().
getPrev
(
edge
);
E
prevTwin
=
getMesh
().
getPrev
(
twin
);
E
nextEdge
=
getMesh
().
getNext
(
edge
);
E
nextTwin
=
getMesh
().
getNext
(
twin
);
getMesh
().
setNext
(
prevEdge
,
nextTwin
);
getMesh
().
setNext
(
prevTwin
,
nextEdge
);
/* adjust vertices, mb later
P eVertex = getMesh().getVertex(edge);
P tVertex = getMesh().getVertex(twin);
*/
if
(
getMesh
().
getEdge
(
remFace
).
equals
(
edge
))
{
getMesh
().
setEdge
(
remFace
,
prevTwin
);
}
else
if
(
getMesh
().
getEdge
(
remFace
).
equals
(
twin
))
{
getMesh
().
setEdge
(
remFace
,
prevEdge
);
}
for
(
E
halfEdge
:
getMesh
().
getEdgeIt
(
remFace
))
{
getMesh
().
setFace
(
halfEdge
,
remFace
);
}
getMesh
().
destroyEdge
(
edge
);
getMesh
().
destroyEdge
(
twin
);
getMesh
().
destroyFace
(
delFace
);
return
remFace
;
}
default
void
removeFace
(
@NotNull
F
face
,
boolean
deleteIsolatedVertices
)
{
assert
!
getMesh
().
isDestroyed
(
face
);
getMesh
().
destroyFace
(
face
);
List
<
E
>
delEdges
=
new
ArrayList
<>();
List
<
P
>
vertices
=
new
ArrayList
<>();
F
boundary
=
getMesh
().
createFace
(
true
);
for
(
E
edge
:
getMesh
().
getEdgeIt
(
face
))
{
getMesh
().
setFace
(
edge
,
boundary
);
if
(
getMesh
().
isBoundary
(
getMesh
().
getTwin
(
edge
)))
{
delEdges
.
add
(
edge
);
}
vertices
.
add
(
getMesh
().
getVertex
(
edge
));
}
if
(!
delEdges
.
isEmpty
())
{
E
h0
,
h1
,
next0
,
next1
,
prev0
,
prev1
;
P
v0
,
v1
;
for
(
E
delEdge
:
delEdges
)
{
h0
=
delEdge
;
v0
=
getMesh
().
getVertex
(
delEdge
);
next0
=
getMesh
().
getNext
(
h0
);
prev0
=
getMesh
().
getPrev
(
h0
);
h1
=
getMesh
().
getTwin
(
delEdge
);
v1
=
getMesh
().
getVertex
(
h1
);
next1
=
getMesh
().
getNext
(
h1
);
prev1
=
getMesh
().
getPrev
(
h1
);
// adjust next and prev handles
getMesh
().
setNext
(
prev0
,
next1
);
getMesh
().
setNext
(
prev1
,
next0
);
// mark edge deleted if the mesh has a edge status
getMesh
().
destroyEdge
(
h0
);
getMesh
().
destroyEdge
(
h1
);
// TODO: delete isolated vertices?
for
(
P
vertex
:
vertices
)
{
adjustVertex
(
vertex
);
}
}
}
}
/**
* Returns a half-edge such that it is part of face1 and the twin of this half-edge
* is part of face2.
*
* @param face1 the first face
* @param face2 the second face that might be a neighbour of face1
* @return the half-edge of face1 such that its twin is part of face2
*/
default
Optional
<
E
>
findTwins
(
final
F
face1
,
final
F
face2
)
{
for
(
E
halfEdge1
:
getMesh
().
getEdgeIt
(
face1
))
{
for
(
E
halfEdge2
:
getMesh
().
getEdgeIt
(
face2
))
{
if
(
getMesh
().
getTwin
(
halfEdge1
).
equals
(
halfEdge2
))
{
return
Optional
.
of
(
halfEdge1
);
}
}
}
return
Optional
.
empty
();
}
}
VadereUtils/src/org/vadere/util/geometry/mesh/ITriConnectivity.java
View file @
43e77c48
package
org.vadere.util.geometry.mesh
;
import
org.apache.commons.lang3.tuple.Pair
;
import
org.apache.commons.lang3.tuple.Triple
;
import
org.jetbrains.annotations.NotNull
;
import
org.vadere.util.geometry.mesh.inter.IFace
;
import
org.vadere.util.geometry.mesh.inter.IHalfEdge
;
import
org.vadere.util.geometry.mesh.inter.IMesh
;
import
org.vadere.util.geometry.shapes.IPoint
;
import
java.util.ArrayList
;
...
...
@@ -17,11 +18,9 @@ import java.util.List;
*/
public
interface
ITriConnectivity
<
P
extends
IPoint
,
E
extends
IHalfEdge
<
P
>,
F
extends
IFace
<
P
>>
extends
IPolyConnectivity
<
P
,
E
,
F
>
{
default
void
split
Triangl
eEvent
(
F
face
,
List
<
F
>
faces
)
{}
default
void
split
Fac
eEvent
(
F
original
,
F
...
faces
)
{}
default
void
flipEvent
(
F
f1
,
F
f2
)
{}
void
splitEdgeEvent
(
List
<
E
>
newEdges
);
default
void
flipEdgeEvent
(
F
f1
,
F
f2
)
{}
boolean
isIllegal
(
E
edge
);
...
...
@@ -31,7 +30,7 @@ public interface ITriConnectivity<P extends IPoint, E extends IHalfEdge<P>, F ex
* @param p the split point
* @param halfEdge the half-edge which will be split
*/
default
List
<
E
>
splitEdge
(
@NotNull
P
p
,
@NotNull
E
halfEdge
)
{
default
List
<
E
>
splitEdge
(
@NotNull
P
p
,
@NotNull
E
halfEdge
,
boolean
legalize
)
{
IMesh
<
P
,
E
,
F
>
mesh
=
getMesh
();
List
<
E
>
newEdges
=
new
ArrayList
<>(
4
);