Line data Source code
1 : // SPDX-License-Identifier: BSD-3-Clause 2 : // Copyright (c) 2023 Scipp contributors (https://github.com/scipp) 3 : /// @file 4 : /// @author Simon Heybrock 5 : #pragma once 6 : 7 : #include <cmath> 8 : #include <limits> 9 : 10 : #include "scipp/common/overloaded.h" 11 : #include "scipp/core/eigen.h" 12 : #include "scipp/core/element/arg_list.h" 13 : #include "scipp/core/time_point.h" 14 : #include "scipp/core/transform_common.h" 15 : 16 : namespace scipp::core::element { 17 : 18 : namespace { 19 : 20 : // Source: https://stackoverflow.com/a/26584177/1458281 21 236 : template <class T, class U> T safe_cast(const U x) { 22 236 : if (std::isnan(x)) 23 0 : return std::numeric_limits<T>::min(); // behavior as numpy 24 : int exp; 25 236 : std::frexp(x, &exp); 26 236 : if (std::isfinite(x) && exp <= 8 * static_cast<int>(sizeof(T)) - 1) 27 236 : return x; 28 0 : return std::signbit(x) ? std::numeric_limits<T>::min() 29 0 : : std::numeric_limits<T>::max(); 30 : } 31 : 32 : template <class T> 33 9357 : constexpr auto round = [](const auto x) { 34 : if constexpr (std::is_integral_v<T>) 35 236 : return safe_cast<T>(x < 0 ? x - 0.5 : x + 0.5); 36 : else 37 9121 : return static_cast<T>(x); 38 : }; 39 : } // namespace 40 : 41 : constexpr auto to_unit = overloaded{ 42 : arg_list<double, std::tuple<float, double>, std::tuple<int64_t, double>, 43 : std::tuple<int64_t, int64_t>, std::tuple<int32_t, double>, 44 : std::tuple<time_point, double>, std::tuple<time_point, int64_t>, 45 : std::tuple<Eigen::Vector3d, double>, 46 : std::tuple<Eigen::Affine3d, double>, 47 : std::tuple<Translation, double>>, 48 : transform_flags::expect_no_variance_arg<1>, 49 9144 : [](const units::Unit &, const units::Unit &target) { return target; }, 50 210 : [](const time_point &x, const auto &scale) { 51 210 : return time_point{round<int64_t>(x.time_since_epoch() * scale)}; 52 : }, 53 1 : [](const Eigen::Affine3d &x, const auto &scale) { 54 1 : auto out = x; 55 1 : out.translation() *= scale; 56 1 : return out; 57 : }, 58 1 : [](const Translation &x, const auto &scale) { 59 1 : return Translation(x.vector() * scale); 60 : }, 61 9147 : [](const auto &x, const auto &scale) { 62 9147 : return round<std::decay_t<decltype(x)>>(x * scale); 63 : }}; 64 : 65 : } // namespace scipp::core::element