Point Cloud Library (PCL) 1.14.0
Loading...
Searching...
No Matches
grabber.h
1/*
2 * Software License Agreement (BSD License)
3 *
4 * Copyright (c) 2011, 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 the copyright holder(s) 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#pragma once
36
37#include <pcl/pcl_config.h>
38
39// needed for the grabber interface / observers
40#include <map>
41#include <memory>
42#include <iostream>
43#include <string>
44#include <typeinfo>
45#include <tuple>
46#include <vector>
47#include <sstream>
48#include <pcl/pcl_macros.h>
49#include <pcl/exceptions.h>
50#include <boost/signals2.hpp> // for connection, signal, ...
51
52namespace pcl
53{
54
55 /** \brief Grabber interface for PCL 1.x device drivers
56 * \author Suat Gedikli <gedikli@willowgarage.com>
57 * \ingroup io
58 */
59 class PCL_EXPORTS Grabber
60 {
61 public:
62 /**
63 * \brief Default ctor
64 */
65 Grabber() = default;
66
67 /**
68 * \brief No copy ctor since Grabber can't be copied
69 */
70 Grabber(const Grabber&) = delete;
71
72 /**
73 * \brief No copy assign operator since Grabber can't be copied
74 */
75 Grabber& operator=(const Grabber&) = delete;
76
77 /**
78 * \brief Move ctor
79 */
80 Grabber(Grabber&&) = default;
81
82 /**
83 * \brief Move assign operator
84 */
85 Grabber& operator=(Grabber&&) = default;
86
87 /** \brief virtual destructor. */
88 virtual inline ~Grabber () noexcept = default;
89
90 /** \brief registers a callback function/method to a signal with the corresponding signature
91 * \param[in] callback: the callback function/method
92 * \return Connection object, that can be used to disconnect the callback method from the signal again.
93 */
94 template<typename T> boost::signals2::connection
95 registerCallback (const std::function<T>& callback);
96
97 /** \brief indicates whether a signal with given parameter-type exists or not
98 * \return true if signal exists, false otherwise
99 */
100 template<typename T> bool
101 providesCallback () const noexcept;
102
103 /** \brief For devices that are streaming, the streams are started by calling this method.
104 * Trigger-based devices, just trigger the device once for each call of start.
105 */
106 virtual void
107 start () = 0;
108
109 /** \brief For devices that are streaming, the streams are stopped.
110 * This method has no effect for triggered devices.
111 */
112 virtual void
113 stop () = 0;
114
115 /** \brief For devices that are streaming, stopped streams are started and running stream are stopped.
116 * For triggered devices, the behavior is not defined.
117 * \return true if grabber is running / streaming. False otherwise.
118 */
119 inline bool
120 toggle ();
121
122 /** \brief returns the name of the concrete subclass.
123 * \return the name of the concrete driver.
124 */
125 virtual std::string
126 getName () const = 0;
127
128 /** \brief Indicates whether the grabber is streaming or not. This value is not defined for triggered devices.
129 * \return true if grabber is running / streaming. False otherwise.
130 */
131 virtual bool
132 isRunning () const = 0;
133
134 /** \brief returns fps. 0 if trigger based. */
135 virtual float
136 getFramesPerSecond () const = 0;
137
138 protected:
139
140 virtual void
141 signalsChanged () { }
142
143 template<typename T> boost::signals2::signal<T>*
144 find_signal () const noexcept;
145
146 template<typename T> int
147 num_slots () const noexcept;
148
149 template<typename T> void
150 disconnect_all_slots ();
151
152 template<typename T> void
153 block_signal ();
154
155 template<typename T> void
156 unblock_signal ();
157
158 inline void
159 block_signals ();
160
161 inline void
162 unblock_signals ();
163
164 template<typename T> boost::signals2::signal<T>*
165 createSignal ();
166
167 std::map<std::string, std::unique_ptr<boost::signals2::signal_base>> signals_;
168 std::map<std::string, std::vector<boost::signals2::connection> > connections_;
169 std::map<std::string, std::vector<boost::signals2::shared_connection_block> > shared_connections_;
170 } ;
171
172 bool
173 Grabber::toggle ()
174 {
175 if (isRunning ())
176 {
177 stop ();
178 } else
179 {
180 start ();
181 }
182 return isRunning ();
183 }
184
185 template<typename T> boost::signals2::signal<T>*
186 Grabber::find_signal () const noexcept
187 {
188 using Signal = boost::signals2::signal<T>;
189
190 const auto signal_it = signals_.find (typeid (T).name ());
191 if (signal_it != signals_.end ())
192 {
193 return (static_cast<Signal*> (signal_it->second.get ()));
194 }
195 return nullptr;
196 }
197
198 template<typename T> void
199 Grabber::disconnect_all_slots ()
200 {
201 const auto signal = find_signal<T> ();
202 if (signal != nullptr)
203 {
204 signal->disconnect_all_slots ();
205 }
206 }
207
208 template<typename T> void
209 Grabber::block_signal ()
210 {
211 if (connections_.find (typeid (T).name ()) != connections_.end ())
212 for (auto &connection : shared_connections_[typeid (T).name ()])
213 connection.block ();
214 }
215
216 template<typename T> void
217 Grabber::unblock_signal ()
218 {
219 if (connections_.find (typeid (T).name ()) != connections_.end ())
220 for (auto &connection : shared_connections_[typeid (T).name ()])
221 connection.unblock ();
222 }
223
224 void
225 Grabber::block_signals ()
226 {
227 for (const auto &signal : signals_)
228 for (auto &connection : shared_connections_[signal.first])
229 connection.block ();
230 }
231
232 void
233 Grabber::unblock_signals ()
234 {
235 for (const auto &signal : signals_)
236 for (auto &connection : shared_connections_[signal.first])
237 connection.unblock ();
238 }
239
240 template<typename T> int
241 Grabber::num_slots () const noexcept
242 {
243 const auto signal = find_signal<T> ();
244 if (signal != nullptr)
245 {
246 return static_cast<int> (signal->num_slots ());
247 }
248 return 0;
249 }
250
251 template<typename T> boost::signals2::signal<T>*
252 Grabber::createSignal ()
253 {
254 using Signal = boost::signals2::signal<T>;
255 using Base = boost::signals2::signal_base;
256 // DefferedPtr serves 2 purposes:
257 // * allows MSVC to copy it around, can't do that with unique_ptr<T>
258 // * performs dynamic allocation only when required. If the key is found, this
259 // struct is a no-op, otherwise it allocates when implicit conversion operator
260 // is called inside emplace/try_emplace
261 struct DefferedPtr {
262 operator std::unique_ptr<Base>() const { return std::make_unique<Signal>(); }
263 };
264 // TODO: remove later for C++17 features: structured bindings and try_emplace
265 std::string signame{typeid (T).name ()};
266 #ifdef __cpp_structured_bindings
267 const auto [iterator, success] =
268 #else
269 typename decltype(signals_)::const_iterator iterator;
270 bool success;
271 std::tie (iterator, success) =
272 #endif
273
274 #ifdef __cpp_lib_map_try_emplace
275 signals_.try_emplace (
276 #else
277 signals_.emplace (
278 #endif
279 signame, DefferedPtr ());
280 if (!success)
281 {
282 return nullptr;
283 }
284 return static_cast<Signal*> (iterator->second.get ());
285 }
286
287 template<typename T> boost::signals2::connection
288 Grabber::registerCallback (const std::function<T> & callback)
289 {
290 const auto signal = find_signal<T> ();
291 if (signal == nullptr)
292 {
293 std::stringstream sstream;
294
295 sstream << "no callback for type:" << typeid (T).name ();
296
297 PCL_THROW_EXCEPTION (pcl::IOException, "[" << getName () << "] " << sstream.str ());
298 //return (boost::signals2::connection ());
299 }
300 boost::signals2::connection ret = signal->connect (callback);
301
302 connections_[typeid (T).name ()].push_back (ret);
303 shared_connections_[typeid (T).name ()].push_back (boost::signals2::shared_connection_block (connections_[typeid (T).name ()].back (), false));
304 signalsChanged ();
305 return (ret);
306 }
307
308 template<typename T> bool
309 Grabber::providesCallback () const noexcept
310 {
311 return find_signal<T> ();
312 }
313
314} // namespace
Grabber interface for PCL 1.x device drivers.
Definition grabber.h:60
Grabber(Grabber &&)=default
Move ctor.
Grabber(const Grabber &)=delete
No copy ctor since Grabber can't be copied.
Grabber()=default
Default ctor.
virtual ~Grabber() noexcept=default
virtual destructor.
Grabber & operator=(const Grabber &)=delete
No copy assign operator since Grabber can't be copied.
Grabber & operator=(Grabber &&)=default
Move assign operator.
An exception that is thrown during an IO error (typical read/write errors)
Definition exceptions.h:179
Defines all the PCL and non-PCL macros used.