/* 2D Vector types implementation. */ #include #include "bevec.h" BeVec bevec(double x, double y) { BeVec result; result.x = x; result.y = y; return result; } BeVec bevec0() { return bevec(0.0, 0.0); } BeVec bevec_add(BeVec v1, BeVec v2) { return bevec(v1.x + v2.x, v1.y + v2.y); } BeVec bevec_sub(BeVec v1, BeVec v2) { return bevec(v1.x - v2.x, v1.y - v2.y); } BeVec bevec_mul(BeVec v1, double factor) { return bevec(v1.x * factor, v1.y * factor); } BeVec bevec_neg(BeVec v1) { return bevec(-v1.x, -v1.y); } /* Dot product. */ double bevec_dot(BeVec v1, BeVec v2) { return (v1.x * v2.x) + (v1.y * v2.y); } BeVec bevec_div_unsafe(BeVec v1, double factor) { return bevec(v1.x / factor, v1.y / factor); } BeVec bevec_div(BeVec v1, double factor) { if (factor == 0.0) { return bevec0(); } return bevec_div_unsafe(v1, factor); } double bevec_lengthsq(BeVec v1) { return (v1.x * v1.x) + (v1.y * v1.y); } double bevec_length(BeVec v1) { return sqrt((v1.x * v1.x) + (v1.y * v1.y)); } BeVec bevec_normalize(BeVec v1) { double length = bevec_length(v1); return bevec_div(v1, length); } BeVec bevec_normalize_unsafe(BeVec v1) { double length = bevec_length(v1); return bevec_div_unsafe(v1, length); } BeVec bevec_project(BeVec vec , BeVec on) { double dot = bevec_dot(vec, on); double lengthsq = bevec_lengthsq(on); double x = on.x * dot / lengthsq; double y = on.y * dot / lengthsq; return bevec(x, y); } BeVec bevec_rightnormal(BeVec vec) { return bevec(-vec.y, vec.x); } BeVec bevec_leftnormal(BeVec vec) { return bevec(vec.y, -vec.x); } double bevec_perproduct(BeVec v1, BeVec v2) { return bevec_dot(v1, bevec_rightnormal(v2)); } BeVec bevec_forangle(double angle) { return bevec(cos(angle), sin(angle)); } /* Returns a unit vector that makes the given angle a with the X axis. */ BeVec bevec_for_angle(double a) { return bevec(cos(a), sin(a)); } double bevec_toangle(BeVec v1) { return atan2(v1.y, v1.x); } /* Cross product magnitude. The cross product of 2D x,y vectors is a 3D vector with a pure z component, so this function returns only the magnitude of that z component. */ double bevec_cross(BeVec self, BeVec other) { return self.x * other.y - self.y * other.x; } /* Perpendicular vector, rotated by 90 degrees, anticlockwise. */ BeVec bevec_perp(BeVec self) { return bevec(-self.y, self.x); } /* Perpendicular vector, rotated by -90 degrees, clockwise. */ BeVec bevec_nperp(BeVec self) { return bevec(self.y, -self.x); } /* Returns a vector that is the projection of self onto other. * Not possible if other has a length 0. */ BeVec bevec_project_2(BeVec self, BeVec other) { double dot_product, other_length; dot_product = bevec_dot(self, other); other_length = bevec_length(other); return bevec_mul(other, dot_product / other_length); } /* Rotates self by other. */ BeVec bevec_rotate(BeVec self, BeVec other) { return bevec(self.x*other.x - self.y*other.y, self.x*other.y + self.y*other.x); } /* Inverse rotation. */ BeVec bevec_unrotate(BeVec self, BeVec other) { return bevec(self.x*other.x + self.y*other.y, self.x*other.y - self.y*other.x); } /* Linear interpolation on a line between between self and other. * Returns a vector that points to a point on the line between self and other. */ BeVec bevec_lerp(BeVec self, BeVec other, double tx) { return bevec_add(bevec_mul(self, 1.0 - tx), bevec_mul(other, tx)); /* self * (1.0 - tx) + (other * tx) */ } /* If the length of the vector is greater than max, this function returns a vector with the same direction as self, but with the length of that vector limited to max. Otherwise, it returns a copy of self. */ BeVec bevec_cliplength(BeVec self, double m) { double len = bevec_length(self); if (len <= m) return self; return bevec_mul(bevec_normalize(self), m); } /* Returns the vector between the two points represented by the vectors self and other. */ BeVec bevec_delta(BeVec self, BeVec other) { return bevec_sub(self, other); } /* Returns the distance between the two points represented by the vectors self and other. */ double bevec_distance(BeVec self, BeVec other) { return bevec_length(bevec_delta(self, other)); } /* Returns the distance squared between the two points represented by the vectors self and other. */ double bevec_distsq(BeVec self, BeVec other) { return bevec_lengthsq(bevec_delta(self, other)); } /* Returns true if the distance between self and other is less than or equal to d. */ double bevec_near_p(BeVec self, BeVec other, double d) { return bevec_distsq(self, other) <= (d*d); } /* Returns the angle of the vector with the X axis in clockwise * direction in radians */ double bevec_angle(BeVec self) { return atan2(self.y, self.x); } /* Returns a vector with components self.x, 0 */ BeVec bevec_xvec(BeVec self) { return bevec(self.x, 0.0); } /* Returns a vector with components 0, self.y */ BeVec bevec_yvec(BeVec self) { return bevec(0.0, self.y); } /* Returns a vector with fabs applied to the components of vec. */ BeVec bevec_abs(BeVec self) { return bevec(fabs(self.x), fabs(self.y)); } /* Returns the overlap of the x component of self, of other, where self and other are centers of line pieces with width rself and rother respectivly. Returned as a vector with only an x component with the magnitude of overlap. BeVec overlap_x(BeVec self, BeVec other,rself, rother) xself = self.vector_x xother = other.vector_x return zero unless xself.near(xother, rself) return zero unless xother.near(xself, rother) end */ // public domain function by Darel Rex Finley, 2006 // Determines the intersection point of the line segment defined by points A and B // with the line segment defined by points C and D. // // Returns YES if the intersection point was found, and stores that point in X,Y. // Returns NO if there is no determinable intersection point, in which case X,Y will // be unmodified. /* int bevec_intersect_segment(BeVec A, BeVec B, BeVec C, BeVec D, BeVeC * result) { double dist_AB, aid_cos, aid_sin, newX, ABpos ; // Fail if either line segment is zero-length. if (A.x == B.x && A.y == B.y || C.x == D.x && C.y == D.y) return NO; // Fail if the segments share an end-point. if (A.x==C.x && A.y==C.y || B.x==C.x && B.y==C.y || A.x==D.x && A.y==D.y || B.x==D.x && B.y==D.y) { return NO; } // (1) Translate the system so that point A is on the origin. B = bevec_sub(B, A); C = bevec_sub(C, A); D = bevec_sub(D, A); // Discover the length of segment A-B. dist_AB = bevec_length(B); // (2) Rotate the system so that point B is on the positive X axis. aid_Cos=Bx/distAB; aid_sin =By/distAB; newX=Cx*theCos+Cy* aid_sin; Cy =Cy*theCos-Cx* aid_sin; Cx=newX; newX=Dx*theCos+Dy* aid_sin; Dy =Dy*theCos-Dx* aid_sin; Dx=newX; // Fail if segment C-D doesn't cross line A-B. if (Cy<0. && Dy<0. || Cy>=0. && Dy>=0.) return NO; // (3) Discover the position of the intersection point along line A-B. ABpos=Dx+(Cx-Dx)*Dy/(Dy-Cy); // Fail if segment C-D crosses line A-B outside of segment A-B. if (ABpos<0. || ABpos>distAB) return NO; // (4) Apply the discovered position to line A-B in the original coordinate system. *X=Ax+ABpos*theCos; *Y=Ay+ABpos* aid_sin; // Success. return YES; } */