Point Cloud Library (PCL)  1.6.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
sac_model_cone.hpp
Go to the documentation of this file.
1 /*
2  * Software License Agreement (BSD License)
3  *
4  * Point Cloud Library (PCL) - www.pointclouds.org
5  * Copyright (c) 2009-2012, Willow Garage, Inc.
6  *
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  *
13  * * Redistributions of source code must retain the above copyright
14  * notice, this list of conditions and the following disclaimer.
15  * * Redistributions in binary form must reproduce the above
16  * copyright notice, this list of conditions and the following
17  * disclaimer in the documentation and/or other materials provided
18  * with the distribution.
19  * * Neither the name of Willow Garage, Inc. nor the names of its
20  * contributors may be used to endorse or promote products derived
21  * from this software without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
33  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34  * POSSIBILITY OF SUCH DAMAGE.
35  *
36  */
37 
38 #ifndef PCL_SAMPLE_CONSENSUS_IMPL_SAC_MODEL_CONE_H_
39 #define PCL_SAMPLE_CONSENSUS_IMPL_SAC_MODEL_CONE_H_
40 
42 #include <pcl/common/concatenate.h>
43 #include <unsupported/Eigen/NonLinearOptimization>
44 
46 template <typename PointT, typename PointNT> bool
48 {
49  return (true);
50 }
51 
53 template <typename PointT, typename PointNT> bool
55  const std::vector<int> &samples, Eigen::VectorXf &model_coefficients)
56 {
57  // Need 3 samples
58  if (samples.size () != 3)
59  {
60  PCL_ERROR ("[pcl::SampleConsensusModelCone::computeModelCoefficients] Invalid set of samples given (%zu)!\n", samples.size ());
61  return (false);
62  }
63 
64  if (!normals_)
65  {
66  PCL_ERROR ("[pcl::SampleConsensusModelCone::computeModelCoefficients] No input dataset containing normals was given!\n");
67  return (false);
68  }
69 
70  Eigen::Vector4f p1 (input_->points[samples[0]].x, input_->points[samples[0]].y, input_->points[samples[0]].z, 0);
71  Eigen::Vector4f p2 (input_->points[samples[1]].x, input_->points[samples[1]].y, input_->points[samples[1]].z, 0);
72  Eigen::Vector4f p3 (input_->points[samples[2]].x, input_->points[samples[2]].y, input_->points[samples[2]].z, 0);
73 
74  Eigen::Vector4f n1 (normals_->points[samples[0]].normal[0], normals_->points[samples[0]].normal[1], normals_->points[samples[0]].normal[2], 0);
75  Eigen::Vector4f n2 (normals_->points[samples[1]].normal[0], normals_->points[samples[1]].normal[1], normals_->points[samples[1]].normal[2], 0);
76  Eigen::Vector4f n3 (normals_->points[samples[2]].normal[0], normals_->points[samples[2]].normal[1], normals_->points[samples[2]].normal[2], 0);
77 
78  //calculate apex (intersection of the three planes defined by points and belonging normals
79  Eigen::Vector4f ortho12 = n1.cross3(n2);
80  Eigen::Vector4f ortho23 = n2.cross3(n3);
81  Eigen::Vector4f ortho31 = n3.cross3(n1);
82 
83  float denominator = n1.dot(ortho23);
84 
85  float d1 = p1.dot (n1);
86  float d2 = p2.dot (n2);
87  float d3 = p3.dot (n3);
88 
89  Eigen::Vector4f apex = (d1 * ortho23 + d2 * ortho31 + d3 * ortho12) / denominator;
90 
91  //compute axis (normal of plane defined by: { apex+(p1-apex)/(||p1-apex||), apex+(p2-apex)/(||p2-apex||), apex+(p3-apex)/(||p3-apex||)}
92  Eigen::Vector4f ap1 = p1 - apex;
93  Eigen::Vector4f ap2 = p2 - apex;
94  Eigen::Vector4f ap3 = p3 - apex;
95 
96  Eigen::Vector4f np1 = apex + (ap1/ap1.norm ());
97  Eigen::Vector4f np2 = apex + (ap2/ap2.norm ());
98  Eigen::Vector4f np3 = apex + (ap3/ap3.norm ());
99 
100  Eigen::Vector4f np1np2 = np2 - np1;
101  Eigen::Vector4f np1np3 = np3 - np1;
102 
103  Eigen::Vector4f axis_dir = np1np2.cross3 (np1np3);
104  axis_dir.normalize ();
105 
106  // normalize the vector (apex->p) for opening angle calculation
107  ap1.normalize ();
108  ap2.normalize ();
109  ap3.normalize ();
110 
111  //compute opening angle
112  float opening_angle = ( acosf (ap1.dot (axis_dir)) + acosf (ap2.dot (axis_dir)) + acosf (ap3.dot (axis_dir)) ) / 3.0f;
113 
114  model_coefficients.resize (7);
115  // model_coefficients.template head<3> () = line_pt.template head<3> ();
116  model_coefficients[0] = apex[0];
117  model_coefficients[1] = apex[1];
118  model_coefficients[2] = apex[2];
119  // model_coefficients.template segment<3> (3) = line_dir.template head<3> ();
120  model_coefficients[3] = axis_dir[0];
121  model_coefficients[4] = axis_dir[1];
122  model_coefficients[5] = axis_dir[2];
123  // cone radius
124  model_coefficients[6] = opening_angle;
125 
126  if (model_coefficients[6] != -std::numeric_limits<double>::max() && model_coefficients[6] < min_angle_)
127  return (false);
128  if (model_coefficients[6] != std::numeric_limits<double>::max() && model_coefficients[6] > max_angle_)
129  return (false);
130 
131  return (true);
132 }
133 
135 template <typename PointT, typename PointNT> void
137  const Eigen::VectorXf &model_coefficients, std::vector<double> &distances)
138 {
139  // Check if the model is valid given the user constraints
140  if (!isModelValid (model_coefficients))
141  {
142  distances.clear ();
143  return;
144  }
145 
146  distances.resize (indices_->size ());
147 
148  Eigen::Vector4f apex (model_coefficients[0], model_coefficients[1], model_coefficients[2], 0);
149  Eigen::Vector4f axis_dir (model_coefficients[3], model_coefficients[4], model_coefficients[5], 0);
150  float opening_angle = model_coefficients[6];
151 
152  float apexdotdir = apex.dot (axis_dir);
153  float dirdotdir = 1.0f / axis_dir.dot (axis_dir);
154  // Iterate through the 3d points and calculate the distances from them to the cone
155  for (size_t i = 0; i < indices_->size (); ++i)
156  {
157  Eigen::Vector4f pt (input_->points[(*indices_)[i]].x, input_->points[(*indices_)[i]].y, input_->points[(*indices_)[i]].z, 0);
158  Eigen::Vector4f n (normals_->points[(*indices_)[i]].normal[0], normals_->points[(*indices_)[i]].normal[1], normals_->points[(*indices_)[i]].normal[2], 0);
159 
160  // Calculate the point's projection on the cone axis
161  float k = (pt.dot (axis_dir) - apexdotdir) * dirdotdir;
162  Eigen::Vector4f pt_proj = apex + k * axis_dir;
163  Eigen::Vector4f dir = pt - pt_proj;
164  dir.normalize ();
165 
166  // Calculate the actual radius of the cone at the level of the projected point
167  Eigen::Vector4f height = apex - pt_proj;
168  float actual_cone_radius = tanf (opening_angle) * height.norm ();
169  height.normalize ();
170 
171  // Calculate the cones perfect normals
172  Eigen::Vector4f cone_normal = sinf (opening_angle) * height + cosf (opening_angle) * dir;
173 
174  // Aproximate the distance from the point to the cone as the difference between
175  // dist(point,cone_axis) and actual cone radius
176  double d_euclid = fabs (pointToAxisDistance (pt, model_coefficients) - actual_cone_radius);
177 
178  // Calculate the angular distance between the point normal and the (dir=pt_proj->pt) vector
179  double d_normal = fabs (getAngle3D (n, cone_normal));
180  d_normal = (std::min) (d_normal, M_PI - d_normal);
181 
182  distances[i] = fabs (normal_distance_weight_ * d_normal + (1 - normal_distance_weight_) * d_euclid);
183  }
184 }
185 
187 template <typename PointT, typename PointNT> void
189  const Eigen::VectorXf &model_coefficients, const double threshold, std::vector<int> &inliers)
190 {
191  // Check if the model is valid given the user constraints
192  if (!isModelValid (model_coefficients))
193  {
194  inliers.clear ();
195  return;
196  }
197 
198  int nr_p = 0;
199  inliers.resize (indices_->size ());
200 
201  Eigen::Vector4f apex (model_coefficients[0], model_coefficients[1], model_coefficients[2], 0);
202  Eigen::Vector4f axis_dir (model_coefficients[3], model_coefficients[4], model_coefficients[5], 0);
203  float opening_angle = model_coefficients[6];
204 
205  float apexdotdir = apex.dot (axis_dir);
206  float dirdotdir = 1.0f / axis_dir.dot (axis_dir);
207  // Iterate through the 3d points and calculate the distances from them to the cone
208  for (size_t i = 0; i < indices_->size (); ++i)
209  {
210  Eigen::Vector4f pt (input_->points[(*indices_)[i]].x, input_->points[(*indices_)[i]].y, input_->points[(*indices_)[i]].z, 0);
211  Eigen::Vector4f n (normals_->points[(*indices_)[i]].normal[0], normals_->points[(*indices_)[i]].normal[1], normals_->points[(*indices_)[i]].normal[2], 0);
212 
213  // Calculate the point's projection on the cone axis
214  float k = (pt.dot (axis_dir) - apexdotdir) * dirdotdir;
215  Eigen::Vector4f pt_proj = apex + k * axis_dir;
216 
217  // Calculate the direction of the point from center
218  Eigen::Vector4f pp_pt_dir = pt - pt_proj;
219  pp_pt_dir.normalize ();
220 
221  // Calculate the actual radius of the cone at the level of the projected point
222  Eigen::Vector4f height = apex - pt_proj;
223  double actual_cone_radius = tan(opening_angle) * height.norm ();
224  height.normalize ();
225 
226  // Calculate the cones perfect normals
227  Eigen::Vector4f cone_normal = sinf (opening_angle) * height + cosf (opening_angle) * pp_pt_dir;
228 
229  // Aproximate the distance from the point to the cone as the difference between
230  // dist(point,cone_axis) and actual cone radius
231  double d_euclid = fabs (pointToAxisDistance (pt, model_coefficients) - actual_cone_radius);
232 
233  // Calculate the angular distance between the point normal and the (dir=pt_proj->pt) vector
234  double d_normal = fabs (getAngle3D (n, cone_normal));
235  d_normal = (std::min) (d_normal, M_PI - d_normal);
236 
237  if (fabs (normal_distance_weight_ * d_normal + (1 - normal_distance_weight_) * d_euclid) < threshold)
238  {
239  // Returns the indices of the points whose distances are smaller than the threshold
240  inliers[nr_p] = (*indices_)[i];
241  nr_p++;
242  }
243  }
244  inliers.resize (nr_p);
245 }
246 
248 template <typename PointT, typename PointNT> int
250  const Eigen::VectorXf &model_coefficients, const double threshold)
251 {
252 
253  // Check if the model is valid given the user constraints
254  if (!isModelValid (model_coefficients))
255  return (0);
256 
257  int nr_p = 0;
258 
259  Eigen::Vector4f apex (model_coefficients[0], model_coefficients[1], model_coefficients[2], 0);
260  Eigen::Vector4f axis_dir (model_coefficients[3], model_coefficients[4], model_coefficients[5], 0);
261  float opening_angle = model_coefficients[6];
262 
263  float apexdotdir = apex.dot (axis_dir);
264  float dirdotdir = 1.0f / axis_dir.dot (axis_dir);
265  // Iterate through the 3d points and calculate the distances from them to the cone
266  for (size_t i = 0; i < indices_->size (); ++i)
267  {
268  Eigen::Vector4f pt (input_->points[(*indices_)[i]].x, input_->points[(*indices_)[i]].y, input_->points[(*indices_)[i]].z, 0);
269  Eigen::Vector4f n (normals_->points[(*indices_)[i]].normal[0], normals_->points[(*indices_)[i]].normal[1], normals_->points[(*indices_)[i]].normal[2], 0);
270 
271  // Calculate the point's projection on the cone axis
272  float k = (pt.dot (axis_dir) - apexdotdir) * dirdotdir;
273  Eigen::Vector4f pt_proj = apex + k * axis_dir;
274 
275  // Calculate the direction of the point from center
276  Eigen::Vector4f pp_pt_dir = pt - pt_proj;
277  pp_pt_dir.normalize ();
278 
279  // Calculate the actual radius of the cone at the level of the projected point
280  Eigen::Vector4f height = apex - pt_proj;
281  double actual_cone_radius = tan(opening_angle) * height.norm ();
282  height.normalize ();
283 
284  // Calculate the cones perfect normals
285  Eigen::Vector4f cone_normal = sinf (opening_angle) * height + cosf (opening_angle) * pp_pt_dir;
286 
287  // Aproximate the distance from the point to the cone as the difference between
288  // dist(point,cone_axis) and actual cone radius
289  double d_euclid = fabs (pointToAxisDistance (pt, model_coefficients) - actual_cone_radius);
290 
291  // Calculate the angular distance between the point normal and the (dir=pt_proj->pt) vector
292  double d_normal = fabs (getAngle3D (n, cone_normal));
293  d_normal = (std::min) (d_normal, M_PI - d_normal);
294 
295  if (fabs (normal_distance_weight_ * d_normal + (1 - normal_distance_weight_) * d_euclid) < threshold)
296  nr_p++;
297  }
298  return (nr_p);
299 }
300 
302 template <typename PointT, typename PointNT> void
304  const std::vector<int> &inliers, const Eigen::VectorXf &model_coefficients, Eigen::VectorXf &optimized_coefficients)
305 {
306  optimized_coefficients = model_coefficients;
307 
308  // Needs a set of valid model coefficients
309  if (model_coefficients.size () != 7)
310  {
311  PCL_ERROR ("[pcl::SampleConsensusModelCone::optimizeModelCoefficients] Invalid number of model coefficients given (%zu)!\n", model_coefficients.size ());
312  return;
313  }
314 
315  if (inliers.empty ())
316  {
317  PCL_DEBUG ("[pcl::SampleConsensusModelCone:optimizeModelCoefficients] Inliers vector empty! Returning the same coefficients.\n");
318  return;
319  }
320 
321  tmp_inliers_ = &inliers;
322 
323  OptimizationFunctor functor (static_cast<int> (inliers.size ()), this);
324  Eigen::NumericalDiff<OptimizationFunctor > num_diff (functor);
325  Eigen::LevenbergMarquardt<Eigen::NumericalDiff<OptimizationFunctor>, float> lm (num_diff);
326  int info = lm.minimize (optimized_coefficients);
327 
328  // Compute the L2 norm of the residuals
329  PCL_DEBUG ("[pcl::SampleConsensusModelCone::optimizeModelCoefficients] LM solver finished with exit code %i, having a residual norm of %g. \nInitial solution: %g %g %g %g %g %g %g \nFinal solution: %g %g %g %g %g %g %g\n",
330  info, lm.fvec.norm (), model_coefficients[0], model_coefficients[1], model_coefficients[2], model_coefficients[3],
331  model_coefficients[4], model_coefficients[5], model_coefficients[6], optimized_coefficients[0], optimized_coefficients[1], optimized_coefficients[2], optimized_coefficients[3], optimized_coefficients[4], optimized_coefficients[5], optimized_coefficients[6]);
332 }
333 
335 template <typename PointT, typename PointNT> void
337  const std::vector<int> &inliers, const Eigen::VectorXf &model_coefficients, PointCloud &projected_points, bool copy_data_fields)
338 {
339  // Needs a valid set of model coefficients
340  if (model_coefficients.size () != 7)
341  {
342  PCL_ERROR ("[pcl::SampleConsensusModelCone::projectPoints] Invalid number of model coefficients given (%zu)!\n", model_coefficients.size ());
343  return;
344  }
345 
346  projected_points.header = input_->header;
347  projected_points.is_dense = input_->is_dense;
348 
349  Eigen::Vector4f apex (model_coefficients[0], model_coefficients[1], model_coefficients[2], 0);
350  Eigen::Vector4f axis_dir (model_coefficients[3], model_coefficients[4], model_coefficients[5], 0);
351  float opening_angle = model_coefficients[6];
352 
353  float apexdotdir = apex.dot (axis_dir);
354  float dirdotdir = 1.0f / axis_dir.dot (axis_dir);
355 
356  // Copy all the data fields from the input cloud to the projected one?
357  if (copy_data_fields)
358  {
359  // Allocate enough space and copy the basics
360  projected_points.points.resize (input_->points.size ());
361  projected_points.width = input_->width;
362  projected_points.height = input_->height;
363 
364  typedef typename pcl::traits::fieldList<PointT>::type FieldList;
365  // Iterate over each point
366  for (size_t i = 0; i < projected_points.points.size (); ++i)
367  // Iterate over each dimension
368  pcl::for_each_type <FieldList> (NdConcatenateFunctor <PointT, PointT> (input_->points[i], projected_points.points[i]));
369 
370  // Iterate through the 3d points and calculate the distances from them to the cone
371  for (size_t i = 0; i < inliers.size (); ++i)
372  {
373  Eigen::Vector4f pt (input_->points[inliers[i]].x,
374  input_->points[inliers[i]].y,
375  input_->points[inliers[i]].z,
376  1);
377 
378  float k = (pt.dot (axis_dir) - apexdotdir) * dirdotdir;
379 
380  pcl::Vector4fMap pp = projected_points.points[inliers[i]].getVector4fMap ();
381  pp = apex + k * axis_dir;
382 
383  Eigen::Vector4f dir = pt - pp;
384  dir.normalize ();
385 
386  // Calculate the actual radius of the cone at the level of the projected point
387  Eigen::Vector4f height = apex - pp;
388  float actual_cone_radius = tanf (opening_angle) * height.norm ();
389 
390  // Calculate the projection of the point onto the cone
391  pp += dir * actual_cone_radius;
392  }
393  }
394  else
395  {
396  // Allocate enough space and copy the basics
397  projected_points.points.resize (inliers.size ());
398  projected_points.width = static_cast<uint32_t> (inliers.size ());
399  projected_points.height = 1;
400 
401  typedef typename pcl::traits::fieldList<PointT>::type FieldList;
402  // Iterate over each point
403  for (size_t i = 0; i < inliers.size (); ++i)
404  // Iterate over each dimension
405  pcl::for_each_type <FieldList> (NdConcatenateFunctor <PointT, PointT> (input_->points[inliers[i]], projected_points.points[i]));
406 
407  // Iterate through the 3d points and calculate the distances from them to the cone
408  for (size_t i = 0; i < inliers.size (); ++i)
409  {
410  pcl::Vector4fMap pp = projected_points.points[i].getVector4fMap ();
411  pcl::Vector4fMapConst pt = input_->points[inliers[i]].getVector4fMap ();
412 
413  float k = (pt.dot (axis_dir) - apexdotdir) * dirdotdir;
414  // Calculate the projection of the point on the line
415  pp = apex + k * axis_dir;
416 
417  Eigen::Vector4f dir = pt - pp;
418  dir.normalize ();
419 
420  // Calculate the actual radius of the cone at the level of the projected point
421  Eigen::Vector4f height = apex - pp;
422  float actual_cone_radius = tanf (opening_angle) * height.norm ();
423 
424  // Calculate the projection of the point onto the cone
425  pp += dir * actual_cone_radius;
426  }
427  }
428 }
429 
431 template <typename PointT, typename PointNT> bool
433  const std::set<int> &indices, const Eigen::VectorXf &model_coefficients, const double threshold)
434 {
435  // Needs a valid model coefficients
436  if (model_coefficients.size () != 7)
437  {
438  PCL_ERROR ("[pcl::SampleConsensusModelCone::doSamplesVerifyModel] Invalid number of model coefficients given (%zu)!\n", model_coefficients.size ());
439  return (false);
440  }
441 
442  Eigen::Vector4f apex (model_coefficients[0], model_coefficients[1], model_coefficients[2], 0);
443  Eigen::Vector4f axis_dir (model_coefficients[3], model_coefficients[4], model_coefficients[5], 0);
444  float openning_angle = model_coefficients[6];
445 
446  float apexdotdir = apex.dot (axis_dir);
447  float dirdotdir = 1.0f / axis_dir.dot (axis_dir);
448 
449  // Iterate through the 3d points and calculate the distances from them to the cone
450  for (std::set<int>::const_iterator it = indices.begin (); it != indices.end (); ++it)
451  {
452  Eigen::Vector4f pt (input_->points[*it].x, input_->points[*it].y, input_->points[*it].z, 0);
453 
454  // Calculate the point's projection on the cone axis
455  float k = (pt.dot (axis_dir) - apexdotdir) * dirdotdir;
456  Eigen::Vector4f pt_proj = apex + k * axis_dir;
457  Eigen::Vector4f dir = pt - pt_proj;
458  dir.normalize ();
459 
460  // Calculate the actual radius of the cone at the level of the projected point
461  Eigen::Vector4f height = apex - pt_proj;
462  double actual_cone_radius = tan (openning_angle) * height.norm ();
463 
464  // Aproximate the distance from the point to the cone as the difference between
465  // dist(point,cone_axis) and actual cone radius
466  if (fabs (static_cast<double>(pointToAxisDistance (pt, model_coefficients) - actual_cone_radius)) > threshold)
467  return (false);
468  }
469 
470  return (true);
471 }
472 
474 template <typename PointT, typename PointNT> double
476  const Eigen::Vector4f &pt, const Eigen::VectorXf &model_coefficients)
477 {
478  Eigen::Vector4f apex (model_coefficients[0], model_coefficients[1], model_coefficients[2], 0);
479  Eigen::Vector4f axis_dir (model_coefficients[3], model_coefficients[4], model_coefficients[5], 0);
480  return sqrt(pcl::sqrPointToLineDistance (pt, apex, axis_dir));
481 }
482 
484 template <typename PointT, typename PointNT> bool
485 pcl::SampleConsensusModelCone<PointT, PointNT>::isModelValid (const Eigen::VectorXf &model_coefficients)
486 {
487  // Needs a valid model coefficients
488  if (model_coefficients.size () != 7)
489  {
490  PCL_ERROR ("[pcl::SampleConsensusModelCone::isModelValid] Invalid number of model coefficients given (%zu)!\n", model_coefficients.size ());
491  return (false);
492  }
493 
494  // Check against template, if given
495  if (eps_angle_ > 0.0)
496  {
497  // Obtain the cone direction
498  Eigen::Vector4f coeff;
499  coeff[0] = model_coefficients[3];
500  coeff[1] = model_coefficients[4];
501  coeff[2] = model_coefficients[5];
502  coeff[3] = 0;
503 
504  Eigen::Vector4f axis (axis_[0], axis_[1], axis_[2], 0);
505  double angle_diff = fabs (getAngle3D (axis, coeff));
506  angle_diff = (std::min) (angle_diff, M_PI - angle_diff);
507  // Check whether the current cone model satisfies our angle threshold criterion with respect to the given axis
508  if (angle_diff > eps_angle_)
509  return (false);
510  }
511 
512  if (model_coefficients[6] != -std::numeric_limits<double>::max() && model_coefficients[6] < min_angle_)
513  return (false);
514  if (model_coefficients[6] != std::numeric_limits<double>::max() && model_coefficients[6] > max_angle_)
515  return (false);
516 
517  return (true);
518 }
519 
520 #define PCL_INSTANTIATE_SampleConsensusModelCone(PointT, PointNT) template class PCL_EXPORTS pcl::SampleConsensusModelCone<PointT, PointNT>;
521 
522 #endif // PCL_SAMPLE_CONSENSUS_IMPL_SAC_MODEL_CONE_H_
523