/* * Software License Agreement (BSD License) * * Point Cloud Library (PCL) - www.pointclouds.org * Copyright (c) 2010-2011, Willow Garage, Inc. * * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 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. * * Neither the name of the copyright holder(s) 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 OWNER 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. * */ #pragma once #include // for pcl::isFinite #include #include ////////////////////////////////////////////////////////////////////////////////////////////// template float pcl::search::BruteForce::getDistSqr ( const PointT& point1, const PointT& point2) const { return (point1.getVector3fMap () - point2.getVector3fMap ()).squaredNorm (); } ////////////////////////////////////////////////////////////////////////////////////////////// template int pcl::search::BruteForce::nearestKSearch ( const PointT& point, int k, Indices& k_indices, std::vector& k_distances) const { assert (isFinite (point) && "Invalid (NaN, Inf) point coordinates given to nearestKSearch!"); k_indices.clear (); k_distances.clear (); if (k < 1) return 0; if (input_->is_dense) return denseKSearch (point, k, k_indices, k_distances); return sparseKSearch (point, k, k_indices, k_distances); } ////////////////////////////////////////////////////////////////////////////////////////////// template int pcl::search::BruteForce::denseKSearch ( const PointT &point, int k, Indices &k_indices, std::vector &k_distances) const { // container for first k elements -> O(1) for insertion, since order not required here std::vector result; result.reserve (k); std::priority_queue queue; if (indices_) { auto iIt = indices_->cbegin (); auto iEnd = indices_->cbegin () + std::min (static_cast (k), static_cast (indices_->size ())); for (; iIt != iEnd; ++iIt) result.push_back (Entry (*iIt, getDistSqr ((*input_)[*iIt], point))); queue = std::priority_queue (result.begin (), result.end ()); // add the rest Entry entry; for (; iIt != indices_->cend (); ++iIt) { entry.distance = getDistSqr ((*input_)[*iIt], point); if (queue.top ().distance > entry.distance) { entry.index = *iIt; queue.pop (); queue.push (entry); } } } else { Entry entry; for (entry.index = 0; entry.index < std::min (k, input_->size ()); ++entry.index) { entry.distance = getDistSqr ((*input_)[entry.index], point); result.push_back (entry); } queue = std::priority_queue (result.begin (), result.end ()); // add the rest for (; entry.index < static_cast(input_->size ()); ++entry.index) { entry.distance = getDistSqr ((*input_)[entry.index], point); if (queue.top ().distance > entry.distance) { queue.pop (); queue.push (entry); } } } k_indices.resize (queue.size ()); k_distances.resize (queue.size ()); std::size_t idx = queue.size () - 1; while (!queue.empty ()) { k_indices [idx] = queue.top ().index; k_distances [idx] = queue.top ().distance; queue.pop (); --idx; } return (static_cast (k_indices.size ())); } ////////////////////////////////////////////////////////////////////////////////////////////// template int pcl::search::BruteForce::sparseKSearch ( const PointT &point, int k, Indices &k_indices, std::vector &k_distances) const { // result used to collect the first k neighbors -> unordered std::vector result; result.reserve (k); std::priority_queue queue; if (indices_) { auto iIt =indices_->cbegin (); for (; iIt != indices_->cend () && result.size () < static_cast (k); ++iIt) { if (std::isfinite ((*input_)[*iIt].x)) result.push_back (Entry (*iIt, getDistSqr ((*input_)[*iIt], point))); } queue = std::priority_queue (result.begin (), result.end ()); // either we have k elements, or there are none left to iterate >in either case we're fine // add the rest Entry entry; for (; iIt != indices_->cend (); ++iIt) { if (!std::isfinite ((*input_)[*iIt].x)) continue; entry.distance = getDistSqr ((*input_)[*iIt], point); if (queue.top ().distance > entry.distance) { entry.index = *iIt; queue.pop (); queue.push (entry); } } } else { Entry entry; for (entry.index = 0; (entry.index < static_cast(input_->size ())) && (result.size () < static_cast (k)); ++entry.index) { if (std::isfinite ((*input_)[entry.index].x)) { entry.distance = getDistSqr ((*input_)[entry.index], point); result.push_back (entry); } } queue = std::priority_queue (result.begin (), result.end ()); // add the rest for (; entry.index < static_cast(input_->size ()); ++entry.index) { if (!std::isfinite ((*input_)[entry.index].x)) continue; entry.distance = getDistSqr ((*input_)[entry.index], point); if (queue.top ().distance > entry.distance) { queue.pop (); queue.push (entry); } } } k_indices.resize (queue.size ()); k_distances.resize (queue.size ()); std::size_t idx = queue.size () - 1; while (!queue.empty ()) { k_indices [idx] = queue.top ().index; k_distances [idx] = queue.top ().distance; queue.pop (); --idx; } return (static_cast (k_indices.size ())); } ////////////////////////////////////////////////////////////////////////////////////////////// template int pcl::search::BruteForce::denseRadiusSearch ( const PointT& point, double radius, Indices &k_indices, std::vector &k_sqr_distances, unsigned int max_nn) const { radius *= radius; std::size_t reserve = max_nn; if (reserve == 0) { if (indices_) reserve = std::min (indices_->size (), input_->size ()); else reserve = input_->size (); } k_indices.reserve (reserve); k_sqr_distances.reserve (reserve); float distance; if (indices_) { for (const auto& idx : *indices_) { distance = getDistSqr ((*input_)[idx], point); if (distance <= radius) { k_indices.push_back (idx); k_sqr_distances.push_back (distance); if (k_indices.size () == max_nn) // max_nn = 0 -> never true break; } } } else { for (std::size_t index = 0; index < input_->size (); ++index) { distance = getDistSqr ((*input_)[index], point); if (distance <= radius) { k_indices.push_back (index); k_sqr_distances.push_back (distance); if (k_indices.size () == max_nn) // never true if max_nn = 0 break; } } } if (sorted_results_) this->sortResults (k_indices, k_sqr_distances); return (static_cast (k_indices.size ())); } ////////////////////////////////////////////////////////////////////////////////////////////// template int pcl::search::BruteForce::sparseRadiusSearch ( const PointT& point, double radius, Indices &k_indices, std::vector &k_sqr_distances, unsigned int max_nn) const { radius *= radius; std::size_t reserve = max_nn; if (reserve == 0) { if (indices_) reserve = std::min (indices_->size (), input_->size ()); else reserve = input_->size (); } k_indices.reserve (reserve); k_sqr_distances.reserve (reserve); float distance; if (indices_) { for (const auto& idx : *indices_) { if (!std::isfinite ((*input_)[idx].x)) continue; distance = getDistSqr ((*input_)[idx], point); if (distance <= radius) { k_indices.push_back (idx); k_sqr_distances.push_back (distance); if (k_indices.size () == max_nn) // never true if max_nn = 0 break; } } } else { for (std::size_t index = 0; index < input_->size (); ++index) { if (!std::isfinite ((*input_)[index].x)) continue; distance = getDistSqr ((*input_)[index], point); if (distance <= radius) { k_indices.push_back (index); k_sqr_distances.push_back (distance); if (k_indices.size () == max_nn) // never true if max_nn = 0 break; } } } if (sorted_results_) this->sortResults (k_indices, k_sqr_distances); return (static_cast (k_indices.size ())); } ////////////////////////////////////////////////////////////////////////////////////////////// template int pcl::search::BruteForce::radiusSearch ( const PointT& point, double radius, Indices &k_indices, std::vector &k_sqr_distances, unsigned int max_nn) const { assert (isFinite (point) && "Invalid (NaN, Inf) point coordinates given to nearestKSearch!"); k_indices.clear (); k_sqr_distances.clear (); if (radius <= 0) return 0; if (input_->is_dense) return denseRadiusSearch (point, radius, k_indices, k_sqr_distances, max_nn); return sparseRadiusSearch (point, radius, k_indices, k_sqr_distances, max_nn); } #define PCL_INSTANTIATE_BruteForce(T) template class PCL_EXPORTS pcl::search::BruteForce;