docs: "The Affine Space" chapter updated to reflect the latest changes

This commit is contained in:
Mateusz Pusz
2023-08-03 13:08:09 +02:00
parent 794ac2fa67
commit b8002d1940

View File

@@ -79,8 +79,8 @@ the **mp-units** library, a `quantity_point` gets a `quantity` in its constructo
- can be obtained with the `relative()` member function. - can be obtained with the `relative()` member function.
```cpp ```cpp
constexpr quantity_point<isq::altitude[m]> everest_base_camp{5364 * m}; constexpr quantity_point<isq::altitude[m]> everest_base_camp_alt{5364 * m};
static_assert(everest_base_camp.relative() == 5364 * m); static_assert(everest_base_camp_alt.relative() == 5364 * m);
``` ```
!!! note !!! note
@@ -89,7 +89,7 @@ static_assert(everest_base_camp.relative() == 5364 * m);
direct initialization. This is why the code below that uses copy initialization does not compile: direct initialization. This is why the code below that uses copy initialization does not compile:
```cpp ```cpp
quantity_point<isq::altitude[m]> everest_base_camp = 5364 * m; // ERROR quantity_point<isq::altitude[m]> everest_base_camp_alt = 5364 * m; // ERROR
``` ```
In the **mp-units** library, the origin is either provided implicitly (as above) or can be predefined In the **mp-units** library, the origin is either provided implicitly (as above) or can be predefined
@@ -98,22 +98,56 @@ by the user and then provided explicitly as the `quantity_point` class template
```cpp ```cpp
constexpr struct mean_sea_level : absolute_point_origin<isq::altitude> {} mean_sea_level; constexpr struct mean_sea_level : absolute_point_origin<isq::altitude> {} mean_sea_level;
constexpr quantity_point<isq::altitude[m], mean_sea_level> everest_base_camp{5364 * m}; constexpr quantity_point<isq::altitude[m], mean_sea_level> everest_base_camp_alt{5364 * m};
static_assert(everest_base_camp.relative() == 5364 * m); static_assert(everest_base_camp_alt.relative() == 5364 * m);
```
!!! note
The `mean_sea_level` and the default `absolute_point_origin<isq::altitude>` origins are distinct from
each other, which means that _points_ defined with them are not compatible (can't be subtracted or
compared).
### Class Template Argument Deduction (CTAD)
Typing the entire `quantity_point` type may sometimes be quite verbose. Also, please note that we
"accidentally" used `double` as a representation type in the above examples, even though we operated
only on integral values. This was done for the convenience of saving typing.
To improve the developer's experience, the `quantity_point` class template comes with the user-defined
class template argument deduction guides. Thanks to them, the above definitions can be rewritten as
follows:
- implicit default origin
```cpp
constexpr quantity_point everest_base_camp_alt{isq::altitude(5364 * m)};
```
- explicit origin
```cpp
constexpr quantity_point everest_base_camp_alt{isq::altitude(5364 * m), mean_sea_level};
``` ```
### Stacking _point_ origins ### Relative _point_ origins
We often do not have one ultimate "zero" point when we measure things. We often do not have only one ultimate "zero" point when we measure things.
Continuing the Mount Everest trip example above, measuring all daily hikes from the `mean_sea_level` Continuing the Mount Everest trip example above, measuring all daily hikes from the `mean_sea_level`
might not be efficient. Maybe we know that we are not good climbers, so all our climbs can be might not be efficient. Maybe we know that we are not good climbers, so all our climbs can be
represented with an 8-bit integer type which will allow us to save memory in our database of climbs? represented with an 8-bit integer type which will allow us to save memory in our database of climbs?
Why not use `everest_base_camp` as our reference point? Why not use `everest_base_camp_alt` as our reference point?
It turns out that in the **mp-units** library, you can use a predefined at compile-time `quantity_point` For this purpose, we can define a `relative_point_origin` in the following way:
as an origin as well:
```cpp
constexpr struct everest_base_camp : relative_point_origin<everest_base_camp_alt> {} everest_base_camp;
```
The above can be used as an origin for subsequent _points_:
```cpp ```cpp
constexpr quantity_point<isq::altitude[m], everest_base_camp, std::uint8_t> first_climb_alt{42 * m}; constexpr quantity_point<isq::altitude[m], everest_base_camp, std::uint8_t> first_climb_alt{42 * m};
@@ -127,13 +161,7 @@ we can either:
- add the two relative heights from both points - add the two relative heights from both points
```cpp ```cpp
static_assert(first_climb_alt.relative() + everest_base_camp.relative() == 5406 * m); static_assert(first_climb_alt.relative() + everest_base_camp_alt.relative() == 5406 * m);
```
- do the same but in a slightly different way:
```cpp
static_assert(first_climb_alt.relative() + first_climb_alt.point_origin.relative() == 5406 * m);
``` ```
- call `absolute()` member function - call `absolute()` member function
@@ -143,6 +171,27 @@ we can either:
``` ```
### Converting between different representations of the same _point_
As we might represent the same _point_ with _vectors_ from various origins, the **mp-units** library
provides facilities to convert the _point_ to the `quantity_point` class templates expressed in terms
of different origins.
For this purpose, we can either use:
- a converting constructor:
```cpp
static_assert(quantity_point<isq::altitude[m], mean_sea_level>{first_climb_alt}.relative() == 5406 * m);
```
- a dedicated conversion interface:
```cpp
constexpr QuantityPoint auto qp = first_climb_alt.point_from(mean_sea_level);
static_assert(qp.relative() == 5406 * m);
```
### _Point_ arithmetics ### _Point_ arithmetics
Let's assume we are going to attend the CppCon conference that is hosted in Aurora, CO, and we Let's assume we are going to attend the CppCon conference that is hosted in Aurora, CO, and we
@@ -178,7 +227,7 @@ quantity<isq::distance[km]> taxi2 = cppcon_venue - den_airport;
quantity<isq::distance[km]> taxi = taxi1 + taxi2; quantity<isq::distance[km]> taxi = taxi1 + taxi2;
``` ```
Now it will print the results: Now if we will print the results:
```cpp ```cpp
std::cout << "Total distance: " << total << "\n"; std::cout << "Total distance: " << total << "\n";
@@ -197,28 +246,28 @@ Taxi distance: 31.2544 km
### Temperature support ### Temperature support
Another important example of [stacking point origins](#stacking-point-origins) is support Another important example of [relative point origins](#relative-point-origins) is support
of temperature quantity points in units different than kelvin [`K`]. of temperature quantity points in units different than kelvin [`K`].
For example, the degree Celsius scale can be implemented as follows: For example, the degree Celsius scale can be implemented as follows:
```cpp ```cpp
constexpr auto ice_point = quantity_point<isq::thermodynamic_temperature[K]>{273.15 * K}; constexpr struct ice_point : relative_point_origin<quantity_point<isq::thermodynamic_temperature[K]>{273.15 * K}> {} ice_point;
using Celsius_point = quantity_point<isq::Celsius_temperature[deg_C], ice_point>; using Celsius_point = quantity_point<isq::thermodynamic_temperature[deg_C], ice_point>;
``` ```
!!! note !!! note
While [stacking point origins](#stacking-point-origins) we can use not only different Notice that while stacking point origins we can use not only different representation types but
representation types but also different units for an origin and a _point_. also different units for an origin and a _point_.
With the above, for example, if we want to implement a room temperature controller, we can type: With the above, for example, if we want to implement a room temperature controller, we can type:
```cpp ```cpp
constexpr Celsius_point room_reference_temperature{21 * deg_C}; constexpr struct room_reference_temperature : relative_point_origin<Celsius_point{21 * deg_C}> {} room_reference_temperature;
using room_temperature = quantity_point<isq::Celsius_temperature[deg_C], room_reference_temperature>; using room_temperature = quantity_point<isq::thermodynamic_temperature[deg_C], room_reference_temperature>;
constexpr auto step_delta = isq::Celsius_temperature(0.5 * deg_C); constexpr auto step_delta = isq::thermodynamic_temperature(0.5 * deg_C);
constexpr int number_of_steps = 6; constexpr int number_of_steps = 6;
room_temperature room_default{}; room_temperature room_default{};
@@ -261,7 +310,3 @@ The following operations are not allowed in the affine space:
The usage of `quantity_point`, and affine space types in general, improves expressiveness and The usage of `quantity_point`, and affine space types in general, improves expressiveness and
type-safety of the code we write. type-safety of the code we write.
## Handling temperature points