-
Notifications
You must be signed in to change notification settings - Fork 5.3k
Description
I am proposing that a Cross Product function be added to both Vector2 and Vector4 of System.Numerics because its use in geometry is so common.
Rationale and Usage
The structs, Vector2, Vector3, and Vector4 are intended to model geometry functions that often need to be performed quickly and which would greatly benefit from SIMD inlining. Dot Product is just as popular and it is properly implemented in these structs. Cross Product is only possible for vectors of length 3 (yes, and 7, but that is not important right now). However, Vector2 and Vector4 are essentially modelling vectors in 3D space. In Vector2 the cross product is commonly used for functions like offsetting, for determining if the next edge in a polygon turns right or left (or convex or concave), or determining overlap/collisions. A cross-product of two Vector2 's would always result in an out-of-plane or z-direction, but it's value and sign is very useful and just as quick to process as Dot.
Vector4 is defined for use as a homogeneous 3D coordinate vector, and so it will be necessary for a Cross function to exist for it just as much as for Vector3.
Proposed Changes And API
The addition of two new methods are quite simple and the functions that these invoke are nothing other than add (+) and multiply (*).
To Vector2_Instrinsics.cs (under Dot() line 109):
/// <summary>
/// Returns the z-value of the cross product of two vectors.
/// Since the Vector2 is in the x-y plane, a 3D cross product
/// only produces the z-value
/// </summary>
/// <param name="value1">The first vector.</param>
/// <param name="value2">The second vector.</param>
/// <returns>The value of the z-coordinate from the cross product.</returns>
[JitIntrinsic]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float Cross(Vector2 value1, Vector2 value2)
{
return value1.X * value2.Y
- value1.Y * value2.X;
}to Vector4_Instrinsics.cs (under Dot() line 157):
/// <summary>
/// Computes the cross product of two vectors. For homogeneous
/// coordinates, the product of the weights is the new weight
/// for the resulting product.
/// </summary>
/// <param name="vector1">The first vector.</param>
/// <param name="vector2">The second vector.</param>
/// <returns>The cross product.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 Cross(Vector4 vector1, Vector4 vector2)
{
return new Vector4(
vector1.Y * vector2.Z - vector1.Z * vector2.Y,
vector1.Z * vector2.X - vector1.X * vector2.Z,
vector1.X * vector2.Y - vector1.Y * vector2.X,
vector1.W * vector2.W);
}Other Details
- One will note that the 'Cross' for 'Vector2' looks like the 'Dot' except the values have moved around. Yes, essentially the 'Cross' for 'Vector2' is the same as taking the 'Dot' with a vector that has been rotate 90-degrees from the original. As such, this is the work around to invoking geometric functions - create a new vector 90-degrees from the original, and then use
Dot. This process is not intuitive and requires extra steps. A simple function, like the one shown above, is both more intuitive and quicker. - The proposed
Crossfunction forVector4is nearly the same as that forVector3with the addition of the fourth value which is the product of the original two w's. This can be derived by symbolically performing the cross product forVector3with values[x_1/w_1, y_1/w_1, z_1/w_1]and[x_2/w_2, y_2/w_2, z_2/w_2].
Open Questions
- Will the name
Crossbe misleading forVector2? If so, one could name itCrossZValue, but I think this is an unwarranted complication. In implementing 2D algorithms, the literature has called this the cross product and one would write the code to mimic the presentation of scientific papers. However, since the result is a single scalar (float), it could be confusing as to why aCrossproduct function is not returning a new vector.
Pull Request
A PR with the proposed changes is forthcoming.