ear_clipping_patched.cpp
Go to the documentation of this file.
1 // -*- mode: c++ -*-
2 /*********************************************************************
3  * Software License Agreement (BSD License)
4  *
5  * Copyright (c) 2015, JSK Lab
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * * Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  * * Redistributions in binary form must reproduce the above
15  * copyright notice, this list of conditions and the following
16  * disclaimer in the documentation and/o2r other materials provided
17  * with the distribution.
18  * * Neither the name of the JSK Lab nor the names of its
19  * contributors may be used to endorse or promote products derived
20  * from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33  * POSSIBILITY OF SUCH DAMAGE.
34  *********************************************************************/
35 
37 #include <pcl/surface/ear_clipping.h>
38 #include <pcl/conversions.h>
39 #include <pcl/pcl_config.h>
40 
42 bool
44 {
45  points_.reset (new pcl::PointCloud<pcl::PointXYZ>);
46 
47  if (!MeshProcessing::initCompute ())
48  return (false);
49  fromPCLPointCloud2 (input_mesh_->cloud, *points_);
50 
51  return (true);
52 }
53 
55 void
57 {
58  output.polygons.clear ();
59  output.cloud = input_mesh_->cloud;
60  for (int i = 0; i < static_cast<int> (input_mesh_->polygons.size ()); ++i)
61  triangulate (input_mesh_->polygons[i], output);
62 }
63 
65 void
66 pcl::EarClippingPatched::triangulate (const Vertices& vertices, PolygonMesh& output)
67 {
68  const size_t n_vertices = vertices.vertices.size ();
69 
70  if (n_vertices < 3)
71  return;
72  else if (n_vertices == 3)
73  {
74  output.polygons.push_back( vertices );
75  return;
76  }
77 
78  std::vector<uint32_t> remaining_vertices = vertices.vertices;
79  size_t count = triangulateClockwiseVertices(remaining_vertices, output);
80 
81  // if the input vertices order is anti-clockwise, it always left a
82  // convex polygon and start infinite loops, which means will left more
83  // than 3 points.
84  if (remaining_vertices.size() < 3) return;
85 
86  output.polygons.erase(output.polygons.end(), output.polygons.end() + count);
87  remaining_vertices.resize(n_vertices);
88  for (size_t v = 0; v < n_vertices; v++)
89  remaining_vertices[v] = vertices.vertices[n_vertices - 1 - v];
90  triangulateClockwiseVertices(remaining_vertices, output);
91 }
92 
94 size_t
95 pcl::EarClippingPatched::triangulateClockwiseVertices (std::vector<uint32_t>& vertices, PolygonMesh& output)
96 {
97  // triangles count
98  size_t count = 0;
99 
100  // Avoid closed loops.
101  if (vertices.front () == vertices.back ())
102  vertices.erase (vertices.end () - 1);
103 
104  // null_iterations avoids infinite loops if the polygon is not simple.
105  for (int u = static_cast<int> (vertices.size ()) - 1, null_iterations = 0;
106  vertices.size () > 2 && null_iterations < static_cast<int >(vertices.size () * 2);
107  ++null_iterations, u = (u+1) % static_cast<int> (vertices.size ()))
108  {
109  int v = (u + 1) % static_cast<int> (vertices.size ());
110  int w = (u + 2) % static_cast<int> (vertices.size ());
111 
112  if (vertices.size() == 3 || isEar (u, v, w, vertices))
113  {
114  Vertices triangle;
115  triangle.vertices.resize (3);
116  triangle.vertices[0] = vertices[u];
117  triangle.vertices[1] = vertices[v];
118  triangle.vertices[2] = vertices[w];
119  output.polygons.push_back (triangle);
120  vertices.erase (vertices.begin () + v);
121  null_iterations = 0;
122  count++;
123  }
124  }
125  return count;
126 }
127 
129 bool
130 pcl::EarClippingPatched::isEar (int u, int v, int w, const std::vector<uint32_t>& vertices)
131 {
132  Eigen::Vector3f p_u, p_v, p_w;
133  p_u = points_->points[vertices[u]].getVector3fMap();
134  p_v = points_->points[vertices[v]].getVector3fMap();
135  p_w = points_->points[vertices[w]].getVector3fMap();
136 
137  const float eps = 1e-15f;
138  Eigen::Vector3f p_vu, p_vw;
139  p_vu = p_u - p_v;
140  p_vw = p_w - p_v;
141 
142  // 1: Avoid flat triangles and concave vertex
143  Eigen::Vector3f cross = p_vu.cross(p_vw);
144  if ((cross[2] > 0) || (cross.norm() < eps))
145  return (false);
146 
147  Eigen::Vector3f p;
148  // 2: Check if any other vertex is inside the triangle.
149  for (int k = 0; k < static_cast<int> (vertices.size ()); k++)
150  {
151  if ((k == u) || (k == v) || (k == w))
152  continue;
153  p = points_->points[vertices[k]].getVector3fMap();
154 
155  if (isInsideTriangle (p_u, p_v, p_w, p))
156  return (false);
157  }
158 
159  // 3: Check if the line segment uw lies completely inside the polygon.
160  // Here we suppose simple polygon (all edges do not intersect by themselves),
161  // so we only check if the middle point of line segment uw is inside the polygon.
162  Eigen::Vector3f p_i0, p_i1;
163  Eigen::Vector3f p_mid_uw = (p_u + p_w) / 2.0;
164  // HACK: avoid double-counting intersection at polygon vertices
165  Eigen::Vector3f p_inf = p_mid_uw + (p_v - p_mid_uw) * 1e15f + p_vu * 1e10f;
166  int intersect_count = 0;
167  for (int i = 0; i < static_cast<int>(vertices.size()); i++)
168  {
169  p_i0 = points_->points[vertices[i]].getVector3fMap();
170  p_i1 = points_->points[vertices[(i + 1) % static_cast<int>(vertices.size())]].getVector3fMap();
171  if (intersect(p_mid_uw, p_inf, p_i0, p_i1))
172  intersect_count++;
173  }
174  if (intersect_count % 2 == 0)
175  return (false);
176 
177  return (true);
178 }
179 
181 bool
183  const Eigen::Vector3f& v,
184  const Eigen::Vector3f& w,
185  const Eigen::Vector3f& p)
186 {
187  // see http://www.blackpawn.com/texts/pointinpoly/default.html
188  // Barycentric Coordinates
189  Eigen::Vector3f v0 = w - u;
190  Eigen::Vector3f v1 = v - u;
191  Eigen::Vector3f v2 = p - u;
192 
193  // Compute dot products
194  float dot00 = v0.dot(v0);
195  float dot01 = v0.dot(v1);
196  float dot02 = v0.dot(v2);
197  float dot11 = v1.dot(v1);
198  float dot12 = v1.dot(v2);
199 
200  // Compute barycentric coordinates
201  float invDenom = 1 / (dot00 * dot11 - dot01 * dot01);
202  float a = (dot11 * dot02 - dot01 * dot12) * invDenom;
203  float b = (dot00 * dot12 - dot01 * dot02) * invDenom;
204 
205  // Check if point is in triangle
206  return (a >= 0) && (b >= 0) && (a + b < 1);
207 }
208 
210 bool
211 pcl::EarClippingPatched::intersect (const Eigen::Vector3f& p0,
212  const Eigen::Vector3f& p1,
213  const Eigen::Vector3f& p2,
214  const Eigen::Vector3f& p3)
215 {
216  // See http://mathworld.wolfram.com/Line-LineIntersection.html
217  Eigen::Vector3f a = p1 - p0;
218  Eigen::Vector3f b = p3 - p2;
219  Eigen::Vector3f c = p2 - p0;
220 
221  // Parallel line segments do not intersect each other.
222  if (a.cross(b).norm() == 0)
223  return (false);
224 
225  // Compute intersection of two lines.
226  float s = (c.cross(b)).dot(a.cross(b)) / ((a.cross(b)).norm() * (a.cross(b)).norm());
227  float t = (c.cross(a)).dot(a.cross(b)) / ((a.cross(b)).norm() * (a.cross(b)).norm());
228 
229  // Check if the intersection is inside the line segments.
230  return ((s >= 0 && s <= 1) && (t >= 0 && t <= 1));
231 }
bool isInsideTriangle(const Eigen::Vector3f &u, const Eigen::Vector3f &v, const Eigen::Vector3f &w, const Eigen::Vector3f &p)
Check if p is inside the triangle (u,v,w).
t
f
TFSIMD_FORCE_INLINE Vector3 cross(const Vector3 &v) const
s
bool initCompute()
This method should get called before starting the actual computation.
doubleAcc dot(const VectorAcc &lhs, const VectorAcc &rhs)
size_t triangulateClockwiseVertices(std::vector< uint32_t > &vertices, PolygonMesh &output)
Triangulate one polygon, assume the vertices are clockwise.
pcl::PointCloud< pcl::PointXYZ >::Ptr points_
a Pointer to the point cloud data.
std::vector< Eigen::Vector3f, Eigen::aligned_allocator< Eigen::Vector3f > > Vertices
Definition: types.h:48
void triangulate(const Vertices &vertices, PolygonMesh &output)
Triangulate one polygon.
w
bool isEar(int u, int v, int w, const std::vector< uint32_t > &vertices)
Check if the triangle (u,v,w) is an ear.
p
void performProcessing(pcl::PolygonMesh &output)
The actual surface reconstruction method.
bool intersect(const Eigen::Vector3f &p0, const Eigen::Vector3f &p1, const Eigen::Vector3f &p2, const Eigen::Vector3f &p3)
Check if two line segments intersect by themselves.


jsk_recognition_utils
Author(s):
autogenerated on Mon May 3 2021 03:03:03