bevec.c 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. /* 2D Vector types implementation. */
  2. #include <math.h>
  3. #include "bevec.h"
  4. BeVec bevec(double x, double y) {
  5. BeVec result;
  6. result.x = x;
  7. result.y = y;
  8. return result;
  9. }
  10. BeVec bevec0() {
  11. return bevec(0.0, 0.0);
  12. }
  13. BeVec bevec_add(BeVec v1, BeVec v2) {
  14. return bevec(v1.x + v2.x, v1.y + v2.y);
  15. }
  16. BeVec bevec_sub(BeVec v1, BeVec v2) {
  17. return bevec(v1.x - v2.x, v1.y - v2.y);
  18. }
  19. BeVec bevec_mul(BeVec v1, double factor) {
  20. return bevec(v1.x * factor, v1.y * factor);
  21. }
  22. BeVec bevec_neg(BeVec v1) {
  23. return bevec(-v1.x, -v1.y);
  24. }
  25. /* Dot product. */
  26. double bevec_dot(BeVec v1, BeVec v2) {
  27. return (v1.x * v2.x) + (v1.y * v2.y);
  28. }
  29. BeVec bevec_div_unsafe(BeVec v1, double factor) {
  30. return bevec(v1.x / factor, v1.y / factor);
  31. }
  32. BeVec bevec_div(BeVec v1, double factor) {
  33. if (factor == 0.0) {
  34. return bevec0();
  35. }
  36. return bevec_div_unsafe(v1, factor);
  37. }
  38. double bevec_lengthsq(BeVec v1) {
  39. return (v1.x * v1.x) + (v1.y * v1.y);
  40. }
  41. double bevec_length(BeVec v1) {
  42. return sqrt((v1.x * v1.x) + (v1.y * v1.y));
  43. }
  44. BeVec bevec_normalize(BeVec v1) {
  45. double length = bevec_length(v1);
  46. return bevec_div(v1, length);
  47. }
  48. BeVec bevec_normalize_unsafe(BeVec v1) {
  49. double length = bevec_length(v1);
  50. return bevec_div_unsafe(v1, length);
  51. }
  52. BeVec bevec_project(BeVec vec , BeVec on) {
  53. double dot = bevec_dot(vec, on);
  54. double lengthsq = bevec_lengthsq(on);
  55. double x = on.x * dot / lengthsq;
  56. double y = on.y * dot / lengthsq;
  57. return bevec(x, y);
  58. }
  59. BeVec bevec_rightnormal(BeVec vec) {
  60. return bevec(-vec.y, vec.x);
  61. }
  62. BeVec bevec_leftnormal(BeVec vec) {
  63. return bevec(vec.y, -vec.x);
  64. }
  65. double bevec_perproduct(BeVec v1, BeVec v2) {
  66. return bevec_dot(v1, bevec_rightnormal(v2));
  67. }
  68. BeVec bevec_forangle(double angle) {
  69. return bevec(cos(angle), sin(angle));
  70. }
  71. /* Returns a unit vector that makes the given angle a with the X axis. */
  72. BeVec bevec_for_angle(double a) {
  73. return bevec(cos(a), sin(a));
  74. }
  75. double bevec_toangle(BeVec v1) {
  76. return atan2(v1.y, v1.x);
  77. }
  78. /* Cross product magnitude. The cross product of 2D x,y vectors is
  79. a 3D vector with a pure z component, so this function returns only the
  80. magnitude of that z component. */
  81. double bevec_cross(BeVec self, BeVec other) {
  82. return self.x * other.y - self.y * other.x;
  83. }
  84. /* Perpendicular vector, rotated by 90 degrees, anticlockwise. */
  85. BeVec bevec_perp(BeVec self) {
  86. return bevec(-self.y, self.x);
  87. }
  88. /* Perpendicular vector, rotated by -90 degrees, clockwise. */
  89. BeVec bevec_nperp(BeVec self) {
  90. return bevec(self.y, -self.x);
  91. }
  92. /* Returns a vector that is the projection of self onto other.
  93. * Not possible if other has a length 0. */
  94. BeVec bevec_project_2(BeVec self, BeVec other) {
  95. double dot_product, other_length;
  96. dot_product = bevec_dot(self, other);
  97. other_length = bevec_length(other);
  98. return bevec_mul(other, dot_product / other_length);
  99. }
  100. /* Rotates self by other. */
  101. BeVec bevec_rotate(BeVec self, BeVec other) {
  102. return bevec(self.x*other.x - self.y*other.y,
  103. self.x*other.y + self.y*other.x);
  104. }
  105. /* Inverse rotation. */
  106. BeVec bevec_unrotate(BeVec self, BeVec other) {
  107. return bevec(self.x*other.x + self.y*other.y,
  108. self.x*other.y - self.y*other.x);
  109. }
  110. /* Linear interpolation on a line between between self and other.
  111. * Returns a vector that points to a point on the line between self and other. */
  112. BeVec bevec_lerp(BeVec self, BeVec other, double tx) {
  113. return bevec_add(bevec_mul(self, 1.0 - tx), bevec_mul(other, tx));
  114. /* self * (1.0 - tx) + (other * tx) */
  115. }
  116. /* If the length of the vector is greater than max, this function
  117. returns a vector with the same direction as self, but with the length
  118. of that vector limited to max. Otherwise, it returns a copy of self.
  119. */
  120. BeVec bevec_cliplength(BeVec self, double m) {
  121. double len = bevec_length(self);
  122. if (len <= m) return self;
  123. return bevec_mul(bevec_normalize(self), m);
  124. }
  125. /* Returns the vector between the two points represented by the vectors self and other. */
  126. BeVec bevec_delta(BeVec self, BeVec other) {
  127. return bevec_sub(self, other);
  128. }
  129. /* Returns the distance between the two points represented by the vectors self and other. */
  130. double bevec_distance(BeVec self, BeVec other) {
  131. return bevec_length(bevec_delta(self, other));
  132. }
  133. /* Returns the distance squared between the two points represented by the vectors self and other. */
  134. double bevec_distsq(BeVec self, BeVec other) {
  135. return bevec_lengthsq(bevec_delta(self, other));
  136. }
  137. /* Returns true if the distance between self and other is less than or
  138. equal to d.
  139. */
  140. double bevec_near_p(BeVec self, BeVec other, double d) {
  141. return bevec_distsq(self, other) <= (d*d);
  142. }
  143. /* Returns the angle of the vector with the X axis in clockwise
  144. * direction in radians
  145. */
  146. double bevec_angle(BeVec self) {
  147. return atan2(self.y, self.x);
  148. }
  149. /* Returns a vector with components self.x, 0 */
  150. BeVec bevec_xvec(BeVec self) {
  151. return bevec(self.x, 0.0);
  152. }
  153. /* Returns a vector with components 0, self.y */
  154. BeVec bevec_yvec(BeVec self) {
  155. return bevec(0.0, self.y);
  156. }
  157. /* Returns a vector with fabs applied to the components of vec. */
  158. BeVec bevec_abs(BeVec self) {
  159. return bevec(fabs(self.x), fabs(self.y));
  160. }
  161. /*
  162. Returns the overlap of the x component of self, of other, where
  163. self and other are centers of line pieces with width rself and rother
  164. respectivly. Returned as a vector with only an x component with the
  165. magnitude of overlap.
  166. BeVec overlap_x(BeVec self, BeVec other,rself, rother)
  167. xself = self.vector_x
  168. xother = other.vector_x
  169. return zero unless xself.near(xother, rself)
  170. return zero unless xother.near(xself, rother)
  171. end
  172. */
  173. // public domain function by Darel Rex Finley, 2006
  174. // Determines the intersection point of the line segment defined by points A and B
  175. // with the line segment defined by points C and D.
  176. //
  177. // Returns YES if the intersection point was found, and stores that point in X,Y.
  178. // Returns NO if there is no determinable intersection point, in which case X,Y will
  179. // be unmodified.
  180. /*
  181. int bevec_intersect_segment(BeVec A, BeVec B, BeVec C, BeVec D, BeVeC * result) {
  182. double dist_AB, aid_cos, aid_sin, newX, ABpos ;
  183. // Fail if either line segment is zero-length.
  184. if (A.x == B.x && A.y == B.y || C.x == D.x && C.y == D.y) return NO;
  185. // Fail if the segments share an end-point.
  186. if (A.x==C.x && A.y==C.y || B.x==C.x && B.y==C.y
  187. || A.x==D.x && A.y==D.y || B.x==D.x && B.y==D.y) {
  188. return NO; }
  189. // (1) Translate the system so that point A is on the origin.
  190. B = bevec_sub(B, A);
  191. C = bevec_sub(C, A);
  192. D = bevec_sub(D, A);
  193. // Discover the length of segment A-B.
  194. dist_AB = bevec_length(B);
  195. // (2) Rotate the system so that point B is on the positive X axis.
  196. aid_Cos=Bx/distAB;
  197. aid_sin =By/distAB;
  198. newX=Cx*theCos+Cy* aid_sin;
  199. Cy =Cy*theCos-Cx* aid_sin; Cx=newX;
  200. newX=Dx*theCos+Dy* aid_sin;
  201. Dy =Dy*theCos-Dx* aid_sin; Dx=newX;
  202. // Fail if segment C-D doesn't cross line A-B.
  203. if (Cy<0. && Dy<0. || Cy>=0. && Dy>=0.) return NO;
  204. // (3) Discover the position of the intersection point along line A-B.
  205. ABpos=Dx+(Cx-Dx)*Dy/(Dy-Cy);
  206. // Fail if segment C-D crosses line A-B outside of segment A-B.
  207. if (ABpos<0. || ABpos>distAB) return NO;
  208. // (4) Apply the discovered position to line A-B in the original coordinate system.
  209. *X=Ax+ABpos*theCos;
  210. *Y=Ay+ABpos* aid_sin;
  211. // Success.
  212. return YES; }
  213. */