Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
K
kicad-source-mirror
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Commits
Open sidebar
Elphel
kicad-source-mirror
Commits
6fa2f060
Commit
6fa2f060
authored
Apr 07, 2014
by
Maciej Suminski
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Formatted ttl library to comply with KiCad coding policy.
parent
a0fb4ed0
Changes
9
Show whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
2654 additions
and
2517 deletions
+2654
-2517
hetriang.cpp
common/geometry/hetriang.cpp
+556
-560
hedart.h
include/ttl/halfedge/hedart.h
+108
-67
hetraits.h
include/ttl/halfedge/hetraits.h
+124
-111
hetriang.h
include/ttl/halfedge/hetriang.h
+277
-207
ttl.h
include/ttl/ttl.h
+1510
-1479
ttl_util.h
include/ttl/ttl_util.h
+53
-67
ratsnest_data.cpp
pcbnew/ratsnest_data.cpp
+17
-17
ratsnest_data.h
pcbnew/ratsnest_data.h
+7
-7
ratsnest_viewitem.cpp
pcbnew/ratsnest_viewitem.cpp
+2
-2
No files found.
common/geometry/hetriang.cpp
View file @
6fa2f060
...
...
@@ -48,154 +48,154 @@
#include <boost/foreach.hpp>
#include <boost/make_shared.hpp>
using
namespace
hed
;
using
namespace
std
;
#ifdef TTL_USE_NODE_ID
int
N
ode
::
id_count
=
0
;
int
N
ODE
::
id_count
=
0
;
#endif
//#define DEBUG_HE
#ifdef DEBUG_HE
#include <iostream>
static
void
errorAndExit
(
char
*
message
)
{
cout
<<
"
\n
!!! ERROR: "
<<
message
<<
" !!!
\n
"
<<
endl
;
exit
(
-
1
);
}
static
void
errorAndExit
(
char
*
aMessage
)
{
cout
<<
"
\n
!!! ERROR: "
<<
aMessage
<<
" !!!
\n
"
<<
endl
;
exit
(
-
1
);
}
#endif
//--------------------------------------------------------------------------------------------------
static
EdgePtr
getLeadingEdgeInTriangle
(
const
EdgePtr
&
e
)
{
EdgePtr
edge
=
e
;
static
EDGE_PTR
getLeadingEdgeInTriangle
(
const
EDGE_PTR
&
aEdge
)
{
EDGE_PTR
edge
=
aEdg
e
;
// Code: 3EF (assumes triangle)
if
(
!
edge
->
isLeadingEdge
())
{
edge
=
edge
->
getNextEdgeInFace
();
if
(
!
edge
->
isLeadingEdge
())
edge
=
edge
->
getNextEdgeInFace
();
if
(
!
edge
->
IsLeadingEdge
()
)
{
edge
=
edge
->
GetNextEdgeInFace
();
if
(
!
edge
->
IsLeadingEdge
()
)
edge
=
edge
->
GetNextEdgeInFace
();
}
if
(
!
edge
->
isLeadingEdge
())
{
return
EdgePtr
();
if
(
!
edge
->
IsLeadingEdge
()
)
{
return
EDGE_PTR
();
}
return
edge
;
}
//--------------------------------------------------------------------------------------------------
static
void
getLimits
(
NodesContainer
::
iterator
first
,
NodesContainer
::
iterator
last
,
int
&
xmin
,
int
&
ymin
,
int
&
xmax
,
int
&
ymax
)
{
static
void
getLimits
(
NODES_CONTAINER
::
iterator
aFirst
,
NODES_CONTAINER
::
iterator
aLast
,
int
&
aXmin
,
int
&
aYmin
,
int
&
aXmax
,
int
&
aYmax
)
{
aXmin
=
aYmin
=
std
::
numeric_limits
<
int
>::
min
();
aXmax
=
aYmax
=
std
::
numeric_limits
<
int
>::
max
();
xmin
=
ymin
=
std
::
numeric_limits
<
int
>::
min
();
xmax
=
ymax
=
std
::
numeric_limits
<
int
>::
max
();
NODES_CONTAINER
::
iterator
it
;
NodesContainer
::
iterator
it
;
for
(
it
=
first
;
it
!=
last
;
++
it
)
{
xmin
=
min
(
xmin
,
(
*
it
)
->
GetX
()
);
ymin
=
min
(
ymin
,
(
*
it
)
->
GetY
()
);
xmax
=
max
(
xmax
,
(
*
it
)
->
GetX
()
);
ymax
=
max
(
ymax
,
(
*
it
)
->
GetY
()
);
for
(
it
=
aFirst
;
it
!=
aLast
;
++
it
)
{
aXmin
=
std
::
min
(
aXmin
,
(
*
it
)
->
GetX
()
);
aYmin
=
std
::
min
(
aYmin
,
(
*
it
)
->
GetY
()
);
aXmax
=
std
::
max
(
aXmax
,
(
*
it
)
->
GetX
()
);
aYmax
=
std
::
max
(
aYmax
,
(
*
it
)
->
GetY
()
);
}
}
//--------------------------------------------------------------------------------------------------
EdgePtr
Triangulation
::
initTwoEnclosingTriangles
(
NodesContainer
::
iterator
first
,
NodesContainer
::
iterator
last
)
{
EDGE_PTR
TRIANGULATION
::
InitTwoEnclosingTriangles
(
NODES_CONTAINER
::
iterator
aFirst
,
NODES_CONTAINER
::
iterator
aLast
)
{
int
xmin
,
ymin
,
xmax
,
ymax
;
getLimits
(
first
,
last
,
xmin
,
ymin
,
xmax
,
ymax
);
getLimits
(
aFirst
,
aLast
,
xmin
,
ymin
,
xmax
,
ymax
);
// Add 10% of range:
double
fac
=
10.0
;
double
dx
=
(
xmax
-
xmin
)
/
fac
;
double
dy
=
(
ymax
-
ymin
)
/
fac
;
double
dx
=
(
xmax
-
xmin
)
/
fac
;
double
dy
=
(
ymax
-
ymin
)
/
fac
;
NodePtr
n1
=
boost
::
make_shared
<
Node
>
(
xmin
-
dx
,
ymin
-
dy
);
NodePtr
n2
=
boost
::
make_shared
<
Node
>
(
xmax
+
dx
,
ymin
-
dy
);
NodePtr
n3
=
boost
::
make_shared
<
Node
>
(
xmax
+
dx
,
ymax
+
dy
);
NodePtr
n4
=
boost
::
make_shared
<
Node
>
(
xmin
-
dx
,
ymax
+
dy
);
NODE_PTR
n1
=
boost
::
make_shared
<
NODE
>
(
xmin
-
dx
,
ymin
-
dy
);
NODE_PTR
n2
=
boost
::
make_shared
<
NODE
>
(
xmax
+
dx
,
ymin
-
dy
);
NODE_PTR
n3
=
boost
::
make_shared
<
NODE
>
(
xmax
+
dx
,
ymax
+
dy
);
NODE_PTR
n4
=
boost
::
make_shared
<
NODE
>
(
xmin
-
dx
,
ymax
+
dy
);
// diagonal
EdgePtr
e1d
=
boost
::
make_shared
<
Edge
>
();
EdgePtr
e2d
=
boost
::
make_shared
<
Edge
>
();
EDGE_PTR
e1d
=
boost
::
make_shared
<
EDGE
>
();
EDGE_PTR
e2d
=
boost
::
make_shared
<
EDGE
>
();
// lower triangle
EdgePtr
e11
=
boost
::
make_shared
<
Edge
>
();
EdgePtr
e12
=
boost
::
make_shared
<
Edge
>
();
EDGE_PTR
e11
=
boost
::
make_shared
<
EDGE
>
();
EDGE_PTR
e12
=
boost
::
make_shared
<
EDGE
>
();
// upper triangle
EdgePtr
e21
=
boost
::
make_shared
<
Edge
>
();
EdgePtr
e22
=
boost
::
make_shared
<
Edge
>
();
EDGE_PTR
e21
=
boost
::
make_shared
<
EDGE
>
();
EDGE_PTR
e22
=
boost
::
make_shared
<
EDGE
>
();
// lower triangle
e1d
->
setSourceNode
(
n3
);
e1d
->
setNextEdgeInFace
(
e11
);
e1d
->
setTwinEdge
(
e2d
);
addLeadingEdge
(
e1d
);
e1d
->
SetSourceNode
(
n3
);
e1d
->
SetNextEdgeInFace
(
e11
);
e1d
->
SetTwinEdge
(
e2d
);
addLeadingEdge
(
e1d
);
e11
->
setSourceNode
(
n1
);
e11
->
setNextEdgeInFace
(
e12
);
e11
->
SetSourceNode
(
n1
);
e11
->
SetNextEdgeInFace
(
e12
);
e12
->
setSourceNode
(
n2
);
e12
->
setNextEdgeInFace
(
e1d
);
e12
->
SetSourceNode
(
n2
);
e12
->
SetNextEdgeInFace
(
e1d
);
// upper triangle
e2d
->
setSourceNode
(
n1
);
e2d
->
setNextEdgeInFace
(
e21
);
e2d
->
setTwinEdge
(
e1d
);
addLeadingEdge
(
e2d
);
e2d
->
SetSourceNode
(
n1
);
e2d
->
SetNextEdgeInFace
(
e21
);
e2d
->
SetTwinEdge
(
e1d
);
addLeadingEdge
(
e2d
);
e21
->
setSourceNode
(
n3
);
e21
->
setNextEdgeInFace
(
e22
);
e21
->
SetSourceNode
(
n3
);
e21
->
SetNextEdgeInFace
(
e22
);
e22
->
setSourceNode
(
n4
);
e22
->
setNextEdgeInFace
(
e2d
);
e22
->
SetSourceNode
(
n4
);
e22
->
SetNextEdgeInFace
(
e2d
);
return
e11
;
}
//--------------------------------------------------------------------------------------------------
Triangulation
::
Triangulation
()
{
helper
=
new
ttl
::
TriangulationHelper
(
*
this
);
TRIANGULATION
::
TRIANGULATION
()
{
m_helper
=
new
ttl
::
TRIANGULATION_HELPER
(
*
this
);
}
//--------------------------------------------------------------------------------------------------
Triangulation
::
Triangulation
(
const
Triangulation
&
tr
)
{
std
::
cout
<<
"Triangulation: Copy constructor not present - EXIT."
;
exit
(
-
1
);
TRIANGULATION
::
TRIANGULATION
(
const
TRIANGULATION
&
aTriangulation
)
{
// Triangulation: Copy constructor not present
assert
(
false
);
}
//--------------------------------------------------------------------------------------------------
Triangulation
::~
Triangulation
()
{
TRIANGULATION
::~
TRIANGULATION
()
{
cleanAll
();
delete
helper
;
delete
m_
helper
;
}
//--------------------------------------------------------------------------------------------------
void
Triangulation
::
createDelaunay
(
NodesContainer
::
iterator
first
,
NodesContainer
::
iterator
last
)
{
void
TRIANGULATION
::
CreateDelaunay
(
NODES_CONTAINER
::
iterator
aFirst
,
NODES_CONTAINER
::
iterator
aLast
)
{
cleanAll
();
EdgePtr
bedge
=
initTwoEnclosingTriangles
(
first
,
last
);
Dart
dc
(
bedge
);
EDGE_PTR
bedge
=
InitTwoEnclosingTriangles
(
aFirst
,
aLast
);
DART
dc
(
bedge
);
Dart
d_iter
=
dc
;
DART
d_iter
=
dc
;
NodesContainer
::
iterator
it
;
for
(
it
=
first
;
it
!=
last
;
++
it
)
{
helper
->
insertNode
<
TTLtraits
>
(
d_iter
,
*
it
);
NODES_CONTAINER
::
iterator
it
;
for
(
it
=
aFirst
;
it
!=
aLast
;
++
it
)
{
m_helper
->
InsertNode
<
TTLtraits
>
(
d_iter
,
*
it
);
}
// In general (e.g. for the triangle based data structure), the initial dart
...
...
@@ -206,112 +206,107 @@ void Triangulation::createDelaunay(NodesContainer::iterator first,
// triangle "outside" the triangulation.)
// Assumes rectangular domain
helper
->
removeRectangularBoundary
<
TTLtraits
>
(
dc
);
m_helper
->
RemoveRectangularBoundary
<
TTLtraits
>
(
dc
);
}
//--------------------------------------------------------------------------------------------------
void
Triangulation
::
removeTriangle
(
EdgePtr
&
edge
)
{
EdgePtr
e1
=
getLeadingEdgeInTriangle
(
edge
);
void
TRIANGULATION
::
RemoveTriangle
(
EDGE_PTR
&
aEdge
)
{
EDGE_PTR
e1
=
getLeadingEdgeInTriangle
(
aEdge
);
#ifdef DEBUG_HE
if
(
!
e1
)
errorAndExit
(
"Triangulation::removeTriangle: could not find leading edge"
);
if
(
!
e1
)
errorAndExit
(
"Triangulation::removeTriangle: could not find leading aEdge"
);
#endif
removeLeadingEdgeFromList
(
e1
);
removeLeadingEdgeFromList
(
e1
);
// cout << "No leading edges = " << leadingEdges_.size() << endl;
// Remove the triangle
EdgePtr
e2
(
e1
->
getNextEdgeInFace
()
);
EdgePtr
e3
(
e2
->
getNextEdgeInFace
()
);
EDGE_PTR
e2
(
e1
->
GetNextEdgeInFace
()
);
EDGE_PTR
e3
(
e2
->
GetNextEdgeInFace
()
);
e1
->
c
lear
();
e2
->
c
lear
();
e3
->
c
lear
();
e1
->
C
lear
();
e2
->
C
lear
();
e3
->
C
lear
();
}
//--------------------------------------------------------------------------------------------------
void
Triangulation
::
reverse_splitTriangle
(
EdgePtr
&
edge
)
{
void
TRIANGULATION
::
ReverseSplitTriangle
(
EDGE_PTR
&
aEdge
)
{
// Reverse operation of splitTriangle
EdgePtr
e1
(
edge
->
getNextEdgeInFace
());
EdgePtr
le
(
getLeadingEdgeInTriangle
(
e1
));
EDGE_PTR
e1
(
aEdge
->
GetNextEdgeInFace
()
);
EDGE_PTR
le
(
getLeadingEdgeInTriangle
(
e1
)
);
#ifdef DEBUG_HE
if
(
!
le
)
errorAndExit
(
"Triangulation::removeTriangle: could not find leading edge"
);
#endif
removeLeadingEdgeFromList
(
le
);
removeLeadingEdgeFromList
(
le
);
EdgePtr
e2
(
e1
->
getNextEdgeInFace
()
->
getTwinEdge
()
->
getNextEdgeInFace
()
);
le
=
getLeadingEdgeInTriangle
(
e2
);
EDGE_PTR
e2
(
e1
->
GetNextEdgeInFace
()
->
GetTwinEdge
()
->
GetNextEdgeInFace
()
);
le
=
getLeadingEdgeInTriangle
(
e2
);
#ifdef DEBUG_HE
if
(
!
le
)
errorAndExit
(
"Triangulation::removeTriangle: could not find leading edge"
);
#endif
removeLeadingEdgeFromList
(
le
);
removeLeadingEdgeFromList
(
le
);
EdgePtr
e3
(
edge
->
getTwinEdge
()
->
getNextEdgeInFace
()
->
getNextEdgeInFace
()
);
le
=
getLeadingEdgeInTriangle
(
e3
);
EDGE_PTR
e3
(
aEdge
->
GetTwinEdge
()
->
GetNextEdgeInFace
()
->
GetNextEdgeInFace
()
);
le
=
getLeadingEdgeInTriangle
(
e3
);
#ifdef DEBUG_HE
if
(
!
le
)
errorAndExit
(
"Triangulation::removeTriangle: could not find leading edge"
);
#endif
removeLeadingEdgeFromList
(
le
);
removeLeadingEdgeFromList
(
le
);
// The three triangles at the node have now been removed
// from the triangulation, but the arcs have not been deleted.
// Next delete the 6 half edges radiating from the node
// The node is maintained by handle and need not be deleted explicitly
EdgePtr
estar
=
e
dge
;
EdgePtr
enext
=
estar
->
getTwinEdge
()
->
g
etNextEdgeInFace
();
estar
->
getTwinEdge
()
->
c
lear
();
estar
->
c
lear
();
EDGE_PTR
estar
=
aE
dge
;
EDGE_PTR
enext
=
estar
->
GetTwinEdge
()
->
G
etNextEdgeInFace
();
estar
->
GetTwinEdge
()
->
C
lear
();
estar
->
C
lear
();
estar
=
enext
;
enext
=
estar
->
getTwinEdge
()
->
getNextEdgeInFace
();
estar
->
getTwinEdge
()
->
clear
();
estar
->
clear
();
enext
->
getTwinEdge
()
->
clear
();
enext
->
clear
();
enext
=
estar
->
GetTwinEdge
()
->
GetNextEdgeInFace
();
estar
->
GetTwinEdge
()
->
Clear
();
estar
->
Clear
();
enext
->
GetTwinEdge
()
->
Clear
();
enext
->
Clear
();
// Create the new triangle
e1
->
setNextEdgeInFace
(
e2
);
e2
->
setNextEdgeInFace
(
e3
);
e3
->
setNextEdgeInFace
(
e1
);
addLeadingEdge
(
e1
);
e1
->
SetNextEdgeInFace
(
e2
);
e2
->
SetNextEdgeInFace
(
e3
);
e3
->
SetNextEdgeInFace
(
e1
);
addLeadingEdge
(
e1
);
}
//--------------------------------------------------------------------------------------------------
Dart
Triangulation
::
createDart
()
{
DART
TRIANGULATION
::
CreateDart
()
{
// Return an arbitrary CCW dart
return
Dart
(
*
leadingEdges_
.
begin
()
);
return
DART
(
*
m_leadingEdges
.
begin
()
);
}
//--------------------------------------------------------------------------------------------------
bool
Triangulation
::
removeLeadingEdgeFromList
(
EdgePtr
&
leadingEdge
)
{
bool
TRIANGULATION
::
removeLeadingEdgeFromList
(
EDGE_PTR
&
aLeadingEdge
)
{
// Remove the edge from the list of leading edges,
// but don't delete it.
// Also set flag for leading edge to false.
// Must search from start of list. Since edges are added to the
// start of the list during triangulation, this operation will
// normally be fast (when used in the triangulation algorithm)
list
<
EdgePtr
>::
iterator
it
;
for
(
it
=
leadingEdges_
.
begin
();
it
!=
leadingEdges_
.
end
();
++
it
)
{
EdgePtr
edge
=
*
it
;
if
(
edge
==
leadingEdge
)
{
std
::
list
<
EDGE_PTR
>::
iterator
it
;
for
(
it
=
m_leadingEdges
.
begin
();
it
!=
m_leadingEdges
.
end
();
++
it
)
{
EDGE_PTR
edge
=
*
it
;
edge
->
setAsLeadingEdge
(
false
);
it
=
leadingEdges_
.
erase
(
it
);
if
(
edge
==
aLeadingEdge
)
{
edge
->
SetAsLeadingEdge
(
false
);
it
=
m_leadingEdges
.
erase
(
it
);
return
true
;
}
...
...
@@ -321,73 +316,75 @@ bool Triangulation::removeLeadingEdgeFromList(EdgePtr& leadingEdge) {
}
//--------------------------------------------------------------------------------------------------
void
Triangulation
::
cleanAll
()
{
BOOST_FOREACH
(
EdgePtr
&
edge
,
leadingEdges_
)
edge
->
setNextEdgeInFace
(
EdgePtr
()
);
void
TRIANGULATION
::
cleanAll
()
{
BOOST_FOREACH
(
EDGE_PTR
&
edge
,
m_leadingEdges
)
edge
->
SetNextEdgeInFace
(
EDGE_PTR
()
);
}
//--------------------------------------------------------------------------------------------------
void
Triangulation
::
swapEdge
(
Dart
&
dart
)
{
swapEdge
(
dart
.
getEdge
()
);
void
TRIANGULATION
::
swapEdge
(
DART
&
aDart
)
{
SwapEdge
(
aDart
.
GetEdge
()
);
}
//--------------------------------------------------------------------------------------------------
void
Triangulation
::
splitTriangle
(
Dart
&
dart
,
const
NodePtr
&
point
)
{
EdgePtr
edge
=
splitTriangle
(
dart
.
getEdge
(),
point
);
dart
.
init
(
edge
);
void
TRIANGULATION
::
splitTriangle
(
DART
&
aDart
,
const
NODE_PTR
&
aPoint
)
{
EDGE_PTR
edge
=
SplitTriangle
(
aDart
.
GetEdge
(),
aPoint
);
aDart
.
Init
(
edge
);
}
//--------------------------------------------------------------------------------------------------
void
Triangulation
::
reverse_splitTriangle
(
Dart
&
dart
)
{
reverse_splitTriangle
(
dart
.
getEdge
()
);
void
TRIANGULATION
::
reverseSplitTriangle
(
DART
&
aDart
)
{
ReverseSplitTriangle
(
aDart
.
GetEdge
()
);
}
//--------------------------------------------------------------------------------------------------
void
Triangulation
::
removeBoundaryTriangle
(
Dart
&
d
)
{
removeTriangle
(
d
.
getEdge
()
);
void
TRIANGULATION
::
removeBoundaryTriangle
(
DART
&
aDart
)
{
RemoveTriangle
(
aDart
.
GetEdge
()
);
}
#ifdef TTL_USE_NODE_FLAG
//--------------------------------------------------------------------------------------------------
// This is a "template" for accessing all nodes (but multiple tests)
void
Triangulation
::
flagNodes
(
bool
flag
)
const
{
list
<
EdgePtr
>::
const_iterator
it
;
for
(
it
=
leadingEdges_
.
begin
();
it
!=
leadingEdges_
.
end
();
++
it
)
{
EdgePtr
edge
=
*
it
;
for
(
int
i
=
0
;
i
<
3
;
++
i
)
{
edge
->
getSourceNode
()
->
SetFlag
(
flag
);
edge
=
edge
->
g
etNextEdgeInFace
();
void
TRIANGULATION
::
FlagNodes
(
bool
aFlag
)
const
{
std
::
list
<
EDGE_PTR
>::
const_iterator
it
;
for
(
it
=
m_leadingEdges
.
begin
();
it
!=
m_leadingEdges
.
end
();
++
it
)
{
EDGE_PTR
edge
=
*
it
;
for
(
int
i
=
0
;
i
<
3
;
++
i
)
{
edge
->
GetSourceNode
()
->
SetFlag
(
aFlag
);
edge
=
edge
->
G
etNextEdgeInFace
();
}
}
}
//--------------------------------------------------------------------------------------------------
list
<
NodePtr
>*
Triangulation
::
getNodes
()
const
{
flagNodes
(
false
)
;
list
<
NodePtr
>*
nodeList
=
new
list
<
NodePtr
>
;
std
::
list
<
NODE_PTR
>*
TRIANGULATION
::
GetNodes
()
const
{
FlagNodes
(
false
);
std
::
list
<
NODE_PTR
>*
nodeList
=
new
std
::
list
<
NODE_PTR
>
;
std
::
list
<
EDGE_PTR
>::
const_iterator
it
;
list
<
EdgePtr
>::
const_iterator
it
;
for
(
it
=
leadingEdges_
.
begin
();
it
!=
leadingEdges_
.
end
();
++
it
)
{
EdgePtr
edge
=
*
it
;
for
(
it
=
m_leadingEdges
.
begin
();
it
!=
m_leadingEdges
.
end
();
++
it
)
{
EDGE_PTR
edge
=
*
it
;
for
(
int
i
=
0
;
i
<
3
;
++
i
)
{
const
NodePtr
&
node
=
edge
->
getSourceNode
();
for
(
int
i
=
0
;
i
<
3
;
++
i
)
{
const
NODE_PTR
&
node
=
edge
->
GetSourceNode
();
if
(
node
->
GetFlag
()
==
false
)
{
nodeList
->
push_back
(
node
);
node
->
SetFlag
(
true
);
if
(
node
->
GetFlag
()
==
false
)
{
nodeList
->
push_back
(
node
);
node
->
SetFlag
(
true
);
}
edge
=
edge
->
g
etNextEdgeInFace
();
edge
=
edge
->
G
etNextEdgeInFace
();
}
}
return
nodeList
;
...
...
@@ -395,42 +392,38 @@ list<NodePtr>* Triangulation::getNodes() const {
#endif
//--------------------------------------------------------------------------------------------------
list
<
EdgePtr
>*
Triangulation
::
getEdges
(
bool
skip_boundary_edges
)
const
{
std
::
list
<
EDGE_PTR
>*
TRIANGULATION
::
GetEdges
(
bool
aSkipBoundaryEdges
)
const
{
// collect all arcs (one half edge for each arc)
// (boundary edges are also collected).
list
<
EdgePtr
>::
const_iterator
it
;
list
<
EdgePtr
>*
elist
=
new
list
<
EdgePtr
>
;
for
(
it
=
leadingEdges_
.
begin
();
it
!=
leadingEdges_
.
end
();
++
it
)
{
EdgePtr
edge
=
*
it
;
for
(
int
i
=
0
;
i
<
3
;
++
i
)
{
EdgePtr
twinedge
=
edge
->
getTwinEdge
();
std
::
list
<
EDGE_PTR
>::
const_iterator
it
;
std
::
list
<
EDGE_PTR
>*
elist
=
new
std
::
list
<
EDGE_PTR
>
;
for
(
it
=
m_leadingEdges
.
begin
();
it
!=
m_leadingEdges
.
end
();
++
it
)
{
EDGE_PTR
edge
=
*
it
;
for
(
int
i
=
0
;
i
<
3
;
++
i
)
{
EDGE_PTR
twinedge
=
edge
->
GetTwinEdge
();
// only one of the half-edges
if
(
(
!
twinedge
&&
!
skip_boundary_edges
)
||
(
twinedge
&&
((
size_t
)
edge
.
get
()
>
(
size_t
)
twinedge
.
get
())
)
)
elist
->
push_front
(
edge
);
if
(
(
!
twinedge
&&
!
aSkipBoundaryEdges
)
||
(
twinedge
&&
(
(
size_t
)
edge
.
get
()
>
(
size_t
)
twinedge
.
get
()
)
)
)
elist
->
push_front
(
edge
);
edge
=
edge
->
g
etNextEdgeInFace
();
edge
=
edge
->
G
etNextEdgeInFace
();
}
}
return
elist
;
}
//--------------------------------------------------------------------------------------------------
EdgePtr
Triangulation
::
splitTriangle
(
EdgePtr
&
edge
,
const
NodePtr
&
point
)
{
EDGE_PTR
TRIANGULATION
::
SplitTriangle
(
EDGE_PTR
&
aEdge
,
const
NODE_PTR
&
aPoint
)
{
// Add a node by just splitting a triangle into three triangles
// Assumes the half edge is located in the triangle
// Returns a half edge with source node as the new node
// double x, y, z;
// x = point.x();
// y = point.y();
// z = point.z();
// Assumes the half aEdge is located in the triangle
// Returns a half aEdge with source node as the new node
// e#_n are new edges
// e# are existing edges
...
...
@@ -438,158 +431,149 @@ EdgePtr Triangulation::splitTriangle(EdgePtr& edge, const NodePtr& point) {
// e##_n are edges incident to the new node
// Add the node to the structure
//NodePtr
new_node(new Node(x,y,z));
NodePtr
n1
(
edge
->
getSourceNode
()
);
EdgePtr
e1
(
edge
);
EdgePtr
e2
(
edge
->
getNextEdgeInFace
()
);
NodePtr
n2
(
e2
->
getSourceNode
()
);
EdgePtr
e3
(
e2
->
getNextEdgeInFace
()
);
NodePtr
n3
(
e3
->
getSourceNode
()
);
EdgePtr
e1_n
=
boost
::
make_shared
<
Edge
>
();
EdgePtr
e11_n
=
boost
::
make_shared
<
Edge
>
();
EdgePtr
e2_n
=
boost
::
make_shared
<
Edge
>
();
EdgePtr
e22_n
=
boost
::
make_shared
<
Edge
>
();
EdgePtr
e3_n
=
boost
::
make_shared
<
Edge
>
();
EdgePtr
e33_n
=
boost
::
make_shared
<
Edge
>
();
e1_n
->
setSourceNode
(
n1
);
e11_n
->
setSourceNode
(
point
);
e2_n
->
setSourceNode
(
n2
);
e22_n
->
setSourceNode
(
point
);
e3_n
->
setSourceNode
(
n3
);
e33_n
->
setSourceNode
(
point
);
e1_n
->
setTwinEdge
(
e11_n
);
e11_n
->
setTwinEdge
(
e1_n
);
e2_n
->
setTwinEdge
(
e22_n
);
e22_n
->
setTwinEdge
(
e2_n
);
e3_n
->
setTwinEdge
(
e33_n
);
e33_n
->
setTwinEdge
(
e3_n
);
e1_n
->
setNextEdgeInFace
(
e33_n
);
e2_n
->
setNextEdgeInFace
(
e11_n
);
e3_n
->
setNextEdgeInFace
(
e22_n
);
e11_n
->
setNextEdgeInFace
(
e1
);
e22_n
->
setNextEdgeInFace
(
e2
);
e33_n
->
setNextEdgeInFace
(
e3
);
// and update old's next e
dge
e1
->
setNextEdgeInFace
(
e2_n
);
e2
->
setNextEdgeInFace
(
e3_n
);
e3
->
setNextEdgeInFace
(
e1_n
);
//NODE_PTR
new_node(new Node(x,y,z));
NODE_PTR
n1
(
aEdge
->
GetSourceNode
()
);
EDGE_PTR
e1
(
aEdge
);
EDGE_PTR
e2
(
aEdge
->
GetNextEdgeInFace
()
);
NODE_PTR
n2
(
e2
->
GetSourceNode
()
);
EDGE_PTR
e3
(
e2
->
GetNextEdgeInFace
()
);
NODE_PTR
n3
(
e3
->
GetSourceNode
()
);
EDGE_PTR
e1_n
=
boost
::
make_shared
<
EDGE
>
();
EDGE_PTR
e11_n
=
boost
::
make_shared
<
EDGE
>
();
EDGE_PTR
e2_n
=
boost
::
make_shared
<
EDGE
>
();
EDGE_PTR
e22_n
=
boost
::
make_shared
<
EDGE
>
();
EDGE_PTR
e3_n
=
boost
::
make_shared
<
EDGE
>
();
EDGE_PTR
e33_n
=
boost
::
make_shared
<
EDGE
>
();
e1_n
->
SetSourceNode
(
n1
);
e11_n
->
SetSourceNode
(
aPoint
);
e2_n
->
SetSourceNode
(
n2
);
e22_n
->
SetSourceNode
(
aPoint
);
e3_n
->
SetSourceNode
(
n3
);
e33_n
->
SetSourceNode
(
aPoint
);
e1_n
->
SetTwinEdge
(
e11_n
);
e11_n
->
SetTwinEdge
(
e1_n
);
e2_n
->
SetTwinEdge
(
e22_n
);
e22_n
->
SetTwinEdge
(
e2_n
);
e3_n
->
SetTwinEdge
(
e33_n
);
e33_n
->
SetTwinEdge
(
e3_n
);
e1_n
->
SetNextEdgeInFace
(
e33_n
);
e2_n
->
SetNextEdgeInFace
(
e11_n
);
e3_n
->
SetNextEdgeInFace
(
e22_n
);
e11_n
->
SetNextEdgeInFace
(
e1
);
e22_n
->
SetNextEdgeInFace
(
e2
);
e33_n
->
SetNextEdgeInFace
(
e3
);
// and update old's next aE
dge
e1
->
SetNextEdgeInFace
(
e2_n
);
e2
->
SetNextEdgeInFace
(
e3_n
);
e3
->
SetNextEdgeInFace
(
e1_n
);
// add the three new leading edges,
// Must remove the old leading e
dge from the list.
// Use the field telling if an edge is a leading e
dge
// Must remove the old leading aE
dge from the list.
// Use the field telling if an aEdge is a leading aE
dge
// NOTE: Must search in the list!!!
if
(
e1
->
isLeadingEdge
()
)
removeLeadingEdgeFromList
(
e1
);
else
if
(
e2
->
isLeadingEdge
()
)
removeLeadingEdgeFromList
(
e2
);
else
if
(
e3
->
isLeadingEdge
()
)
removeLeadingEdgeFromList
(
e3
);
if
(
e1
->
IsLeadingEdge
()
)
removeLeadingEdgeFromList
(
e1
);
else
if
(
e2
->
IsLeadingEdge
()
)
removeLeadingEdgeFromList
(
e2
);
else
if
(
e3
->
IsLeadingEdge
()
)
removeLeadingEdgeFromList
(
e3
);
else
assert
(
false
);
// one of the edges should be leading
addLeadingEdge
(
e1_n
);
addLeadingEdge
(
e2_n
);
addLeadingEdge
(
e3_n
);
addLeadingEdge
(
e1_n
);
addLeadingEdge
(
e2_n
);
addLeadingEdge
(
e3_n
);
// Return a half e
dge incident to the new node (with the new node as source node)
// Return a half aE
dge incident to the new node (with the new node as source node)
return
e11_n
;
}
//--------------------------------------------------------------------------------------------------
void
Triangulation
::
swapEdge
(
EdgePtr
&
diagonal
)
{
void
TRIANGULATION
::
SwapEdge
(
EDGE_PTR
&
aDiagonal
)
{
// Note that diagonal is both input and output and it is always
// kept in counterclockwise direction (this is not required by all
// functions in TriangulationHelper now)
// Swap by rotating counterclockwise
// Use the same objects - no deletion or new objects
EdgePtr
eL
(
diagonal
);
EdgePtr
eR
(
eL
->
getTwinEdge
()
);
EdgePtr
eL_1
(
eL
->
getNextEdgeInFace
()
);
EdgePtr
eL_2
(
eL_1
->
getNextEdgeInFace
()
);
EdgePtr
eR_1
(
eR
->
getNextEdgeInFace
()
);
EdgePtr
eR_2
(
eR_1
->
getNextEdgeInFace
()
);
EDGE_PTR
eL
(
aDiagonal
);
EDGE_PTR
eR
(
eL
->
GetTwinEdge
()
);
EDGE_PTR
eL_1
(
eL
->
GetNextEdgeInFace
()
);
EDGE_PTR
eL_2
(
eL_1
->
GetNextEdgeInFace
()
);
EDGE_PTR
eR_1
(
eR
->
GetNextEdgeInFace
()
);
EDGE_PTR
eR_2
(
eR_1
->
GetNextEdgeInFace
()
);
// avoid node to be dereferenced to zero and deleted
NodePtr
nR
(
eR_2
->
getSourceNode
()
);
NodePtr
nL
(
eL_2
->
getSourceNode
()
);
NODE_PTR
nR
(
eR_2
->
GetSourceNode
()
);
NODE_PTR
nL
(
eL_2
->
GetSourceNode
()
);
eL
->
setSourceNode
(
nR
);
eR
->
setSourceNode
(
nL
);
eL
->
SetSourceNode
(
nR
);
eR
->
SetSourceNode
(
nL
);
// and now 6 1-sewings
eL
->
setNextEdgeInFace
(
eL_2
);
eL_2
->
setNextEdgeInFace
(
eR_1
);
eR_1
->
setNextEdgeInFace
(
eL
);
eR
->
setNextEdgeInFace
(
eR_2
);
eR_2
->
setNextEdgeInFace
(
eL_1
);
eL_1
->
setNextEdgeInFace
(
eR
);
if
(
eL
->
isLeadingEdge
()
)
removeLeadingEdgeFromList
(
eL
);
else
if
(
eL_1
->
isLeadingEdge
()
)
removeLeadingEdgeFromList
(
eL_1
);
else
if
(
eL_2
->
isLeadingEdge
()
)
removeLeadingEdgeFromList
(
eL_2
);
if
(
eR
->
isLeadingEdge
()
)
removeLeadingEdgeFromList
(
eR
);
else
if
(
eR_1
->
isLeadingEdge
()
)
removeLeadingEdgeFromList
(
eR_1
);
else
if
(
eR_2
->
isLeadingEdge
()
)
removeLeadingEdgeFromList
(
eR_2
);
addLeadingEdge
(
eL
);
addLeadingEdge
(
eR
);
eL
->
SetNextEdgeInFace
(
eL_2
);
eL_2
->
SetNextEdgeInFace
(
eR_1
);
eR_1
->
SetNextEdgeInFace
(
eL
);
eR
->
SetNextEdgeInFace
(
eR_2
);
eR_2
->
SetNextEdgeInFace
(
eL_1
);
eL_1
->
SetNextEdgeInFace
(
eR
);
if
(
eL
->
IsLeadingEdge
()
)
removeLeadingEdgeFromList
(
eL
);
else
if
(
eL_1
->
IsLeadingEdge
()
)
removeLeadingEdgeFromList
(
eL_1
);
else
if
(
eL_2
->
IsLeadingEdge
()
)
removeLeadingEdgeFromList
(
eL_2
);
if
(
eR
->
IsLeadingEdge
()
)
removeLeadingEdgeFromList
(
eR
);
else
if
(
eR_1
->
IsLeadingEdge
()
)
removeLeadingEdgeFromList
(
eR_1
);
else
if
(
eR_2
->
IsLeadingEdge
()
)
removeLeadingEdgeFromList
(
eR_2
);
addLeadingEdge
(
eL
);
addLeadingEdge
(
eR
);
}
////--------------------------------------------------------------------------
//static void printEdge(const Dart& dart, ostream& ofile) {
//
// Dart d0 = dart;
// d0.alpha0();
//
// ofile << dart.x() << " " << dart.y() << endl;
// ofile << d0.x() << " " << d0.y() << endl;
//}
//--------------------------------------------------------------------------
bool
Triangulation
::
checkDelaunay
()
const
{
bool
TRIANGULATION
::
CheckDelaunay
()
const
{
// ???? outputs !!!!
// ofstream os("qweND.dat");
const
list
<
EdgePtr
>&
leadingEdges
=
g
etLeadingEdges
();
const
std
::
list
<
EDGE_PTR
>&
leadingEdges
=
G
etLeadingEdges
();
list
<
EdgePtr
>::
const_iterator
it
;
std
::
list
<
EDGE_PTR
>::
const_iterator
it
;
bool
ok
=
true
;
int
noNotDelaunay
=
0
;
for
(
it
=
leadingEdges
.
begin
();
it
!=
leadingEdges
.
end
();
++
it
)
{
EdgePtr
edge
=
*
it
;
for
(
it
=
leadingEdges
.
begin
();
it
!=
leadingEdges
.
end
();
++
it
)
{
EDGE_PTR
edge
=
*
it
;
for
(
int
i
=
0
;
i
<
3
;
++
i
)
{
EdgePtr
twinedge
=
edge
->
getTwinEdge
();
for
(
int
i
=
0
;
i
<
3
;
++
i
)
{
EDGE_PTR
twinedge
=
edge
->
GetTwinEdge
();
// only one of the half-edges
if
(
!
twinedge
||
(
size_t
)
edge
.
get
()
>
(
size_t
)
twinedge
.
get
())
{
Dart
dart
(
edge
);
if
(
helper
->
swapTestDelaunay
<
TTLtraits
>
(
dart
))
{
if
(
!
twinedge
||
(
size_t
)
edge
.
get
()
>
(
size_t
)
twinedge
.
get
()
)
{
DART
dart
(
edge
);
if
(
m_helper
->
SwapTestDelaunay
<
TTLtraits
>
(
dart
)
)
{
noNotDelaunay
++
;
//printEdge(dart,os); os << "\n";
...
...
@@ -597,7 +581,8 @@ bool Triangulation::checkDelaunay() const {
//cout << "............. not Delaunay .... " << endl;
}
}
edge
=
edge
->
getNextEdgeInFace
();
edge
=
edge
->
GetNextEdgeInFace
();
}
}
...
...
@@ -609,9 +594,8 @@ bool Triangulation::checkDelaunay() const {
}
//--------------------------------------------------------------------------------------------------
void
Triangulation
::
optimizeDelaunay
()
{
void
TRIANGULATION
::
OptimizeDelaunay
()
{
// This function is also present in ttl where it is implemented
// generically.
// The implementation below is tailored for the half-edge data structure,
...
...
@@ -619,114 +603,126 @@ void Triangulation::optimizeDelaunay() {
// Collect all interior edges (one half edge for each arc)
bool
skip_boundary_edges
=
true
;
list
<
EdgePtr
>*
elist
=
getEdges
(
skip_boundary_edges
);
std
::
list
<
EDGE_PTR
>*
elist
=
GetEdges
(
skip_boundary_edges
);
// Assumes that elist has only one half-edge for each arc.
bool
cycling_check
=
true
;
bool
optimal
=
false
;
list
<
EdgePtr
>::
const_iterator
it
;
while
(
!
optimal
)
{
std
::
list
<
EDGE_PTR
>::
const_iterator
it
;
while
(
!
optimal
)
{
optimal
=
true
;
for
(
it
=
elist
->
begin
();
it
!=
elist
->
end
();
++
it
)
{
EdgePtr
edge
=
*
it
;
Dart
dart
(
edge
);
for
(
it
=
elist
->
begin
();
it
!=
elist
->
end
();
++
it
)
{
EDGE_PTR
edge
=
*
it
;
DART
dart
(
edge
);
// Constrained edges should not be swapped
if
(
helper
->
swapTestDelaunay
<
TTLtraits
>
(
dart
,
cycling_check
))
{
if
(
m_helper
->
SwapTestDelaunay
<
TTLtraits
>
(
dart
,
cycling_check
)
)
{
optimal
=
false
;
swapEdge
(
edge
);
SwapEdge
(
edge
);
}
}
}
delete
elist
;
}
//--------------------------------------------------------------------------------------------------
EdgePtr
Triangulation
::
getInteriorNode
()
const
{
EDGE_PTR
TRIANGULATION
::
GetInteriorNode
()
const
{
const
std
::
list
<
EDGE_PTR
>&
leadingEdges
=
GetLeadingEdges
();
std
::
list
<
EDGE_PTR
>::
const_iterator
it
;
const
list
<
EdgePtr
>&
leadingEdges
=
getLeadingEdges
();
list
<
EdgePtr
>::
const_iterator
it
;
for
(
it
=
leadingEdges
.
begin
();
it
!=
leadingEdges
.
end
();
++
it
)
{
EdgePtr
edge
=
*
it
;
for
(
it
=
leadingEdges
.
begin
();
it
!=
leadingEdges
.
end
();
++
it
)
{
EDGE_PTR
edge
=
*
it
;
// multiple checks, but only until found
for
(
int
i
=
0
;
i
<
3
;
++
i
)
{
if
(
edge
->
getTwinEdge
())
{
if
(
!
helper
->
isBoundaryNode
(
Dart
(
edge
)))
for
(
int
i
=
0
;
i
<
3
;
++
i
)
{
if
(
edge
->
GetTwinEdge
()
)
{
if
(
!
m_helper
->
IsBoundaryNode
(
DART
(
edge
)
)
)
return
edge
;
}
edge
=
edge
->
getNextEdgeInFace
();
edge
=
edge
->
GetNextEdgeInFace
();
}
}
return
EdgePtr
();
// no boundary nodes
return
EDGE_PTR
();
// no boundary nodes
}
//--------------------------------------------------------------------------------------------------
EdgePtr
Triangulation
::
getBoundaryEdgeInTriangle
(
const
EdgePtr
&
e
)
const
{
EdgePtr
edge
=
e
;
EDGE_PTR
TRIANGULATION
::
GetBoundaryEdgeInTriangle
(
const
EDGE_PTR
&
aEdge
)
const
{
EDGE_PTR
edge
=
aEdg
e
;
if
(
helper
->
isBoundaryEdge
(
Dart
(
edge
))
)
if
(
m_helper
->
IsBoundaryEdge
(
DART
(
edge
)
)
)
return
edge
;
edge
=
edge
->
g
etNextEdgeInFace
();
if
(
helper
->
isBoundaryEdge
(
Dart
(
edge
))
)
edge
=
edge
->
G
etNextEdgeInFace
();
if
(
m_helper
->
IsBoundaryEdge
(
DART
(
edge
)
)
)
return
edge
;
edge
=
edge
->
g
etNextEdgeInFace
();
if
(
helper
->
isBoundaryEdge
(
Dart
(
edge
))
)
edge
=
edge
->
G
etNextEdgeInFace
();
if
(
m_helper
->
IsBoundaryEdge
(
DART
(
edge
)
)
)
return
edge
;
return
EdgePtr
();
return
EDGE_PTR
();
}
//--------------------------------------------------------------------------------------------------
EdgePtr
Triangulation
::
getBoundaryEdge
()
const
{
EDGE_PTR
TRIANGULATION
::
GetBoundaryEdge
()
const
{
// Get an arbitrary (CCW) boundary edge
// If the triangulation is closed, NULL is returned
const
std
::
list
<
EDGE_PTR
>&
leadingEdges
=
GetLeadingEdges
();
std
::
list
<
EDGE_PTR
>::
const_iterator
it
;
EDGE_PTR
edge
;
const
list
<
EdgePtr
>&
leadingEdges
=
getLeadingEdges
();
list
<
EdgePtr
>::
const_iterator
it
;
EdgePtr
edge
;
for
(
it
=
leadingEdges
.
begin
();
it
!=
leadingEdges
.
end
();
++
it
)
{
edge
=
getBoundaryEdgeInTriangle
(
*
it
);
for
(
it
=
leadingEdges
.
begin
();
it
!=
leadingEdges
.
end
();
++
it
)
{
edge
=
GetBoundaryEdgeInTriangle
(
*
it
);
if
(
edge
)
if
(
edge
)
return
edge
;
}
return
EdgePtr
();
return
EDGE_PTR
();
}
//--------------------------------------------------------------------------------------------------
void
Triangulation
::
printEdges
(
ofstream
&
os
)
const
{
void
TRIANGULATION
::
PrintEdges
(
std
::
ofstream
&
aOutput
)
const
{
// Print source node and target node for each edge face by face,
// but only one of the half-edges.
const
std
::
list
<
EDGE_PTR
>&
leadingEdges
=
GetLeadingEdges
();
std
::
list
<
EDGE_PTR
>::
const_iterator
it
;
const
list
<
EdgePtr
>&
leadingEdges
=
getLeadingEdges
();
list
<
EdgePtr
>::
const_iterator
it
;
for
(
it
=
leadingEdges
.
begin
();
it
!=
leadingEdges
.
end
();
++
it
)
{
EdgePtr
edge
=
*
it
;
for
(
it
=
leadingEdges
.
begin
();
it
!=
leadingEdges
.
end
();
++
it
)
{
EDGE_PTR
edge
=
*
it
;
for
(
int
i
=
0
;
i
<
3
;
++
i
)
{
EdgePtr
twinedge
=
edge
->
getTwinEdge
();
for
(
int
i
=
0
;
i
<
3
;
++
i
)
{
EDGE_PTR
twinedge
=
edge
->
GetTwinEdge
();
// Print only one edge (the highest value of the pointer)
if
(
!
twinedge
||
(
size_t
)
edge
.
get
()
>
(
size_t
)
twinedge
.
get
())
{
if
(
!
twinedge
||
(
size_t
)
edge
.
get
()
>
(
size_t
)
twinedge
.
get
()
)
{
// Print source node and target node
NodePtr
node
=
edge
->
g
etSourceNode
();
os
<<
node
->
GetX
()
<<
" "
<<
node
->
GetY
()
<<
endl
;
node
=
edge
->
g
etTargetNode
();
os
<<
node
->
GetX
()
<<
" "
<<
node
->
GetY
()
<<
endl
;
os
<<
'\n'
;
// blank line
NODE_PTR
node
=
edge
->
G
etSourceNode
();
aOutput
<<
node
->
GetX
()
<<
" "
<<
node
->
GetY
()
<<
std
::
endl
;
node
=
edge
->
G
etTargetNode
();
aOutput
<<
node
->
GetX
()
<<
" "
<<
node
->
GetY
()
<<
std
::
endl
;
aOutput
<<
'\n'
;
// blank line
}
edge
=
edge
->
getNextEdgeInFace
();
edge
=
edge
->
GetNextEdgeInFace
();
}
}
}
include/ttl/halfedge/hedart.h
View file @
6fa2f060
...
...
@@ -40,111 +40,152 @@
#ifndef _HALF_EDGE_DART_
#define _HALF_EDGE_DART_
#include <ttl/halfedge/hetriang.h>
namespace
hed
{
//------------------------------------------------------------------------------------------------
// Dart class for the half-edge data structure
//------------------------------------------------------------------------------------------------
/** \class Dart
namespace
hed
{
/**
* \class Dart
* \brief \b %Dart class for the half-edge data structure.
*
* See \ref api for a detailed description of how the member functions
* should be implemented.
*/
class
DART
{
EDGE_PTR
m_edge
;
class
Dart
{
EdgePtr
edge_
;
bool
dir_
;
// true if dart is counterclockwise in face
/// Dart direction: true if dart is counterclockwise in face
bool
m_dir
;
public
:
public
:
/// Default constructor
Dart
()
{
dir_
=
true
;
}
DART
()
{
m_dir
=
true
;
}
/// Constructor
Dart
(
const
EdgePtr
&
edge
,
bool
dir
=
true
)
{
edge_
=
edge
;
dir_
=
dir
;
}
DART
(
const
EDGE_PTR
&
aEdge
,
bool
aDir
=
true
)
{
m_edge
=
aEdge
;
m_dir
=
aDir
;
}
/// Copy constructor
Dart
(
const
Dart
&
dart
)
{
edge_
=
dart
.
edge_
;
dir_
=
dart
.
dir_
;
}
DART
(
const
DART
&
aDart
)
{
m_edge
=
aDart
.
m_edge
;
m_dir
=
aDart
.
m_dir
;
}
/// Destructor
~
Dart
()
{}
~
DART
()
{
}
/// Assignment operator
Dart
&
operator
=
(
const
Dart
&
dart
)
{
if
(
this
==
&
dart
)
DART
&
operator
=
(
const
DART
&
aDart
)
{
if
(
this
==
&
aDart
)
return
*
this
;
edge_
=
dart
.
edge_
;
dir_
=
dart
.
dir_
;
m_edge
=
aDart
.
m_edge
;
m_dir
=
aDart
.
m_dir
;
return
*
this
;
}
/// Comparing dart objects
bool
operator
==
(
const
Dart
&
dart
)
const
{
if
(
dart
.
edge_
==
edge_
&&
dart
.
dir_
==
dir_
)
return
true
;
return
false
;
bool
operator
==
(
const
DART
&
aDart
)
const
{
return
(
aDart
.
m_edge
==
m_edge
&&
aDart
.
m_dir
==
m_dir
);
}
/// Comparing dart objects
bool
operator
!=
(
const
Dart
&
dart
)
const
{
return
!
(
dart
==*
this
);
bool
operator
!=
(
const
DART
&
aDart
)
const
{
return
!
(
aDart
==
*
this
);
}
/// Maps the dart to a different node
Dart
&
alpha0
()
{
dir_
=
!
dir_
;
return
*
this
;
}
DART
&
Alpha0
()
{
m_dir
=
!
m_dir
;
return
*
this
;
}
/// Maps the dart to a different edge
Dart
&
alpha1
()
{
if
(
dir_
)
{
edge_
=
edge_
->
getNextEdgeInFace
()
->
getNextEdgeInFace
();
dir_
=
false
;
DART
&
Alpha1
()
{
if
(
m_dir
)
{
m_edge
=
m_edge
->
GetNextEdgeInFace
()
->
GetNextEdgeInFace
();
m_dir
=
false
;
}
else
{
edge_
=
edge_
->
getNextEdgeInFace
();
dir_
=
true
;
else
{
m_edge
=
m_edge
->
GetNextEdgeInFace
();
m_dir
=
true
;
}
return
*
this
;
}
/// Maps the dart to a different triangle. \b Note: the dart is not changed if it is at the boundary!
Dart
&
alpha2
()
{
if
(
edge_
->
getTwinEdge
())
{
edge_
=
edge_
->
getTwinEdge
();
dir_
=
!
dir_
;
DART
&
Alpha2
()
{
if
(
m_edge
->
GetTwinEdge
()
)
{
m_edge
=
m_edge
->
GetTwinEdge
();
m_dir
=
!
m_dir
;
}
// else, the dart is at the boundary and should not be changed
return
*
this
;
}
// Utilities not required by TTL
// -----------------------------
/** @name Utilities not required by TTL */
//@{
void
Init
(
const
EDGE_PTR
&
aEdge
,
bool
aDir
=
true
)
{
m_edge
=
aEdge
;
m_dir
=
aDir
;
}
double
X
()
const
{
return
GetNode
()
->
GetX
();
}
void
init
(
const
EdgePtr
&
edge
,
bool
dir
=
true
)
{
edge_
=
edge
;
dir_
=
dir
;
}
double
Y
()
const
{
return
GetNode
()
->
GetY
();
}
double
x
()
const
{
return
getNode
()
->
GetX
();
}
// x-coordinate of source node
double
y
()
const
{
return
getNode
()
->
GetY
();
}
// y-coordinate of source node
bool
IsCCW
()
const
{
return
m_dir
;
}
bool
isCounterClockWise
()
const
{
return
dir_
;
}
const
NODE_PTR
&
GetNode
()
const
{
return
m_dir
?
m_edge
->
GetSourceNode
()
:
m_edge
->
GetTargetNode
();
}
const
NodePtr
&
getNode
()
const
{
return
dir_
?
edge_
->
getSourceNode
()
:
edge_
->
getTargetNode
();
}
const
NodePtr
&
getOppositeNode
()
const
{
return
dir_
?
edge_
->
getTargetNode
()
:
edge_
->
getSourceNode
();
}
EdgePtr
&
getEdge
()
{
return
edge_
;
}
const
NODE_PTR
&
GetOppositeNode
()
const
{
return
m_dir
?
m_edge
->
GetTargetNode
()
:
m_edge
->
GetSourceNode
();
}
//@} // End of Utilities not required by TTL
EDGE_PTR
&
GetEdge
()
{
return
m_edge
;
}
};
//@} // End of Utilities not required by TTL
};
}
;
// End of hed namespace
}
// End of hed namespace
#endif
include/ttl/halfedge/hetraits.h
View file @
6fa2f060
...
...
@@ -40,19 +40,13 @@
#ifndef _HALF_EDGE_TRAITS_
#define _HALF_EDGE_TRAITS_
#include <ttl/halfedge/hetriang.h>
#include <ttl/halfedge/hedart.h>
namespace
hed
{
//------------------------------------------------------------------------------------------------
// Traits class for the half-edge data structure
//------------------------------------------------------------------------------------------------
/** \struct TTLtraits
namespace
hed
{
/**
* \struct TTLtraits
* \brief \b Traits class (static struct) for the half-edge data structure.
*
* The member functions are those required by different function templates
...
...
@@ -64,112 +58,131 @@ namespace hed {
* half-edge data structure.
*
* \see \ref api
*
*/
struct
TTLtraits
{
/** The floating point type used in calculations
* involving scalar products and cross products.
struct
TTLtraits
{
/**
* The floating point type used in calculations involving scalar products and cross products.
*/
typedef
double
real_type
;
//----------------------------------------------------------------------------------------------
// ------------------------------- Geometric Predicates Group ---------------------------------
//----------------------------------------------------------------------------------------------
typedef
double
REAL_TYPE
;
/** @name Geometric Predicates */
//@{
//----------------------------------------------------------------------------------------------
/** Scalar product between two 2D vectors represented as darts.\n
/**
* Scalar product between two 2D vectors represented as darts.\n
*
* ttl_util::scalarProduct2d can be used.
*/
static
real_type
scalarProduct2d
(
const
Dart
&
v1
,
const
Dart
&
v2
)
{
Dart
v10
=
v1
;
v10
.
alpha0
();
Dart
v20
=
v2
;
v20
.
alpha0
();
return
ttl_util
::
scalarProduct2d
(
v10
.
x
()
-
v1
.
x
(),
v10
.
y
()
-
v1
.
y
(),
v20
.
x
()
-
v2
.
x
(),
v20
.
y
()
-
v2
.
y
());
}
static
REAL_TYPE
ScalarProduct2D
(
const
DART
&
aV1
,
const
DART
&
aV2
)
{
DART
v10
=
aV1
;
v10
.
Alpha0
();
DART
v20
=
aV2
;
v20
.
Alpha0
();
//----------------------------------------------------------------------------------------------
/** Scalar product between two 2D vectors.
return
ttl_util
::
ScalarProduct2D
(
v10
.
X
()
-
aV1
.
X
(),
v10
.
Y
()
-
aV1
.
Y
(),
v20
.
X
()
-
aV2
.
X
(),
v20
.
Y
()
-
aV2
.
Y
()
);
}
/**
* Scalar product between two 2D vectors.
* The first vector is represented by a dart \e v, and the second
* vector has direction from the source node of \e v to the point \e p.\n
*
* ttl_util::scalarProduct2d
can be used.
* ttl_util::ScalarProduct2D
can be used.
*/
static
real_type
scalarProduct2d
(
const
Dart
&
v
,
const
NodePtr
&
p
)
{
Dart
d0
=
v
;
d0
.
alpha0
();
return
ttl_util
::
scalarProduct2d
(
d0
.
x
()
-
v
.
x
(),
d0
.
y
()
-
v
.
y
(),
p
->
GetX
()
-
v
.
x
(),
p
->
GetY
()
-
v
.
y
());
}
static
REAL_TYPE
ScalarProduct2D
(
const
DART
&
aV
,
const
NODE_PTR
&
aP
)
{
DART
d0
=
aV
;
d0
.
Alpha0
();
return
ttl_util
::
ScalarProduct2D
(
d0
.
X
()
-
aV
.
X
(),
d0
.
Y
()
-
aV
.
Y
(),
aP
->
GetX
()
-
aV
.
X
(),
aP
->
GetY
()
-
aV
.
Y
()
);
}
/
/----------------------------------------------------------------------------------------------
/*
* Cross product between two vectors in the plane represented as darts.
/
**
* Cross product between two vectors in the plane represented as darts.
* The z-component of the cross product is returned.\n
*
* ttl_util::crossProduct2d
can be used.
* ttl_util::CrossProduct2D
can be used.
*/
static
real_type
crossProduct2d
(
const
Dart
&
v1
,
const
Dart
&
v2
)
{
Dart
v10
=
v1
;
v10
.
alpha0
();
Dart
v20
=
v2
;
v20
.
alpha0
();
return
ttl_util
::
crossProduct2d
(
v10
.
x
()
-
v1
.
x
(),
v10
.
y
()
-
v1
.
y
(),
v20
.
x
()
-
v2
.
x
(),
v20
.
y
()
-
v2
.
y
());
}
static
REAL_TYPE
CrossProduct2D
(
const
DART
&
aV1
,
const
DART
&
aV2
)
{
DART
v10
=
aV1
;
v10
.
Alpha0
();
DART
v20
=
aV2
;
v20
.
Alpha0
();
//----------------------------------------------------------------------------------------------
/** Cross product between two vectors in the plane.
return
ttl_util
::
CrossProduct2D
(
v10
.
X
()
-
aV1
.
X
(),
v10
.
Y
()
-
aV1
.
Y
(),
v20
.
X
()
-
aV2
.
X
(),
v20
.
Y
()
-
aV2
.
Y
()
);
}
/**
* Cross product between two vectors in the plane.
* The first vector is represented by a dart \e v, and the second
* vector has direction from the source node of \e v to the point \e p.
* The z-component of the cross product is returned.\n
*
* ttl_util::c
rossProduct2d can be used.
* ttl_util::C
rossProduct2d can be used.
*/
static
real_type
crossProduct2d
(
const
Dart
&
v
,
const
NodePtr
&
p
)
{
Dart
d0
=
v
;
d0
.
alpha0
();
return
ttl_util
::
crossProduct2d
(
d0
.
x
()
-
v
.
x
(),
d0
.
y
()
-
v
.
y
(),
p
->
GetX
()
-
v
.
x
(),
p
->
GetY
()
-
v
.
y
());
}
static
REAL_TYPE
CrossProduct2D
(
const
DART
&
aV
,
const
NODE_PTR
&
aP
)
{
DART
d0
=
aV
;
d0
.
Alpha0
();
return
ttl_util
::
CrossProduct2D
(
d0
.
X
()
-
aV
.
X
(),
d0
.
Y
()
-
aV
.
Y
(),
aP
->
GetX
()
-
aV
.
X
(),
aP
->
GetY
()
-
aV
.
Y
()
);
}
/
/----------------------------------------------------------------------------------------------
/*
* Let \e n1 and \e n2 be the nodes associated with two darts, and let \e p
/
**
* Let \e n1 and \e n2 be the nodes associated with two darts, and let \e p
* be a point in the plane. Return a positive value if \e n1, \e n2,
* and \e p occur in counterclockwise order; a negative value if they occur
* in clockwise order; and zero if they are collinear.
*/
static
real_type
orient2d
(
const
Dart
&
n1
,
const
Dart
&
n2
,
const
NodePtr
&
p
)
{
real_type
pa
[
2
];
real_type
pb
[
2
];
real_type
pc
[
2
];
pa
[
0
]
=
n1
.
x
();
pa
[
1
]
=
n1
.
y
();
pb
[
0
]
=
n2
.
x
();
pb
[
1
]
=
n2
.
y
();
pc
[
0
]
=
p
->
GetX
();
pc
[
1
]
=
p
->
GetY
();
return
ttl_util
::
orient2dfast
(
pa
,
pb
,
pc
);
static
REAL_TYPE
Orient2D
(
const
DART
&
aN1
,
const
DART
&
aN2
,
const
NODE_PTR
&
aP
)
{
REAL_TYPE
pa
[
2
];
REAL_TYPE
pb
[
2
];
REAL_TYPE
pc
[
2
];
pa
[
0
]
=
aN1
.
X
();
pa
[
1
]
=
aN1
.
Y
();
pb
[
0
]
=
aN2
.
X
();
pb
[
1
]
=
aN2
.
Y
();
pc
[
0
]
=
aP
->
GetX
();
pc
[
1
]
=
aP
->
GetY
();
return
ttl_util
::
Orient2DFast
(
pa
,
pb
,
pc
);
}
//----------------------------------------------------------------------------------------------
/** This is the same predicate as represented with the function above,
/**
* This is the same predicate as represented with the function above,
* but with a slighty different interface:
* The last parameter is given as a dart where the source node of the dart
* represents a point in the plane.
* This function is required for constrained triangulation.
*/
static
real_type
orient2d
(
const
Dart
&
n1
,
const
Dart
&
n2
,
const
Dart
&
p
)
{
real_type
pa
[
2
];
real_type
pb
[
2
];
real_type
pc
[
2
];
pa
[
0
]
=
n1
.
x
();
pa
[
1
]
=
n1
.
y
();
pb
[
0
]
=
n2
.
x
();
pb
[
1
]
=
n2
.
y
();
pc
[
0
]
=
p
.
x
();
pc
[
1
]
=
p
.
y
();
return
ttl_util
::
orient2dfast
(
pa
,
pb
,
pc
);
static
REAL_TYPE
Orient2D
(
const
DART
&
aN1
,
const
DART
&
aN2
,
const
DART
&
aP
)
{
REAL_TYPE
pa
[
2
];
REAL_TYPE
pb
[
2
];
REAL_TYPE
pc
[
2
];
pa
[
0
]
=
aN1
.
X
();
pa
[
1
]
=
aN1
.
Y
();
pb
[
0
]
=
aN2
.
X
();
pb
[
1
]
=
aN2
.
Y
();
pc
[
0
]
=
aP
.
X
();
pc
[
1
]
=
aP
.
Y
();
return
ttl_util
::
Orient2DFast
(
pa
,
pb
,
pc
);
}
//@} // End of Geometric Predicates Group
};
};
};
// End of hed namespace
...
...
include/ttl/halfedge/hetriang.h
View file @
6fa2f060
...
...
@@ -42,11 +42,9 @@
#ifndef _HE_TRIANG_H_
#define _HE_TRIANG_H_
#define TTL_USE_NODE_ID // Each node gets it's own unique id
#define TTL_USE_NODE_FLAG // Each node gets a flag (can be set to true or false)
#include <list>
#include <vector>
#include <iostream>
...
...
@@ -55,28 +53,26 @@
#include <boost/shared_ptr.hpp>
#include <boost/weak_ptr.hpp>
namespace
ttl
{
class
TriangulationHelper
;
namespace
ttl
{
class
TRIANGULATION_HELPER
;
};
//--------------------------------------------------------------------------------------------------
// The half-edge data structure
//--------------------------------------------------------------------------------------------------
namespace
hed
{
// Helper typedefs
class
Node
;
class
Edge
;
typedef
boost
::
shared_ptr
<
Node
>
NodePtr
;
typedef
boost
::
shared_ptr
<
Edge
>
EdgePtr
;
typedef
boost
::
weak_ptr
<
Edge
>
EdgeWeakPtr
;
typedef
std
::
vector
<
NodePtr
>
NodesContainer
;
//------------------------------------------------------------------------------------------------
// Node class for data structures
//------------------------------------------------------------------------------------------------
/** \class Node
/**
* The half-edge data structure
*/
namespace
hed
{
// Helper typedefs
class
NODE
;
class
EDGE
;
typedef
boost
::
shared_ptr
<
NODE
>
NODE_PTR
;
typedef
boost
::
shared_ptr
<
EDGE
>
EDGE_PTR
;
typedef
boost
::
weak_ptr
<
EDGE
>
EDGE_WEAK_PTR
;
typedef
std
::
vector
<
NODE_PTR
>
NODES_CONTAINER
;
/**
* \class NODE
* \brief \b Node class for data structures (Inherits from HandleId)
*
* \note
...
...
@@ -85,13 +81,12 @@ namespace hed {
* - TTL_USE_NODE_ID and TTL_USE_NODE_FLAG should only be enabled if this functionality is
* required by the application, because they increase the memory usage for each Node object.
*/
class
Node
{
class
NODE
{
protected
:
#ifdef TTL_USE_NODE_FLAG
/// TTL_USE_NODE_FLAG must be defined
bool
flag_
;
bool
m_flag
;
#endif
#ifdef TTL_USE_NODE_ID
...
...
@@ -99,173 +94,245 @@ protected:
static
int
id_count
;
/// A unique id for each node (TTL_USE_NODE_ID must be defined)
int
id_
;
int
m_id
;
#endif
int
x_
,
y_
;
/// Node coordinates
int
m_x
,
m_y
;
unsigned
int
refCount_
;
/// Reference count
unsigned
int
m_refCount
;
public
:
/// Constructor
N
ode
(
int
x
=
0
,
int
y
=
0
)
:
N
ODE
(
int
aX
=
0
,
int
aY
=
0
)
:
#ifdef TTL_USE_NODE_FLAG
flag_
(
false
),
m_flag
(
false
),
#endif
#ifdef TTL_USE_NODE_ID
id_
(
id_count
++
),
m_id
(
id_count
++
),
#endif
x_
(
x
),
y_
(
y
),
refCount_
(
0
)
{}
m_x
(
aX
),
m_y
(
aY
),
m_refCount
(
0
)
{
}
/// Destructor
~
N
ode
()
{}
~
N
ODE
()
{}
/// Returns the x-coordinate
int
GetX
()
const
{
return
x_
;
}
int
GetX
()
const
{
return
m_x
;
}
/// Returns the y-coordinate
int
GetY
()
const
{
return
y_
;
}
int
GetY
()
const
{
return
m_y
;
}
#ifdef TTL_USE_NODE_ID
/// Returns the id (TTL_USE_NODE_ID must be defined)
int
Id
()
const
{
return
id_
;
}
int
Id
()
const
{
return
m_id
;
}
#endif
#ifdef TTL_USE_NODE_FLAG
/// Sets the flag (TTL_USE_NODE_FLAG must be defined)
void
SetFlag
(
bool
aFlag
)
{
flag_
=
aFlag
;
}
void
SetFlag
(
bool
aFlag
)
{
m_flag
=
aFlag
;
}
/// Returns the flag (TTL_USE_NODE_FLAG must be defined)
const
bool
&
GetFlag
()
const
{
return
flag_
;
}
const
bool
&
GetFlag
()
const
{
return
m_flag
;
}
#endif
void
IncRefCount
()
{
refCount_
++
;
}
void
DecRefCount
()
{
refCount_
--
;
}
unsigned
int
GetRefCount
()
const
{
return
refCount_
;
}
};
// End of class Node
void
IncRefCount
()
{
m_refCount
++
;
}
void
DecRefCount
()
{
m_refCount
--
;
}
unsigned
int
GetRefCount
()
const
{
return
m_refCount
;
}
};
//------------------------------------------------------------------------------------------------
// Edge class in the half-edge data structure
//------------------------------------------------------------------------------------------------
/** \class Edge
/**
* \class EDGE
* \brief \b %Edge class in the in the half-edge data structure.
*/
class
Edge
{
public
:
class
EDGE
{
public
:
/// Constructor
Edge
()
:
weight_
(
0
),
isLeadingEdge_
(
false
)
{}
EDGE
()
:
m_weight
(
0
),
m_isLeadingEdge
(
false
)
{
}
/// Destructor
virtual
~
Edge
()
{}
virtual
~
EDGE
()
{
}
/// Sets the source node
void
setSourceNode
(
const
NodePtr
&
node
)
{
sourceNode_
=
node
;
}
void
SetSourceNode
(
const
NODE_PTR
&
aNode
)
{
m_sourceNode
=
aNode
;
}
/// Sets the next edge in face
void
setNextEdgeInFace
(
const
EdgePtr
&
edge
)
{
nextEdgeInFace_
=
edge
;
}
void
SetNextEdgeInFace
(
const
EDGE_PTR
&
aEdge
)
{
m_nextEdgeInFace
=
aEdge
;
}
/// Sets the twin edge
void
setTwinEdge
(
const
EdgePtr
&
edge
)
{
twinEdge_
=
edge
;
}
void
SetTwinEdge
(
const
EDGE_PTR
&
aEdge
)
{
m_twinEdge
=
aEdge
;
}
/// Sets the edge as a leading edge
void
setAsLeadingEdge
(
bool
val
=
true
)
{
isLeadingEdge_
=
val
;
}
void
SetAsLeadingEdge
(
bool
aLeading
=
true
)
{
m_isLeadingEdge
=
aLeading
;
}
/// Checks if an edge is a leading edge
bool
isLeadingEdge
()
const
{
return
isLeadingEdge_
;
}
bool
IsLeadingEdge
()
const
{
return
m_isLeadingEdge
;
}
/// Returns the twin edge
EdgePtr
getTwinEdge
()
const
{
return
twinEdge_
.
lock
();
};
EDGE_PTR
GetTwinEdge
()
const
{
return
m_twinEdge
.
lock
();
}
void
clearTwinEdge
()
{
twinEdge_
.
reset
();
}
void
ClearTwinEdge
()
{
m_twinEdge
.
reset
();
}
/// Returns the next edge in face
const
EdgePtr
&
getNextEdgeInFace
()
const
{
return
nextEdgeInFace_
;
}
const
EDGE_PTR
&
GetNextEdgeInFace
()
const
{
return
m_nextEdgeInFace
;
}
/// Retuns the source node
const
NodePtr
&
getSourceNode
()
const
{
return
sourceNode_
;
}
const
NODE_PTR
&
GetSourceNode
()
const
{
return
m_sourceNode
;
}
/// Returns the target node
virtual
const
NodePtr
&
getTargetNode
()
const
{
return
nextEdgeInFace_
->
getSourceNode
();
}
virtual
const
NODE_PTR
&
GetTargetNode
()
const
{
return
m_nextEdgeInFace
->
GetSourceNode
();
}
void
setWeight
(
unsigned
int
weight
)
{
weight_
=
weight
;
}
void
SetWeight
(
unsigned
int
weight
)
{
m_weight
=
weight
;
}
unsigned
int
getWeight
()
const
{
return
weight_
;
}
unsigned
int
GetWeight
()
const
{
return
m_weight
;
}
void
c
lear
()
void
C
lear
()
{
sourceNode_
.
reset
();
nextEdgeInFace_
.
reset
();
m_sourceNode
.
reset
();
m_nextEdgeInFace
.
reset
();
if
(
!
twinEdge_
.
expired
()
)
if
(
!
m_twinEdge
.
expired
()
)
{
twinEdge_
.
lock
()
->
c
learTwinEdge
();
twinEdge_
.
reset
();
m_twinEdge
.
lock
()
->
C
learTwinEdge
();
m_twinEdge
.
reset
();
}
}
protected
:
N
odePtr
sourceNode_
;
E
dgeWeakPtr
twinEdge_
;
E
dgePtr
nextEdgeInFace_
;
unsigned
int
weight_
;
bool
isLeadingEdge_
;
};
// End of class Edge
protected
:
N
ODE_PTR
m_sourceNode
;
E
DGE_WEAK_PTR
m_twinEdge
;
E
DGE_PTR
m_nextEdgeInFace
;
unsigned
int
m_weight
;
bool
m_isLeadingEdge
;
};
/** \class EdgeMST
* \brief \b Specialization of %Edge class to be used for Minimum Spanning Tree algorithm.
/**
* \class EDGE_MST
* \brief \b Specialization of %EDGE class to be used for Minimum Spanning Tree algorithm.
*/
class
EdgeMST
:
public
Edge
{
private
:
N
odePtr
target_
;
class
EDGE_MST
:
public
EDGE
{
private
:
N
ODE_PTR
m_target
;
public
:
EdgeMST
(
const
NodePtr
&
source
,
const
NodePtr
&
target
,
unsigned
int
weight
=
0
)
:
target_
(
target
)
{
sourceNode_
=
source
;
weight_
=
weight
;
}
public
:
EDGE_MST
(
const
NODE_PTR
&
aSource
,
const
NODE_PTR
&
aTarget
,
unsigned
int
aWeight
=
0
)
:
m_target
(
aTarget
)
{
m_sourceNode
=
aSource
;
m_weight
=
aWeight
;
}
E
dgeMST
(
const
Edge
&
edge
)
E
DGE_MST
(
const
EDGE
&
edge
)
{
sourceNode_
=
edge
.
g
etSourceNode
();
target_
=
edge
.
g
etTargetNode
();
weight_
=
edge
.
g
etWeight
();
m_sourceNode
=
edge
.
G
etSourceNode
();
m_target
=
edge
.
G
etTargetNode
();
m_weight
=
edge
.
G
etWeight
();
}
~
EdgeMST
()
{};
~
EDGE_MST
()
{
}
/// @copydoc Edge::setSourceNode()
virtual
const
NodePtr
&
getTargetNode
()
const
{
return
target_
;
}
};
//------------------------------------------------------------------------------------------------
class
Dart
;
// Forward declaration (class in this namespace)
virtual
const
NODE_PTR
&
GetTargetNode
()
const
{
return
m_target
;
}
};
//------------------------------------------------------------------------------------------------
// Triangulation class in the half-edge data structure
//------------------------------------------------------------------------------------------------
class
DART
;
// Forward declaration (class in this namespace)
/** \class Triangulation
/**
* \class TRIANGULATION
* \brief \b %Triangulation class for the half-edge data structure with adaption to TTL.
*/
class
TRIANGULATION
{
protected
:
/// One half-edge for each arc
std
::
list
<
EDGE_PTR
>
m_leadingEdges
;
class
Triangulation
{
protected
:
std
::
list
<
EdgePtr
>
leadingEdges_
;
// one half-edge for each arc
ttl
::
TriangulationHelper
*
helper
;
ttl
::
TRIANGULATION_HELPER
*
m_helper
;
void
addLeadingEdge
(
EdgePtr
&
edge
)
{
edge
->
setAsLeadingEdge
();
leadingEdges_
.
push_front
(
edge
);
void
addLeadingEdge
(
EDGE_PTR
&
aEdge
)
{
aEdge
->
SetAsLeadingEdge
();
m_leadingEdges
.
push_front
(
aEdge
);
}
bool
removeLeadingEdgeFromList
(
EdgePtr
&
leadingEdge
);
bool
removeLeadingEdgeFromList
(
EDGE_PTR
&
aLeadingEdge
);
void
cleanAll
();
...
...
@@ -275,7 +342,7 @@ public:
* \image html swapEdge.gif
* </center>
*
* \param d
art
* \param aD
art
* Some of the functions require a dart as output.
* If this is required by the actual function, the dart should be delivered
* back in a position as seen if it was glued to the edge when swapping (rotating)
...
...
@@ -287,115 +354,118 @@ public:
* - Some functions in TTL require that \c swapEdge is implemented such that
* darts outside the quadrilateral are not affected by the swap.
*/
void
swapEdge
(
Dart
&
dart
);
void
swapEdge
(
DART
&
aDart
);
/** Splits the triangle associated with \e dart in the actual data structure into
/**
* Splits the triangle associated with \e dart in the actual data structure into
* three new triangles joining at \e point.
*
* <center>
* \image html splitTriangle.gif
* </center>
*
* \param d
art
* \param aD
art
* Output: A CCW dart incident with the new node; see the figure.
*/
void
splitTriangle
(
Dart
&
dart
,
const
NodePtr
&
point
);
void
splitTriangle
(
DART
&
aDart
,
const
NODE_PTR
&
aPoint
);
/** The reverse operation of TTLtraits::splitTriangle.
/**
* The reverse operation of TTLtraits::splitTriangle.
* This function is only required for functions that involve
* removal of interior nodes; see for example TrinagulationHelper::r
emoveInteriorNode.
* removal of interior nodes; see for example TrinagulationHelper::R
emoveInteriorNode.
*
* <center>
* \image html reverse_splitTriangle.gif
* </center>
*/
void
reverse
_splitTriangle
(
Dart
&
dart
);
void
reverse
SplitTriangle
(
DART
&
aDart
);
/** Removes a triangle with an edge at the boundary of the triangulation
/**
* Removes a triangle with an edge at the boundary of the triangulation
* in the actual data structure
*/
void
removeBoundaryTriangle
(
Dart
&
d
);
void
removeBoundaryTriangle
(
DART
&
aDart
);
public
:
public
:
/// Default constructor
T
riangulation
();
T
RIANGULATION
();
/// Copy constructor
T
riangulation
(
const
Triangulation
&
tr
);
T
RIANGULATION
(
const
TRIANGULATION
&
aTriangulation
);
/// Destructor
~
T
riangulation
();
~
T
RIANGULATION
();
/// Creates a Delaunay triangulation from a set of points
void
createDelaunay
(
NodesContainer
::
iterator
first
,
NodesContainer
::
iterator
last
);
void
CreateDelaunay
(
NODES_CONTAINER
::
iterator
aFirst
,
NODES_CONTAINER
::
iterator
aLast
);
/// Creates an initial Delaunay triangulation from two enclosing triangles
// When using rectangular boundary - loop through all points and expand.
// (Called from createDelaunay(...) when starting)
EdgePtr
initTwoEnclosingTriangles
(
NodesContainer
::
iterator
first
,
NodesContainer
::
iterator
last
);
EDGE_PTR
InitTwoEnclosingTriangles
(
NODES_CONTAINER
::
iterator
aFirst
,
NODES_CONTAINER
::
iterator
aLast
);
// These two functions are required by TTL for Delaunay triangulation
/// Swaps the edge associated with diagonal
void
swapEdge
(
EdgePtr
&
diagonal
);
void
SwapEdge
(
EDGE_PTR
&
aDiagonal
);
/// Splits the triangle associated with edge into three new triangles joining at point
EdgePtr
splitTriangle
(
EdgePtr
&
edge
,
const
NodePtr
&
point
);
EDGE_PTR
SplitTriangle
(
EDGE_PTR
&
aEdge
,
const
NODE_PTR
&
aPoint
);
// Functions required by TTL for removing nodes in a Delaunay triangulation
/// Removes the boundary triangle associated with edge
void
removeTriangle
(
EdgePtr
&
edge
);
// boundary triangle required
void
RemoveTriangle
(
EDGE_PTR
&
aEdge
);
// boundary triangle required
/// The reverse operation of removeTriangle
void
reverse_splitTriangle
(
EdgePtr
&
edge
);
void
ReverseSplitTriangle
(
EDGE_PTR
&
aEdge
);
/// Creates an arbitrary CCW dart
D
art
c
reateDart
();
D
ART
C
reateDart
();
/// Returns a list of "triangles" (one leading half-edge for each triangle)
const
std
::
list
<
EdgePtr
>&
getLeadingEdges
()
const
{
return
leadingEdges_
;
}
const
std
::
list
<
EDGE_PTR
>&
GetLeadingEdges
()
const
{
return
m_leadingEdges
;
}
/// Returns the number of triangles
int
noTriangles
()
const
{
return
(
int
)
leadingEdges_
.
size
();
}
int
NoTriangles
()
const
{
return
(
int
)
m_leadingEdges
.
size
();
}
/// Returns a list of half-edges (one half-edge for each arc)
std
::
list
<
E
dgePtr
>*
getEdges
(
bool
skip_boundary_edges
=
false
)
const
;
std
::
list
<
E
DGE_PTR
>*
GetEdges
(
bool
aSkipBoundaryEdges
=
false
)
const
;
#ifdef TTL_USE_NODE_FLAG
/// Sets flag in all the nodes
void
flagNodes
(
bool
flag
)
const
;
void
FlagNodes
(
bool
aFlag
)
const
;
/// Returns a list of nodes. This function requires TTL_USE_NODE_FLAG to be defined. \see Node.
std
::
list
<
N
odePtr
>*
g
etNodes
()
const
;
std
::
list
<
N
ODE_PTR
>*
G
etNodes
()
const
;
#endif
/// Swaps edges until the triangulation is Delaunay (constrained edges are not swapped)
void
o
ptimizeDelaunay
();
void
O
ptimizeDelaunay
();
/// Checks if the triangulation is Delaunay
bool
checkDelaunay
()
const
;
bool
CheckDelaunay
()
const
;
/// Returns an arbitrary interior node (as the source node of the returned edge)
E
dgePtr
g
etInteriorNode
()
const
;
E
DGE_PTR
G
etInteriorNode
()
const
;
E
dgePtr
getBoundaryEdgeInTriangle
(
const
EdgePtr
&
e
)
const
;
E
DGE_PTR
GetBoundaryEdgeInTriangle
(
const
EDGE_PTR
&
aEdge
)
const
;
/// Returns an arbitrary boundary edge
E
dgePtr
g
etBoundaryEdge
()
const
;
E
DGE_PTR
G
etBoundaryEdge
()
const
;
/// Print edges for plotting with, e.g., gnuplot
void
printEdges
(
std
::
ofstream
&
os
)
const
;
friend
class
ttl
::
TriangulationHelper
;
};
// End of class Triangulation
void
PrintEdges
(
std
::
ofstream
&
aOutput
)
const
;
friend
class
ttl
::
TRIANGULATION_HELPER
;
};
};
// End of hed namespace
#endif
include/ttl/ttl.h
View file @
6fa2f060
...
...
@@ -40,19 +40,18 @@
#ifndef _TTL_H_
#define _TTL_H_
#include <list>
#include <iterator>
// Debugging
#ifdef DEBUG_TTL
static
void
errorAndExit
(
char
*
message
)
{
cout
<<
"
\n
!!! ERROR: "
<<
message
<<
" !!!
\n
"
<<
endl
;
static
void
errorAndExit
(
char
*
aMessage
)
{
cout
<<
"
\n
!!! ERROR: "
<<
aMessage
<<
" !!!
\n
"
<<
endl
;
exit
(
-
1
);
}
}
#endif
// Next on TOPOLOGY:
// - get triangle strips
// - weighted graph, algorithms using a weight (real) for each edge,
...
...
@@ -63,8 +62,8 @@
// - analyze in detail locateFace: e.g. detect 0-orbit in case of infinite loop
// around a node etc.
/*
* \brief Main interface to TTL
/**
* \brief Main interface to TTL
*
* This namespace contains the basic generic algorithms for the TTL,
* the Triangulation Template Library.\n
...
...
@@ -77,21 +76,21 @@
* - Misc. queries for extracting information for visualisation systems etc.
*
* \par General requirements and assumptions:
*
- \e DartType and \e TraitsType
should be implemented in accordance with the description
*
- \e DART_TYPE and \e TRAITS_TYPE
should be implemented in accordance with the description
* in \ref api.
* - A \b "Requires:" section in the documentation of a function template
*
shows which functionality is required in \e TraitsType
to
*
shows which functionality is required in \e TRAITS_TYPE
to
* support that specific function.\n
*
Functionalty required in \e DartType
is the same (almost) for all
*
Functionalty required in \e DART_TYPE
is the same (almost) for all
* function templates; see \ref api and the example referred to.
* - When a reference to a \e dart object is passed to a function in TTL,
* it is assumed that it is oriented \e counterclockwise (CCW) in a triangle
* unless it is explicitly mentioned that it can also be \e clockwise (CW).
* The same applies for a dart that is passed from a function in TTL to
*
the users TraitsType
class (or struct).
*
the users TRAITS_TYPE
class (or struct).
* - When an edge (represented with a dart) is swapped, it is assumed that darts
* outside the quadrilateral where the edge is a diagonal are not affected by
*
the swap. Thus, \ref hed::TTLtraits::swapEdge "TraitsType
::swapEdge"
*
the swap. Thus, \ref hed::TTLtraits::swapEdge "TRAITS_TYPE
::swapEdge"
* must be implemented in accordance with this rule.
*
* \par Glossary:
...
...
@@ -111,152 +110,146 @@
*/
namespace
ttl
{
class
T
riangulationHelper
namespace
ttl
{
class
T
RIANGULATION_HELPER
{
#ifndef DOXYGEN_SHOULD_SKIP_THIS
public
:
TriangulationHelper
(
hed
::
Triangulation
&
triang
)
:
triangulation
(
triang
)
TRIANGULATION_HELPER
(
hed
::
TRIANGULATION
&
aTriang
)
:
m_triangulation
(
aTriang
)
{
}
// Delaunay Triangulation
// ----------------------
template
<
class
TraitsType
,
class
DartType
,
class
PointType
>
bool
insertNode
(
DartType
&
dart
,
PointType
&
point
);
template
<
class
TraitsType
,
class
DartType
>
void
removeRectangularBoundary
(
DartType
&
dart
);
template
<
class
TRAITS_TYPE
,
class
DART_TYPE
,
class
POINT_TYPE
>
bool
InsertNode
(
DART_TYPE
&
aDart
,
POINT_TYPE
&
aPoint
);
template
<
class
TraitsType
,
class
DartType
>
void
removeNode
(
DartType
&
dart
);
template
<
class
TRAITS_TYPE
,
class
DART_TYPE
>
void
RemoveRectangularBoundary
(
DART_TYPE
&
aDart
);
template
<
class
TraitsType
,
class
DartType
>
void
removeBoundaryNode
(
DartType
&
dart
);
template
<
class
TRAITS_TYPE
,
class
DART_TYPE
>
void
RemoveNode
(
DART_TYPE
&
aDart
);
template
<
class
TraitsType
,
class
DartType
>
void
removeInteriorNode
(
DartType
&
dart
);
template
<
class
TRAITS_TYPE
,
class
DART_TYPE
>
void
RemoveBoundaryNode
(
DART_TYPE
&
aDart
);
template
<
class
TRAITS_TYPE
,
class
DART_TYPE
>
void
RemoveInteriorNode
(
DART_TYPE
&
aDart
);
// Topological and Geometric Queries
// ---------------------------------
template
<
class
TraitsType
,
class
PointType
,
class
DartType
>
static
bool
locateFaceSimplest
(
const
PointType
&
point
,
DartType
&
dart
);
template
<
class
TRAITS_TYPE
,
class
POINT_TYPE
,
class
DART_TYPE
>
static
bool
LocateFaceSimplest
(
const
POINT_TYPE
&
aPoint
,
DART_TYPE
&
aDart
);
template
<
class
TraitsType
,
class
PointType
,
class
DartType
>
static
bool
locateTriangle
(
const
PointType
&
point
,
DartType
&
dart
);
template
<
class
TRAITS_TYPE
,
class
POINT_TYPE
,
class
DART_TYPE
>
static
bool
LocateTriangle
(
const
POINT_TYPE
&
aPoint
,
DART_TYPE
&
aDart
);
template
<
class
TraitsType
,
class
PointType
,
class
DartType
>
static
bool
inTriangleSimplest
(
const
PointType
&
point
,
const
DartType
&
dart
);
template
<
class
TRAITS_TYPE
,
class
POINT_TYPE
,
class
DART_TYPE
>
static
bool
InTriangleSimplest
(
const
POINT_TYPE
&
aPoint
,
const
DART_TYPE
&
aDart
);
template
<
class
TraitsType
,
class
PointType
,
class
DartType
>
static
bool
inTriangle
(
const
PointType
&
point
,
const
DartType
&
dart
);
template
<
class
TRAITS_TYPE
,
class
POINT_TYPE
,
class
DART_TYPE
>
static
bool
InTriangle
(
const
POINT_TYPE
&
aPoint
,
const
DART_TYPE
&
aDart
);
template
<
class
DartType
,
class
DartListType
>
static
void
getBoundary
(
const
DartType
&
dart
,
DartListType
&
boundary
);
template
<
class
DART_TYPE
,
class
DART_LIST_TYPE
>
static
void
GetBoundary
(
const
DART_TYPE
&
aDart
,
DART_LIST_TYPE
&
aBoundary
);
template
<
class
DartType
>
static
bool
isBoundaryEdge
(
const
DartType
&
dart
);
template
<
class
DART_TYPE
>
static
bool
IsBoundaryEdge
(
const
DART_TYPE
&
aDart
);
template
<
class
DartType
>
static
bool
isBoundaryFace
(
const
DartType
&
dart
);
template
<
class
DART_TYPE
>
static
bool
IsBoundaryFace
(
const
DART_TYPE
&
aDart
);
template
<
class
DartType
>
static
bool
isBoundaryNode
(
const
DartType
&
dart
);
template
<
class
DART_TYPE
>
static
bool
IsBoundaryNode
(
const
DART_TYPE
&
aDart
);
template
<
class
DartType
>
static
int
getDegreeOfNode
(
const
DartType
&
dart
);
template
<
class
DART_TYPE
>
static
int
GetDegreeOfNode
(
const
DART_TYPE
&
aDart
);
template
<
class
DartType
,
class
DartListType
>
static
void
get_0_orbit_interior
(
const
DartType
&
dart
,
DartListType
&
orbit
);
template
<
class
DART_TYPE
,
class
DART_LIST_TYPE
>
static
void
Get0OrbitInterior
(
const
DART_TYPE
&
aDart
,
DART_LIST_TYPE
&
aOrbit
);
template
<
class
DartType
,
class
DartListType
>
static
void
get_0_orbit_boundary
(
const
DartType
&
dart
,
DartListType
&
orbit
);
template
<
class
DART_TYPE
,
class
DART_LIST_TYPE
>
static
void
Get0OrbitBoundary
(
const
DART_TYPE
&
aDart
,
DART_LIST_TYPE
&
aOrbit
);
template
<
class
DartType
>
static
bool
same_0_orbit
(
const
DartType
&
d1
,
const
DartType
&
d2
);
template
<
class
DART_TYPE
>
static
bool
Same0Orbit
(
const
DART_TYPE
&
aD1
,
const
DART_TYPE
&
aD2
);
template
<
class
DartType
>
static
bool
same_1_orbit
(
const
DartType
&
d1
,
const
DartType
&
d2
);
template
<
class
DART_TYPE
>
static
bool
Same1Orbit
(
const
DART_TYPE
&
aD1
,
const
DART_TYPE
&
aD2
);
template
<
class
DartType
>
static
bool
same_2_orbit
(
const
DartType
&
d1
,
const
DartType
&
d2
);
template
<
class
DART_TYPE
>
static
bool
Same2Orbit
(
const
DART_TYPE
&
aD1
,
const
DART_TYPE
&
aD2
);
template
<
class
TraitsType
,
class
DartType
>
static
bool
swappableEdge
(
const
DartType
&
dart
,
bool
allowDegeneracy
=
false
);
template
<
class
TRAITS_TYPE
,
class
DART_TYPE
>
static
bool
SwappableEdge
(
const
DART_TYPE
&
aDart
,
bool
aAllowDegeneracy
=
false
);
template
<
class
DartType
>
static
void
positionAtNextBoundaryEdge
(
DartType
&
dart
);
template
<
class
TraitsType
,
class
DartType
>
static
bool
convexBoundary
(
const
DartType
&
dart
);
template
<
class
DART_TYPE
>
static
void
PositionAtNextBoundaryEdge
(
DART_TYPE
&
aDart
);
template
<
class
TRAITS_TYPE
,
class
DART_TYPE
>
static
bool
ConvexBoundary
(
const
DART_TYPE
&
aDart
);
// Utilities for Delaunay Triangulation
// ------------------------------------
template
<
class
TraitsType
,
class
DartType
,
class
DartListType
>
void
optimizeDelaunay
(
DartListType
&
elist
);
template
<
class
TraitsType
,
class
DartType
,
class
DartListType
>
void
optimizeDelaunay
(
DartListType
&
elist
,
const
typename
DartListType
::
iterator
end
);
template
<
class
TRAITS_TYPE
,
class
DART_TYPE
,
class
DART_LIST_TYPE
>
void
OptimizeDelaunay
(
DART_LIST_TYPE
&
aElist
);
template
<
class
TraitsType
,
class
DartType
>
bool
swapTestDelaunay
(
const
DartType
&
dart
,
bool
cycling_check
=
false
)
const
;
template
<
class
TRAITS_TYPE
,
class
DART_TYPE
,
class
DART_LIST_TYPE
>
void
OptimizeDelaunay
(
DART_LIST_TYPE
&
aElist
,
const
typename
DART_LIST_TYPE
::
iterator
aEnd
)
;
template
<
class
TraitsType
,
class
DartType
>
void
recSwapDelaunay
(
DartType
&
diagonal
)
;
template
<
class
TRAITS_TYPE
,
class
DART_TYPE
>
bool
SwapTestDelaunay
(
const
DART_TYPE
&
aDart
,
bool
aCyclingCheck
=
false
)
const
;
template
<
class
TraitsType
,
class
DartType
,
class
ListType
>
void
swapEdgesAwayFromInteriorNode
(
DartType
&
dart
,
ListType
&
swapped_edges
);
template
<
class
TRAITS_TYPE
,
class
DART_TYPE
>
void
RecSwapDelaunay
(
DART_TYPE
&
aDiagonal
);
template
<
class
TraitsType
,
class
DartType
,
class
ListType
>
void
swapEdgesAwayFromBoundaryNode
(
DartType
&
dart
,
ListType
&
swapped_edges
);
template
<
class
TRAITS_TYPE
,
class
DART_TYPE
,
class
LIST_TYPE
>
void
SwapEdgesAwayFromInteriorNode
(
DART_TYPE
&
aDart
,
LIST_TYPE
&
aSwappedEdges
);
template
<
class
TraitsType
,
class
DartType
,
class
DartListType
>
void
swapEdgeInList
(
const
typename
DartListType
::
iterator
&
it
,
DartListType
&
elist
);
template
<
class
TRAITS_TYPE
,
class
DART_TYPE
,
class
LIST_TYPE
>
void
SwapEdgesAwayFromBoundaryNode
(
DART_TYPE
&
aDart
,
LIST_TYPE
&
aSwappedEdges
);
template
<
class
TRAITS_TYPE
,
class
DART_TYPE
,
class
DART_LIST_TYPE
>
void
SwapEdgeInList
(
const
typename
DART_LIST_TYPE
::
iterator
&
aIt
,
DART_LIST_TYPE
&
aElist
);
// Constrained Triangulation
// -------------------------
template
<
class
TraitsType
,
class
DartType
>
static
D
artType
insertConstraint
(
DartType
&
dstart
,
DartType
&
dend
,
bool
optimize_delaunay
);
template
<
class
TRAITS_TYPE
,
class
DART_TYPE
>
static
D
ART_TYPE
InsertConstraint
(
DART_TYPE
&
aDStart
,
DART_TYPE
&
aDEnd
,
bool
aOptimizeDelaunay
);
private
:
hed
::
Triangulation
&
triangulation
;
hed
::
TRIANGULATION
&
m_
triangulation
;
template
<
class
TraitsType
,
class
ForwardIterator
,
class
DartType
>
void
insertNodes
(
ForwardIterator
first
,
ForwardIterator
last
,
DartType
&
dart
);
template
<
class
TRAITS_TYPE
,
class
FORWARD_ITERATOR
,
class
DART_TYPE
>
void
insertNodes
(
FORWARD_ITERATOR
aFirst
,
FORWARD_ITERATOR
aLast
,
DART_TYPE
&
aDart
);
template
<
class
TopologyElementType
,
class
DartType
>
static
bool
isMemberOfFace
(
const
TopologyElementType
&
topologyElement
,
const
DartType
&
dart
);
template
<
class
TOPOLOGY_ELEMENT_TYPE
,
class
DART_TYPE
>
static
bool
isMemberOfFace
(
const
TOPOLOGY_ELEMENT_TYPE
&
aTopologyElement
,
const
DART_TYPE
&
aDart
);
template
<
class
TraitsType
,
class
NodeType
,
class
DartType
>
static
bool
locateFaceWithNode
(
const
NodeType
&
node
,
DartType
&
dart_iter
);
template
<
class
TRAITS_TYPE
,
class
NODE_TYPE
,
class
DART_TYPE
>
static
bool
locateFaceWithNode
(
const
NODE_TYPE
&
aNode
,
DART_TYPE
&
aDartIter
);
template
<
class
DartType
>
static
void
getAdjacentTriangles
(
const
DartType
&
dart
,
DartType
&
t1
,
DartType
&
t2
,
DartType
&
t3
);
template
<
class
DART_TYPE
>
static
void
getAdjacentTriangles
(
const
DART_TYPE
&
aDart
,
DART_TYPE
&
aT1
,
DART_TYPE
&
aT2
,
DART_TYPE
&
aT3
);
template
<
class
DartType
>
static
void
getNeighborNodes
(
const
DartType
&
dart
,
std
::
list
<
DartType
>&
node_list
,
bool
&
boundary
);
template
<
class
DART_TYPE
>
static
void
getNeighborNodes
(
const
DART_TYPE
&
aDart
,
std
::
list
<
DART_TYPE
>&
aNodeList
,
bool
&
aBoundary
);
template
<
class
TraitsType
,
class
DartType
>
static
bool
degenerateTriangle
(
const
DartType
&
dart
);
template
<
class
TRAITS_TYPE
,
class
DART_TYPE
>
static
bool
degenerateTriangle
(
const
DART_TYPE
&
aDart
);
};
#endif // DOXYGEN_SHOULD_SKIP_THIS
//------------------------------------------------------------------------------------------------
// ------------------------------- Delaunay Triangulation Group ---------------------------------
//------------------------------------------------------------------------------------------------
/** @name Delaunay Triangulation */
//@{
//------------------------------------------------------------------------------------------------
/** Inserts a new node in an existing Delaunay triangulation and
//@{
/**
* Inserts a new node in an existing Delaunay triangulation and
* swaps edges to obtain a new Delaunay triangulation.
* This is the basic function for incremental Delaunay triangulation.
* When starting from a set of points, an initial Delaunay triangulation
...
...
@@ -270,11 +263,11 @@ private:
* Note that this incremetal scheme will run much faster if the points
* have been sorted lexicographically on \e x and \e y.
*
* \param dart
* \param aDart
* An arbitrary CCW dart in the tringulation.\n
* Output: A CCW dart incident to the new node.
*
* \param point
* \param aPoint
* A point (node) to be inserted in the triangulation.
*
* \retval bool
...
...
@@ -283,11 +276,11 @@ private:
* \c false is returned.
*
* \require
* - \ref hed::TTLtraits::splitTriangle "TraitsType::splitTriangle" (DartType&, const PointType
&)
* - \ref hed::TTLtraits::splitTriangle "TRAITS_TYPE::splitTriangle" (DART_TYPE&, const POINT_TYPE
&)
*
* \using
* - locateTriangle
* - r
ecSwapDelaunay
* - R
ecSwapDelaunay
*
* \note
* - For efficiency reasons \e dart should be close to the insertion \e point.
...
...
@@ -295,11 +288,13 @@ private:
* \see
* removeRectangularBoundary
*/
template
<
class
TraitsType
,
class
DartType
,
class
PointType
>
bool
TriangulationHelper
::
insertNode
(
DartType
&
dart
,
PointType
&
point
)
{
template
<
class
TRAITS_TYPE
,
class
DART_TYPE
,
class
POINT_TYPE
>
bool
TRIANGULATION_HELPER
::
InsertNode
(
DART_TYPE
&
aDart
,
POINT_TYPE
&
aPoint
)
{
bool
found
=
LocateTriangle
<
TRAITS_TYPE
>
(
aPoint
,
aDart
);
bool
found
=
locateTriangle
<
TraitsType
>
(
point
,
dart
);
if
(
!
found
)
{
if
(
!
found
)
{
#ifdef DEBUG_TTL
cout
<<
"ERROR: Triangulation::insertNode: NO triangle found. /n"
;
#endif
...
...
@@ -307,63 +302,67 @@ private:
}
// ??? can we hide the dart? this is not possible if one triangle only
triangulation
.
splitTriangle
(
dart
,
point
);
m_triangulation
.
splitTriangle
(
aDart
,
aPoint
);
D
artType
d1
=
d
art
;
d1
.
alpha2
().
alpha1
().
alpha2
().
alpha0
().
a
lpha1
();
D
ART_TYPE
d1
=
aD
art
;
d1
.
Alpha2
().
Alpha1
().
Alpha2
().
Alpha0
().
A
lpha1
();
D
artType
d2
=
d
art
;
d2
.
alpha1
().
alpha0
().
a
lpha1
();
D
ART_TYPE
d2
=
aD
art
;
d2
.
Alpha1
().
Alpha0
().
A
lpha1
();
// Preserve a dart as output incident to the node and CCW
DartType
d3
=
dart
;
d3
.
alpha2
();
dart
=
d3
;
// and see below
//DartType dsav = d3;
d3
.
alpha0
().
alpha1
();
//if (!TraitsType::fixedEdge(d1) && !isBoundaryEdge(d1)) {
if
(
!
isBoundaryEdge
(
d1
))
{
d1
.
alpha2
();
recSwapDelaunay
<
TraitsType
>
(
d1
);
DART_TYPE
d3
=
aDart
;
d3
.
Alpha2
();
aDart
=
d3
;
// and see below
//DART_TYPE dsav = d3;
d3
.
Alpha0
().
Alpha1
();
//if (!TRAITS_TYPE::fixedEdge(d1) && !IsBoundaryEdge(d1)) {
if
(
!
IsBoundaryEdge
(
d1
)
)
{
d1
.
Alpha2
();
RecSwapDelaunay
<
TRAITS_TYPE
>
(
d1
);
}
//if (!TraitsType::fixedEdge(d2) && !isBoundaryEdge(d2)) {
if
(
!
isBoundaryEdge
(
d2
))
{
d2
.
alpha2
();
recSwapDelaunay
<
TraitsType
>
(
d2
);
//if (!TRAITS_TYPE::fixedEdge(d2) && !IsBoundaryEdge(d2)) {
if
(
!
IsBoundaryEdge
(
d2
)
)
{
d2
.
Alpha2
();
RecSwapDelaunay
<
TRAITS_TYPE
>
(
d2
);
}
// Preserve the incoming dart as output incident to the node and CCW
//d = dsav.alpha2();
dart
.
alpha2
();
//if (!TraitsType::fixedEdge(d3) && !isBoundaryEdge(d3)) {
if
(
!
isBoundaryEdge
(
d3
))
{
d3
.
alpha2
();
recSwapDelaunay
<
TraitsType
>
(
d3
);
//d = dsav.Alpha2();
aDart
.
Alpha2
();
//if (!TRAITS_TYPE::fixedEdge(d3) && !IsBoundaryEdge(d3)) {
if
(
!
IsBoundaryEdge
(
d3
)
)
{
d3
.
Alpha2
();
RecSwapDelaunay
<
TRAITS_TYPE
>
(
d3
);
}
return
true
;
}
}
//------------------------------------------------------------------------------------------------
// Private/Hidden function (might change later)
template
<
class
TraitsType
,
class
ForwardIterator
,
class
DartType
>
void
TriangulationHelper
::
insertNodes
(
ForwardIterator
first
,
ForwardIterator
last
,
DartType
&
dart
)
{
//------------------------------------------------------------------------------------------------
// Private/Hidden function (might change later)
template
<
class
TRAITS_TYPE
,
class
FORWARD_ITERATOR
,
class
DART_TYPE
>
void
TRIANGULATION_HELPER
::
insertNodes
(
FORWARD_ITERATOR
aFirst
,
FORWARD_ITERATOR
aLast
,
DART_TYPE
&
aDart
)
{
// Assumes that the dereferenced point objects are pointers.
// References to the point objects are then passed to TTL.
F
orwardIterator
it
;
for
(
it
=
first
;
it
!=
last
;
++
it
)
{
insertNode
<
TraitsType
>
(
dart
,
**
it
);
}
F
ORWARD_ITERATOR
it
;
for
(
it
=
aFirst
;
it
!=
aLast
;
++
it
)
{
InsertNode
<
TRAITS_TYPE
>
(
aDart
,
**
it
);
}
}
//------------------------------------------------------------------------------------------------
/** Removes the rectangular boundary of a triangulation as a final step of an
/** Removes the rectangular boundary of a triangulation as a final step of an
* incremental Delaunay triangulation.
* The four nodes at the corners will be removed and the resulting triangulation
* will have a convex boundary and be Delaunay.
...
...
@@ -373,129 +372,129 @@ private:
* Output: A CCW dart at the new boundary
*
* \using
* - r
emoveBoundaryNode
* - R
emoveBoundaryNode
*
* \note
* - This function requires that the boundary of the
triangulation is
* - This function requires that the boundary of the m_
triangulation is
* a rectangle with four nodes (one in each corner).
*/
template
<
class
TraitsType
,
class
DartType
>
void
TriangulationHelper
::
removeRectangularBoundary
(
DartType
&
dart
)
{
D
artType
d_next
=
d
art
;
D
artType
d_iter
;
template
<
class
TRAITS_TYPE
,
class
DART_TYPE
>
void
TRIANGULATION_HELPER
::
RemoveRectangularBoundary
(
DART_TYPE
&
aDart
)
{
D
ART_TYPE
d_next
=
aD
art
;
D
ART_TYPE
d_iter
;
for
(
int
i
=
0
;
i
<
4
;
i
++
)
{
for
(
int
i
=
0
;
i
<
4
;
i
++
)
{
d_iter
=
d_next
;
d_next
.
a
lpha0
();
positionAtNextBoundaryEdge
(
d_next
);
removeBoundaryNode
<
TraitsType
>
(
d_iter
);
d_next
.
A
lpha0
();
PositionAtNextBoundaryEdge
(
d_next
);
RemoveBoundaryNode
<
TRAITS_TYPE
>
(
d_iter
);
}
d
art
=
d_next
;
// Return a dart at the new boundary
}
aD
art
=
d_next
;
// Return a dart at the new boundary
}
//------------------------------------------------------------------------------------------------
/** Removes the node associated with \e dart and
/** Removes the node associated with \e dart and
* updates the triangulation to be Delaunay.
*
* \using
* - r
emoveBoundaryNode if \e dart represents a node at the boundary
* - r
emoveInteriorNode if \e dart represents an interior node
* - R
emoveBoundaryNode if \e dart represents a node at the boundary
* - R
emoveInteriorNode if \e dart represents an interior node
*
* \note
* - The node cannot belong to a fixed (constrained) edge that is not
* swappable. (An endless loop is likely to occur in this case).
*/
template
<
class
TraitsType
,
class
DartType
>
void
TriangulationHelper
::
removeNode
(
DartType
&
dart
)
{
template
<
class
TRAITS_TYPE
,
class
DART_TYPE
>
void
TRIANGULATION_HELPER
::
RemoveNode
(
DART_TYPE
&
aDart
)
{
if
(
isBoundaryNode
(
dart
)
)
removeBoundaryNode
<
TraitsType
>
(
dart
);
if
(
isBoundaryNode
(
aDart
)
)
RemoveBoundaryNode
<
TRAITS_TYPE
>
(
aDart
);
else
removeInteriorNode
<
TraitsType
>
(
dart
);
}
RemoveInteriorNode
<
TRAITS_TYPE
>
(
aDart
);
}
//------------------------------------------------------------------------------------------------
/** Removes the boundary node associated with \e dart and
/** Removes the boundary node associated with \e dart and
* updates the triangulation to be Delaunay.
*
* \using
* - s
wapEdgesAwayFromBoundaryNode
* - o
ptimizeDelaunay
* - S
wapEdgesAwayFromBoundaryNode
* - O
ptimizeDelaunay
*
* \require
* - \ref hed::TTLtraits::removeBoundaryTriangle "TraitsType
::removeBoundaryTriangle" (Dart&)
* - \ref hed::TTLtraits::removeBoundaryTriangle "TRAITS_TYPE
::removeBoundaryTriangle" (Dart&)
*/
template
<
class
TraitsType
,
class
DartType
>
void
TriangulationHelper
::
removeBoundaryNode
(
DartType
&
dart
)
{
template
<
class
TRAITS_TYPE
,
class
DART_TYPE
>
void
TRIANGULATION_HELPER
::
RemoveBoundaryNode
(
DART_TYPE
&
aDart
)
{
// ... and update Delaunay
// - CCW dart must be given (for remove)
// - No dart is delivered back now (but this is possible if
// we assume that there is not only one triangle left in the triangulation.
// we assume that there is not only one triangle left in the
m_
triangulation.
// Position at boundary edge and CCW
if
(
!
isBoundaryEdge
(
dart
))
{
dart
.
alpha1
();
// ensures that next function delivers back a CCW dart (if the given dart is CCW)
positionAtNextBoundaryEdge
(
dart
);
if
(
!
IsBoundaryEdge
(
aDart
)
)
{
aDart
.
Alpha1
();
// ensures that next function delivers back a CCW dart (if the given dart is CCW)
PositionAtNextBoundaryEdge
(
aDart
);
}
std
::
list
<
D
artType
>
swapped_edges
;
swapEdgesAwayFromBoundaryNode
<
TraitsType
>
(
dart
,
swapped_edges
);
std
::
list
<
D
ART_TYPE
>
swapped_edges
;
SwapEdgesAwayFromBoundaryNode
<
TRAITS_TYPE
>
(
aDart
,
swapped_edges
);
// Remove boundary triangles and remove the new boundary from the list
// of swapped edges, see below.
D
artType
d_iter
=
d
art
;
D
artType
dnext
=
d
art
;
D
ART_TYPE
d_iter
=
aD
art
;
D
ART_TYPE
dnext
=
aD
art
;
bool
bend
=
false
;
while
(
bend
==
false
)
{
dnext
.
alpha1
().
alpha2
();
if
(
isBoundaryEdge
(
dnext
))
while
(
bend
==
false
)
{
dnext
.
Alpha1
().
Alpha2
();
if
(
IsBoundaryEdge
(
dnext
)
)
bend
=
true
;
// Stop when boundary
// Generic: Also remove the new boundary from the list of swapped edges
DartType
n_bedge
=
d_iter
;
n_bedge
.
alpha1
().
alpha0
().
alpha1
().
a
lpha2
();
// new boundary edge
DART_TYPE
n_bedge
=
d_iter
;
n_bedge
.
Alpha1
().
Alpha0
().
Alpha1
().
A
lpha2
();
// new boundary edge
// ??? can we avoid find if we do this in swap away?
typename
std
::
list
<
DartType
>::
iterator
it
;
it
=
find
(
swapped_edges
.
begin
(),
swapped_edges
.
end
(),
n_bedge
);
typename
std
::
list
<
DART_TYPE
>::
iterator
it
;
it
=
find
(
swapped_edges
.
begin
(),
swapped_edges
.
end
(),
n_bedge
);
if
(
it
!=
swapped_edges
.
end
()
)
swapped_edges
.
erase
(
it
);
if
(
it
!=
swapped_edges
.
end
()
)
swapped_edges
.
erase
(
it
);
// Remove the boundary triangle
triangulation
.
removeBoundaryTriangle
(
d_iter
);
m_triangulation
.
removeBoundaryTriangle
(
d_iter
);
d_iter
=
dnext
;
}
// Optimize Delaunay
typedef
std
::
list
<
D
artType
>
DartListType
;
optimizeDelaunay
<
TraitsType
,
DartType
,
DartListType
>
(
swapped_edges
);
}
typedef
std
::
list
<
D
ART_TYPE
>
DART_LIST_TYPE
;
OptimizeDelaunay
<
TRAITS_TYPE
,
DART_TYPE
,
DART_LIST_TYPE
>
(
swapped_edges
);
}
//------------------------------------------------------------------------------------------------
/** Removes the interior node associated with \e dart and
/** Removes the interior node associated with \e dart and
* updates the triangulation to be Delaunay.
*
* \using
* - s
wapEdgesAwayFromInteriorNode
* - o
ptimizeDelaunay
* - S
wapEdgesAwayFromInteriorNode
* - O
ptimizeDelaunay
*
* \require
* - \ref hed::TTLtraits::reverse_splitTriangle "TraitsType
::reverse_splitTriangle" (Dart&)
* - \ref hed::TTLtraits::reverse_splitTriangle "TRAITS_TYPE
::reverse_splitTriangle" (Dart&)
*
* \note
* - The node cannot belong to a fixed (constrained) edge that is not
* swappable. (An endless loop is likely to occur in this case).
*/
template
<
class
TraitsType
,
class
DartType
>
void
TriangulationHelper
::
removeInteriorNode
(
DartType
&
dart
)
{
template
<
class
TRAITS_TYPE
,
class
DART_TYPE
>
void
TRIANGULATION_HELPER
::
RemoveInteriorNode
(
DART_TYPE
&
aDart
)
{
// ... and update to Delaunay.
// Must allow degeneracy temporarily, see comments in swap edges away
// Assumes:
...
...
@@ -505,18 +504,18 @@ private:
// 1) Swaps edges away from the node until degree=3 (generic)
// 2) Removes the remaining 3 triangles and creates a new to fill the hole
// unsplitTriangle which is required
// 3) Runs LOP on the platelet to obtain a Delaunay triangulation
// 3) Runs LOP on the platelet to obtain a Delaunay
m_
triangulation
// (No dart is delivered as output)
// Assumes dart is counterclockwise
std
::
list
<
D
artType
>
swapped_edges
;
swapEdgesAwayFromInteriorNode
<
TraitsType
>
(
dart
,
swapped_edges
);
std
::
list
<
D
ART_TYPE
>
swapped_edges
;
SwapEdgesAwayFromInteriorNode
<
TRAITS_TYPE
>
(
aDart
,
swapped_edges
);
// The reverse operation of split triangle:
// Make one triangle of the three triangles at the node associated with dart
// T
raitsType
::
triangulation
.
reverse_splitTriangle
(
dart
);
// T
RAITS_TYPE
::
m_triangulation
.
reverseSplitTriangle
(
aDart
);
// ???? Not generic yet if we are very strict:
// When calling unsplit triangle, darts at the three opposite sides may
...
...
@@ -529,75 +528,72 @@ private:
// Note the theoretical result: if there are no edges in the list,
// the triangulation is Delaunay already
optimizeDelaunay
<
TraitsType
,
DartType
>
(
swapped_edges
);
}
//@} // End of Delaunay Triangulation Group
OptimizeDelaunay
<
TRAITS_TYPE
,
DART_TYPE
>
(
swapped_edges
);
}
//------------------------------------------------------------------------------------------------
// -------------------------- Topological and Geometric Queries Group ---------------------------
//------------------------------------------------------------------------------------------------
/** @name Topological and Geometric Queries */
//@{
//------------------------------------------------------------------------------------------------
// Private/Hidden function (might change later)
template
<
class
TopologyElementType
,
class
DartType
>
bool
TriangulationHelper
::
isMemberOfFace
(
const
TopologyElementType
&
topologyElement
,
const
DartType
&
dart
)
{
//@} // End of Delaunay Triangulation Group
/** @name Topological and Geometric Queries */
//@{
//------------------------------------------------------------------------------------------------
// Private/Hidden function (might change later)
template
<
class
TOPOLOGY_ELEMENT_TYPE
,
class
DART_TYPE
>
bool
TRIANGULATION_HELPER
::
isMemberOfFace
(
const
TOPOLOGY_ELEMENT_TYPE
&
aTopologyElement
,
const
DART_TYPE
&
aDart
)
{
// Check if the given topology element (node, edge or face) is a member of the face
// Assumes:
// - D
artType::isMember(TopologyElementType
)
// - D
ART_TYPE::isMember(TOPOLOGY_ELEMENT_TYPE
)
DartType
dart_iter
=
dart
;
do
{
if
(
dart_iter
.
isMember
(
topologyElement
))
return
true
;
dart_iter
.
alpha0
().
alpha1
();
}
while
(
dart_iter
!=
dart
);
DART_TYPE
dart_iter
=
aDart
;
return
false
;
do
{
if
(
dart_iter
.
isMember
(
aTopologyElement
)
)
return
true
;
dart_iter
.
Alpha0
().
Alpha1
();
}
while
(
dart_iter
!=
aDart
);
return
false
;
}
//------------------------------------------------------------------------------------------------
// Private/Hidden function (might change later)
template
<
class
TraitsType
,
class
NodeType
,
class
DartType
>
bool
TriangulationHelper
::
locateFaceWithNode
(
const
NodeType
&
node
,
DartType
&
dart_iter
)
{
//------------------------------------------------------------------------------------------------
// Private/Hidden function (might change later)
template
<
class
TRAITS_TYPE
,
class
NODE_TYPE
,
class
DART_TYPE
>
bool
TRIANGULATION_HELPER
::
locateFaceWithNode
(
const
NODE_TYPE
&
aNode
,
DART_TYPE
&
aDartIter
)
{
// Locate a face in the topology structure with the given node as a member
// Assumes:
// - T
raitsType::orient2d(DartType, DartType, NodeType
)
// - D
artType::isMember(NodeType
)
// - T
RAITS_TYPE::Orient2D(DART_TYPE, DART_TYPE, NODE_TYPE
)
// - D
ART_TYPE::isMember(NODE_TYPE
)
// - Note that if false is returned, the node might still be in the
// topology structure. Application programmer
// should check all if by hypothesis the node is in the topology structure;
// see doc. on
locateTriangle.
// see doc. on
LocateTriangle.
bool
status
=
locateFaceSimplest
<
TraitsType
>
(
node
,
dart_iter
);
if
(
status
==
false
)
bool
status
=
LocateFaceSimplest
<
TRAITS_TYPE
>
(
aNode
,
aDartIter
);
if
(
status
==
false
)
return
status
;
// True was returned from
l
ocateFaceSimplest, but if the located triangle is
// True was returned from
L
ocateFaceSimplest, but if the located triangle is
// degenerate and the node is on the extension of the edges,
// the node might still be inside. Check if node is a member and return false
// if not. (Still the node might be in the topology structure, see doc. above
// and in locateTriangle(const PointType& point, DartType& dart_iter)
return
isMemberOfFace
(
node
,
dart_iter
);
}
// and in locateTriangle(const POINT_TYPE& point, DART_TYPE& dart_iter)
return
isMemberOfFace
(
aNode
,
aDartIter
);
}
//------------------------------------------------------------------------------------------------
/** Locates the face containing a given point.
/** Locates the face containing a given point.
* It is assumed that the tessellation (e.g. a triangulation) is \e regular in the sense that
* there are no holes, the boundary is convex and there are no degenerate faces.
*
* \param point
* \param aPoint
* A point to be located
*
* \param d
art
* \param aD
art
* An arbitrary CCW dart in the triangulation\n
* Output: A CCW dart in the located face
*
...
...
@@ -605,17 +601,18 @@ private:
* \c true if a face is found; \c false if not.
*
* \require
* - \ref hed::TTLtraits::orient2d "TraitsType::orient2d" (DartType&, DartType&, PointType
&)
* - \ref hed::TTLtraits::Orient2D "TRAITS_TYPE::Orient2D" (DART_TYPE&, DART_TYPE&, POINT_TYPE
&)
*
* \note
* - If \c false is returned, \e point may still be inside a face if the tessellation is not
* \e regular as explained above.
*
* \see
* l
ocateTriangle
* L
ocateTriangle
*/
template
<
class
TraitsType
,
class
PointType
,
class
DartType
>
bool
TriangulationHelper
::
locateFaceSimplest
(
const
PointType
&
point
,
DartType
&
dart
)
{
template
<
class
TRAITS_TYPE
,
class
POINT_TYPE
,
class
DART_TYPE
>
bool
TRIANGULATION_HELPER
::
LocateFaceSimplest
(
const
POINT_TYPE
&
aPoint
,
DART_TYPE
&
aDart
)
{
// Not degenerate triangles if point is on the extension of the edges
// But inTriangle may be called in case of true (may update to inFace2)
// Convex boundary
...
...
@@ -623,43 +620,47 @@ private:
// convex faces (works for general convex faces)
// Not specialized for triangles, but ok?
//
// T
raitsType::orint2d(PointType
) is the half open half-plane defined
// T
RAITS_TYPE::orint2d(POINT_TYPE
) is the half open half-plane defined
// by the dart:
// n1 = dart.node()
// n2 = dart.
a
lpha0().node
// n2 = dart.
A
lpha0().node
// Only the following gives true:
// ((n2->x()-n1->x())*(point.y()-n1->y()) >= (point.x()-n1->x())*(n2->y()-n1->y()))
DartType
dart_start
;
dart_start
=
dart
;
DartType
dart_prev
;
DartType
d0
;
for
(;;)
{
d0
=
dart
;
d0
.
alpha0
();
if
(
TraitsType
::
orient2d
(
dart
,
d0
,
point
)
>=
0
)
{
dart
.
alpha0
().
alpha1
();
if
(
dart
==
dart_start
)
DART_TYPE
dart_start
;
dart_start
=
aDart
;
DART_TYPE
dart_prev
;
DART_TYPE
d0
;
for
(
;;
)
{
d0
=
aDart
;
d0
.
Alpha0
();
if
(
TRAITS_TYPE
::
Orient2D
(
aDart
,
d0
,
aPoint
)
>=
0
)
{
aDart
.
Alpha0
().
Alpha1
();
if
(
aDart
==
dart_start
)
return
true
;
// left to all edges in face
}
else
{
dart_prev
=
dart
;
dart
.
alpha2
();
if
(
dart
==
dart_prev
)
else
{
dart_prev
=
aDart
;
aDart
.
Alpha2
();
if
(
aDart
==
dart_prev
)
return
false
;
// iteration to outside boundary
dart_start
=
d
art
;
dart_start
.
a
lpha0
();
dart_start
=
aD
art
;
dart_start
.
A
lpha0
();
dart
.
alpha1
();
// avoid twice on same edge and ccw in next
}
aDart
.
Alpha1
();
// avoid twice on same edge and ccw in next
}
}
}
//------------------------------------------------------------------------------------------------
/** Locates the triangle containing a given point.
/** Locates the triangle containing a given point.
* It is assumed that the triangulation is \e regular in the sense that there
* are no holes and the boundary is convex.
* This function deals with degeneracy to some extent, but round-off errors may still
...
...
@@ -674,15 +675,16 @@ private:
*
* \retval bool
* \c true if a triangle is found; \c false if not.\n
* If \e point is outside the
triangulation, in which case \c false is returned,
* then the edge associated with \e dart will be at the boundary of the
triangulation.
* If \e point is outside the m_
triangulation, in which case \c false is returned,
* then the edge associated with \e dart will be at the boundary of the m_
triangulation.
*
* \using
* - l
ocateFaceSimplest
* - i
nTriangle
* - L
ocateFaceSimplest
* - I
nTriangle
*/
template
<
class
TraitsType
,
class
PointType
,
class
DartType
>
bool
TriangulationHelper
::
locateTriangle
(
const
PointType
&
point
,
DartType
&
dart
)
{
template
<
class
TRAITS_TYPE
,
class
POINT_TYPE
,
class
DART_TYPE
>
bool
TRIANGULATION_HELPER
::
LocateTriangle
(
const
POINT_TYPE
&
aPoint
,
DART_TYPE
&
aDart
)
{
// The purpose is to have a fast and stable procedure that
// i) avoids concluding that a point is inside a triangle if it is not inside
// ii) avoids infinite loops
...
...
@@ -690,7 +692,7 @@ private:
// Thus, if false is returned, the point might still be inside a triangle in
// the triangulation. But this will probably only occur in the following cases:
// i) There are holes in the triangulation which causes the procedure to stop.
// ii) The boundary of the triangulation is not convex.
// ii) The boundary of the
m_
triangulation is not convex.
// ii) There might be degenerate triangles interior to the triangulation, or on the
// the boundary, which in some cases might cause the procedure to stop there due
// to the logic of the algorithm.
...
...
@@ -700,14 +702,14 @@ private:
// in the triangulation and and false is returned, then all triangles in the
// triangulation should be checked by the application. This can be done using
// the function:
// bool inTriangle(const PointType& point, const DartType& dart).
// bool inTriangle(const POINT_TYPE& point, const DART_TYPE& dart).
// Assumes:
// - crossProduct2d, scalarProduct2d etc., see functions called
// - CrossProduct2D, ScalarProduct2D etc., see functions called
bool
status
=
LocateFaceSimplest
<
TRAITS_TYPE
>
(
aPoint
,
aDart
);
bool
status
=
locateFaceSimplest
<
TraitsType
>
(
point
,
dart
);
if
(
status
==
false
)
if
(
status
==
false
)
return
status
;
// There may be degeneracy, i.e., the point might be outside the triangle
...
...
@@ -716,460 +718,453 @@ private:
// The next call returns true if inside a non-degenerate or a degenerate triangle,
// but false if the point coincides with the "supernode" in the case where all
// edges are degenerate.
return
inTriangle
<
TraitsType
>
(
point
,
dart
);
}
return
InTriangle
<
TRAITS_TYPE
>
(
aPoint
,
aDart
);
}
//------------------------------------------------------------------------------------------------
/** Checks if \e point is inside the triangle associated with \e dart.
//------------------------------------------------------------------------------------------------
/** Checks if \e point is inside the triangle associated with \e dart.
* A fast and simple function that does not deal with degeneracy.
*
* \param d
art
* \param aD
art
* A CCW dart in the triangle
*
* \require
* - \ref hed::TTLtraits::orient2d "TraitsType::orient2d" (DartType&, DartType&, PointType
&)
* - \ref hed::TTLtraits::Orient2D "TRAITS_TYPE::Orient2D" (DART_TYPE&, DART_TYPE&, POINT_TYPE
&)
*
* \see
* i
nTriangle for a more robust function
* I
nTriangle for a more robust function
*/
template
<
class
TraitsType
,
class
PointType
,
class
DartType
>
bool
TriangulationHelper
::
inTriangleSimplest
(
const
PointType
&
point
,
const
DartType
&
dart
)
{
template
<
class
TRAITS_TYPE
,
class
POINT_TYPE
,
class
DART_TYPE
>
bool
TRIANGULATION_HELPER
::
InTriangleSimplest
(
const
POINT_TYPE
&
aPoint
,
const
DART_TYPE
&
aDart
)
{
// Fast and simple: Do not deal with degenerate faces, i.e., if there is
// degeneracy, true will be returned if the point is on the extension of the
// edges of a degenerate triangle
DartType
d_iter
=
dart
;
DartType
d0
=
d_iter
;
d0
.
alpha0
();
if
(
!
TraitsType
::
orient2d
(
d_iter
,
d0
,
point
)
>=
0
)
DART_TYPE
d_iter
=
aDart
;
DART_TYPE
d0
=
d_iter
;
d0
.
Alpha0
();
if
(
!
TRAITS_TYPE
::
Orient2D
(
d_iter
,
d0
,
aPoint
)
>=
0
)
return
false
;
d_iter
.
alpha0
().
a
lpha1
();
d_iter
.
Alpha0
().
A
lpha1
();
d0
=
d_iter
;
d0
.
alpha0
();
if
(
!
TraitsType
::
orient2d
(
d_iter
,
d0
,
point
)
>=
0
)
d0
.
Alpha0
();
if
(
!
TRAITS_TYPE
::
Orient2D
(
d_iter
,
d0
,
aPoint
)
>=
0
)
return
false
;
d_iter
.
alpha0
().
a
lpha1
();
d_iter
.
Alpha0
().
A
lpha1
();
d0
=
d_iter
;
d0
.
alpha0
();
if
(
!
TraitsType
::
orient2d
(
d_iter
,
d0
,
point
)
>=
0
)
d0
.
Alpha0
();
if
(
!
TRAITS_TYPE
::
Orient2D
(
d_iter
,
d0
,
aPoint
)
>=
0
)
return
false
;
return
true
;
}
}
//------------------------------------------------------------------------------------------------
/** Checks if \e point is inside the triangle associated with \e dart.
/** Checks if \e point is inside the triangle associated with \e dart.
* This function deals with degeneracy to some extent, but round-off errors may still
* lead to wrong result if the triangle is degenerate.
*
* \param dart
* \param aDart
* A CCW dart in the triangle
*
* \require
* - \ref hed::TTLtraits::crossProduct2d "TraitsType::crossProduct2d" (DartType&, PointType
&)
* - \ref hed::TTLtraits::scalarProduct2d "TraitsType::scalarProduct2d" (DartType&, PointType
&)
* - \ref hed::TTLtraits::CrossProduct2D "TRAITS_TYPE::CrossProduct2D" (DART_TYPE&, POINT_TYPE
&)
* - \ref hed::TTLtraits::ScalarProduct2D "TRAITS_TYPE::ScalarProduct2D" (DART_TYPE&, POINT_TYPE
&)
*
* \see
* i
nTriangleSimplest
* I
nTriangleSimplest
*/
template
<
class
TraitsType
,
class
PointType
,
class
DartType
>
bool
TriangulationHelper
::
inTriangle
(
const
PointType
&
point
,
const
DartType
&
dart
)
{
template
<
class
TRAITS_TYPE
,
class
POINT_TYPE
,
class
DART_TYPE
>
bool
TRIANGULATION_HELPER
::
InTriangle
(
const
POINT_TYPE
&
aPoint
,
const
DART_TYPE
&
aDart
)
{
// SHOULD WE INCLUDE A STRATEGY WITH EDGE X e_1 ETC? TO GUARANTEE THAT
// ONLY ON ONE EDGE? BUT THIS DOES NOT SOLVE PROBLEMS WITH
// notInE1 && notInE1.neghbour ?
// Returns true if inside (but not necessarily strictly inside)
// Works for degenerate triangles, but not when all edges are degenerate,
// and the
p
oint coincides with all nodes;
// and the
aP
oint coincides with all nodes;
// then false is always returned.
typedef
typename
T
raitsType
::
real_type
real_type
;
typedef
typename
T
RAITS_TYPE
::
REAL_TYPE
REAL_TYPE
;
D
artType
dart_iter
=
d
art
;
D
ART_TYPE
dart_iter
=
aD
art
;
real_type
cr1
=
TraitsType
::
crossProduct2d
(
dart_iter
,
point
);
if
(
cr1
<
0
)
REAL_TYPE
cr1
=
TRAITS_TYPE
::
CrossProduct2D
(
dart_iter
,
aPoint
);
if
(
cr1
<
0
)
return
false
;
dart_iter
.
alpha0
().
a
lpha1
();
real_type
cr2
=
TraitsType
::
crossProduct2d
(
dart_iter
,
point
);
dart_iter
.
Alpha0
().
A
lpha1
();
REAL_TYPE
cr2
=
TRAITS_TYPE
::
CrossProduct2D
(
dart_iter
,
aPoint
);
if
(
cr2
<
0
)
if
(
cr2
<
0
)
return
false
;
dart_iter
.
alpha0
().
a
lpha1
();
real_type
cr3
=
TraitsType
::
crossProduct2d
(
dart_iter
,
point
);
if
(
cr3
<
0
)
dart_iter
.
Alpha0
().
A
lpha1
();
REAL_TYPE
cr3
=
TRAITS_TYPE
::
CrossProduct2D
(
dart_iter
,
aPoint
);
if
(
cr3
<
0
)
return
false
;
// All cross products are >= 0
// Check for degeneracy
if
(
cr1
!=
0
||
cr2
!=
0
||
cr3
!=
0
)
if
(
cr1
!=
0
||
cr2
!=
0
||
cr3
!=
0
)
return
true
;
// inside non-degenerate face
// All cross-products are zero, i.e. degenerate triangle, check if inside
// Strategy: d.
scalarProduct2d >= 0 && alpha0(d).d.scalarProduct2d
>= 0 for one of
// the edges. But if all edges are degenerate and the
p
oint is on (all) the nodes,
// Strategy: d.
ScalarProduct2D >= 0 && alpha0(d).d.ScalarProduct2D
>= 0 for one of
// the edges. But if all edges are degenerate and the
aP
oint is on (all) the nodes,
// then "false is returned".
D
artType
dart_tmp
=
dart_iter
;
real_type
sc1
=
TraitsType
::
scalarProduct2d
(
dart_tmp
,
point
);
real_type
sc2
=
TraitsType
::
scalarProduct2d
(
dart_tmp
.
alpha0
(),
point
);
D
ART_TYPE
dart_tmp
=
dart_iter
;
REAL_TYPE
sc1
=
TRAITS_TYPE
::
ScalarProduct2D
(
dart_tmp
,
aPoint
);
REAL_TYPE
sc2
=
TRAITS_TYPE
::
ScalarProduct2D
(
dart_tmp
.
Alpha0
(),
aPoint
);
if
(
sc1
>=
0
&&
sc2
>=
0
)
{
if
(
sc1
>=
0
&&
sc2
>=
0
)
{
// test for degenerate edge
if
(
sc1
!=
0
||
sc2
!=
0
)
if
(
sc1
!=
0
||
sc2
!=
0
)
return
true
;
// interior to this edge or on a node (but see comment above)
}
dart_tmp
=
dart_iter
.
alpha0
().
alpha1
();
sc1
=
TraitsType
::
scalarProduct2d
(
dart_tmp
,
point
);
sc2
=
TraitsType
::
scalarProduct2d
(
dart_tmp
.
alpha0
(),
point
);
if
(
sc1
>=
0
&&
sc2
>=
0
)
{
dart_tmp
=
dart_iter
.
Alpha0
().
Alpha1
();
sc1
=
TRAITS_TYPE
::
ScalarProduct2D
(
dart_tmp
,
aPoint
);
sc2
=
TRAITS_TYPE
::
ScalarProduct2D
(
dart_tmp
.
Alpha0
(),
aPoint
);
if
(
sc1
>=
0
&&
sc2
>=
0
)
{
// test for degenerate edge
if
(
sc1
!=
0
||
sc2
!=
0
)
if
(
sc1
!=
0
||
sc2
!=
0
)
return
true
;
// interior to this edge or on a node (but see comment above)
}
dart_tmp
=
dart_iter
.
alpha1
();
sc1
=
TraitsType
::
scalarProduct2d
(
dart_tmp
,
point
);
sc2
=
TraitsType
::
scalarProduct2d
(
dart_tmp
.
alpha0
(),
point
);
if
(
sc1
>=
0
&&
sc2
>=
0
)
{
dart_tmp
=
dart_iter
.
Alpha1
();
sc1
=
TRAITS_TYPE
::
ScalarProduct2D
(
dart_tmp
,
aPoint
);
sc2
=
TRAITS_TYPE
::
ScalarProduct2D
(
dart_tmp
.
Alpha0
(),
aPoint
);
if
(
sc1
>=
0
&&
sc2
>=
0
)
{
// test for degenerate edge
if
(
sc1
!=
0
||
sc2
!=
0
)
if
(
sc1
!=
0
||
sc2
!=
0
)
return
true
;
// interior to this edge or on a node (but see comment above)
}
// Not on any of the edges of the degenerate triangle.
// The only possibility for the
p
oint to be "inside" is that all edges are degenerate
// The only possibility for the
aP
oint to be "inside" is that all edges are degenerate
// and the point coincide with all nodes. So false is returned in this case.
return
false
;
}
}
//------------------------------------------------------------------------------------------------
// Private/Hidden function (might change later)
template
<
class
DartType
>
void
TriangulationHelper
::
getAdjacentTriangles
(
const
DartType
&
dart
,
DartType
&
t1
,
DartType
&
t2
,
DartType
&
t3
)
{
// Private/Hidden function (might change later)
template
<
class
DART_TYPE
>
void
TRIANGULATION_HELPER
::
getAdjacentTriangles
(
const
DART_TYPE
&
aDart
,
DART_TYPE
&
aT1
,
DART_TYPE
&
aT2
,
DART_TYPE
&
aT3
)
{
D
artType
dart_iter
=
d
art
;
D
ART_TYPE
dart_iter
=
aD
art
;
// add first
if
(
dart_iter
.
alpha2
()
!=
dart
)
{
t1
=
dart_iter
;
dart_iter
=
dart
;
if
(
dart_iter
.
Alpha2
()
!=
aDart
)
{
aT1
=
dart_iter
;
dart_iter
=
aDart
;
}
// add second
dart_iter
.
alpha0
();
dart_iter
.
alpha1
();
DartType
dart_prev
=
dart_iter
;
if
((
dart_iter
.
alpha2
())
!=
dart_prev
)
{
t2
=
dart_iter
;
dart_iter
.
Alpha0
();
dart_iter
.
Alpha1
();
DART_TYPE
dart_prev
=
dart_iter
;
if
(
(
dart_iter
.
Alpha2
()
)
!=
dart_prev
)
{
aT2
=
dart_iter
;
dart_iter
=
dart_prev
;
}
// add third
dart_iter
.
a
lpha0
();
dart_iter
.
a
lpha1
();
dart_iter
.
A
lpha0
();
dart_iter
.
A
lpha1
();
dart_prev
=
dart_iter
;
if
((
dart_iter
.
alpha2
())
!=
dart_prev
)
t3
=
dart_iter
;
}
if
(
(
dart_iter
.
Alpha2
()
)
!=
dart_prev
)
aT3
=
dart_iter
;
}
//------------------------------------------------------------------------------------------------
/** Gets the boundary as sequence of darts, where the edges associated with the darts are boundary
//------------------------------------------------------------------------------------------------
/** Gets the boundary as sequence of darts, where the edges associated with the darts are boundary
* edges, given a dart with an associating edge at the boundary of a topology structure.
* The first dart in the sequence will be the given one, and the others will have the same
* orientation (CCW or CW) as the first.
* Assumes that the given dart is at the boundary.
*
* \param dart
* \param aDart
* A dart at the boundary (CCW or CW)
*
* \param b
oundary
* \param aB
oundary
* A sequence of darts, where the associated edges are the boundary edges
*
* \require
* - DartListType::push_back (DartType
&)
* - DART_LIST_TYPE::push_back (DART_TYPE
&)
*/
template
<
class
DartType
,
class
DartListType
>
void
TriangulationHelper
::
getBoundary
(
const
DartType
&
dart
,
DartListType
&
boundary
)
{
template
<
class
DART_TYPE
,
class
DART_LIST_TYPE
>
void
TRIANGULATION_HELPER
::
GetBoundary
(
const
DART_TYPE
&
aDart
,
DART_LIST_TYPE
&
aBoundary
)
{
// assumes the given dart is at the boundary (by edge)
D
artType
dart_iter
(
dart
);
boundary
.
push_back
(
dart_iter
);
// Given dart as first element
dart_iter
.
a
lpha0
();
positionAtNextBoundaryEdge
(
dart_iter
);
D
ART_TYPE
dart_iter
(
aDart
);
aBoundary
.
push_back
(
dart_iter
);
// Given dart as first element
dart_iter
.
A
lpha0
();
PositionAtNextBoundaryEdge
(
dart_iter
);
while
(
dart_iter
!=
dart
)
{
boundary
.
push_back
(
dart_iter
);
dart_iter
.
alpha0
(
);
positionAtNextBoundaryEdge
(
dart_iter
);
}
while
(
dart_iter
!=
aDart
)
{
aBoundary
.
push_back
(
dart_iter
);
dart_iter
.
Alpha0
(
);
PositionAtNextBoundaryEdge
(
dart_iter
);
}
}
//------------------------------------------------------------------------------------------------
/*
// Asumes a fixed point (a boundary edge) is given
//
template <class DartType>
class boundary_1_Iterator { // i.e. "circulator"
DartType current_;
public:
boundaryEdgeIterator(const DartType& dart) {current_ = dart;}
DartType& operator * () const {return current_;}
void operator ++ () {current_.alpha0(); positionAtNextBoundaryEdge(current_);}
};
*/
//------------------------------------------------------------------------------------------------
/** Checks if the edge associated with \e dart is at
* the boundary of the triangulation.
/** Checks if the edge associated with \e dart is at
* the boundary of the m_triangulation.
*
* \par Implements:
* \code
* DartType
dart_iter = dart;
* if (dart_iter.a
lpha2() == dart)
* DART_TYPE
dart_iter = dart;
* if (dart_iter.A
lpha2() == dart)
* return true;
* else
* return false;
* \endcode
*/
template
<
class
DartType
>
bool
TriangulationHelper
::
isBoundaryEdge
(
const
DartType
&
dart
)
{
template
<
class
DART_TYPE
>
bool
TRIANGULATION_HELPER
::
IsBoundaryEdge
(
const
DART_TYPE
&
aDart
)
{
DART_TYPE
dart_iter
=
aDart
;
DartType
dart_iter
=
dart
;
if
(
dart_iter
.
alpha2
()
==
dart
)
if
(
dart_iter
.
Alpha2
()
==
aDart
)
return
true
;
else
return
false
;
}
}
//------------------------------------------------------------------------------------------------
/** Checks if the face associated with \e dart is at
* the boundary of the triangulation.
/** Checks if the face associated with \e dart is at
* the boundary of the m_triangulation.
*/
template
<
class
DartType
>
bool
TriangulationHelper
::
isBoundaryFace
(
const
DartType
&
dart
)
{
template
<
class
DART_TYPE
>
bool
TRIANGULATION_HELPER
::
IsBoundaryFace
(
const
DART_TYPE
&
aDart
)
{
// Strategy: boundary if alpha2(d)=d
D
artType
dart_iter
(
dart
);
D
artType
dart_prev
;
D
ART_TYPE
dart_iter
(
aDart
);
D
ART_TYPE
dart_prev
;
do
{
do
{
dart_prev
=
dart_iter
;
if
(
dart_iter
.
alpha2
()
==
dart_prev
)
if
(
dart_iter
.
Alpha2
()
==
dart_prev
)
return
true
;
else
dart_iter
=
dart_prev
;
// back again
dart_iter
.
a
lpha0
();
dart_iter
.
a
lpha1
();
dart_iter
.
A
lpha0
();
dart_iter
.
A
lpha1
();
}
while
(
dart_iter
!=
dart
);
}
while
(
dart_iter
!=
aDart
);
return
false
;
}
}
//------------------------------------------------------------------------------------------------
/** Checks if the node associated with \e dart is at
* the boundary of the triangulation.
/** Checks if the node associated with \e dart is at
* the boundary of the m_triangulation.
*/
template
<
class
DartType
>
bool
TriangulationHelper
::
isBoundaryNode
(
const
DartType
&
dart
)
{
template
<
class
DART_TYPE
>
bool
TRIANGULATION_HELPER
::
IsBoundaryNode
(
const
DART_TYPE
&
aDart
)
{
// Strategy: boundary if alpha2(d)=d
D
artType
dart_iter
(
dart
);
D
artType
dart_prev
;
D
ART_TYPE
dart_iter
(
aDart
);
D
ART_TYPE
dart_prev
;
// If input dart is reached again, then internal node
// If alpha2(d)=d, then boundary
do
{
dart_iter
.
alpha1
();
do
{
dart_iter
.
Alpha1
();
dart_prev
=
dart_iter
;
dart_iter
.
a
lpha2
();
dart_iter
.
A
lpha2
();
if
(
dart_iter
==
dart_prev
)
if
(
dart_iter
==
dart_prev
)
return
true
;
}
while
(
dart_iter
!=
dart
);
}
while
(
dart_iter
!=
aDart
);
return
false
;
}
}
//------------------------------------------------------------------------------------------------
/** Returns the degree of the node associated with \e dart.
/** Returns the degree of the node associated with \e dart.
*
* \par Definition:
* The \e degree (or valency) of a node \e V in a
triangulation,
* The \e degree (or valency) of a node \e V in a m_
triangulation,
* is defined as the number of edges incident with \e V, i.e.,
* the number of edges joining \e V with another node in the triangulation.
*/
template
<
class
DartType
>
int
TriangulationHelper
::
getDegreeOfNode
(
const
DartType
&
dart
)
{
D
artType
dart_iter
(
dart
);
D
artType
dart_prev
;
template
<
class
DART_TYPE
>
int
TRIANGULATION_HELPER
::
GetDegreeOfNode
(
const
DART_TYPE
&
aDart
)
{
D
ART_TYPE
dart_iter
(
aDart
);
D
ART_TYPE
dart_prev
;
// If input dart is reached again, then interior node
// If alpha2(d)=d, then boundary
int
degree
=
0
;
bool
boundaryVisited
=
false
;
do
{
dart_iter
.
alpha1
();
do
{
dart_iter
.
Alpha1
();
degree
++
;
dart_prev
=
dart_iter
;
dart_iter
.
a
lpha2
();
dart_iter
.
A
lpha2
();
if
(
dart_iter
==
dart_prev
)
{
if
(
!
boundaryVisited
)
{
if
(
dart_iter
==
dart_prev
)
{
if
(
!
boundaryVisited
)
{
boundaryVisited
=
true
;
// boundary is reached first time, count in the reversed direction
degree
++
;
// count the start since it is not done above
dart_iter
=
dart
;
dart_iter
.
alpha2
();
}
else
dart_iter
=
aDart
;
dart_iter
.
Alpha2
();
}
else
return
degree
;
}
}
while
(
dart_iter
!=
dart
);
}
while
(
dart_iter
!=
aDart
);
return
degree
;
}
}
// Modification of GetDegreeOfNode:
// Strategy, reverse the list and start in the other direction if the boundary
// is reached. NB. copying of darts but ok., or we could have collected pointers,
// but the memory management.
//------------------------------------------------------------------------------------------------
// Modification of getDegreeOfNode:
// Strategy, reverse the list and start in the other direction if the boundary
// is reached. NB. copying of darts but ok., or we could have collected pointers,
// but the memory management.
// NOTE: not symmetry if we choose to collect opposite edges
// now we collect darts with radiating edges
// NOTE: not symmetry if we choose to collect opposite edges
// now we collect darts with radiating edges
// Remember that we must also copy the node, but ok with push_back
// The size of the list will be the degree of the node
// Remember that we must also copy the node, but ok with push_back
// The size of the list will be the degree of the node
// No CW/CCW since topology only
// No CW/CCW since topology only
// Each dart consists of an incident edge and an adjacent node.
// But note that this is only how we interpret the dart in this implementation.
// Given this list, how can we find the opposite edges:
// We can perform alpha1 on each, but for boundary nodes we will get one edge twice.
// But this is will always be the last dart!
// The darts in the list are in sequence and starts with the alpha0(dart)
// alpha0, alpha1 and alpha2
// Each dart consists of an incident edge and an adjacent node.
// But note that this is only how we interpret the dart in this implementation.
// Given this list, how can we find the opposite edges:
// We can perform alpha1 on each, but for boundary nodes we will get one edge twice.
// But this is will always be the last dart!
// The darts in the list are in sequence and starts with the alpha0(dart)
// alpha0, alpha1 and alpha2
// Private/Hidden function
template
<
class
DartType
>
void
TriangulationHelper
::
getNeighborNodes
(
const
DartType
&
dart
,
std
::
list
<
DartType
>&
node_list
,
bool
&
boundary
)
{
DartType
dart_iter
(
dart
);
dart_iter
.
alpha0
();
// position the dart at an opposite node
DartType
dart_prev
=
dart_iter
;
// Private/Hidden function
template
<
class
DART_TYPE
>
void
TRIANGULATION_HELPER
::
getNeighborNodes
(
const
DART_TYPE
&
aDart
,
std
::
list
<
DART_TYPE
>&
aNodeList
,
bool
&
aBoundary
)
{
DART_TYPE
dart_iter
(
aDart
);
dart_iter
.
Alpha0
();
// position the dart at an opposite node
DART_TYPE
dart_prev
=
dart_iter
;
bool
start_at_boundary
=
false
;
dart_iter
.
alpha2
();
if
(
dart_iter
==
dart_prev
)
dart_iter
.
Alpha2
();
if
(
dart_iter
==
dart_prev
)
start_at_boundary
=
true
;
else
dart_iter
=
dart_prev
;
// back again
D
artType
dart_start
=
dart_iter
;
D
ART_TYPE
dart_start
=
dart_iter
;
do
{
node_list
.
push_back
(
dart_iter
);
dart_iter
.
alpha1
();
dart_iter
.
alpha0
();
dart_iter
.
alpha1
();
do
{
aNodeList
.
push_back
(
dart_iter
);
dart_iter
.
Alpha1
();
dart_iter
.
Alpha0
();
dart_iter
.
Alpha1
();
dart_prev
=
dart_iter
;
dart_iter
.
alpha2
();
if
(
dart_iter
==
dart_prev
)
{
dart_iter
.
Alpha2
();
if
(
dart_iter
==
dart_prev
)
{
// boundary reached
boundary
=
true
;
if
(
start_at_boundary
==
true
)
{
aBoundary
=
true
;
if
(
start_at_boundary
==
true
)
{
// add the dart which now is positioned at the opposite boundary
node_list
.
push_back
(
dart_iter
);
aNodeList
.
push_back
(
dart_iter
);
return
;
}
else
{
else
{
// call the function again such that we start at the boundary
// first clear the list and reposition to the initial node
dart_iter
.
alpha0
();
node_list
.
clear
();
getNeighborNodes
(
dart_iter
,
node_list
,
boundary
);
dart_iter
.
Alpha0
();
aNodeList
.
clear
();
getNeighborNodes
(
dart_iter
,
aNodeList
,
aBoundary
);
return
;
// after one recursive step
}
}
}
while
(
dart_iter
!=
dart_start
);
boundary
=
false
;
}
while
(
dart_iter
!=
dart_start
);
aBoundary
=
false
;
}
//------------------------------------------------------------------------------------------------
/** Gets the 0-orbit around an interior node.
/** Gets the 0-orbit around an interior node.
*
* \param d
art
* \param aD
art
* A dart (CCW or CW) positioned at an \e interior node.
*
* \retval o
rbit
* \retval aO
rbit
* Sequence of darts with one orbit for each arc. All the darts have the same
* orientation (CCW or CW) as \e dart, and \e dart is the first element
* in the sequence.
*
* \require
* - DartListType::push_back (DartType
&)
* - DART_LIST_TYPE::push_back (DART_TYPE
&)
*
* \see
* get_0_orbit_b
oundary
* Get0OrbitB
oundary
*/
template
<
class
DartType
,
class
DartListType
>
void
TriangulationHelper
::
get_0_orbit_interior
(
const
DartType
&
dart
,
DartListType
&
orbit
)
{
D
artType
d_iter
=
d
art
;
orbit
.
push_back
(
d_iter
);
d_iter
.
alpha1
().
a
lpha2
();
template
<
class
DART_TYPE
,
class
DART_LIST_TYPE
>
void
TRIANGULATION_HELPER
::
Get0OrbitInterior
(
const
DART_TYPE
&
aDart
,
DART_LIST_TYPE
&
aOrbit
)
{
D
ART_TYPE
d_iter
=
aD
art
;
aOrbit
.
push_back
(
d_iter
);
d_iter
.
Alpha1
().
A
lpha2
();
while
(
d_iter
!=
dart
)
{
orbit
.
push_back
(
d_iter
);
d_iter
.
alpha1
().
alpha2
(
);
}
while
(
d_iter
!=
aDart
)
{
aOrbit
.
push_back
(
d_iter
);
d_iter
.
Alpha1
().
Alpha2
();
}
}
//------------------------------------------------------------------------------------------------
/** Gets the 0-orbit around a node at the boundary
/** Gets the 0-orbit around a node at the boundary
*
* \param d
art
* \param aD
art
* A dart (CCW or CW) positioned at a \e boundary \e node and at a \e boundary \e edge.
*
* \retval orbit
...
...
@@ -1178,32 +1173,33 @@ private:
* in the sequence.
*
* \require
* - DartListType::push_back (DartType
&)
* - DART_LIST_TYPE::push_back (DART_TYPE
&)
*
* \note
* - The last dart in the sequence have opposite orientation compared to the others!
*
* \see
* get_0_orbit_i
nterior
* Get0OrbitI
nterior
*/
template
<
class
DartType
,
class
DartListType
>
void
TriangulationHelper
::
get_0_orbit_boundary
(
const
DartType
&
dart
,
DartListType
&
orbit
)
{
DartType
dart_prev
;
DartType
d_iter
=
dart
;
do
{
orbit
.
push_back
(
d_iter
);
d_iter
.
alpha1
();
dart_prev
=
d_iter
;
d_iter
.
alpha2
();
}
while
(
d_iter
!=
dart_prev
);
template
<
class
DART_TYPE
,
class
DART_LIST_TYPE
>
void
TRIANGULATION_HELPER
::
Get0OrbitBoundary
(
const
DART_TYPE
&
aDart
,
DART_LIST_TYPE
&
aOrbit
)
{
DART_TYPE
dart_prev
;
DART_TYPE
d_iter
=
aDart
;
orbit
.
push_back
(
d_iter
);
// the last one with opposite orientation
do
{
aOrbit
.
push_back
(
d_iter
);
d_iter
.
Alpha1
();
dart_prev
=
d_iter
;
d_iter
.
Alpha2
();
}
while
(
d_iter
!=
dart_prev
);
aOrbit
.
push_back
(
d_iter
);
// the last one with opposite orientation
}
//------------------------------------------------------------------------------------------------
/** Checks if the two darts belong to the same 0-orbit, i.e.,
/** Checks if the two darts belong to the same 0-orbit, i.e.,
* if they share a node.
* \e d1 and/or \e d2 can be CCW or CW.
*
...
...
@@ -1213,141 +1209,140 @@ private:
* node and a faster version is needed, the user should implement his/her
* own version.)
*/
template
<
class
DartType
>
bool
TriangulationHelper
::
same_0_orbit
(
const
DartType
&
d1
,
const
DartType
&
d2
)
{
template
<
class
DART_TYPE
>
bool
TRIANGULATION_HELPER
::
Same0Orbit
(
const
DART_TYPE
&
aD1
,
const
DART_TYPE
&
aD2
)
{
// Two copies of the same dart
D
artType
d_iter
=
d
2
;
D
artType
d_end
=
d
2
;
D
ART_TYPE
d_iter
=
aD
2
;
D
ART_TYPE
d_end
=
aD
2
;
if
(
isBoundaryNode
(
d_iter
))
{
if
(
isBoundaryNode
(
d_iter
)
)
{
// position at both boundary edges
positionAtNextBoundaryEdge
(
d_iter
);
d_end
.
a
lpha1
();
positionAtNextBoundaryEdge
(
d_end
);
PositionAtNextBoundaryEdge
(
d_iter
);
d_end
.
A
lpha1
();
PositionAtNextBoundaryEdge
(
d_end
);
}
for
(;;)
{
if
(
d_iter
==
d1
)
for
(
;;
)
{
if
(
d_iter
==
aD1
)
return
true
;
d_iter
.
alpha1
();
if
(
d_iter
==
d1
)
d_iter
.
Alpha1
();
if
(
d_iter
==
aD1
)
return
true
;
d_iter
.
alpha2
();
if
(
d_iter
==
d_end
)
d_iter
.
Alpha2
();
if
(
d_iter
==
d_end
)
break
;
}
return
false
;
}
}
//------------------------------------------------------------------------------------------------
/** Checks if the two darts belong to the same 1-orbit, i.e.,
/** Checks if the two darts belong to the same 1-orbit, i.e.,
* if they share an edge.
* \e d1 and/or \e d2 can be CCW or CW.
*/
template
<
class
DartType
>
bool
TriangulationHelper
::
same_1_orbit
(
const
DartType
&
d1
,
const
DartType
&
d2
)
{
template
<
class
DART_TYPE
>
bool
TRIANGULATION_HELPER
::
Same1Orbit
(
const
DART_TYPE
&
aD1
,
const
DART_TYPE
&
aD2
)
{
DART_TYPE
d_iter
=
aD2
;
DartType
d_iter
=
d2
;
// (Also works at the boundary)
if
(
d_iter
==
d1
||
d_iter
.
alpha0
()
==
d1
||
d_iter
.
alpha2
()
==
d1
||
d_iter
.
alpha0
()
==
d1
)
return
true
;
return
false
;
}
return
(
d_iter
==
aD1
||
d_iter
.
Alpha0
()
==
aD1
||
d_iter
.
Alpha2
()
==
aD1
||
d_iter
.
Alpha0
()
==
aD1
);
}
//------------------------------------------------------------------------------------------------
/** Checks if the two darts belong to the same 2-orbit, i.e.,
//------------------------------------------------------------------------------------------------
/** Checks if the two darts belong to the same 2-orbit, i.e.,
* if they lie in the same triangle.
* \e d1 and/or \e d2 can be CCW or CW
*/
template
<
class
DartType
>
bool
TriangulationHelper
::
same_2_orbit
(
const
DartType
&
d1
,
const
DartType
&
d2
)
{
DartType
d_iter
=
d2
;
if
(
d_iter
==
d1
||
d_iter
.
alpha0
()
==
d1
||
d_iter
.
alpha1
()
==
d1
||
d_iter
.
alpha0
()
==
d1
||
d_iter
.
alpha1
()
==
d1
||
d_iter
.
alpha0
()
==
d1
)
return
true
;
return
false
;
}
template
<
class
DART_TYPE
>
bool
TRIANGULATION_HELPER
::
Same2Orbit
(
const
DART_TYPE
&
aD1
,
const
DART_TYPE
&
aD2
)
{
DART_TYPE
d_iter
=
aD2
;
//------------------------------------------------------------------------------------------------
// Private/Hidden function
template
<
class
TraitsType
,
class
DartType
>
bool
TriangulationHelper
::
degenerateTriangle
(
const
DartType
&
dart
)
{
return
(
d_iter
==
aD1
||
d_iter
.
Alpha0
()
==
aD1
||
d_iter
.
Alpha1
()
==
aD1
||
d_iter
.
Alpha0
()
==
aD1
||
d_iter
.
Alpha1
()
==
aD1
||
d_iter
.
Alpha0
()
==
aD1
);
}
// Private/Hidden function
template
<
class
TRAITS_TYPE
,
class
DART_TYPE
>
bool
TRIANGULATION_HELPER
::
degenerateTriangle
(
const
DART_TYPE
&
aDart
)
{
// Check if triangle is degenerate
// Assumes CCW dart
DartType
d1
=
dart
;
DartType
d2
=
d1
;
d2
.
alpha1
();
if
(
TraitsType
::
crossProduct2d
(
d1
,
d2
)
==
0
)
return
true
;
return
false
;
}
DART_TYPE
d1
=
aDart
;
DART_TYPE
d2
=
d1
;
d2
.
Alpha1
();
return
(
TRAITS_TYPE
::
CrossProduct2D
(
d1
,
d2
)
==
0
);
}
//------------------------------------------------------------------------------------------------
/** Checks if the edge associated with \e dart is swappable, i.e., if the edge
/** Checks if the edge associated with \e dart is swappable, i.e., if the edge
* is a diagonal in a \e strictly convex (or convex) quadrilateral.
*
* \param a
llowDegeneracy
* \param aA
llowDegeneracy
* If set to true, the function will also return true if the numerical calculations
* indicate that the quadrilateral is convex only, and not necessarily strictly
* convex.
*
* \require
* - \ref hed::TTLtraits::crossProduct2d "TraitsType::crossProduct2d
" (Dart&, Dart&)
* - \ref hed::TTLtraits::CrossProduct2D "TRAITS_TYPE::CrossProduct2D
" (Dart&, Dart&)
*/
template
<
class
TraitsType
,
class
DartType
>
bool
TriangulationHelper
::
swappableEdge
(
const
DartType
&
dart
,
bool
allowDegeneracy
)
{
template
<
class
TRAITS_TYPE
,
class
DART_TYPE
>
bool
TRIANGULATION_HELPER
::
SwappableEdge
(
const
DART_TYPE
&
aDart
,
bool
aAllowDegeneracy
)
{
// How "safe" is it?
if
(
isBoundaryEdge
(
dart
)
)
if
(
IsBoundaryEdge
(
aDart
)
)
return
false
;
// "angles" are at the diagonal
DartType
d1
=
dart
;
d1
.
alpha2
().
alpha1
();
DartType
d2
=
dart
;
d2
.
alpha1
();
if
(
allowDegeneracy
)
{
if
(
TraitsType
::
crossProduct2d
(
d1
,
d2
)
<
0
.
0
)
DART_TYPE
d1
=
aDart
;
d1
.
Alpha2
().
Alpha1
();
DART_TYPE
d2
=
aDart
;
d2
.
Alpha1
();
if
(
aAllowDegeneracy
)
{
if
(
TRAITS_TYPE
::
CrossProduct2D
(
d1
,
d2
)
<
0
.
0
)
return
false
;
}
else
{
if
(
TraitsType
::
crossProduct2d
(
d1
,
d2
)
<=
0
.
0
)
else
{
if
(
TRAITS_TYPE
::
CrossProduct2D
(
d1
,
d2
)
<=
0
.
0
)
return
false
;
}
// Opposite side (still angle at the diagonal)
d1
=
d
art
;
d1
.
a
lpha0
();
d1
=
aD
art
;
d1
.
A
lpha0
();
d2
=
d1
;
d1
.
a
lpha1
();
d2
.
alpha2
().
a
lpha1
();
d1
.
A
lpha1
();
d2
.
Alpha2
().
A
lpha1
();
if
(
allowDegeneracy
)
{
if
(
TraitsType
::
crossProduct2d
(
d1
,
d2
)
<
0
.
0
)
if
(
aAllowDegeneracy
)
{
if
(
TRAITS_TYPE
::
CrossProduct2D
(
d1
,
d2
)
<
0
.
0
)
return
false
;
}
else
{
if
(
TraitsType
::
crossProduct2d
(
d1
,
d2
)
<=
0
.
0
)
else
{
if
(
TRAITS_TYPE
::
CrossProduct2D
(
d1
,
d2
)
<=
0
.
0
)
return
false
;
}
return
true
;
}
return
true
;
}
//------------------------------------------------------------------------------------------------
/** Given a \e dart, CCW or CW, positioned in a 0-orbit at the boundary of a tessellation.
/** Given a \e dart, CCW or CW, positioned in a 0-orbit at the boundary of a tessellation.
* Position \e dart at a boundary edge in the same 0-orbit.\n
* If the given \e dart is CCW, \e dart is positioned at the left boundary edge
* and will be CW.\n
...
...
@@ -1358,59 +1353,66 @@ private:
* - The given \e dart must have a source node at the boundary, otherwise an
* infinit loop occurs.
*/
template
<
class
DartType
>
void
TriangulationHelper
::
positionAtNextBoundaryEdge
(
DartType
&
dart
)
{
D
artType
dart_prev
;
template
<
class
DART_TYPE
>
void
TRIANGULATION_HELPER
::
PositionAtNextBoundaryEdge
(
DART_TYPE
&
aDart
)
{
D
ART_TYPE
dart_prev
;
// If alpha2(d)=d, then boundary
//old convention: dart.
a
lpha0();
do
{
dart
.
alpha1
();
dart_prev
=
dart
;
dart
.
alpha2
()
;
}
while
(
dart
!=
dart_prev
);
//old convention: dart.
A
lpha0();
do
{
aDart
.
Alpha1
()
;
dart_prev
=
aDart
;
aDart
.
Alpha2
(
);
}
while
(
aDart
!=
dart_prev
);
}
//------------------------------------------------------------------------------------------------
/** Checks if the boundary of a triangulation is convex.
/** Checks if the boundary of a triangulation is convex.
*
* \param dart
* A CCW dart at the boundary of the
triangulation
* A CCW dart at the boundary of the m_
triangulation
*
* \require
* - \ref hed::TTLtraits::crossProduct2d "TraitsType::crossProduct2d
" (const Dart&, const Dart&)
* - \ref hed::TTLtraits::CrossProduct2D "TRAITS_TYPE::CrossProduct2D
" (const Dart&, const Dart&)
*/
template
<
class
TraitsType
,
class
DartType
>
bool
TriangulationHelper
::
convexBoundary
(
const
DartType
&
dart
)
{
std
::
list
<
D
artType
>
blist
;
getBoundary
(
dart
,
blist
);
template
<
class
TRAITS_TYPE
,
class
DART_TYPE
>
bool
TRIANGULATION_HELPER
::
ConvexBoundary
(
const
DART_TYPE
&
aDart
)
{
std
::
list
<
D
ART_TYPE
>
blist
;
getBoundary
(
aDart
,
blist
);
int
no
;
no
=
(
int
)
blist
.
size
();
typename
std
::
list
<
D
artType
>::
const_iterator
bit
=
blist
.
begin
();
D
artType
d1
=
*
bit
;
no
=
(
int
)
blist
.
size
();
typename
std
::
list
<
D
ART_TYPE
>::
const_iterator
bit
=
blist
.
begin
();
D
ART_TYPE
d1
=
*
bit
;
++
bit
;
D
artType
d2
;
D
ART_TYPE
d2
;
bool
convex
=
true
;
for
(;
bit
!=
blist
.
end
();
++
bit
)
{
for
(
;
bit
!=
blist
.
end
();
++
bit
)
{
d2
=
*
bit
;
double
crossProd
=
TraitsType
::
crossProduct2d
(
d1
,
d2
);
if
(
crossProd
<
0
.
0
)
{
double
crossProd
=
TRAITS_TYPE
::
CrossProduct2D
(
d1
,
d2
);
if
(
crossProd
<
0
.
0
)
{
//cout << "!!! Boundary is NOT convex: crossProd = " << crossProd << endl;
convex
=
false
;
return
convex
;
}
d1
=
d2
;
}
// Check the last angle
d2
=
*
blist
.
begin
();
double
crossProd
=
TraitsType
::
crossProduct2d
(
d1
,
d2
);
if
(
crossProd
<
0
.
0
)
{
double
crossProd
=
TRAITS_TYPE
::
CrossProduct2D
(
d1
,
d2
);
if
(
crossProd
<
0
.
0
)
{
//cout << "!!! Boundary is NOT convex: crossProd = " << crossProd << endl;
convex
=
false
;
}
...
...
@@ -1419,46 +1421,41 @@ private:
// cout << "\n---> Boundary is convex\n" << endl;
//cout << endl;
return
convex
;
}
//@} // End of Topological and Geometric Queries Group
//------------------------------------------------------------------------------------------------
// ------------------------ Utilities for Delaunay Triangulation Group --------------------------
//------------------------------------------------------------------------------------------------
}
/** @name Utilities for Delaunay Triangulation */
//@{
//@} // End of Topological and Geometric Queries Group
//------------------------------------------------------------------------------------------------
/** Optimizes the edges in the given sequence according to the
/** @name Utilities for Delaunay Triangulation */
//@{
//------------------------------------------------------------------------------------------------
/** Optimizes the edges in the given sequence according to the
* \e Delaunay criterion, i.e., such that the edge will fullfill the
* \e circumcircle criterion (or equivalently the \e MaxMin
* angle criterion) with respect to the quadrilaterals where
* they are diagonals.
*
* \param elist
* \param aElist
* The sequence of edges
*
* \require
* - \ref hed::TTLtraits::swapEdge "TraitsType::swapEdge" (DartType
& \e dart)\n
* - \ref hed::TTLtraits::swapEdge "TRAITS_TYPE::swapEdge" (DART_TYPE
& \e dart)\n
* \b Note: Must be implemented such that \e dart is delivered back in a position as
* seen if it was glued to the edge when swapping (rotating) the edge CCW
*
* \using
* - swapTestDelaunay
*/
template
<
class
TraitsType
,
class
DartType
,
class
DartListType
>
void
TriangulationHelper
::
optimizeDelaunay
(
DartListType
&
elist
)
{
optimizeDelaunay
<
TraitsType
,
DartType
,
DartListType
>
(
elist
,
elist
.
end
());
}
//------------------------------------------------------------------------------------------------
template
<
class
TraitsType
,
class
DartType
,
class
DartListType
>
void
TriangulationHelper
::
optimizeDelaunay
(
DartListType
&
elist
,
const
typename
DartListType
::
iterator
end
)
{
template
<
class
TRAITS_TYPE
,
class
DART_TYPE
,
class
DART_LIST_TYPE
>
void
TRIANGULATION_HELPER
::
OptimizeDelaunay
(
DART_LIST_TYPE
&
aElist
)
{
OptimizeDelaunay
<
TRAITS_TYPE
,
DART_TYPE
,
DART_LIST_TYPE
>
(
aElist
,
aElist
.
end
()
);
}
//------------------------------------------------------------------------------------------------
template
<
class
TRAITS_TYPE
,
class
DART_TYPE
,
class
DART_LIST_TYPE
>
void
TRIANGULATION_HELPER
::
OptimizeDelaunay
(
DART_LIST_TYPE
&
aElist
,
const
typename
DART_LIST_TYPE
::
iterator
aEnd
)
{
// CCW darts
// Optimize here means Delaunay, but could be any criterion by
// requiring a "should swap" in the traits class, or give
...
...
@@ -1475,15 +1472,15 @@ private:
// (A vector instead of a list may be better.)
// First check that elist is not empty
if
(
elist
.
empty
()
)
if
(
aElist
.
empty
()
)
return
;
// Avoid cycling by more extensive circumcircle test
bool
cycling_check
=
true
;
bool
optimal
=
false
;
typename
D
artListType
::
iterator
it
;
typename
D
ART_LIST_TYPE
::
iterator
it
;
typename
D
artListType
::
iterator
end_opt
=
e
nd
;
typename
D
ART_LIST_TYPE
::
iterator
end_opt
=
aE
nd
;
// Hmm... The following code is trying to derefence an iterator that may
// be invalid. This may lead to debug error on Windows, so we comment out
...
...
@@ -1491,52 +1488,53 @@ private:
// problems...
//
// last_opt is passed the end of the "active list"
//typename D
artListType
::iterator end_opt;
//typename D
ART_LIST_TYPE
::iterator end_opt;
//if (*end != NULL)
// end_opt = end;
//else
// end_opt = elist.end();
while
(
!
optimal
)
{
while
(
!
optimal
)
{
optimal
=
true
;
for
(
it
=
elist
.
begin
();
it
!=
end_opt
;
++
it
)
{
if
(
swapTestDelaunay
<
TraitsType
>
(
*
it
,
cycling_check
))
{
for
(
it
=
aElist
.
begin
();
it
!=
end_opt
;
++
it
)
{
if
(
SwapTestDelaunay
<
TRAITS_TYPE
>
(
*
it
,
cycling_check
)
)
{
// Preserve darts. Potential darts in the list are:
// - The current dart
// - the four CCW darts on the boundary of the quadrilateral
// (the current arc has only one dart)
swapEdgeInList
<
TraitsType
,
DartType
>
(
it
,
elist
);
SwapEdgeInList
<
TRAITS_TYPE
,
DART_TYPE
>
(
it
,
aElist
);
optimal
=
false
;
}
// end if should swap
}
// end for
}
// end pass
}
}
//------------------------------------------------------------------------------------------------
/** Checks if the edge associated with \e dart should be swapped according
/** Checks if the edge associated with \e dart should be swapped according
* to the \e Delaunay criterion, i.e., the \e circumcircle criterion (or
* equivalently the \e MaxMin angle criterion).
*
* \param cycling_c
heck
* \param aCyclingC
heck
* Must be set to \c true when used in connection with optimization algorithms,
* e.g., o
ptimizeDelaunay. This will avoid cycling and infinite loops in nearly
* e.g., O
ptimizeDelaunay. This will avoid cycling and infinite loops in nearly
* neutral cases.
*
* \require
* - \ref hed::TTLtraits::scalarProduct2d "TraitsType::scalarProduct2d" (DartType&, DartType
&)
* - \ref hed::TTLtraits::crossProduct2d "TraitsType::crossProduct2d" (DartType&, DartType
&)
* - \ref hed::TTLtraits::ScalarProduct2D "TRAITS_TYPE::ScalarProduct2D" (DART_TYPE&, DART_TYPE
&)
* - \ref hed::TTLtraits::CrossProduct2D "TRAITS_TYPE::CrossProduct2D" (DART_TYPE&, DART_TYPE
&)
*/
template
<
class
TraitsType
,
class
DartType
>
template
<
class
TRAITS_TYPE
,
class
DART_TYPE
>
#if ((_MSC_VER > 0) && (_MSC_VER < 1300))//#ifdef _MSC_VER
bool
TriangulationHelper
::
swapTestDelaunay
(
const
DartType
&
dart
,
bool
cycling_check
=
false
)
const
{
bool
TRIANGULATION_HELPER
::
SwapTestDelaunay
(
const
DART_TYPE
&
aDart
,
bool
aCyclingCheck
=
false
)
const
{
#else
bool
TriangulationHelper
::
swapTestDelaunay
(
const
DartType
&
dart
,
bool
cycling_check
)
const
{
bool
TRIANGULATION_HELPER
::
SwapTestDelaunay
(
const
DART_TYPE
&
aDart
,
bool
aCyclingCheck
)
const
{
#endif
// The general strategy is taken from Cline & Renka. They claim that
// their algorithm insure numerical stability, but experiments show
// that this is not correct for neutral, or almost neutral cases.
...
...
@@ -1544,41 +1542,44 @@ private:
// cycling and infinit loops when used in connection with LOP algorithms;
// see the comments below.
typedef
typename
T
raitsType
::
real_type
real_type
;
typedef
typename
T
RAITS_TYPE
::
REAL_TYPE
REAL_TYPE
;
if
(
isBoundaryEdge
(
dart
)
)
if
(
IsBoundaryEdge
(
aDart
)
)
return
false
;
D
artType
v11
=
d
art
;
v11
.
alpha1
().
a
lpha0
();
D
artType
v12
=
v11
;
v12
.
a
lpha1
();
D
ART_TYPE
v11
=
aD
art
;
v11
.
Alpha1
().
A
lpha0
();
D
ART_TYPE
v12
=
v11
;
v12
.
A
lpha1
();
D
artType
v22
=
d
art
;
v22
.
alpha2
().
alpha1
().
a
lpha0
();
D
artType
v21
=
v22
;
v21
.
a
lpha1
();
D
ART_TYPE
v22
=
aD
art
;
v22
.
Alpha2
().
Alpha1
().
A
lpha0
();
D
ART_TYPE
v21
=
v22
;
v21
.
A
lpha1
();
real_type
cos1
=
TraitsType
::
scalarProduct2d
(
v11
,
v12
);
real_type
cos2
=
TraitsType
::
scalarProduct2d
(
v21
,
v22
);
REAL_TYPE
cos1
=
TRAITS_TYPE
::
ScalarProduct2D
(
v11
,
v12
);
REAL_TYPE
cos2
=
TRAITS_TYPE
::
ScalarProduct2D
(
v21
,
v22
);
// "Angles" are opposite to the diagonal.
// The diagonals should be swapped iff (t1+t2) .gt. 180
// degrees. The following two tests insure numerical
// stability according to Cline & Renka. But experiments show
// that cycling may still happen; see the aditional test below.
if
(
cos1
>=
0
&&
cos2
>=
0
)
// both angles are grater or equual 90
if
(
cos1
>=
0
&&
cos2
>=
0
)
// both angles are grater or equual 90
return
false
;
if
(
cos1
<
0
&&
cos2
<
0
)
// both angles are less than 90
if
(
cos1
<
0
&&
cos2
<
0
)
// both angles are less than 90
return
true
;
real_type
sin1
=
TraitsType
::
crossProduct2d
(
v11
,
v12
);
real_type
sin2
=
TraitsType
::
crossProduct2d
(
v21
,
v22
);
real_type
sin12
=
sin1
*
cos2
+
cos1
*
sin2
;
if
(
sin12
>=
0
)
// equality represents a neutral case
REAL_TYPE
sin1
=
TRAITS_TYPE
::
CrossProduct2D
(
v11
,
v12
);
REAL_TYPE
sin2
=
TRAITS_TYPE
::
CrossProduct2D
(
v21
,
v22
);
REAL_TYPE
sin12
=
sin1
*
cos2
+
cos1
*
sin2
;
if
(
sin12
>=
0
)
// equality represents a neutral case
return
false
;
if
(
cycling_check
)
{
if
(
aCyclingCheck
)
{
// situation so far is sin12 < 0. Test if this also
// happens for the swapped edge.
...
...
@@ -1587,108 +1588,111 @@ private:
// in neutral cases, or almost neutral cases, it may happen that
// the swapped edge may again be found to be not Delaunay and thus
// be swapped if we return true here. This may lead to cycling and
// an infinte loop when used, e.g., in connection with o
ptimizeDelaunay.
// an infinte loop when used, e.g., in connection with O
ptimizeDelaunay.
//
// In an attempt to avoid this we test if the swapped edge will
// also be found to be not Delaunay by repeating the last test above
// for the swapped edge.
// We now rely on the general requirement for TraitsType
::swapEdge which
// We now rely on the general requirement for TRAITS_TYPE
::swapEdge which
// should deliver CCW dart back in "the same position"; see the general
// description. This will insure numerical stability as the next calculation
// is the same as if this function was called again with the swapped edge.
// Cycling is thus impossible provided that the initial tests above does
// not result in ambiguity (and they should probably not do so).
v11
.
a
lpha0
();
v12
.
a
lpha0
();
v21
.
a
lpha0
();
v22
.
a
lpha0
();
v11
.
A
lpha0
();
v12
.
A
lpha0
();
v21
.
A
lpha0
();
v22
.
A
lpha0
();
// as if the edge was swapped/rotated CCW
cos1
=
TraitsType
::
scalarProduct2d
(
v22
,
v11
);
cos2
=
TraitsType
::
scalarProduct2d
(
v12
,
v21
);
sin1
=
TraitsType
::
crossProduct2d
(
v22
,
v11
);
sin2
=
TraitsType
::
crossProduct2d
(
v12
,
v21
);
sin12
=
sin1
*
cos2
+
cos1
*
sin2
;
if
(
sin12
<
0
)
{
cos1
=
TRAITS_TYPE
::
ScalarProduct2D
(
v22
,
v11
);
cos2
=
TRAITS_TYPE
::
ScalarProduct2D
(
v12
,
v21
);
sin1
=
TRAITS_TYPE
::
CrossProduct2D
(
v22
,
v11
);
sin2
=
TRAITS_TYPE
::
CrossProduct2D
(
v12
,
v21
);
sin12
=
sin1
*
cos2
+
cos1
*
sin2
;
if
(
sin12
<
0
)
{
// A neutral case, but the tests above lead to swapping
return
false
;
}
}
return
true
;
}
//-----------------------------------------------------------------------
//
// x
//" / \ "
// / | \ Darts:
//oe2 / | \ oe2 = oppEdge2
// x....|....x
// \ d| d/ d = diagonal (input and output)
// \ | /
// oe1 \ / oe1 = oppEdge1
// x
//
//-----------------------------------------------------------------------
/** Recursively swaps edges in the triangulation according to the \e Delaunay criterion.
*
* \param diagonal
}
//-----------------------------------------------------------------------
//
// x
//" / \ "
// / | \ Darts:
//oe2 / | \ oe2 = oppEdge2
// x....|....x
// \ d| d/ d = diagonal (input and output)
// \ | /
// oe1 \ / oe1 = oppEdge1
// x
//
//-----------------------------------------------------------------------
/** Recursively swaps edges in the triangulation according to the \e Delaunay criterion.
*
* \param aDiagonal
* A CCW dart representing the edge where the recursion starts from.
*
* \require
* - \ref hed::TTLtraits::swapEdge "TraitsType::swapEdge" (DartType
&)\n
* - \ref hed::TTLtraits::swapEdge "TRAITS_TYPE::swapEdge" (DART_TYPE
&)\n
* \b Note: Must be implemented such that the darts outside the quadrilateral
* are not affected by the swap.
*
* \using
* - Calls itself recursively
*/
template
<
class
TraitsType
,
class
DartType
>
void
TriangulationHelper
::
recSwapDelaunay
(
DartType
&
diagonal
)
{
if
(
!
swapTestDelaunay
<
TraitsType
>
(
diagonal
)
)
template
<
class
TRAITS_TYPE
,
class
DART_TYPE
>
void
TRIANGULATION_HELPER
::
RecSwapDelaunay
(
DART_TYPE
&
aDiagonal
)
{
if
(
!
SwapTestDelaunay
<
TRAITS_TYPE
>
(
aDiagonal
)
)
// ??? swapTestDelaunay also checks if boundary, so this can be optimized
return
;
// Get the other "edges" of the current triangle; see illustration above.
D
artType
oppEdge1
=
diagonal
;
oppEdge1
.
a
lpha1
();
D
ART_TYPE
oppEdge1
=
aDiagonal
;
oppEdge1
.
A
lpha1
();
bool
b1
;
if
(
isBoundaryEdge
(
oppEdge1
))
if
(
IsBoundaryEdge
(
oppEdge1
)
)
b1
=
true
;
else
{
else
{
b1
=
false
;
oppEdge1
.
a
lpha2
();
oppEdge1
.
A
lpha2
();
}
DartType
oppEdge2
=
diagonal
;
oppEdge2
.
alpha0
().
alpha1
().
alpha0
();
DART_TYPE
oppEdge2
=
aDiagonal
;
oppEdge2
.
Alpha0
().
Alpha1
().
Alpha0
();
bool
b2
;
if
(
isBoundaryEdge
(
oppEdge2
))
if
(
IsBoundaryEdge
(
oppEdge2
)
)
b2
=
true
;
else
{
else
{
b2
=
false
;
oppEdge2
.
a
lpha2
();
oppEdge2
.
A
lpha2
();
}
// Swap the given diagonal
triangulation
.
swapEdge
(
diagonal
);
m_triangulation
.
swapEdge
(
aDiagonal
);
if
(
!
b1
)
recSwapDelaunay
<
TraitsType
>
(
oppEdge1
);
if
(
!
b2
)
recSwapDelaunay
<
TraitsType
>
(
oppEdge2
);
}
if
(
!
b1
)
RecSwapDelaunay
<
TRAITS_TYPE
>
(
oppEdge1
);
if
(
!
b2
)
RecSwapDelaunay
<
TRAITS_TYPE
>
(
oppEdge2
);
}
//------------------------------------------------------------------------------------------------
/** Swaps edges away from the (interior) node associated with
/** Swaps edges away from the (interior) node associated with
* \e dart such that that exactly three edges remain incident
* with the node.
* This function is used as a first step in r
emoveInteriorNode
* This function is used as a first step in R
emoveInteriorNode
*
* \retval dart
* A CCW dart incident with the node
...
...
@@ -1698,7 +1702,7 @@ private:
* triangulation.
*
* \require
* - \ref hed::TTLtraits::swapEdge "TraitsType::swapEdge" (DartType
& \e dart)\n
* - \ref hed::TTLtraits::swapEdge "TRAITS_TYPE::swapEdge" (DART_TYPE
& \e dart)\n
* \b Note: Must be implemented such that \e dart is delivered back in a position as
* seen if it was glued to the edge when swapping (rotating) the edge CCW
*
...
...
@@ -1708,13 +1712,15 @@ private:
* at the node that is given as input.
*
* \see
* s
wapEdgesAwayFromBoundaryNode
* S
wapEdgesAwayFromBoundaryNode
*/
template
<
class
TraitsType
,
class
DartType
,
class
ListType
>
void
TriangulationHelper
::
swapEdgesAwayFromInteriorNode
(
DartType
&
dart
,
ListType
&
swapped_edges
)
{
template
<
class
TRAITS_TYPE
,
class
DART_TYPE
,
class
LIST_TYPE
>
void
TRIANGULATION_HELPER
::
SwapEdgesAwayFromInteriorNode
(
DART_TYPE
&
aDart
,
LIST_TYPE
&
aSwappedEdges
)
{
// Same iteration as in fixEdgesAtCorner, but not boundary
D
artType
dnext
=
d
art
;
D
ART_TYPE
dnext
=
aD
art
;
// Allow degeneracy, otherwise we might end up with degree=4.
// For example, the reverse operation of inserting a point on an
...
...
@@ -1725,52 +1731,55 @@ private:
// infinite loop with degree > 3.
bool
allowDegeneracy
=
true
;
int
degree
=
getDegreeOfNode
(
dart
);
DartType
d_iter
;
while
(
degree
>
3
)
{
int
degree
=
getDegreeOfNode
(
aDart
);
DART_TYPE
d_iter
;
while
(
degree
>
3
)
{
d_iter
=
dnext
;
dnext
.
alpha1
().
a
lpha2
();
dnext
.
Alpha1
().
A
lpha2
();
if
(
swappableEdge
<
TraitsType
>
(
d_iter
,
allowDegeneracy
))
{
triangulation
.
swapEdge
(
d_iter
);
// swap the edge away
if
(
SwappableEdge
<
TRAITS_TYPE
>
(
d_iter
,
allowDegeneracy
)
)
{
m_triangulation
.
swapEdge
(
d_iter
);
// swap the edge away
// Collect swapped edges in the list
// "Hide" the dart on the other side of the edge to avoid it being changed for
// other swaps
DartType
swapped_edge
=
d_iter
;
// it was delivered back
swapped_edge
.
alpha2
().
a
lpha0
();
// CCW (if not at boundary)
swapped_edges
.
push_back
(
swapped_edge
);
DART_TYPE
swapped_edge
=
d_iter
;
// it was delivered back
swapped_edge
.
Alpha2
().
A
lpha0
();
// CCW (if not at boundary)
aSwappedEdges
.
push_back
(
swapped_edge
);
degree
--
;
}
}
// Output, incident to the node
dart
=
dnext
;
}
// Output, incident to the node
aDart
=
dnext
;
}
//------------------------------------------------------------------------------------------------
/** Swaps edges away from the (boundary) node associated with
/** Swaps edges away from the (boundary) node associated with
* \e dart in such a way that when removing the edges that remain incident
* with the node, the boundary of the triangulation will be convex.
* This function is used as a first step in r
emoveBoundaryNode
* This function is used as a first step in R
emoveBoundaryNode
*
* \retval dart
* A CCW dart incident with the node
*
* \require
* - \ref hed::TTLtraits::swapEdge "TraitsType::swapEdge" (DartType
& \e dart)\n
* - \ref hed::TTLtraits::swapEdge "TRAITS_TYPE::swapEdge" (DART_TYPE
& \e dart)\n
* \b Note: Must be implemented such that \e dart is delivered back in a position as
* seen if it was glued to the edge when swapping (rotating) the edge CCW
*
* \par Assumes:
* - The node associated with \e dart is at the boundary of the
triangulation.
* - The node associated with \e dart is at the boundary of the m_
triangulation.
*
* \see
* s
wapEdgesAwayFromInteriorNode
* S
wapEdgesAwayFromInteriorNode
*/
template
<
class
TraitsType
,
class
DartType
,
class
ListType
>
void
TriangulationHelper
::
swapEdgesAwayFromBoundaryNode
(
DartType
&
dart
,
ListType
&
swapped_edges
)
{
template
<
class
TRAITS_TYPE
,
class
DART_TYPE
,
class
LIST_TYPE
>
void
TRIANGULATION_HELPER
::
SwapEdgesAwayFromBoundaryNode
(
DART_TYPE
&
aDart
,
LIST_TYPE
&
aSwappedEdges
)
{
// All darts that are swappable.
// To treat collinear nodes at an existing boundary, we must allow degeneracy
// when swapping to the boundary.
...
...
@@ -1783,94 +1792,104 @@ private:
//int degree = getDegreeOfNode(dart);
passes
:
passes
:
// Swap swappable edges that radiate from the node away
DartType
d_iter
=
d
art
;
// ???? can simply use dart
d_iter
.
alpha1
().
a
lpha2
();
// first not at boundary
DartType
d_next
=
d_iter
;
DART_TYPE
d_iter
=
aD
art
;
// ???? can simply use dart
d_iter
.
Alpha1
().
A
lpha2
();
// first not at boundary
DART_TYPE
d_next
=
d_iter
;
bool
bend
=
false
;
bool
swapped_next_to_boundary
=
false
;
bool
swapped_in_pass
=
false
;
bool
allowDegeneracy
;
// = true;
DartType
tmp1
,
tmp2
;
DART_TYPE
tmp1
,
tmp2
;
while
(
!
bend
)
{
while
(
!
bend
)
{
d_next
.
Alpha1
().
Alpha2
();
d_next
.
alpha1
().
alpha2
();
if
(
isBoundaryEdge
(
d_next
))
if
(
IsBoundaryEdge
(
d_next
)
)
bend
=
true
;
// then it is CW since alpha2
// To allow removing among collinear nodes at the boundary,
// degenerate triangles must be allowed
// (they will be removed when used in connection with removeBoundaryNode)
tmp1
=
d_iter
;
tmp1
.
alpha1
();
tmp2
=
d_iter
;
tmp2
.
alpha2
().
alpha1
();
// don't bother with boundary (checked later)
// (they will be removed when used in connection with RemoveBoundaryNode)
tmp1
=
d_iter
;
tmp1
.
Alpha1
();
tmp2
=
d_iter
;
tmp2
.
Alpha2
().
Alpha1
();
// don't bother with boundary (checked later)
if
(
isBoundaryEdge
(
tmp1
)
&&
isBoundaryEdge
(
tmp2
)
)
if
(
IsBoundaryEdge
(
tmp1
)
&&
IsBoundaryEdge
(
tmp2
)
)
allowDegeneracy
=
true
;
else
allowDegeneracy
=
false
;
if
(
swappableEdge
<
TraitsType
>
(
d_iter
,
allowDegeneracy
))
{
triangulation
.
swapEdge
(
d_iter
);
if
(
SwappableEdge
<
TRAITS_TYPE
>
(
d_iter
,
allowDegeneracy
)
)
{
m_triangulation
.
swapEdge
(
d_iter
);
// Collect swapped edges in the list
// "Hide" the dart on the other side of the edge to avoid it being changed for
// other swapps
DartType
swapped_edge
=
d_iter
;
// it was delivered back
swapped_edge
.
alpha2
().
a
lpha0
();
// CCW
swapped_edges
.
push_back
(
swapped_edge
);
DART_TYPE
swapped_edge
=
d_iter
;
// it was delivered back
swapped_edge
.
Alpha2
().
A
lpha0
();
// CCW
aSwappedEdges
.
push_back
(
swapped_edge
);
//degree--; // if degree is 2, or bend=true, we are done
swapped_in_pass
=
true
;
if
(
bend
)
if
(
bend
)
swapped_next_to_boundary
=
true
;
}
if
(
!
bend
)
if
(
!
bend
)
d_iter
=
d_next
;
}
// Deliver a dart as output in the same position as the incoming dart
if
(
swapped_next_to_boundary
)
{
if
(
swapped_next_to_boundary
)
{
// Assume that "swapping is CCW and dart is preserved in the same position
d_iter
.
alpha1
().
alpha0
().
a
lpha1
();
// CW and see below
d_iter
.
Alpha1
().
Alpha0
().
A
lpha1
();
// CW and see below
}
else
{
d_iter
.
alpha1
();
// CW and see below
else
{
d_iter
.
Alpha1
();
// CW and see below
}
positionAtNextBoundaryEdge
(
d_iter
);
// CCW
PositionAtNextBoundaryEdge
(
d_iter
);
// CCW
d
art
=
d_iter
;
// for next pass or output
aD
art
=
d_iter
;
// for next pass or output
// If a dart was swapped in this iteration we must run it more
if
(
swapped_in_pass
)
if
(
swapped_in_pass
)
goto
passes
;
}
}
//------------------------------------------------------------------------------------------------
/** Swap the the edge associated with iterator \e it and update affected darts
/** Swap the the edge associated with iterator \e it and update affected darts
* in \e elist accordingly.
* The darts affected by the swap are those in the same quadrilateral.
* Thus, if one want to preserve one or more of these darts on should
* keep them in \e elist.
*/
template
<
class
TraitsType
,
class
DartType
,
class
DartListType
>
void
TriangulationHelper
::
swapEdgeInList
(
const
typename
DartListType
::
iterator
&
it
,
DartListType
&
elist
)
{
typename
DartListType
::
iterator
it1
,
it2
,
it3
,
it4
;
DartType
dart
(
*
it
);
template
<
class
TRAITS_TYPE
,
class
DART_TYPE
,
class
DART_LIST_TYPE
>
void
TRIANGULATION_HELPER
::
SwapEdgeInList
(
const
typename
DART_LIST_TYPE
::
iterator
&
aIt
,
DART_LIST_TYPE
&
aElist
)
{
//typename TraitsType::DartType d1 = dart; d1.alpha2().alpha1();
//typename TraitsType::DartType d2 = d1; d2.alpha0().alpha1();
//typename TraitsType::DartType d3 = dart; d3.alpha0().alpha1();
//typename TraitsType::DartType d4 = d3; d4.alpha0().alpha1();
DartType
d1
=
dart
;
d1
.
alpha2
().
alpha1
();
DartType
d2
=
d1
;
d2
.
alpha0
().
alpha1
();
DartType
d3
=
dart
;
d3
.
alpha0
().
alpha1
();
DartType
d4
=
d3
;
d4
.
alpha0
().
alpha1
();
typename
DART_LIST_TYPE
::
iterator
it1
,
it2
,
it3
,
it4
;
DART_TYPE
dart
(
*
aIt
);
//typename TRAITS_TYPE::DART_TYPE d1 = dart; d1.Alpha2().Alpha1();
//typename TRAITS_TYPE::DART_TYPE d2 = d1; d2.Alpha0().Alpha1();
//typename TRAITS_TYPE::DART_TYPE d3 = dart; d3.Alpha0().Alpha1();
//typename TRAITS_TYPE::DART_TYPE d4 = d3; d4.Alpha0().Alpha1();
DART_TYPE
d1
=
dart
;
d1
.
Alpha2
().
Alpha1
();
DART_TYPE
d2
=
d1
;
d2
.
Alpha0
().
Alpha1
();
DART_TYPE
d3
=
dart
;
d3
.
Alpha0
().
Alpha1
();
DART_TYPE
d4
=
d3
;
d4
.
Alpha0
().
Alpha1
();
// Find pinters to the darts that may change.
// ??? Note, this is not very efficient since we must use find, which is O(N),
...
...
@@ -1881,37 +1900,49 @@ passes:
// - sould we use another container type or,
// - erase them and reinsert?
// - or use two lists?
it1
=
find
(
elist
.
begin
(),
elist
.
end
(),
d1
);
it2
=
find
(
elist
.
begin
(),
elist
.
end
(),
d2
);
it3
=
find
(
elist
.
begin
(),
elist
.
end
(),
d3
);
it4
=
find
(
elist
.
begin
(),
elist
.
end
(),
d4
);
it1
=
find
(
aElist
.
begin
(),
aElist
.
end
(),
d1
);
it2
=
find
(
aElist
.
begin
(),
aElist
.
end
(),
d2
);
it3
=
find
(
aElist
.
begin
(),
aElist
.
end
(),
d3
);
it4
=
find
(
aElist
.
begin
(),
aElist
.
end
(),
d4
);
triangulation
.
swapEdge
(
dart
);
m_triangulation
.
swapEdge
(
dart
);
// Update the current dart which may have changed
*
i
t
=
dart
;
*
aI
t
=
dart
;
// Update darts that may have changed again (if they were present)
// Note that dart is delivered back after swapping
if
(
it1
!=
elist
.
end
())
{
d1
=
dart
;
d1
.
alpha1
().
alpha0
();
if
(
it1
!=
aElist
.
end
()
)
{
d1
=
dart
;
d1
.
Alpha1
().
Alpha0
();
*
it1
=
d1
;
}
if
(
it2
!=
elist
.
end
())
{
d2
=
dart
;
d2
.
alpha2
().
alpha1
();
if
(
it2
!=
aElist
.
end
()
)
{
d2
=
dart
;
d2
.
Alpha2
().
Alpha1
();
*
it2
=
d2
;
}
if
(
it3
!=
elist
.
end
())
{
d3
=
dart
;
d3
.
alpha2
().
alpha1
().
alpha0
().
alpha1
();
if
(
it3
!=
aElist
.
end
()
)
{
d3
=
dart
;
d3
.
Alpha2
().
Alpha1
().
Alpha0
().
Alpha1
();
*
it3
=
d3
;
}
if
(
it4
!=
elist
.
end
())
{
d4
=
dart
;
d4
.
alpha0
().
alpha1
();
if
(
it4
!=
aElist
.
end
()
)
{
d4
=
dart
;
d4
.
Alpha0
().
Alpha1
();
*
it4
=
d4
;
}
}
}
//@} // End of Utilities for Delaunay Triangulation Group
//@} // End of Utilities for Delaunay Triangulation Group
};
// End of ttl namespace scope (but other files may also contain functions for ttl)
}
// End of ttl namespace scope (but other files may also contain functions for ttl)
#endif // _TTL_H_
include/ttl/ttl_util.h
View file @
6fa2f060
...
...
@@ -3,11 +3,11 @@
* Applied Mathematics, Norway.
*
* Contact information: E-mail: tor.dokken@sintef.no
* SINTEF ICT, De
partment of Applied Mathematics,
* SINTEF ICT, De
aPArtment of Applied Mathematics,
* P.O. Box 124 Blindern,
* 0314 Oslo, Norway.
*
* This file is
pa
rt of TTL.
* This file is
aPA
rt of TTL.
*
* TTL is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
...
...
@@ -16,7 +16,7 @@
*
* TTL is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE. See the
* MERCHANTABILITY or FITNESS FOR A
aPARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public
...
...
@@ -40,28 +40,22 @@
#ifndef _TTL_UTIL_H_
#define _TTL_UTIL_H_
#include <vector>
#include <algorithm>
#ifdef _MSC_VER
# if _MSC_VER < 1300
# include <minmax.h>
# endif
#endif
//using namespace std;
/** \brief Utilities
*
* This name s
pa
ce contains utility functions for TTL.\n
* This name s
aPA
ce contains utility functions for TTL.\n
*
* Point and vector algebra such as scalar product and cross product
* between vectors are implemented here.
* These functions are required by functions in the \ref ttl names
pa
ce,
* These functions are required by functions in the \ref ttl names
aPA
ce,
* where they are assumed to be present in the \ref hed::TTLtraits "TTLtraits" class.
* Thus, the user can call these functions from the traits class.
* For efficiency reasons, the user may consider implementing these
...
...
@@ -77,51 +71,41 @@
* ttl and \ref api
*
* \author
* Øyvind Hjelle, oyvindhj@ifi.uio.no
*
�
yvind Hjelle, oyvindhj@ifi.uio.no
*/
namespace
ttl_util
{
//------------------------------------------------------------------------------------------------
// ------------------------------ Computational Geometry Group ----------------------------------
//------------------------------------------------------------------------------------------------
/** @name Computational geometry */
//@{
//------------------------------------------------------------------------------------------------
/** Scalar product between two 2D vectors.
namespace
ttl_util
{
/** @name Computational geometry */
//@{
/** Scalar product between two 2D vectors.
*
* \pa
r Returns:
* \aPA
r Returns:
* \code
* dx1*dx2 + dy1*dy
2
* aDX1*aDX2 + aDY1*aDY
2
* \endcode
*/
template
<
class
real_type
>
real_type
scalarProduct2d
(
real_type
dx1
,
real_type
dy1
,
real_type
dx2
,
real_type
dy2
)
{
return
dx1
*
dx2
+
dy1
*
dy2
;
}
template
<
class
REAL_TYPE
>
REAL_TYPE
ScalarProduct2D
(
REAL_TYPE
aDX1
,
REAL_TYPE
aDY1
,
REAL_TYPE
aDX2
,
REAL_TYPE
aDY2
)
{
return
aDX1
*
aDX2
+
aDY1
*
aDY2
;
}
//------------------------------------------------------------------------------------------------
/** Cross product between two 2D vectors. (The z-component of the actual cross product.)
/** Cross product between two 2D vectors. (The z-component of the actual cross product.)
*
* \pa
r Returns:
* \aPA
r Returns:
* \code
* dx1*dy2 - dy1*dx
2
* aDX1*aDY2 - aDY1*aDX
2
* \endcode
*/
template
<
class
real_type
>
real_type
crossProduct2d
(
real_type
dx1
,
real_type
dy1
,
real_type
dx2
,
real_type
dy2
)
{
return
dx1
*
dy2
-
dy1
*
dx2
;
}
//------------------------------------------------------------------------------------------------
/** Returns a positive value if the 2D nodes/points \e pa, \e pb, and
* \e pc occur in counterclockwise order; a negative value if they occur
template
<
class
REAL_TYPE
>
REAL_TYPE
CrossProduct2D
(
REAL_TYPE
aDX1
,
REAL_TYPE
aDY1
,
REAL_TYPE
aDX2
,
REAL_TYPE
aDY2
)
{
return
aDX1
*
aDY2
-
aDY1
*
aDX2
;
}
/** Returns a positive value if the 2D nodes/points \e aPA, \e aPB, and
* \e aPC occur in counterclockwise order; a negative value if they occur
* in clockwise order; and zero if they are collinear.
*
* \note
...
...
@@ -129,15 +113,17 @@ namespace ttl_util {
* exact arithmetic schemes by Jonathan Richard Shewchuk. See
* http://www-2.cs.cmu.edu/~quake/robust.html
*/
template
<
class
real_type
>
real_type
orient2dfast
(
real_type
pa
[
2
],
real_type
pb
[
2
],
real_type
pc
[
2
])
{
real_type
acx
=
pa
[
0
]
-
pc
[
0
];
real_type
bcx
=
pb
[
0
]
-
pc
[
0
];
real_type
acy
=
pa
[
1
]
-
pc
[
1
];
real_type
bcy
=
pb
[
1
]
-
pc
[
1
];
template
<
class
REAL_TYPE
>
REAL_TYPE
Orient2DFast
(
REAL_TYPE
aPA
[
2
],
REAL_TYPE
aPB
[
2
],
REAL_TYPE
aPC
[
2
]
)
{
REAL_TYPE
acx
=
aPA
[
0
]
-
aPC
[
0
];
REAL_TYPE
bcx
=
aPB
[
0
]
-
aPC
[
0
];
REAL_TYPE
acy
=
aPA
[
1
]
-
aPC
[
1
];
REAL_TYPE
bcy
=
aPB
[
1
]
-
aPC
[
1
];
return
acx
*
bcy
-
acy
*
bcx
;
}
}
}
;
// End of ttl_util namespace scope
}
// namespace ttl_util
#endif // _TTL_UTIL_H_
pcbnew/ratsnest_data.cpp
View file @
6fa2f060
...
...
@@ -68,7 +68,7 @@ bool sortDistance( const RN_NODE_PTR& aOrigin, const RN_NODE_PTR& aNode1,
bool
sortWeight
(
const
RN_EDGE_PTR
&
aEdge1
,
const
RN_EDGE_PTR
&
aEdge2
)
{
return
aEdge1
->
getWeight
()
<
aEdge2
->
g
etWeight
();
return
aEdge1
->
GetWeight
()
<
aEdge2
->
G
etWeight
();
}
...
...
@@ -92,7 +92,7 @@ bool operator!=( const RN_NODE_PTR& aFirst, const RN_NODE_PTR& aSecond )
bool
isEdgeConnectingNode
(
const
RN_EDGE_PTR
&
aEdge
,
const
RN_NODE_PTR
&
aNode
)
{
return
aEdge
->
getSourceNode
()
==
aNode
||
aEdge
->
g
etTargetNode
()
==
aNode
;
return
aEdge
->
GetSourceNode
()
==
aNode
||
aEdge
->
G
etTargetNode
()
==
aNode
;
}
...
...
@@ -125,8 +125,8 @@ std::vector<RN_EDGE_PTR>* kruskalMST( RN_LINKS::RN_EDGE_LIST& aEdges,
{
RN_EDGE_PTR
&
dt
=
*
aEdges
.
begin
();
int
srcTag
=
tags
[
dt
->
g
etSourceNode
()];
int
trgTag
=
tags
[
dt
->
g
etTargetNode
()];
int
srcTag
=
tags
[
dt
->
G
etSourceNode
()];
int
trgTag
=
tags
[
dt
->
G
etTargetNode
()];
// Check if by adding this edge we are going to join two different forests
if
(
srcTag
!=
trgTag
)
...
...
@@ -139,7 +139,7 @@ std::vector<RN_EDGE_PTR>* kruskalMST( RN_LINKS::RN_EDGE_LIST& aEdges,
// Move nodes that were marked with old tag to the list marked with the new tag
cycles
[
srcTag
].
splice
(
cycles
[
srcTag
].
end
(),
cycles
[
trgTag
]
);
if
(
dt
->
g
etWeight
()
==
0
)
// Skip already existing connections (weight == 0)
if
(
dt
->
G
etWeight
()
==
0
)
// Skip already existing connections (weight == 0)
{
mstExpectedSize
--
;
}
...
...
@@ -148,9 +148,9 @@ std::vector<RN_EDGE_PTR>* kruskalMST( RN_LINKS::RN_EDGE_LIST& aEdges,
// Do a copy of edge, but make it RN_EDGE_MST. In contrary to RN_EDGE,
// RN_EDGE_MST saves both source and target node and does not require any other
// edges to exist for getting source/target nodes
RN_EDGE_MST_PTR
newEdge
=
boost
::
make_shared
<
RN_EDGE_MST
>
(
dt
->
g
etSourceNode
(),
dt
->
g
etTargetNode
(),
dt
->
g
etWeight
()
);
RN_EDGE_MST_PTR
newEdge
=
boost
::
make_shared
<
RN_EDGE_MST
>
(
dt
->
G
etSourceNode
(),
dt
->
G
etTargetNode
(),
dt
->
G
etWeight
()
);
mst
->
push_back
(
newEdge
);
++
mstSize
;
}
...
...
@@ -169,8 +169,8 @@ std::vector<RN_EDGE_PTR>* kruskalMST( RN_LINKS::RN_EDGE_LIST& aEdges,
void
RN_NET
::
validateEdge
(
RN_EDGE_PTR
&
aEdge
)
{
RN_NODE_PTR
source
=
aEdge
->
g
etSourceNode
();
RN_NODE_PTR
target
=
aEdge
->
g
etTargetNode
();
RN_NODE_PTR
source
=
aEdge
->
G
etSourceNode
();
RN_NODE_PTR
target
=
aEdge
->
G
etTargetNode
();
bool
valid
=
true
;
// If any of nodes belonging to the edge has the flag set,
...
...
@@ -280,13 +280,13 @@ void RN_NET::compute()
std
::
partial_sort_copy
(
boardNodes
.
begin
(),
boardNodes
.
end
(),
nodes
.
begin
(),
nodes
.
end
()
);
TRIANGULATOR
triangulator
;
triangulator
.
c
reateDelaunay
(
nodes
.
begin
(),
nodes
.
end
()
);
boost
::
scoped_ptr
<
RN_LINKS
::
RN_EDGE_LIST
>
triangEdges
(
triangulator
.
g
etEdges
()
);
triangulator
.
C
reateDelaunay
(
nodes
.
begin
(),
nodes
.
end
()
);
boost
::
scoped_ptr
<
RN_LINKS
::
RN_EDGE_LIST
>
triangEdges
(
triangulator
.
G
etEdges
()
);
// Compute weight/distance for edges resulting from triangulation
RN_LINKS
::
RN_EDGE_LIST
::
iterator
eit
,
eitEnd
;
for
(
eit
=
(
*
triangEdges
).
begin
(),
eitEnd
=
(
*
triangEdges
).
end
();
eit
!=
eitEnd
;
++
eit
)
(
*
eit
)
->
setWeight
(
getDistance
(
(
*
eit
)
->
getSourceNode
(),
(
*
eit
)
->
g
etTargetNode
()
)
);
(
*
eit
)
->
SetWeight
(
getDistance
(
(
*
eit
)
->
GetSourceNode
(),
(
*
eit
)
->
G
etTargetNode
()
)
);
// Add the currently existing connections list to the results of triangulation
std
::
copy
(
boardEdges
.
begin
(),
boardEdges
.
end
(),
std
::
front_inserter
(
*
triangEdges
)
);
...
...
@@ -508,8 +508,8 @@ void RN_NET::RemoveItem( const TRACK* aTrack )
RN_EDGE_PTR
&
edge
=
m_tracks
.
at
(
aTrack
);
// Save nodes, so they can be cleared later
RN_NODE_PTR
aBegin
=
edge
->
g
etSourceNode
();
RN_NODE_PTR
aEnd
=
edge
->
g
etTargetNode
();
RN_NODE_PTR
aBegin
=
edge
->
G
etSourceNode
();
RN_NODE_PTR
aEnd
=
edge
->
G
etTargetNode
();
m_links
.
RemoveConnection
(
edge
);
// Remove nodes associated with the edge. It is done in a safe way, there is a check
...
...
@@ -696,8 +696,8 @@ std::list<RN_NODE_PTR> RN_NET::GetNodes( const BOARD_CONNECTED_ITEM* aItem ) con
const
TRACK
*
track
=
static_cast
<
const
TRACK
*>
(
aItem
);
RN_EDGE_PTR
edge
=
m_tracks
.
at
(
track
);
nodes
.
push_back
(
edge
->
g
etSourceNode
()
);
nodes
.
push_back
(
edge
->
g
etTargetNode
()
);
nodes
.
push_back
(
edge
->
G
etSourceNode
()
);
nodes
.
push_back
(
edge
->
G
etTargetNode
()
);
}
break
;
...
...
pcbnew/ratsnest_data.h
View file @
6fa2f060
...
...
@@ -50,13 +50,13 @@ class ZONE_CONTAINER;
class
CPolyPt
;
// Preserve KiCad coding style policy
typedef
hed
::
N
ode
RN_NODE
;
typedef
hed
::
N
odePtr
RN_NODE_PTR
;
typedef
hed
::
E
dge
RN_EDGE
;
typedef
hed
::
E
dgePtr
RN_EDGE_PTR
;
typedef
hed
::
E
dgeMST
RN_EDGE_MST
;
typedef
boost
::
shared_ptr
<
hed
::
EdgeMST
>
RN_EDGE_MST_PT
R
;
typedef
hed
::
Triangulation
TRIANGULATO
R
;
typedef
hed
::
N
ODE
RN_NODE
;
typedef
hed
::
N
ODE_PTR
RN_NODE_PTR
;
typedef
hed
::
E
DGE
RN_EDGE
;
typedef
hed
::
E
DGE_PTR
RN_EDGE_PTR
;
typedef
hed
::
E
DGE_MST
RN_EDGE_MST
;
typedef
hed
::
TRIANGULATION
TRIANGULATO
R
;
typedef
boost
::
shared_ptr
<
hed
::
EDGE_MST
>
RN_EDGE_MST_PT
R
;
bool
operator
==
(
const
RN_NODE_PTR
&
aFirst
,
const
RN_NODE_PTR
&
aSecond
);
bool
operator
!=
(
const
RN_NODE_PTR
&
aFirst
,
const
RN_NODE_PTR
&
aSecond
);
...
...
pcbnew/ratsnest_viewitem.cpp
View file @
6fa2f060
...
...
@@ -97,8 +97,8 @@ void RATSNEST_VIEWITEM::ViewDraw( int aLayer, GAL* aGal ) const
BOOST_FOREACH
(
const
RN_EDGE_PTR
&
edge
,
*
edges
)
{
const
RN_NODE_PTR
&
sourceNode
=
edge
->
g
etSourceNode
();
const
RN_NODE_PTR
&
targetNode
=
edge
->
g
etTargetNode
();
const
RN_NODE_PTR
&
sourceNode
=
edge
->
G
etSourceNode
();
const
RN_NODE_PTR
&
targetNode
=
edge
->
G
etTargetNode
();
VECTOR2D
source
(
sourceNode
->
GetX
(),
sourceNode
->
GetY
()
);
VECTOR2D
target
(
targetNode
->
GetX
(),
targetNode
->
GetY
()
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a 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