aline.c 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. #include "aline.h"
  2. /* An Aline is an axis-oriended line segment that has it's center in c
  3. * and a "radius" r, andt hat mis mooving at a speed v. It's used to split up
  4. * collision problems into simpler 1-dimensional solutions.
  5. */
  6. /* Equal to c - r */
  7. double aline_lo(Aline self) {
  8. return self.c - self.r;
  9. }
  10. /* Equal to c + r */
  11. double aline_hi(Aline self) {
  12. return self.c + self.r;
  13. }
  14. /* Equal to r + r */
  15. double aline_r2(Aline self) {
  16. return self.r + self.r;
  17. }
  18. /* Unicode warning: I used unicode characters in the comments for this class
  19. for deriving the maths. The characters on the next line should all be
  20. readable: Δ⁰¹²³⁴⁵⁶⁷⁸⁹⁺⁻⁼⁽⁾ ₀₁₂₃₄₅₆₇₈₉ ₊₋₌₍₎ᵃᵇᶜᵈᵉᶠᵍʰⁱʲᵏˡᵐⁿᵒᵖʳˢᵗᵘᵛʷˣʸᶻₐₑₒₓᵅᵋᶿᶥᶲ.
  21. */
  22. /* Initialize a new Aline with position c, radius r and velocity v */
  23. Aline aline(double c, double r, double v) {
  24. Aline self;
  25. self.r = r;
  26. self.c = c;
  27. self.v = v;
  28. return self;
  29. }
  30. /* Returns true if self is overlapping with other right now,
  31. at the current position, false if not
  32. */
  33. int aline_bump_now_p(Aline self, Aline other) {
  34. if (self.c == other.c) return 1;
  35. if (self.c < other.c) /* positive side collision */
  36. return (self.c + self.r) >= (other.c - other.r);
  37. else /* self.c > other.c, so negative side collision */
  38. return (self.c - self.r) <= (other.c + other.r);
  39. }
  40. /* Calculates bump time for collisions on the positive side of self.
  41. * Returns 0 if no bump time could be calculated.
  42. */
  43. double aline_positive_bump_time(Aline self, Aline other) {
  44. /* Δtᵇ is the time of collision calculated from now, as we define t⁰ == 0.
  45. # self.cᵇ is the position of the center of self at collision time Δtᵇ.
  46. # other.cᵇ is the position of the center of other at collision time Δtᵇ.
  47. #
  48. # Now at collision on the positive side:
  49. #
  50. # self.cᵇ + self.r == other.cᵇ - other.r
  51. # self.cᵇ - other.cᵇ == - self.r - other.r (1)
  52. #
  53. # Now, self.v is kept constant during Δt, so:
  54. #
  55. # self.v == Δself.c / Δt
  56. # self.v == (self.cᵇ - self.c⁰) / (tᵇ - t⁰ self.cᵇ)
  57. # t₀ == 0, so:
  58. # self.v == (self.cᵇ - self.c⁰) / tᵇ
  59. # self.cᵇ - self.c⁰ == self.v * tᵇ
  60. # self.cᵇ == self.v * tᵇ + self.c⁰ (2)
  61. #
  62. #
  63. # the same goes for other so:
  64. # other.v == (other.cᵇ - other.c⁰) / tᵇ
  65. # other.cᵇ == other.v * tᵇ + other.c⁰ (3)
  66. #
  67. # Substitute (2) and (3) into (1):
  68. # self.v * tᵇ + self.c⁰ - other.v * tᵇ - other.c⁰ == - self.r - other.r
  69. # self.v * tᵇ - other.v * tᵇ + self.c⁰ - other.c⁰ == - self.r - other.r
  70. # (self.v - other.v) * tᵇ + (self.c⁰ - other.c⁰) == - self.r - other.r
  71. # (self.v - other.v) * tᵇ == -self.r - other.r - self.c⁰ + other.c⁰
  72. # (reversing the sign):
  73. # (other.v - self.v) * tᵇ == self.r + other.r + (self.c⁰ - other.c⁰)
  74. # let vrel = (other.v - self.v)
  75. # and crel = (other.c⁰ - self.c⁰)
  76. # and rsum = self.r + other.r
  77. # then:
  78. # vrel * tᵇ == rsum - crel
  79. # if vrel != 0
  80. # tᵇ == (rsum - crel) / vrel
  81. */
  82. double vrel = self.v - other.v; /* Relative speed. */
  83. double crel = self.c - other.c; /* Relative position. */
  84. double rsum = self.r + other.r; /* Sum of the radiuses. */
  85. double tb = (rsum - crel) / vrel;
  86. return tb;
  87. }
  88. /* Calculates bump time for collisions on the negative side of self */
  89. int aline_negative_bump_time(Aline self, Aline other) {
  90. /* Δtᵇ is the time of collision calculated from now, as we define t⁰ == 0.
  91. # self.cᵇ is the position of the center of self at collision time Δtᵇ.
  92. # other.cᵇ is the position of the center of other at collision time Δtᵇ.
  93. #
  94. # Now at collision from the negative side:
  95. #
  96. # self.cᵇ - self.r == other.cᵇ + other.r
  97. # self.cᵇ - other.cᵇ == self.r + other.r (1)
  98. #
  99. # Now, self.v is kept constant during Δt, so:
  100. #
  101. # self.v == Δself.c / Δt
  102. # self.v == (self.cᵇ - self.c⁰) / (tᵇ - t⁰ self.cᵇ)
  103. # t₀ == 0, so:
  104. # self.v == (self.cᵇ - self.c⁰) / tᵇ
  105. # self.cᵇ - self.c⁰ == self.v * tᵇ
  106. # self.cᵇ == self.v * tᵇ + self.c⁰ (2)
  107. #
  108. #
  109. # the same goes for other so:
  110. # other.v == (other.cᵇ - other.c⁰) / tᵇ
  111. # other.cᵇ == other.v * tᵇ + other.c⁰ (3)
  112. #
  113. # Substitute (2) and (3) into (1):
  114. # self.v * tᵇ + self.c⁰ - other.v * tᵇ - other.c⁰ == self.r + other.r
  115. # self.v * tᵇ - other.v * tᵇ + self.c⁰ - other.c⁰ == self.r + other.r
  116. # (self.v - other.v) * tᵇ + (self.c⁰ - other.c⁰) == self.r + other.r
  117. # (self.v - other.v) * tᵇ == self.r + other.r - self.c⁰ + other.c⁰
  118. # (reversing the sign):
  119. # (other.v - self.v) * tᵇ == - self.r - other.r + (self.c⁰ - other.c⁰)
  120. # let vrel = (other.v - self.v)
  121. # and crel = (other.c⁰ - self.c⁰)
  122. # and rsum = self.r + other.r
  123. # then:
  124. # vrel * tᵇ == - rsum - crel
  125. # if vrel != 0
  126. # tᵇ == (- rsum - crel) / vrel
  127. # tᵇ == -( rsum + crel) / vrel
  128. */
  129. double vrel = self.v - other.v; /* Relative speed. */
  130. double crel = self.c - other.c; /* Relative position. */
  131. double rsum = self.r + other.r; /* Sum of the radiuses. */
  132. double tb = (-(rsum + crel)) / vrel;
  133. return tb;
  134. }
  135. /* Calculates the time when self will bump into other. Returns nonzero
  136. *and stores the time in tb if there is a collision. Returns zero if there is
  137. no collision possible, for example, in the case their speeds are the same,
  138. in which case they will either never collide, or always were and always
  139. will be colliding, assuming their speed does not change.
  140. If the bump time is negative, the initial collision took place in the
  141. past, and may still be ongoing.
  142. */
  143. int aline_bump_time(Aline self, Aline other, double * tb) {
  144. /* Two objects moving at equal speed who are not already colliding
  145. will never collide with each other. */
  146. double res;
  147. if (self.v == other.v) return 0;
  148. if (self.c <= other.c)
  149. /* The collision will happen or has happened on the positive
  150. side of self at self.c + self.r and at the negative side of
  151. other at other.c - other.r
  152. */
  153. res = aline_negative_bump_time(self, other);
  154. else /* here self.c > other.c */
  155. /* The collision will happen or has happened on the negative
  156. side of self at self.c - self.r and at the positive side of
  157. other at other.c + other.r */
  158. res = aline_positive_bump_time(self, other);
  159. if (tb) (*tb) = res;
  160. return !0;
  161. }
  162. /* Caluclates the prediced position of c where self will bump into other
  163. if both retain the same speeds. Returns 0 if their speeds are the same
  164. in which case they will either never collide, or always stay in overlap.
  165. */
  166. int aline_bump_c(Aline self, Aline other, double * c) {
  167. double tb, cb;
  168. if(!aline_bump_time(self, other, &tb)) return 0;
  169. /* self.cᵇ == self.v * tᵇ + self.c⁰ (3) */
  170. cb = self.v * tb + self.c;
  171. if(c) (*c) = cb;
  172. return !0;
  173. }
  174. /* Simulates a motion that takes place during a time interval dt (Δt)
  175. * assuming the speed remained constant during that interval.
  176. * Returns a new line piece aline with it's c value updated to reflect
  177. * the changed position.
  178. * @return [Aline]
  179. */
  180. Aline aline_step(Aline self, double dt) {
  181. double dc = dt * self.v;
  182. double newc = self.c + dc;
  183. return aline(newc, self.r, self.v);
  184. }
  185. /* Simulates a motion as per aline_step, but modifies self.
  186. * @return [Aline]
  187. */
  188. Aline * aline_step_i(Aline * self, double dt) {
  189. double dc = dt * self->v;
  190. self->c = self->c + dc;
  191. return self;
  192. }
  193. /* Sets the speed of the Aline. */
  194. Aline * aline_v(Aline * self, double newv) {
  195. self->v = newv;
  196. return self;
  197. }