/// <summary> /// Returns the angle between this vector and the given vector in the range 0-2pi. /// </summary> /// <param name="v"></param> /// <returns></returns> public Radian Angle(VectorF2D v) { return VectorF2D.Angle(this, v); }
/// <summary> /// Calcuates the dot-product of the two given vectors. /// </summary> /// <param name="a"></param> /// <param name="b"></param> /// <returns></returns> public static double Dot(VectorF2D a, VectorF2D b) { double dot = 0.0f; for (int idx = 0; idx < 2; idx++) { dot = dot + a[idx] * b[idx]; } return dot; }
/// <summary> /// Returns the angle between 0 and 2*pi between the two vectors given. /// </summary> /// <param name="v1"></param> /// <param name="v2"></param> /// <returns></returns> public static Radian Angle(VectorF2D v1, VectorF2D v2) { double size_v1 = v1.Size; double size_v2 = v2.Size; double dot = VectorF2D.Dot(v1, v2); double cross = VectorF2D.Cross(v1, v2); // filter out the vectors that are parallel. if (v1[0] == v2[0] && v1[1] == v2[1]) { return 0; } else if (v1[0] == v2[0] && v1[1] == -v2[1]) { return System.Math.PI / 2.0f; } else if (v1[0] == -v2[0] && v1[1] == v2[1]) { return -System.Math.PI / 2.0f; } else if (v1[0] == -v2[0] && v1[1] == -v2[1]) { return System.Math.PI; } // split per quadrant. double angle; if (dot > 0) { // dot > 0 if (cross > 0) { // dot > 0 and cross > 0 // Quadrant 1 angle = (double)System.Math.Asin(cross / (size_v1 * size_v2)); if (angle < System.Math.PI / 4f) { // use cosine. angle = (double)System.Math.Acos(dot / (size_v1 * size_v2)); } // angle is ok here for quadrant 1. } else { // dot > 0 and cross <= 0 // Quadrant 4 angle = (double)(System.Math.PI * 2.0f) + (double)System.Math.Asin(cross / (size_v1 * size_v2)); if (angle > (double)(System.Math.PI * 2.0f) - System.Math.PI / 4f) { // use cosine. angle = (double)(System.Math.PI * 2.0f) - (double)System.Math.Acos(dot / (size_v1 * size_v2)); } // angle is ok here for quadrant 1. } } else { // dot <= 0 if (cross > 0) { // dot > 0 and cross > 0 // Quadrant 2 angle = (double)System.Math.PI - (double)System.Math.Asin(cross / (size_v1 * size_v2)); if (angle > System.Math.PI / 2f + System.Math.PI / 4f) { // use cosine. angle = (double)System.Math.Acos(dot / (size_v1 * size_v2)); } // angle is ok here for quadrant 2. } else { // dot > 0 and cross <= 0 // Quadrant 3 angle = -(-(double)System.Math.PI + (double)System.Math.Asin(cross / (size_v1 * size_v2))); if (angle < System.Math.PI + System.Math.PI / 4f) { // use cosine. angle = (double)(System.Math.PI * 2.0f) - (double)System.Math.Acos(dot / (size_v1 * size_v2)); } // angle is ok here for quadrant 3. } } return angle; }
/// <summary> /// Calculates the cross product. /// </summary> /// <param name="a"></param> /// <param name="b"></param> /// <returns></returns> public static double Cross(VectorF2D a, VectorF2D b) { return a[0] * b[1] - a[1] * b[0]; }
public void Vector2DTest() { // create the test cases. VectorF2D a_b = new VectorF2D(1 , 1); VectorF2D b_a = new VectorF2D(-1,-1); VectorF2D a_c = new VectorF2D(-1, 1); VectorF2D a_d = new VectorF2D(0, 1); VectorF2D a_e = new VectorF2D(-1, 0); VectorF2D a_f = new VectorF2D(0, 1); VectorF2D a_g = new VectorF2D(0, -1); // calculate the results double sqrt_2 = (double)System.Math.Sqrt(2); // check the sizes. Assert.AreEqual(a_b.Size, sqrt_2, string.Format("Size should be {0}!", sqrt_2)); Assert.AreEqual(b_a.Size, sqrt_2, string.Format("Size should be {0}!", sqrt_2)); // check the equality. Assert.IsTrue(a_b.Inverse == b_a, "The inverse of ab should be ba!"); // check the cross product. Assert.AreEqual(VectorF2D.Cross(a_b, b_a), 0, "Cross product of two parallel vectors should be 0!"); Assert.AreEqual(VectorF2D.Cross(a_b, a_c), 2, string.Format("Cross product of two perpendicular vectors should be maximized; in this case {0}!", 2)); Assert.AreEqual(VectorF2D.Cross(b_a, a_b), 0, "Cross product of two parallel vectors should be 0!"); Assert.AreEqual(VectorF2D.Cross(a_c, a_b), -2, string.Format("Cross product of two perpendicular vectors should be maximized; in this case {0}!", -2)); // check the dot product. Assert.AreEqual(VectorF2D.Dot(a_b, b_a), -2, string.Format("Cross product of two parallel vectors should be maximized (absolute value); in this case {0}!", -2)); Assert.AreEqual(VectorF2D.Dot(a_b, a_c), 0, string.Format("Cross product of two perpendicular vectors should be {0}!", 0)); Assert.AreEqual(VectorF2D.Dot(a_b, a_d), 1); Assert.AreEqual(VectorF2D.Dot(a_b, a_e), -1); Assert.AreEqual(VectorF2D.Dot(a_b, a_f), 1); Assert.AreEqual(VectorF2D.Dot(a_b, a_g), -1); Assert.AreEqual(VectorF2D.Dot(b_a, a_b), -2, string.Format("Cross product of two parallel vectors should be maximized; in this case {0}!", -2)); Assert.AreEqual(VectorF2D.Dot(a_c, a_b), 0, string.Format("Cross product of two perpendicular vectors should be {0}!", 0)); }