util/radial_shape.h
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | /// @file | ||
| 2 | /// @brief `RadialShape`, a star-shaped body's radius along each direction from its centre. | ||
| 3 | #pragma once | ||
| 4 | |||
| 5 | #include "terraingen/util/geometry.h" | ||
| 6 | |||
| 7 | #include <cstddef> | ||
| 8 | #include <functional> | ||
| 9 | #include <vector> | ||
| 10 | |||
| 11 | namespace terraingen { | ||
| 12 | |||
| 13 | /// The radius of a star-shaped body (one every ray from its centre crosses once) along each | ||
| 14 | /// direction: a radial ICQ grid, the vertex labels (I, J, F) of Gaskell's implicitly connected | ||
| 15 | /// quadrilateral format (I and J from 0 to Q, faces F from 1 to 6 centred on +z, -y, -x, +y, +x | ||
| 16 | /// and -z) each at a fixed equiangular direction, holding the radius there. Within each of a | ||
| 17 | /// face's Q^2 quadrilaterals the radius is interpolated bilinearly in those angles. Labels the | ||
| 18 | /// format shares between faces have the same direction and radius, so the radius is continuous; | ||
| 19 | /// it never leaves the range of the label radii. | ||
| 20 | class RadialShape { | ||
| 21 | public: | ||
| 22 | /// The shape of `q` intervals per face edge from a radius in metres along each unit direction, | ||
| 23 | /// evaluated at every label. | ||
| 24 | /// @throws std::invalid_argument for a `q` of 0, or a radius that is not positive and finite. | ||
| 25 | static RadialShape Sample(std::size_t q, const std::function<double(const Vec3d&)>& radius); | ||
| 26 | |||
| 27 | /// The shape of `q` intervals per face edge from 6 (q + 1)^2 label radii in metres, in ICQ | ||
| 28 | /// file order (`LabelIndex`). | ||
| 29 | /// @throws std::invalid_argument for a `q` of 0, the wrong count, a radius that is not | ||
| 30 | /// positive and finite, or labels shared between faces with different radii. | ||
| 31 | RadialShape(std::size_t q, std::vector<double> radii); | ||
| 32 | |||
| 33 | /// The unit direction of label (`i`, `j`, `face`) of a grid of `q` intervals per edge, at | ||
| 34 | /// equiangular coordinates with Gaskell's face orientation: on face 1 (+z) I runs along +x and | ||
| 35 | /// J along -y; on faces 2 to 5 (-y, -x, +y, +x) J runs along -z; on face 6 (-z) I runs along +x | ||
| 36 | /// and J along +y. Labels the format shares between faces get the same direction exactly. | ||
| 37 | /// @throws std::invalid_argument unless `q` > 0, `i` and `j` <= `q` and 1 <= `face` <= 6. | ||
| 38 | static Vec3d LabelDirection(std::size_t q, std::size_t i, std::size_t j, std::size_t face); | ||
| 39 | |||
| 40 | /// The index of label (`i`, `j`, `face`) in the label radii, `face` from 1 to 6: ICQ file | ||
| 41 | /// order, face, then J, then I. | ||
| 42 | 34432982 | std::size_t LabelIndex(std::size_t i, std::size_t j, std::size_t face) const { | |
| 43 | 34432982 | return ((face - 1) * (q_ + 1) + j) * (q_ + 1) + i; | |
| 44 | } | ||
| 45 | |||
| 46 | /// The radius in metres along a nonzero `direction`. | ||
| 47 | double At(const Vec3d& direction) const; | ||
| 48 | |||
| 49 | /// Q, the intervals per face edge. | ||
| 50 | 14 | std::size_t Q() const { | |
| 51 | 14 | return q_; | |
| 52 | } | ||
| 53 | |||
| 54 | /// The label radii in metres, in the order of `LabelIndex`. | ||
| 55 | 5402 | const std::vector<double>& Radii() const { | |
| 56 | 5402 | return radii_; | |
| 57 | } | ||
| 58 | |||
| 59 | /// The smallest label radius in metres, a lower bound of `At`. | ||
| 60 | 2013 | double MinRadius() const { | |
| 61 | 2013 | return min_; | |
| 62 | } | ||
| 63 | |||
| 64 | /// The largest label radius in metres, an upper bound of `At`. | ||
| 65 | 2418 | double MaxRadius() const { | |
| 66 | 2418 | return max_; | |
| 67 | } | ||
| 68 | |||
| 69 | /// An upper bound in m^2 of the area per steradian, r^2 / (u . n), over the interpolated | ||
| 70 | /// surface: its largest value at any quadrilateral's corner with the quadrilateral's mean | ||
| 71 | /// normal (from the cross product of its diagonals), times a margin for the variation within | ||
| 72 | /// quadrilaterals. | ||
| 73 | 5100 | double MaxAreaPerSteradian() const { | |
| 74 | 5100 | return maxArea_; | |
| 75 | } | ||
| 76 | |||
| 77 | /// Whether two shapes have the same Q and label radii. | ||
| 78 | 6 | bool operator==(const RadialShape&) const = default; | |
| 79 | |||
| 80 | private: | ||
| 81 | 3 | std::size_t q_ = 0; | |
| 82 | 3 | std::vector<double> radii_; | |
| 83 | 3 | double min_ = 0.0; | |
| 84 | 3 | double max_ = 0.0; | |
| 85 | 3 | double maxArea_ = 0.0; | |
| 86 | }; | ||
| 87 | |||
| 88 | } // namespace terraingen | ||
| 89 |