diff --git a/Quadratic.Carto.csproj b/Quadratic.Carto.csproj
index f6d64a5..39a5382 100644
--- a/Quadratic.Carto.csproj
+++ b/Quadratic.Carto.csproj
@@ -4,6 +4,7 @@
+
net8.0
diff --git a/src/Math/DBasis.cs b/src/Math/DBasis.cs
new file mode 100644
index 0000000..c94c55e
--- /dev/null
+++ b/src/Math/DBasis.cs
@@ -0,0 +1,210 @@
+using System;
+using Vim.Math3d;
+
+namespace Quadratic.Carto.MathExt;
+
+///
+/// A 3x3 matrix of doubles. Made to aid .
+///
+public readonly record struct DBasis
+{
+ public readonly DVector3 col1;
+ public readonly DVector3 col2;
+ public readonly DVector3 col3;
+
+ public DVector3 Row1 => new(col1.X, col2.X, col3.X);
+ public DVector3 Row2 => new(col1.Y, col2.Y, col3.Y);
+ public DVector3 Row3 => new(col1.Z, col2.Z, col3.Z);
+
+ public DBasis(DVector3 col1, DVector3 col2, DVector3 col3)
+ {
+ this.col1 = col1;
+ this.col2 = col2;
+ this.col3 = col3;
+ }
+
+ public DBasis(Godot.Basis basis)
+ {
+ col1 = new DVector3(basis.X.X, basis.X.Y, basis.X.Z);
+ col2 = new DVector3(basis.Y.X, basis.Y.Y, basis.Y.Z);
+ col3 = new DVector3(basis.Z.X, basis.Z.Y, basis.Z.Z);
+ }
+
+ public DBasis(double x1, double y1, double z1, double x2, double y2, double z2, double x3, double y3, double z3)
+ {
+ col1 = new DVector3(x1, y1, z1);
+ col2 = new DVector3(x2, y2, z2);
+ col3 = new DVector3(x3, y3, z3);
+ }
+
+ public DBasis(DVector3 x, DVector3 y, bool normalize = false)
+ {
+ col1 = x;
+ col2 = y;
+ col3 = x.Cross(y);
+ if (normalize)
+ {
+ col3 = col3.Normalize();
+ }
+ }
+
+ public DBasis(double x1, double y1, double z1, double x2, double y2, double z2, bool normalize = false)
+ {
+ col1 = new DVector3(x1, y1, z1);
+ col2 = new DVector3(x2, y2, z2);
+ col3 = col1.Cross(col2);
+ if (normalize)
+ {
+ col3 = col3.Normalize();
+ }
+ }
+
+ public static DBasis Identity => new(
+ new DVector3(1, 0, 0),
+ new DVector3(0, 1, 0),
+ new DVector3(0, 0, 1)
+ );
+
+ ///
+ /// Transform a vector.
+ ///
+ ///
+ ///
+ public readonly DVector3 Transform(DVector3 b)
+ {
+ return col1 * b.X + col2 * b.Y + col3 * b.Z;
+ }
+
+ ///
+ /// Inverse transform a vector. Only works with orthonormal bases.
+ ///
+ ///
+ ///
+ public readonly DVector3 OrthonormalInvTransform(DVector3 b)
+ {
+ return this.Transpose().Transform(b);
+ }
+
+ public bool IsUnit()
+ {
+ return Math.Abs(col1.LengthSquared() - 1) < 1e-6
+ && Math.Abs(col2.LengthSquared() - 1) < 1e-6
+ && Math.Abs(col3.LengthSquared() - 1) < 1e-6;
+ }
+
+ public static DBasis operator *(DBasis a, DBasis b)
+ {
+ return new DBasis(
+ new DVector3(
+ a.col1.X * b.col1.X + a.col2.X * b.col1.Y + a.col3.X * b.col1.Z,
+ a.col1.Y * b.col1.X + a.col2.Y * b.col1.Y + a.col3.Y * b.col1.Z,
+ a.col1.Z * b.col1.X + a.col2.Z * b.col1.Y + a.col3.Z * b.col1.Z
+ ),
+ new DVector3(
+ a.col1.X * b.col2.X + a.col2.X * b.col2.Y + a.col3.X * b.col2.Z,
+ a.col1.Y * b.col2.X + a.col2.Y * b.col2.Y + a.col3.Y * b.col2.Z,
+ a.col1.Z * b.col2.X + a.col2.Z * b.col2.Y + a.col3.Z * b.col2.Z
+ ),
+ new DVector3(
+ a.col1.X * b.col3.X + a.col2.X * b.col3.Y + a.col3.X * b.col3.Z,
+ a.col1.Y * b.col3.X + a.col2.Y * b.col3.Y + a.col3.Y * b.col3.Z,
+ a.col1.Z * b.col3.X + a.col2.Z * b.col3.Y + a.col3.Z * b.col3.Z
+ )
+ );
+ }
+
+ public static DVector3 operator *(DBasis a, DVector3 b)
+ {
+ return a.Transform(b);
+ }
+
+ public static DBasis operator *(DBasis a, double b)
+ {
+ return new DBasis(a.col1 * b, a.col2 * b, a.col3 * b);
+ }
+
+ public static DBasis operator +(DBasis a, DBasis b)
+ {
+ return new DBasis(a.col1 + b.col1, a.col2 + b.col2, a.col3 + b.col3);
+ }
+
+ public static DBasis operator -(DBasis a, DBasis b)
+ {
+ return new DBasis(a.col1 - b.col1, a.col2 - b.col2, a.col3 - b.col3);
+ }
+
+ public static DBasis operator -(DBasis a)
+ {
+ return new DBasis(-a.col1, -a.col2, -a.col3);
+ }
+
+ public static DBasis operator /(DBasis a, double b)
+ {
+ return new DBasis(a.col1 / b, a.col2 / b, a.col3 / b);
+ }
+
+ public static DBasis operator /(DBasis a, DBasis b)
+ {
+ return a * b.Transpose();
+ }
+
+ public readonly DBasis Transpose()
+ {
+ return new DBasis(Row1, Row2, Row3);
+ }
+
+ [Obsolete("The implementation is flawed and awaiting a fix")]
+ public readonly DBasis Inverse()
+ {
+ double
+ m00 = col1.X,
+ m01 = col1.Y,
+ m02 = col1.Z,
+ m10 = col2.X,
+ m11 = col2.Y,
+ m12 = col2.Z,
+ m20 = col3.X,
+ m21 = col3.Y,
+ m22 = col3.Z;
+
+ double det = m00 * (m11 * m22 - m21 * m12) -
+ m01 * (m10 * m22 - m12 * m20) +
+ m02 * (m10 * m21 - m11 * m20);
+
+ if (Math.Abs(det) < 1e-6)
+ return Identity;
+
+ double invDet = 1 / det;
+
+ double
+ mi00 = (m11 * m22 - m21 * m12) * invDet,
+ mi01 = (m02 * m21 - m01 * m22) * invDet,
+ mi02 = (m01 * m12 - m02 * m11) * invDet,
+ mi10 = (m12 * m20 - m10 * m22) * invDet,
+ mi11 = (m00 * m22 - m02 * m20) * invDet,
+ mi12 = (m02 * m10 - m00 * m12) * invDet,
+ mi20 = (m10 * m21 - m20 * m11) * invDet,
+ mi21 = (m20 * m01 - m00 * m21) * invDet,
+ mi22 = (m00 * m11 - m10 * m01) * invDet;
+
+ return new DBasis(
+ new DVector3(mi00, mi10, mi20),
+ new DVector3(mi01, mi11, mi21),
+ new DVector3(mi02, mi12, mi22)
+ );
+ }
+
+ public readonly Godot.Basis AsBasis()
+ {
+ return new Godot.Basis(
+ (float)col1.X, (float)col1.Y, (float)col1.Z,
+ (float)col2.X, (float)col2.Y, (float)col2.Z,
+ (float)col3.X, (float)col3.Y, (float)col3.Z
+ );
+ }
+
+ public override string ToString()
+ {
+ return $"({col1}, {col2}, {col3})";
+ }
+}
diff --git a/src/Math/VectorsExt.Conversion.cs b/src/Math/VectorsExt.Conversion.cs
index 2a2b159..79a8c85 100644
--- a/src/Math/VectorsExt.Conversion.cs
+++ b/src/Math/VectorsExt.Conversion.cs
@@ -3,6 +3,26 @@ namespace Quadratic.Carto.MathExt;
public static partial class VectorsExt
{
+ public static Godot.Vector3 AsGodot(this Vim.Math3d.Vector3 v)
+ {
+ return new Godot.Vector3(v.X, v.Y, v.Z);
+ }
+
+ public static Vim.Math3d.Vector3 AsVim(this Godot.Vector3 v)
+ {
+ return new Vim.Math3d.Vector3(v.X, v.Y, v.Z);
+ }
+
+ public static System.Numerics.Vector3 AsSystem(this Vim.Math3d.Vector3 v)
+ {
+ return new System.Numerics.Vector3(v.X, v.Y, v.Z);
+ }
+
+ public static Vim.Math3d.Vector3 AsVim(this System.Numerics.Vector3 v)
+ {
+ return new Vim.Math3d.Vector3(v.X, v.Y, v.Z);
+ }
+
public static Godot.Vector3 AsGodot(this System.Numerics.Vector3 v)
{
return new Godot.Vector3(v.X, v.Y, v.Z);
@@ -13,6 +33,36 @@ public static partial class VectorsExt
return new System.Numerics.Vector3(v.X, v.Y, v.Z);
}
+ public static DVector3 AsDouble(this Vim.Math3d.Vector3 v)
+ {
+ return new DVector3(v.X, v.Y, v.Z);
+ }
+
+ public static Vim.Math3d.Vector3 AsSingle(this DVector3 v)
+ {
+ return new Vim.Math3d.Vector3((float)v.X, (float)v.Y, (float)v.Z);
+ }
+
+ public static Godot.Vector2 AsGodot(this Vim.Math3d.Vector2 v)
+ {
+ return new Godot.Vector2(v.X, v.Y);
+ }
+
+ public static Vim.Math3d.Vector2 AsVim(this Godot.Vector2 v)
+ {
+ return new Vim.Math3d.Vector2(v.X, v.Y);
+ }
+
+ public static System.Numerics.Vector2 AsSystem(this Vim.Math3d.Vector2 v)
+ {
+ return new System.Numerics.Vector2(v.X, v.Y);
+ }
+
+ public static Vim.Math3d.Vector2 AsVim(this System.Numerics.Vector2 v)
+ {
+ return new Vim.Math3d.Vector2(v.X, v.Y);
+ }
+
public static Godot.Vector2 AsGodot(this System.Numerics.Vector2 v)
{
return new Godot.Vector2(v.X, v.Y);
@@ -23,6 +73,26 @@ public static partial class VectorsExt
return new System.Numerics.Vector2(v.X, v.Y);
}
+ public static Godot.Quaternion AsGodot(this Vim.Math3d.Quaternion q)
+ {
+ return new Godot.Quaternion(q.X, q.Y, q.Z, q.W);
+ }
+
+ public static Vim.Math3d.Quaternion AsVim(this Godot.Quaternion q)
+ {
+ return new Vim.Math3d.Quaternion(q.X, q.Y, q.Z, q.W);
+ }
+
+ public static System.Numerics.Quaternion AsSystem(this Vim.Math3d.Quaternion q)
+ {
+ return new System.Numerics.Quaternion(q.X, q.Y, q.Z, q.W);
+ }
+
+ public static Vim.Math3d.Quaternion AsVim(this System.Numerics.Quaternion q)
+ {
+ return new Vim.Math3d.Quaternion(q.X, q.Y, q.Z, q.W);
+ }
+
public static Godot.Quaternion AsGodot(this System.Numerics.Quaternion q)
{
return new Godot.Quaternion(q.X, q.Y, q.Z, q.W);
@@ -33,6 +103,26 @@ public static partial class VectorsExt
return new System.Numerics.Quaternion(q.X, q.Y, q.Z, q.W);
}
+ public static Godot.Vector4 AsGodot(this Vim.Math3d.Vector4 v)
+ {
+ return new Godot.Vector4(v.X, v.Y, v.Z, v.W);
+ }
+
+ public static Vim.Math3d.Vector4 AsVim(this Godot.Vector4 v)
+ {
+ return new Vim.Math3d.Vector4(v.X, v.Y, v.Z, v.W);
+ }
+
+ public static System.Numerics.Vector4 AsSystem(this Vim.Math3d.Vector4 v)
+ {
+ return new System.Numerics.Vector4(v.X, v.Y, v.Z, v.W);
+ }
+
+ public static Vim.Math3d.Vector4 AsVim(this System.Numerics.Vector4 v)
+ {
+ return new Vim.Math3d.Vector4(v.X, v.Y, v.Z, v.W);
+ }
+
public static Godot.Vector4 AsGodot(this System.Numerics.Vector4 v)
{
return new Godot.Vector4(v.X, v.Y, v.Z, v.W);
@@ -42,6 +132,16 @@ public static partial class VectorsExt
{
return new System.Numerics.Vector4(v.X, v.Y, v.Z, v.W);
}
+
+ public static Vim.Math3d.Ray AsVim(this Ray ray)
+ {
+ return new Vim.Math3d.Ray(ray.origin.AsVim(), ray.direction.AsVim());
+ }
+
+ public static Ray AsGodot(this Vim.Math3d.Ray ray)
+ {
+ return new Ray(ray.Position.AsGodot(), ray.Direction.AsGodot());
+ }
}