feat: quantity_kind and quantity_point_kind
This commit is contained in:
1 parent
384f4b2624
commit
6bf09aa646
32 files changed
+2757
-202
No files matched your search
@@ -4,7 +4,7 @@ Basic Concepts
|
||||
==============
|
||||
|
||||
The most important concepts in the library are `Unit`, `Dimension`,
|
||||
`Quantity`, and `QuantityPoint`:
|
||||
`Quantity`, `QuantityPoint`, `QuantityKind`, and `QuantityPointKind`:
|
||||
|
||||
.. image:: /_static/img/concepts.png
|
||||
:align: center
|
||||
@@ -18,15 +18,35 @@ The most important concepts in the library are `Unit`, `Dimension`,
|
||||
[exponent<Dimension, Num, Den>]<-[derived_dimension<Child, Unit, Exponent...>]
|
||||
]
|
||||
|
||||
[<abstract>Quantity|
|
||||
[quantity<Dimension, Unit, Rep>]
|
||||
]
|
||||
|
||||
[<abstract>QuantityPoint|
|
||||
[quantity_point<Dimension, Unit, Rep>]
|
||||
]
|
||||
|
||||
[<abstract>QuantityKind|
|
||||
[quantity_kind<Kind, Unit, Rep>]
|
||||
]
|
||||
|
||||
[<abstract>QuantityPointKind|
|
||||
[quantity_point_kind<PointKind, Unit, Rep>]
|
||||
]
|
||||
|
||||
[<abstract>Unit]<-[Dimension]
|
||||
[Dimension]<-[Quantity]
|
||||
[Unit]<-[Quantity]
|
||||
[Quantity]<-[QuantityPoint]
|
||||
|
||||
[<abstract>Kind]<-[QuantityKind]
|
||||
[Dimension]<-[Kind]
|
||||
[Quantity]<-[QuantityKind]
|
||||
|
||||
[<abstract>PointKind]<-[QuantityPointKind]
|
||||
[Kind]<-[PointKind]
|
||||
[QuantityKind]-<[QuantityPointKind]
|
||||
|
||||
`Unit` is a basic building block of the library. Every dimension works with
|
||||
a concrete hierarchy of units. Such hierarchy defines a reference unit and
|
||||
often a few scaled versions of it.
|
||||
@@ -40,3 +60,7 @@ derived dimensions.
|
||||
specific representation.
|
||||
|
||||
`QuantityPoint` is an absolute `Quantity` with respect to some origin.
|
||||
|
||||
`QuantityKind` is a `Quantity` with more specific usage.
|
||||
|
||||
`QuantityPointKind` is an absolute `QuantityKind` with respect to some origin.
|
||||
@@ -56,7 +56,8 @@ Explicit
|
||||
--------
|
||||
|
||||
Explicit conversions are available with
|
||||
the `quantity_cast` and `quantity_point_cast` function templates.
|
||||
the `quantity_cast`, `quantity_point_cast`,
|
||||
`quantity_kind_cast`, and `quantity_point_kind_cast` function templates.
|
||||
They are especially useful to force a truncating conversion across quantities of the same
|
||||
dimension for integral representation types and ratios that may cause precision loss::
|
||||
|
||||
@@ -99,6 +100,13 @@ or a specific target `quantity_point`::
|
||||
|
||||
std::cout << "Point: " << quantity_point_cast<decltype(quantity_point{0_q_m})>(d) << '\n';
|
||||
|
||||
For a single explicit template argument,
|
||||
`quantity_point_kind_cast` is a superset of `quantity_kind_cast`,
|
||||
which is also a superset of `quantity_cast`.
|
||||
For the (dimension, unit) pair of explicit arguments case of `quantity_cast`,
|
||||
`quantity_point_kind_cast` and `quantity_kind_cast`
|
||||
accept a `PointKind` and `Kind` instead of a `Dimension`, respectively.
|
||||
|
||||
.. seealso::
|
||||
|
||||
For more information on conversion and casting and on how to extend the above "integral"
|
||||
@@ -115,14 +123,14 @@ represent numbers it would be highly uncomfortable to every time type::
|
||||
|
||||
const auto d1 = 10_q_km;
|
||||
const auto d2 = 3_q_km;
|
||||
if(d1 / d2 > dimensionless<one, 2>) {
|
||||
if(d1 / d2 > dimensionless<one>(2)) {
|
||||
// ...
|
||||
}
|
||||
|
||||
or::
|
||||
|
||||
const auto fill_time_left = (box.height / box.fill_level(measured_mass) -
|
||||
dimensionless<one, 1>) * fill_time;
|
||||
dimensionless<one>(1)) * fill_time;
|
||||
|
||||
This is why it was decided to allow the ``dimensionless<one>`` quantity of any
|
||||
representation type to be implicitly constructible from this representation type.
|
||||
@@ -147,7 +155,7 @@ could be ambiguous. For example::
|
||||
return d1 / d2 + 1;
|
||||
}
|
||||
|
||||
As long as we can reason about what such code means for ``foo(10_q_km, 2_q_km)`` it is not that obvious
|
||||
As long as we can reason about what such code means for ``foo(10_q_km, 2_q_km)`` it is not that obvious
|
||||
at all in the case of ``foo(10_q_cm, 2_q_ft)``. To make such code to compile for every case we have to
|
||||
either change the type of the resulting unit to the one having ``ratio(1)`` (:term:`coherent derived unit`)::
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ probably will always end up in a quantity of a yet another dimension:
|
||||
|
||||
However, please note that there is an exception from the above rule.
|
||||
In case we divide the same dimensions, or multiply by the inverted
|
||||
dimension, than we will end up with just a scalable number type:
|
||||
dimension, than we will end up with just a dimensionless quantity:
|
||||
|
||||
.. code-block::
|
||||
:emphasize-lines: 4-5
|
||||
@@ -58,8 +58,23 @@ dimension, than we will end up with just a scalable number type:
|
||||
Time auto dur1 = 10_q_s;
|
||||
Time auto dur2 = 2_q_s;
|
||||
Frequency auto fr1 = 5_q_Hz;
|
||||
QuantityValue auto v1 = dur1 / dur2; // 5
|
||||
QuantityValue auto v2 = dur1 * fr1; // 50
|
||||
Dimensionless auto v1 = dur1 / dur2; // quantity(5)
|
||||
Dimensionless auto v2 = dur1 * fr1; // quantity(50)
|
||||
|
||||
Quantity kinds behave the same as quantities for addition, substraction, and
|
||||
multiplication with, and division by a :term:`scalable number`.
|
||||
|
||||
Multiplication and divison with a quantity
|
||||
(but not a quantity kind) is allowed.
|
||||
The result is a quantity kind with the appropiate dimension
|
||||
and related to the original quantity kind.
|
||||
|
||||
struct height : kind<height, dim_length> {};
|
||||
struct rate_of_climb : derived_kind<rate_of_climb, height, dim_speed> {};
|
||||
|
||||
quantity_kind h(height{}, 100 * m);
|
||||
quantity_point_kind rate = h / (25 * s);
|
||||
// `quantity_point_kind<rate_of_climb, si::metre_per_second, int>(4 * m / s)`
|
||||
|
||||
Quantity points have a more restricted set of operations.
|
||||
Quantity points can't be added together,
|
||||
@@ -81,7 +96,7 @@ The result will always be a quantity point of the same dimension:
|
||||
|
||||
.. code-block::
|
||||
:emphasize-lines: 3
|
||||
|
||||
|
||||
Length auto dist1 = 2_q_m;
|
||||
Length auto dist2 = 1_q_m;
|
||||
auto res1 = dist1 - quantity_point{dist2}; // ERROR
|
||||
@@ -98,6 +113,9 @@ The result is a relative quantity of the same dimension:
|
||||
|
||||
That's it! You can't multiply nor divide quantity points with anything else.
|
||||
|
||||
The same restrictions of a quantity point with respect to its quantity
|
||||
apply to a quantity point kind with respect to its quantity kind.
|
||||
|
||||
|
||||
Base Dimensions
|
||||
---------------
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
.. namespace:: units
|
||||
|
||||
Quantity Kinds
|
||||
==============
|
||||
|
||||
A quantity kind is a quantity of more specific usage.
|
||||
It is represented in the library with a `quantity_kind` class template.
|
||||
|
||||
|
||||
.. _quantity-point-construction:
|
||||
|
||||
Kind creation
|
||||
-------------
|
||||
|
||||
We need a `kind` to represent the more specific usage of a quantity.
|
||||
|
||||
struct radius : kind<radius, si::dim_length> {};
|
||||
|
||||
Quantities of kind `radius` represent a radius.
|
||||
They are clearly distinct from more generic usages of length quantities.
|
||||
|
||||
|
||||
Construction
|
||||
------------
|
||||
|
||||
To create the quantity kind object from a `quantity` we just have to pass
|
||||
the value to the `quantity_kind` class template constructor::
|
||||
|
||||
quantity_kind<radius, si::kilometre, double> d(123 * km);
|
||||
|
||||
.. note::
|
||||
|
||||
As the constructor without the kind argument is explicit,
|
||||
the quantity object can be created from a quantity only via
|
||||
`direct initialization <https://en.cppreference.com/w/cpp/language/direct_initialization>`_.
|
||||
This is why the code below using
|
||||
`copy initialization <https://en.cppreference.com/w/cpp/language/copy_initialization>`_
|
||||
**does not compile**::
|
||||
|
||||
quantity_kind<radius, si::kilometre, double> d = 123 * km; // ERROR
|
||||
|
||||
|
||||
Differences to quantity
|
||||
-----------------------
|
||||
|
||||
Unlike `quantity`, the library provides:
|
||||
|
||||
- no kinds, such as ``radius`` or ``width``, therefore
|
||||
* no UDLs or unit constants,
|
||||
* no kind-specific concepts, such as ``Radius``,
|
||||
(there's the generic `QuantityKind` and kind-specifiable `QuantityKindOf`),
|
||||
- a slightly different set of operations on quantity kinds
|
||||
(see the :ref:`Dimensions` chapter)
|
||||
|
||||
Quantity point kind
|
||||
-------------------
|
||||
|
||||
A quantity point kind is the analogous of a quantity point for quantity kinds.
|
||||
(see the :ref:`Quantity Points` chapter).
|
||||
|
||||
They are represented in the library with a `quantity_point_kind` class template.
|
||||
|
||||
First, we need a `point_kind` for a `kind`.
|
||||
|
||||
struct width : kind<width, si::dim_length> {};
|
||||
struct x_coordinate : point_kind<x_coordinate, width> {};
|
||||
|
||||
Now x coordinates can be constructed:
|
||||
|
||||
quantity_point_kind<x_coordinate, si::metre, int> auto x_pos(123 * m);
|
||||
// `QuantityPointKindOf<x_coordinate>` with `x_pos.relative()`
|
||||
// equal to `quantity_kind<width, si::metre, int>(123 * m)`
|
||||
@@ -40,4 +40,4 @@ Unlike `quantity`, the library provides:
|
||||
- no dimension-specific concepts, such as ``LengthPoint``
|
||||
(there's the dimension-agnostic `QuantityPoint`),
|
||||
- a more limited set of operations on quantity points
|
||||
(see the :ref:`Conversions and Casting` chapter)
|
||||
(see the :ref:`Dimensions` chapter)
|
||||
@@ -8,13 +8,14 @@ also tries really hard to print any quantity in the most user friendly way.
|
||||
|
||||
.. note::
|
||||
|
||||
The library provides no text output for quantity points.
|
||||
The library provides no text output for
|
||||
quantity points or quantity (point) kinds.
|
||||
|
||||
Output Streams
|
||||
--------------
|
||||
|
||||
.. tip::
|
||||
|
||||
|
||||
The streaming support is provided via the ``<units/quantity_io.h>`` header
|
||||
file.
|
||||
|
||||
|
||||
Reference in new issue
Block a user