moveit2
The MoveIt Motion Planning Framework for ROS 2.
Loading...
Searching...
No Matches
shape_mask.cpp
Go to the documentation of this file.
1/*********************************************************************
2 * Software License Agreement (BSD License)
3 *
4 * Copyright (c) 2008, Willow Garage, Inc.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials provided
16 * with the distribution.
17 * * Neither the name of Willow Garage nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 * POSSIBILITY OF SUCH DAMAGE.
33 *********************************************************************/
34
35/* Author: Ioan Sucan */
36
38#include <geometric_shapes/body_operations.h>
39#include <sensor_msgs/point_cloud2_iterator.hpp>
40#include <rclcpp/logger.hpp>
41#include <rclcpp/logging.hpp>
43
44namespace
45{
46rclcpp::Logger getLogger()
47{
48 return moveit::getLogger("moveit.ros.shape_mask");
49}
50} // namespace
51
53 : transform_callback_(transform_callback), next_handle_(1), min_handle_(1)
54{
55}
56
61
62void point_containment_filter::ShapeMask::freeMemory()
63{
64 for (const SeeShape& body : bodies_)
65 delete body.body;
66 bodies_.clear();
67}
68
70{
71 std::scoped_lock _(shapes_lock_);
72 transform_callback_ = transform_callback;
73}
74
76 double scale, double padding)
77{
78 std::scoped_lock _(shapes_lock_);
79 SeeShape ss;
80 ss.body = bodies::createEmptyBodyFromShapeType(shape->type);
81 if (ss.body)
82 {
83 ss.body->setDimensionsDirty(shape.get());
84 ss.body->setScaleDirty(scale);
85 ss.body->setPaddingDirty(padding);
86 ss.body->updateInternalData();
87 ss.volume = ss.body->computeVolume();
88 ss.handle = next_handle_;
89 std::pair<std::set<SeeShape, SortBodies>::iterator, bool> insert_op = bodies_.insert(ss);
90 if (!insert_op.second)
91 {
92 RCLCPP_ERROR(getLogger(), "Internal error in management of bodies in ShapeMask. This is a serious error.");
93 }
94 used_handles_[next_handle_] = insert_op.first;
95 }
96 else
97 {
98 return 0;
99 }
100
101 ShapeHandle ret = next_handle_;
102 const std::size_t sz = min_handle_ + bodies_.size() + 1;
103 for (std::size_t i = min_handle_; i < sz; ++i)
104 {
105 if (used_handles_.find(i) == used_handles_.end())
106 {
107 next_handle_ = i;
108 break;
109 }
110 }
111 min_handle_ = next_handle_;
112
113 return ret;
114}
115
117{
118 std::scoped_lock _(shapes_lock_);
119 std::map<ShapeHandle, std::set<SeeShape, SortBodies>::iterator>::iterator it = used_handles_.find(handle);
120 if (it != used_handles_.end())
121 {
122 delete it->second->body;
123 bodies_.erase(it->second);
124 used_handles_.erase(it);
125 min_handle_ = handle;
126 }
127 else
128 {
129 RCLCPP_ERROR(getLogger(), "Unable to remove shape handle %u", handle);
130 }
131}
132
133void point_containment_filter::ShapeMask::maskContainment(const sensor_msgs::msg::PointCloud2& data_in,
134 const Eigen::Vector3d& /*sensor_origin*/,
135 const double min_sensor_dist, const double max_sensor_dist,
136 std::vector<int>& mask)
137{
138 std::scoped_lock _(shapes_lock_);
139 const unsigned int np = data_in.data.size() / data_in.point_step;
140 mask.resize(np);
141
142 if (bodies_.empty())
143 {
144 std::fill(mask.begin(), mask.end(), static_cast<int>(OUTSIDE));
145 }
146 else
147 {
148 Eigen::Isometry3d tmp;
149 bspheres_.resize(bodies_.size());
150 std::size_t j = 0;
151 for (std::set<SeeShape>::const_iterator it = bodies_.begin(); it != bodies_.end(); ++it)
152 {
153 if (!transform_callback_(it->handle, tmp))
154 {
155 if (!it->body)
156 {
157 RCLCPP_ERROR_STREAM(getLogger(),
158 "Missing transform for shape with handle " << it->handle << " without a body");
159 }
160 else
161 {
162 RCLCPP_ERROR_STREAM(getLogger(),
163 "Missing transform for shape " << it->body->getType() << " with handle " << it->handle);
164 }
165 }
166 else
167 {
168 it->body->setPose(tmp);
169 it->body->computeBoundingSphere(bspheres_[j++]);
170 }
171 }
172
173 // compute a sphere that bounds the entire robot
174 bodies::BoundingSphere bound;
175 bodies::mergeBoundingSpheres(bspheres_, bound);
176 const double radius_squared = bound.radius * bound.radius;
177
178 // we now decide which points we keep
179 sensor_msgs::PointCloud2ConstIterator<float> iter_x(data_in, "x");
180 sensor_msgs::PointCloud2ConstIterator<float> iter_y(data_in, "y");
181 sensor_msgs::PointCloud2ConstIterator<float> iter_z(data_in, "z");
182
183 // Cloud iterators are not incremented in the for loop, because of the pragma
184 // Comment out below parallelization as it can result in very high CPU consumption
185 //#pragma omp parallel for schedule(dynamic)
186 for (int i = 0; i < static_cast<int>(np); ++i)
187 {
188 Eigen::Vector3d pt = Eigen::Vector3d(*(iter_x + i), *(iter_y + i), *(iter_z + i));
189 double d = pt.norm();
190 int out = OUTSIDE;
191 if (d < min_sensor_dist || d > max_sensor_dist)
192 {
193 out = CLIP;
194 }
195 else if ((bound.center - pt).squaredNorm() < radius_squared)
196 {
197 for (std::set<SeeShape>::const_iterator it = bodies_.begin(); it != bodies_.end() && out == OUTSIDE; ++it)
198 {
199 if (it->body->containsPoint(pt))
200 out = INSIDE;
201 }
202 }
203 mask[i] = out;
204 }
205 }
206}
207
209{
210 std::scoped_lock _(shapes_lock_);
211
212 int out = OUTSIDE;
213 for (std::set<SeeShape>::const_iterator it = bodies_.begin(); it != bodies_.end() && out == OUTSIDE; ++it)
214 {
215 if (it->body->containsPoint(pt))
216 out = INSIDE;
217 }
218 return out;
219}
220
221int point_containment_filter::ShapeMask::getMaskContainment(double x, double y, double z) const
222{
223 return getMaskContainment(Eigen::Vector3d(x, y, z));
224}
ShapeHandle addShape(const shapes::ShapeConstPtr &shape, double scale=1.0, double padding=0.0)
std::mutex shapes_lock_
Protects, bodies_ and bspheres_. All public methods acquire this mutex for their whole duration.
std::vector< bodies::BoundingSphere > bspheres_
std::set< SeeShape, SortBodies > bodies_
std::function< bool(ShapeHandle, Eigen::Isometry3d &)> TransformCallback
void removeShape(ShapeHandle handle)
ShapeMask(const TransformCallback &transform_callback=TransformCallback())
Construct the filter.
void maskContainment(const sensor_msgs::msg::PointCloud2 &data_in, const Eigen::Vector3d &sensor_pos, const double min_sensor_dist, const double max_sensor_dist, std::vector< int > &mask)
Compute the containment mask (INSIDE or OUTSIDE) for a given pointcloud. If a mask element is INSIDE,...
int getMaskContainment(double x, double y, double z) const
Get the containment mask (INSIDE or OUTSIDE) value for an individual point. It is assumed the point i...
virtual ~ShapeMask()
Destructor to clean up.
void setTransformCallback(const TransformCallback &transform_callback)
rclcpp::Logger getLogger(const std::string &name)
Creates a namespaced logger.
Definition logger.cpp:106