diff --git a/structs/Vector3d.cs b/structs/Vector3d.cs
new file mode 100644
index 0000000..998bb25
--- /dev/null
+++ b/structs/Vector3d.cs
@@ -0,0 +1,264 @@
+using System.Diagnostics.CodeAnalysis;
+
+namespace GeometriCS.structs
+{
+ ///
+ /// Three-dimensional vector with double precision.
+ ///
+ public struct Vector3d
+ {
+ ///
+ /// Vector with 0 length.
+ ///
+ public static readonly Vector3d ZeroVector = new(0d, 0d, 0d);
+
+ ///
+ /// Unit vector following the X axis, or (1; 0; 0)
+ ///
+ public static readonly Vector3d XAxis = new(1d, 0d, 0d);
+
+ ///
+ /// Unit vector following the Y axis, or (0; 1; 0)
+ ///
+ public static readonly Vector3d YAxis = new(0d, 1d, 0d);
+
+ ///
+ /// Unit vector following the Z axis, or (0; 0; 1)
+ ///
+ public static readonly Vector3d ZAxis = new(0d, 1d, 1d);
+
+ ///
+ /// X component of the vector.
+ ///
+ public double X { get; set; }
+
+ ///
+ /// Y component of the vector.
+ ///
+ public double Y { get; set; }
+
+ ///
+ /// Z component of the vector.
+ ///
+ public double Z { get; set; }
+
+ ///
+ /// Length of the vector.
+ ///
+ public double Length
+ {
+ get
+ {
+ return Math.Sqrt(X * X + Y * Y + Z * Z);
+ }
+ set
+ {
+ // If desired length is 0, set the components to 0 manually.
+ if (IsZero)
+ {
+ X = 0;
+ Y = 0;
+ Z = 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;
+ Z *= 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; 0) if original is (0; 0; 0).
+ public Vector3d Normalized()
+ {
+ // If this is a zero vector, return a zero vector.
+ if (IsZero)
+ {
+ return new Vector3d(0, 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 Vector3d(X * scaleDelta, Y * scaleDelta, Z * scaleDelta);
+ }
+
+ ///
+ /// Compute the cross product between this and another vector.
+ ///
+ /// Other vector.
+ /// The cross product of the two vectors.
+ public Vector3d CrossProduct(Vector3d other)
+ {
+ return new Vector3d(
+ Y * other.Z - Z * other.Y,
+ Z * other.X - X * other.Z,
+ 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(Vector3d other)
+ {
+ return X * other.X + Y * other.Y + Z * other.Z;
+ }
+
+ ///
+ /// 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 Vector3d GetVectorTo(Vector3d other)
+ {
+ return new Vector3d(-X + other.Y, -Y + other.Y, -Z + other.Z);
+ }
+
+ ///
+ /// Constructor.
+ ///
+ /// X component of the vector.
+ /// X component of the vector.
+ /// Z component of the vector.
+ public Vector3d(double x, double y, double z)
+ {
+ X = x;
+ Y = y;
+ Z = z;
+ }
+
+ ///
+ /// String representation of the vector.
+ ///
+ /// (X; Y; Z)
+ public override string ToString()
+ {
+ return $"({X}; {Y}; {Z})";
+ }
+
+ ///
+ /// 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 Vector3d asVect)
+ {
+ return this == asVect;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ public override int GetHashCode()
+ {
+ return HashCode.Combine(X, Y, Z);
+ }
+
+ ///
+ /// Negation of the vector.
+ ///
+ /// Vector to negate.
+ /// Negated vector.
+ public static Vector3d operator -(Vector3d vect)
+ {
+ return new Vector3d(-vect.X, -vect.Y, -vect.Z);
+ }
+
+ ///
+ /// Are the vectors equal?
+ ///
+ /// First vector.
+ /// Second vector.
+ /// true if the vectors are equal. Otherwise false
+ public static bool operator ==(Vector3d a, Vector3d b)
+ {
+ return Utils.DoubleEquals(a.X, b.X) && Utils.DoubleEquals(a.Y, b.Y) && Utils.DoubleEquals(a.Z, b.Z);
+ }
+
+ ///
+ /// Are the vectors different?
+ ///
+ /// First vector.
+ /// Second vector.
+ /// true if the vectors are different. Otherwise false
+ public static bool operator !=(Vector3d a, Vector3d b)
+ {
+ return !(Utils.DoubleEquals(a.X, b.X) && Utils.DoubleEquals(a.Y, b.Y) && Utils.DoubleEquals(a.Z, b.Z));
+ }
+
+ ///
+ /// Add the vectors together.
+ ///
+ /// First vector.
+ /// Second vector.
+ /// a + b
+ public static Vector3d operator +(Vector3d a, Vector3d b)
+ {
+ return new Vector3d(a.X + b.X, a.Y + b.Y, a.Z + b.Z);
+ }
+
+ ///
+ /// Add the first vector and the negation of the second negation.
+ ///
+ /// First vector.
+ /// Second vector.
+ /// a + (-b)
+ public static Vector3d operator -(Vector3d a, Vector3d b)
+ {
+ return new Vector3d(a.X - b.X, a.Y - b.Y, a.Z - b.Z);
+ }
+
+ ///
+ /// Scale the vector by the scalar.
+ ///
+ /// Vector.
+ /// Scalar.
+ /// vect * scalar
+ public static Vector3d operator *(Vector3d vect, double scalar)
+ {
+ return new Vector3d(vect.X * scalar, vect.Y * scalar, vect.Z * scalar);
+ }
+
+ ///
+ /// Scale the vector by the inverse of the scalar.
+ ///
+ /// Vector.
+ /// Scalar.
+ /// vect * (1 / scalar)
+ public static Vector3d operator /(Vector3d vect, double scalar)
+ {
+ if (Utils.DoubleEquals(scalar, 0))
+ {
+ throw new DivideByZeroException("Cannot divide by zero, silly.");
+ }
+ return new Vector3d(vect.X / scalar, vect.Y / scalar, vect.Z / scalar);
+ }
+ }
+}