Skip to content
GitLab
Menu
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
OpenFlipper-Free
OpenFlipper-Free
Commits
1ca7b894
Commit
1ca7b894
authored
Oct 09, 2015
by
Jan Möbius
Browse files
Accidentally merged Triangle code
Revert "add ear clipping triangulation algorithm" This reverts commit
8686ee90
.
parent
31f2b44a
Changes
2
Hide whitespace changes
Inline
Side-by-side
ACG/Geometry/Triangulator.cc
deleted
100644 → 0
View file @
31f2b44a
/*===========================================================================*\
* *
* OpenFlipper *
* Copyright (c) 2001-2015, RWTH-Aachen University *
* Department of Computer Graphics and Multimedia *
* All rights reserved. *
* www.openflipper.org *
* *
*---------------------------------------------------------------------------*
* This file is part of OpenFlipper. *
*---------------------------------------------------------------------------*
* *
* Redistribution and use in source and binary forms, with or without *
* modification, are permitted provided that the following conditions *
* are met: *
* *
* 1. Redistributions of source code must retain the above copyright notice, *
* this list of conditions and the following disclaimer. *
* *
* 2. Redistributions in binary form must reproduce the above copyright *
* notice, this list of conditions and the following disclaimer in the *
* documentation and/or other materials provided with the distribution. *
* *
* 3. Neither the name of the copyright holder nor the names of its *
* contributors may be used to endorse or promote products derived from *
* this software without specific prior written permission. *
* *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
* *
\*===========================================================================*/
/*===========================================================================*\
* *
* $Revision: 21022 $ *
* $Author: moebius $ *
* $Date: 2015-07-17 08:23:03 +0200 (Fri, 17 Jul 2015) $ *
* *
\*===========================================================================*/
#include
"Triangulator.hh"
#include
<iostream>
namespace
ACG
{
Triangulator
::
Triangulator
(
const
std
::
vector
<
Vec3f
>&
_pos
)
:
polySize_
(
_pos
.
size
()),
numRemaningVertices_
(
_pos
.
size
()),
numTris_
(
0
),
numReflexVertices_
(
0
),
status_
(
-
1
),
convex_
(
false
)
{
if
(
polySize_
<
3
)
return
;
if
(
polySize_
==
3
)
{
numTris_
=
1
;
tris_
.
resize
(
3
);
tris_
[
0
]
=
0
;
tris_
[
1
]
=
1
;
tris_
[
2
]
=
2
;
numRemaningVertices_
=
0
;
convex_
=
true
;
status_
=
0
;
}
else
{
// project vertices onto the 2d plane of the polygon.
// the projection plane is chosen orthogonal to the polygon surface normal
// use Newell's Method to compute the surface normal
// http://www.opengl.org/wiki/Calculating_a_Surface_Normal
Vec3f
n
(
0.0
f
,
0.0
f
,
0.0
f
);
for
(
int
i
=
0
;
i
<
polySize_
;
++
i
)
{
int
next
=
(
i
+
1
)
%
polySize_
;
Vec3f
a
=
_pos
[
i
]
-
_pos
[
next
];
Vec3f
b
=
_pos
[
i
]
+
_pos
[
next
];
n
[
0
]
+=
a
[
1
]
*
b
[
2
];
n
[
1
]
+=
a
[
2
]
*
b
[
0
];
n
[
2
]
+=
a
[
0
]
*
b
[
1
];
}
// project to 2d
pos_
.
resize
(
polySize_
);
Vec3f
axis
[
3
]
=
{
Vec3f
(
1.0
f
,
0.0
f
,
0.0
f
),
Vec3f
(
0.0
f
,
1.0
f
,
0.0
f
),
n
};
// orthonormalize projection axes
axis
[
2
].
normalize
();
// make sure first axis is linearly independent from the normal
while
(
std
::
abs
(
axis
[
0
]
|
axis
[
2
])
>
0.95
f
||
(
axis
[
0
].
sqrnorm
()
<
0.001
f
))
{
for
(
int
i
=
0
;
i
<
3
;
++
i
)
axis
[
0
][
i
]
=
float
(
rand
())
/
float
(
RAND_MAX
)
*
2.0
f
-
1.0
f
;
axis
[
0
].
normalize
();
}
// make axis[0] orthogonal to normal
axis
[
0
]
=
axis
[
0
]
-
axis
[
2
]
*
(
axis
[
0
]
|
axis
[
2
]);
axis
[
0
].
normalize
();
axis
[
1
]
=
axis
[
2
]
%
axis
[
0
];
for
(
int
i
=
0
;
i
<
polySize_
;
++
i
)
{
// project onto polygon plane
pos_
[
i
][
0
]
=
axis
[
0
]
|
_pos
[
i
];
pos_
[
i
][
1
]
=
axis
[
1
]
|
_pos
[
i
];
}
// create triangle fans if there is at most one concave vertex
int
reflexVertexID
=
0
;
for
(
int
i
=
0
;
i
<
polySize_
;
++
i
)
{
// test vertex (i+1)
if
(
isReflexVertex
(
pos_
[
i
],
pos_
[(
i
+
1
)
%
polySize_
],
pos_
[(
i
+
2
)
%
polySize_
]))
{
++
numReflexVertices_
;
reflexVertexID
=
(
i
+
1
)
%
polySize_
;
}
}
convex_
=
!
numReflexVertices_
;
if
(
numReflexVertices_
<=
1
)
{
// create triangle fans
numTris_
=
polySize_
-
2
;
tris_
.
resize
(
numTris_
*
3
);
numRemaningVertices_
=
0
;
status_
=
0
;
for
(
int
i
=
0
;
i
<
numTris_
;
++
i
)
{
tris_
[
i
*
3
]
=
reflexVertexID
;
tris_
[
i
*
3
+
1
]
=
(
reflexVertexID
+
i
+
1
)
%
polySize_
;
tris_
[
i
*
3
+
2
]
=
(
reflexVertexID
+
i
+
2
)
%
polySize_
;
}
}
else
{
// use the ear clipping algorithm
earClippingN2
();
// earClippingN3();
// triangulateExternal();
}
}
}
Triangulator
::~
Triangulator
()
{
}
bool
Triangulator
::
isReflexVertex
(
const
Vec2f
&
v0
,
const
Vec2f
&
v1
,
const
Vec2f
&
v2
)
const
{
// compute the sign of the cross product of the edges sharing vertex v1
// <0 : inner angle greater than 180 deg (reflex)
// >0 : inner angle less than 180 deg (convex)
Vec2f
u
=
v2
-
v1
;
Vec2f
v
=
v0
-
v1
;
return
u
[
0
]
*
v
[
1
]
-
u
[
1
]
*
v
[
0
]
<
0.0
f
;
}
bool
Triangulator
::
isReflexVertex
(
int
i
)
const
{
int
p
=
(
i
+
polySize_
-
1
)
%
polySize_
;
int
n
=
(
i
+
1
)
%
polySize_
;
return
isReflexVertex
(
pos_
[
p
],
pos_
[
i
],
pos_
[
n
]);
}
float
Triangulator
::
triangleAreaSign
(
const
Vec2f
&
v0
,
const
Vec2f
&
v1
,
const
Vec2f
&
v2
)
const
{
// cross product
return
(
v0
[
0
]
-
v2
[
0
])
*
(
v1
[
1
]
-
v2
[
1
])
-
(
v1
[
0
]
-
v2
[
0
])
*
(
v0
[
1
]
-
v2
[
1
]);
}
float
Triangulator
::
distancePointToSegmentSq
(
const
Vec2f
&
v0
,
const
Vec2f
&
v1
,
const
Vec2f
&
pt
)
const
{
Vec2f
segment
=
v1
-
v0
;
Vec2f
vec
=
pt
-
v0
;
float
dp
=
vec
|
segment
;
if
(
dp
<
0.0
f
)
return
vec
.
sqrnorm
();
float
segSq
=
segment
.
sqrnorm
();
dp
/=
segSq
;
if
(
dp
<
1.0
f
)
return
vec
.
sqrnorm
()
-
dp
*
dp
*
segSq
;
vec
=
pt
-
v1
;
return
vec
.
sqrnorm
();
}
bool
Triangulator
::
pointInTriangle
(
const
Vec2f
&
v0
,
const
Vec2f
&
v1
,
const
Vec2f
&
v2
,
const
Vec2f
&
pt
)
const
{
// ACG implementation based on barycentric coordinates (slow)
// return Geometry::isInTriangle(pt, v0, v1, v2);
// fast implementation based on triangle areas
// http://www.gamedev.net/topic/295943-is-this-a-better-point-in-triangle-test-2d/
return
triangleAreaSign
(
pt
,
v0
,
v1
)
>=
0.0
f
&&
triangleAreaSign
(
pt
,
v1
,
v2
)
>=
0.0
f
&&
triangleAreaSign
(
pt
,
v2
,
v0
)
>=
0.0
f
;
// // more accurate algorithm:
// // http://totologic.blogspot.de/2014/01/accurate-point-in-triangle-test.html
// // note: didn't improve accuracy at all for problematic polygons
//
// static const float eps = 1e-4f;
// static const float eps2 = eps*eps;
//
//
// // point in aabb of triangle
// Vec2f aabbMin = v0;
//
// aabbMin.minimize(v1);
// aabbMin.minimize(v2);
//
// if (pt[0] + eps < aabbMin[0] || pt[1] + eps < aabbMin[1])
// return false;
//
// Vec2f aabbMax = v0;
// aabbMax.maximize(v1);
// aabbMax.maximize(v2);
//
// if (pt[0] > aabbMax[0] + eps || pt[1] > aabbMax[1] + eps)
// return false;
//
//
// if (triangleAreaSign(pt, v0, v1) >= 0.0f &&
// triangleAreaSign(pt, v1, v2) >= 0.0f &&
// triangleAreaSign(pt, v2, v0) >= 0.0f)
// return true;
//
//
// return (distancePointToSegmentSq(v0, v1, pt) <= eps2 ||
// distancePointToSegmentSq(v1, v2, pt) <= eps2 ||
// distancePointToSegmentSq(v2, v0, pt) <= eps2);
}
void
Triangulator
::
initVertexList
()
{
vertices_
.
resize
(
polySize_
);
reflexVertices_
.
clear
();
for
(
int
i
=
0
;
i
<
polySize_
;
++
i
)
{
int
p
=
(
i
+
polySize_
-
1
)
%
polySize_
;
int
n
=
(
i
+
1
)
%
polySize_
;
vertices_
[
i
]
=
RingVertex
(
i
,
isReflexVertex
(
pos_
[
p
],
pos_
[
i
],
pos_
[
n
]),
pos_
[
i
],
&
vertices_
[
p
],
&
vertices_
[
n
]);
if
(
vertices_
[
i
].
reflex
)
reflexVertices_
.
push_back
(
&
vertices_
[
i
]);
}
}
int
Triangulator
::
earClippingN3
()
{
// http://www.geometrictools.com/Documentation/TriangulationByEarClipping.pdf
// O(n^3)
numTris_
=
0
;
status_
=
0
;
initVertexList
();
tris_
.
resize
((
polySize_
-
2
)
*
3
);
int
numIterations
=
0
;
RingVertex
*
firstVertex
=
&
vertices_
[
0
];
while
(
numTris_
<
polySize_
-
2
)
{
// find an ear in the remaining polygon
bool
hasEars
=
false
;
RingVertex
*
curVertex
=
firstVertex
;
do
{
curVertex
->
reflex
=
isReflexVertex
(
curVertex
->
prev
->
pos
,
curVertex
->
pos
,
curVertex
->
next
->
pos
);
if
(
!
curVertex
->
reflex
)
{
// triangle containment test
bool
isEar
=
true
;
// check all remaining vertices r for containment
for
(
RingVertex
*
r
=
curVertex
->
next
->
next
;
r
!=
curVertex
->
prev
;
r
=
r
->
next
)
{
if
(
pointInTriangle
(
curVertex
->
prev
->
pos
,
curVertex
->
pos
,
curVertex
->
next
->
pos
,
r
->
pos
))
{
isEar
=
false
;
break
;
}
}
// found an ear
if
(
isEar
)
{
// triangulate ear
hasEars
=
true
;
tris_
[
numTris_
*
3
]
=
curVertex
->
prev
->
id
;
tris_
[
numTris_
*
3
+
1
]
=
curVertex
->
id
;
tris_
[
numTris_
*
3
+
2
]
=
curVertex
->
next
->
id
;
++
numTris_
;
// remove vertex from linked list
curVertex
->
prev
->
next
=
curVertex
->
next
;
curVertex
->
next
->
prev
=
curVertex
->
prev
;
break
;
}
}
curVertex
=
curVertex
->
next
;
++
numIterations
;
}
while
(
curVertex
!=
firstVertex
);
firstVertex
=
firstVertex
->
next
;
// create triangle fans and hope for good result if there are no more ears
if
(
!
hasEars
&&
(
numTris_
+
2
<
polySize_
))
{
for
(
RingVertex
*
iteratorVertex
=
firstVertex
->
next
;
iteratorVertex
!=
firstVertex
->
prev
;
iteratorVertex
=
iteratorVertex
->
next
)
{
tris_
[
numTris_
*
3
]
=
firstVertex
->
id
;
tris_
[
numTris_
*
3
+
1
]
=
iteratorVertex
->
id
;
tris_
[
numTris_
*
3
+
2
]
=
iteratorVertex
->
next
->
id
;
++
numTris_
;
}
assert
(
numTris_
==
polySize_
-
2
);
}
}
return
numTris_
;
}
int
Triangulator
::
earClippingN2
()
{
// http://www.geometrictools.com/Documentation/TriangulationByEarClipping.pdf
// O(n^2)
numTris_
=
0
;
status_
=
0
;
initVertexList
();
// triangulate
int
numTries
=
0
;
// # checked vertices per iteration that aren't ears
numRemaningVertices_
=
polySize_
;
// size of currently remaining polygon
int
numIterations
=
0
;
tris_
.
resize
((
polySize_
-
2
)
*
3
);
RingVertex
*
curVertex
=
&
vertices_
[
0
];
while
(
numRemaningVertices_
>
3
)
{
// check if the current vertex is an ear tip
bool
isEar
=
false
;
if
(
!
curVertex
->
reflex
)
{
// test current vertex for ear property
isEar
=
true
;
for
(
std
::
list
<
RingVertex
*>::
iterator
it
=
reflexVertices_
.
begin
();
isEar
&&
it
!=
reflexVertices_
.
end
();
++
it
)
{
// skip direct neighbors
if
(
*
it
==
curVertex
->
prev
||
*
it
==
curVertex
->
next
)
continue
;
// if any remaining vertex is inside the triangle, the current vertex is not an ear
if
(
pointInTriangle
(
curVertex
->
prev
->
pos
,
curVertex
->
pos
,
curVertex
->
next
->
pos
,
(
*
it
)
->
pos
))
isEar
=
false
;
}
// found an ear
if
(
isEar
)
{
addEar
(
curVertex
);
numTries
=
0
;
}
}
if
(
!
isEar
)
++
numTries
;
if
(
numTries
>
numRemaningVertices_
)
{
// something went wrong
// create a triangle anyway and hope the result is ok
addEar
(
curVertex
);
numTries
=
0
;
status_
=
1
;
}
curVertex
=
curVertex
->
next
;
++
numIterations
;
}
// add the last remaining triangle
if
(
numRemaningVertices_
==
3
)
{
tris_
[
numTris_
*
3
+
0
]
=
curVertex
->
prev
->
id
;
tris_
[
numTris_
*
3
+
1
]
=
curVertex
->
id
;
tris_
[
numTris_
*
3
+
2
]
=
curVertex
->
next
->
id
;
++
numTris_
;
}
return
numTris_
;
}
bool
Triangulator
::
updateReflexVertex
(
RingVertex
*
v
)
{
if
(
v
->
reflex
)
{
// check reflex property
v
->
reflex
=
isReflexVertex
(
v
->
prev
->
pos
,
v
->
pos
,
v
->
next
->
pos
);
// update list of reflex vertices
if
(
!
v
->
reflex
)
reflexVertices_
.
remove
(
v
);
}
return
v
->
reflex
;
}
void
Triangulator
::
addEar
(
RingVertex
*
_earTip
)
{
// add ear triangle
tris_
[
numTris_
*
3
+
0
]
=
_earTip
->
prev
->
id
;
tris_
[
numTris_
*
3
+
1
]
=
_earTip
->
id
;
tris_
[
numTris_
*
3
+
2
]
=
_earTip
->
next
->
id
;
// remove ear vertex from the linked list
_earTip
->
prev
->
next
=
_earTip
->
next
;
_earTip
->
next
->
prev
=
_earTip
->
prev
;
// update reflex vertices list by checking the neighboring vertices
updateReflexVertex
(
_earTip
->
prev
);
updateReflexVertex
(
_earTip
->
next
);
--
numRemaningVertices_
;
++
numTris_
;
}
}
\ No newline at end of file
ACG/Geometry/Triangulator.hh
deleted
100644 → 0
View file @
31f2b44a
/*===========================================================================*\
* *
* OpenFlipper *
* Copyright (c) 2001-2015, RWTH-Aachen University *
* Department of Computer Graphics and Multimedia *
* All rights reserved. *
* www.openflipper.org *
* *
*---------------------------------------------------------------------------*
* This file is part of OpenFlipper. *
*---------------------------------------------------------------------------*
* *
* Redistribution and use in source and binary forms, with or without *
* modification, are permitted provided that the following conditions *
* are met: *
* *
* 1. Redistributions of source code must retain the above copyright notice, *
* this list of conditions and the following disclaimer. *
* *
* 2. Redistributions in binary form must reproduce the above copyright *
* notice, this list of conditions and the following disclaimer in the *
* documentation and/or other materials provided with the distribution. *
* *
* 3. Neither the name of the copyright holder nor the names of its *
* contributors may be used to endorse or promote products derived from *
* this software without specific prior written permission. *
* *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
* *
\*===========================================================================*/
/*===========================================================================*\
* *
* $Revision: 21022 $ *
* $Author: moebius $ *
* $Date: 2015-07-17 08:23:03 +0200 (Fri, 17 Jul 2015) $ *
* *
\*===========================================================================*/
#ifndef ACG_TRIANGULATOR_HH
#define ACG_TRIANGULATOR_HH
#include
<ACG/Math/VectorT.hh>
#include
<ACG/Config/ACGDefines.hh>
#include
<vector>
#include
<list>
namespace
ACG
{
class
ACGDLLEXPORT
Triangulator
{
public:
Triangulator
(
const
std
::
vector
<
Vec3f
>&
_pos
);
virtual
~
Triangulator
();
int
numTriangles
()
const
{
return
numTris_
;
}
int
index
(
int
i
)
const
{
return
tris_
[
i
];
}
const
std
::
vector
<
int
>&
indices
()
const
{
return
tris_
;
}
bool
convex
()
const
{
return
convex_
;
}
int
numReflexVertices
()
const
{
return
numReflexVertices_
;
}
bool
isReflexVertex
(
int
i
)
const
;
bool
success
()
const
{
return
!
status_
;
}
private:
void
initVertexList
();
// ear clipping algorithm in O(n^2)
int
earClippingN2
();
// ear clipping algorithm in O(n^3)
int
earClippingN3
();
// disable assignment operator
Triangulator
&
operator
=
(
const
Triangulator
&
){}
float
triangleAreaSign
(
const
Vec2f
&
v0
,
const
Vec2f
&
v1
,
const
Vec2f
&
v2
)
const
;
float
distancePointToSegmentSq
(
const
Vec2f
&
v0
,
const
Vec2f
&
v1
,
const
Vec2f
&
pt
)
const
;
// test if vertex v1 is reflex in triangle v0-v1-v2 (inner angle at v1 is greater than 180 deg)
bool
isReflexVertex
(
const
Vec2f
&
v0
,
const
Vec2f
&
v1
,
const
Vec2f
&
v2
)
const
;
bool
pointInTriangle
(
const
Vec2f
&
v0
,
const
Vec2f
&
v1
,
const
Vec2f
&
v2
,
const
Vec2f
&
pt
)
const
;
struct
RingVertex
{
RingVertex
()
{}
RingVertex
(
int
i
,
bool
r
,
const
Vec2f
&
x
,
RingVertex
*
p
,
RingVertex
*
n
)
:
id
(
i
),
reflex
(
r
),
pos
(
x
),
prev
(
p
),
next
(
n
)
{
}
int
id
;