util/geometry.h
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | /// @file | ||
| 2 | /// @brief Small vector types, vector math and axis-aligned boxes. | ||
| 3 | #pragma once | ||
| 4 | |||
| 5 | #include <cmath> | ||
| 6 | #include <limits> | ||
| 7 | #include <numbers> | ||
| 8 | |||
| 9 | namespace terraingen { | ||
| 10 | |||
| 11 | /// One degree in radians. | ||
| 12 | inline constexpr double kDegree = std::numbers::pi / 180.0; | ||
| 13 | |||
| 14 | /// A 2D point or offset in double precision. | ||
| 15 | struct Vec2d { | ||
| 16 | 21 | double x = 0.0; | |
| 17 | 20 | double y = 0.0; | |
| 18 | |||
| 19 | /// Componentwise equality. | ||
| 20 | 21 | bool operator==(const Vec2d&) const = default; | |
| 21 | }; | ||
| 22 | |||
| 23 | /// A 3D point or vector in double precision. | ||
| 24 | struct Vec3d { | ||
| 25 | 2242 | double x = 0.0; | |
| 26 | 2240 | double y = 0.0; | |
| 27 | 2239 | double z = 0.0; | |
| 28 | |||
| 29 | /// Componentwise equality. | ||
| 30 | 2242 | bool operator==(const Vec3d&) const = default; | |
| 31 | }; | ||
| 32 | |||
| 33 | /// Componentwise sum. | ||
| 34 | 159985809 | inline Vec3d operator+(const Vec3d& a, const Vec3d& b) { | |
| 35 | 159985809 | return {a.x + b.x, a.y + b.y, a.z + b.z}; | |
| 36 | } | ||
| 37 | |||
| 38 | /// Componentwise difference. | ||
| 39 | 93218782 | inline Vec3d operator-(const Vec3d& a, const Vec3d& b) { | |
| 40 | 93218782 | return {a.x - b.x, a.y - b.y, a.z - b.z}; | |
| 41 | } | ||
| 42 | |||
| 43 | /// `v` scaled by `s`. | ||
| 44 | 144305778 | inline Vec3d operator*(const Vec3d& v, double s) { | |
| 45 | 144305778 | return {v.x * s, v.y * s, v.z * s}; | |
| 46 | } | ||
| 47 | |||
| 48 | /// Dot product. | ||
| 49 | 259539736 | inline double Dot(const Vec3d& a, const Vec3d& b) { | |
| 50 | 259539736 | return a.x * b.x + a.y * b.y + a.z * b.z; | |
| 51 | } | ||
| 52 | |||
| 53 | /// Cross product. | ||
| 54 | 21203292 | inline Vec3d Cross(const Vec3d& a, const Vec3d& b) { | |
| 55 | 21203292 | return {a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x}; | |
| 56 | } | ||
| 57 | |||
| 58 | /// Euclidean length. | ||
| 59 | 22943019 | inline double Length(const Vec3d& v) { | |
| 60 | 22943019 | return std::sqrt(Dot(v, v)); | |
| 61 | } | ||
| 62 | |||
| 63 | /// `v` scaled to unit length; the zero vector stays zero. | ||
| 64 | 3433611 | inline Vec3d Normalized(const Vec3d& v) { | |
| 65 | 3433611 | const double length = Length(v); | |
| 66 | 3433611 | return length > 0.0 ? v * (1.0 / length) : v; | |
| 67 | } | ||
| 68 | |||
| 69 | /// An axis-aligned box [`minX`, `maxX`) x [`minY`, `maxY`) in surface coordinates (metres | ||
| 70 | /// on a plane, the world coordinates a raster's `GeoTransform` maps pixels to). | ||
| 71 | struct Bounds2d { | ||
| 72 | double minX = 0.0; | ||
| 73 | double minY = 0.0; | ||
| 74 | double maxX = 0.0; | ||
| 75 | double maxY = 0.0; | ||
| 76 | |||
| 77 | /// Whether the half-open box holds the point (`x`, `y`). | ||
| 78 | 1527486632 | bool Contains(double x, double y) const { | |
| 79 | 1527486632 | return x >= minX && x < maxX && y >= minY && y < maxY; | |
| 80 | } | ||
| 81 | |||
| 82 | /// The box grown by `margin` (in the box's units) on every side. | ||
| 83 | 10871283 | Bounds2d Expanded(double margin) const { | |
| 84 | 10871283 | return {minX - margin, minY - margin, maxX + margin, maxY + margin}; | |
| 85 | } | ||
| 86 | }; | ||
| 87 | |||
| 88 | /// The smallest box that contains a point: [`x`, next double above `x`) x [`y`, next double | ||
| 89 | /// above `y`). | ||
| 90 | 4508533 | inline Bounds2d PointBounds(double x, double y) { | |
| 91 | 4508533 | constexpr double kInf = std::numeric_limits<double>::infinity(); | |
| 92 | 4508533 | return {x, y, std::nextafter(x, kInf), std::nextafter(y, kInf)}; | |
| 93 | } | ||
| 94 | |||
| 95 | } // namespace terraingen | ||
| 96 |