1 /++ 2 Module for working with mathematical angles. Contains the translation of 3 measurement systems, work in the form of determining the angle, 4 vector rotation and more. 5 6 Macros: 7 LREF = <a href="#$1">$1</a> 8 HREF = <a href="$1">$2</a> 9 10 Authors: $(HREF https://github.com/TodNaz,TodNaz) 11 Copyright: Copyright (c) 2020 - 2021, TodNaz. 12 License: $(HREF https://github.com/TodNaz/Tida/blob/master/LICENSE,MIT) 13 +/ 14 module tida.angle; 15 16 import std.math : PI; 17 18 enum Radians = 0; /// Radians 19 enum Degrees = 1; /// Degrees 20 enum Turns = 2; /// Turns 21 enum Gons = 3; /// Gons 22 23 /++ 24 Maximum angle value. 25 26 Params: 27 Type = Type angle. 28 29 Example: 30 --- 31 auto maxRad = max!Radians; 32 --- 33 +/ 34 template max(ubyte Type) 35 { 36 static if (Type == Radians) 37 { 38 enum max = 2 * PI; 39 }else 40 static if (Type == Degrees) 41 { 42 enum max = 360.0f; 43 }else 44 static if (Type == Turns) 45 { 46 enum max = 1.0f; 47 }else 48 static if (Type == Gons) 49 { 50 enum max = 400.0f; 51 } 52 } 53 54 alias perigon = max; /// perigon 55 56 /++ 57 Returns the right angle. 58 59 Params: 60 Type = Type angle. 61 62 Example: 63 --- 64 auto riaRad = rightAngle!Radians; 65 --- 66 +/ 67 template rightAngle(ubyte Type) 68 { 69 static if (Type == Radians) 70 { 71 enum rightAngle = PI / 2; 72 }else 73 static if (Type == Degrees) 74 { 75 enum rightAngle = 90.0f; 76 }else 77 static if (Type == Turns) 78 { 79 enum rightAngle = 1 / 4; 80 }else 81 static if (Type == Gons) 82 { 83 enum rightAngle = 100; 84 }else 85 static assert(null, "Unknown angle type!"); 86 } 87 88 /++ 89 Returns straight angle. 90 91 Params: 92 Type = Type angle. 93 94 Example: 95 --- 96 auto strRad = straight!Radians; 97 --- 98 +/ 99 template straight(ubyte Type) 100 { 101 static if (Type == Radians) 102 { 103 enum straight = PI; 104 }else 105 static if (Type == Degrees) 106 { 107 enum straight = 180; 108 }else 109 static if (Type == Turns) 110 { 111 enum straight = 0.5; 112 }else 113 static if (Type == Gons) 114 { 115 enum straight = 200; 116 }else 117 static assert(null,"Unknown angle type!"); 118 } 119 120 /++ 121 Translate one system of angles into another. 122 123 Params: 124 What = What to translate. 125 In = What to translate. 126 value = Value. 127 128 Example: 129 --- 130 from(Degrees,Radians)(45); 131 --- 132 +/ 133 float conv(ubyte What,ubyte In)(float value) @safe nothrow pure 134 { 135 import std.math; 136 137 static if (What == In) return value; 138 else 139 static if (In == Turns) return value / max!What; 140 else 141 static if (What == Turns) return max!In * value; 142 else 143 static if (What == Radians) 144 { 145 static if (In == Degrees) 146 { 147 return value * 180 / PI; 148 }else 149 static if (In == Gons) 150 { 151 return value * 200 / PI; 152 } 153 }else 154 static if (What == Degrees) 155 { 156 static if (In == Radians) 157 { 158 return value * PI / 180; 159 }else 160 static if (In == Gons) 161 { 162 return value * 200 / 180; 163 } 164 }else 165 static if (What == Gons) 166 { 167 static if (In == Radians) 168 { 169 return value * PI / 200; 170 }else 171 static if (In == Degrees) 172 { 173 return value * 180 / 200; 174 } 175 } 176 } 177 178 alias from = conv; // old name saved. 179 180 /++ 181 Converts degrees to radians. 182 183 Params: 184 value = The value is in degrees. 185 186 Returns: 187 The value is in degrees. 188 +/ 189 alias degToRad = conv!(Degrees, Radians); 190 191 /++ 192 Convert radians to degrees. 193 194 Params: 195 value = The value is in radians. 196 197 Returns: 198 The value is in degrees. 199 +/ 200 alias radToDeg = conv!(Radians, Degrees); 201 202 /++ 203 Brings the angle back to normal. 204 205 Params: 206 Type = Angle type. 207 angle = Angle. 208 209 Example: 210 --- 211 assert(375.minimize!Degrees == 15); 212 --- 213 +/ 214 float minimize(ubyte Type)(float angle) @safe nothrow pure 215 { 216 int k = cast(int) (angle / max!Type); 217 float sign = angle >= 0 ? 1 : -1; 218 219 return angle - ((max!Type * cast(float) k) * sign); 220 } 221 222 unittest 223 { 224 assert(minimize!Degrees(361) == 1); 225 assert(minimize!Degrees(470) == (470 - 360)); 226 assert(minimize!Degrees(848) == 128); 227 } 228 229 /++ 230 Finds the angle between two angel's. Accepted in any angle change systems. 231 232 Params: 233 a = First angle. 234 b = Second angle. 235 236 Returns: Angle between two angel's. 237 +/ 238 float betweenAngle(float a, float b) @safe nothrow pure 239 { 240 return (a + b) / 2; 241 } 242 243 unittest 244 { 245 assert(max!Radians.from!(Radians,Degrees) == (max!Degrees)); 246 assert(max!Degrees.from!(Degrees,Gons) == (max!Gons)); 247 assert(max!Gons.from!(Gons,Turns) == (max!Turns)); 248 249 assert(rightAngle!Radians.from!(Radians,Degrees) == (rightAngle!Degrees)); 250 assert(rightAngle!Degrees.from!(Degrees,Gons) == (rightAngle!Gons)); 251 } 252 253 import tida.vector; 254 255 /++ 256 Returns the angle between two vectors in radians. 257 258 Params: 259 a = First point. 260 b = Second point. 261 262 Returns: Angle in radians. 263 264 To convert, for example, to degrees, use the function like this: 265 --- 266 pointDirection(...).from!(Radians,Degrees); 267 --- 268 +/ 269 T pointDirection(T)(Vector!T a, Vector!T b) @safe nothrow pure 270 { 271 import std.math : atan2; 272 273 T result = atan2(b.y - a.y, b.x - a.x); 274 return result; 275 } 276 277 /++ 278 Rotates the point by the specified number of degrees. 279 280 Params: 281 vec = Point. 282 angle = Angle of rotation. 283 center = Center of rotation. 284 +/ 285 Vecf rotate(Vecf vec, float angle, Vecf center = vecf(0, 0)) @safe nothrow pure 286 { 287 import std.math : sin, cos; 288 289 float ca = cos(angle); 290 float sa = sin(angle); 291 292 Vecf result; 293 294 vec -= center; 295 296 result.x = vec.x * ca - vec.y * sa; 297 result.y = vec.x * sa + vec.y * ca; 298 299 return result + center; 300 } 301 302 /++ 303 Convert angle to direction vector. Use when moving an object at a given angle. 304 305 Params: 306 angle = Angle. 307 308 Example: 309 --- 310 Vecf vecd = vectorDirection(45.from!(Degrees,Radians)); 311 position += vecd * 5; // Move the object 45 degrees at a given speed. 312 --- 313 +/ 314 Vector!T vectorDirection(T)(T angle) @safe nothrow pure 315 { 316 import std.math : cos, sin; 317 318 return vec!T(cos(angle), sin(angle)); 319 }