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 return 0;
98
99 ShapeHandle ret = next_handle_;
100 const std::size_t sz = min_handle_ + bodies_.size() + 1;
101 for (std::size_t i = min_handle_; i < sz; ++i)
102 {
103 if (used_handles_.find(i) == used_handles_.end())
104 {
105 next_handle_ = i;
106 break;
107 }
108 }
109 min_handle_ = next_handle_;
110
111 return ret;
112}
113
115{
116 std::scoped_lock _(shapes_lock_);
117 std::map<ShapeHandle, std::set<SeeShape, SortBodies>::iterator>::iterator it = used_handles_.find(handle);
118 if (it != used_handles_.end())
119 {
120 delete it->second->body;
121 bodies_.erase(it->second);
122 used_handles_.erase(it);
123 min_handle_ = handle;
124 }
125 else
126 RCLCPP_ERROR(getLogger(), "Unable to remove shape handle %u", handle);
127}
128
129void point_containment_filter::ShapeMask::maskContainment(const sensor_msgs::msg::PointCloud2& data_in,
130 const Eigen::Vector3d& /*sensor_origin*/,
131 const double min_sensor_dist, const double max_sensor_dist,
132 std::vector<int>& mask)
133{
134 std::scoped_lock _(shapes_lock_);
135 const unsigned int np = data_in.data.size() / data_in.point_step;
136 mask.resize(np);
137
138 if (bodies_.empty())
139 {
140 std::fill(mask.begin(), mask.end(), static_cast<int>(OUTSIDE));
141 }
142 else
143 {
144 Eigen::Isometry3d tmp;
145 bspheres_.resize(bodies_.size());
146 std::size_t j = 0;
147 for (std::set<SeeShape>::const_iterator it = bodies_.begin(); it != bodies_.end(); ++it)
148 {
149 if (!transform_callback_(it->handle, tmp))
150 {
151 if (!it->body)
152 {
153 RCLCPP_ERROR_STREAM(getLogger(),
154 "Missing transform for shape with handle " << it->handle << " without a body");
155 }
156 else
157 {
158 RCLCPP_ERROR_STREAM(getLogger(),
159 "Missing transform for shape " << it->body->getType() << " with handle " << it->handle);
160 }
161 }
162 else
163 {
164 it->body->setPose(tmp);
165 it->body->computeBoundingSphere(bspheres_[j++]);
166 }
167 }
168
169 // compute a sphere that bounds the entire robot
170 bodies::BoundingSphere bound;
171 bodies::mergeBoundingSpheres(bspheres_, bound);
172 const double radius_squared = bound.radius * bound.radius;
173
174 // we now decide which points we keep
175 sensor_msgs::PointCloud2ConstIterator<float> iter_x(data_in, "x");
176 sensor_msgs::PointCloud2ConstIterator<float> iter_y(data_in, "y");
177 sensor_msgs::PointCloud2ConstIterator<float> iter_z(data_in, "z");
178
179 // Cloud iterators are not incremented in the for loop, because of the pragma
180 // Comment out below parallelization as it can result in very high CPU consumption
181 //#pragma omp parallel for schedule(dynamic)
182 for (int i = 0; i < static_cast<int>(np); ++i)
183 {
184 Eigen::Vector3d pt = Eigen::Vector3d(*(iter_x + i), *(iter_y + i), *(iter_z + i));
185 double d = pt.norm();
186 int out = OUTSIDE;
187 if (d < min_sensor_dist || d > max_sensor_dist)
188 {
189 out = CLIP;
190 }
191 else if ((bound.center - pt).squaredNorm() < radius_squared)
192 {
193 for (std::set<SeeShape>::const_iterator it = bodies_.begin(); it != bodies_.end() && out == OUTSIDE; ++it)
194 {
195 if (it->body->containsPoint(pt))
196 out = INSIDE;
197 }
198 }
199 mask[i] = out;
200 }
201 }
202}
203
205{
206 std::scoped_lock _(shapes_lock_);
207
208 int out = OUTSIDE;
209 for (std::set<SeeShape>::const_iterator it = bodies_.begin(); it != bodies_.end() && out == OUTSIDE; ++it)
210 {
211 if (it->body->containsPoint(pt))
212 out = INSIDE;
213 }
214 return out;
215}
216
217int point_containment_filter::ShapeMask::getMaskContainment(double x, double y, double z) const
218{
219 return getMaskContainment(Eigen::Vector3d(x, y, z));
220}
ShapeHandle addShape(const shapes::ShapeConstPtr &shape, double scale=1.0, double padding=0.0)
std::function< bool(ShapeHandle, Eigen::Isometry3d &)> TransformCallback
Definition shape_mask.h:63
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:79
unsigned int ShapeHandle
Definition shape_mask.h:49