~aleteoryx/muditaos

muditaos/module-utils/utility/ValueScaler.hpp -rw-r--r-- 1.9 KiB
a405cad6Aleteoryx trim readme 6 days ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/blob/master/LICENSE.md

#pragma once

#include <cstdint>
#include <algorithm>
#include <optional>
#include <cmath>
#include <array>

namespace utils
{
    template <typename T>
    struct Range
    {
        T min;
        T max;
    };

    /// Perform scaling of the input value based on the input&output ranges. If the input values is not contained within
    /// the provided input range return std::nullopt.
    template <typename T>
    std::optional<T> scale_value(const Range<T> inputRange, const Range<T> outputRange, const T input)
    {
        if (input > inputRange.max || input < inputRange.min) {
            return {};
        }

        const auto inRangeVal  = inputRange.max - inputRange.min;
        const auto outRangeVal = outputRange.max - outputRange.min;

        if (outRangeVal == 0 || inRangeVal == 0) {
            return outputRange.min;
        }
        float slope = 1.0 * (outRangeVal) / (inRangeVal);
        auto output = outputRange.min + slope * (input - inputRange.min);

        return static_cast<T>(std::floor(output));
    }

    template <typename T>
    struct Entry
    {
        const Range<T> input;
        const Range<T> output;
    };

    /// Try to find the given input value in the the entries array. If the value is found, perform scaling and then
    /// return the scaled value. If the value is not found, return std::nullopt.
    template <typename T, const size_t N>
    [[nodiscard]] std::optional<T> find_and_scale_value(const std::array<Entry<T>, N> &entries, const T val)
    {
        auto result = std::find_if(
            entries.begin(), entries.end(), [val](const auto &e) { return val >= e.input.min && val <= e.input.max; });

        if (result != entries.end()) {
            return scale_value(result->input, result->output, val);
        }

        return {};
    }
} // namespace utils