Phyth v0.1.0
A dimensional safe C++ header-only mechanics and electromagnetics simulation library.
Loading...
Searching...
No Matches
Dimension.hpp
Go to the documentation of this file.
1#ifndef PHYTH_DIMENSION_HPP
2#define PHYTH_DIMENSION_HPP
3
4#include <ratio>
5#include <type_traits>
6#include <string>
7#include <tuple>
8#include <cmath>
9
10namespace Phyth {
24 template<typename... Ratios>
25 struct Dimension {
26 static constexpr int size = sizeof...(Ratios);
27 using ratio_tuple = std::tuple<Ratios...>;
28 };
29
30 static_assert(Dimension<>::size == 0, "Dimension requires exactly 7 ratios");
31
38 template<int N, typename D>
40
41 template<int N, typename... Ratios>
42 struct DimComponent<N, Dimension<Ratios...> > {
43 static_assert(N < sizeof...(Ratios), "Index out of range");
44 using type = std::tuple_element_t<N, std::tuple<Ratios...> >;
45 };
46
50 template<int N, typename D>
52
58 template<typename D1, typename D2>
59 struct DimMul;
60
61 template<typename... R1, typename... R2>
62 struct DimMul<Dimension<R1...>, Dimension<R2...> > {
63 static_assert(sizeof...(R1) == sizeof...(R2), "Dimension count mismatch");
65 };
66
70 template<typename D1, typename D2>
71 using DimMulT = typename DimMul<D1, D2>::type;
72
78 template<typename D1, typename D2>
79 struct DimDiv;
80
81 template<typename... R1, typename... R2>
82 struct DimDiv<Dimension<R1...>, Dimension<R2...> > {
83 static_assert(sizeof...(R1) == sizeof...(R2), "Dimension count mismatch");
85 };
86
90 template<typename D1, typename D2>
91 using DimDivT = typename DimDiv<D1, D2>::type;
92
100 template<int N, typename D>
101 struct DimRoot;
102
103 template<int N, typename... Ratios>
104 struct DimRoot<N, Dimension<Ratios...> > {
105 static_assert(N > 0, "Root index must be positive");
107 };
108
112 template<int N, typename D>
114
120 template<typename D>
121 struct DimRcp;
122
123 template<typename... Ratios>
124 struct DimRcp<Dimension<Ratios...> > {
125 using type = Dimension<std::ratio_multiply<Ratios, std::ratio<-1> >...>;
126 };
127
131 template<typename D>
132 using DimRcpT = typename DimRcp<D>::type;
133
137 template<typename D1, typename D2>
138 struct DimEqual;
139
140 template<typename... R1, typename... R2>
141 struct DimEqual<Dimension<R1...>, Dimension<R2...> > {
142 static constexpr bool value = (std::is_same_v<R1, R2> && ...);
143 };
144
148 template<typename D1, typename D2>
149 inline constexpr bool dim_equal_v = DimEqual<D1, D2>::value;
150
154 template<typename>
155 struct is_dim : std::false_type {
156 };
157
158 template<typename... Ratios>
159 struct is_dim<Dimension<Ratios...> > : std::true_type {
160 };
161
165 template<typename T>
166 inline constexpr bool is_dim_v = is_dim<T>::value;
167
174 inline std::string formatPower(const double power) {
175 if (std::floor(power + 0.5) == power) {
176 return std::to_string(static_cast<int>(power));
177 }
178 return std::to_string(power);
179 }
180
193 template<typename D>
195
196 template<typename... Ratios>
197 struct DimToString<Dimension<Ratios...> > {
198 static std::string value() {
199 const std::string names[] = {"m", "kg", "s", "A", "K", "mol", "cd"};
200
201 std::string numerator, denominator;
202 bool has_num = false, has_den = false;
203 int idx = 0;
204
205 ((void) [&] {
206 const double power = static_cast<double>(Ratios::num) / Ratios::den;
207 if (power == 0) {
208 ++idx;
209 return;
210 }
211
212 const std::string unit = names[idx];
213 std::string power_str;
214 if (power != 1 && power != -1) {
215 power_str = formatPower(power < 0 ? -power : power);
216 }
217
218 if (power > 0) {
219 if (has_num) numerator += '*';
220 numerator += unit;
221 if (power != 1) {
222 numerator += "^" + power_str;
223 }
224 has_num = true;
225 } else {
226 if (has_den) denominator += '*';
227 denominator += unit;
228 if (power != -1) {
229 denominator += "^" + power_str;
230 }
231 has_den = true;
232 }
233 ++idx;
234 }(), ...);
235
236 std::string result;
237 if (has_num) {
238 result += numerator;
239 } else if (has_den) {
240 result += '1';
241 }
242
243 if (has_den) {
244 result += '/';
245 if (denominator.find('*') != std::string::npos) {
246 result += "(" + denominator + ")";
247 } else {
248 result += denominator;
249 }
250 }
251
252 return result;
253 }
254 };
255
257 std::ratio<0>, std::ratio<0>, std::ratio<0>,
258 std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<0>
259 >;
260
262 std::ratio<1>, std::ratio<0>, std::ratio<0>,
263 std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<0>
264 >;
265
267 std::ratio<0>, std::ratio<1>, std::ratio<0>,
268 std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<0>
269 >;
270
272 std::ratio<0>, std::ratio<0>, std::ratio<1>,
273 std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<0>
274 >;
275
277 std::ratio<0>, std::ratio<0>, std::ratio<0>,
278 std::ratio<1>, std::ratio<0>, std::ratio<0>, std::ratio<0>
279 >;
280
282 std::ratio<0>, std::ratio<0>, std::ratio<0>,
283 std::ratio<0>, std::ratio<1>, std::ratio<0>, std::ratio<0>
284 >;
285
287 std::ratio<0>, std::ratio<0>, std::ratio<0>,
288 std::ratio<0>, std::ratio<0>, std::ratio<1>, std::ratio<0>
289 >;
290
292 std::ratio<0>, std::ratio<0>, std::ratio<0>,
293 std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<1>
294 >;
295
326
332 template<typename UnitT>
334 static constexpr bool value = std::is_same_v<typename UnitT::DimensionT, Dimensionless>;
335 };
336
340 template<typename UnitT>
342
349 template<int N, typename D>
350 struct DimPower;
351
352 template<int N, typename... Ratios>
353 struct DimPower<N, Dimension<Ratios...> > {
354 static constexpr double value = static_cast<double>(
355 std::tuple_element_t<N, std::tuple<Ratios...> >::num
356 ) / std::tuple_element_t<N, std::tuple<Ratios...> >::den;
357 };
358
366 template<int N, typename D>
367 inline constexpr double dim_power_v = DimPower<N, D>::value;
368
375 template<int P, typename D>
377 using type = DimMulT<D, typename DimPowerHelper<P - 1, D>::type>;
378 };
379
380 template<typename D>
381 struct DimPowerHelper<0, D> {
383 };
384
385 template<int Power, typename D>
388 };
389
397 template<int Power, typename D>
399}
400
401#endif // PHYTH_DIMENSION_HPP
typename DimPowerType< Power, D >::type DimPowerTypeT
Convenience alias for DimPowerType.
DimDivT< Mass, Time > DampingCoefficient
constexpr bool dim_equal_v
Convenience variable template for DimEqual.
DimDivT< Force, Volume > ForceDensity
DimDivT< Energy, Time > Power
DimMulT< Mass, Area > MomentOfInertia
typename DimDiv< D1, D2 >::type DimDivT
Convenience alias for DimDiv.
Definition Dimension.hpp:91
DimDivT< Force, Charge > ElectricFieldIntensity
DimDivT< Dimensionless, Time > Frequency
DimDivT< Force, DimMulT< Length, Length > > Pressure
DimDivT< Voltage, DimDivT< ElectricCurrent, Time > > Inductance
std::tuple_element_t< N, std::tuple< Ratios... > > type
Definition Dimension.hpp:44
typename DimRcp< D >::type DimRcpT
Convenience alias for DimRcp.
DimDivT< Mass, Volume > MassDensity
DimDivT< Velocity, Time > Acceleration
constexpr bool is_dimensionless_v
Convenience variable template for is_dimensionless.
typename DimMul< D1, D2 >::type DimMulT
Convenience alias for DimMul.
Definition Dimension.hpp:71
std::string formatPower(const double power)
Format a floating-point exponent for string output.
DimMulT< Voltage, Time > MagneticFlux
typename DimPowerHelper< Power, D >::type type
DimMulT< Length, Area > Volume
DimMulT< Time, ElectricCurrent > Charge
DimDivT< MagneticFlux, DimMulT< Length, Length > > MagneticFluxDensity
constexpr double dim_power_v
Convenience variable template for DimPower.
Dimension< std::ratio< 0 >, std::ratio< 0 >, std::ratio< 0 >, std::ratio< 0 >, std::ratio< 0 >, std::ratio< 0 >, std::ratio< 0 > > Dimensionless
constexpr bool is_dim_v
Convenience variable template for is_dim.
DimDivT< Force, Length > TranslationalStiffness
DimMulT< ElectricCurrent, Area > MagneticDipoleMoment
DimMulT< Mass, Acceleration > Force
DimMulT< D, typename DimPowerHelper< P - 1, D >::type > type
DimDivT< Charge, Voltage > Capacitance
DimDivT< Charge, Length > LinearChargeDensity
DimDivT< Dimensionless, Time > AngularVelocity
DimDivT< Charge, Area > SurfaceChargeDensity
DimDivT< Charge, Volume > BulkChargeDensity
DimDivT< Length, Time > Velocity
DimDivT< Voltage, ElectricCurrent > Resistance
DimDivT< Capacitance, Length > ElectricPotential
typename DimRoot< N, D >::type DimRootT
Convenience alias for DimRoot.
DimDivT< Energy, Volume > EnergyDensity
typename DimComponent< N, D >::type DimComponentT
Convenience alias for DimComponent.
Definition Dimension.hpp:51
DimMulT< Length, Length > Area
DimMulT< Charge, Length > ElectricDipoleMoment
DimMulT< Force, Length > Energy
DimDivT< Power, ElectricCurrent > Voltage
Extract the N-th base exponent from a Dimension.
Definition Dimension.hpp:39
Divide one dimension by another: exponent-wise subtraction.
Definition Dimension.hpp:79
Check if two dimensions are identical (all exponents equal)
Add two dimensions: exponent-wise addition.
Definition Dimension.hpp:59
Extract the numeric value of the N-th exponent from a Dimension.
Raise a Dimension to an integer power.
Reciprocal of a dimension: negate all exponents.
Take the N-th root of a dimension: divide all exponents by N.
Convert a Dimension to a human-readable string.
Compile-time physical dimension as 7 SI base exponents.
Definition Dimension.hpp:25
std::tuple< Ratios... > ratio_tuple
Definition Dimension.hpp:27
static constexpr int size
Definition Dimension.hpp:26
Trait: check if a type is a Dimension instantiation.
Trait: check if a quantity's dimension is dimensionless.
static constexpr bool value