ADTF Device Toolbox SDK
Loading...
Searching...
No Matches
pointcloud_transformation.h
Go to the documentation of this file.
1
16
17#pragma once
18
19#include "pointcloud_data.h"
20
21#include <algorithm>
22#include <cmath>
23#include <cstddef>
24#include <limits>
25#include <memory>
26#include <stdexcept>
27#include <variant>
28
32namespace adtf
33{
37namespace devicetb
38{
42namespace sdk
43{
47namespace pointcloud
48{
49
50namespace navigation
51{
52
53namespace detail
54{
55
56template<typename Output, typename Input>
57struct Clamper
58{
59 static Output clamp(const Input& value) noexcept
60 {
61 static_assert(std::is_arithmetic_v<Output>, "Output must be arithmetic");
62 static_assert(std::is_arithmetic_v<Input>, "Input must be arithmetic");
63
64 if constexpr (std::is_same_v<Input, Output>)
65 {
66 return value;
67 }
68 else if constexpr (std::is_same_v<Input, bool> || std::is_same_v<Output, bool>)
69 {
70 return static_cast<Output>(value);
71 }
72 else
73 {
74 constexpr const auto max_output = std::numeric_limits<Output>::max();
75 if constexpr (std::is_unsigned_v<Input> && std::is_unsigned_v<Output>)
76 {
77 return value > max_output ? max_output : static_cast<Output>(value);
78 }
79 else if constexpr (std::is_unsigned_v<Input> && std::is_signed_v<Output>)
80 {
81 return value >= max_output ? max_output : static_cast<Output>(value);
82 }
83 else if constexpr (std::is_signed_v<Input> && std::is_unsigned_v<Output>)
84 {
85 if (value < 0)
86 {
87 return 0;
88 }
89 else
90 {
91 return static_cast<uint64_t>(value) > max_output ? max_output : static_cast<Output>(value);
92 }
93 }
94 else
95 {
96 if (value < 0)
97 {
98 constexpr const auto min_output = std::numeric_limits<Output>::lowest();
99 return value <= min_output ? min_output : static_cast<Output>(value);
100 }
101 else
102 {
103 if constexpr (max_output > std::numeric_limits<Input>::max())
104 {
105 return static_cast<Output>(value);
106 }
107 else
108 {
109 return value > max_output ? max_output : static_cast<Output>(value);
110 }
111 }
112 }
113 }
114 }
115};
116
117template <typename Output>
118struct Clamper<Output, float16_t>
119{
120 static Output clamp(const float16_t& value) noexcept
121 {
122 return Clamper<Output, float>::clamp(static_cast<float>(value));
123 }
124};
125
126template <typename Input>
127struct Clamper<float16_t, Input>
128{
129 static float16_t clamp(const Input& value) noexcept
130 {
131 return float16_t(static_cast<double>(value));
132 }
133};
134
135template <>
137{
138 static float16_t clamp(const float16_t& value) noexcept
139 {
140 return value;
141 }
142};
143
144template<typename Output, typename Input>
145Output clamp(const Input& value) noexcept
146{
147 return Clamper<Output, Input>::clamp(value);
148}
149
150template <typename SourceType, typename DestinationType>
151void copy(const tAttribute::tInMemory& sSource,
152 const tAttribute::tInMemory& sDestination,
153 const void* const __restrict pSourceBuffer,
154 void* const __restrict pDestinationBuffer,
155 const size_t nCount)
156{
157 auto pReadPosition = static_cast<const std::byte*>(pSourceBuffer) + sSource.offset;
158 auto pWritePosition = static_cast<std::byte*>(pDestinationBuffer) + sDestination.offset;
159
160 if constexpr (std::is_same_v<SourceType, DestinationType>)
161 {
162 if (sSource.stride == sizeof(SourceType) &&
163 sSource.stride == sDestination.stride &&
164 sSource.endianess == sDestination.endianess)
165 {
166 std::memcpy(pWritePosition, pReadPosition, sizeof(SourceType) * nCount);
167 return;
168 }
169 }
170
171 if (sSource.endianess == get_byteorder())
172 {
173 if (sSource.endianess == sDestination.endianess)
174 {
175 for (size_t nIndex = 0; nIndex < nCount; ++nIndex)
176 {
177 *(reinterpret_cast<DestinationType*>(pWritePosition)) = clamp<DestinationType>(access<SourceType, false>(pReadPosition));
178 pReadPosition += sSource.stride;
179 pWritePosition += sDestination.stride;
180 }
181 }
182 else
183 {
184 for (size_t nIndex = 0; nIndex < nCount; ++nIndex)
185 {
186 *(reinterpret_cast<DestinationType*>(pWritePosition)) = byte_swap(clamp<DestinationType>(access<SourceType, false>(pReadPosition)));
187 pReadPosition += sSource.stride;
188 pWritePosition += sDestination.stride;
189 }
190 }
191 }
192 else
193 {
194 if (sSource.endianess == sDestination.endianess)
195 {
196 if constexpr (std::is_same_v<SourceType, DestinationType>)
197 {
198 for (size_t nIndex = 0; nIndex < nCount; ++nIndex)
199 {
200 *(reinterpret_cast<DestinationType*>(pWritePosition)) = *(reinterpret_cast<const SourceType*>(pReadPosition));
201 pReadPosition += sSource.stride;
202 pWritePosition += sDestination.stride;
203 }
204 }
205 else
206 {
207 for (size_t nIndex = 0; nIndex < nCount; ++nIndex)
208 {
209 *(reinterpret_cast<DestinationType*>(pWritePosition)) = byte_swap(clamp<DestinationType>(access<SourceType, true>(pReadPosition)));
210 pReadPosition += sSource.stride;
211 pWritePosition += sDestination.stride;
212 }
213 }
214 }
215 else
216 {
217 for (size_t nIndex = 0; nIndex < nCount; ++nIndex)
218 {
219 *(reinterpret_cast<DestinationType*>(pWritePosition)) = clamp<DestinationType>(access<SourceType, true>(pReadPosition));
220 pReadPosition += sSource.stride;
221 pWritePosition += sDestination.stride;
222 }
223 }
224 }
225}
226
227template <typename SourceType>
228void copy(const tAttribute::tInMemory& sSource,
229 const tAttribute& sDestinationAttribute,
230 const void* const __restrict pSourceBuffer,
231 void* const __restrict pDestinationBuffer,
232 const size_t nCount)
233{
234 switch (sDestinationAttribute.type)
235 {
236 case tAttribute::tDataType::dt_boolean: copy<SourceType, bool>(sSource, sDestinationAttribute.sInMemory, pSourceBuffer, pDestinationBuffer, nCount); break;
237 case tAttribute::tDataType::dt_int8: copy<SourceType, int8_t>(sSource, sDestinationAttribute.sInMemory, pSourceBuffer, pDestinationBuffer, nCount); break;
238 case tAttribute::tDataType::dt_uint8: copy<SourceType, uint8_t>(sSource, sDestinationAttribute.sInMemory, pSourceBuffer, pDestinationBuffer, nCount); break;
239 case tAttribute::tDataType::dt_int16: copy<SourceType, int16_t>(sSource, sDestinationAttribute.sInMemory, pSourceBuffer, pDestinationBuffer, nCount); break;
240 case tAttribute::tDataType::dt_uint16: copy<SourceType, uint16_t>(sSource, sDestinationAttribute.sInMemory, pSourceBuffer, pDestinationBuffer, nCount); break;
241 case tAttribute::tDataType::dt_int32: copy<SourceType, int32_t>(sSource, sDestinationAttribute.sInMemory, pSourceBuffer, pDestinationBuffer, nCount); break;
242 case tAttribute::tDataType::dt_uint32: copy<SourceType, uint32_t>(sSource, sDestinationAttribute.sInMemory, pSourceBuffer, pDestinationBuffer, nCount); break;
243 case tAttribute::tDataType::dt_int64: copy<SourceType, int64_t>(sSource, sDestinationAttribute.sInMemory, pSourceBuffer, pDestinationBuffer, nCount); break;
244 case tAttribute::tDataType::dt_uint64: copy<SourceType, uint64_t>(sSource, sDestinationAttribute.sInMemory, pSourceBuffer, pDestinationBuffer, nCount); break;
245 case tAttribute::tDataType::dt_float16: copy<SourceType, float16_t>(sSource, sDestinationAttribute.sInMemory, pSourceBuffer, pDestinationBuffer, nCount); break;
246 case tAttribute::tDataType::dt_float32: copy<SourceType, float>(sSource, sDestinationAttribute.sInMemory, pSourceBuffer, pDestinationBuffer, nCount); break;
247 case tAttribute::tDataType::dt_float64: copy<SourceType, double>(sSource, sDestinationAttribute.sInMemory, pSourceBuffer, pDestinationBuffer, nCount); break;
248 case tAttribute::tDataType::dt_computed_from_index: throw std::runtime_error("unexpected"); break;
249 }
250}
251
252inline void copy(const tAttribute& sSourceAttribute,
253 const tAttribute& sDestinationAttribute,
254 const void* const __restrict pSourceBuffer,
255 void* const __restrict pDestinationBuffer,
256 const size_t nCount)
257{
258 switch (sSourceAttribute.type)
259 {
260 case tAttribute::tDataType::dt_boolean: copy<bool>(sSourceAttribute.sInMemory, sDestinationAttribute, pSourceBuffer, pDestinationBuffer, nCount); break;
261 case tAttribute::tDataType::dt_int8: copy<int8_t>(sSourceAttribute.sInMemory, sDestinationAttribute, pSourceBuffer, pDestinationBuffer, nCount); break;
262 case tAttribute::tDataType::dt_uint8: copy<uint8_t>(sSourceAttribute.sInMemory, sDestinationAttribute, pSourceBuffer, pDestinationBuffer, nCount); break;
263 case tAttribute::tDataType::dt_int16: copy<int16_t>(sSourceAttribute.sInMemory, sDestinationAttribute, pSourceBuffer, pDestinationBuffer, nCount); break;
264 case tAttribute::tDataType::dt_uint16: copy<uint16_t>(sSourceAttribute.sInMemory, sDestinationAttribute, pSourceBuffer, pDestinationBuffer, nCount); break;
265 case tAttribute::tDataType::dt_int32: copy<int32_t>(sSourceAttribute.sInMemory, sDestinationAttribute, pSourceBuffer, pDestinationBuffer, nCount); break;
266 case tAttribute::tDataType::dt_uint32: copy<uint32_t>(sSourceAttribute.sInMemory, sDestinationAttribute, pSourceBuffer, pDestinationBuffer, nCount); break;
267 case tAttribute::tDataType::dt_int64: copy<int64_t>(sSourceAttribute.sInMemory, sDestinationAttribute, pSourceBuffer, pDestinationBuffer, nCount); break;
268 case tAttribute::tDataType::dt_uint64: copy<uint64_t>(sSourceAttribute.sInMemory, sDestinationAttribute, pSourceBuffer, pDestinationBuffer, nCount); break;
269 case tAttribute::tDataType::dt_float16: copy<float16_t>(sSourceAttribute.sInMemory, sDestinationAttribute, pSourceBuffer, pDestinationBuffer, nCount); break;
270 case tAttribute::tDataType::dt_float32: copy<float>(sSourceAttribute.sInMemory, sDestinationAttribute, pSourceBuffer, pDestinationBuffer, nCount); break;
271 case tAttribute::tDataType::dt_float64: copy<double>(sSourceAttribute.sInMemory, sDestinationAttribute, pSourceBuffer, pDestinationBuffer, nCount); break;
272 case tAttribute::tDataType::dt_computed_from_index: throw std::runtime_error("unexpected"); break;
273 }
274}
275
276inline void copy_attributes(const tAttributes& oSourceAttributes,
277 const tAttributes& oDestAttributes,
278 const void* const __restrict pSourceData,
279 void* const __restrict pDestData,
280 const size_t nCount,
281 bool bIgnoreMissing = true)
282{
283 for (const auto& oTuple : oDestAttributes)
284 {
285 const auto& oDestAttr = std::get<tAttribute>(oTuple);
286 const auto& strDestAttrName = std::get<std::string>(oTuple);
287
288 if (oDestAttr.type == tAttribute::tDataType::dt_computed_from_index)
289 {
290 THROW_ERROR_DESC(ERR_INVALID_ARG, "The destination attribute %s is of type computed_from_index, which cannot be written to.",
291 strDestAttrName.c_str());
292 }
293
294 if (!oSourceAttributes.exists(strDestAttrName))
295 {
296 if (bIgnoreMissing)
297 {
298 continue;
299 }
300
301 THROW_ERROR_DESC(ERR_NOT_FOUND, "The source does not contain the %s attribute.", strDestAttrName.c_str());
302 }
303
304 const auto& oSourceAttr = oSourceAttributes.at(strDestAttrName);
305
306 copy(oSourceAttr, oDestAttr, pSourceData, pDestData, nCount);
307 }
308}
309
310template <bool exclude = true, typename Elements>
311tAttributes filter(const tAttributes& oSourceAttributes, const Elements& elements)
312{
313 tAttributes oResult;
314
315 if constexpr(exclude)
316 {
317 for (const auto& oAttribute : oSourceAttributes)
318 {
319 if (std::find(elements.begin(), elements.end(), std::get<0>(oAttribute)) ==
320 elements.end())
321 {
322 oResult.add(std::get<0>(oAttribute), std::get<1>(oAttribute));
323 }
324 }
325 }
326 else
327 {
328 for (const auto& oAttribute : oSourceAttributes)
329 {
330 if (std::find(elements.begin(), elements.end(), std::get<0>(oAttribute)) !=
331 elements.end())
332 {
333 oResult.add(std::get<0>(oAttribute), std::get<1>(oAttribute));
334 }
335 }
336 }
337 return oResult;
338}
339
340}
341
343{
344public:
345 enum struct tTransformation
346 {
347 none = 0,
348 copy_all = 1,
349 copy_existing = 2,
350 cartesian_to_polar = 3,
351 polar_to_cartesian = 4,
352 };
353
354 static tTransformation GetSupportedTransformation(const tAttributes& oSourceAttributes,
355 const tAttributes& oDestAttributes)
356 {
357 const auto bAllDestinationAttributesInSource = [&]()
358 {
359 for (const auto& strDestinationAttribute: oDestAttributes)
360 {
361 if (!oSourceAttributes.exists(std::get<0>(strDestinationAttribute)))
362 {
363 return false;
364 }
365 }
366 return true;
367 }();
368
369 if (bAllDestinationAttributesInSource)
370 {
371 return tTransformation::copy_all;
372 }
373 else if (CanTransform<cTransformCartesianToPolar>(oSourceAttributes, oDestAttributes))
374 {
375 return tTransformation::cartesian_to_polar;
376 }
377 else if (CanTransform<cTransformPolarToCartesian>(oSourceAttributes, oDestAttributes))
378 {
379 return tTransformation::polar_to_cartesian;
380 }
381 else
382 {
383 return tTransformation::none;
384 }
385 }
386
387 static void Transform(tTransformation eTransformType,
388 const tAttributes& oSourceAttributes,
389 const tAttributes& oDestAttributes,
390 const size_t nCount,
391 const detail::tConstBuffer& oSourceBuffer,
392 const detail::tBuffer& oDestinationBuffer)
393 {
394 switch (eTransformType)
395 {
396 case tTransformation::cartesian_to_polar:
397 {
398 cTransformCartesianToPolar::transform(oSourceAttributes, oDestAttributes, nCount, oSourceBuffer, oDestinationBuffer);
399 break;
400 }
401 case tTransformation::polar_to_cartesian:
402 {
403 cTransformPolarToCartesian::transform(oSourceAttributes, oDestAttributes, nCount, oSourceBuffer, oDestinationBuffer);
404 break;
405 }
406 case tTransformation::copy_all:
407 {
408 detail::copy_attributes(oSourceAttributes, oDestAttributes, oSourceBuffer.pData, oDestinationBuffer.pData, nCount);
409 break;
410 }
411 case tTransformation::copy_existing:
412 {
413 detail::copy_attributes(oSourceAttributes, oDestAttributes, oSourceBuffer.pData, oDestinationBuffer.pData, nCount, true);
414 break;
415 }
416 case tTransformation::none:
417 {
418 break;
419 }
420 }
421 }
422
423 static void Transform(const cPointCloudTypeHelper::tPointCloudAccess& oSource,
425 bool bIgnoreMissingAdditionalAttributes = false)
426 {
427 if (*oSource.GetCount() != *oDestination.GetCount())
428 {
429 THROW_ERROR_DESC(ERR_INVALID_ARG,
430 "The layouts have no matching amount of points within their pointclouds (%zu vs. %zu).",
431 *oSource.GetCount(), *oDestination.GetCount());
432 }
433
434 const auto& oSourceAttributes = oSource.GetAttributes();
435 const auto& oDestAttributes = oDestination.GetAttributes();
436
437 const auto nSourceBufferSize = oSource.GetBufferSize();
438 const auto nDestBufferSize = oDestination.GetBufferSize();
439
440 // Best case scenario, we are fully layout compatible.
441 if (oSourceAttributes == oDestAttributes)
442 {
443 if (nSourceBufferSize != nDestBufferSize)
444 {
445 THROW_ERROR_DESC(ERR_MEMORY, "Can only copy buffers with same sizes (%zu vs. %zu).",
446 nSourceBufferSize, nDestBufferSize);
447 }
448
449 std::memcpy(oDestination.GetMutableData(), oSource.GetData(), nSourceBufferSize);
450 }
451 else
452 {
453 using namespace std::literals;
454 static const std::array<std::string, 6> oMandatoryNames{"x"s, "y"s, "z"s, "distance"s, "yaw"s, "pitch"s};
455
456 const auto oMandatoryAttributes = detail::filter<false>(oDestAttributes, oMandatoryNames);
457 const auto oAdditionalAttributes = detail::filter<true>(oDestAttributes, oMandatoryNames);
458
459 const auto eMandatoryTransformType = cPointCloudTransformation::GetSupportedTransformation(oSourceAttributes,
460 oMandatoryAttributes);
461 if (eMandatoryTransformType == cPointCloudTransformation::tTransformation::none)
462 {
463 THROW_ERROR_DESC(ERR_NOT_SUPPORTED, "No transformation for mandatory attributes found.");
464 }
465
466 const auto nCount = *oSource.GetCount();
467 Transform(eMandatoryTransformType,
468 oSourceAttributes,
469 oMandatoryAttributes,
470 nCount,
471 detail::tConstBuffer(oSource.GetData(), nSourceBufferSize),
472 detail::tBuffer(oDestination.GetMutableData(), nDestBufferSize));
473
474 if (!oAdditionalAttributes.empty())
475 {
476 auto eAdditionlTransformType = cPointCloudTransformation::GetSupportedTransformation(oSourceAttributes,
477 oAdditionalAttributes);
478 if (eAdditionlTransformType == cPointCloudTransformation::tTransformation::none)
479 {
480 if (!bIgnoreMissingAdditionalAttributes)
481 {
482 THROW_ERROR_DESC(ERR_NOT_SUPPORTED, "No transformation for additonal attributes found.");
483 }
484
485 eAdditionlTransformType = cPointCloudTransformation::tTransformation::copy_existing;
486 }
487
488 Transform(eAdditionlTransformType,
489 oSourceAttributes,
490 oAdditionalAttributes,
491 nCount,
492 detail::tConstBuffer(oSource.GetData(), nSourceBufferSize),
493 detail::tBuffer(oDestination.GetMutableData(), nDestBufferSize));
494 }
495 }
496 }
497
498private:
499
500 template <typename Transform>
501 static bool CanTransform(const tAttributes& oSourceAttributes,
502 const tAttributes& oDestAttributes)
503 {
504 for (const auto& strSourceElement: Transform::required_source_elements)
505 {
506 if (!oSourceAttributes.exists(strSourceElement))
507 {
508 return false;
509 }
510 }
511
512 for (const auto& strDestinationElement: Transform::required_destination_elements)
513 {
514 if (!oDestAttributes.exists(strDestinationElement) ||
515 oDestAttributes.at(strDestinationElement).type == tAttribute::tDataType::dt_computed_from_index)
516 {
517 return false;
518 }
519 }
520
521 return true;
522 }
523
524 struct cTransformCartesianToPolar
525 {
526 static constexpr std::array<const char*, 3> required_source_elements = {"x", "y", "z"};
527 static constexpr std::array<const char*, 3> required_destination_elements = {"distance", "yaw", "pitch"};
528
532 static void transform(const tAttributes& oSourceAttributes,
533 const tAttributes& oDestAttributes,
534 const size_t& nCount,
535 const detail::tConstBuffer& oSourceBuffer,
536 const detail::tBuffer& oDestinationBuffer)
537 {
538 using namespace std::literals;
539 const auto& oX = oSourceAttributes.at("x"s);
540 const auto& oY = oSourceAttributes.at("y"s);
541 const auto& oZ = oSourceAttributes.at("z"s);
542
543 const auto& oDistance = oDestAttributes.at("distance"s);
544 const auto& oYaw = oDestAttributes.at("yaw"s);
545 const auto& oPitch = oDestAttributes.at("pitch"s);
546
547 for (size_t nIdx = 0; nIdx < nCount; nIdx++)
548 {
549 // Read values
550 const auto x = detail::to_type<double>(get_attribute_value(oX, oSourceBuffer, nIdx));
551 const auto y = detail::to_type<double>(get_attribute_value(oY, oSourceBuffer, nIdx));
552 const auto z = detail::to_type<double>(get_attribute_value(oZ, oSourceBuffer, nIdx));
553
554 // Actually calculate
555 const auto distance = std::sqrt(std::pow(x, 2) + std::pow(y, 2) + std::pow(z, 2));
556 const auto yaw = std::atan2(y, x);
557 double pitch;
558 distance == 0.0 ? pitch = 0.0 : pitch = std::asin(z / distance);
559
560 // Write values
561 set_attribute_value(oDistance, oDestinationBuffer, nIdx, distance);
562 set_attribute_value(oYaw, oDestinationBuffer, nIdx, yaw);
563 set_attribute_value(oPitch, oDestinationBuffer, nIdx, pitch);
564 }
565 }
566 };
567
568 struct cTransformPolarToCartesian
569 {
570 static constexpr std::array<const char*, 3> required_source_elements = {"distance", "yaw", "pitch"};
571 static constexpr std::array<const char*, 3> required_destination_elements = {"x", "y", "z"};
572
576 static void transform(const tAttributes& oSourceAttributes,
577 const tAttributes& oDestAttributes,
578 const size_t& nCount,
579 const detail::tConstBuffer& oSourceBuffer,
580 const detail::tBuffer& oDestinationBuffer)
581 {
582 using namespace std::literals;
583
584 const auto& oDistance = oSourceAttributes.at("distance"s);
585 const auto& oYaw = oSourceAttributes.at("yaw"s);
586 const auto& oPitch = oSourceAttributes.at("pitch"s);
587
588 const auto& oX = oDestAttributes.at("x"s);
589 const auto& oY = oDestAttributes.at("y"s);
590 const auto& oZ = oDestAttributes.at("z"s);
591
592 for (size_t nIdx = 0; nIdx < nCount; ++nIdx)
593 {
594 // Read values
595 const auto distance = detail::to_type<double>(get_attribute_value(oDistance, oSourceBuffer, nIdx));
596 const auto yaw = detail::to_type<double>(get_attribute_value(oYaw, oSourceBuffer, nIdx));
597 const auto pitch = detail::to_type<double>(get_attribute_value(oPitch, oSourceBuffer, nIdx));
598
599 // Actually calculate
600 const auto x = distance * std::cos(pitch) * std::cos(yaw);
601 const auto y = distance * std::cos(pitch) * std::sin(yaw);
602 const auto z = distance * std::sin(pitch);
603
604 // Write values
605 set_attribute_value(oX, oDestinationBuffer, nIdx, x);
606 set_attribute_value(oY, oDestinationBuffer, nIdx, y);
607 set_attribute_value(oZ, oDestinationBuffer, nIdx, z);
608 }
609 }
610 };
611};
612
613} // namespace navigation
614
615using cPointCloudTransformation = navigation::cPointCloudTransformation;
616} // namespace pointcloud
617} // namespace sdk
618} // namespace devicetb
619} // namespace adtf
Namespace for functionality provided by 3.13.0.
Definition pointcloud_access.h:52
Namespace for pointcloud in ADTF-Devicetoolbox.
Definition pointcloud_access.h:49
Namespace for SDK of ADTF-Devicetoolbox.
Definition bus_database_intf.h:42
Devicetoolbox - Namespace.
Definition bus_database_intf.h:36
ADTF - Namespace.
Definition bus_database_intf.h:30
Definition pointcloud_transformation.h:58