TTL Programming Triangulations: Triangulation Template Library INF-MAT5370, Øyvind Hjelle

advertisement
Programming Triangulations:
Triangulation Template Library
TTL
INF-MAT5370, Øyvind Hjelle
Goal:
Implementation of a collection of generic algorithms for
triangulation that are independent and clearly separated
from the underlying data structure.
Using G-maps: dart algebra and -iterators
(involutions) to model the triangulation at an abstract
level.
Implementation (in C ) by generic programming in
the spirit of STL (The Standard Template Library)
1
The half-edge data structure
revisited
Node
1
(next edge in triangle)
1
(twin edge)
1
HalfEdge
1
Triangle
N
Triangulation
Classes: Node, HalfEdge, Triangle, Triangulation
class Node: geometry x, y, z .
class HalfEdge: pointer to source node, “next
edge in face” and “twin edge”.
class Triangle: pointer to one of its half-edges
(the triangle’s “leading edge”)
class Triangulation:
std::list Triangle
Typical member functions:
HalfEdge::getNextEdgeInFace ” ”
HalfEdge::getTwinEdge ” ”
0
2
1
0
d
d
2
!" #
$
" # $ % " #
!" # $
" # & '
(
#" #
!" #
)((
" # & '
*
+%
!" # $ #
!" # $ #
$ # *
- (
(
%
)((
" #
(
)((
#" #
!
$
" # & '
!" # $
" #
!" # $
#
+%
" #
" # & '
#" #
#" #
#
%
%
" #
" # & '
#
#
" #
" # & '
# ,
(
(
#" #
#" #
3
+
#
.
+
!" # $/
#" #
#
0
!" # $
% " #
!" # $
.
.
+% "
!" #
+
#
#+
$/
$/
#
#
!" #
!
.
.
$/
$/
!
#
Note:
This design is just for convenience in the presentation
and not necessarily the actual design.
Memory-handling (garbage collection) is also
necessary.
4
Generic Design of TTL
and the Adaptation Layer
Application
Algorithms on triangulations
Fixed Application Data Structure
(e.g. half-edge data structure)
Static design
Application
Triangulation
Template Library (TTL)
Generic algorithms based on G-maps, and
simple geometric and topological operations.
Topological elements: Darts D = { d }
Iterators α i : D → D, i = 0,1,2.
namespaces ttl and ttl_util
Adaptation layer
Interface to application data structure.
• Dart class with α-iterators
• Traits class with geometric and topological
operations, and type definitions.
Application Data Structure
Generic design of TTL
5
Adaptation layer
Implements a set of requirements specified by function
templates in TTL used by the application:
Dart class (or struct) with -iterators
Traits class (or struct) with basic geometric predicates,
and geometric modifiers.
namespace ttl and ttl_util:
#include
ttl.h
ttl::locateTriangle( parameters )
or
using namespace ttl;
locateTriangle( parameters )
6
TTL is totally independent of the underlying data
structure in contrast to the a static non-generic design
with algorithms working directly on a specific data
structure; see figure.
7
Topological Queries and the
Dart class
Definition: Topological queries consists of functions that
act on the topology but do not change the topology (or
the geometry) of triangulations.
Implemented generically using darts and -iterators in
G-maps.
Example:
Let d
v i , e j , t k . Is e j a boundary edge?
bool isBoundaryEdge d :
if
d
d
return TRUE
2
// Fixed point!
else
return FALSE
8
The behaviour of isBoundaryEdge d is not affected
by how the incoming dart is implemented
Use a C function template !
namespace ttl {
template class DartType
bool isBoundaryEdge(const DartType& d) {
DartType dart_iter
d;
if (dart_iter.alpha2()
d)
return true;
else
return false;
}
};
Requires a Dart class:
class Dart {
Dart (const Dart& d); // Copy constructor
operator
(const Dart& d) {...};
Dart& alpha2() {...} //
2
d
...
};
9
0
!" # $
#
11 2
0
0
!
#
0
#
4
0
11
# 3
!
4
$ 5
0
5 6
0
5 7
4
$ 5
!
#
#
8/#
" # & '
#
#
8/#
" # & '
8/#
" # & '
4
$ 5
0
5 9
: !
11 25
11 %
!
#
#
5
5
#
8/# +% " #
# 8/# +%
4
&!
5
5
11 25
:
!
" #
$ 5
Dart class for half-edge data structure.
10
Other topological queries in TTL:
bool isBoundaryTriangle(const DartType& d)
bool isBoundaryNode(const DartType& d);
int getDegreeOfNode(const DartType& d);
void getAdjacentTriangles(const DartType& d,
DartType& dt1, DartType& dt2,
DartType& dt3);
Note: Only DartType in interface!
11
... ...
d start
d3
d2
d 2 = α1 α 0 ( d start )
d 3 = α1 α 2
α1 α 2 ( d 2 )
Iteration at the boundary of a triangulation.
void getBoundary(const DartType& d,
list DartType & boundary);
Alternative:
Implement a boundary iterator (a “circulator”) and return
this type from getBoundary !!!
Exercise!
12
“Circulators”, example with Orbit2
Circular sequences (contrary to STL).
template
class DartType
class Orbit2_Iterator {
DartType d_;
public:
Orbit2_Iterator(const DartType& d);
...
DartType& operator*() {return d_;}
Orbit2& operator
() {...; return *this;}
Orbit2& operator- -() {...; return *this;}
};
Exercise: Implement
class Orbit0 and
class Orbit1
How should fixed point be handled, (
2
d
d ?)
13
Geometric Queries and the
Traits Class
v i,
(a)
(b)
d ′ = α1 α 0 (d )
H (d )
v i,
ej
ej
tk
tk
d
d
vi
H (d )
vi
H (d ' )
(b): Intersection of half-planes
PROBLEM. Given a point p
d
v i , e j , t k . Is p
R 2 and a ccw dart
tk ?
Solution:
La H d be the half-plane “left of” d containing v i and
the node of 0 d ; Figure (a).
p
tk
p
Hd
H
1
0
d
H
0
1
d
14
The query p H d can be implemented by evaluating
the sign of a determinant.
Let v i
x1, y1 , vi
x2, y2 , p
x 3 , y 3 and
x1 y1 1
|D|
x2 y2 1
x1
x3 y2
y3
x2
x3 y1
x3 y3 1
p
Hd
|D|
0
Numerical calculations on the application side, in the
adaptation layer, in a traits class!
class MyTraits {
bool inLeftHalfPlane(...)
...
};
15
Definition. A traits class is a C class that encapsulates
a set of types and functions necessary for template
classes and template functions to manipulate objects of
types for which they are instantiated.
Thus, our traits class is an ordinary C class where the
application programmer implements functions required
by function templates in TTL for interfacing the actual
data structure.
implementation of p
C
t k , with d
vi, ej, tk :
namespace ttl {
template class TraitsType, class PointType, class DartType
bool inTriangle(const PointType& p, DartType& d) {
for (int i
0; i
3; i
// d is CCW
){
if (!TraitsType::inLeftHalfPlane(p, d))
return false;
d.alpha0().alpha1();
}
return true;
}
};
16
struct MyTraits { // (or a class)
static bool inLeftHalfPlane(const MyPoint& p, const MyDart& d) {...}
...
};
MyPoint p;
MyDart d;
bool in_triangle
ttl::inTriangle MyTraits (p,d);
...
“Standard functions” like inLeftHalfPlane are also in:
namespace ttl_util {
bool inLeftHalfPlaneFast(const MyPoint& p, const MyDart& d) {...}
double scalarProduct(const DartType& d1, ...);
double crossProduct(const DartType& d1, ...);
...
};
17
Point location in a triangulation
PROBLEM. Given a point p and a triangle t start in
P.
t ; or decide if
Find the triangle t in P such that p
p is outside
.
Fast algorithms for Problem important in,
incremental Delaunay triangulation algorithms,
when evaluating f P x, y .
Solution:
Given d
Assume
2
db
v i , e i , t start oriented ccw in t start .
P has convex boundary:
d b and p
H db
p is outside
P.
18
Algorithm
p
d
Algorithm: Dart locateTriangle (Point p, Dart d, bool
found)
1. d start : d
2. if p H d
3. d : 1 0 d // next edge ccw. in t
4. if d
d start
5.
FOUND : true, RETURN // inside triangle
6. else // try to move to the adjacent triangle
7. if 2 d
d // check if on boundary
8.
FOUND : false, RETURN // outside
9. d start : 0 2 d i
10. d : 1 2 d // next edge ccw. in adj. t
11. GOTO Step 2
19
namespace ttl {
template class TraitsType, class PointType, class DartType
bool locateFace(PointType& point, DartType& dart_iter) {
DartType dart_start
dart_iter;
DartType dart_prev;
for (;;) { // ”endless loop”
if (TraitsType::inLeftHalfPlane(dart_iter, point)) {
dart_iter.alpha0().alpha1();
if (dart_iter
dart_start)
return true; // left to all edges in face
}
else { // try to move to the adjacent triangle
dart_prev
dart_iter;
dart_iter.alpha2();
if (dart_iter
dart_prev)
return false; // iteration to outside boundary
dart_start
dart_iter;
dart_start.alpha0();
dart_iter.alpha1(); // avoid twice on same edge and ccw in next
}
} // end for loop
}
};
20
Geometric and
Topological Modifiers
Assumpton:
Geometric embedding information
only.
3D position of nodes
So far TTL has no modifiers that change positions of
nodes.
Topological modifiers; three kinds:
1. Add nodes, edges and triangles.
2. Remove nodes, edges and triangles.
3. Modifiers that preserve |V|, |E| and |T|
edge-swapping, e.g. inserting constraints.
(Recall also: all possible triangulations of a set of
points can be reached by a sequence of edge-swaps)
21
Swapping and sewing:
d 6′
d4
d 3′
v4
v2
d6
d3
d 4′
ei
d5
v1
d1
d2
ei′
d 2′
d1′
v3
d 5′
Sewing-operations when
Definition:
Two darts d i and d j are said to be k-sewed, or
in a G-map if k d i
d j (and k d j
d i ).
k -sewed,
Swapping e to e involves six sewings:
sew1 d i , d i , i 1, 6.
Sewings are not used in TTL as atomic operations (like
-iterators), thus:
22
Topological modifiers in TTL that need swapping require
a function swapEdge(DartType& d) in the traits
class of the adaptation layer that swaps an edge
associated with the given dart:
Algorithm: MyTraits::swapEdge(DartType& d)
// Triangle “left of” d
d2
2 d1 , d5
1 d2 , d1
d6
0 d2 , d3
1 d6 .
0
d5 , d2
1
d1 ,
// Triangle right of d
d5
1 d1 , d4
d4
1 d6
1
d4 , d6
0
d3 ,
0
d5 , d3
// Make the sewings
for (i 1, , 6)
sew1(d i , d i
23
Other topological modifiers in ttl:
namespace ttl {
insertNode(DartType& d, NodeType& n)
// Requires:
// MyTraits::splitTriangle(DartType& d, NodeType& n);
ttl::removeNode(DartType& d)
// Requires:
// MyTraits::reverse_splitTriangle(DartType& d, NodeType& n);
};
24
Generic Delaunay Triangulation
Incremental Delaunay triangulation:
(a)
(b)
×
×
×
×
×
×
×
×
×
×
×
×
×
×
×
×
(a):
×
×
2
(b):
× node1
×
×
×
×
×
×
×
×
×
×
×
×
×
3
Triangulation::initTwoEnclosingTriangles(
for (i 1, ...)
ttl::insertNode(dart, node i )
25
Step 1 Locate triangle t in N that contains p.
Step 2 Split t into three triangles and obtain N 1 .
Step 3 Swapping procedure to obtain Delaunay
triangulation
(a)
N 1.
(b)
d1,1
d1,2
d1
d3,2
d3,1
p
d3
d0
d2
d2,2
d2,1
After Step 2
Algorithm: ttl::insertNode(Point p, Dart d
1.
2.
3.
4.
5.
6.
7.
8.
dt
ttl::locateTriangle(p, d, found)
d0
app::splitTriangle(d t , p) // Traits
d1
2
1
0
1
2
1 d0
d2
2
1
0
1 d0
d3
2
1
2
0 d0
ttl::recSwapDelaunay(d 1 )
ttl::recSwapDelaunay(d 2 )
ttl::recSwapDelaunay(d 3 )
26
The swapping procedure with dart
algebra:
Algorithm: recSwapDelaunay(Dart d i )
1. if (ttl::circumcircleTest(d i )
TRUE)
2.
RETURN
// Do not swap
3. d i,1
2
1 di
4. d i,2
2
0
1
0 di
5. app::swapEdge(d i ) // In Traits
6. ttl::recSwapDelaunay(d i,1 ) // recursion
7. ttl::recSwapDelaunay(d i,2 ) // recursion
(a)
(b)
d1,1
d1,1
d1,2
d1,2
d1
d3,2
d3,1
d3,2
p
d0
d3
(c)
d2
d2,1
d0
d2,2
(d)
d1,1
d3,2
p
d3
d3
d3,1
d2,2
d3,2
p
d0
d2
d2,1
d1,1
p
d0
d3,1
d3,1
d2,2
d2
d2,1
d2,2
(e)
d2
d2,1
d1,1
p
d0
d3,1
d2,2
d2
d2,1
27
(a)
(b)
d1,1
d1,1
d1,2
d1,2
d1
d3,2
d3,1
d3,2
p
d0
d3
d3,1
d2,2
(c)
d2
d0
d2,2
(d)
d2
d2,1
d1,1
d3,2
p
d3
d3
d2,1
d1,1
d3,2
p
d0
p
d0
d3,1
d3,1
d2,2
d2
d2,1
d2,2
(e)
d2
d2,1
d1,1
p
d0
d3,1
d2,2
d2
d2,1
Algorithm: recSwapDelaunay(Dart d i )
Recall Theorem: On termination, all edges are locally
optimal and N 1 is a Delaunay.
28
The circumcircle test
d3 β
d
d4
ei
d2 α d1
Circumcircle test
Swap iff
sin cos
Interpret the darts d i , i
space.
0,
1, 2, 3, 4 as unit vectors in 3D
sin
d1
d2
e3
sin
d3
d4
e3
cos
where e 3
cos sin
cos
0, 0, 1 .
d1 d2
d3 d4,
29
Assume:
app::crossProduct(d i , d j )
app::scalarProduct(d i , d j )
di
dj
e3
d1 d2
Algorithm: bool ttl::circumcircleTest(Dart d)
1. d 1
1
0
1
2 d
2. d 2
0
1
2 d
3. d 3
0
1 d
4. d 4
1
0
1 d
5. sin app::crossProduct(d 1 , d 2 )
6. sin app::crossProduct(d 3 , d 4 )
7. cos app::scalarProduct(d 1 , d 2 )
8. cos app::scalarProduct(d 3 , d 4 )
9. if sin cos
cos sin
0
10.
return FALSE
// swap the edge
11. else
12.
return TRUE
Notes on TTL:
Step 9 is replaced with more robust tests
Cycling and infinite loops are handled
Default implementations:
ttl_util::crossProduct and
ttl_util::scalarProduct
30
(a)
(b)
×
×
×
×
×
×
×
×
×
×
×
×
×
×
×
×
(c)
(d)
(b):
P
B
Removing artificial boundary:
namespace ttl {
removeBoundaryNode(DartType& d){...}
// Requires: app::removeBoundaryTriangle(d)
};
31
Some final remarks:
Sort point set P lexicographically (cf.
divide-and-conquer algorithm).
Use std::sort in STL and provide
function object (a.k.a. functor) “compare”.
Rule on semantics: darts outside a quadrilateral are not
changed when swapping the diagonal.
Cf. darts d 1,1 and d 1,2 in recSwapDelaunay.
ttl::insertConstraint
(no additional requirements)
Clean interfaces
Compact algorithms
Easy to read and maintain
Probably no significant loss of efficiency (more
efficient than class inheritance and dynamic binding)
-iterators as C
inline functions (in class Dart)
32
Download