ModulationScheme.cs 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. using System;
  2. using System.Collections.Generic;
  3. using Raahn;
  4. namespace RaahnSimulation
  5. {
  6. public partial class Car
  7. {
  8. public class ModulationScheme
  9. {
  10. public enum Scheme
  11. {
  12. NONE = -1,
  13. WALL_AVOIDANCE = 0
  14. }
  15. private const uint DEFAULT_SCHEME_INDEX = 0;
  16. private const uint WALL_AVOIDANCE_PARAMETER_COUNT = 1;
  17. private const double MODULATION_STENGTH = 1.0;
  18. private const double MODULATION_RESET = 0.0;
  19. private const double MODULATION_NOT_RESET = -1.0;
  20. private const double PERPENDICULAR = 90.0;
  21. public delegate void SchemeFunction(Car car, List<Entity> entitiesInBounds, List<uint> modSigs);
  22. public static readonly SchemeFunction[] SCHEMES =
  23. {
  24. WallAvoidance
  25. };
  26. public static readonly string[] SCHEME_STRINGS =
  27. {
  28. "WallAvoidance"
  29. };
  30. private static double lastAngleBetween = MODULATION_RESET;
  31. private static double viewDistance = 0.0;
  32. private static Wall lastWallInRange = null;
  33. public static void InterpretParameters(string[] parameters, Scheme scheme)
  34. {
  35. //Interpret parameters specific to each scheme, if any.
  36. switch (scheme)
  37. {
  38. case Scheme.WALL_AVOIDANCE:
  39. {
  40. if (parameters.Length >= WALL_AVOIDANCE_PARAMETER_COUNT)
  41. viewDistance = double.Parse(parameters[0]);
  42. break;
  43. }
  44. }
  45. }
  46. //Resets global variables used by schemes.
  47. public static void Reset()
  48. {
  49. lastAngleBetween = MODULATION_RESET;
  50. lastWallInRange = null;
  51. }
  52. public static Scheme GetSchemeFromString(string schemeString)
  53. {
  54. for (int i = 0; i < SCHEME_STRINGS.Length; i++)
  55. {
  56. if (schemeString.Equals(SCHEME_STRINGS[i]))
  57. return (Scheme)i;
  58. }
  59. return Scheme.NONE;
  60. }
  61. public static SchemeFunction GetSchemeFunction(Scheme scheme)
  62. {
  63. int schemei = (int)scheme;
  64. if (schemei >= 0 && schemei < SCHEMES.Length)
  65. return SCHEMES[schemei];
  66. else
  67. return null;
  68. }
  69. public static void WallAvoidance(Car car, List<Entity> entitiesInBounds, List<uint> modSigs)
  70. {
  71. double xViewDist = car.center.x + Math.Cos(Utils.DegToRad(car.angle)) * viewDistance;
  72. double yViewDist = car.center.y + Math.Sin(Utils.DegToRad(car.angle)) * viewDistance;
  73. Utils.Point2 original = new Utils.Point2(car.center.x, car.center.y);
  74. Utils.Point2 viewEndPoint = new Utils.Point2(xViewDist, yViewDist);
  75. Utils.LineSegment viewLine = new Utils.LineSegment();
  76. viewLine.SetUp(original, viewEndPoint);
  77. Wall compareWall = null;
  78. double nearestDist = Utils.GetDist(original, viewEndPoint);
  79. //Get the nearest wall in the view distance if any.
  80. for (int i = 0; i < entitiesInBounds.Count; i++)
  81. {
  82. if (entitiesInBounds[i].GetEntityType() == Entity.EntityType.WALL)
  83. {
  84. Wall currentWall = (Wall)entitiesInBounds[i];
  85. Utils.LineSegment compare = currentWall.GetLineSegment();
  86. List<Utils.Point2> intersections = viewLine.Intersects(compare);
  87. if (intersections.Count > 0)
  88. {
  89. //The first index is always the nearest.
  90. double dist = Utils.GetDist(original, intersections[0]);
  91. if (dist < nearestDist)
  92. {
  93. nearestDist = dist;
  94. compareWall = currentWall;
  95. }
  96. }
  97. }
  98. }
  99. //The angle to use for modulation. Should never be zero when the angle delta is calculated.
  100. //If it is there must be a bug.
  101. double angleBetween = 0.0;
  102. double newLastAngle = MODULATION_NOT_RESET;
  103. Utils.Vector2 viewVector = new Utils.Vector2(viewEndPoint.x - car.center.x, viewEndPoint.y - car.center.y);
  104. //If there is no nearest wall.
  105. if (compareWall == null)
  106. {
  107. //If there is no previous wall, set the modulation to zero and reset the last angle.
  108. if (lastWallInRange == null)
  109. {
  110. if (lastAngleBetween != MODULATION_RESET)
  111. {
  112. lastAngleBetween = MODULATION_RESET;
  113. for (int i = 0; i < modSigs.Count; i++)
  114. ModulationSignal.SetSignal(modSigs[i], ModulationSignal.NO_MODULATION);
  115. }
  116. //Nothing to modulate and nothing to save. Don't continue.
  117. return;
  118. }
  119. //Just left a wall.
  120. else
  121. {
  122. Utils.Vector2 lastWallVector = new Utils.Vector2(lastWallInRange.GetRelativeX(), lastWallInRange.GetRelativeY());
  123. angleBetween = viewVector.AngleBetween(lastWallVector);
  124. }
  125. }
  126. //If the wall changed.
  127. else if (compareWall != lastWallInRange)
  128. {
  129. //There was a last wall that is different from the current wall.
  130. if (lastWallInRange != null)
  131. {
  132. Utils.Vector2 compareWallVector = new Utils.Vector2(compareWall.GetRelativeX(), compareWall.GetRelativeY());
  133. Utils.Vector2 lastWallVector = new Utils.Vector2(lastWallInRange.GetRelativeX(), lastWallInRange.GetRelativeY());
  134. angleBetween = viewVector.AngleBetween(lastWallVector);
  135. newLastAngle = viewVector.AngleBetween(compareWallVector);
  136. }
  137. //It is the first time any wall was hit, don't continue.
  138. //Save the angle between and current wall.
  139. else
  140. {
  141. Utils.Vector2 compareWallVector = new Utils.Vector2(compareWall.GetRelativeX(), compareWall.GetRelativeY());
  142. lastAngleBetween = angleBetween = viewVector.AngleBetween(compareWallVector);
  143. lastWallInRange = compareWall;
  144. return;
  145. }
  146. }
  147. //The usual case, the last wall is equal to the current wall.
  148. else
  149. {
  150. Utils.Vector2 compareWallVector = new Utils.Vector2(compareWall.GetRelativeX(), compareWall.GetRelativeY());
  151. newLastAngle = angleBetween = viewVector.AngleBetween(compareWallVector);
  152. }
  153. double delta = angleBetween - lastAngleBetween;
  154. double modulation = MODULATION_STENGTH;
  155. if (angleBetween > PERPENDICULAR)
  156. modulation *= delta / Car.ROTATE_SPEED;
  157. else
  158. modulation *= -delta / Car.ROTATE_SPEED;
  159. for (int i = 0; i < modSigs.Count; i++)
  160. ModulationSignal.SetSignal(modSigs[i], modulation);
  161. lastAngleBetween = newLastAngle;
  162. lastWallInRange = compareWall;
  163. }
  164. }
  165. }
  166. }