diff --git a/structs/Vector2d.cs b/structs/Vector2d.cs
new file mode 100644
index 0000000..52904ef
--- /dev/null
+++ b/structs/Vector2d.cs
@@ -0,0 +1,251 @@
+using System.Diagnostics.CodeAnalysis;
+
+namespace GeometriCS.structs
+{
+ ///
+ /// Two-dimensional vector with double precision.
+ ///
+ public struct Vector2d
+ {
+ ///
+ /// Vector with 0 length.
+ ///
+ public static readonly Vector2d ZeroVector = new(0d, 0d);
+
+ ///
+ /// Unit vector following the X axis, or (1; 0)
+ ///
+ public static readonly Vector2d XAxis = new(1d, 0d);
+
+ ///
+ /// Unit vector following the Y axis, or (0; 1)
+ ///
+ public static readonly Vector2d YAxis = new(0d, 1d);
+
+ ///
+ /// X component of the vector.
+ ///
+ public double X { get; set; }
+
+ ///
+ /// Y component of the vector.
+ ///
+ public double Y { get; set; }
+
+ ///
+ /// Length of the vector.
+ ///
+ public double Length
+ {
+ get
+ {
+ return Math.Sqrt(X*X + Y*Y);
+ }
+ set
+ {
+ // If desired length is 0, set the components to 0 manually.
+ if(IsZero)
+ {
+ X = 0;
+ Y = 0;
+ return;
+ }
+
+ // New length divided by the old Length.
+ // Or, the scalar we need to apply to the vector in order for it to reach the desired length.
+ double scaleDelta = value / Length;
+
+ // Scale the vector by the scalar delta.
+ X *= scaleDelta;
+ Y *= scaleDelta;
+ }
+ }
+
+ ///
+ /// Is this a zero vecor?
+ ///
+ public bool IsZero => Utils.DoubleEquals(Length, 0);
+
+ ///
+ /// Is this a unit vector?
+ ///
+ public bool IsUnit => Utils.DoubleEquals(Length, 1);
+
+ ///
+ /// Normalized, or unit version of the vector.
+ ///
+ /// Calling this method does not affect the source vector.
+ /// Normalized vector, or (0; 0) if original is (0; 0).
+ public Vector2d Normalized()
+ {
+ // If this is a zero vector, return a zero vector.
+ if(IsZero)
+ {
+ return new Vector2d(0, 0);
+ }
+
+ // Get the inverse of the length of the vector,
+ // Or the scalar we need to apply to the vector in order for it to reach the desired length.
+ double scaleDelta = 1 / Length;
+
+ // Return this vector scaled to have its Length equal to 1
+ return new Vector2d(X * scaleDelta, Y * scaleDelta);
+ }
+
+ ///
+ /// Compute the cross product between this and another vector.
+ ///
+ ///
+ /// Determinant of a matrix made of the two vectors.
+ ///
+ /// Other vector.
+ /// The cross product of the two vectors.
+ public double CrossProduct(Vector2d other)
+ {
+ // Compute the determinant by the rule of Sarrus
+ return (X * other.Y) - (Y * other.X);
+ }
+
+ ///
+ /// Compute the dot product between this and another vector.
+ ///
+ /// Other vector.
+ /// The dot product of the two vectors.
+ public double DotProduct(Vector2d other)
+ {
+ return X * other.X + Y * other.Y;
+ }
+
+ ///
+ /// Get the vector needed to get from the point at the end of this vector to the end of another vector.
+ ///
+ /// The vector to get to the end of.
+ /// Vector leading from the tip of this vector to the tip of the other vector.
+ public Vector2d GetVectorTo(Vector2d other)
+ {
+ return new Vector2d(-X + other.Y, -Y + other.Y);
+ }
+
+ ///
+ /// Constructor.
+ ///
+ /// X component of the vector.
+ /// Y component of the vector.
+ public Vector2d(double x, double y)
+ {
+ X = x;
+ Y = y;
+ }
+
+ ///
+ /// String representation of the vector.
+ ///
+ /// (X; Y)
+ public override string ToString()
+ {
+ return $"({X}; {Y})";
+ }
+
+ ///
+ /// Do the two objects represent the same vector?
+ ///
+ /// Object to compare.
+ /// true if the vectors are equal. Otherwise false
+ public override bool Equals([NotNullWhen(true)] object? obj)
+ {
+ if (obj is Vector2d asVect)
+ {
+ return this == asVect;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ public override int GetHashCode()
+ {
+ return HashCode.Combine(X, Y);
+ }
+
+ ///
+ /// Negation of the vector.
+ ///
+ /// Vector to negate.
+ /// Negated vector.
+ public static Vector2d operator -(Vector2d vect)
+ {
+ return new Vector2d(-vect.X, -vect.Y);
+ }
+
+ ///
+ /// Are the vectors equal?
+ ///
+ /// First vector.
+ /// Second vector.
+ /// true if the vectors are equal. Otherwise false
+ public static bool operator ==(Vector2d a, Vector2d b)
+ {
+ return Utils.DoubleEquals(a.X, b.X) && Utils.DoubleEquals(a.Y, b.Y);
+ }
+
+ ///
+ /// Are the vectors different?
+ ///
+ /// First vector.
+ /// Second vector.
+ /// true if the vectors are different. Otherwise false
+ public static bool operator !=(Vector2d a, Vector2d b)
+ {
+ return !Utils.DoubleEquals(a.X, b.X) && Utils.DoubleEquals(a.Y, b.Y);
+ }
+
+ ///
+ /// Add the vectors together.
+ ///
+ /// First vector.
+ /// Second vector.
+ /// a + b
+ public static Vector2d operator +(Vector2d a, Vector2d b)
+ {
+ return new Vector2d(a.X + b.X, a.Y + b.Y);
+ }
+
+ ///
+ /// Add the first vector and the negation of the second negation.
+ ///
+ /// First vector.
+ /// Second vector.
+ /// a + (-b)
+ public static Vector2d operator -(Vector2d a, Vector2d b)
+ {
+ return new Vector2d(a.X - b.X, a.Y - b.Y);
+ }
+
+ ///
+ /// Scale the vector by the scalar.
+ ///
+ /// Vector.
+ /// Scalar.
+ /// vect * scalar
+ public static Vector2d operator *(Vector2d vect, double scalar)
+ {
+ return new Vector2d(vect.X * scalar, vect.Y * scalar);
+ }
+
+ ///
+ /// Scale the vector by the inverse of the scalar.
+ ///
+ /// Vector.
+ /// Scalar.
+ /// vect * (1 / scalar)
+ public static Vector2d operator /(Vector2d vect, double scalar)
+ {
+ if(Utils.DoubleEquals(scalar, 0))
+ {
+ throw new DivideByZeroException("Cannot divide by zero, silly.");
+ }
+ return new Vector2d(vect.X / scalar, vect.Y / scalar);
+ }
+ }
+}