@@ -68,8 +68,13 @@ pcl::EarClipping::triangulate (const Vertices& vertices, PolygonMesh& output)
68
68
{
69
69
const int n_vertices = static_cast <const int > (vertices.vertices .size ());
70
70
71
- if (n_vertices <= 3 )
71
+ if (n_vertices < 3 )
72
72
return ;
73
+ else if (n_vertices == 3 )
74
+ {
75
+ output.polygons .push_back ( vertices );
76
+ return ;
77
+ }
73
78
74
79
std::vector<uint32_t > remaining_vertices (n_vertices);
75
80
if (area (vertices.vertices ) > 0 ) // clockwise?
@@ -109,51 +114,64 @@ pcl::EarClipping::triangulate (const Vertices& vertices, PolygonMesh& output)
109
114
float
110
115
pcl::EarClipping::area (const std::vector<uint32_t >& vertices)
111
116
{
112
- int n = static_cast <int > (vertices.size ());
113
- float area = 0 .0f ;
114
- Eigen::Vector2f prev_p, cur_p;
115
- for (int prev = n - 1 , cur = 0 ; cur < n; prev = cur++)
116
- {
117
- prev_p[0 ] = points_->points [vertices[prev]].x ;
118
- prev_p[1 ] = points_->points [vertices[prev]].y ;
119
- cur_p[0 ] = points_->points [vertices[cur]].x ;
120
- cur_p[1 ] = points_->points [vertices[cur]].y ;
117
+ // if the polygon is projected onto the xy-plane, the area of the polygon is determined
118
+ // by the trapeze formula of Gauss. However this fails, if the projection is one 'line'.
119
+ // Therefore the following implementation determines the area of the flat polygon in 3D-space
120
+ // using Stoke's law: http://code.activestate.com/recipes/578276-3d-polygon-area/
121
+
122
+ int n = static_cast <int > (vertices.size ());
123
+ float area = 0 .0f ;
124
+ Eigen::Vector3f prev_p, cur_p;
125
+ Eigen::Vector3f total (0 ,0 ,0 );
126
+ Eigen::Vector3f unit_normal;
127
+
128
+ if (n > 3 )
129
+ {
130
+ for (int prev = n - 1 , cur = 0 ; cur < n; prev = cur++)
131
+ {
132
+ prev_p = points_->points [vertices[prev]].getVector3fMap ();
133
+ cur_p = points_->points [vertices[cur]].getVector3fMap ();
121
134
122
- area += crossProduct (prev_p, cur_p);
123
- }
124
- return (area * 0 .5f );
135
+ total += prev_p.cross ( cur_p );
136
+ }
137
+
138
+ // unit_normal is unit normal vector of plane defined by the first three points
139
+ prev_p = points_->points [vertices[1 ]].getVector3fMap () - points_->points [vertices[0 ]].getVector3fMap ();
140
+ cur_p = points_->points [vertices[2 ]].getVector3fMap () - points_->points [vertices[0 ]].getVector3fMap ();
141
+ unit_normal = (prev_p.cross (cur_p)).normalized ();
142
+
143
+ area = total.dot ( unit_normal );
144
+ }
145
+
146
+ return area * 0 .5f ;
125
147
}
126
148
127
149
128
150
// ///////////////////////////////////////////////////////////////////////////////////////////
129
151
bool
130
152
pcl::EarClipping::isEar (int u, int v, int w, const std::vector<uint32_t >& vertices)
131
153
{
132
- Eigen::Vector2f p_u, p_v, p_w;
133
- p_u[0 ] = points_->points [vertices[u]].x ;
134
- p_u[1 ] = points_->points [vertices[u]].y ;
135
- p_v[0 ] = points_->points [vertices[v]].x ;
136
- p_v[1 ] = points_->points [vertices[v]].y ;
137
- p_w[0 ] = points_->points [vertices[w]].x ;
138
- p_w[1 ] = points_->points [vertices[w]].y ;
154
+ Eigen::Vector3f p_u, p_v, p_w;
155
+ p_u = points_->points [vertices[u]].getVector3fMap ();
156
+ p_v = points_->points [vertices[v]].getVector3fMap ();
157
+ p_w = points_->points [vertices[w]].getVector3fMap ();
139
158
140
- // Avoid flat triangles.
141
- // FIXME: triangulation would fail if all the triangles are flat in the X-Y axis
142
159
const float eps = 1e-15f ;
143
- Eigen::Vector2f p_uv, p_uw;
160
+ Eigen::Vector3f p_uv, p_uw;
144
161
p_uv = p_v - p_u;
145
162
p_uw = p_w - p_u;
146
- if (crossProduct (p_uv, p_uw) < eps)
163
+
164
+ // Avoid flat triangles.
165
+ if ((p_uv.cross (p_uw)).norm () < eps)
147
166
return (false );
148
167
149
- Eigen::Vector2f p;
168
+ Eigen::Vector3f p;
150
169
// Check if any other vertex is inside the triangle.
151
170
for (int k = 0 ; k < static_cast <int > (vertices.size ()); k++)
152
171
{
153
172
if ((k == u) || (k == v) || (k == w))
154
173
continue ;
155
- p[0 ] = points_->points [vertices[k]].x ;
156
- p[1 ] = points_->points [vertices[k]].y ;
174
+ p = points_->points [vertices[k]].getVector3fMap ();
157
175
158
176
if (isInsideTriangle (p_u, p_v, p_w, p))
159
177
return (false );
@@ -163,23 +181,30 @@ pcl::EarClipping::isEar (int u, int v, int w, const std::vector<uint32_t>& verti
163
181
164
182
// ///////////////////////////////////////////////////////////////////////////////////////////
165
183
bool
166
- pcl::EarClipping::isInsideTriangle (const Eigen::Vector2f & u,
167
- const Eigen::Vector2f & v,
168
- const Eigen::Vector2f & w,
169
- const Eigen::Vector2f & p)
184
+ pcl::EarClipping::isInsideTriangle (const Eigen::Vector3f & u,
185
+ const Eigen::Vector3f & v,
186
+ const Eigen::Vector3f & w,
187
+ const Eigen::Vector3f & p)
170
188
{
171
- // Check first side.
172
- if (crossProduct (w - v, p - v) < 0 )
173
- return (false );
174
-
175
- // Check second side.
176
- if (crossProduct (v - u, p - u) < 0 )
177
- return (false );
178
-
179
- // Check third side.
180
- if (crossProduct (u - w, p - w) < 0 )
181
- return (false );
182
-
183
- return (true );
189
+ // see http://www.blackpawn.com/texts/pointinpoly/default.html
190
+ // Barycentric Coordinates
191
+ Eigen::Vector3f v0 = w - u;
192
+ Eigen::Vector3f v1 = v - u;
193
+ Eigen::Vector3f v2 = p - u;
194
+
195
+ // Compute dot products
196
+ float dot00 = v0.dot (v0);
197
+ float dot01 = v0.dot (v1);
198
+ float dot02 = v0.dot (v2);
199
+ float dot11 = v1.dot (v1);
200
+ float dot12 = v1.dot (v2);
201
+
202
+ // Compute barycentric coordinates
203
+ float invDenom = 1 / (dot00 * dot11 - dot01 * dot01);
204
+ float a = (dot11 * dot02 - dot01 * dot12) * invDenom;
205
+ float b = (dot00 * dot12 - dot01 * dot02) * invDenom;
206
+
207
+ // Check if point is in triangle
208
+ return (a >= 0 ) && (b >= 0 ) && (a + b < 1 );
184
209
}
185
210
0 commit comments