TimeQueue.h
Go to the documentation of this file.
1/*
2 * This file is part of ArmarX.
3 *
4 * ArmarX is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 * ArmarX is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * @author Fabian Reister ( fabian dot reister at kit dot edu )
17 * @date 2021
18 * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
19 * GNU General Public License
20 */
21
22#pragma once
23
24#include <algorithm>
25#include <deque>
26#include <iterator>
27#include <mutex>
28#include <shared_mutex>
29#include <vector>
30
31#include <Eigen/Core>
32#include <Eigen/Geometry>
33
34#include <SimoxUtility/math/pose/interpolate.h>
35
39
41{
42
43 // struct PoseStamped
44 // {
45 // Eigen::Isometry3f pose;
46 // int64_t timestamp;
47 // };
48
49 template <typename MessageType>
51 {
52
53 public:
54 TimeQueue(const std::size_t maxQueueSize) : maxQueueSize(maxQueueSize)
55 {
56 }
57
58 TimeQueue(TimeQueue&& other) noexcept :
59 queue(std::move(other.queue)), maxQueueSize(other.maxQueueSize)
60 {
61 }
62
63 // using MessagePtr = std::shared_ptr<MessageType>;
64 // using MessageConstPtr = std::shared_ptr<const MessageType>;
65
66 void
67 insert(MessageType message)
68 {
70 ARMARX_DEBUG << "Locking insert()";
71 std::unique_lock g{mtx};
72
73 // if (not queue.empty())
74 // {
75 // ARMARX_CHECK_GREATER(message.timestamp, queue.back().timestamp)
76 // << "Poses have to be passed in with increasing timestamps";
77 // }
78
80
81 queue.emplace_back(std::move(message));
82
83 // only keep the last x seconds specified by duration
84 //trimUntil(poseStamped.timestamp - duration);
85
86 while (queue.size() > maxQueueSize)
87 {
88 queue.pop_front();
89 }
90 }
91
92 std::vector<int64_t>
93 timestamps() const
94 {
96 ARMARX_DEBUG << "Locking timestamps()";
97
98 std::vector<int64_t> ts;
99 ts.reserve(queue.size());
100
101 std::shared_lock g{mtx};
102 std::transform(queue.begin(),
103 queue.end(),
104 std::back_inserter(ts),
105 [](const MessageType& msg) { return msg.timestamp; });
106
107 return ts;
108 }
109
110 const MessageType&
111 lookupAt(int64_t referenceTimestamp) const
112 {
114 ARMARX_DEBUG << "Locking lookupAt()";
115 std::shared_lock g{mtx};
116
117 // ARMARX_CHECK(_has(referenceTimestamp))
118 // << "Cannot perform lookup of timestamp " << referenceTimestamp;
119
120 // const auto poseNextIt = findFirstElementAtOrAfter(referenceTimestamp);
121 const auto poseIt = findFirstElementAtOrBefore(referenceTimestamp);
122
123 // TODO(fabian.reister): check if poseBeforeIt is valid and compare dt's
124
125 return *poseIt;
126 }
127
128 bool
129 has(int64_t timestamp) const
130 {
132 ARMARX_DEBUG << "Locking has()";
133 std::shared_lock g{mtx};
134 return _has(timestamp);
135 }
136
137 void
139 {
141 ARMARX_DEBUG << "Locking trimUntil()";
142
143 std::unique_lock g{mtx};
144
145 while (not queue.empty())
146 {
147 if (queue.front().timestamp <= timestamp)
148 {
149 queue.pop_front();
150 }
151
152 // We reached a valid entry. Done.
153 break;
154 }
155 }
156
157 void
159 {
160 std::lock_guard g{mtx};
161 queue.clear();
162 }
163
164 std::size_t
165 size() const noexcept
166 {
167 std::lock_guard g{mtx};
168 return queue.size();
169 }
170
171 using QueueType = std::deque<MessageType>;
172 using QueueIterator = typename QueueType::iterator;
173 using QueueConstIterator = typename QueueType::const_iterator;
174 using QueueConstReverseIterator = typename QueueType::const_reverse_iterator;
175
176
177 protected:
180 {
181 auto timestampBeyond = [timestamp](const MessageType& poseStamped)
182 { return poseStamped.timestamp >= timestamp; };
183
184 const auto poseNextIt = std::find_if(queue.begin(), queue.end(), timestampBeyond);
185 return poseNextIt;
186 }
187
190 {
191 auto timestampBefore = [timestamp](const MessageType& poseStamped)
192 { return poseStamped.timestamp <= timestamp; };
193
194 const auto poseBeforeIt = std::find_if(queue.rbegin(), queue.rend(), timestampBefore);
195 return poseBeforeIt;
196 }
197
198 bool
199 _has(int64_t timestamp) const
200 {
201 // Cannot perform lookup when queue is empty
202 if (queue.empty())
203 {
204 return false;
205 }
206
207 // Cannot perform lookup into the future!
208 if (queue.back().timestamp < timestamp)
209 {
210 // ARMARX_DEBUG << "Cannot perform lookup into future";
211 return false;
212 }
213
214 // Cannot perform lookup. Timestamp too old
215 if (queue.front().timestamp > timestamp)
216 {
217 // ARMARX_DEBUG << "Cannot perform lookup into past";
218 return false;
219 }
220
221 // => now we know that there is an element right after and before the timestamp within our queue
222 return true;
223 }
224
225
226 protected:
228
229 mutable std::shared_mutex mtx;
230
231 private:
232 void
233 trimUntilPriv(const size_t pos)
234 {
235 if (pos >= queue.size())
236 {
237 // TODO(fabian.reister): warning
238 return;
239 }
240
241 if (pos == 0)
242 {
243 queue.clear();
244 }
245
246 queue.erase(queue.begin(), queue.begin() + pos);
247 }
248
249 const std::size_t maxQueueSize;
250 };
251
252} // namespace armarx::localization_and_mapping::cartographer_adapter
std::string timestamp()
QueueConstIterator findFirstElementAtOrAfter(int64_t timestamp) const
Definition TimeQueue.h:179
const MessageType & lookupAt(int64_t referenceTimestamp) const
Definition TimeQueue.h:111
QueueConstReverseIterator findFirstElementAtOrBefore(int64_t timestamp) const
Definition TimeQueue.h:189
#define ARMARX_DEBUG
The logging level for output that is only interesting while debugging.
Definition Logging.h:184
#define ARMARX_TRACE
Definition trace.h:77