1
0

AtmosDirection.cs 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. using System.Numerics;
  2. using System.Runtime.CompilerServices;
  3. using Robust.Shared.Serialization;
  4. namespace Content.Shared.Atmos
  5. {
  6. /// <summary>
  7. /// The reason we use this over <see cref="Direction"/> is that we are going to do some heavy bitflag usage.
  8. /// </summary>
  9. [Flags, Serializable]
  10. [FlagsFor(typeof(AtmosDirectionFlags))]
  11. public enum AtmosDirection
  12. {
  13. Invalid = 0, // 0
  14. North = 1 << 0, // 1
  15. South = 1 << 1, // 2
  16. East = 1 << 2, // 4
  17. West = 1 << 3, // 8
  18. // If more directions are added, note that AtmosDirectionHelpers.ToOppositeIndex() expects opposite directions
  19. // to come in pairs
  20. NorthEast = North | East, // 5
  21. SouthEast = South | East, // 6
  22. NorthWest = North | West, // 9
  23. SouthWest = South | West, // 10
  24. All = North | South | East | West, // 15
  25. }
  26. public static class AtmosDirectionHelpers
  27. {
  28. public static AtmosDirection GetOpposite(this AtmosDirection direction)
  29. {
  30. return direction switch
  31. {
  32. AtmosDirection.North => AtmosDirection.South,
  33. AtmosDirection.South => AtmosDirection.North,
  34. AtmosDirection.East => AtmosDirection.West,
  35. AtmosDirection.West => AtmosDirection.East,
  36. AtmosDirection.NorthEast => AtmosDirection.SouthWest,
  37. AtmosDirection.NorthWest => AtmosDirection.SouthEast,
  38. AtmosDirection.SouthEast => AtmosDirection.NorthWest,
  39. AtmosDirection.SouthWest => AtmosDirection.NorthEast,
  40. _ => throw new ArgumentOutOfRangeException(nameof(direction))
  41. };
  42. }
  43. /// <summary>
  44. /// This returns the index that corresponds to the opposite direction of some other direction index.
  45. /// I.e., <c>1&lt;&lt;OppositeIndex(i) == (1&lt;&lt;i).GetOpposite()</c>
  46. /// </summary>
  47. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  48. public static int ToOppositeIndex(this int index)
  49. {
  50. return index ^ 1;
  51. }
  52. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  53. public static AtmosDirection ToOppositeDir(this int index)
  54. {
  55. return (AtmosDirection) (1 << (index ^ 1));
  56. }
  57. public static Direction ToDirection(this AtmosDirection direction)
  58. {
  59. return direction switch
  60. {
  61. AtmosDirection.North => Direction.North,
  62. AtmosDirection.South => Direction.South,
  63. AtmosDirection.East => Direction.East,
  64. AtmosDirection.West => Direction.West,
  65. AtmosDirection.NorthEast => Direction.NorthEast,
  66. AtmosDirection.NorthWest => Direction.NorthWest,
  67. AtmosDirection.SouthEast => Direction.SouthEast,
  68. AtmosDirection.SouthWest => Direction.SouthWest,
  69. AtmosDirection.Invalid => Direction.Invalid,
  70. _ => throw new ArgumentOutOfRangeException(nameof(direction))
  71. };
  72. }
  73. public static AtmosDirection ToAtmosDirection(this Direction direction)
  74. {
  75. return direction switch
  76. {
  77. Direction.North => AtmosDirection.North,
  78. Direction.South => AtmosDirection.South,
  79. Direction.East => AtmosDirection.East,
  80. Direction.West => AtmosDirection.West,
  81. Direction.NorthEast => AtmosDirection.NorthEast,
  82. Direction.NorthWest => AtmosDirection.NorthWest,
  83. Direction.SouthEast => AtmosDirection.SouthEast,
  84. Direction.SouthWest => AtmosDirection.SouthWest,
  85. Direction.Invalid => AtmosDirection.Invalid,
  86. _ => throw new ArgumentOutOfRangeException(nameof(direction))
  87. };
  88. }
  89. /// <summary>
  90. /// Converts a direction to an angle, where angle is -PI to +PI.
  91. /// </summary>
  92. /// <param name="direction"></param>
  93. /// <returns></returns>
  94. public static Angle ToAngle(this AtmosDirection direction)
  95. {
  96. return direction switch
  97. {
  98. AtmosDirection.South => Angle.Zero,
  99. AtmosDirection.East => new Angle(MathHelper.PiOver2),
  100. AtmosDirection.North => new Angle(Math.PI),
  101. AtmosDirection.West => new Angle(-MathHelper.PiOver2),
  102. AtmosDirection.NorthEast => new Angle(Math.PI*3/4),
  103. AtmosDirection.NorthWest => new Angle(-Math.PI*3/4),
  104. AtmosDirection.SouthWest => new Angle(-MathHelper.PiOver4),
  105. AtmosDirection.SouthEast => new Angle(MathHelper.PiOver4),
  106. _ => throw new ArgumentOutOfRangeException(nameof(direction), $"It was {direction}."),
  107. };
  108. }
  109. /// <summary>
  110. /// Converts an angle to a cardinal AtmosDirection
  111. /// </summary>
  112. /// <param name="angle"></param>
  113. /// <returns></returns>
  114. public static AtmosDirection ToAtmosDirectionCardinal(this Angle angle)
  115. {
  116. return angle.GetCardinalDir().ToAtmosDirection();
  117. }
  118. /// <summary>
  119. /// Converts an angle to an AtmosDirection
  120. /// </summary>
  121. /// <param name="angle"></param>
  122. /// <returns></returns>
  123. public static AtmosDirection ToAtmosDirection(this Angle angle)
  124. {
  125. return angle.GetDir().ToAtmosDirection();
  126. }
  127. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  128. public static int ToIndex(this AtmosDirection direction)
  129. {
  130. // This will throw if you pass an invalid direction. Not this method's fault, but yours!
  131. return BitOperations.Log2((uint)direction);
  132. }
  133. public static AtmosDirection WithFlag(this AtmosDirection direction, AtmosDirection other)
  134. {
  135. return direction | other;
  136. }
  137. public static AtmosDirection WithoutFlag(this AtmosDirection direction, AtmosDirection other)
  138. {
  139. return direction & ~other;
  140. }
  141. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  142. public static bool IsFlagSet(this AtmosDirection direction, AtmosDirection other)
  143. {
  144. return (direction & other) == other;
  145. }
  146. public static Vector2i CardinalToIntVec(this AtmosDirection dir)
  147. {
  148. switch (dir)
  149. {
  150. case AtmosDirection.North:
  151. return new Vector2i(0, 1);
  152. case AtmosDirection.East:
  153. return new Vector2i(1, 0);
  154. case AtmosDirection.South:
  155. return new Vector2i(0, -1);
  156. case AtmosDirection.West:
  157. return new Vector2i(-1, 0);
  158. default:
  159. throw new ArgumentException($"Direction dir {dir} is not a cardinal direction", nameof(dir));
  160. }
  161. }
  162. public static Vector2i Offset(this Vector2i pos, AtmosDirection dir)
  163. {
  164. return pos + dir.CardinalToIntVec();
  165. }
  166. }
  167. public sealed class AtmosDirectionFlags { }
  168. }