MeshLib C++ Docs
Loading...
Searching...
No Matches
MRUnitInfo.h
Go to the documentation of this file.
1#pragma once
2
3#include "MRVectorTraits.h"
4#include "MRMacros.h"
5
6#include <cassert>
7#include <optional>
8
9namespace MR
10{
11
12// A stub measurement unit representing no unit.
13enum class NoUnit
14{
15 _count [[maybe_unused]]
16};
17
18// Measurement units of length.
19enum class LengthUnit
20{
21 microns,
24 meters,
25 inches,
26 feet,
27 _count [[maybe_unused]],
28};
29
30// Measurement units of angle.
31enum class AngleUnit
32{
33 radians,
34 degrees,
35 _count [[maybe_unused]],
36};
37
38// Measurement units of screen sizes.
39enum class PixelSizeUnit
40{
41 pixels,
42 _count [[maybe_unused]],
43};
44
45// Measurement units for factors / ratios.
46enum class RatioUnit
47{
48 factor, // 0..1 x
49 percents, // 0..100 %
50 _count [[maybe_unused]],
51};
52
53// Measurement units for time.
54enum class TimeUnit
55{
56 seconds,
58 _count [[maybe_unused]],
59};
60
61// Measurement units for movement speed.
72
73// Measurement units for surface area.
74enum class AreaUnit
75{
79 meters2,
80 inches2,
81 feet2,
82 _count [[maybe_unused]],
83};
84
85// Measurement units for body volume.
86enum class VolumeUnit
87{
91 meters3,
92 inches3,
93 feet3,
94 _count [[maybe_unused]],
95};
96
97// Measurement units for 1/length.
98enum class InvLengthUnit
99{
105 inv_feet,
106 _count [[maybe_unused]],
107};
108
109// A list of all unit enums, for internal use.
110#define DETAIL_MR_UNIT_ENUMS(X) X(NoUnit) X(LengthUnit) X(AngleUnit) X(PixelSizeUnit) X(RatioUnit) X(TimeUnit) X(MovementSpeedUnit) X(AreaUnit) X(VolumeUnit) X(InvLengthUnit)
111
112// All supported value types for `valueToString()`.
113// Not using `__VA_OPT__(,)` here to support legacy MSVC preprocessor.
114#ifdef __clang__
115#pragma clang diagnostic push
116#pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
117#endif
118#define DETAIL_MR_UNIT_VALUE_TYPES(X, ...) \
119 X(float ,__VA_ARGS__) X(double ,__VA_ARGS__) X(long double ,__VA_ARGS__) \
120 X(signed char ,__VA_ARGS__) X(unsigned char ,__VA_ARGS__) \
121 X(short ,__VA_ARGS__) X(unsigned short ,__VA_ARGS__) \
122 X(int ,__VA_ARGS__) X(unsigned int ,__VA_ARGS__) \
123 X(long ,__VA_ARGS__) X(unsigned long ,__VA_ARGS__) \
124 X(long long ,__VA_ARGS__) X(unsigned long long ,__VA_ARGS__)
125#ifdef __clang__
126#pragma clang diagnostic pop
127#endif
128
129// Whether `E` is one of the unit enums: NoUnit, LengthUnit, AngleUnit, ...
130template <typename T>
131concept UnitEnum =
132 #define MR_X(E) || std::same_as<T, E>
134 #undef MR_X
135
136// ---
137
138// Information about a single measurement unit.
140{
141 // This is used to convert between units.
142 // To convert from A to B, multiply by A's factor and divide by B's.
144
145 std::string_view prettyName;
146
147 // The short unit name that's placed after values.
148 // This may or may not start with a space.
149 std::string_view unitSuffix;
150};
151
152// Returns information about a single measurement unit.
153template <UnitEnum E>
154[[nodiscard]] const UnitInfo& getUnitInfo( E unit ) = delete;
155
156// ignore for bindings to prevent GCC14 error: undefined symbol: _ZN2MR11getUnitInfoITkNS_8UnitEnumENS_8TimeUnitEEERKNS_8UnitInfoET_
157#define MR_X(E) template <> [[nodiscard]] MRMESH_API MR_BIND_IGNORE const UnitInfo& getUnitInfo( E unit );
159#undef MR_X
160
161// Returns true if converting a value between units `a` and `b` doesn't change its value.
162template <UnitEnum E>
163[[nodiscard]] bool unitsAreEquivalent( E a, E b )
164{
165 return a == b || getUnitInfo( a ).conversionFactor == getUnitInfo( b ).conversionFactor;
166}
167// This version also returns true if `a` or `b` is null.
168template <UnitEnum E>
169[[nodiscard]] bool unitsAreEquivalent( const std::optional<E> &a, const std::optional<E> &b )
170{
171 return !a || !b || unitsAreEquivalent( *a, *b );
172}
173
174namespace detail::Units
175{
176 template <typename T>
177 concept Scalar = std::is_arithmetic_v<T> && !std::is_same_v<T, bool>;
178
179 template <typename T>
180 using MakeFloatingPoint = std::conditional_t<std::is_integral_v<typename VectorTraits<T>::BaseType>, typename VectorTraits<T>::template ChangeBaseType<float>, T>;
181}
182
183// Converts `value` from unit `from` to unit `to`. `value` is a scalar of a Vector2/3/4 or ImVec2/4 of them.
184// The return type matches `T` if it's not integral. If it's integral, its element type type is changed to `float`.
185// Returns min/max floating-point values unchanged.
186template <UnitEnum E, typename T>
187[[nodiscard]] detail::Units::MakeFloatingPoint<T> convertUnits( E from, E to, const T& value )
188{
189 using ReturnType = detail::Units::MakeFloatingPoint<T>;
190
191 bool needConversion = !unitsAreEquivalent( from, to );
192
193 if constexpr ( std::is_same_v<T, ReturnType> )
194 {
195 if ( !needConversion )
196 return value;
197 }
198
199 ReturnType ret{};
200
201 for ( int i = 0; i < VectorTraits<T>::size; i++ )
202 {
204
205 // Don't touch min/max floating-point values.
206 bool needElemConversion = needConversion;
207 if constexpr ( std::is_floating_point_v<typename VectorTraits<T>::BaseType> )
208 {
209 if ( needElemConversion &&
210 (
211 target <= std::numeric_limits<typename VectorTraits<T>::BaseType>::lowest() ||
212 target >= std::numeric_limits<typename VectorTraits<T>::BaseType>::max()
213 )
214 )
215 needElemConversion = false;
216 }
217
218 if ( needElemConversion )
219 target = target * getUnitInfo( from ).conversionFactor / getUnitInfo( to ).conversionFactor;
220 }
221
222 return ret;
223}
224
225// This version is a no-op if `from` or `to` is null.
226template <UnitEnum E, typename T>
227[[nodiscard]] detail::Units::MakeFloatingPoint<T> convertUnits( const std::optional<E> &from, const std::optional<E> &to, const T& value )
228{
229 if ( from && to )
230 return convertUnits( *from, *to, value );
231 else
233}
234
235} //namespace MR
#define MR_X(E)
Definition MRUnitInfo.h:157
#define DETAIL_MR_UNIT_ENUMS(X)
Definition MRUnitInfo.h:110
Definition MRUnitInfo.h:131
Definition MRUnitInfo.h:177
std::conditional_t< std::is_integral_v< typename VectorTraits< T >::BaseType >, typename VectorTraits< T >::template ChangeBaseType< float >, T > MakeFloatingPoint
Definition MRUnitInfo.h:180
Definition MRCameraOrientationPlugin.h:8
PixelSizeUnit
Definition MRUnitInfo.h:40
const UnitInfo & getUnitInfo(E unit)=delete
NoUnit
Definition MRUnitInfo.h:14
bool unitsAreEquivalent(E a, E b)
Definition MRUnitInfo.h:163
LengthUnit
Definition MRUnitInfo.h:20
RatioUnit
Definition MRUnitInfo.h:47
MovementSpeedUnit
Definition MRUnitInfo.h:63
detail::Units::MakeFloatingPoint< T > convertUnits(E from, E to, const T &value)
Definition MRUnitInfo.h:187
VolumeUnit
Definition MRUnitInfo.h:87
AreaUnit
Definition MRUnitInfo.h:75
TimeUnit
Definition MRUnitInfo.h:55
InvLengthUnit
Definition MRUnitInfo.h:99
AngleUnit
Definition MRUnitInfo.h:32
Definition MRUnitInfo.h:140
std::string_view unitSuffix
Definition MRUnitInfo.h:149
std::string_view prettyName
Definition MRUnitInfo.h:145
float conversionFactor
Definition MRUnitInfo.h:143
Definition MRMesh/MRVectorTraits.h:15
static constexpr auto && getElem(int i, U &&value)
Definition MRMesh/MRVectorTraits.h:29
T BaseType
Definition MRMesh/MRVectorTraits.h:18