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 See_Also: 184 $(LREF conv) 185 +/ 186 alias degToRad = conv!(Degrees, Radians); 187 188 /++ 189 Convert radians to degrees. 190 191 192 See_Also: 193 $(LREF conv) 194 +/ 195 alias radToDeg = conv!(Radians, Degrees); 196 197 /++ 198 Brings the angle back to normal. 199 200 Params: 201 Type = Angle type. 202 angle = Angle. 203 204 Example: 205 --- 206 assert(375.minimize!Degrees == 15); 207 --- 208 +/ 209 float minimize(ubyte Type)(float angle) @safe nothrow pure 210 { 211 int k = cast(int) (angle / max!Type); 212 float sign = angle >= 0 ? 1 : -1; 213 214 return angle - ((max!Type * cast(float) k) * sign); 215 } 216 217 unittest 218 { 219 assert(minimize!Degrees(361) == 1); 220 assert(minimize!Degrees(470) == (470 - 360)); 221 assert(minimize!Degrees(848) == 128); 222 } 223 224 /++ 225 Finds the angle between two angel's. Accepted in any angle change systems. 226 227 Params: 228 a = First angle. 229 b = Second angle. 230 231 Returns: Angle between two angel's. 232 +/ 233 float betweenAngle(float a, float b) @safe nothrow pure 234 { 235 return (a + b) / 2; 236 } 237 238 unittest 239 { 240 assert(max!Radians.from!(Radians,Degrees) == (max!Degrees)); 241 assert(max!Degrees.from!(Degrees,Gons) == (max!Gons)); 242 assert(max!Gons.from!(Gons,Turns) == (max!Turns)); 243 244 assert(rightAngle!Radians.from!(Radians,Degrees) == (rightAngle!Degrees)); 245 assert(rightAngle!Degrees.from!(Degrees,Gons) == (rightAngle!Gons)); 246 } 247 248 import tida.vector; 249 250 /++ 251 Returns the angle between two vectors in radians. 252 253 Params: 254 a = First point. 255 b = Second point. 256 257 Returns: Angle in radians. 258 259 To convert, for example, to degrees, use the function like this: 260 --- 261 pointDirection(...).from!(Radians,Degrees); 262 --- 263 +/ 264 T pointDirection(T)(Vector!T a, Vector!T b) @safe nothrow pure 265 { 266 import std.math : atan2; 267 268 T result = atan2(b.y - a.y, b.x - a.x); 269 return result; 270 } 271 272 /++ 273 Rotates the point by the specified number of degrees. 274 275 Params: 276 vec = Point. 277 angle = Angle of rotation. 278 center = Center of rotation. 279 +/ 280 Vecf rotate(Vecf vec, float angle, Vecf center = vecf(0, 0)) @safe nothrow pure 281 { 282 import std.math : sin, cos; 283 284 float ca = cos(angle); 285 float sa = sin(angle); 286 287 Vecf result; 288 289 vec -= center; 290 291 result.x = vec.x * ca - vec.y * sa; 292 result.y = vec.x * sa + vec.y * ca; 293 294 return result + center; 295 } 296 297 /++ 298 Convert angle to direction vector. Use when moving an object at a given angle. 299 300 Params: 301 angle = Angle. 302 303 Example: 304 --- 305 Vecf vecd = vectorDirection(45.from!(Degrees,Radians)); 306 position += vecd * 5; // Move the object 45 degrees at a given speed. 307 --- 308 +/ 309 Vector!T vectorDirection(T)(T angle) @safe nothrow pure 310 { 311 import std.math : cos, sin; 312 313 return vec!T(cos(angle), sin(angle)); 314 }