Branch data Line data Source code
1 : : #pragma once 2 : : 3 : : #include <cmath> 4 : : #include <type_traits> 5 : : 6 : : namespace Geometry 7 : : { 8 : : 9 : : template <typename CoordinateValue> 10 : : struct Vector { 11 : : CoordinateValue x = {0}; 12 : : CoordinateValue y = {0}; 13 : : 14 : 41 : constexpr Vector(CoordinateValue x, CoordinateValue y) 15 : 41 : : x(x) 16 : 41 : , y(y) 17 : : { 18 : 41 : } 19 : : 20 : 1 : auto constexpr operator+=(Vector const& rhs) -> Vector& 21 : : { 22 : 1 : x += rhs.x; 23 : 1 : y += rhs.y; 24 : 1 : return *this; 25 : : } 26 : : 27 : 1 : constexpr friend auto operator+(Vector lhs, Vector const& rhs) -> Vector 28 : : { 29 : 1 : lhs += rhs; 30 : 1 : return lhs; 31 : : } 32 : : 33 : 17 : auto constexpr operator-=(Vector const& rhs) -> Vector& 34 : : { 35 : 17 : x -= rhs.x; 36 : 17 : y -= rhs.y; 37 : 17 : return *this; 38 : : } 39 : : 40 : 17 : friend auto constexpr operator-(Vector lhs, Vector const& rhs) -> Vector 41 : : { 42 : 17 : lhs -= rhs; 43 : 17 : return lhs; 44 : : } 45 : : 46 : 2 : auto constexpr operator*=(CoordinateValue const& rhs) -> Vector& 47 : : { 48 : 2 : x *= rhs; 49 : 2 : y *= rhs; 50 : 2 : return *this; 51 : : } 52 : : 53 : 1 : friend auto constexpr operator*(Vector lhs, CoordinateValue const& rhs) -> Vector 54 : : { 55 : 1 : lhs *= rhs; 56 : 1 : return lhs; 57 : : } 58 : : 59 : 1 : friend auto constexpr operator*(CoordinateValue const& lhs, Vector rhs) -> Vector 60 : : { 61 : 1 : rhs *= lhs; 62 : 1 : return rhs; 63 : : } 64 : : 65 : 1 : auto constexpr operator/=(CoordinateValue const& rhs) -> Vector& 66 : : { 67 : 1 : x /= rhs; 68 : 1 : y /= rhs; 69 : 1 : return *this; 70 : : } 71 : : 72 : 1 : friend auto constexpr operator/(Vector lhs, CoordinateValue const& rhs) -> Vector 73 : : { 74 : 1 : lhs /= rhs; 75 : 1 : return lhs; 76 : : } 77 : : 78 : 6 : friend auto constexpr operator==(Vector const& lhs, Vector const& rhs) -> bool 79 : : { 80 : 6 : return lhs.x == rhs.x && lhs.y == rhs.y; 81 : : } 82 : : 83 : 4 : friend auto constexpr operator<(Vector const& lhs, Vector const& rhs) -> bool 84 : : { 85 : 4 : return (lhs.x == rhs.x) ? (lhs.y < rhs.y) : (lhs.x < rhs.x); 86 : : } 87 : : 88 : 8 : auto static constexpr DotProduct(Vector const& lhs, Vector const& rhs) -> CoordinateValue 89 : : { 90 : 8 : return lhs.x * rhs.x + lhs.y * rhs.y; 91 : : } 92 : : 93 : 22 : auto static constexpr CrossProduct(Vector const& lhs, Vector const& rhs) -> CoordinateValue 94 : : { 95 : 22 : return lhs.x * rhs.y - lhs.y * rhs.x; 96 : : } 97 : : 98 : 4 : auto constexpr SquaredLength() const -> CoordinateValue 99 : : { 100 : 4 : return DotProduct(*this, *this); 101 : : } 102 : : 103 : 4 : auto static constexpr SquaredLength(Vector const& vector) -> CoordinateValue 104 : : { 105 : 4 : return vector.SquaredLength(); 106 : : } 107 : : 108 : : template <typename CoordinateValueOther = CoordinateValue> 109 : : auto constexpr Length() const 110 : : -> std::enable_if_t<std::is_floating_point_v<CoordinateValueOther>, CoordinateValueOther> 111 : : { 112 : : return std::sqrt(static_cast<CoordinateValueOther>(SquaredLength())); 113 : : } 114 : : 115 : : template <typename CoordinateValueOther = CoordinateValue> 116 : : auto static constexpr Length(Vector<CoordinateValueOther> const& vector) 117 : : -> std::enable_if_t<std::is_floating_point_v<CoordinateValueOther>, CoordinateValueOther> 118 : : { 119 : : return vector.Length(); 120 : : } 121 : : 122 : 0 : auto static constexpr Zero() -> Vector 123 : : { 124 : 0 : return {0, 0}; 125 : : } 126 : : 127 : 0 : auto static constexpr UnitAxisX() -> Vector 128 : : { 129 : 0 : return {1, 0}; 130 : : } 131 : : 132 : 0 : auto static constexpr UnitAxisY() -> Vector 133 : : { 134 : 0 : return {0, 1}; 135 : : } 136 : : 137 : 5 : auto static constexpr CompareXThenY(Vector const& lhs, Vector const& rhs) -> bool 138 : : { 139 : 5 : return (lhs.x != rhs.x) ? (lhs.x < rhs.x) : (lhs.y < rhs.y); 140 : : } 141 : : 142 : 5 : auto static constexpr CompareYThenX(Vector const& lhs, Vector const& rhs) -> bool 143 : : { 144 : 5 : return (lhs.y != rhs.y) ? (lhs.y < rhs.y) : (lhs.x < rhs.x); 145 : : } 146 : : 147 : 5 : auto static constexpr CalculateSemiPlane(Vector const& vector) -> int 148 : : { 149 : 5 : if (vector.y != 0) { 150 : 2 : return 0 < vector.y ? -1 : +1; 151 : : } 152 : : 153 : 3 : if (vector.x != 0) { 154 : 2 : return 0 < vector.x ? -1 : +1; 155 : : } 156 : : 157 : 1 : return 0; 158 : : } 159 : : 160 : 16 : auto static constexpr CalculateSemiPlane(Vector direction, Vector vector) 161 : : { 162 : 16 : auto const cross = CrossProduct(direction, vector); 163 : : 164 : 16 : if (cross != 0) { 165 : 12 : return (0 < cross) ? -1 : +1; 166 : : } 167 : : 168 : 4 : auto const dot = DotProduct(direction, vector); 169 : : 170 : 4 : if (dot != 0) { 171 : 4 : return (0 < dot) ? -1 : +1; 172 : : } 173 : : 174 : 0 : return 0; 175 : : } 176 : : 177 : 0 : auto static constexpr CreateComparatorByAngle(Vector const& center = Zero(), Vector const& direction = UnitAxisX()) 178 : : { 179 : 8 : return [=](Vector const& lhs, Vector const& rhs) { 180 : 8 : auto const lhsSemiPlane = CalculateSemiPlane(direction, lhs - center); 181 : 8 : auto const rhsSemiPlane = CalculateSemiPlane(direction, rhs - center); 182 : : 183 : 8 : if (lhsSemiPlane != rhsSemiPlane) { 184 : 2 : return lhsSemiPlane < rhsSemiPlane; 185 : : } 186 : : 187 : 6 : auto const cross = CrossProduct(lhs, rhs); 188 : : 189 : 6 : if (cross != 0) { 190 : 4 : return 0 < cross; 191 : : } 192 : : 193 : 2 : return SquaredLength(lhs) < SquaredLength(rhs); 194 : 0 : }; 195 : : } 196 : : }; 197 : : 198 : : } // namespace Geometry